From 0dc221b200b9d3df550e2d760cb396e4cb5f7176 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Sat, 20 Aug 2022 08:44:27 -0400 Subject: [PATCH] submodule LuaJIT; build libs through Makefile --- .gitignore | 4 +- .gitmodules | 3 + Makefile | 24 +- lib/LuaJIT/.gitignore | 11 - lib/LuaJIT/COPYRIGHT | 56 - lib/LuaJIT/Makefile | 166 - lib/LuaJIT/README | 16 - lib/LuaJIT/doc/bluequad-print.css | 166 - lib/LuaJIT/doc/bluequad.css | 325 -- lib/LuaJIT/doc/changes.html | 882 --- lib/LuaJIT/doc/contact.html | 110 - lib/LuaJIT/doc/ext_c_api.html | 188 - lib/LuaJIT/doc/ext_ffi.html | 331 -- lib/LuaJIT/doc/ext_ffi_api.html | 571 -- lib/LuaJIT/doc/ext_ffi_semantics.html | 1261 ---- lib/LuaJIT/doc/ext_ffi_tutorial.html | 602 -- lib/LuaJIT/doc/ext_jit.html | 200 - lib/LuaJIT/doc/ext_profiler.html | 364 -- lib/LuaJIT/doc/extensions.html | 482 -- lib/LuaJIT/doc/faq.html | 185 - lib/LuaJIT/doc/img/contact.png | Bin 1340 -> 0 bytes lib/LuaJIT/doc/install.html | 691 --- lib/LuaJIT/doc/luajit.html | 235 - lib/LuaJIT/doc/running.html | 308 - lib/LuaJIT/doc/status.html | 122 - lib/LuaJIT/dynasm/dasm_arm.h | 458 -- lib/LuaJIT/dynasm/dasm_arm.lua | 1125 ---- lib/LuaJIT/dynasm/dasm_arm64.h | 519 -- lib/LuaJIT/dynasm/dasm_arm64.lua | 1166 ---- lib/LuaJIT/dynasm/dasm_mips.h | 420 -- lib/LuaJIT/dynasm/dasm_mips.lua | 1008 ---- lib/LuaJIT/dynasm/dasm_mips64.lua | 12 - lib/LuaJIT/dynasm/dasm_ppc.h | 420 -- lib/LuaJIT/dynasm/dasm_ppc.lua | 1919 ------ lib/LuaJIT/dynasm/dasm_proto.h | 83 - lib/LuaJIT/dynasm/dasm_x64.lua | 12 - lib/LuaJIT/dynasm/dasm_x86.h | 509 -- lib/LuaJIT/dynasm/dasm_x86.lua | 2360 -------- lib/LuaJIT/dynasm/dynasm.lua | 1094 ---- lib/LuaJIT/etc/luajit.1 | 88 - lib/LuaJIT/etc/luajit.pc | 25 - lib/LuaJIT/src/.gitignore | 7 - lib/LuaJIT/src/Makefile | 722 --- lib/LuaJIT/src/Makefile.dep | 246 - lib/LuaJIT/src/host/.gitignore | 3 - lib/LuaJIT/src/host/README | 4 - lib/LuaJIT/src/host/buildvm.c | 518 -- lib/LuaJIT/src/host/buildvm.h | 105 - lib/LuaJIT/src/host/buildvm_asm.c | 359 -- lib/LuaJIT/src/host/buildvm_fold.c | 229 - lib/LuaJIT/src/host/buildvm_lib.c | 457 -- lib/LuaJIT/src/host/buildvm_libbc.h | 56 - lib/LuaJIT/src/host/buildvm_peobj.c | 392 -- lib/LuaJIT/src/host/genlibbc.lua | 197 - lib/LuaJIT/src/host/genminilua.lua | 429 -- lib/LuaJIT/src/host/minilua.c | 7770 ------------------------- lib/LuaJIT/src/jit/.gitignore | 1 - lib/LuaJIT/src/jit/bc.lua | 190 - lib/LuaJIT/src/jit/bcsave.lua | 661 --- lib/LuaJIT/src/jit/dis_arm.lua | 689 --- lib/LuaJIT/src/jit/dis_arm64.lua | 1216 ---- lib/LuaJIT/src/jit/dis_arm64be.lua | 12 - lib/LuaJIT/src/jit/dis_mips.lua | 443 -- lib/LuaJIT/src/jit/dis_mips64.lua | 17 - lib/LuaJIT/src/jit/dis_mips64el.lua | 17 - lib/LuaJIT/src/jit/dis_mipsel.lua | 17 - lib/LuaJIT/src/jit/dis_ppc.lua | 591 -- lib/LuaJIT/src/jit/dis_x64.lua | 17 - lib/LuaJIT/src/jit/dis_x86.lua | 953 --- lib/LuaJIT/src/jit/dump.lua | 712 --- lib/LuaJIT/src/jit/p.lua | 311 - lib/LuaJIT/src/jit/v.lua | 170 - lib/LuaJIT/src/jit/zone.lua | 45 - lib/LuaJIT/src/lauxlib.h | 161 - lib/LuaJIT/src/lib_aux.c | 374 -- lib/LuaJIT/src/lib_base.c | 679 --- lib/LuaJIT/src/lib_bit.c | 180 - lib/LuaJIT/src/lib_debug.c | 405 -- lib/LuaJIT/src/lib_ffi.c | 872 --- lib/LuaJIT/src/lib_init.c | 55 - lib/LuaJIT/src/lib_io.c | 539 -- lib/LuaJIT/src/lib_jit.c | 777 --- lib/LuaJIT/src/lib_math.c | 226 - lib/LuaJIT/src/lib_os.c | 292 - lib/LuaJIT/src/lib_package.c | 623 -- lib/LuaJIT/src/lib_string.c | 748 --- lib/LuaJIT/src/lib_table.c | 327 -- lib/LuaJIT/src/lj.supp | 41 - lib/LuaJIT/src/lj_alloc.c | 1490 ----- lib/LuaJIT/src/lj_alloc.h | 17 - lib/LuaJIT/src/lj_api.c | 1292 ---- lib/LuaJIT/src/lj_arch.h | 599 -- lib/LuaJIT/src/lj_asm.c | 2414 -------- lib/LuaJIT/src/lj_asm.h | 17 - lib/LuaJIT/src/lj_asm_arm.h | 2210 ------- lib/LuaJIT/src/lj_asm_arm64.h | 2031 ------- lib/LuaJIT/src/lj_asm_mips.h | 2659 --------- lib/LuaJIT/src/lj_asm_ppc.h | 2251 ------- lib/LuaJIT/src/lj_asm_x86.h | 3121 ---------- lib/LuaJIT/src/lj_bc.c | 14 - lib/LuaJIT/src/lj_bc.h | 265 - lib/LuaJIT/src/lj_bcdump.h | 68 - lib/LuaJIT/src/lj_bcread.c | 457 -- lib/LuaJIT/src/lj_bcwrite.c | 361 -- lib/LuaJIT/src/lj_buf.c | 232 - lib/LuaJIT/src/lj_buf.h | 103 - lib/LuaJIT/src/lj_carith.c | 437 -- lib/LuaJIT/src/lj_carith.h | 38 - lib/LuaJIT/src/lj_ccall.c | 1183 ---- lib/LuaJIT/src/lj_ccall.h | 194 - lib/LuaJIT/src/lj_ccallback.c | 787 --- lib/LuaJIT/src/lj_ccallback.h | 25 - lib/LuaJIT/src/lj_cconv.c | 754 --- lib/LuaJIT/src/lj_cconv.h | 70 - lib/LuaJIT/src/lj_cdata.c | 299 - lib/LuaJIT/src/lj_cdata.h | 78 - lib/LuaJIT/src/lj_char.c | 43 - lib/LuaJIT/src/lj_char.h | 42 - lib/LuaJIT/src/lj_clib.c | 430 -- lib/LuaJIT/src/lj_clib.h | 29 - lib/LuaJIT/src/lj_cparse.c | 1898 ------ lib/LuaJIT/src/lj_cparse.h | 65 - lib/LuaJIT/src/lj_crecord.c | 1892 ------ lib/LuaJIT/src/lj_crecord.h | 38 - lib/LuaJIT/src/lj_ctype.c | 637 -- lib/LuaJIT/src/lj_ctype.h | 461 -- lib/LuaJIT/src/lj_debug.c | 699 --- lib/LuaJIT/src/lj_debug.h | 65 - lib/LuaJIT/src/lj_def.h | 361 -- lib/LuaJIT/src/lj_dispatch.c | 557 -- lib/LuaJIT/src/lj_dispatch.h | 156 - lib/LuaJIT/src/lj_emit_arm.h | 357 -- lib/LuaJIT/src/lj_emit_arm64.h | 419 -- lib/LuaJIT/src/lj_emit_mips.h | 295 - lib/LuaJIT/src/lj_emit_ppc.h | 238 - lib/LuaJIT/src/lj_emit_x86.h | 573 -- lib/LuaJIT/src/lj_err.c | 854 --- lib/LuaJIT/src/lj_err.h | 41 - lib/LuaJIT/src/lj_errmsg.h | 190 - lib/LuaJIT/src/lj_ff.h | 18 - lib/LuaJIT/src/lj_ffrecord.c | 1226 ---- lib/LuaJIT/src/lj_ffrecord.h | 24 - lib/LuaJIT/src/lj_frame.h | 297 - lib/LuaJIT/src/lj_func.c | 187 - lib/LuaJIT/src/lj_func.h | 24 - lib/LuaJIT/src/lj_gc.c | 854 --- lib/LuaJIT/src/lj_gc.h | 134 - lib/LuaJIT/src/lj_gdbjit.c | 817 --- lib/LuaJIT/src/lj_gdbjit.h | 22 - lib/LuaJIT/src/lj_ir.c | 494 -- lib/LuaJIT/src/lj_ir.h | 590 -- lib/LuaJIT/src/lj_ircall.h | 358 -- lib/LuaJIT/src/lj_iropt.h | 162 - lib/LuaJIT/src/lj_jit.h | 505 -- lib/LuaJIT/src/lj_lex.c | 509 -- lib/LuaJIT/src/lj_lex.h | 86 - lib/LuaJIT/src/lj_lib.c | 303 - lib/LuaJIT/src/lj_lib.h | 115 - lib/LuaJIT/src/lj_load.c | 168 - lib/LuaJIT/src/lj_mcode.c | 381 -- lib/LuaJIT/src/lj_mcode.h | 30 - lib/LuaJIT/src/lj_meta.c | 477 -- lib/LuaJIT/src/lj_meta.h | 38 - lib/LuaJIT/src/lj_obj.c | 50 - lib/LuaJIT/src/lj_obj.h | 991 ---- lib/LuaJIT/src/lj_opt_dce.c | 78 - lib/LuaJIT/src/lj_opt_fold.c | 2555 -------- lib/LuaJIT/src/lj_opt_loop.c | 449 -- lib/LuaJIT/src/lj_opt_mem.c | 935 --- lib/LuaJIT/src/lj_opt_narrow.c | 654 --- lib/LuaJIT/src/lj_opt_sink.c | 251 - lib/LuaJIT/src/lj_opt_split.c | 870 --- lib/LuaJIT/src/lj_parse.c | 2728 --------- lib/LuaJIT/src/lj_parse.h | 18 - lib/LuaJIT/src/lj_profile.c | 368 -- lib/LuaJIT/src/lj_profile.h | 21 - lib/LuaJIT/src/lj_record.c | 2649 --------- lib/LuaJIT/src/lj_record.h | 45 - lib/LuaJIT/src/lj_snap.c | 916 --- lib/LuaJIT/src/lj_snap.h | 34 - lib/LuaJIT/src/lj_state.c | 300 - lib/LuaJIT/src/lj_state.h | 35 - lib/LuaJIT/src/lj_str.c | 197 - lib/LuaJIT/src/lj_str.h | 27 - lib/LuaJIT/src/lj_strfmt.c | 472 -- lib/LuaJIT/src/lj_strfmt.h | 125 - lib/LuaJIT/src/lj_strfmt_num.c | 592 -- lib/LuaJIT/src/lj_strscan.c | 547 -- lib/LuaJIT/src/lj_strscan.h | 39 - lib/LuaJIT/src/lj_tab.c | 688 --- lib/LuaJIT/src/lj_tab.h | 73 - lib/LuaJIT/src/lj_target.h | 164 - lib/LuaJIT/src/lj_target_arm.h | 270 - lib/LuaJIT/src/lj_target_arm64.h | 332 -- lib/LuaJIT/src/lj_target_mips.h | 377 -- lib/LuaJIT/src/lj_target_ppc.h | 280 - lib/LuaJIT/src/lj_target_x86.h | 362 -- lib/LuaJIT/src/lj_trace.c | 909 --- lib/LuaJIT/src/lj_trace.h | 55 - lib/LuaJIT/src/lj_traceerr.h | 61 - lib/LuaJIT/src/lj_udata.c | 34 - lib/LuaJIT/src/lj_udata.h | 14 - lib/LuaJIT/src/lj_vm.h | 120 - lib/LuaJIT/src/lj_vmevent.c | 58 - lib/LuaJIT/src/lj_vmevent.h | 59 - lib/LuaJIT/src/lj_vmmath.c | 152 - lib/LuaJIT/src/ljamalg.c | 97 - lib/LuaJIT/src/lua.h | 402 -- lib/LuaJIT/src/lua.hpp | 9 - lib/LuaJIT/src/luaconf.h | 152 - lib/LuaJIT/src/luajit.c | 587 -- lib/LuaJIT/src/luajit.h | 79 - lib/LuaJIT/src/lualib.h | 43 - lib/LuaJIT/src/msvcbuild.bat | 122 - lib/LuaJIT/src/ps4build.bat | 123 - lib/LuaJIT/src/psvitabuild.bat | 93 - lib/LuaJIT/src/vm_arm.dasc | 4593 --------------- lib/LuaJIT/src/vm_arm64.dasc | 3988 ------------- lib/LuaJIT/src/vm_mips.dasc | 5264 ----------------- lib/LuaJIT/src/vm_mips64.dasc | 5112 ---------------- lib/LuaJIT/src/vm_ppc.dasc | 6053 ------------------- lib/LuaJIT/src/vm_x64.dasc | 4909 ---------------- lib/LuaJIT/src/vm_x86.dasc | 5780 ------------------ lib/LuaJIT/src/xb1build.bat | 101 - lib/LuaJIT/src/xedkbuild.bat | 92 - lib/libSOIL.a | Bin 121960 -> 0 bytes lib/libentityx.a | Bin 945228 -> 0 bytes lib/libluajit.a | Bin 866936 -> 0 bytes lib/luajit | 1 + 229 files changed, 24 insertions(+), 141531 deletions(-) delete mode 100644 lib/LuaJIT/.gitignore delete mode 100644 lib/LuaJIT/COPYRIGHT delete mode 100644 lib/LuaJIT/Makefile delete mode 100644 lib/LuaJIT/README delete mode 100644 lib/LuaJIT/doc/bluequad-print.css delete mode 100644 lib/LuaJIT/doc/bluequad.css delete mode 100644 lib/LuaJIT/doc/changes.html delete mode 100644 lib/LuaJIT/doc/contact.html delete mode 100644 lib/LuaJIT/doc/ext_c_api.html delete mode 100644 lib/LuaJIT/doc/ext_ffi.html delete mode 100644 lib/LuaJIT/doc/ext_ffi_api.html delete mode 100644 lib/LuaJIT/doc/ext_ffi_semantics.html delete mode 100644 lib/LuaJIT/doc/ext_ffi_tutorial.html delete mode 100644 lib/LuaJIT/doc/ext_jit.html delete mode 100644 lib/LuaJIT/doc/ext_profiler.html delete mode 100644 lib/LuaJIT/doc/extensions.html delete mode 100644 lib/LuaJIT/doc/faq.html delete mode 100644 lib/LuaJIT/doc/img/contact.png delete mode 100644 lib/LuaJIT/doc/install.html delete mode 100644 lib/LuaJIT/doc/luajit.html delete mode 100644 lib/LuaJIT/doc/running.html delete mode 100644 lib/LuaJIT/doc/status.html delete mode 100644 lib/LuaJIT/dynasm/dasm_arm.h delete mode 100644 lib/LuaJIT/dynasm/dasm_arm.lua delete mode 100644 lib/LuaJIT/dynasm/dasm_arm64.h delete mode 100644 lib/LuaJIT/dynasm/dasm_arm64.lua delete mode 100644 lib/LuaJIT/dynasm/dasm_mips.h delete mode 100644 lib/LuaJIT/dynasm/dasm_mips.lua delete mode 100644 lib/LuaJIT/dynasm/dasm_mips64.lua delete mode 100644 lib/LuaJIT/dynasm/dasm_ppc.h delete mode 100644 lib/LuaJIT/dynasm/dasm_ppc.lua delete mode 100644 lib/LuaJIT/dynasm/dasm_proto.h delete mode 100644 lib/LuaJIT/dynasm/dasm_x64.lua delete mode 100644 lib/LuaJIT/dynasm/dasm_x86.h delete mode 100644 lib/LuaJIT/dynasm/dasm_x86.lua delete mode 100644 lib/LuaJIT/dynasm/dynasm.lua delete mode 100644 lib/LuaJIT/etc/luajit.1 delete mode 100644 lib/LuaJIT/etc/luajit.pc delete mode 100644 lib/LuaJIT/src/.gitignore delete mode 100644 lib/LuaJIT/src/Makefile delete mode 100644 lib/LuaJIT/src/Makefile.dep delete mode 100644 lib/LuaJIT/src/host/.gitignore delete mode 100644 lib/LuaJIT/src/host/README delete mode 100644 lib/LuaJIT/src/host/buildvm.c delete mode 100644 lib/LuaJIT/src/host/buildvm.h delete mode 100644 lib/LuaJIT/src/host/buildvm_asm.c delete mode 100644 lib/LuaJIT/src/host/buildvm_fold.c delete mode 100644 lib/LuaJIT/src/host/buildvm_lib.c delete mode 100644 lib/LuaJIT/src/host/buildvm_libbc.h delete mode 100644 lib/LuaJIT/src/host/buildvm_peobj.c delete mode 100644 lib/LuaJIT/src/host/genlibbc.lua delete mode 100644 lib/LuaJIT/src/host/genminilua.lua delete mode 100644 lib/LuaJIT/src/host/minilua.c delete mode 100644 lib/LuaJIT/src/jit/.gitignore delete mode 100644 lib/LuaJIT/src/jit/bc.lua delete mode 100644 lib/LuaJIT/src/jit/bcsave.lua delete mode 100644 lib/LuaJIT/src/jit/dis_arm.lua delete mode 100644 lib/LuaJIT/src/jit/dis_arm64.lua delete mode 100644 lib/LuaJIT/src/jit/dis_arm64be.lua delete mode 100644 lib/LuaJIT/src/jit/dis_mips.lua delete mode 100644 lib/LuaJIT/src/jit/dis_mips64.lua delete mode 100644 lib/LuaJIT/src/jit/dis_mips64el.lua delete mode 100644 lib/LuaJIT/src/jit/dis_mipsel.lua delete mode 100644 lib/LuaJIT/src/jit/dis_ppc.lua delete mode 100644 lib/LuaJIT/src/jit/dis_x64.lua delete mode 100644 lib/LuaJIT/src/jit/dis_x86.lua delete mode 100644 lib/LuaJIT/src/jit/dump.lua delete mode 100644 lib/LuaJIT/src/jit/p.lua delete mode 100644 lib/LuaJIT/src/jit/v.lua delete mode 100644 lib/LuaJIT/src/jit/zone.lua delete mode 100644 lib/LuaJIT/src/lauxlib.h delete mode 100644 lib/LuaJIT/src/lib_aux.c delete mode 100644 lib/LuaJIT/src/lib_base.c delete mode 100644 lib/LuaJIT/src/lib_bit.c delete mode 100644 lib/LuaJIT/src/lib_debug.c delete mode 100644 lib/LuaJIT/src/lib_ffi.c delete mode 100644 lib/LuaJIT/src/lib_init.c delete mode 100644 lib/LuaJIT/src/lib_io.c delete mode 100644 lib/LuaJIT/src/lib_jit.c delete mode 100644 lib/LuaJIT/src/lib_math.c delete mode 100644 lib/LuaJIT/src/lib_os.c delete mode 100644 lib/LuaJIT/src/lib_package.c delete mode 100644 lib/LuaJIT/src/lib_string.c delete mode 100644 lib/LuaJIT/src/lib_table.c delete mode 100644 lib/LuaJIT/src/lj.supp delete mode 100644 lib/LuaJIT/src/lj_alloc.c delete mode 100644 lib/LuaJIT/src/lj_alloc.h delete mode 100644 lib/LuaJIT/src/lj_api.c delete mode 100644 lib/LuaJIT/src/lj_arch.h delete mode 100644 lib/LuaJIT/src/lj_asm.c delete mode 100644 lib/LuaJIT/src/lj_asm.h delete mode 100644 lib/LuaJIT/src/lj_asm_arm.h delete mode 100644 lib/LuaJIT/src/lj_asm_arm64.h delete mode 100644 lib/LuaJIT/src/lj_asm_mips.h delete mode 100644 lib/LuaJIT/src/lj_asm_ppc.h delete mode 100644 lib/LuaJIT/src/lj_asm_x86.h delete mode 100644 lib/LuaJIT/src/lj_bc.c delete mode 100644 lib/LuaJIT/src/lj_bc.h delete mode 100644 lib/LuaJIT/src/lj_bcdump.h delete mode 100644 lib/LuaJIT/src/lj_bcread.c delete mode 100644 lib/LuaJIT/src/lj_bcwrite.c delete mode 100644 lib/LuaJIT/src/lj_buf.c delete mode 100644 lib/LuaJIT/src/lj_buf.h delete mode 100644 lib/LuaJIT/src/lj_carith.c delete mode 100644 lib/LuaJIT/src/lj_carith.h delete mode 100644 lib/LuaJIT/src/lj_ccall.c delete mode 100644 lib/LuaJIT/src/lj_ccall.h delete mode 100644 lib/LuaJIT/src/lj_ccallback.c delete mode 100644 lib/LuaJIT/src/lj_ccallback.h delete mode 100644 lib/LuaJIT/src/lj_cconv.c delete mode 100644 lib/LuaJIT/src/lj_cconv.h delete mode 100644 lib/LuaJIT/src/lj_cdata.c delete mode 100644 lib/LuaJIT/src/lj_cdata.h delete mode 100644 lib/LuaJIT/src/lj_char.c delete mode 100644 lib/LuaJIT/src/lj_char.h delete mode 100644 lib/LuaJIT/src/lj_clib.c delete mode 100644 lib/LuaJIT/src/lj_clib.h delete mode 100644 lib/LuaJIT/src/lj_cparse.c delete mode 100644 lib/LuaJIT/src/lj_cparse.h delete mode 100644 lib/LuaJIT/src/lj_crecord.c delete mode 100644 lib/LuaJIT/src/lj_crecord.h delete mode 100644 lib/LuaJIT/src/lj_ctype.c delete mode 100644 lib/LuaJIT/src/lj_ctype.h delete mode 100644 lib/LuaJIT/src/lj_debug.c delete mode 100644 lib/LuaJIT/src/lj_debug.h delete mode 100644 lib/LuaJIT/src/lj_def.h delete mode 100644 lib/LuaJIT/src/lj_dispatch.c delete mode 100644 lib/LuaJIT/src/lj_dispatch.h delete mode 100644 lib/LuaJIT/src/lj_emit_arm.h delete mode 100644 lib/LuaJIT/src/lj_emit_arm64.h delete mode 100644 lib/LuaJIT/src/lj_emit_mips.h delete mode 100644 lib/LuaJIT/src/lj_emit_ppc.h delete mode 100644 lib/LuaJIT/src/lj_emit_x86.h delete mode 100644 lib/LuaJIT/src/lj_err.c delete mode 100644 lib/LuaJIT/src/lj_err.h delete mode 100644 lib/LuaJIT/src/lj_errmsg.h delete mode 100644 lib/LuaJIT/src/lj_ff.h delete mode 100644 lib/LuaJIT/src/lj_ffrecord.c delete mode 100644 lib/LuaJIT/src/lj_ffrecord.h delete mode 100644 lib/LuaJIT/src/lj_frame.h delete mode 100644 lib/LuaJIT/src/lj_func.c delete mode 100644 lib/LuaJIT/src/lj_func.h delete mode 100644 lib/LuaJIT/src/lj_gc.c delete mode 100644 lib/LuaJIT/src/lj_gc.h delete mode 100644 lib/LuaJIT/src/lj_gdbjit.c delete mode 100644 lib/LuaJIT/src/lj_gdbjit.h delete mode 100644 lib/LuaJIT/src/lj_ir.c delete mode 100644 lib/LuaJIT/src/lj_ir.h delete mode 100644 lib/LuaJIT/src/lj_ircall.h delete mode 100644 lib/LuaJIT/src/lj_iropt.h delete mode 100644 lib/LuaJIT/src/lj_jit.h delete mode 100644 lib/LuaJIT/src/lj_lex.c delete mode 100644 lib/LuaJIT/src/lj_lex.h delete mode 100644 lib/LuaJIT/src/lj_lib.c delete mode 100644 lib/LuaJIT/src/lj_lib.h delete mode 100644 lib/LuaJIT/src/lj_load.c delete mode 100644 lib/LuaJIT/src/lj_mcode.c delete mode 100644 lib/LuaJIT/src/lj_mcode.h delete mode 100644 lib/LuaJIT/src/lj_meta.c delete mode 100644 lib/LuaJIT/src/lj_meta.h delete mode 100644 lib/LuaJIT/src/lj_obj.c delete mode 100644 lib/LuaJIT/src/lj_obj.h delete mode 100644 lib/LuaJIT/src/lj_opt_dce.c delete mode 100644 lib/LuaJIT/src/lj_opt_fold.c delete mode 100644 lib/LuaJIT/src/lj_opt_loop.c delete mode 100644 lib/LuaJIT/src/lj_opt_mem.c delete mode 100644 lib/LuaJIT/src/lj_opt_narrow.c delete mode 100644 lib/LuaJIT/src/lj_opt_sink.c delete mode 100644 lib/LuaJIT/src/lj_opt_split.c delete mode 100644 lib/LuaJIT/src/lj_parse.c delete mode 100644 lib/LuaJIT/src/lj_parse.h delete mode 100644 lib/LuaJIT/src/lj_profile.c delete mode 100644 lib/LuaJIT/src/lj_profile.h delete mode 100644 lib/LuaJIT/src/lj_record.c delete mode 100644 lib/LuaJIT/src/lj_record.h delete mode 100644 lib/LuaJIT/src/lj_snap.c delete mode 100644 lib/LuaJIT/src/lj_snap.h delete mode 100644 lib/LuaJIT/src/lj_state.c delete mode 100644 lib/LuaJIT/src/lj_state.h delete mode 100644 lib/LuaJIT/src/lj_str.c delete mode 100644 lib/LuaJIT/src/lj_str.h delete mode 100644 lib/LuaJIT/src/lj_strfmt.c delete mode 100644 lib/LuaJIT/src/lj_strfmt.h delete mode 100644 lib/LuaJIT/src/lj_strfmt_num.c delete mode 100644 lib/LuaJIT/src/lj_strscan.c delete mode 100644 lib/LuaJIT/src/lj_strscan.h delete mode 100644 lib/LuaJIT/src/lj_tab.c delete mode 100644 lib/LuaJIT/src/lj_tab.h delete mode 100644 lib/LuaJIT/src/lj_target.h delete mode 100644 lib/LuaJIT/src/lj_target_arm.h delete mode 100644 lib/LuaJIT/src/lj_target_arm64.h delete mode 100644 lib/LuaJIT/src/lj_target_mips.h delete mode 100644 lib/LuaJIT/src/lj_target_ppc.h delete mode 100644 lib/LuaJIT/src/lj_target_x86.h delete mode 100644 lib/LuaJIT/src/lj_trace.c delete mode 100644 lib/LuaJIT/src/lj_trace.h delete mode 100644 lib/LuaJIT/src/lj_traceerr.h delete mode 100644 lib/LuaJIT/src/lj_udata.c delete mode 100644 lib/LuaJIT/src/lj_udata.h delete mode 100644 lib/LuaJIT/src/lj_vm.h delete mode 100644 lib/LuaJIT/src/lj_vmevent.c delete mode 100644 lib/LuaJIT/src/lj_vmevent.h delete mode 100644 lib/LuaJIT/src/lj_vmmath.c delete mode 100644 lib/LuaJIT/src/ljamalg.c delete mode 100644 lib/LuaJIT/src/lua.h delete mode 100644 lib/LuaJIT/src/lua.hpp delete mode 100644 lib/LuaJIT/src/luaconf.h delete mode 100644 lib/LuaJIT/src/luajit.c delete mode 100644 lib/LuaJIT/src/luajit.h delete mode 100644 lib/LuaJIT/src/lualib.h delete mode 100644 lib/LuaJIT/src/msvcbuild.bat delete mode 100644 lib/LuaJIT/src/ps4build.bat delete mode 100644 lib/LuaJIT/src/psvitabuild.bat delete mode 100644 lib/LuaJIT/src/vm_arm.dasc delete mode 100644 lib/LuaJIT/src/vm_arm64.dasc delete mode 100644 lib/LuaJIT/src/vm_mips.dasc delete mode 100644 lib/LuaJIT/src/vm_mips64.dasc delete mode 100644 lib/LuaJIT/src/vm_ppc.dasc delete mode 100644 lib/LuaJIT/src/vm_x64.dasc delete mode 100644 lib/LuaJIT/src/vm_x86.dasc delete mode 100644 lib/LuaJIT/src/xb1build.bat delete mode 100644 lib/LuaJIT/src/xedkbuild.bat delete mode 100644 lib/libSOIL.a delete mode 100644 lib/libentityx.a delete mode 100644 lib/libluajit.a create mode 160000 lib/luajit diff --git a/.gitignore b/.gitignore index 3435d00..45c80fb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ main out -.*.swp -.*.swo +.*sw* +*.a *.o *.json TODOS diff --git a/.gitmodules b/.gitmodules index e2f5cf7..911085e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -8,3 +8,6 @@ [submodule "lib/cereal"] path = lib/cereal url = https://github.com/USCiLab/cereal +[submodule "lib/luajit"] + path = lib/luajit + url = https://luajit.org/git/luajit.git diff --git a/Makefile b/Makefile index 23f522e..db7c130 100644 --- a/Makefile +++ b/Makefile @@ -37,15 +37,14 @@ DEPEXT = d LIBDIR = lib LIBS = -L$(LIBDIR) -lSDL2 -lpthread -lentityx -lluajit -ldl -lGLEW -lGL \ - -lSDL2_image -lSOIL -lfreetype -lopenal -lalut + -lSDL2_image -lsoil -lfreetype -lopenal -lalut CXXFLAGS = -ggdb -std=c++17 -Wall -Wextra -Werror -pedantic \ - -Wno-class-memaccess -Wno-implicit-fallthrough -Wno-unused-parameter + -Wno-class-memaccess -Wno-implicit-fallthrough -Wno-unused-parameter CXXINCS = -I$(SRCDIR) \ -I$(LIBDIR)/entityx \ - -I$(LIBDIR)/LuaJIT/src \ - -I$(LIBDIR)/LuaBridge/Source \ + -I$(LIBDIR)/luajit/src \ -I$(LIBDIR)/sol2/include \ -I$(LIBDIR)/soil \ -I$(LIBDIR)/cereal/include \ @@ -69,11 +68,11 @@ directories: clean: @echo " CLEAN" @$(RM) -rf $(OUTDIR) + @$(RM) -f lib/libentityx.a lib/libluajit.a lib/libsoil.a cleaner: clean -#@$(RM) -rf $(EXECDIR) -$(EXEC): $(CXXOBJ) +$(EXEC): lib/libentityx.a lib/libluajit.a lib/libsoil.a $(CXXOBJ) @echo " CXX " $(EXEC) @$(CXX) -o $(EXECDIR)/$(EXEC) $^ $(LIBS) @@ -87,5 +86,18 @@ $(OUTDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT) @sed -e 's/.*://' -e 's/\\$$//' < $(OUTDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(OUTDIR)/$*.$(DEPEXT) @rm -f $(OUTDIR)/$*.$(DEPEXT).tmp +lib/libentityx.a: + @cmake lib/entityx -DENTITYX_BUILD_SHARED=FALSE + @make -Clib/entityx -j4 entityx + @cp lib/entityx/libentityx.a lib/libentityx.a + +lib/libluajit.a: + @make -Clib/luajit -j4 + @cp lib/luajit/src/libluajit.a lib/libluajit.a + +lib/libsoil.a: + @gcc -c lib/soil/soil/*.c + @ar rcs lib/libsoil.a lib/soil/soil/*.o + .PHONY: all remake clean cleaner resources diff --git a/lib/LuaJIT/.gitignore b/lib/LuaJIT/.gitignore deleted file mode 100644 index 1a07bf7..0000000 --- a/lib/LuaJIT/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -*.[oa] -*.so -*.obj -*.lib -*.exp -*.dll -*.exe -*.manifest -*.dmp -*.swp -.tags diff --git a/lib/LuaJIT/COPYRIGHT b/lib/LuaJIT/COPYRIGHT deleted file mode 100644 index 6ed4002..0000000 --- a/lib/LuaJIT/COPYRIGHT +++ /dev/null @@ -1,56 +0,0 @@ -=============================================================================== -LuaJIT -- a Just-In-Time Compiler for Lua. http://luajit.org/ - -Copyright (C) 2005-2017 Mike Pall. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -[ MIT license: http://www.opensource.org/licenses/mit-license.php ] - -=============================================================================== -[ LuaJIT includes code from Lua 5.1/5.2, which has this license statement: ] - -Copyright (C) 1994-2012 Lua.org, PUC-Rio. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -=============================================================================== -[ LuaJIT includes code from dlmalloc, which has this license statement: ] - -This is a version (aka dlmalloc) of malloc/free/realloc written by -Doug Lea and released to the public domain, as explained at -http://creativecommons.org/licenses/publicdomain - -=============================================================================== diff --git a/lib/LuaJIT/Makefile b/lib/LuaJIT/Makefile deleted file mode 100644 index 0f93308..0000000 --- a/lib/LuaJIT/Makefile +++ /dev/null @@ -1,166 +0,0 @@ -############################################################################## -# LuaJIT top level Makefile for installation. Requires GNU Make. -# -# Please read doc/install.html before changing any variables! -# -# Suitable for POSIX platforms (Linux, *BSD, OSX etc.). -# Note: src/Makefile has many more configurable options. -# -# ##### This Makefile is NOT useful for Windows! ##### -# For MSVC, please follow the instructions given in src/msvcbuild.bat. -# For MinGW and Cygwin, cd to src and run make with the Makefile there. -# -# Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -############################################################################## - -MAJVER= 2 -MINVER= 1 -RELVER= 0 -PREREL= -beta3 -VERSION= $(MAJVER).$(MINVER).$(RELVER)$(PREREL) -ABIVER= 5.1 - -############################################################################## -# -# Change the installation path as needed. This automatically adjusts -# the paths in src/luaconf.h, too. Note: PREFIX must be an absolute path! -# -export PREFIX= /usr/local -export MULTILIB= lib -############################################################################## - -DPREFIX= $(DESTDIR)$(PREFIX) -INSTALL_BIN= $(DPREFIX)/bin -INSTALL_LIB= $(DPREFIX)/$(MULTILIB) -INSTALL_SHARE= $(DPREFIX)/share -INSTALL_INC= $(DPREFIX)/include/luajit-$(MAJVER).$(MINVER) - -INSTALL_LJLIBD= $(INSTALL_SHARE)/luajit-$(VERSION) -INSTALL_JITLIB= $(INSTALL_LJLIBD)/jit -INSTALL_LMODD= $(INSTALL_SHARE)/lua -INSTALL_LMOD= $(INSTALL_LMODD)/$(ABIVER) -INSTALL_CMODD= $(INSTALL_LIB)/lua -INSTALL_CMOD= $(INSTALL_CMODD)/$(ABIVER) -INSTALL_MAN= $(INSTALL_SHARE)/man/man1 -INSTALL_PKGCONFIG= $(INSTALL_LIB)/pkgconfig - -INSTALL_TNAME= luajit-$(VERSION) -INSTALL_TSYMNAME= luajit -INSTALL_ANAME= libluajit-$(ABIVER).a -INSTALL_SOSHORT1= libluajit-$(ABIVER).so -INSTALL_SOSHORT2= libluajit-$(ABIVER).so.$(MAJVER) -INSTALL_SONAME= $(INSTALL_SOSHORT2).$(MINVER).$(RELVER) -INSTALL_DYLIBSHORT1= libluajit-$(ABIVER).dylib -INSTALL_DYLIBSHORT2= libluajit-$(ABIVER).$(MAJVER).dylib -INSTALL_DYLIBNAME= libluajit-$(ABIVER).$(MAJVER).$(MINVER).$(RELVER).dylib -INSTALL_PCNAME= luajit.pc - -INSTALL_STATIC= $(INSTALL_LIB)/$(INSTALL_ANAME) -INSTALL_DYN= $(INSTALL_LIB)/$(INSTALL_SONAME) -INSTALL_SHORT1= $(INSTALL_LIB)/$(INSTALL_SOSHORT1) -INSTALL_SHORT2= $(INSTALL_LIB)/$(INSTALL_SOSHORT2) -INSTALL_T= $(INSTALL_BIN)/$(INSTALL_TNAME) -INSTALL_TSYM= $(INSTALL_BIN)/$(INSTALL_TSYMNAME) -INSTALL_PC= $(INSTALL_PKGCONFIG)/$(INSTALL_PCNAME) - -INSTALL_DIRS= $(INSTALL_BIN) $(INSTALL_LIB) $(INSTALL_INC) $(INSTALL_MAN) \ - $(INSTALL_PKGCONFIG) $(INSTALL_JITLIB) $(INSTALL_LMOD) $(INSTALL_CMOD) -UNINSTALL_DIRS= $(INSTALL_JITLIB) $(INSTALL_LJLIBD) $(INSTALL_INC) \ - $(INSTALL_LMOD) $(INSTALL_LMODD) $(INSTALL_CMOD) $(INSTALL_CMODD) - -RM= rm -f -MKDIR= mkdir -p -RMDIR= rmdir 2>/dev/null -SYMLINK= ln -sf -INSTALL_X= install -m 0755 -INSTALL_F= install -m 0644 -UNINSTALL= $(RM) -LDCONFIG= ldconfig -n -SED_PC= sed -e "s|^prefix=.*|prefix=$(PREFIX)|" \ - -e "s|^multilib=.*|multilib=$(MULTILIB)|" - -FILE_T= luajit -FILE_A= libluajit.a -FILE_SO= libluajit.so -FILE_MAN= luajit.1 -FILE_PC= luajit.pc -FILES_INC= lua.h lualib.h lauxlib.h luaconf.h lua.hpp luajit.h -FILES_JITLIB= bc.lua bcsave.lua dump.lua p.lua v.lua zone.lua \ - dis_x86.lua dis_x64.lua dis_arm.lua dis_arm64.lua \ - dis_arm64be.lua dis_ppc.lua dis_mips.lua dis_mipsel.lua \ - dis_mips64.lua dis_mips64el.lua vmdef.lua - -ifeq (,$(findstring Windows,$(OS))) - HOST_SYS:= $(shell uname -s) -else - HOST_SYS= Windows -endif -TARGET_SYS?= $(HOST_SYS) - -ifeq (Darwin,$(TARGET_SYS)) - INSTALL_SONAME= $(INSTALL_DYLIBNAME) - INSTALL_SOSHORT1= $(INSTALL_DYLIBSHORT1) - INSTALL_SOSHORT2= $(INSTALL_DYLIBSHORT2) - LDCONFIG= : -endif - -############################################################################## - -INSTALL_DEP= src/luajit - -default all $(INSTALL_DEP): - @echo "==== Building LuaJIT $(VERSION) ====" - $(MAKE) -C src - @echo "==== Successfully built LuaJIT $(VERSION) ====" - -install: $(INSTALL_DEP) - @echo "==== Installing LuaJIT $(VERSION) to $(PREFIX) ====" - $(MKDIR) $(INSTALL_DIRS) - cd src && $(INSTALL_X) $(FILE_T) $(INSTALL_T) - cd src && test -f $(FILE_A) && $(INSTALL_F) $(FILE_A) $(INSTALL_STATIC) || : - $(RM) $(INSTALL_DYN) $(INSTALL_SHORT1) $(INSTALL_SHORT2) - cd src && test -f $(FILE_SO) && \ - $(INSTALL_X) $(FILE_SO) $(INSTALL_DYN) && \ - $(LDCONFIG) $(INSTALL_LIB) && \ - $(SYMLINK) $(INSTALL_SONAME) $(INSTALL_SHORT1) && \ - $(SYMLINK) $(INSTALL_SONAME) $(INSTALL_SHORT2) || : - cd etc && $(INSTALL_F) $(FILE_MAN) $(INSTALL_MAN) - cd etc && $(SED_PC) $(FILE_PC) > $(FILE_PC).tmp && \ - $(INSTALL_F) $(FILE_PC).tmp $(INSTALL_PC) && \ - $(RM) $(FILE_PC).tmp - cd src && $(INSTALL_F) $(FILES_INC) $(INSTALL_INC) - cd src/jit && $(INSTALL_F) $(FILES_JITLIB) $(INSTALL_JITLIB) - @echo "==== Successfully installed LuaJIT $(VERSION) to $(PREFIX) ====" - @echo "" - @echo "Note: the development releases deliberately do NOT install a symlink for luajit" - @echo "You can do this now by running this command (with sudo):" - @echo "" - @echo " $(SYMLINK) $(INSTALL_TNAME) $(INSTALL_TSYM)" - @echo "" - - -uninstall: - @echo "==== Uninstalling LuaJIT $(VERSION) from $(PREFIX) ====" - $(UNINSTALL) $(INSTALL_T) $(INSTALL_STATIC) $(INSTALL_DYN) $(INSTALL_SHORT1) $(INSTALL_SHORT2) $(INSTALL_MAN)/$(FILE_MAN) $(INSTALL_PC) - for file in $(FILES_JITLIB); do \ - $(UNINSTALL) $(INSTALL_JITLIB)/$$file; \ - done - for file in $(FILES_INC); do \ - $(UNINSTALL) $(INSTALL_INC)/$$file; \ - done - $(LDCONFIG) $(INSTALL_LIB) - $(RMDIR) $(UNINSTALL_DIRS) || : - @echo "==== Successfully uninstalled LuaJIT $(VERSION) from $(PREFIX) ====" - -############################################################################## - -amalg: - @echo "Building LuaJIT $(VERSION)" - $(MAKE) -C src amalg - -clean: - $(MAKE) -C src clean - -.PHONY: all install amalg clean - -############################################################################## diff --git a/lib/LuaJIT/README b/lib/LuaJIT/README deleted file mode 100644 index 2b9ae9d..0000000 --- a/lib/LuaJIT/README +++ /dev/null @@ -1,16 +0,0 @@ -README for LuaJIT 2.1.0-beta3 ------------------------------ - -LuaJIT is a Just-In-Time (JIT) compiler for the Lua programming language. - -Project Homepage: http://luajit.org/ - -LuaJIT is Copyright (C) 2005-2017 Mike Pall. -LuaJIT is free software, released under the MIT license. -See full Copyright Notice in the COPYRIGHT file or in luajit.h. - -Documentation for LuaJIT is available in HTML format. -Please point your favorite browser to: - - doc/luajit.html - diff --git a/lib/LuaJIT/doc/bluequad-print.css b/lib/LuaJIT/doc/bluequad-print.css deleted file mode 100644 index d5a3ea3..0000000 --- a/lib/LuaJIT/doc/bluequad-print.css +++ /dev/null @@ -1,166 +0,0 @@ -/* Copyright (C) 2004-2018 Mike Pall. - * - * You are welcome to use the general ideas of this design for your own sites. - * But please do not steal the stylesheet, the layout or the color scheme. - */ -body { - font-family: serif; - font-size: 11pt; - margin: 0 3em; - padding: 0; - border: none; -} -a:link, a:visited, a:hover, a:active { - text-decoration: none; - background: transparent; - color: #0000ff; -} -h1, h2, h3 { - font-family: sans-serif; - font-weight: bold; - text-align: left; - margin: 0.5em 0; - padding: 0; -} -h1 { - font-size: 200%; -} -h2 { - font-size: 150%; -} -h3 { - font-size: 125%; -} -p { - margin: 0 0 0.5em 0; - padding: 0; -} -ul, ol { - margin: 0.5em 0; - padding: 0 0 0 2em; -} -ul { - list-style: outside square; -} -ol { - list-style: outside decimal; -} -li { - margin: 0; - padding: 0; -} -dl { - margin: 1em 0; - padding: 1em; - border: 1px solid black; -} -dt { - font-weight: bold; - margin: 0; - padding: 0; -} -dt sup { - float: right; - margin-left: 1em; -} -dd { - margin: 0.5em 0 0 2em; - padding: 0; -} -table { - table-layout: fixed; - width: 100%; - margin: 1em 0; - padding: 0; - border: 1px solid black; - border-spacing: 0; - border-collapse: collapse; -} -tr { - margin: 0; - padding: 0; - border: none; -} -td { - text-align: left; - margin: 0; - padding: 0.2em 0.5em; - border-top: 1px solid black; - border-bottom: 1px solid black; -} -tr.separate td { - border-top: double; -} -tt, pre, code, kbd, samp { - font-family: monospace; - font-size: 75%; -} -kbd { - font-weight: bolder; -} -blockquote, pre { - margin: 1em 2em; - padding: 0; -} -img { - border: none; - vertical-align: baseline; - margin: 0; - padding: 0; -} -img.left { - float: left; - margin: 0.5em 1em 0.5em 0; -} -img.right { - float: right; - margin: 0.5em 0 0.5em 1em; -} -.flush { - clear: both; - visibility: hidden; -} -.hide, .noprint, #nav { - display: none !important; -} -.pagebreak { - page-break-before: always; -} -#site { - text-align: right; - font-family: sans-serif; - font-weight: bold; - margin: 0 1em; - border-bottom: 1pt solid black; -} -#site a { - font-size: 1.2em; -} -#site a:link, #site a:visited { - text-decoration: none; - font-weight: bold; - background: transparent; - color: #ffffff; -} -#logo { - color: #ff8000; -} -#head { - clear: both; - margin: 0 1em; -} -#main { - line-height: 1.3; - text-align: justify; - margin: 1em; -} -#foot { - clear: both; - font-size: 80%; - text-align: center; - margin: 0 1.25em; - padding: 0.5em 0 0 0; - border-top: 1pt solid black; - page-break-before: avoid; - page-break-after: avoid; -} diff --git a/lib/LuaJIT/doc/bluequad.css b/lib/LuaJIT/doc/bluequad.css deleted file mode 100644 index cfc889a..0000000 --- a/lib/LuaJIT/doc/bluequad.css +++ /dev/null @@ -1,325 +0,0 @@ -/* Copyright (C) 2004-2018 Mike Pall. - * - * You are welcome to use the general ideas of this design for your own sites. - * But please do not steal the stylesheet, the layout or the color scheme. - */ -/* colorscheme: - * - * site | head #4162bf/white | #6078bf/#e6ecff - * ------+------ ----------------+------------------- - * nav | main #bfcfff | #e6ecff/black - * - * nav: hiback loback #c5d5ff #b9c9f9 - * hiborder loborder #e6ecff #97a7d7 - * link hover #2142bf #ff0000 - * - * link: link visited hover #2142bf #8122bf #ff0000 - * - * main: boxback boxborder #f0f4ff #bfcfff - */ -body { - font-family: Verdana, Arial, Helvetica, sans-serif; - font-size: 10pt; - margin: 0; - padding: 0; - border: none; - background: #e0e0e0; - color: #000000; -} -a:link { - text-decoration: none; - background: transparent; - color: #2142bf; -} -a:visited { - text-decoration: none; - background: transparent; - color: #8122bf; -} -a:hover, a:active { - text-decoration: underline; - background: transparent; - color: #ff0000; -} -h1, h2, h3 { - font-weight: bold; - text-align: left; - margin: 0.5em 0; - padding: 0; - background: transparent; -} -h1 { - font-size: 200%; - line-height: 3em; /* really 6em relative to body, match #site span */ - margin: 0; -} -h2 { - font-size: 150%; - color: #606060; -} -h3 { - font-size: 125%; - color: #404040; -} -p { - max-width: 600px; - margin: 0 0 0.5em 0; - padding: 0; -} -b { - color: #404040; -} -ul, ol { - max-width: 600px; - margin: 0.5em 0; - padding: 0 0 0 2em; -} -ul { - list-style: outside square; -} -ol { - list-style: outside decimal; -} -li { - margin: 0; - padding: 0; -} -dl { - max-width: 600px; - margin: 1em 0; - padding: 1em; - border: 1px solid #bfcfff; - background: #f0f4ff; -} -dt { - font-weight: bold; - margin: 0; - padding: 0; -} -dt sup { - float: right; - margin-left: 1em; - color: #808080; -} -dt a:visited { - text-decoration: none; - color: #2142bf; -} -dt a:hover, dt a:active { - text-decoration: none; - color: #ff0000; -} -dd { - margin: 0.5em 0 0 2em; - padding: 0; -} -div.tablewrap { /* for IE *sigh* */ - max-width: 600px; -} -table { - table-layout: fixed; - border-spacing: 0; - border-collapse: collapse; - max-width: 600px; - width: 100%; - margin: 1em 0; - padding: 0; - border: 1px solid #bfcfff; -} -tr { - margin: 0; - padding: 0; - border: none; -} -tr.odd { - background: #f0f4ff; -} -tr.separate td { - border-top: 1px solid #bfcfff; -} -td { - text-align: left; - margin: 0; - padding: 0.2em 0.5em; - border: none; -} -tt, code, kbd, samp { - font-family: Courier New, Courier, monospace; - line-height: 1.2; - font-size: 110%; -} -kbd { - font-weight: bolder; -} -blockquote, pre { - max-width: 600px; - margin: 1em 2em; - padding: 0; -} -pre { - line-height: 1.1; -} -pre.code { - line-height: 1.4; - margin: 0.5em 0 1em 0.5em; - padding: 0.5em 1em; - border: 1px solid #bfcfff; - background: #f0f4ff; -} -pre.mark { - padding-left: 2em; -} -span.codemark { - position:absolute; - left: 16em; - color: #4040c0; -} -span.mark { - color: #4040c0; - font-family: Courier New, Courier, monospace; - line-height: 1.1; -} -img { - border: none; - vertical-align: baseline; - margin: 0; - padding: 0; -} -img.left { - float: left; - margin: 0.5em 1em 0.5em 0; -} -img.right { - float: right; - margin: 0.5em 0 0.5em 1em; -} -.indent { - padding-left: 1em; -} -.flush { - clear: both; - visibility: hidden; -} -.hide, .noscreen { - display: none !important; -} -.ext { - color: #ff8000; -} -.new { - font-size: 6pt; - vertical-align: middle; - background: #ff8000; - color: #ffffff; -} -#site { - clear: both; - float: left; - width: 13em; - text-align: center; - font-weight: bold; - margin: 0; - padding: 0; - background: transparent; - color: #ffffff; -} -#site a { - font-size: 200%; -} -#site a:link, #site a:visited { - text-decoration: none; - font-weight: bold; - background: transparent; - color: #ffffff; -} -#site span { - line-height: 3em; /* really 6em relative to body, match h1 */ -} -#logo { - color: #ffb380; -} -#head { - margin: 0; - padding: 0 0 0 2em; - border-left: solid 13em #4162bf; - border-right: solid 3em #6078bf; - background: #6078bf; - color: #e6ecff; -} -#nav { - clear: both; - float: left; - overflow: hidden; - text-align: left; - line-height: 1.5; - width: 13em; - padding-top: 1em; - background: transparent; -} -#nav ul { - list-style: none outside; - margin: 0; - padding: 0; -} -#nav li { - margin: 0; - padding: 0; -} -#nav a { - display: block; - text-decoration: none; - font-weight: bold; - margin: 0; - padding: 2px 1em; - border-top: 1px solid transparent; - border-bottom: 1px solid transparent; - background: transparent; - color: #2142bf; -} -#nav a:hover, #nav a:active { - text-decoration: none; - border-top: 1px solid #97a7d7; - border-bottom: 1px solid #e6ecff; - background: #b9c9f9; - color: #ff0000; -} -#nav a.current, #nav a.current:hover, #nav a.current:active { - border-top: 1px solid #e6ecff; - border-bottom: 1px solid #97a7d7; - background: #c5d5ff; - color: #2142bf; -} -#nav ul ul a { - padding: 0 1em 0 1.7em; -} -#nav ul ul ul a { - padding: 0 0.5em 0 2.4em; -} -#main { - line-height: 1.5; - text-align: left; - margin: 0; - padding: 1em 2em; - border-left: solid 13em #bfcfff; - border-right: solid 3em #e6ecff; - background: #e6ecff; -} -#foot { - clear: both; - font-size: 80%; - text-align: center; - margin: 0; - padding: 0.5em; - background: #6078bf; - color: #ffffff; -} -#foot a:link, #foot a:visited { - text-decoration: underline; - background: transparent; - color: #ffffff; -} -#foot a:hover, #foot a:active { - text-decoration: underline; - background: transparent; - color: #bfcfff; -} diff --git a/lib/LuaJIT/doc/changes.html b/lib/LuaJIT/doc/changes.html deleted file mode 100644 index 1208ac8..0000000 --- a/lib/LuaJIT/doc/changes.html +++ /dev/null @@ -1,882 +0,0 @@ - - - -LuaJIT Change History - - - - - - - - -
-Lua -
- - -
-

-This is a list of changes between the released versions of LuaJIT.
-The current stable version is LuaJIT 2.0.5.
-

-

-Please check the -» Online Change History -to see whether newer versions are available. -

- -
-

LuaJIT 2.1.0-beta3 — 2017-05-01

-
    -
  • Rewrite memory block allocator.
  • -
  • Add various extension from Lua 5.2/5.3.
  • -
  • Remove old Lua 5.0 compatibility defines.
  • -
  • Set arg table before evaluating LUA_INIT and -e chunks.
  • -
  • Fix FOLD rules for math.abs() and FP negation.
  • -
  • Fix soft-float math.abs() and negation.
  • -
  • Fix formatting of some small denormals at low precision.
  • -
  • LJ_GC64: Add JIT compiler support.
  • -
  • x64/LJ_GC64: Add JIT compiler backend.
  • -
  • x86/x64: Generate BMI2 shifts and rotates, if available.
  • -
  • Windows/x86: Add full exception interoperability.
  • -
  • ARM64: Add big-endian support.
  • -
  • ARM64: Add JIT compiler backend.
  • -
  • MIPS: Fix TSETR barrier.
  • -
  • MIPS: Support MIPS16 interlinking.
  • -
  • MIPS soft-float: Fix code generation for HREF.
  • -
  • MIPS64: Add MIPS64 hard-float JIT compiler backend.
  • -
  • MIPS64: Add MIPS64 hard-float/soft-float support to interpreter.
  • -
  • FFI: Compile bitfield loads/stores.
  • -
  • Various fixes common with the 2.0 branch.
  • -
- -

LuaJIT 2.1.0-beta2 — 2016-03-03

-
    -
  • Enable trace stitching.
  • -
  • Use internal implementation for converting FP numbers to strings.
  • -
  • Parse Unicode escape '\u{XX...}' in string literals.
  • -
  • Add MIPS soft-float support.
  • -
  • Switch MIPS port to dual-number mode.
  • -
  • x86/x64: Add support for AES-NI, AVX and AVX2 to DynASM.
  • -
  • FFI: Add ssize_t declaration.
  • -
  • FFI: Parse #line NN and #NN.
  • -
  • Various minor fixes.
  • -
- -

LuaJIT 2.1.0-beta1 — 2015-08-25

-

-This is a brief summary of the major changes in LuaJIT 2.1 compared to 2.0. -Please take a look at the commit history for more details. -

-
    -
  • Changes to the VM core: -
      -
    • Add low-overhead profiler (-jp).
    • -
    • Add LJ_GC64 mode: 64 bit GC object references (really: 47 bit). Interpreter-only for now.
    • -
    • Add LJ_FR2 mode: Two-slot frame info. Required by LJ_GC64 mode.
    • -
    • Add table.new() and table.clear().
    • -
    • Parse binary number literals (0bxxx).
    • -
  • -
  • Improvements to the JIT compiler: -
      -
    • Add trace stitching (disabled for now).
    • -
    • Compile various builtins: string.char(), string.reverse(), string.lower(), string.upper(), string.rep(), string.format(), table.concat(), bit.tohex(), getfenv(0), debug.getmetatable().
    • -
    • Compile string.find() for fixed string searches (no patterns).
    • -
    • Compile BC_TSETM, e.g. {1,2,3,f()}.
    • -
    • Compile string concatenations (BC_CAT).
    • -
    • Compile __concat metamethod.
    • -
    • Various minor optimizations.
    • -
  • -
  • Internal Changes: -
      -
    • Add support for embedding LuaJIT bytecode for builtins.
    • -
    • Replace various builtins with embedded bytecode.
    • -
    • Refactor string buffers and string formatting.
    • -
    • Remove obsolete non-truncating number to integer conversions.
    • -
  • -
  • Ports: -
      -
    • Add Xbox One port (LJ_GC64 mode).
    • -
    • ARM64: Add port of the interpreter (LJ_GC64 mode).
    • -
    • x64: Add separate port of the interpreter to LJ_GC64 mode.
    • -
    • x86/x64: Drop internal x87 math functions. Use libm functions.
    • -
    • x86: Remove x87 support from interpreter. SSE2 is mandatory now.
    • -
    • PPC/e500: Drop support for this architecture.
    • -
  • -
  • FFI library: -
      -
    • FFI: Add 64 bit bitwise operations.
    • -
    • FFI: Compile VLA/VLS and large cdata allocations with default initialization.
    • -
    • FFI: Compile conversions from functions to function pointers.
    • -
    • FFI: Compile lightuserdata to void * conversion.
    • -
    • FFI: Compile ffi.gc(cdata, nil), too.
    • -
    • FFI: Add ffi.typeinfo().
    • -
  • -
-
- -
-

LuaJIT 2.0.5 — 2017-05-01

-
    -
  • Add workaround for MSVC 2015 stdio changes.
  • -
  • Limit mcode alloc probing, depending on the available pool size.
  • -
  • Fix overly restrictive range calculation in mcode allocation.
  • -
  • Fix out-of-scope goto handling in parser.
  • -
  • Remove internal __mode = "K" and replace with safe check.
  • -
  • Add "proto" field to jit.util.funcinfo().
  • -
  • Fix GC step size calculation.
  • -
  • Initialize uv->immutable for upvalues of loaded chunks.
  • -
  • Fix for cdata vs. non-cdata arithmetics/comparisons.
  • -
  • Drop leftover regs in 'for' iterator assignment, too.
  • -
  • Fix PHI remarking in SINK pass.
  • -
  • Don't try to record outermost pcall() return to lower frame.
  • -
  • Add guard for obscure aliasing between open upvalues and SSA slots.
  • -
  • Remove assumption that lj_math_random_step() doesn't clobber FPRs.
  • -
  • Fix handling of non-numeric strings in arithmetic coercions.
  • -
  • Fix recording of select(n, ...) with off-trace varargs
  • -
  • Fix install for cross-builds.
  • -
  • Don't allocate unused 2nd result register in JIT compiler backend.
  • -
  • Drop marks from replayed instructions when sinking.
  • -
  • Fix unsinking check.
  • -
  • Properly handle OOM in trace_save().
  • -
  • Limit number of arguments given to io.lines() and fp:lines().
  • -
  • Fix narrowing of TOBIT.
  • -
  • OSX: Fix build with recent XCode.
  • -
  • x86/x64: Don't spill an explicit REF_BASE in the IR.
  • -
  • x86/x64: Fix instruction length decoder.
  • -
  • x86/x64: Search for exit jumps with instruction length decoder.
  • -
  • ARM: Fix BLX encoding for Thumb interworking calls.
  • -
  • MIPS: Don't use RID_GP as a scratch register.
  • -
  • MIPS: Fix emitted code for U32 to float conversion.
  • -
  • MIPS: Backport workaround for compact unwind tables.
  • -
  • MIPS: Fix cross-endian jit.bcsave.
  • -
  • MIPS: Fix BC_ISNEXT fallback path.
  • -
  • MIPS: Fix use of ffgccheck delay slots in interpreter.
  • -
  • FFI: Fix FOLD rules for int64_t comparisons.
  • -
  • FFI: Fix SPLIT pass for CONV i64.u64.
  • -
  • FFI: Fix ipairs() recording.
  • -
  • FFI: Don't propagate qualifiers into subtypes of complex.
  • -
- -

LuaJIT 2.0.4 — 2015-05-14

-
    -
  • Fix stack check in narrowing optimization.
  • -
  • Fix Lua/C API typecheck error for special indexes.
  • -
  • Fix string to number conversion.
  • -
  • Fix lexer error for chunks without tokens.
  • -
  • Don't compile IR_RETF after CALLT to ff with-side effects.
  • -
  • Fix BC_UCLO/BC_JMP join optimization in Lua parser.
  • -
  • Fix corner case in string to number conversion.
  • -
  • Gracefully handle lua_error() for a suspended coroutine.
  • -
  • Avoid error messages when building with Clang.
  • -
  • Fix snapshot #0 handling for traces with a stack check on entry.
  • -
  • Fix fused constant loads under high register pressure.
  • -
  • Invalidate backpropagation cache after DCE.
  • -
  • Fix ABC elimination.
  • -
  • Fix debug info for main chunk of stripped bytecode.
  • -
  • Fix FOLD rule for string.sub(s, ...) == k.
  • -
  • Fix FOLD rule for STRREF of SNEW.
  • -
  • Fix frame traversal while searching for error function.
  • -
  • Prevent GC estimate miscalculation due to buffer growth.
  • -
  • Prevent adding side traces for stack checks.
  • -
  • Fix top slot calculation for snapshots with continuations.
  • -
  • Fix check for reuse of SCEV results in FORL.
  • -
  • Add PS Vita port.
  • -
  • Fix compatibility issues with Illumos.
  • -
  • Fix DragonFly build (unsupported).
  • -
  • OpenBSD/x86: Better executable memory allocation for W^X mode.
  • -
  • x86: Fix argument checks for ipairs() iterator.
  • -
  • x86: lj_math_random_step() clobbers XMM regs on OSX Clang.
  • -
  • x86: Fix code generation for unused result of math.random().
  • -
  • x64: Allow building with LUAJIT_USE_SYSMALLOC and LUAJIT_USE_VALGRIND.
  • -
  • x86/x64: Fix argument check for bit shifts.
  • -
  • x86/x64: Fix code generation for fused test/arith ops.
  • -
  • ARM: Fix write barrier check in BC_USETS.
  • -
  • PPC: Fix red zone overflow in machine code generation.
  • -
  • PPC: Don't use mcrxr on PPE.
  • -
  • Various archs: Fix excess stack growth in interpreter.
  • -
  • FFI: Fix FOLD rule for TOBIT + CONV num.u32.
  • -
  • FFI: Prevent DSE across ffi.string().
  • -
  • FFI: No meta fallback when indexing pointer to incomplete struct.
  • -
  • FFI: Fix initialization of unions of subtypes.
  • -
  • FFI: Fix cdata vs. non-cdata arithmetic and comparisons.
  • -
  • FFI: Fix __index/__newindex metamethod resolution for ctypes.
  • -
  • FFI: Fix compilation of reference field access.
  • -
  • FFI: Fix frame traversal for backtraces with FFI callbacks.
  • -
  • FFI: Fix recording of indexing a struct pointer ctype object itself.
  • -
  • FFI: Allow non-scalar cdata to be compared for equality by address.
  • -
  • FFI: Fix pseudo type conversions for type punning.
  • -
- -

LuaJIT 2.0.3 — 2014-03-12

-
    -
  • Add PS4 port.
  • -
  • Add support for multilib distro builds.
  • -
  • Fix OSX build.
  • -
  • Fix MinGW build.
  • -
  • Fix Xbox 360 build.
  • -
  • Improve ULOAD forwarding for open upvalues.
  • -
  • Fix GC steps threshold handling when called by JIT-compiled code.
  • -
  • Fix argument checks for math.deg() and math.rad().
  • -
  • Fix jit.flush(func|true).
  • -
  • Respect jit.off(func) when returning to a function, too.
  • -
  • Fix compilation of string.byte(s, nil, n).
  • -
  • Fix line number for relocated bytecode after closure fixup
  • -
  • Fix frame traversal for backtraces.
  • -
  • Fix ABC elimination.
  • -
  • Fix handling of redundant PHIs.
  • -
  • Fix snapshot restore for exit to function header.
  • -
  • Fix type punning alias analysis for constified pointers
  • -
  • Fix call unroll checks in the presence of metamethod frames.
  • -
  • Fix initial maxslot for down-recursive traces.
  • -
  • Prevent BASE register coalescing if parent uses IR_RETF.
  • -
  • Don't purge modified function from stack slots in BC_RET.
  • -
  • Fix recording of BC_VARG.
  • -
  • Don't access dangling reference to reallocated IR.
  • -
  • Fix frame depth display for bytecode dump in -jdump.
  • -
  • ARM: Fix register allocation when rematerializing FPRs.
  • -
  • x64: Fix store to upvalue for lightuserdata values.
  • -
  • FFI: Add missing GC steps for callback argument conversions.
  • -
  • FFI: Properly unload loaded DLLs.
  • -
  • FFI: Fix argument checks for ffi.string().
  • -
  • FFI/x64: Fix passing of vector arguments to calls.
  • -
  • FFI: Rehash finalizer table after GC cycle, if needed.
  • -
  • FFI: Fix cts->L for cdata unsinking in snapshot restore.
  • -
- -

LuaJIT 2.0.2 — 2013-06-03

-
    -
  • Fix memory access check for fast string interning.
  • -
  • Fix MSVC intrinsics for older versions.
  • -
  • Add missing GC steps for io.* functions.
  • -
  • Fix spurious red zone overflows in machine code generation.
  • -
  • Fix jump-range constrained mcode allocation.
  • -
  • Inhibit DSE for implicit loads via calls.
  • -
  • Fix builtin string to number conversion for overflow digits.
  • -
  • Fix optional argument handling while recording builtins.
  • -
  • Fix optional argument handling in table.concat().
  • -
  • Add partial support for building with MingW64 GCC 4.8-SEH.
  • -
  • Add missing PHI barrier to string.sub(str, a, b) == kstr FOLD rule.
  • -
  • Fix compatibility issues with Illumos.
  • -
  • ARM: Fix cache flush/sync for exit stubs of JIT-compiled code.
  • -
  • MIPS: Fix cache flush/sync for JIT-compiled code jump area.
  • -
  • PPC: Add plt suffix for external calls from assembler code.
  • -
  • FFI: Fix snapshot substitution in SPLIT pass.
  • -
  • FFI/x86: Fix register allocation for 64 bit comparisons.
  • -
  • FFI: Fix tailcall in lowest frame to C function with bool result.
  • -
  • FFI: Ignore long type specifier in ffi.istype().
  • -
  • FFI: Fix calling conventions for 32 bit OSX and iOS simulator (struct returns).
  • -
  • FFI: Fix calling conventions for ARM hard-float EABI (nested structs).
  • -
  • FFI: Improve error messages for arithmetic and comparison operators.
  • -
  • FFI: Insert no-op type conversion for pointer to integer cast.
  • -
  • FFI: Fix unroll limit for ffi.fill().
  • -
  • FFI: Must sink XBAR together with XSTOREs.
  • -
  • FFI: Preserve intermediate string for const char * conversion.
  • -
- -

LuaJIT 2.0.1 — 2013-02-19

-
    -
  • Don't clear frame for out-of-memory error.
  • -
  • Leave hook when resume catches error thrown from hook.
  • -
  • Add missing GC steps for template table creation.
  • -
  • Fix discharge order of comparisons in Lua parser.
  • -
  • Improve buffer handling for io.read().
  • -
  • OSX: Add support for Mach-O object files to -b option.
  • -
  • Fix PS3 port.
  • -
  • Fix/enable Xbox 360 port.
  • -
  • x86/x64: Always mark ref for shift count as non-weak.
  • -
  • x64: Don't fuse implicitly 32-to-64 extended operands.
  • -
  • ARM: Fix armhf call argument handling.
  • -
  • ARM: Fix code generation for integer math.min/math.max.
  • -
  • PPC/e500: Fix lj_vm_floor() for Inf/NaN.
  • -
  • FFI: Change priority of table initializer variants for structs.
  • -
  • FFI: Fix code generation for bool call result check on x86/x64.
  • -
  • FFI: Load FFI library on-demand for bytecode with cdata literals.
  • -
  • FFI: Fix handling of qualified transparent structs/unions.
  • -
- -

LuaJIT 2.0.0 — 2012-11-08

-
    -
  • Correctness and completeness: -
      -
    • Fix Android/x86 build.
    • -
    • Fix recording of equality comparisons with __eq metamethods.
    • -
    • Fix detection of immutable upvalues.
    • -
    • Replace error with PANIC for callbacks from JIT-compiled code.
    • -
    • Fix builtin string to number conversion for INT_MIN.
    • -
    • Don't create unneeded array part for template tables.
    • -
    • Fix CONV.num.int sinking.
    • -
    • Don't propagate implicitly widened number to index metamethods.
    • -
    • ARM: Fix ordered comparisons of number vs. non-number.
    • -
    • FFI: Fix code generation for replay of sunk float fields.
    • -
    • FFI: Fix signedness of bool.
    • -
    • FFI: Fix recording of bool call result check on x86/x64.
    • -
    • FFI: Fix stack-adjustment for __thiscall callbacks.
    • -
  • -
- -

LuaJIT 2.0.0-beta11 — 2012-10-16

-
    -
  • New features: -
      -
    • Use ARM VFP instructions, if available (build-time detection).
    • -
    • Add support for ARM hard-float EABI (armhf).
    • -
    • Add PS3 port.
    • -
    • Add many features from Lua 5.2, e.g. goto/labels. - Refer to this list.
    • -
    • FFI: Add parameterized C types.
    • -
    • FFI: Add support for copy constructors.
    • -
    • FFI: Equality comparisons never raise an error (treat as unequal instead).
    • -
    • FFI: Box all accessed or returned enums.
    • -
    • FFI: Check for __new metamethod when calling a constructor.
    • -
    • FFI: Handle __pairs/__ipairs metamethods for cdata objects.
    • -
    • FFI: Convert io.* file handle to FILE * pointer (but as a void *).
    • -
    • FFI: Detect and support type punning through unions.
    • -
    • FFI: Improve various error messages.
    • -
  • -
  • Build-system reorganization: -
      -
    • Reorganize directory layout:
      - lib/*src/jit/*
      - src/buildvm_*.dascsrc/vm_*.dasc
      - src/buildvm_*.h → removed
      - src/buildvm*src/host/*
    • -
    • Add minified Lua interpreter plus Lua BitOp (minilua) to run DynASM.
    • -
    • Change DynASM bit operations to use Lua BitOp
    • -
    • Translate only vm_*.dasc for detected target architecture.
    • -
    • Improve target detection for msvcbuild.bat.
    • -
    • Fix build issues on Cygwin and MinGW with optional MSys.
    • -
    • Handle cross-compiles with FPU/no-FPU or hard-fp/soft-fp ABI mismatch.
    • -
    • Remove some library functions for no-JIT/no-FFI builds.
    • -
    • Add uninstall target to top-level Makefile.
    • -
  • -
  • Correctness and completeness: -
      -
    • Preserve snapshot #0 PC for all traces.
    • -
    • Fix argument checks for coroutine.create().
    • -
    • Command line prints version and JIT status to stdout, not stderr.
    • -
    • Fix userdata __gc separations at Lua state close.
    • -
    • Fix TDUP to HLOAD forwarding for LJ_DUALNUM builds.
    • -
    • Fix buffer check in bytecode writer.
    • -
    • Make os.date() thread-safe.
    • -
    • Add missing declarations for MSVC intrinsics.
    • -
    • Fix dispatch table modifications for return hooks.
    • -
    • Workaround for MSVC conversion bug (doubleuint32_tint32_t).
    • -
    • Fix FOLD rule (i-j)-i => 0-j.
    • -
    • Never use DWARF unwinder on Windows.
    • -
    • Fix shrinking of direct mapped blocks in builtin allocator.
    • -
    • Limit recursion depth in string.match() et al.
    • -
    • Fix late despecialization of ITERN after loop has been entered.
    • -
    • Fix 'f' and 'L' options for debug.getinfo() and lua_getinfo().
    • -
    • Fix package.searchpath().
    • -
    • OSX: Change dylib names to be consistent with other platforms.
    • -
    • Android: Workaround for broken sprintf("%g", -0.0).
    • -
    • x86: Remove support for ancient CPUs without CMOV (before Pentium Pro).
    • -
    • x86: Fix register allocation for calls returning register pair.
    • -
    • x86/x64: Fix fusion of unsigned byte comparisons with swapped operands.
    • -
    • ARM: Fix tonumber() argument check.
    • -
    • ARM: Fix modulo operator and math.floor()/math.ceil() for inf/nan.
    • -
    • ARM: Invoke SPLIT pass for leftover IR_TOBIT.
    • -
    • ARM: Fix BASE register coalescing.
    • -
    • PPC: Fix interpreter state setup in callbacks.
    • -
    • PPC: Fix string.sub() range check.
    • -
    • MIPS: Support generation of MIPS/MIPSEL bytecode object files.
    • -
    • MIPS: Fix calls to floor()/ceil()/trunc().
    • -
    • ARM/PPC: Detect more target architecture variants.
    • -
    • ARM/PPC/e500/MIPS: Fix tailcalls from fast functions, esp. tostring().
    • -
    • ARM/PPC/MIPS: Fix rematerialization of FP constants.
    • -
    • FFI: Don't call FreeLibrary() on our own EXE/DLL.
    • -
    • FFI: Resolve metamethods for constructors, too.
    • -
    • FFI: Properly disable callbacks on iOS (would require executable memory).
    • -
    • FFI: Fix cdecl string parsing during recording.
    • -
    • FFI: Show address pointed to for tostring(ref), too.
    • -
    • FFI: Fix alignment of C call argument/return structure.
    • -
    • FFI: Initialize all fields of standard types.
    • -
    • FFI: Fix callback handling when new C types are declared in callback.
    • -
    • FFI: Fix recording of constructors for pointers.
    • -
    • FFI: Always resolve metamethods for pointers to structs.
    • -
    • FFI: Correctly propagate alignment when interning nested types.
    • -
  • -
  • Structural and performance enhancements: -
      -
    • Add allocation sinking and store sinking optimization.
    • -
    • Constify immutable upvalues.
    • -
    • Add builtin string to integer or FP number conversion. Improves cross-platform consistency and correctness.
    • -
    • Create string hash slots in template tables for non-const values, too. Avoids later table resizes.
    • -
    • Eliminate HREFK guard for template table references.
    • -
    • Add various new FOLD rules.
    • -
    • Don't use stack unwinding for lua_yield() (slow on x64).
    • -
    • ARM, PPC, MIPS: Improve XLOAD operand fusion and register hinting.
    • -
    • PPC, MIPS: Compile math.sqrt() to sqrt instruction, if available.
    • -
    • FFI: Fold KPTR + constant offset in SPLIT pass.
    • -
    • FFI: Optimize/inline ffi.copy() and ffi.fill().
    • -
    • FFI: Compile and optimize array/struct copies.
    • -
    • FFI: Compile ffi.typeof(cdata|ctype), ffi.sizeof(), ffi.alignof(), ffi.offsetof() and ffi.gc().
    • -
  • -
- -

LuaJIT 2.0.0-beta10 — 2012-05-09

-
    -
  • New features: -
      -
    • The MIPS of LuaJIT is complete. It requires a CPU conforming to the -MIPS32 R1 architecture with hardware FPU. O32 hard-fp ABI, -little-endian or big-endian.
    • -
    • Auto-detect target arch via cross-compiler. No need for -TARGET=arch anymore.
    • -
    • Make DynASM compatible with Lua 5.2.
    • -
    • From Lua 5.2: Try __tostring metamethod on non-string error -messages..
    • -
  • -
  • Correctness and completeness: -
      -
    • Fix parsing of hex literals with exponents.
    • -
    • Fix bytecode dump for certain number constants.
    • -
    • Fix argument type in error message for relative arguments.
    • -
    • Fix argument error handling on Lua stacks without a frame.
    • -
    • Add missing mcode limit check in assembler backend.
    • -
    • Fix compilation on OpenBSD.
    • -
    • Avoid recursive GC steps after GC-triggered trace exit.
    • -
    • Replace <unwind.h> definitions with our own.
    • -
    • Fix OSX build issues. Bump minimum required OSX version to 10.4.
    • -
    • Fix discharge order of comparisons in Lua parser.
    • -
    • Ensure running __gc of userdata created in __gc -at state close.
    • -
    • Limit number of userdata __gc separations at state close.
    • -
    • Fix bytecode JMP slot range when optimizing -and/or with constant LHS.
    • -
    • Fix DSE of USTORE.
    • -
    • Make lua_concat() work from C hook with partial frame.
    • -
    • Add required PHIs for implicit conversions, e.g. via XREF -forwarding.
    • -
    • Add more comparison variants to Valgrind suppressions file.
    • -
    • Disable loading bytecode with an extra header (BOM or #!).
    • -
    • Fix PHI stack slot syncing.
    • -
    • ARM: Reorder type/value tests to silence Valgrind.
    • -
    • ARM: Fix register allocation for ldrd-optimized -HREFK.
    • -
    • ARM: Fix conditional branch fixup for OBAR.
    • -
    • ARM: Invoke SPLIT pass for double args in FFI call.
    • -
    • ARM: Handle all CALL* ops with double results in -SPLIT pass.
    • -
    • ARM: Fix rejoin of POW in SPLIT pass.
    • -
    • ARM: Fix compilation of math.sinh, math.cosh, -math.tanh.
    • -
    • ARM, PPC: Avoid pointless arg clearing in BC_IFUNCF.
    • -
    • PPC: Fix resume after yield from hook.
    • -
    • PPC: Fix argument checking for rawget().
    • -
    • PPC: Fix fusion of floating-point XLOAD/XSTORE.
    • -
    • PPC: Fix HREFK code generation for huge tables.
    • -
    • PPC: Use builtin D-Cache/I-Cache sync code.
    • -
  • -
  • FFI library: -
      -
    • Ignore empty statements in ffi.cdef().
    • -
    • Ignore number parsing errors while skipping definitions.
    • -
    • Don't touch frame in callbacks with tailcalls to fast functions.
    • -
    • Fix library unloading on POSIX systems.
    • -
    • Finalize cdata before userdata when closing the state.
    • -
    • Change ffi.load() library name resolution for Cygwin.
    • -
    • Fix resolving of function name redirects on Windows/x86.
    • -
    • Fix symbol resolving error messages on Windows.
    • -
    • Fix blacklisting of C functions calling callbacks.
    • -
    • Fix result type of pointer difference.
    • -
    • Use correct PC in FFI metamethod error message.
    • -
    • Allow 'typedef _Bool int BOOL;' for the Windows API.
    • -
    • Don't record test for bool result of call, if ignored.
    • -
  • -
- -

LuaJIT 2.0.0-beta9 — 2011-12-14

-
    -
  • New features: -
      -
    • PPC port of LuaJIT is complete. Default is the dual-number port -(usually faster). Single-number port selectable via src/Makefile -at build time.
    • -
    • Add FFI callback support.
    • -
    • Extend -b to generate .c, .h or .obj/.o -files with embedded bytecode.
    • -
    • Allow loading embedded bytecode with require().
    • -
    • From Lua 5.2: Change to '\z' escape. Reject undefined escape -sequences.
    • -
  • -
  • Correctness and completeness: -
      -
    • Fix OSX 10.7 build. Fix install_name and versioning on OSX.
    • -
    • Fix iOS build.
    • -
    • Install dis_arm.lua, too.
    • -
    • Mark installed shared library as executable.
    • -
    • Add debug option to msvcbuild.bat and improve error handling.
    • -
    • Fix data-flow analysis for iterators.
    • -
    • Fix forced unwinding triggered by external unwinder.
    • -
    • Record missing for loop slot loads (return to lower frame).
    • -
    • Always use ANSI variants of Windows system functions.
    • -
    • Fix GC barrier for multi-result table constructor (TSETM).
    • -
    • Fix/add various FOLD rules.
    • -
    • Add potential PHI for number conversions due to type instability.
    • -
    • Do not eliminate PHIs only referenced from other PHIs.
    • -
    • Correctly anchor implicit number to string conversions in Lua/C API.
    • -
    • Fix various stack limit checks.
    • -
    • x64: Use thread-safe exceptions for external unwinding (GCC platforms).
    • -
    • x64: Fix result type of cdata index conversions.
    • -
    • x64: Fix math.random() and bit.bswap() code generation.
    • -
    • x64: Fix lightuserdata comparisons.
    • -
    • x64: Always extend stack-passed arguments to pointer size.
    • -
    • ARM: Many fixes to code generation backend.
    • -
    • PPC/e500: Fix dispatch for binop metamethods.
    • -
    • PPC/e500: Save/restore condition registers when entering/leaving the VM.
    • -
    • PPC/e500: Fix write barrier in stores of strings to upvalues.
    • -
  • -
  • FFI library: -
      -
    • Fix C comment parsing.
    • -
    • Fix snapshot optimization for cdata comparisons.
    • -
    • Fix recording of const/enum lookups in namespaces.
    • -
    • Fix call argument and return handling for I8/U8/I16/U16 types.
    • -
    • Fix unfused loads of float fields.
    • -
    • Fix ffi.string() recording.
    • -
    • Save GetLastError() around ffi.load() and symbol -resolving, too.
    • -
    • Improve ld script detection in ffi.load().
    • -
    • Record loads/stores to external variables in namespaces.
    • -
    • Compile calls to stdcall, fastcall and vararg functions.
    • -
    • Treat function ctypes like pointers in comparisons.
    • -
    • Resolve __call metamethod for pointers, too.
    • -
    • Record C function calls with bool return values.
    • -
    • Record ffi.errno().
    • -
    • x86: Fix number to uint32_t conversion rounding.
    • -
    • x86: Fix 64 bit arithmetic in assembler backend.
    • -
    • x64: Fix struct-by-value calling conventions.
    • -
    • ARM: Ensure invocation of SPLIT pass for float conversions.
    • -
  • -
  • Structural and performance enhancements: -
      -
    • Display trace types with -jv and -jdump.
    • -
    • Record isolated calls. But prefer recording loops over calls.
    • -
    • Specialize to prototype for non-monomorphic functions. Solves the -trace-explosion problem for closure-heavy programming styles.
    • -
    • Always generate a portable vmdef.lua. Easier for distros.
    • -
  • -
- -

LuaJIT 2.0.0-beta8 — 2011-06-23

-
    -
  • New features: -
      -
    • Soft-float ARM port of LuaJIT is complete.
    • -
    • Add support for bytecode loading/saving and -b command line -option.
    • -
    • From Lua 5.2: __len metamethod for tables -(disabled by default).
    • -
  • -
  • Correctness and completeness: -
      -
    • ARM: Misc. fixes for interpreter.
    • -
    • x86/x64: Fix bit.* argument checking in interpreter.
    • -
    • Catch early out-of-memory in memory allocator initialization.
    • -
    • Fix data-flow analysis for paths leading to an upvalue close.
    • -
    • Fix check for missing arguments in string.format().
    • -
    • Fix Solaris/x86 build (note: not a supported target).
    • -
    • Fix recording of loops with instable directions in side traces.
    • -
    • x86/x64: Fix fusion of comparisons with u8/u16 -XLOAD.
    • -
    • x86/x64: Fix register allocation for variable shifts.
    • -
  • -
  • FFI library: -
      -
    • Add ffi.errno(). Save errno/GetLastError() -around allocations etc.
    • -
    • Fix __gc for VLA/VLS cdata objects.
    • -
    • Fix recording of casts from 32 bit cdata pointers to integers.
    • -
    • tonumber(cdata) returns nil for non-numbers.
    • -
    • Show address pointed to for tostring(pointer).
    • -
    • Print NULL pointers as "cdata<... *>: NULL".
    • -
    • Support __tostring metamethod for pointers to structs, too.
    • -
  • -
  • Structural and performance enhancements: -
      -
    • More tuning for loop unrolling heuristics.
    • -
    • Flatten and compress in-memory debug info (saves ~70%).
    • -
  • -
- -

LuaJIT 2.0.0-beta7 — 2011-05-05

-
    -
  • New features: -
      -
    • ARM port of the LuaJIT interpreter is complete.
    • -
    • FFI library: Add ffi.gc(), ffi.metatype(), -ffi.istype().
    • -
    • FFI library: Resolve ld script redirection in ffi.load().
    • -
    • From Lua 5.2: package.searchpath(), fp:read("*L"), -load(string).
    • -
    • From Lua 5.2, disabled by default: empty statement, -table.unpack(), modified coroutine.running().
    • -
  • -
  • Correctness and completeness: -
      -
    • FFI library: numerous fixes.
    • -
    • Fix type mismatches in store-to-load forwarding.
    • -
    • Fix error handling within metamethods.
    • -
    • Fix table.maxn().
    • -
    • Improve accuracy of x^-k on x64.
    • -
    • Fix code generation for Intel Atom in x64 mode.
    • -
    • Fix narrowing of POW.
    • -
    • Fix recording of retried fast functions.
    • -
    • Fix code generation for bit.bnot() and multiplies.
    • -
    • Fix error location within cpcall frames.
    • -
    • Add workaround for old libgcc unwind bug.
    • -
    • Fix lua_yield() and getmetatable(lightuserdata) on x64.
    • -
    • Misc. fixes for PPC/e500 interpreter.
    • -
    • Fix stack slot updates for down-recursion.
    • -
  • -
  • Structural and performance enhancements: -
      -
    • Add dual-number mode (int/double) for the VM. Enabled for ARM.
    • -
    • Improve narrowing of arithmetic operators and for loops.
    • -
    • Tune loop unrolling heuristics and increase trace recorder limits.
    • -
    • Eliminate dead slots in snapshots using bytecode data-flow analysis.
    • -
    • Avoid phantom stores to proxy tables.
    • -
    • Optimize lookups in empty proxy tables.
    • -
    • Improve bytecode optimization of and/or operators.
    • -
  • -
- -

LuaJIT 2.0.0-beta6 — 2011-02-11

-
    -
  • New features: -
      -
    • PowerPC/e500v2 port of the LuaJIT interpreter is complete.
    • -
    • Various minor features from Lua 5.2: Hex escapes in literals, -'\*' escape, reversible string.format("%q",s), -"%g" pattern, table.sort checks callbacks, -os.exit(status|true|false[,close]).
    • -
    • Lua 5.2 __pairs and __ipairs metamethods -(disabled by default).
    • -
    • Initial release of the FFI library.
    • -
  • -
  • Correctness and completeness: -
      -
    • Fix string.format() for non-finite numbers.
    • -
    • Fix memory leak when compiled to use the built-in allocator.
    • -
    • x86/x64: Fix unnecessary resize in TSETM bytecode.
    • -
    • Fix various GC issues with traces and jit.flush().
    • -
    • x64: Fix fusion of indexes for array references.
    • -
    • x86/x64: Fix stack overflow handling for coroutine results.
    • -
    • Enable low-2GB memory allocation on FreeBSD/x64.
    • -
    • Fix collectgarbage("count") result if more than 2GB is in use.
    • -
    • Fix parsing of hex floats.
    • -
    • x86/x64: Fix loop branch inversion with trailing -HREF+NE/EQ.
    • -
    • Add jit.os string.
    • -
    • coroutine.create() permits running C functions, too.
    • -
    • Fix OSX build to work with newer ld64 versions.
    • -
    • Fix bytecode optimization of and/or operators.
    • -
  • -
  • Structural and performance enhancements: -
      -
    • Emit specialized bytecode for pairs()/next().
    • -
    • Improve bytecode coalescing of nil constants.
    • -
    • Compile calls to vararg functions.
    • -
    • Compile select().
    • -
    • Improve alias analysis, esp. for loads from allocations.
    • -
    • Tuning of various compiler heuristics.
    • -
    • Refactor and extend IR conversion instructions.
    • -
    • x86/x64: Various backend enhancements related to the FFI.
    • -
    • Add SPLIT pass to split 64 bit IR instructions for 32 bit CPUs.
    • -
  • -
- -

LuaJIT 2.0.0-beta5 — 2010-08-24

-
    -
  • Correctness and completeness: -
      -
    • Fix trace exit dispatch to function headers.
    • -
    • Fix Windows and OSX builds with LUAJIT_DISABLE_JIT.
    • -
    • Reorganize and fix placement of generated machine code on x64.
    • -
    • Fix TNEW in x64 interpreter.
    • -
    • Do not eliminate PHIs for values only referenced from side exits.
    • -
    • OS-independent canonicalization of strings for non-finite numbers.
    • -
    • Fix string.char() range check on x64.
    • -
    • Fix tostring() resolving within print().
    • -
    • Fix error handling for next().
    • -
    • Fix passing of constant arguments to external calls on x64.
    • -
    • Fix interpreter argument check for two-argument SSE math functions.
    • -
    • Fix C frame chain corruption caused by lua_cpcall().
    • -
    • Fix return from pcall() within active hook.
    • -
  • -
  • Structural and performance enhancements: -
      -
    • Replace on-trace GC frame syncing with interpreter exit.
    • -
    • Improve hash lookup specialization by not removing dead keys during GC.
    • -
    • Turn traces into true GC objects.
    • -
    • Avoid starting a GC cycle immediately after library init.
    • -
    • Add weak guards to improve dead-code elimination.
    • -
    • Speed up string interning.
    • -
  • -
- -

LuaJIT 2.0.0-beta4 — 2010-03-28

-
    -
  • Correctness and completeness: -
      -
    • Fix precondition for on-trace creation of table keys.
    • -
    • Fix {f()} on x64 when table is resized.
    • -
    • Fix folding of ordered comparisons with same references.
    • -
    • Fix snapshot restores for multi-result bytecodes.
    • -
    • Fix potential hang when recording bytecode with nested closures.
    • -
    • Fix recording of getmetatable(), tonumber() and bad argument types.
    • -
    • Fix SLOAD fusion across returns to lower frames.
    • -
  • -
  • Structural and performance enhancements: -
      -
    • Add array bounds check elimination. -Oabc is enabled by default.
    • -
    • More tuning for x64, e.g. smaller table objects.
    • -
  • -
- -

LuaJIT 2.0.0-beta3 — 2010-03-07

-
    -
  • LuaJIT x64 port: -
      -
    • Port integrated memory allocator to Linux/x64, Windows/x64 and OSX/x64.
    • -
    • Port interpreter and JIT compiler to x64.
    • -
    • Port DynASM to x64.
    • -
    • Many 32/64 bit cleanups in the VM.
    • -
    • Allow building the interpreter with either x87 or SSE2 arithmetics.
    • -
    • Add external unwinding and C++ exception interop (default on x64).
    • -
  • -
  • Correctness and completeness: -
      -
    • Fix constructor bytecode generation for certain conditional values.
    • -
    • Fix some cases of ordered string comparisons.
    • -
    • Fix lua_tocfunction().
    • -
    • Fix cutoff register in JMP bytecode for some conditional expressions.
    • -
    • Fix PHI marking algorithm for references from variant slots.
    • -
    • Fix package.cpath for non-default PREFIX.
    • -
    • Fix DWARF2 frame unwind information for interpreter on OSX.
    • -
    • Drive the GC forward on string allocations in the parser.
    • -
    • Implement call/return hooks (zero-cost if disabled).
    • -
    • Implement yield from C hooks.
    • -
    • Disable JIT compiler on older non-SSE2 CPUs instead of aborting.
    • -
  • -
  • Structural and performance enhancements: -
      -
    • Compile recursive code (tail-, up- and down-recursion).
    • -
    • Improve heuristics for bytecode penalties and blacklisting.
    • -
    • Split CALL/FUNC recording and clean up fast function call semantics.
    • -
    • Major redesign of internal function call handling.
    • -
    • Improve FOR loop const specialization and integerness checks.
    • -
    • Switch to pre-initialized stacks. Avoid frame-clearing.
    • -
    • Colocation of prototypes and related data: bytecode, constants, debug info.
    • -
    • Cleanup parser and streamline bytecode generation.
    • -
    • Add support for weak IR references to register allocator.
    • -
    • Switch to compressed, extensible snapshots.
    • -
    • Compile returns to frames below the start frame.
    • -
    • Improve alias analysis of upvalues using a disambiguation hash value.
    • -
    • Compile floor/ceil/trunc to SSE2 helper calls or SSE4.1 instructions.
    • -
    • Add generic C call handling to IR and backend.
    • -
    • Improve KNUM fuse vs. load heuristics.
    • -
    • Compile various io.*() functions.
    • -
    • Compile math.sinh(), math.cosh(), math.tanh() -and math.random().
    • -
  • -
- -

LuaJIT 2.0.0-beta2 — 2009-11-09

-
    -
  • Reorganize build system. Build static+shared library on POSIX.
  • -
  • Allow C++ exception conversion on all platforms -using a wrapper function.
  • -
  • Automatically catch C++ exceptions and rethrow Lua error -(DWARF2 only).
  • -
  • Check for the correct x87 FPU precision at strategic points.
  • -
  • Always use wrappers for libm functions.
  • -
  • Resurrect metamethod name strings before copying them.
  • -
  • Mark current trace, even if compiler is idle.
  • -
  • Ensure FILE metatable is created only once.
  • -
  • Fix type comparisons when different integer types are involved.
  • -
  • Fix getmetatable() recording.
  • -
  • Fix TDUP with dead keys in template table.
  • -
  • jit.flush(tr) returns status. -Prevent manual flush of a trace that's still linked.
  • -
  • Improve register allocation heuristics for invariant references.
  • -
  • Compile the push/pop variants of table.insert() and -table.remove().
  • -
  • Compatibility with MSVC link /debug.
  • -
  • Fix lua_iscfunction().
  • -
  • Fix math.random() when compiled with -fpic (OSX).
  • -
  • Fix table.maxn().
  • -
  • Bump MACOSX_DEPLOYMENT_TARGET to 10.4
  • -
  • luaL_check*() and luaL_opt*() now support -negative arguments, too.
    -This matches the behavior of Lua 5.1, but not the specification.
  • -
- -

LuaJIT 2.0.0-beta1 — 2009-10-31

-
    -
  • This is the first public release of LuaJIT 2.0.
  • -
  • The whole VM has been rewritten from the ground up, so there's -no point in listing differences over earlier versions.
  • -
-
-
-
- - - diff --git a/lib/LuaJIT/doc/contact.html b/lib/LuaJIT/doc/contact.html deleted file mode 100644 index 2aace4b..0000000 --- a/lib/LuaJIT/doc/contact.html +++ /dev/null @@ -1,110 +0,0 @@ - - - -Contact - - - - - - - -
-Lua -
- - -
-

-If you want to report bugs, propose fixes or suggest enhancements, -please use the -GitHub issue tracker. -

-

-Please send general questions to the -» LuaJIT mailing list. -

-

-You can also send any questions you have directly to me: -

- - - - - -

Copyright

-

-All documentation is -Copyright © 2005-2018 Mike Pall. -

- - -
-
- - - diff --git a/lib/LuaJIT/doc/ext_c_api.html b/lib/LuaJIT/doc/ext_c_api.html deleted file mode 100644 index f27b956..0000000 --- a/lib/LuaJIT/doc/ext_c_api.html +++ /dev/null @@ -1,188 +0,0 @@ - - - -Lua/C API Extensions - - - - - - - -
-Lua -
- - -
-

-LuaJIT adds some extensions to the standard Lua/C API. The LuaJIT include -directory must be in the compiler search path (-Ipath) -to be able to include the required header for C code: -

-
-#include "luajit.h"
-
-

-Or for C++ code: -

-
-#include "lua.hpp"
-
- -

luaJIT_setmode(L, idx, mode) -— Control VM

-

-This is a C API extension to allow control of the VM from C code. The -full prototype of LuaJIT_setmode is: -

-
-LUA_API int luaJIT_setmode(lua_State *L, int idx, int mode);
-
-

-The returned status is either success (1) or failure (0). -The second argument is either 0 or a stack index (similar to the -other Lua/C API functions). -

-

-The third argument specifies the mode, which is 'or'ed with a flag. -The flag can be LUAJIT_MODE_OFF to turn a feature off, -LUAJIT_MODE_ON to turn a feature on, or -LUAJIT_MODE_FLUSH to flush cached code. -

-

-The following modes are defined: -

- -

luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE|flag)

-

-Turn the whole JIT compiler on or off or flush the whole cache of compiled code. -

- -

luaJIT_setmode(L, idx, LUAJIT_MODE_FUNC|flag)
-luaJIT_setmode(L, idx, LUAJIT_MODE_ALLFUNC|flag)
-luaJIT_setmode(L, idx, LUAJIT_MODE_ALLSUBFUNC|flag)

-

-This sets the mode for the function at the stack index idx or -the parent of the calling function (idx = 0). It either -enables JIT compilation for a function, disables it and flushes any -already compiled code or only flushes already compiled code. This -applies recursively to all sub-functions of the function with -LUAJIT_MODE_ALLFUNC or only to the sub-functions with -LUAJIT_MODE_ALLSUBFUNC. -

- -

luaJIT_setmode(L, trace,
-  LUAJIT_MODE_TRACE|LUAJIT_MODE_FLUSH)

-

-Flushes the specified root trace and all of its side traces from the cache. -The code for the trace will be retained as long as there are any other -traces which link to it. -

- -

luaJIT_setmode(L, idx, LUAJIT_MODE_WRAPCFUNC|flag)

-

-This mode defines a wrapper function for calls to C functions. If -called with LUAJIT_MODE_ON, the stack index at idx -must be a lightuserdata object holding a pointer to the wrapper -function. From now on all C functions are called through the wrapper -function. If called with LUAJIT_MODE_OFF this mode is turned -off and all C functions are directly called. -

-

-The wrapper function can be used for debugging purposes or to catch -and convert foreign exceptions. But please read the section on -C++ exception interoperability -first. Recommended usage can be seen in this C++ code excerpt: -

-
-#include <exception>
-#include "lua.hpp"
-
-// Catch C++ exceptions and convert them to Lua error messages.
-// Customize as needed for your own exception classes.
-static int wrap_exceptions(lua_State *L, lua_CFunction f)
-{
-  try {
-    return f(L);  // Call wrapped function and return result.
-  } catch (const char *s) {  // Catch and convert exceptions.
-    lua_pushstring(L, s);
-  } catch (std::exception& e) {
-    lua_pushstring(L, e.what());
-  } catch (...) {
-    lua_pushliteral(L, "caught (...)");
-  }
-  return lua_error(L);  // Rethrow as a Lua error.
-}
-
-static int myinit(lua_State *L)
-{
-  ...
-  // Define wrapper function and enable it.
-  lua_pushlightuserdata(L, (void *)wrap_exceptions);
-  luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC|LUAJIT_MODE_ON);
-  lua_pop(L, 1);
-  ...
-}
-
-

-Note that you can only define a single global wrapper function, -so be careful when using this mechanism from multiple C++ modules. -Also note that this mechanism is not without overhead. -

-
-
- - - diff --git a/lib/LuaJIT/doc/ext_ffi.html b/lib/LuaJIT/doc/ext_ffi.html deleted file mode 100644 index de57bcf..0000000 --- a/lib/LuaJIT/doc/ext_ffi.html +++ /dev/null @@ -1,331 +0,0 @@ - - - -FFI Library - - - - - - - -
-Lua -
- - -
-

- -The FFI library allows calling external C functions and -using C data structures from pure Lua code. - -

-

- -The FFI library largely obviates the need to write tedious manual -Lua/C bindings in C. No need to learn a separate binding language -— it parses plain C declarations! These can be -cut-n-pasted from C header files or reference manuals. It's up to -the task of binding large libraries without the need for dealing with -fragile binding generators. - -

-

-The FFI library is tightly integrated into LuaJIT (it's not available -as a separate module). The code generated by the JIT-compiler for -accesses to C data structures from Lua code is on par with the -code a C compiler would generate. Calls to C functions can -be inlined in JIT-compiled code, unlike calls to functions bound via -the classic Lua/C API. -

-

-This page gives a short introduction to the usage of the FFI library. -Please use the FFI sub-topics in the navigation bar to learn more. -

- -

Motivating Example: Calling External C Functions

-

-It's really easy to call an external C library function: -

-
-①
-②
-
-
-③local ffi = require("ffi")
-ffi.cdef[[
-int printf(const char *fmt, ...);
-]]
-ffi.C.printf("Hello %s!", "world")
-
-

-So, let's pick that apart: -

-

- Load the FFI library. -

-

- Add a C declaration -for the function. The part inside the double-brackets (in green) is -just standard C syntax. -

-

- Call the named -C function — Yes, it's that simple! -

-

-Actually, what goes on behind the scenes is far from simple: makes use of the standard -C library namespace ffi.C. Indexing this namespace with -a symbol name ("printf") automatically binds it to the -standard C library. The result is a special kind of object which, -when called, runs the printf function. The arguments passed -to this function are automatically converted from Lua objects to the -corresponding C types. -

-

-Ok, so maybe the use of printf() wasn't such a spectacular -example. You could have done that with io.write() and -string.format(), too. But you get the idea ... -

-

-So here's something to pop up a message box on Windows: -

-
-local ffi = require("ffi")
-ffi.cdef[[
-int MessageBoxA(void *w, const char *txt, const char *cap, int type);
-]]
-ffi.C.MessageBoxA(nil, "Hello world!", "Test", 0)
-
-

-Bing! Again, that was far too easy, no? -

-

-Compare this with the effort required to bind that function using the -classic Lua/C API: create an extra C file, add a C function -that retrieves and checks the argument types passed from Lua and calls -the actual C function, add a list of module functions and their -names, add a luaopen_* function and register all module -functions, compile and link it into a shared library (DLL), move it to -the proper path, add Lua code that loads the module aaaand ... finally -call the binding function. Phew! -

- -

Motivating Example: Using C Data Structures

-

-The FFI library allows you to create and access C data -structures. Of course the main use for this is for interfacing with -C functions. But they can be used stand-alone, too. -

-

-Lua is built upon high-level data types. They are flexible, extensible -and dynamic. That's why we all love Lua so much. Alas, this can be -inefficient for certain tasks, where you'd really want a low-level -data type. E.g. a large array of a fixed structure needs to be -implemented with a big table holding lots of tiny tables. This imposes -both a substantial memory overhead as well as a performance overhead. -

-

-Here's a sketch of a library that operates on color images plus a -simple benchmark. First, the plain Lua version: -

-
-local floor = math.floor
-
-local function image_ramp_green(n)
-  local img = {}
-  local f = 255/(n-1)
-  for i=1,n do
-    img[i] = { red = 0, green = floor((i-1)*f), blue = 0, alpha = 255 }
-  end
-  return img
-end
-
-local function image_to_grey(img, n)
-  for i=1,n do
-    local y = floor(0.3*img[i].red + 0.59*img[i].green + 0.11*img[i].blue)
-    img[i].red = y; img[i].green = y; img[i].blue = y
-  end
-end
-
-local N = 400*400
-local img = image_ramp_green(N)
-for i=1,1000 do
-  image_to_grey(img, N)
-end
-
-

-This creates a table with 160.000 pixels, each of which is a table -holding four number values in the range of 0-255. First an image with -a green ramp is created (1D for simplicity), then the image is -converted to greyscale 1000 times. Yes, that's silly, but I was in -need of a simple example ... -

-

-And here's the FFI version. The modified parts have been marked in -bold: -

-
-①
-
-
-
-
-
-②
-
-③
-④
-
-
-
-
-
-
-③
-⑤local ffi = require("ffi")
-ffi.cdef[[
-typedef struct { uint8_t red, green, blue, alpha; } rgba_pixel;
-]]
-
-local function image_ramp_green(n)
-  local img = ffi.new("rgba_pixel[?]", n)
-  local f = 255/(n-1)
-  for i=0,n-1 do
-    img[i].green = i*f
-    img[i].alpha = 255
-  end
-  return img
-end
-
-local function image_to_grey(img, n)
-  for i=0,n-1 do
-    local y = 0.3*img[i].red + 0.59*img[i].green + 0.11*img[i].blue
-    img[i].red = y; img[i].green = y; img[i].blue = y
-  end
-end
-
-local N = 400*400
-local img = image_ramp_green(N)
-for i=1,1000 do
-  image_to_grey(img, N)
-end
-
-

-Ok, so that wasn't too difficult: -

-

- First, load the FFI -library and declare the low-level data type. Here we choose a -struct which holds four byte fields, one for each component -of a 4x8 bit RGBA pixel. -

-

- Creating the data -structure with ffi.new() is straightforward — the -'?' is a placeholder for the number of elements of a -variable-length array. -

-

- C arrays are -zero-based, so the indexes have to run from 0 to -n-1. One might want to allocate one more element instead to -simplify converting legacy code. -

-

- Since ffi.new() -zero-fills the array by default, we only need to set the green and the -alpha fields. -

-

- The calls to -math.floor() can be omitted here, because floating-point -numbers are already truncated towards zero when converting them to an -integer. This happens implicitly when the number is stored in the -fields of each pixel. -

-

-Now let's have a look at the impact of the changes: first, memory -consumption for the image is down from 22 Megabytes to -640 Kilobytes (400*400*4 bytes). That's a factor of 35x less! So, -yes, tables do have a noticeable overhead. BTW: The original program -would consume 40 Megabytes in plain Lua (on x64). -

-

-Next, performance: the pure Lua version runs in 9.57 seconds (52.9 -seconds with the Lua interpreter) and the FFI version runs in 0.48 -seconds on my machine (YMMV). That's a factor of 20x faster (110x -faster than the Lua interpreter). -

-

-The avid reader may notice that converting the pure Lua version over -to use array indexes for the colors ([1] instead of -.red, [2] instead of .green etc.) ought to -be more compact and faster. This is certainly true (by a factor of -~1.7x). Switching to a struct-of-arrays would help, too. -

-

-However the resulting code would be less idiomatic and rather -error-prone. And it still doesn't get even close to the performance of -the FFI version of the code. Also, high-level data structures cannot -be easily passed to other C functions, especially I/O functions, -without undue conversion penalties. -

-
-
- - - diff --git a/lib/LuaJIT/doc/ext_ffi_api.html b/lib/LuaJIT/doc/ext_ffi_api.html deleted file mode 100644 index 54ff0ce..0000000 --- a/lib/LuaJIT/doc/ext_ffi_api.html +++ /dev/null @@ -1,571 +0,0 @@ - - - -ffi.* API Functions - - - - - - - - -
-Lua -
- - -
-

-This page describes the API functions provided by the FFI library in -detail. It's recommended to read through the -introduction and the -FFI tutorial first. -

- -

Glossary

- - -

Declaring and Accessing External Symbols

-

-External symbols must be declared first and can then be accessed by -indexing a C library -namespace, which automatically binds the symbol to a specific -library. -

- -

ffi.cdef(def)

-

-Adds multiple C declarations for types or external symbols (named -variables or functions). def must be a Lua string. It's -recommended to use the syntactic sugar for string arguments as -follows: -

-
-ffi.cdef[[
-typedef struct foo { int a, b; } foo_t;  // Declare a struct and typedef.
-int dofoo(foo_t *f, int n);  /* Declare an external C function. */
-]]
-
-

-The contents of the string (the part in green above) must be a -sequence of -C declarations, -separated by semicolons. The trailing semicolon for a single -declaration may be omitted. -

-

-Please note that external symbols are only declared, but they -are not bound to any specific address, yet. Binding is -achieved with C library namespaces (see below). -

-

-C declarations are not passed through a C pre-processor, -yet. No pre-processor tokens are allowed, except for -#pragma pack. Replace #define in existing -C header files with enum, static const -or typedef and/or pass the files through an external -C pre-processor (once). Be careful not to include unneeded or -redundant declarations from unrelated header files. -

- -

ffi.C

-

-This is the default C library namespace — note the -uppercase 'C'. It binds to the default set of symbols or -libraries on the target system. These are more or less the same as a -C compiler would offer by default, without specifying extra link -libraries. -

-

-On POSIX systems, this binds to symbols in the default or global -namespace. This includes all exported symbols from the executable and -any libraries loaded into the global namespace. This includes at least -libc, libm, libdl (on Linux), -libgcc (if compiled with GCC), as well as any exported -symbols from the Lua/C API provided by LuaJIT itself. -

-

-On Windows systems, this binds to symbols exported from the -*.exe, the lua51.dll (i.e. the Lua/C API -provided by LuaJIT itself), the C runtime library LuaJIT was linked -with (msvcrt*.dll), kernel32.dll, -user32.dll and gdi32.dll. -

- -

clib = ffi.load(name [,global])

-

-This loads the dynamic library given by name and returns -a new C library namespace which binds to its symbols. On POSIX -systems, if global is true, the library symbols are -loaded into the global namespace, too. -

-

-If name is a path, the library is loaded from this path. -Otherwise name is canonicalized in a system-dependent way and -searched in the default search path for dynamic libraries: -

-

-On POSIX systems, if the name contains no dot, the extension -.so is appended. Also, the lib prefix is prepended -if necessary. So ffi.load("z") looks for "libz.so" -in the default shared library search path. -

-

-On Windows systems, if the name contains no dot, the extension -.dll is appended. So ffi.load("ws2_32") looks for -"ws2_32.dll" in the default DLL search path. -

- -

Creating cdata Objects

-

-The following API functions create cdata objects (type() -returns "cdata"). All created cdata objects are -garbage collected. -

- -

cdata = ffi.new(ct [,nelem] [,init...])
-cdata = ctype([nelem,] [init...])

-

-Creates a cdata object for the given ct. VLA/VLS types -require the nelem argument. The second syntax uses a ctype as -a constructor and is otherwise fully equivalent. -

-

-The cdata object is initialized according to the -rules for initializers, -using the optional init arguments. Excess initializers cause -an error. -

-

-Performance notice: if you want to create many objects of one kind, -parse the cdecl only once and get its ctype with -ffi.typeof(). Then use the ctype as a constructor repeatedly. -

-

-Please note that an anonymous struct declaration implicitly -creates a new and distinguished ctype every time you use it for -ffi.new(). This is probably not what you want, -especially if you create more than one cdata object. Different anonymous -structs are not considered assignment-compatible by the -C standard, even though they may have the same fields! Also, they -are considered different types by the JIT-compiler, which may cause an -excessive number of traces. It's strongly suggested to either declare -a named struct or typedef with ffi.cdef() -or to create a single ctype object for an anonymous struct -with ffi.typeof(). -

- -

ctype = ffi.typeof(ct)

-

-Creates a ctype object for the given ct. -

-

-This function is especially useful to parse a cdecl only once and then -use the resulting ctype object as a constructor. -

- -

cdata = ffi.cast(ct, init)

-

-Creates a scalar cdata object for the given ct. The cdata -object is initialized with init using the "cast" variant of -the C type conversion -rules. -

-

-This functions is mainly useful to override the pointer compatibility -checks or to convert pointers to addresses or vice versa. -

- -

ctype = ffi.metatype(ct, metatable)

-

-Creates a ctype object for the given ct and associates it with -a metatable. Only struct/union types, complex numbers -and vectors are allowed. Other types may be wrapped in a -struct, if needed. -

-

-The association with a metatable is permanent and cannot be changed -afterwards. Neither the contents of the metatable nor the -contents of an __index table (if any) may be modified -afterwards. The associated metatable automatically applies to all uses -of this type, no matter how the objects are created or where they -originate from. Note that pre-defined operations on types have -precedence (e.g. declared field names cannot be overriden). -

-

-All standard Lua metamethods are implemented. These are called directly, -without shortcuts and on any mix of types. For binary operations, the -left operand is checked first for a valid ctype metamethod. The -__gc metamethod only applies to struct/union -types and performs an implicit ffi.gc() -call during creation of an instance. -

- -

cdata = ffi.gc(cdata, finalizer)

-

-Associates a finalizer with a pointer or aggregate cdata object. The -cdata object is returned unchanged. -

-

-This function allows safe integration of unmanaged resources into the -automatic memory management of the LuaJIT garbage collector. Typical -usage: -

-
-local p = ffi.gc(ffi.C.malloc(n), ffi.C.free)
-...
-p = nil -- Last reference to p is gone.
--- GC will eventually run finalizer: ffi.C.free(p)
-
-

-A cdata finalizer works like the __gc metamethod for userdata -objects: when the last reference to a cdata object is gone, the -associated finalizer is called with the cdata object as an argument. The -finalizer can be a Lua function or a cdata function or cdata function -pointer. An existing finalizer can be removed by setting a nil -finalizer, e.g. right before explicitly deleting a resource: -

-
-ffi.C.free(ffi.gc(p, nil)) -- Manually free the memory.
-
- -

C Type Information

-

-The following API functions return information about C types. -They are most useful for inspecting cdata objects. -

- -

size = ffi.sizeof(ct [,nelem])

-

-Returns the size of ct in bytes. Returns nil if -the size is not known (e.g. for "void" or function types). -Requires nelem for VLA/VLS types, except for cdata objects. -

- -

align = ffi.alignof(ct)

-

-Returns the minimum required alignment for ct in bytes. -

- -

ofs [,bpos,bsize] = ffi.offsetof(ct, field)

-

-Returns the offset (in bytes) of field relative to the start -of ct, which must be a struct. Additionally returns -the position and the field size (in bits) for bit fields. -

- -

status = ffi.istype(ct, obj)

-

-Returns true if obj has the C type given by -ct. Returns false otherwise. -

-

-C type qualifiers (const etc.) are ignored. Pointers are -checked with the standard pointer compatibility rules, but without any -special treatment for void *. If ct specifies a -struct/union, then a pointer to this type is accepted, -too. Otherwise the types must match exactly. -

-

-Note: this function accepts all kinds of Lua objects for the -obj argument, but always returns false for non-cdata -objects. -

- -

Utility Functions

- -

err = ffi.errno([newerr])

-

-Returns the error number set by the last C function call which -indicated an error condition. If the optional newerr argument -is present, the error number is set to the new value and the previous -value is returned. -

-

-This function offers a portable and OS-independent way to get and set the -error number. Note that only some C functions set the error -number. And it's only significant if the function actually indicated an -error condition (e.g. with a return value of -1 or -NULL). Otherwise, it may or may not contain any previously set -value. -

-

-You're advised to call this function only when needed and as close as -possible after the return of the related C function. The -errno value is preserved across hooks, memory allocations, -invocations of the JIT compiler and other internal VM activity. The same -applies to the value returned by GetLastError() on Windows, but -you need to declare and call it yourself. -

- -

str = ffi.string(ptr [,len])

-

-Creates an interned Lua string from the data pointed to by -ptr. -

-

-If the optional argument len is missing, ptr is -converted to a "char *" and the data is assumed to be -zero-terminated. The length of the string is computed with -strlen(). -

-

-Otherwise ptr is converted to a "void *" and -len gives the length of the data. The data may contain -embedded zeros and need not be byte-oriented (though this may cause -endianess issues). -

-

-This function is mainly useful to convert (temporary) -"const char *" pointers returned by -C functions to Lua strings and store them or pass them to other -functions expecting a Lua string. The Lua string is an (interned) copy -of the data and bears no relation to the original data area anymore. -Lua strings are 8 bit clean and may be used to hold arbitrary, -non-character data. -

-

-Performance notice: it's faster to pass the length of the string, if -it's known. E.g. when the length is returned by a C call like -sprintf(). -

- -

ffi.copy(dst, src, len)
-ffi.copy(dst, str)

-

-Copies the data pointed to by src to dst. -dst is converted to a "void *" and src -is converted to a "const void *". -

-

-In the first syntax, len gives the number of bytes to copy. -Caveat: if src is a Lua string, then len must not -exceed #src+1. -

-

-In the second syntax, the source of the copy must be a Lua string. All -bytes of the string plus a zero-terminator are copied to -dst (i.e. #src+1 bytes). -

-

-Performance notice: ffi.copy() may be used as a faster -(inlinable) replacement for the C library functions -memcpy(), strcpy() and strncpy(). -

- -

ffi.fill(dst, len [,c])

-

-Fills the data pointed to by dst with len constant -bytes, given by c. If c is omitted, the data is -zero-filled. -

-

-Performance notice: ffi.fill() may be used as a faster -(inlinable) replacement for the C library function -memset(dst, c, len). Please note the different -order of arguments! -

- -

Target-specific Information

- -

status = ffi.abi(param)

-

-Returns true if param (a Lua string) applies for the -target ABI (Application Binary Interface). Returns false -otherwise. The following parameters are currently defined: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - -
ParameterDescription
32bit32 bit architecture
64bit64 bit architecture
leLittle-endian architecture
beBig-endian architecture
fpuTarget has a hardware FPU
softfpsoftfp calling conventions
hardfphardfp calling conventions
eabiEABI variant of the standard ABI
winWindows variant of the standard ABI
uwpUniversal Windows Platform
gc6464 bit GC references
- -

ffi.os

-

-Contains the target OS name. Same contents as -jit.os. -

- -

ffi.arch

-

-Contains the target architecture name. Same contents as -jit.arch. -

- -

Methods for Callbacks

-

-The C types for callbacks -have some extra methods: -

- -

cb:free()

-

-Free the resources associated with a callback. The associated Lua -function is unanchored and may be garbage collected. The callback -function pointer is no longer valid and must not be called anymore -(it may be reused by a subsequently created callback). -

- -

cb:set(func)

-

-Associate a new Lua function with a callback. The C type of the -callback and the callback function pointer are unchanged. -

-

-This method is useful to dynamically switch the receiver of callbacks -without creating a new callback each time and registering it again (e.g. -with a GUI library). -

- -

Extended Standard Library Functions

-

-The following standard library functions have been extended to work -with cdata objects: -

- -

n = tonumber(cdata)

-

-Converts a number cdata object to a double and returns it as -a Lua number. This is particularly useful for boxed 64 bit -integer values. Caveat: this conversion may incur a precision loss. -

- -

s = tostring(cdata)

-

-Returns a string representation of the value of 64 bit integers -("nnnLL" or "nnnULL") or -complex numbers ("re±imi"). Otherwise -returns a string representation of the C type of a ctype object -("ctype<type>") or a cdata object -("cdata<type>: address"), unless you -override it with a __tostring metamethod (see -ffi.metatype()). -

- -

iter, obj, start = pairs(cdata)
-iter, obj, start = ipairs(cdata)

-

-Calls the __pairs or __ipairs metamethod of the -corresponding ctype. -

- -

Extensions to the Lua Parser

-

-The parser for Lua source code treats numeric literals with the -suffixes LL or ULL as signed or unsigned 64 bit -integers. Case doesn't matter, but uppercase is recommended for -readability. It handles decimal (42LL), hexadecimal -(0x2aLL) and binary (0b101010LL) literals. -

-

-The imaginary part of complex numbers can be specified by suffixing -number literals with i or I, e.g. 12.5i. -Caveat: you'll need to use 1i to get an imaginary part with -the value one, since i itself still refers to a variable -named i. -

-
-
- - - diff --git a/lib/LuaJIT/doc/ext_ffi_semantics.html b/lib/LuaJIT/doc/ext_ffi_semantics.html deleted file mode 100644 index 4b03da9..0000000 --- a/lib/LuaJIT/doc/ext_ffi_semantics.html +++ /dev/null @@ -1,1261 +0,0 @@ - - - -FFI Semantics - - - - - - - - -
-Lua -
- - -
-

-This page describes the detailed semantics underlying the FFI library -and its interaction with both Lua and C code. -

-

-Given that the FFI library is designed to interface with C code -and that declarations can be written in plain C syntax, it -closely follows the C language semantics, wherever possible. -Some minor concessions are needed for smoother interoperation with Lua -language semantics. -

-

-Please don't be overwhelmed by the contents of this page — this -is a reference and you may need to consult it, if in doubt. It doesn't -hurt to skim this page, but most of the semantics "just work" as you'd -expect them to work. It should be straightforward to write -applications using the LuaJIT FFI for developers with a C or C++ -background. -

- -

C Language Support

-

-The FFI library has a built-in C parser with a minimal memory -footprint. It's used by the ffi.* library -functions to declare C types or external symbols. -

-

-It's only purpose is to parse C declarations, as found e.g. in -C header files. Although it does evaluate constant expressions, -it's not a C compiler. The body of inline -C function definitions is simply ignored. -

-

-Also, this is not a validating C parser. It expects and -accepts correctly formed C declarations, but it may choose to -ignore bad declarations or show rather generic error messages. If in -doubt, please check the input against your favorite C compiler. -

-

-The C parser complies to the C99 language standard plus -the following extensions: -

- -

-The following C types are pre-defined by the C parser (like -a typedef, except re-declarations will be ignored): -

- -

-You're encouraged to use these types in preference to -compiler-specific extensions or target-dependent standard types. -E.g. char differs in signedness and long differs in -size, depending on the target architecture and platform ABI. -

-

-The following C features are not supported: -

- - -

C Type Conversion Rules

- -

Conversions from C types to Lua objects

-

-These conversion rules apply for read accesses to -C types: indexing pointers, arrays or -struct/union types; reading external variables or -constant values; retrieving return values from C calls: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
InputConversionOutput
int8_t, int16_tsign-ext int32_tdoublenumber
uint8_t, uint16_tzero-ext int32_tdoublenumber
int32_t, uint32_tdoublenumber
int64_t, uint64_tboxed value64 bit int cdata
double, floatdoublenumber
bool0 → false, otherwise trueboolean
enumboxed valueenum cdata
Complex numberboxed valuecomplex cdata
Vectorboxed valuevector cdata
Pointerboxed valuepointer cdata
Arrayboxed referencereference cdata
struct/unionboxed referencereference cdata
-

-Bitfields are treated like their underlying type. -

-

-Reference types are dereferenced before a conversion can take -place — the conversion is applied to the C type pointed to -by the reference. -

- -

Conversions from Lua objects to C types

-

-These conversion rules apply for write accesses to -C types: indexing pointers, arrays or -struct/union types; initializing cdata objects; -casts to C types; writing to external variables; passing -arguments to C calls: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
InputConversionOutput
numberdouble
booleanfalse → 0, true → 1bool
nilNULL(void *)
lightuserdatalightuserdata address →(void *)
userdatauserdata payload →(void *)
io.* fileget FILE * handle →(void *)
stringmatch against enum constantenum
stringcopy string data + zero-byteint8_t[], uint8_t[]
stringstring data →const char[]
functioncreate callbackC function type
tabletable initializerArray
tabletable initializerstruct/union
cdatacdata payload →C type
-

-If the result type of this conversion doesn't match the -C type of the destination, the -conversion rules between C types -are applied. -

-

-Reference types are immutable after initialization ("no re-seating of -references"). For initialization purposes or when passing values to -reference parameters, they are treated like pointers. Note that unlike -in C++, there's no way to implement automatic reference generation of -variables under the Lua language semantics. If you want to call a -function with a reference parameter, you need to explicitly pass a -one-element array. -

- -

Conversions between C types

-

-These conversion rules are more or less the same as the standard -C conversion rules. Some rules only apply to casts, or require -pointer or type compatibility: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
InputConversionOutput
Signed integernarrow or sign-extendInteger
Unsigned integernarrow or zero-extendInteger
Integerrounddouble, float
double, floattrunc int32_tnarrow(u)int8_t, (u)int16_t
double, floattrunc(u)int32_t, (u)int64_t
double, floatroundfloat, double
Numbern == 0 → 0, otherwise 1bool
boolfalse → 0, true → 1Number
Complex numberconvert real partNumber
Numberconvert real part, imag = 0Complex number
Complex numberconvert real and imag partComplex number
Numberconvert scalar and replicateVector
Vectorcopy (same size)Vector
struct/uniontake base address (compat)Pointer
Arraytake base address (compat)Pointer
Functiontake function addressFunction pointer
Numberconvert via uintptr_t (cast)Pointer
Pointerconvert address (compat/cast)Pointer
Pointerconvert address (cast)Integer
Arrayconvert base address (cast)Integer
Arraycopy (compat)Array
struct/unioncopy (identical type)struct/union
-

-Bitfields or enum types are treated like their underlying -type. -

-

-Conversions not listed above will raise an error. E.g. it's not -possible to convert a pointer to a complex number or vice versa. -

- -

Conversions for vararg C function arguments

-

-The following default conversion rules apply when passing Lua objects -to the variable argument part of vararg C functions: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
InputConversionOutput
numberdouble
booleanfalse → 0, true → 1bool
nilNULL(void *)
userdatauserdata payload →(void *)
lightuserdatalightuserdata address →(void *)
stringstring data →const char *
float cdatadouble
Array cdatatake base addressElement pointer
struct/union cdatatake base addressstruct/union pointer
Function cdatatake function addressFunction pointer
Any other cdatano conversionC type
-

-To pass a Lua object, other than a cdata object, as a specific type, -you need to override the conversion rules: create a temporary cdata -object with a constructor or a cast and initialize it with the value -to pass: -

-

-Assuming x is a Lua number, here's how to pass it as an -integer to a vararg function: -

-
-ffi.cdef[[
-int printf(const char *fmt, ...);
-]]
-ffi.C.printf("integer value: %d\n", ffi.new("int", x))
-
-

-If you don't do this, the default Lua number → double -conversion rule applies. A vararg C function expecting an integer -will see a garbled or uninitialized value. -

- -

Initializers

-

-Creating a cdata object with -ffi.new() or the -equivalent constructor syntax always initializes its contents, too. -Different rules apply, depending on the number of optional -initializers and the C types involved: -

- - -

Table Initializers

-

-The following rules apply if a Lua table is used to initialize an -Array or a struct/union: -

- -

-Example: -

-
-local ffi = require("ffi")
-
-ffi.cdef[[
-struct foo { int a, b; };
-union bar { int i; double d; };
-struct nested { int x; struct foo y; };
-]]
-
-ffi.new("int[3]", {})            --> 0, 0, 0
-ffi.new("int[3]", {1})           --> 1, 1, 1
-ffi.new("int[3]", {1,2})         --> 1, 2, 0
-ffi.new("int[3]", {1,2,3})       --> 1, 2, 3
-ffi.new("int[3]", {[0]=1})       --> 1, 1, 1
-ffi.new("int[3]", {[0]=1,2})     --> 1, 2, 0
-ffi.new("int[3]", {[0]=1,2,3})   --> 1, 2, 3
-ffi.new("int[3]", {[0]=1,2,3,4}) --> error: too many initializers
-
-ffi.new("struct foo", {})            --> a = 0, b = 0
-ffi.new("struct foo", {1})           --> a = 1, b = 0
-ffi.new("struct foo", {1,2})         --> a = 1, b = 2
-ffi.new("struct foo", {[0]=1,2})     --> a = 1, b = 2
-ffi.new("struct foo", {b=2})         --> a = 0, b = 2
-ffi.new("struct foo", {a=1,b=2,c=3}) --> a = 1, b = 2  'c' is ignored
-
-ffi.new("union bar", {})        --> i = 0, d = 0.0
-ffi.new("union bar", {1})       --> i = 1, d = ?
-ffi.new("union bar", {[0]=1,2}) --> i = 1, d = ?    '2' is ignored
-ffi.new("union bar", {d=2})     --> i = ?, d = 2.0
-
-ffi.new("struct nested", {1,{2,3}})     --> x = 1, y.a = 2, y.b = 3
-ffi.new("struct nested", {x=1,y={2,3}}) --> x = 1, y.a = 2, y.b = 3
-
- -

Operations on cdata Objects

-

-All of the standard Lua operators can be applied to cdata objects or a -mix of a cdata object and another Lua object. The following list shows -the pre-defined operations. -

-

-Reference types are dereferenced before performing each of -the operations below — the operation is applied to the -C type pointed to by the reference. -

-

-The pre-defined operations are always tried first before deferring to a -metamethod or index table (if any) for the corresponding ctype (except -for __new). An error is raised if the metamethod lookup or -index table lookup fails. -

- -

Indexing a cdata object

- -

-A ctype object can be indexed with a string key, too. The only -pre-defined operation is reading scoped constants of -struct/union types. All other accesses defer -to the corresponding metamethods or index tables (if any). -

-

-Note: since there's (deliberately) no address-of operator, a cdata -object holding a value type is effectively immutable after -initialization. The JIT compiler benefits from this fact when applying -certain optimizations. -

-

-As a consequence, the elements of complex numbers and -vectors are immutable. But the elements of an aggregate holding these -types may be modified of course. I.e. you cannot assign to -foo.c.im, but you can assign a (newly created) complex number -to foo.c. -

-

-The JIT compiler implements strict aliasing rules: accesses to different -types do not alias, except for differences in signedness (this -applies even to char pointers, unlike C99). Type punning -through unions is explicitly detected and allowed. -

- -

Calling a cdata object

- - -

Arithmetic on cdata objects

- - -

Comparisons of cdata objects

- - -

cdata objects as table keys

-

-Lua tables may be indexed by cdata objects, but this doesn't provide -any useful semantics — cdata objects are unsuitable as table -keys! -

-

-A cdata object is treated like any other garbage-collected object and -is hashed and compared by its address for table indexing. Since -there's no interning for cdata value types, the same value may be -boxed in different cdata objects with different addresses. Thus -t[1LL+1LL] and t[2LL] usually do not point to -the same hash slot and they certainly do not point to the same -hash slot as t[2]. -

-

-It would seriously drive up implementation complexity and slow down -the common case, if one were to add extra handling for by-value -hashing and comparisons to Lua tables. Given the ubiquity of their use -inside the VM, this is not acceptable. -

-

-There are three viable alternatives, if you really need to use cdata -objects as keys: -

- - -

Parameterized Types

-

-To facilitate some abstractions, the two functions -ffi.typeof and -ffi.cdef support -parameterized types in C declarations. Note: none of the other API -functions taking a cdecl allow this. -

-

-Any place you can write a typedef name, an -identifier or a number in a declaration, you can write -$ (the dollar sign) instead. These placeholders are replaced in -order of appearance with the arguments following the cdecl string: -

-
--- Declare a struct with a parameterized field type and name:
-ffi.cdef([[
-typedef struct { $ $; } foo_t;
-]], type1, name1)
-
--- Anonymous struct with dynamic names:
-local bar_t = ffi.typeof("struct { int $, $; }", name1, name2)
--- Derived pointer type:
-local bar_ptr_t = ffi.typeof("$ *", bar_t)
-
--- Parameterized dimensions work even where a VLA won't work:
-local matrix_t = ffi.typeof("uint8_t[$][$]", width, height)
-
-

-Caveat: this is not simple text substitution! A passed ctype or -cdata object is treated like the underlying type, a passed string is -considered an identifier and a number is considered a number. You must -not mix this up: e.g. passing "int" as a string doesn't work in -place of a type, you'd need to use ffi.typeof("int") instead. -

-

-The main use for parameterized types are libraries implementing abstract -data types -(example), -similar to what can be achieved with C++ template metaprogramming. -Another use case are derived types of anonymous structs, which avoids -pollution of the global struct namespace. -

-

-Please note that parameterized types are a nice tool and indispensable -for certain use cases. But you'll want to use them sparingly in regular -code, e.g. when all types are actually fixed. -

- -

Garbage Collection of cdata Objects

-

-All explicitly (ffi.new(), ffi.cast() etc.) or -implicitly (accessors) created cdata objects are garbage collected. -You need to ensure to retain valid references to cdata objects -somewhere on a Lua stack, an upvalue or in a Lua table while they are -still in use. Once the last reference to a cdata object is gone, the -garbage collector will automatically free the memory used by it (at -the end of the next GC cycle). -

-

-Please note that pointers themselves are cdata objects, however they -are not followed by the garbage collector. So e.g. if you -assign a cdata array to a pointer, you must keep the cdata object -holding the array alive as long as the pointer is still in use: -

-
-ffi.cdef[[
-typedef struct { int *a; } foo_t;
-]]
-
-local s = ffi.new("foo_t", ffi.new("int[10]")) -- WRONG!
-
-local a = ffi.new("int[10]") -- OK
-local s = ffi.new("foo_t", a)
--- Now do something with 's', but keep 'a' alive until you're done.
-
-

-Similar rules apply for Lua strings which are implicitly converted to -"const char *": the string object itself must be -referenced somewhere or it'll be garbage collected eventually. The -pointer will then point to stale data, which may have already been -overwritten. Note that string literals are automatically kept -alive as long as the function containing it (actually its prototype) -is not garbage collected. -

-

-Objects which are passed as an argument to an external C function -are kept alive until the call returns. So it's generally safe to -create temporary cdata objects in argument lists. This is a common -idiom for passing specific C types to -vararg functions. -

-

-Memory areas returned by C functions (e.g. from malloc()) -must be manually managed, of course (or use -ffi.gc()). Pointers to -cdata objects are indistinguishable from pointers returned by C -functions (which is one of the reasons why the GC cannot follow them). -

- -

Callbacks

-

-The LuaJIT FFI automatically generates special callback functions -whenever a Lua function is converted to a C function pointer. This -associates the generated callback function pointer with the C type -of the function pointer and the Lua function object (closure). -

-

-This can happen implicitly due to the usual conversions, e.g. when -passing a Lua function to a function pointer argument. Or you can use -ffi.cast() to explicitly cast a Lua function to a -C function pointer. -

-

-Currently only certain C function types can be used as callback -functions. Neither C vararg functions nor functions with -pass-by-value aggregate argument or result types are supported. There -are no restrictions for the kind of Lua functions that can be called -from the callback — no checks for the proper number of arguments -are made. The return value of the Lua function will be converted to the -result type and an error will be thrown for invalid conversions. -

-

-It's allowed to throw errors across a callback invocation, but it's not -advisable in general. Do this only if you know the C function, that -called the callback, copes with the forced stack unwinding and doesn't -leak resources. -

-

-One thing that's not allowed, is to let an FFI call into a C function -get JIT-compiled, which in turn calls a callback, calling into Lua again. -Usually this attempt is caught by the interpreter first and the -C function is blacklisted for compilation. -

-

-However, this heuristic may fail under specific circumstances: e.g. a -message polling function might not run Lua callbacks right away and the call -gets JIT-compiled. If it later happens to call back into Lua (e.g. a rarely -invoked error callback), you'll get a VM PANIC with the message -"bad callback". Then you'll need to manually turn off -JIT-compilation with -jit.off() for the -surrounding Lua function that invokes such a message polling function (or -similar). -

- -

Callback resource handling

-

-Callbacks take up resources — you can only have a limited number -of them at the same time (500 - 1000, depending on the -architecture). The associated Lua functions are anchored to prevent -garbage collection, too. -

-

-Callbacks due to implicit conversions are permanent! There is no -way to guess their lifetime, since the C side might store the -function pointer for later use (typical for GUI toolkits). The associated -resources cannot be reclaimed until termination: -

-
-ffi.cdef[[
-typedef int (__stdcall *WNDENUMPROC)(void *hwnd, intptr_t l);
-int EnumWindows(WNDENUMPROC func, intptr_t l);
-]]
-
--- Implicit conversion to a callback via function pointer argument.
-local count = 0
-ffi.C.EnumWindows(function(hwnd, l)
-  count = count + 1
-  return true
-end, 0)
--- The callback is permanent and its resources cannot be reclaimed!
--- Ok, so this may not be a problem, if you do this only once.
-
-

-Note: this example shows that you must properly declare -__stdcall callbacks on Windows/x86 systems. The calling -convention cannot be automatically detected, unlike for -__stdcall calls to Windows functions. -

-

-For some use cases it's necessary to free up the resources or to -dynamically redirect callbacks. Use an explicit cast to a -C function pointer and keep the resulting cdata object. Then use -the cb:free() -or cb:set() methods -on the cdata object: -

-
--- Explicitly convert to a callback via cast.
-local count = 0
-local cb = ffi.cast("WNDENUMPROC", function(hwnd, l)
-  count = count + 1
-  return true
-end)
-
--- Pass it to a C function.
-ffi.C.EnumWindows(cb, 0)
--- EnumWindows doesn't need the callback after it returns, so free it.
-
-cb:free()
--- The callback function pointer is no longer valid and its resources
--- will be reclaimed. The created Lua closure will be garbage collected.
-
- -

Callback performance

-

-Callbacks are slow! First, the C to Lua transition itself -has an unavoidable cost, similar to a lua_call() or -lua_pcall(). Argument and result marshalling add to that cost. -And finally, neither the C compiler nor LuaJIT can inline or -optimize across the language barrier and hoist repeated computations out -of a callback function. -

-

-Do not use callbacks for performance-sensitive work: e.g. consider a -numerical integration routine which takes a user-defined function to -integrate over. It's a bad idea to call a user-defined Lua function from -C code millions of times. The callback overhead will be absolutely -detrimental for performance. -

-

-It's considerably faster to write the numerical integration routine -itself in Lua — the JIT compiler will be able to inline the -user-defined function and optimize it together with its calling context, -with very competitive performance. -

-

-As a general guideline: use callbacks only when you must, because -of existing C APIs. E.g. callback performance is irrelevant for a -GUI application, which waits for user input most of the time, anyway. -

-

-For new designs avoid push-style APIs: a C function repeatedly -calling a callback for each result. Instead use pull-style APIs: -call a C function repeatedly to get a new result. Calls from Lua -to C via the FFI are much faster than the other way round. Most well-designed -libraries already use pull-style APIs (read/write, get/put). -

- -

C Library Namespaces

-

-A C library namespace is a special kind of object which allows -access to the symbols contained in shared libraries or the default -symbol namespace. The default -ffi.C namespace is -automatically created when the FFI library is loaded. C library -namespaces for specific shared libraries may be created with the -ffi.load() API -function. -

-

-Indexing a C library namespace object with a symbol name (a Lua -string) automatically binds it to the library. First the symbol type -is resolved — it must have been declared with -ffi.cdef. Then the -symbol address is resolved by searching for the symbol name in the -associated shared libraries or the default symbol namespace. Finally, -the resulting binding between the symbol name, the symbol type and its -address is cached. Missing symbol declarations or nonexistent symbol -names cause an error. -

-

-This is what happens on a read access for the different kinds of -symbols: -

- -

-This is what happens on a write access: -

- -

-C library namespaces themselves are garbage collected objects. If -the last reference to the namespace object is gone, the garbage -collector will eventually release the shared library reference and -remove all memory associated with the namespace. Since this may -trigger the removal of the shared library from the memory of the -running process, it's generally not safe to use function -cdata objects obtained from a library if the namespace object may be -unreferenced. -

-

-Performance notice: the JIT compiler specializes to the identity of -namespace objects and to the strings used to index it. This -effectively turns function cdata objects into constants. It's not -useful and actually counter-productive to explicitly cache these -function objects, e.g. local strlen = ffi.C.strlen. OTOH it -is useful to cache the namespace itself, e.g. local C = -ffi.C. -

- -

No Hand-holding!

-

-The FFI library has been designed as a low-level library. The -goal is to interface with C code and C data types with a -minimum of overhead. This means you can do anything you can do -from C: access all memory, overwrite anything in memory, call -machine code at any memory address and so on. -

-

-The FFI library provides no memory safety, unlike regular Lua -code. It will happily allow you to dereference a NULL -pointer, to access arrays out of bounds or to misdeclare -C functions. If you make a mistake, your application might crash, -just like equivalent C code would. -

-

-This behavior is inevitable, since the goal is to provide full -interoperability with C code. Adding extra safety measures, like -bounds checks, would be futile. There's no way to detect -misdeclarations of C functions, since shared libraries only -provide symbol names, but no type information. Likewise there's no way -to infer the valid range of indexes for a returned pointer. -

-

-Again: the FFI library is a low-level library. This implies it needs -to be used with care, but it's flexibility and performance often -outweigh this concern. If you're a C or C++ developer, it'll be easy -to apply your existing knowledge. OTOH writing code for the FFI -library is not for the faint of heart and probably shouldn't be the -first exercise for someone with little experience in Lua, C or C++. -

-

-As a corollary of the above, the FFI library is not safe for use by -untrusted Lua code. If you're sandboxing untrusted Lua code, you -definitely don't want to give this code access to the FFI library or -to any cdata object (except 64 bit integers or complex -numbers). Any properly engineered Lua sandbox needs to provide safety -wrappers for many of the standard Lua library functions — -similar wrappers need to be written for high-level operations on FFI -data types, too. -

- -

Current Status

-

-The initial release of the FFI library has some limitations and is -missing some features. Most of these will be fixed in future releases. -

-

-C language support is -currently incomplete: -

- -

-The JIT compiler already handles a large subset of all FFI operations. -It automatically falls back to the interpreter for unimplemented -operations (you can check for this with the --jv command line option). -The following operations are currently not compiled and may exhibit -suboptimal performance, especially when used in inner loops: -

- -

-Other missing features: -

- -
-
- - - diff --git a/lib/LuaJIT/doc/ext_ffi_tutorial.html b/lib/LuaJIT/doc/ext_ffi_tutorial.html deleted file mode 100644 index e0b0821..0000000 --- a/lib/LuaJIT/doc/ext_ffi_tutorial.html +++ /dev/null @@ -1,602 +0,0 @@ - - - -FFI Tutorial - - - - - - - - -
-Lua -
- - -
-

-This page is intended to give you an overview of the features of the FFI -library by presenting a few use cases and guidelines. -

-

-This page makes no attempt to explain all of the FFI library, though. -You'll want to have a look at the ffi.* API -function reference and the FFI -semantics to learn more. -

- -

Loading the FFI Library

-

-The FFI library is built into LuaJIT by default, but it's not loaded -and initialized by default. The suggested way to use the FFI library -is to add the following to the start of every Lua file that needs one -of its functions: -

-
-local ffi = require("ffi")
-
-

-Please note this doesn't define an ffi variable in the table -of globals — you really need to use the local variable. The -require function ensures the library is only loaded once. -

-

-Note: If you want to experiment with the FFI from the interactive prompt -of the command line executable, omit the local, as it doesn't -preserve local variables across lines. -

- -

Accessing Standard System Functions

-

-The following code explains how to access standard system functions. -We slowly print two lines of dots by sleeping for 10 milliseconds -after each dot: -

-
- 
-①
-
-
-
-
-
-②
-③
-④
-
-
-
-⑤
-
-
-
-
-
-⑥local ffi = require("ffi")
-ffi.cdef[[
-void Sleep(int ms);
-int poll(struct pollfd *fds, unsigned long nfds, int timeout);
-]]
-
-local sleep
-if ffi.os == "Windows" then
-  function sleep(s)
-    ffi.C.Sleep(s*1000)
-  end
-else
-  function sleep(s)
-    ffi.C.poll(nil, 0, s*1000)
-  end
-end
-
-for i=1,160 do
-  io.write("."); io.flush()
-  sleep(0.01)
-end
-io.write("\n")
-
-

-Here's the step-by-step explanation: -

-

- This defines the -C library functions we're going to use. The part inside the -double-brackets (in green) is just standard C syntax. You can -usually get this info from the C header files or the -documentation provided by each C library or C compiler. -

-

- The difficulty we're -facing here, is that there are different standards to choose from. -Windows has a simple Sleep() function. On other systems there -are a variety of functions available to achieve sub-second sleeps, but -with no clear consensus. Thankfully poll() can be used for -this task, too, and it's present on most non-Windows systems. The -check for ffi.os makes sure we use the Windows-specific -function only on Windows systems. -

-

- Here we're wrapping the -call to the C function in a Lua function. This isn't strictly -necessary, but it's helpful to deal with system-specific issues only -in one part of the code. The way we're wrapping it ensures the check -for the OS is only done during initialization and not for every call. -

-

- A more subtle point is -that we defined our sleep() function (for the sake of this -example) as taking the number of seconds, but accepting fractional -seconds. Multiplying this by 1000 gets us milliseconds, but that still -leaves it a Lua number, which is a floating-point value. Alas, the -Sleep() function only accepts an integer value. Luckily for -us, the FFI library automatically performs the conversion when calling -the function (truncating the FP value towards zero, like in C). -

-

-Some readers will notice that Sleep() is part of -KERNEL32.DLL and is also a stdcall function. So how -can this possibly work? The FFI library provides the ffi.C -default C library namespace, which allows calling functions from -the default set of libraries, like a C compiler would. Also, the -FFI library automatically detects stdcall functions, so you -don't need to declare them as such. -

-

- The poll() -function takes a couple more arguments we're not going to use. You can -simply use nil to pass a NULL pointer and 0 -for the nfds parameter. Please note that the -number 0 does not convert to a pointer value, -unlike in C++. You really have to pass pointers to pointer arguments -and numbers to number arguments. -

-

-The page on FFI semantics has all -of the gory details about -conversions between Lua -objects and C types. For the most part you don't have to deal -with this, as it's performed automatically and it's carefully designed -to bridge the semantic differences between Lua and C. -

-

- Now that we have defined -our own sleep() function, we can just call it from plain Lua -code. That wasn't so bad, huh? Turning these boring animated dots into -a fascinating best-selling game is left as an exercise for the reader. -:-) -

- -

Accessing the zlib Compression Library

-

-The following code shows how to access the zlib compression library from Lua code. -We'll define two convenience wrapper functions that take a string and -compress or uncompress it to another string: -

-
- 
-①
-
-
-
-
-
-
-②
-
-
-③
-
-④
-
-
-⑤
-
-
-⑥
-
-
-
-
-
-
-
-⑦local ffi = require("ffi")
-ffi.cdef[[
-unsigned long compressBound(unsigned long sourceLen);
-int compress2(uint8_t *dest, unsigned long *destLen,
-	      const uint8_t *source, unsigned long sourceLen, int level);
-int uncompress(uint8_t *dest, unsigned long *destLen,
-	       const uint8_t *source, unsigned long sourceLen);
-]]
-local zlib = ffi.load(ffi.os == "Windows" and "zlib1" or "z")
-
-local function compress(txt)
-  local n = zlib.compressBound(#txt)
-  local buf = ffi.new("uint8_t[?]", n)
-  local buflen = ffi.new("unsigned long[1]", n)
-  local res = zlib.compress2(buf, buflen, txt, #txt, 9)
-  assert(res == 0)
-  return ffi.string(buf, buflen[0])
-end
-
-local function uncompress(comp, n)
-  local buf = ffi.new("uint8_t[?]", n)
-  local buflen = ffi.new("unsigned long[1]", n)
-  local res = zlib.uncompress(buf, buflen, comp, #comp)
-  assert(res == 0)
-  return ffi.string(buf, buflen[0])
-end
-
--- Simple test code.
-local txt = string.rep("abcd", 1000)
-print("Uncompressed size: ", #txt)
-local c = compress(txt)
-print("Compressed size: ", #c)
-local txt2 = uncompress(c, #txt)
-assert(txt2 == txt)
-
-

-Here's the step-by-step explanation: -

-

- This defines some of the -C functions provided by zlib. For the sake of this example, some -type indirections have been reduced and it uses the pre-defined -fixed-size integer types, while still adhering to the zlib API/ABI. -

-

- This loads the zlib shared -library. On POSIX systems it's named libz.so and usually -comes pre-installed. Since ffi.load() automatically adds any -missing standard prefixes/suffixes, we can simply load the -"z" library. On Windows it's named zlib1.dll and -you'll have to download it first from the -» zlib site. The check for -ffi.os makes sure we pass the right name to -ffi.load(). -

-

- First, the maximum size of -the compression buffer is obtained by calling the -zlib.compressBound function with the length of the -uncompressed string. The next line allocates a byte buffer of this -size. The [?] in the type specification indicates a -variable-length array (VLA). The actual number of elements of this -array is given as the 2nd argument to ffi.new(). -

-

- This may look strange at -first, but have a look at the declaration of the compress2 -function from zlib: the destination length is defined as a pointer! -This is because you pass in the maximum buffer size and get back the -actual length that was used. -

-

-In C you'd pass in the address of a local variable -(&buflen). But since there's no address-of operator in -Lua, we'll just pass in a one-element array. Conveniently it can be -initialized with the maximum buffer size in one step. Calling the -actual zlib.compress2 function is then straightforward. -

-

- We want to return the -compressed data as a Lua string, so we'll use ffi.string(). -It needs a pointer to the start of the data and the actual length. The -length has been returned in the buflen array, so we'll just -get it from there. -

-

-Note that since the function returns now, the buf and -buflen variables will eventually be garbage collected. This -is fine, because ffi.string() has copied the contents to a -newly created (interned) Lua string. If you plan to call this function -lots of times, consider reusing the buffers and/or handing back the -results in buffers instead of strings. This will reduce the overhead -for garbage collection and string interning. -

-

- The uncompress -functions does the exact opposite of the compress function. -The compressed data doesn't include the size of the original string, -so this needs to be passed in. Otherwise no surprises here. -

-

- The code, that makes use -of the functions we just defined, is just plain Lua code. It doesn't -need to know anything about the LuaJIT FFI — the convenience -wrapper functions completely hide it. -

-

-One major advantage of the LuaJIT FFI is that you are now able to -write those wrappers in Lua. And at a fraction of the time it -would cost you to create an extra C module using the Lua/C API. -Many of the simpler C functions can probably be used directly -from your Lua code, without any wrappers. -

-

-Side note: the zlib API uses the long type for passing -lengths and sizes around. But all those zlib functions actually only -deal with 32 bit values. This is an unfortunate choice for a -public API, but may be explained by zlib's history — we'll just -have to deal with it. -

-

-First, you should know that a long is a 64 bit type e.g. -on POSIX/x64 systems, but a 32 bit type on Windows/x64 and on -32 bit systems. Thus a long result can be either a plain -Lua number or a boxed 64 bit integer cdata object, depending on -the target system. -

-

-Ok, so the ffi.* functions generally accept cdata objects -wherever you'd want to use a number. That's why we get a away with -passing n to ffi.string() above. But other Lua -library functions or modules don't know how to deal with this. So for -maximum portability one needs to use tonumber() on returned -long results before passing them on. Otherwise the -application might work on some systems, but would fail in a POSIX/x64 -environment. -

- -

Defining Metamethods for a C Type

-

-The following code explains how to define metamethods for a C type. -We define a simple point type and add some operations to it: -

-
- 
-①
-
-
-
-②
-
-③
-
-④
-
-
-
-⑤
-
-⑥local ffi = require("ffi")
-ffi.cdef[[
-typedef struct { double x, y; } point_t;
-]]
-
-local point
-local mt = {
-  __add = function(a, b) return point(a.x+b.x, a.y+b.y) end,
-  __len = function(a) return math.sqrt(a.x*a.x + a.y*a.y) end,
-  __index = {
-    area = function(a) return a.x*a.x + a.y*a.y end,
-  },
-}
-point = ffi.metatype("point_t", mt)
-
-local a = point(3, 4)
-print(a.x, a.y)  --> 3  4
-print(#a)        --> 5
-print(a:area())  --> 25
-local b = a + point(0.5, 8)
-print(#b)        --> 12.5
-
-

-Here's the step-by-step explanation: -

-

- This defines the C type for a -two-dimensional point object. -

-

- We have to declare the variable -holding the point constructor first, because it's used inside of a -metamethod. -

-

- Let's define an __add -metamethod which adds the coordinates of two points and creates a new -point object. For simplicity, this function assumes that both arguments -are points. But it could be any mix of objects, if at least one operand -is of the required type (e.g. adding a point plus a number or vice -versa). Our __len metamethod returns the distance of a point to -the origin. -

-

- If we run out of operators, we can -define named methods, too. Here the __index table defines an -area function. For custom indexing needs, one might want to -define __index and __newindex functions instead. -

-

- This associates the metamethods with -our C type. This only needs to be done once. For convenience, a -constructor is returned by -ffi.metatype(). -We're not required to use it, though. The original C type can still -be used e.g. to create an array of points. The metamethods automatically -apply to any and all uses of this type. -

-

-Please note that the association with a metatable is permanent and -the metatable must not be modified afterwards! Ditto for the -__index table. -

-

- Here are some simple usage examples -for the point type and their expected results. The pre-defined -operations (such as a.x) can be freely mixed with the newly -defined metamethods. Note that area is a method and must be -called with the Lua syntax for methods: a:area(), not -a.area(). -

-

-The C type metamethod mechanism is most useful when used in -conjunction with C libraries that are written in an object-oriented -style. Creators return a pointer to a new instance and methods take an -instance pointer as the first argument. Sometimes you can just point -__index to the library namespace and __gc to the -destructor and you're done. But often enough you'll want to add -convenience wrappers, e.g. to return actual Lua strings or when -returning multiple values. -

-

-Some C libraries only declare instance pointers as an opaque -void * type. In this case you can use a fake type for all -declarations, e.g. a pointer to a named (incomplete) struct will do: -typedef struct foo_type *foo_handle. The C side doesn't -know what you declare with the LuaJIT FFI, but as long as the underlying -types are compatible, everything still works. -

- -

Translating C Idioms

-

-Here's a list of common C idioms and their translation to the -LuaJIT FFI: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
IdiomC codeLua code
Pointer dereference
int *p;
x = *p;
*p = y;
x = p[0]
p[0] = y
Pointer indexing
int i, *p;
x = p[i];
p[i+1] = y;
x = p[i]
p[i+1] = y
Array indexing
int i, a[];
x = a[i];
a[i+1] = y;
x = a[i]
a[i+1] = y
struct/union dereference
struct foo s;
x = s.field;
s.field = y;
x = s.field
s.field = y
struct/union pointer deref.
struct foo *sp;
x = sp->field;
sp->field = y;
x = s.field
s.field = y
Pointer arithmetic
int i, *p;
x = p + i;
y = p - i;
x = p + i
y = p - i
Pointer difference
int *p1, *p2;
x = p1 - p2;x = p1 - p2
Array element pointer
int i, a[];
x = &a[i];x = a+i
Cast pointer to address
int *p;
x = (intptr_t)p;x = tonumber(
 ffi.cast("intptr_t",
          p))
Functions with outargs
void foo(int *inoutlen);
int len = x;
foo(&len);
y = len;
local len =
  ffi.new("int[1]", x)
foo(len)
y = len[0]
Vararg conversions
int printf(char *fmt, ...);
printf("%g", 1.0);
printf("%d", 1);
 
printf("%g", 1);
printf("%d",
  ffi.new("int", 1))
- -

To Cache or Not to Cache

-

-It's a common Lua idiom to cache library functions in local variables -or upvalues, e.g.: -

-
-local byte, char = string.byte, string.char
-local function foo(x)
-  return char(byte(x)+1)
-end
-
-

-This replaces several hash-table lookups with a (faster) direct use of -a local or an upvalue. This is less important with LuaJIT, since the -JIT compiler optimizes hash-table lookups a lot and is even able to -hoist most of them out of the inner loops. It can't eliminate -all of them, though, and it saves some typing for often-used -functions. So there's still a place for this, even with LuaJIT. -

-

-The situation is a bit different with C function calls via the -FFI library. The JIT compiler has special logic to eliminate all -of the lookup overhead for functions resolved from a -C library namespace! -Thus it's not helpful and actually counter-productive to cache -individual C functions like this: -

-
-local funca, funcb = ffi.C.funca, ffi.C.funcb -- Not helpful!
-local function foo(x, n)
-  for i=1,n do funcb(funca(x, i), 1) end
-end
-
-

-This turns them into indirect calls and generates bigger and slower -machine code. Instead you'll want to cache the namespace itself and -rely on the JIT compiler to eliminate the lookups: -

-
-local C = ffi.C          -- Instead use this!
-local function foo(x, n)
-  for i=1,n do C.funcb(C.funca(x, i), 1) end
-end
-
-

-This generates both shorter and faster code. So don't cache -C functions, but do cache namespaces! Most often the -namespace is already in a local variable at an outer scope, e.g. from -local lib = ffi.load(...). Note that copying -it to a local variable in the function scope is unnecessary. -

-
-
- - - diff --git a/lib/LuaJIT/doc/ext_jit.html b/lib/LuaJIT/doc/ext_jit.html deleted file mode 100644 index 73cd3c2..0000000 --- a/lib/LuaJIT/doc/ext_jit.html +++ /dev/null @@ -1,200 +0,0 @@ - - - -jit.* Library - - - - - - - -
-Lua -
- - -
-

-The functions in this built-in module control the behavior of the JIT -compiler engine. Note that JIT-compilation is fully automatic — -you probably won't need to use any of the following functions unless -you have special needs. -

- -

jit.on()
-jit.off()

-

-Turns the whole JIT compiler on (default) or off. -

-

-These functions are typically used with the command line options --j on or -j off. -

- -

jit.flush()

-

-Flushes the whole cache of compiled code. -

- -

jit.on(func|true [,true|false])
-jit.off(func|true [,true|false])
-jit.flush(func|true [,true|false])

-

-jit.on enables JIT compilation for a Lua function (this is -the default). -

-

-jit.off disables JIT compilation for a Lua function and -flushes any already compiled code from the code cache. -

-

-jit.flush flushes the code, but doesn't affect the -enable/disable status. -

-

-The current function, i.e. the Lua function calling this library -function, can also be specified by passing true as the first -argument. -

-

-If the second argument is true, JIT compilation is also -enabled, disabled or flushed recursively for all sub-functions of a -function. With false only the sub-functions are affected. -

-

-The jit.on and jit.off functions only set a flag -which is checked when the function is about to be compiled. They do -not trigger immediate compilation. -

-

-Typical usage is jit.off(true, true) in the main chunk -of a module to turn off JIT compilation for the whole module for -debugging purposes. -

- -

jit.flush(tr)

-

-Flushes the root trace, specified by its number, and all of its side -traces from the cache. The code for the trace will be retained as long -as there are any other traces which link to it. -

- -

status, ... = jit.status()

-

-Returns the current status of the JIT compiler. The first result is -either true or false if the JIT compiler is turned -on or off. The remaining results are strings for CPU-specific features -and enabled optimizations. -

- -

jit.version

-

-Contains the LuaJIT version string. -

- -

jit.version_num

-

-Contains the version number of the LuaJIT core. Version xx.yy.zz -is represented by the decimal number xxyyzz. -

- -

jit.os

-

-Contains the target OS name: -"Windows", "Linux", "OSX", "BSD", "POSIX" or "Other". -

- -

jit.arch

-

-Contains the target architecture name: -"x86", "x64", "arm", "arm64", "ppc", "mips" or "mips64". -

- -

jit.opt.* — JIT compiler optimization control

-

-This sub-module provides the backend for the -O command line -option. -

-

-You can also use it programmatically, e.g.: -

-
-jit.opt.start(2) -- same as -O2
-jit.opt.start("-dce")
-jit.opt.start("hotloop=10", "hotexit=2")
-
-

-Unlike in LuaJIT 1.x, the module is built-in and -optimization is turned on by default! -It's no longer necessary to run require("jit.opt").start(), -which was one of the ways to enable optimization. -

- -

jit.util.* — JIT compiler introspection

-

-This sub-module holds functions to introspect the bytecode, generated -traces, the IR and the generated machine code. The functionality -provided by this module is still in flux and therefore undocumented. -

-

-The debug modules -jbc, -jv and -jdump make -extensive use of these functions. Please check out their source code, -if you want to know more. -

-
-
- - - diff --git a/lib/LuaJIT/doc/ext_profiler.html b/lib/LuaJIT/doc/ext_profiler.html deleted file mode 100644 index d34ce6d..0000000 --- a/lib/LuaJIT/doc/ext_profiler.html +++ /dev/null @@ -1,364 +0,0 @@ - - - -Profiler - - - - - - - -
-Lua -
- - -
-

-LuaJIT has an integrated statistical profiler with very low overhead. It -allows sampling the currently executing stack and other parameters in -regular intervals. -

-

-The integrated profiler can be accessed from three levels: -

- - -

High-Level Profiler

-

-The bundled high-level profiler offers basic profiling functionality. It -generates simple textual summaries or source code annotations. It can be -accessed with the -jp command line option -or from Lua code by loading the underlying jit.p module. -

-

-To cut to the chase — run this to get a CPU usage profile by -function name: -

-
-luajit -jp myapp.lua
-
-

-It's not a stated goal of the bundled profiler to add every -possible option or to cater for special profiling needs. The low-level -profiler APIs are documented below. They may be used by third-party -authors to implement advanced functionality, e.g. IDE integration or -graphical profilers. -

-

-Note: Sampling works for both interpreted and JIT-compiled code. The -results for JIT-compiled code may sometimes be surprising. LuaJIT -heavily optimizes and inlines Lua code — there's no simple -one-to-one correspondence between source code lines and the sampled -machine code. -

- -

-jp=[options[,output]]

-

-The -jp command line option starts the high-level profiler. -When the application run by the command line terminates, the profiler -stops and writes the results to stdout or to the specified -output file. -

-

-The options argument specifies how the profiling is to be -performed: -

- -

-The default output for -jp is a list of the most CPU consuming -spots in the application. Increasing the stack dump depth with (say) --jp=2 may help to point out the main callers or callees of -hotspots. But sample aggregation is still flat per unique stack dump. -

-

-To get a two-level view (split view) of callers/callees, use --jp=s or -jp=-s. The percentages shown for the second -level are relative to the first level. -

-

-To see how much time is spent in each line relative to a function, use --jp=fl. -

-

-To see how much time is spent in different VM states or -zones, use -jp=v or -jp=z. -

-

-Combinations of v/z with f/F/l produce two-level -views, e.g. -jp=vf or -jp=fv. This shows the time -spent in a VM state or zone vs. hotspots. This can be used to answer -questions like "Which time consuming functions are only interpreted?" or -"What's the garbage collector overhead for a specific function?". -

-

-Multiple options can be combined — but not all combinations make -sense, see above. E.g. -jp=3si4m1 samples three stack levels -deep in 4ms intervals and shows a split view of the CPU consuming -functions and their callers with a 1% threshold. -

-

-Source code annotations produced by -jp=a or -jp=A are -always flat and at the line level. Obviously, the source code files need -to be readable by the profiler script. -

-

-The high-level profiler can also be started and stopped from Lua code with: -

-
-require("jit.p").start(options, output)
-...
-require("jit.p").stop()
-
- -

jit.zone — Zones

-

-Zones can be used to provide information about different parts of an -application to the high-level profiler. E.g. a game could make use of an -"AI" zone, a "PHYS" zone, etc. Zones are hierarchical, -organized as a stack. -

-

-The jit.zone module needs to be loaded explicitly: -

-
-local zone = require("jit.zone")
-
- -

-To show the time spent in each zone use -jp=z. To show the time -spent relative to hotspots use e.g. -jp=zf or -jp=fz. -

- -

Low-level Lua API

-

-The jit.profile module gives access to the low-level API of the -profiler from Lua code. This module needs to be loaded explicitly: -

-local profile = require("jit.profile")
-
-

-This module can be used to implement your own higher-level profiler. -A typical profiling run starts the profiler, captures stack dumps in -the profiler callback, adds them to a hash table to aggregate the number -of samples, stops the profiler and then analyzes all of the captured -stack dumps. Other parameters can be sampled in the profiler callback, -too. But it's important not to spend too much time in the callback, -since this may skew the statistics. -

- -

profile.start(mode, cb) -— Start profiler

-

-This function starts the profiler. The mode argument is a -string holding options: -

- -

-The cb argument is a callback function which is called with -three arguments: (thread, samples, vmstate). The callback is -called on a separate coroutine, the thread argument is the -state that holds the stack to sample for profiling. Note: do -not modify the stack of that state or call functions on it. -

-

-samples gives the number of accumulated samples since the last -callback (usually 1). -

-

-vmstate holds the VM state at the time the profiling timer -triggered. This may or may not correspond to the state of the VM when -the profiling callback is called. The state is either 'N' -native (compiled) code, 'I' interpreted code, 'C' -C code, 'G' the garbage collector, or 'J' the JIT -compiler. -

- -

profile.stop() -— Stop profiler

-

-This function stops the profiler. -

- -

dump = profile.dumpstack([thread,] fmt, depth) -— Dump stack

-

-This function allows taking stack dumps in an efficient manner. It -returns a string with a stack dump for the thread (coroutine), -formatted according to the fmt argument: -

- -

-The depth argument gives the number of frames to dump, starting -at the topmost frame of the thread. A negative number dumps the frames in -inverse order. -

-

-The first example prints a list of the current module names and line -numbers of up to 10 frames in separate lines. The second example prints -semicolon-separated function names for all frames (up to 100) in inverse -order: -

-
-print(profile.dumpstack(thread, "l\n", 10))
-print(profile.dumpstack(thread, "lZ;", -100))
-
- -

Low-level C API

-

-The profiler can be controlled directly from C code, e.g. for -use by IDEs. The declarations are in "luajit.h" (see -Lua/C API extensions). -

- -

luaJIT_profile_start(L, mode, cb, data) -— Start profiler

-

-This function starts the profiler. See -above for a description of the mode argument. -

-

-The cb argument is a callback function with the following -declaration: -

-
-typedef void (*luaJIT_profile_callback)(void *data, lua_State *L,
-                                        int samples, int vmstate);
-
-

-data is available for use by the callback. L is the -state that holds the stack to sample for profiling. Note: do -not modify this stack or call functions on this stack — -use a separate coroutine for this purpose. See -above for a description of samples and vmstate. -

- -

luaJIT_profile_stop(L) -— Stop profiler

-

-This function stops the profiler. -

- -

p = luaJIT_profile_dumpstack(L, fmt, depth, len) -— Dump stack

-

-This function allows taking stack dumps in an efficient manner. -See above for a description of fmt -and depth. -

-

-This function returns a const char * pointing to a -private string buffer of the profiler. The int *len -argument returns the length of the output string. The buffer is -overwritten on the next call and deallocated when the profiler stops. -You either need to consume the content immediately or copy it for later -use. -

-
-
- - - diff --git a/lib/LuaJIT/doc/extensions.html b/lib/LuaJIT/doc/extensions.html deleted file mode 100644 index 7379041..0000000 --- a/lib/LuaJIT/doc/extensions.html +++ /dev/null @@ -1,482 +0,0 @@ - - - -Extensions - - - - - - - - -
-Lua -
- - -
-

-LuaJIT is fully upwards-compatible with Lua 5.1. It supports all -» standard Lua -library functions and the full set of -» Lua/C API -functions. -

-

-LuaJIT is also fully ABI-compatible to Lua 5.1 at the linker/dynamic -loader level. This means you can compile a C module against the -standard Lua headers and load the same shared library from either Lua -or LuaJIT. -

-

-LuaJIT extends the standard Lua VM with new functionality and adds -several extension modules. Please note this page is only about -functional enhancements and not about performance enhancements, -such as the optimized VM, the faster interpreter or the JIT compiler. -

- -

Extensions Modules

-

-LuaJIT comes with several built-in extension modules: -

- -

bit.* — Bitwise operations

-

-LuaJIT supports all bitwise operations as defined by -» Lua BitOp: -

-
-bit.tobit  bit.tohex  bit.bnot    bit.band bit.bor  bit.bxor
-bit.lshift bit.rshift bit.arshift bit.rol  bit.ror  bit.bswap
-
-

-This module is a LuaJIT built-in — you don't need to download or -install Lua BitOp. The Lua BitOp site has full documentation for all -» Lua BitOp API functions. -The FFI adds support for -64 bit bitwise operations, -using the same API functions. -

-

-Please make sure to require the module before using any of -its functions: -

-
-local bit = require("bit")
-
-

-An already installed Lua BitOp module is ignored by LuaJIT. -This way you can use bit operations from both Lua and LuaJIT on a -shared installation. -

- -

ffi.* — FFI library

-

-The FFI library allows calling external -C functions and the use of C data structures from pure Lua -code. -

- -

jit.* — JIT compiler control

-

-The functions in this module -control the behavior of the JIT compiler engine. -

- -

C API extensions

-

-LuaJIT adds some -extra functions to the Lua/C API. -

- -

Profiler

-

-LuaJIT has an integrated profiler. -

- -

Enhanced Standard Library Functions

- -

xpcall(f, err [,args...]) passes arguments

-

-Unlike the standard implementation in Lua 5.1, xpcall() -passes any arguments after the error function to the function -which is called in a protected context. -

- -

loadfile() etc. handle UTF-8 source code

-

-Non-ASCII characters are handled transparently by the Lua source code parser. -This allows the use of UTF-8 characters in identifiers and strings. -A UTF-8 BOM is skipped at the start of the source code. -

- -

tostring() etc. canonicalize NaN and ±Inf

-

-All number-to-string conversions consistently convert non-finite numbers -to the same strings on all platforms. NaN results in "nan", -positive infinity results in "inf" and negative infinity results -in "-inf". -

- -

tonumber() etc. use builtin string to number conversion

-

-All string-to-number conversions consistently convert integer and -floating-point inputs in decimal, hexadecimal and binary on all platforms. -strtod() is not used anymore, which avoids numerous -problems with poor C library implementations. The builtin conversion -function provides full precision according to the IEEE-754 standard, it -works independently of the current locale and it supports hex floating-point -numbers (e.g. 0x1.5p-3). -

- -

string.dump(f [,strip]) generates portable bytecode

-

-An extra argument has been added to string.dump(). If set to -true, 'stripped' bytecode without debug information is -generated. This speeds up later bytecode loading and reduces memory -usage. See also the --b command line option. -

-

-The generated bytecode is portable and can be loaded on any architecture -that LuaJIT supports, independent of word size or endianess. However the -bytecode compatibility versions must match. Bytecode stays compatible -for dot releases (x.y.0 → x.y.1), but may change with major or -minor releases (2.0 → 2.1) or between any beta release. Foreign -bytecode (e.g. from Lua 5.1) is incompatible and cannot be loaded. -

-

-Note: LJ_GC64 mode requires a different frame layout, which implies -a different, incompatible bytecode format for ports that use this mode (e.g. -ARM64 or MIPS64) or when explicitly enabled for x64. This may be rectified -in the future. -

- -

table.new(narray, nhash) allocates a pre-sized table

-

-An extra library function table.new() can be made available via -require("table.new"). This creates a pre-sized table, just like -the C API equivalent lua_createtable(). This is useful for big -tables if the final table size is known and automatic table resizing is -too expensive. -

- -

table.clear(tab) clears a table

-

-An extra library function table.clear() can be made available -via require("table.clear"). This clears all keys and values -from a table, but preserves the allocated array/hash sizes. This is -useful when a table, which is linked from multiple places, needs to be -cleared and/or when recycling a table for use by the same context. This -avoids managing backlinks, saves an allocation and the overhead of -incremental array/hash part growth. -

-

-Please note this function is meant for very specific situations. In most -cases it's better to replace the (usually single) link with a new table -and let the GC do its work. -

- -

Enhanced PRNG for math.random()

-

-LuaJIT uses a Tausworthe PRNG with period 2^223 to implement -math.random() and math.randomseed(). The quality of -the PRNG results is much superior compared to the standard Lua -implementation which uses the platform-specific ANSI rand(). -

-

-The PRNG generates the same sequences from the same seeds on all -platforms and makes use of all bits in the seed argument. -math.random() without arguments generates 52 pseudo-random bits -for every call. The result is uniformly distributed between 0.0 and 1.0. -It's correctly scaled up and rounded for math.random(n [,m]) to -preserve uniformity. -

- -

io.* functions handle 64 bit file offsets

-

-The file I/O functions in the standard io.* library handle -64 bit file offsets. In particular this means it's possible -to open files larger than 2 Gigabytes and to reposition or obtain -the current file position for offsets beyond 2 GB -(fp:seek() method). -

- -

debug.* functions identify metamethods

-

-debug.getinfo() and lua_getinfo() also return information -about invoked metamethods. The namewhat field is set to -"metamethod" and the name field has the name of -the corresponding metamethod (e.g. "__index"). -

- -

Fully Resumable VM

-

-The LuaJIT VM is fully resumable. This means you can yield from a -coroutine even across contexts, where this would not possible with -the standard Lua 5.1 VM: e.g. you can yield across pcall() -and xpcall(), across iterators and across metamethods. -

- -

Extensions from Lua 5.2

-

-LuaJIT supports some language and library extensions from Lua 5.2. -Features that are unlikely to break existing code are unconditionally -enabled: -

- -

-Other features are only enabled, if LuaJIT is built with --DLUAJIT_ENABLE_LUA52COMPAT: -

- -

-Note: this provides only partial compatibility with Lua 5.2 at the -language and Lua library level. LuaJIT is API+ABI-compatible with -Lua 5.1, which prevents implementing features that would otherwise -break the Lua/C API and ABI (e.g. _ENV). -

- -

Extensions from Lua 5.3

-

-LuaJIT supports some extensions from Lua 5.3: -

- -

C++ Exception Interoperability

-

-LuaJIT has built-in support for interoperating with C++ exceptions. -The available range of features depends on the target platform and -the toolchain used to compile LuaJIT: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PlatformCompilerInteroperability
POSIX/x64, DWARF2 unwindingGCC 4.3+, ClangFull
ARM -DLUAJIT_UNWIND_EXTERNALGCC, ClangFull
Other platforms, DWARF2 unwindingGCC, ClangLimited
Windows/x64MSVC or WinSDKFull
Windows/x86AnyFull
Other platformsOther compilersNo
-

-Full interoperability means: -

- -

-Limited interoperability means: -

- - -

-No interoperability means: -

- -
-
- - - diff --git a/lib/LuaJIT/doc/faq.html b/lib/LuaJIT/doc/faq.html deleted file mode 100644 index ad88c49..0000000 --- a/lib/LuaJIT/doc/faq.html +++ /dev/null @@ -1,185 +0,0 @@ - - - -Frequently Asked Questions (FAQ) - - - - - - - - -
-Lua -
- - -
-
-
Q: Where can I learn more about LuaJIT and Lua?
-
- -
- -
-
Q: Where can I learn more about the compiler technology used by LuaJIT?
-
-I'm planning to write more documentation about the internals of LuaJIT. -In the meantime, please use the following Google Scholar searches -to find relevant papers:
-Search for: » Trace Compiler
-Search for: » JIT Compiler
-Search for: » Dynamic Language Optimizations
-Search for: » SSA Form
-Search for: » Linear Scan Register Allocation
-Here is a list of the » innovative features in LuaJIT.
-And, you know, reading the source is of course the only way to enlightenment. :-) -
-
- -
-
Q: Why do I get this error: "attempt to index global 'arg' (a nil value)"?
-Q: My vararg functions fail after switching to LuaJIT!
-
LuaJIT is compatible to the Lua 5.1 language standard. It doesn't -support the implicit arg parameter for old-style vararg -functions from Lua 5.0.
Please convert your code to the -» Lua 5.1 -vararg syntax.
-
- -
-
Q: Why do I get this error: "bad FPU precision"?
-
Q: I get weird behavior after initializing Direct3D.
-
Q: Some FPU operations crash after I load a Delphi DLL.
-
-
- -DirectX/Direct3D (up to version 9) sets the x87 FPU to single-precision -mode by default. This violates the Windows ABI and interferes with the -operation of many programs — LuaJIT is affected, too. Please make -sure you always use the D3DCREATE_FPU_PRESERVE flag when -initializing Direct3D.
- -Direct3D version 10 or higher do not show this behavior anymore. -Consider testing your application with older versions, too.
- -Similarly, the Borland/Delphi runtime modifies the FPU control word and -enables FP exceptions. Of course this violates the Windows ABI, too. -Please check the Delphi docs for the Set8087CW method. - -
- -
-
Q: Sometimes Ctrl-C fails to stop my Lua program. Why?
-
The interrupt signal handler sets a Lua debug hook. But this is -currently ignored by compiled code (this will eventually be fixed). If -your program is running in a tight loop and never falls back to the -interpreter, the debug hook never runs and can't throw the -"interrupted!" error.
In the meantime you have to press Ctrl-C -twice to get stop your program. That's similar to when it's stuck -running inside a C function under the Lua interpreter.
-
- -
-
Q: Why doesn't my favorite power-patch for Lua apply against LuaJIT?
-
Because it's a completely redesigned VM and has very little code -in common with Lua anymore. Also, if the patch introduces changes to -the Lua semantics, these would need to be reflected everywhere in the -VM, from the interpreter up to all stages of the compiler.
Please -use only standard Lua language constructs. For many common needs you -can use source transformations or use wrapper or proxy functions. -The compiler will happily optimize away such indirections.
-
- -
-
Q: Lua runs everywhere. Why doesn't LuaJIT support my CPU?
-
Because it's a compiler — it needs to generate native -machine code. This means the code generator must be ported to each -architecture. And the fast interpreter is written in assembler and -must be ported, too. This is quite an undertaking.
-The install documentation shows the supported -architectures. Other architectures will follow based on sufficient user -demand and/or sponsoring.
-
- -
-
Q: When will feature X be added? When will the next version be released?
-
When it's ready.
-C'mon, it's open source — I'm doing it on my own time and you're -getting it for free. You can either contribute a patch or sponsor -the development of certain features, if they are important to you. -
-
-
-
- - - diff --git a/lib/LuaJIT/doc/img/contact.png b/lib/LuaJIT/doc/img/contact.png deleted file mode 100644 index 9c73dc594efc1f47309d6c9b73d7719c3a9e04df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1340 zcmV-C1;hG@P)sQ4|K#fZOHEVa==(`aQP0%nM@di3(&I%(O)@h#$&+f^&9&U}9=sU}#xfW8dZX zS6X4+hl`eQb9`=bdTMQUS6N_FRb1EH?oLrx)!OXR*y%bu zKs7fzyTH%6zRkD1%O4*iwYte19Urr}$DpLK7#SM{1qGa-tpfuC0RaJph?9SUjedfR ze1M8)YI0?0aARg}VPtGhP*&yZ{!C6(sq^PzF3k;#Avk3_bkCL7T2MCRjoQjT_h>Vwp zij{MAe{pnuZ*qHWaCvKPcUD+m*xm0?Qd!p9?bO-p)7k3L*XYmH<~BGyy}{8mHafb$ z&bYnIARr?h9v~YW9vK=O7Z@4@1O%I(tO5c8@Y5f50008dNklZz)3AlitwxnPH%H`Uot)Wm#A~UJD{dq04A@c=B#o!5#fVO zK9y#&^Z}?|*LsioK&(FDooZAR)tQj#4t{T51EP;48U9I=7br`Bk^O8MkeX!ZNe^m_BH=Vrj*jZZuSKj$t2j7FZ^2u4YKv8(~ zaMJ@oQZ>+`rSiG$iy;5QP}GpcaF4=ry2srsiZ0RqYjK@LQA)d@GB0_aay0Tvrp83dAL2x{13 zII2|!RUp(7P{l^2T*QHZ71!E*QcTqNtMh0|uLS!2k^8W?Ka#6$aBn3*=LUe(BpUo6 z=nkI1fP*0x3aYH^su6tQT}{)EfU4IyLBQ-;(w1i;#)>KNGk41l6I5_B2)f}c}CK-PL&a{M5Rut(jQ@VX1_p&z6vN)t zNcp7CYSP6-mE96jwhE}y?lvr|2kRa0g^iLTaJ1y+9qs~F+W}}-FHd&oy;TeG2n6hM z2eK~@vIu+Z%WDWZDK7wkG0}TEXW(~!Gk+0t(i)Sck-Ht%F=yzi{ZFXe-}F6T**!vM y)$^3mN5{Eb6*vAD>S)nmP3aw7v29)6WaBSReaJM4z7xj)0000 - - -Installation - - - - - - - - -
-Lua -
- - -
-

-LuaJIT is only distributed as a source package. This page explains -how to build and install LuaJIT with different operating systems -and C compilers. -

-

-For the impatient (on POSIX systems): -

-
-make && sudo make install
-
-

-LuaJIT currently builds out-of-the box on most systems. -Here's the compatibility matrix for the supported combinations of -operating systems, CPUs and compilers: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CPU / OSLinux or
Android
*BSD, OtherOSX 10.4+ or
iOS 3.0+
Windows
XP/Vista/7
x86 (32 bit)GCC 4.2+GCC 4.2+XCode 5.0+
Clang
MSVC, MSVC/EE
WinSDK
MinGW, Cygwin
x64 (64 bit)GCC 4.2+GCC 4.2+
ORBIS (PS4)
XCode 5.0+
Clang
MSVC + SDK v7.0
WinSDK v7.0
Durango (Xbox One)
ARMv5+
ARM9E+
GCC 4.2+GCC 4.2+
PSP2 (PS VITA)
XCode 5.0+
Clang
 
ARM64GCC 4.8+ XCode 6.0+
Clang 3.5+
 
PPCGCC 4.3+GCC 4.3+
GCC 4.1 (PS3)
 XEDK (Xbox 360)
MIPS32
MIPS64
GCC 4.3+GCC 4.3+  
- -

Configuring LuaJIT

-

-The standard configuration should work fine for most installations. -Usually there is no need to tweak the settings. The following files -hold all user-configurable settings: -

-
    -
  • src/luaconf.h sets some configuration variables.
  • -
  • Makefile has settings for installing LuaJIT (POSIX -only).
  • -
  • src/Makefile has settings for compiling LuaJIT -under POSIX, MinGW or Cygwin.
  • -
  • src/msvcbuild.bat has settings for compiling LuaJIT with -MSVC or WinSDK.
  • -
-

-Please read the instructions given in these files, before changing -any settings. -

-

-LuaJIT on x64 currently uses 32 bit GC objects by default. -LJ_GC64 mode may be explicitly enabled: -add XCFLAGS=-DLUAJIT_ENABLE_GC64 to the make command or run -msvcbuild gc64 for MSVC/WinSDK. Please check the note -about the bytecode format -differences, too. -

- -

POSIX Systems (Linux, OSX, *BSD etc.)

-

Prerequisites

-

-Depending on your distribution, you may need to install a package for -GCC, the development headers and/or a complete SDK. E.g. on a current -Debian/Ubuntu, install libc6-dev with the package manager. -

-

-Download the current source package of LuaJIT (pick the .tar.gz), -if you haven't already done so. Move it to a directory of your choice, -open a terminal window and change to this directory. Now unpack the archive -and change to the newly created directory: -

-
-tar zxf LuaJIT-2.0.5.tar.gz
-cd LuaJIT-2.0.5
-

Building LuaJIT

-

-The supplied Makefiles try to auto-detect the settings needed for your -operating system and your compiler. They need to be run with GNU Make, -which is probably the default on your system, anyway. Simply run: -

-
-make
-
-

-This always builds a native binary, depending on the host OS -you're running this command on. Check the section on -cross-compilation for more options. -

-

-By default, modules are only searched under the prefix /usr/local. -You can add an extra prefix to the search paths by appending the -PREFIX option, e.g.: -

-
-make PREFIX=/home/myself/lj2
-
-

-Note for OSX: if the MACOSX_DEPLOYMENT_TARGET environment -variable is not set, then it's forced to 10.4. -

-

Installing LuaJIT

-

-The top-level Makefile installs LuaJIT by default under -/usr/local, i.e. the executable ends up in -/usr/local/bin and so on. You need root privileges -to write to this path. So, assuming sudo is installed on your system, -run the following command and enter your sudo password: -

-
-sudo make install
-
-

-Otherwise specify the directory prefix as an absolute path, e.g.: -

-
-make install PREFIX=/home/myself/lj2
-
-

-Obviously the prefixes given during build and installation need to be the same. -

- -

Windows Systems

-

Prerequisites

-

-Either install one of the open source SDKs -(» MinGW or -» Cygwin), which come with a modified -GCC plus the required development headers. -

-

-Or install Microsoft's Visual C++ (MSVC). The freely downloadable -» Express Edition -works just fine, but only contains an x86 compiler. -

-

-The freely downloadable -» Windows SDK -only comes with command line tools, but this is all you need to build LuaJIT. -It contains x86 and x64 compilers. -

-

-Next, download the source package and unpack it using an archive manager -(e.g. the Windows Explorer) to a directory of your choice. -

-

Building with MSVC

-

-Open a "Visual Studio .NET Command Prompt", cd to the -directory where you've unpacked the sources and run these commands: -

-
-cd src
-msvcbuild
-
-

-Then follow the installation instructions below. -

-

Building with the Windows SDK

-

-Open a "Windows SDK Command Shell" and select the x86 compiler: -

-
-setenv /release /x86
-
-

-Or select the x64 compiler: -

-
-setenv /release /x64
-
-

-Then cd to the directory where you've unpacked the sources -and run these commands: -

-
-cd src
-msvcbuild
-
-

-Then follow the installation instructions below. -

-

Building with MinGW or Cygwin

-

-Open a command prompt window and make sure the MinGW or Cygwin programs -are in your path. Then cd to the directory where -you've unpacked the sources and run this command for MinGW: -

-
-mingw32-make
-
-

-Or this command for Cygwin: -

-
-make
-
-

-Then follow the installation instructions below. -

-

Installing LuaJIT

-

-Copy luajit.exe and lua51.dll (built in the src -directory) to a newly created directory (any location is ok). -Add lua and lua\jit directories below it and copy -all Lua files from the src\jit directory of the distribution -to the latter directory. -

-

-There are no hardcoded -absolute path names — all modules are loaded relative to the -directory where luajit.exe is installed -(see src/luaconf.h). -

- -

Cross-compiling LuaJIT

-

-First, let's clear up some terminology: -

-
    -
  • Host: This is your development system, usually based on a x64 or x86 CPU.
  • -
  • Target: This is the target system you want LuaJIT to run on, e.g. Android/ARM.
  • -
  • Toolchain: This comprises a C compiler, linker, assembler and a matching C library.
  • -
  • Host (or system) toolchain: This is the toolchain used to build native binaries for your host system.
  • -
  • Cross-compile toolchain: This is the toolchain used to build binaries for the target system. They can only be run on the target system.
  • -
-

-The GNU Makefile-based build system allows cross-compiling on any host -for any supported target: -

-
    -
  • Yes, you need a toolchain for both your host and your target!
  • -
  • Both host and target architectures must have the same pointer size.
  • -
  • E.g. if you want to cross-compile to a 32 bit target on a 64 bit host, you need to install the multilib development package (e.g. libc6-dev-i386 on Debian/Ubuntu) and build a 32 bit host part (HOST_CC="gcc -m32").
  • -
  • 64 bit targets always require compilation on a 64 bit host.
  • -
-

-You need to specify TARGET_SYS whenever the host OS and the -target OS differ, or you'll get assembler or linker errors: -

-
    -
  • E.g. if you're compiling on a Windows or OSX host for embedded Linux or Android, you need to add TARGET_SYS=Linux to the examples below.
  • -
  • For a minimal target OS, you may need to disable the built-in allocator in src/Makefile and use TARGET_SYS=Other.
  • -
  • Don't forget to specify the same TARGET_SYS for the install step, too.
  • -
-

-Here are some examples where host and target have the same CPU: -

-
-# Cross-compile to a 32 bit binary on a multilib x64 OS
-make CC="gcc -m32"
-
-# Cross-compile on Debian/Ubuntu for Windows (mingw32 package)
-make HOST_CC="gcc -m32" CROSS=i586-mingw32msvc- TARGET_SYS=Windows
-
-

-The CROSS prefix allows specifying a standard GNU cross-compile -toolchain (Binutils, GCC and a matching libc). The prefix may vary -depending on the --target the toolchain was built for (note the -CROSS prefix has a trailing "-"). The examples below -use the canonical toolchain triplets for Linux. -

-

-Since there's often no easy way to detect CPU features at runtime, it's -important to compile with the proper CPU or architecture settings: - -

    -
  • The best way to get consistent results is to specify the correct settings when building the toolchain yourself.
  • -
  • For a pre-built, generic toolchain add -mcpu=... or -march=... and other necessary flags to TARGET_CFLAGS.
  • -
  • For ARM it's important to have the correct -mfloat-abi=... setting, too. Otherwise LuaJIT may not run at the full performance of your target CPU.
  • -
  • For MIPS it's important to select a supported ABI (o32 on MIPS32, n64 on MIPS64) and consistently compile your project either with hard-float or soft-float compiler settings.
  • -
-

-Here are some examples for targets with a different CPU than the host: -

-
-# ARM soft-float
-make HOST_CC="gcc -m32" CROSS=arm-linux-gnueabi- \
-     TARGET_CFLAGS="-mfloat-abi=soft"
-
-# ARM soft-float ABI with VFP (example for Cortex-A9)
-make HOST_CC="gcc -m32" CROSS=arm-linux-gnueabi- \
-     TARGET_CFLAGS="-mcpu=cortex-a9 -mfloat-abi=softfp"
-
-# ARM hard-float ABI with VFP (armhf, most modern toolchains)
-make HOST_CC="gcc -m32" CROSS=arm-linux-gnueabihf-
-
-# ARM64
-make CROSS=aarch64-linux-
-
-# PPC
-make HOST_CC="gcc -m32" CROSS=powerpc-linux-gnu-
-
-# MIPS32 big-endian
-make HOST_CC="gcc -m32" CROSS=mips-linux-
-# MIPS32 little-endian
-make HOST_CC="gcc -m32" CROSS=mipsel-linux-
-
-# MIPS64 big-endian
-make CROSS=mips-linux- TARGET_CFLAGS="-mips64r2 -mabi=64"
-# MIPS64 little-endian
-make CROSS=mipsel-linux- TARGET_CFLAGS="-mips64r2 -mabi=64"
-
-

-You can cross-compile for Android using the Android NDK. -The environment variables need to match the install locations and the -desired target platform. E.g. Android 4.0 corresponds to ABI level 14. -For details check the folder docs in the NDK directory. -

-

-Only a few common variations for the different CPUs, ABIs and platforms -are listed. Please use your own judgement for which combination you want -to build/deploy or which lowest common denominator you want to pick: -

-
-# Android/ARM, armeabi (ARMv5TE soft-float), Android 2.2+ (Froyo)
-NDK=/opt/android/ndk
-NDKABI=8
-NDKVER=$NDK/toolchains/arm-linux-androideabi-4.9
-NDKP=$NDKVER/prebuilt/linux-x86/bin/arm-linux-androideabi-
-NDKF="--sysroot $NDK/platforms/android-$NDKABI/arch-arm"
-make HOST_CC="gcc -m32" CROSS=$NDKP TARGET_FLAGS="$NDKF"
-
-# Android/ARM, armeabi-v7a (ARMv7 VFP), Android 4.0+ (ICS)
-NDK=/opt/android/ndk
-NDKABI=14
-NDKVER=$NDK/toolchains/arm-linux-androideabi-4.9
-NDKP=$NDKVER/prebuilt/linux-x86/bin/arm-linux-androideabi-
-NDKF="--sysroot $NDK/platforms/android-$NDKABI/arch-arm"
-NDKARCH="-march=armv7-a -mfloat-abi=softfp -Wl,--fix-cortex-a8"
-make HOST_CC="gcc -m32" CROSS=$NDKP TARGET_FLAGS="$NDKF $NDKARCH"
-
-# Android/MIPS, mipsel (MIPS32R1 hard-float), Android 4.0+ (ICS)
-NDK=/opt/android/ndk
-NDKABI=14
-NDKVER=$NDK/toolchains/mipsel-linux-android-4.9
-NDKP=$NDKVER/prebuilt/linux-x86/bin/mipsel-linux-android-
-NDKF="--sysroot $NDK/platforms/android-$NDKABI/arch-mips"
-make HOST_CC="gcc -m32" CROSS=$NDKP TARGET_FLAGS="$NDKF"
-
-# Android/x86, x86 (i686 SSE3), Android 4.0+ (ICS)
-NDK=/opt/android/ndk
-NDKABI=14
-NDKVER=$NDK/toolchains/x86-4.9
-NDKP=$NDKVER/prebuilt/linux-x86/bin/i686-linux-android-
-NDKF="--sysroot $NDK/platforms/android-$NDKABI/arch-x86"
-make HOST_CC="gcc -m32" CROSS=$NDKP TARGET_FLAGS="$NDKF"
-
-

-You can cross-compile for iOS 3.0+ (iPhone/iPad) using the » iOS SDK: -

-

-Note: the JIT compiler is disabled for iOS, because regular iOS Apps -are not allowed to generate code at runtime. You'll only get the performance -of the LuaJIT interpreter on iOS. This is still faster than plain Lua, but -much slower than the JIT compiler. Please complain to Apple, not me. -Or use Android. :-p -

-
-# iOS/ARM (32 bit)
-ISDKP=$(xcrun --sdk iphoneos --show-sdk-path)
-ICC=$(xcrun --sdk iphoneos --find clang)
-ISDKF="-arch armv7 -isysroot $ISDKP"
-make DEFAULT_CC=clang HOST_CC="clang -m32 -arch i386" \
-     CROSS="$(dirname $ICC)/" TARGET_FLAGS="$ISDKF" TARGET_SYS=iOS
-
-# iOS/ARM64
-ISDKP=$(xcrun --sdk iphoneos --show-sdk-path)
-ICC=$(xcrun --sdk iphoneos --find clang)
-ISDKF="-arch arm64 -isysroot $ISDKP"
-make DEFAULT_CC=clang CROSS="$(dirname $ICC)/" \
-     TARGET_FLAGS="$ISDKF" TARGET_SYS=iOS
-
- -

Cross-compiling for consoles

-

-Building LuaJIT for consoles requires both a supported host compiler -(x86 or x64) and a cross-compiler (to PPC or ARM) from the official -console SDK. -

-

-Due to restrictions on consoles, the JIT compiler is disabled and only -the fast interpreter is built. This is still faster than plain Lua, -but much slower than the JIT compiler. The FFI is disabled, too, since -it's not very useful in such an environment. -

-

-The following commands build a static library libluajit.a, -which can be linked against your game, just like the Lua library. -

-

-To cross-compile for PS3 from a Linux host (requires -32 bit GCC, i.e. multilib Linux/x64) or a Windows host (requires -32 bit MinGW), run this command: -

-
-make HOST_CC="gcc -m32" CROSS=ppu-lv2-
-
-

-To cross-compile for PS4 from a Windows host, -open a "Visual Studio .NET Command Prompt" (64 bit host compiler), -cd to the directory where you've unpacked the sources and -run the following commands: -

-
-cd src
-ps4build
-
-

-To cross-compile for PS Vita from a Windows host, -open a "Visual Studio .NET Command Prompt" (32 bit host compiler), -cd to the directory where you've unpacked the sources and -run the following commands: -

-
-cd src
-psvitabuild
-
-

-To cross-compile for Xbox 360 from a Windows host, -open a "Visual Studio .NET Command Prompt" (32 bit host compiler), -cd to the directory where you've unpacked the sources and run -the following commands: -

-
-cd src
-xedkbuild
-
-

-To cross-compile for Xbox One from a Windows host, -open a "Visual Studio .NET Command Prompt" (64 bit host compiler), -cd to the directory where you've unpacked the sources and run -the following commands: -

-
-cd src
-xb1build
-
- -

Embedding LuaJIT

-

-LuaJIT is API-compatible with Lua 5.1. If you've already embedded Lua -into your application, you probably don't need to do anything to switch -to LuaJIT, except link with a different library: -

-
    -
  • It's strongly suggested to build LuaJIT separately using the supplied -build system. Please do not attempt to integrate the individual -source files into your build tree. You'll most likely get the internal build -dependencies wrong or mess up the compiler flags. Treat LuaJIT like any -other external library and link your application with either the dynamic -or static library, depending on your needs.
  • -
  • If you want to load C modules compiled for plain Lua -with require(), you need to make sure the public symbols -(e.g. lua_pushnumber) are exported, too: -
    • On POSIX systems you can either link to the shared library -or link the static library into your application. In the latter case -you'll need to export all public symbols from your main executable -(e.g. -Wl,-E on Linux) and add the external dependencies -(e.g. -lm -ldl on Linux).
    • -
    • Since Windows symbols are bound to a specific DLL name, you need to -link to the lua51.dll created by the LuaJIT build (do not rename -the DLL). You may link LuaJIT statically on Windows only if you don't -intend to load Lua/C modules at runtime. -
    -
  • -
  • -If you're building a 64 bit application on OSX which links directly or -indirectly against LuaJIT which is not built for LJ_GC64 mode, -you need to link your main executable with these flags: -
    --pagezero_size 10000 -image_base 100000000
    -
    -
  • -
-

Additional hints for initializing LuaJIT using the C API functions:

-
    -
  • Here's a -» simple example -for embedding Lua or LuaJIT into your application.
  • -
  • Make sure you use luaL_newstate. Avoid using -lua_newstate, since this uses the (slower) default memory -allocator from your system (no support for this on x64).
  • -
  • Make sure you use luaL_openlibs and not the old Lua 5.0 style -of calling luaopen_base etc. directly.
  • -
  • To change or extend the list of standard libraries to load, copy -src/lib_init.c to your project and modify it accordingly. -Make sure the jit library is loaded or the JIT compiler -will not be activated.
  • -
  • The bit.* module for bitwise operations -is already built-in. There's no need to statically link -» Lua BitOp to your application.
  • -
- -

Hints for Distribution Maintainers

-

-The LuaJIT build system has extra provisions for the needs of most -POSIX-based distributions. If you're a package maintainer for -a distribution, please make use of these features and -avoid patching, subverting, autotoolizing or messing up the build system -in unspeakable ways. -

-

-There should be absolutely no need to patch luaconf.h or any -of the Makefiles. And please do not hand-pick files for your packages — -simply use whatever make install creates. There's a reason -for all of the files and directories it creates. -

-

-The build system uses GNU make and auto-detects most settings based on -the host you're building it on. This should work fine for native builds, -even when sandboxed. You may need to pass some of the following flags to -both the make and the make install command lines -for a regular distribution build: -

-
    -
  • PREFIX overrides the installation path and should usually -be set to /usr. Setting this also changes the module paths and -the paths needed to locate the shared library.
  • -
  • DESTDIR is an absolute path which allows you to install -to a shadow tree instead of the root tree of the build system.
  • -
  • MULTILIB sets the architecture-specific library path component -for multilib systems. The default is lib.
  • -
  • Have a look at the top-level Makefile and src/Makefile -for additional variables to tweak. The following variables may be -overridden, but it's not recommended, except for special needs -like cross-builds: -BUILDMODE, CC, HOST_CC, STATIC_CC, DYNAMIC_CC, CFLAGS, HOST_CFLAGS, -TARGET_CFLAGS, LDFLAGS, HOST_LDFLAGS, TARGET_LDFLAGS, TARGET_SHLDFLAGS, -TARGET_FLAGS, LIBS, HOST_LIBS, TARGET_LIBS, CROSS, HOST_SYS, TARGET_SYS -
  • -
-

-The build system has a special target for an amalgamated build, i.e. -make amalg. This compiles the LuaJIT core as one huge C file -and allows GCC to generate faster and shorter code. Alas, this requires -lots of memory during the build. This may be a problem for some users, -that's why it's not enabled by default. But it shouldn't be a problem for -most build farms. It's recommended that binary distributions use this -target for their LuaJIT builds. -

-

-The tl;dr version of the above: -

-
-make amalg PREFIX=/usr && \
-make install PREFIX=/usr DESTDIR=/tmp/buildroot
-
-

-Finally, if you encounter any difficulties, please -contact me first, instead of releasing a broken -package onto unsuspecting users. Because they'll usually gonna complain -to me (the upstream) and not you (the package maintainer), anyway. -

-
-
- - - diff --git a/lib/LuaJIT/doc/luajit.html b/lib/LuaJIT/doc/luajit.html deleted file mode 100644 index a85c201..0000000 --- a/lib/LuaJIT/doc/luajit.html +++ /dev/null @@ -1,235 +0,0 @@ - - - -LuaJIT - - - - - - - - - -
-Lua -
- - -
-

-LuaJIT is a Just-In-Time Compiler (JIT) for the -» Lua programming language. -Lua is a powerful, dynamic and light-weight programming language. -It may be embedded or used as a general-purpose, stand-alone language. -

-

-LuaJIT is Copyright © 2005-2018 Mike Pall, released under the -» MIT open source license. -

-

-

- -

Compatibility

- - -
WindowsLinuxBSDOSXPOSIX
- - -
EmbeddedAndroidiOS
- - -
PS3PS4PS VitaXbox 360Xbox One
- - -
GCCClang
LLVM
MSVC
- - -
x86
x64
ARM
ARM64
PPCMIPS32
MIPS64
- - -
Lua 5.1
API+ABI
+ JIT+ BitOp+ FFIDrop-in
DLL/.so
- -

Overview

- - - - - - - - - -
3x
-  100x
115 KB
VM
90 KB
JIT
63 KLOC
C
24 KLOC
ASM
11 KLOC
Lua
-

-LuaJIT has been successfully used as a scripting middleware in -games, appliances, network and graphics apps, numerical simulations, -trading platforms and many other specialty applications. It scales from -embedded devices, smartphones, desktops up to server farms. It combines -high flexibility with » high performance -and an unmatched low memory footprint. -

-

-LuaJIT has been in continuous development since 2005. It's widely -considered to be one of the fastest dynamic language -implementations. It has outperformed other dynamic languages on many -cross-language benchmarks since its first release — often by a -substantial margin. -

-

-For LuaJIT 2.0, the whole VM has been rewritten from the ground up -and relentlessly optimized for performance. It combines a high-speed -interpreter, written in assembler, with a state-of-the-art JIT -compiler. -

-

-An innovative trace compiler is integrated with advanced, -SSA-based optimizations and highly tuned code generation backends. -A substantial reduction of the overhead associated with dynamic languages -allows it to break into the performance range traditionally reserved for -offline, static language compilers. -

- -

More ...

-

-Please select a sub-topic in the navigation bar to learn more about LuaJIT. -

-
-
- - - diff --git a/lib/LuaJIT/doc/running.html b/lib/LuaJIT/doc/running.html deleted file mode 100644 index ae3cd71..0000000 --- a/lib/LuaJIT/doc/running.html +++ /dev/null @@ -1,308 +0,0 @@ - - - -Running LuaJIT - - - - - - - - -
-Lua -
- - -
-

-LuaJIT has only a single stand-alone executable, called luajit on -POSIX systems or luajit.exe on Windows. It can be used to run simple -Lua statements or whole Lua applications from the command line. It has an -interactive mode, too. -

- -

Command Line Options

-

-The luajit stand-alone executable is just a slightly modified -version of the regular lua stand-alone executable. -It supports the same basic options, too. luajit -h -prints a short list of the available options. Please have a look at the -» Lua manual -for details. -

-

-LuaJIT has some additional options: -

- -

-b[options] input output

-

-This option saves or lists bytecode. The following additional options -are accepted: -

-
    -
  • -l — Only list bytecode.
  • -
  • -s — Strip debug info (this is the default).
  • -
  • -g — Keep debug info.
  • -
  • -n name — Set module name (default: auto-detect from input name)
  • -
  • -t type — Set output file type (default: auto-detect from output name).
  • -
  • -a arch — Override architecture for object files (default: native).
  • -
  • -o os — Override OS for object files (default: native).
  • -
  • -e chunk — Use chunk string as input.
  • -
  • - (a single minus sign) — Use stdin as input and/or stdout as output.
  • -
-

-The output file type is auto-detected from the extension of the output -file name: -

-
    -
  • c — C source file, exported bytecode data.
  • -
  • h — C header file, static bytecode data.
  • -
  • obj or o — Object file, exported bytecode data -(OS- and architecture-specific).
  • -
  • raw or any other extension — Raw bytecode file (portable). -
-

-Notes: -

-
    -
  • See also string.dump() -for information on bytecode portability and compatibility.
  • -
  • A file in raw bytecode format is auto-detected and can be loaded like -any Lua source file. E.g. directly from the command line or with -loadfile(), dofile() etc.
  • -
  • To statically embed the bytecode of a module in your application, -generate an object file and just link it with your application.
  • -
  • On most ELF-based systems (e.g. Linux) you need to explicitly export the -global symbols when linking your application, e.g. with: -Wl,-E
  • -
  • require() tries to load embedded bytecode data from exported -symbols (in *.exe or lua51.dll on Windows) and from -shared libraries in package.cpath.
  • -
-

-Typical usage examples: -

-
-luajit -b test.lua test.out                 # Save bytecode to test.out
-luajit -bg test.lua test.out                # Keep debug info
-luajit -be "print('hello world')" test.out  # Save cmdline script
-
-luajit -bl test.lua                         # List to stdout
-luajit -bl test.lua test.txt                # List to test.txt
-luajit -ble "print('hello world')"          # List cmdline script
-
-luajit -b test.lua test.obj                 # Generate object file
-# Link test.obj with your application and load it with require("test")
-
- -

-j cmd[=arg[,arg...]]

-

-This option performs a LuaJIT control command or activates one of the -loadable extension modules. The command is first looked up in the -jit.* library. If no matching function is found, a module -named jit.<cmd> is loaded and the start() -function of the module is called with the specified arguments (if -any). The space between -j and cmd is optional. -

-

-Here are the available LuaJIT control commands: -

-
    -
  • -jon — Turns the JIT compiler on (default).
  • -
  • -joff — Turns the JIT compiler off (only use the interpreter).
  • -
  • -jflush — Flushes the whole cache of compiled code.
  • -
  • -jv — Shows verbose information about the progress of the JIT compiler.
  • -
  • -jdump — Dumps the code and structures used in various compiler stages.
  • -
  • -jp — Start the integrated profiler.
  • -
-

-The -jv and -jdump commands are extension modules -written in Lua. They are mainly used for debugging the JIT compiler -itself. For a description of their options and output format, please -read the comment block at the start of their source. -They can be found in the lib directory of the source -distribution or installed under the jit directory. By default -this is /usr/local/share/luajit-2.0.5/jit on POSIX -systems. -

- -

-O[level]
--O[+]flag   -O-flag
--Oparam=value

-

-This options allows fine-tuned control of the optimizations used by -the JIT compiler. This is mainly intended for debugging LuaJIT itself. -Please note that the JIT compiler is extremely fast (we are talking -about the microsecond to millisecond range). Disabling optimizations -doesn't have any visible impact on its overhead, but usually generates -code that runs slower. -

-

-The first form sets an optimization level — this enables a -specific mix of optimization flags. -O0 turns off all -optimizations and higher numbers enable more optimizations. Omitting -the level (i.e. just -O) sets the default optimization level, -which is -O3 in the current version. -

-

-The second form adds or removes individual optimization flags. -The third form sets a parameter for the VM or the JIT compiler -to a specific value. -

-

-You can either use this option multiple times (like -Ocse --O-dce -Ohotloop=10) or separate several settings with a comma -(like -O+cse,-dce,hotloop=10). The settings are applied from -left to right and later settings override earlier ones. You can freely -mix the three forms, but note that setting an optimization level -overrides all earlier flags. -

-

-Here are the available flags and at what optimization levels they -are enabled: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Flag-O1-O2-O3 
foldConstant Folding, Simplifications and Reassociation
cseCommon-Subexpression Elimination
dceDead-Code Elimination
narrow Narrowing of numbers to integers
loop Loop Optimizations (code hoisting)
fwd  Load Forwarding (L2L) and Store Forwarding (S2L)
dse  Dead-Store Elimination
abc  Array Bounds Check Elimination
sink  Allocation/Store Sinking
fuse  Fusion of operands into instructions
-

-Here are the parameters and their default settings: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ParameterDefault 
maxtrace1000Max. number of traces in the cache
maxrecord4000Max. number of recorded IR instructions
maxirconst500Max. number of IR constants of a trace
maxside100Max. number of side traces of a root trace
maxsnap500Max. number of snapshots for a trace
hotloop56Number of iterations to detect a hot loop or hot call
hotexit10Number of taken exits to start a side trace
tryside4Number of attempts to compile a side trace
instunroll4Max. unroll factor for instable loops
loopunroll15Max. unroll factor for loop ops in side traces
callunroll3Max. unroll factor for pseudo-recursive calls
recunroll2Min. unroll factor for true recursion
sizemcode32Size of each machine code area in KBytes (Windows: 64K)
maxmcode512Max. total size of all machine code areas in KBytes
-
-
- - - diff --git a/lib/LuaJIT/doc/status.html b/lib/LuaJIT/doc/status.html deleted file mode 100644 index e0d912e..0000000 --- a/lib/LuaJIT/doc/status.html +++ /dev/null @@ -1,122 +0,0 @@ - - - -Status - - - - - - - - -
-Lua -
- - -
-

-LuaJIT 2.0 is the current -stable branch. This branch is in -feature-freeze — new features will only be added to LuaJIT 2.1. -

- -

Current Status

-

-LuaJIT ought to run all Lua 5.1-compatible source code just fine. -It's considered a serious bug if the VM crashes or produces unexpected -results — please report this. -

-

-Known incompatibilities and issues in LuaJIT 2.0: -

-
    -
  • -There are some differences in implementation-defined behavior. -These either have a good reason, are arbitrary design choices -or are due to quirks in the VM. The latter cases may get fixed if a -demonstrable need is shown. -
  • -
  • -The Lua debug API is missing a couple of features (return -hooks for non-Lua functions) and shows slightly different behavior -in LuaJIT (no per-coroutine hooks, no tail call counting). -
  • -
  • -Currently some out-of-memory errors from on-trace code are not -handled correctly. The error may fall through an on-trace -pcall or it may be passed on to the function set with -lua_atpanic on x64. This issue will be fixed with the new -garbage collector. -
  • -
  • -LuaJIT on 64 bit systems provides a limited range of 47 bits for the -legacy lightuserdata data type. -This is only relevant on x64 systems which use the negative part of the -virtual address space in user mode, e.g. Solaris/x64, and on ARM64 systems -configured with a 48 bit or 52 bit VA. -Avoid using lightuserdata to hold pointers that may point outside -of that range, e.g. variables on the stack. In general, avoid this data -type for new code and replace it with (much more performant) FFI bindings. -FFI cdata pointers can address the full 64 bit range. -
  • -
-
-
- - - diff --git a/lib/LuaJIT/dynasm/dasm_arm.h b/lib/LuaJIT/dynasm/dasm_arm.h deleted file mode 100644 index 1d404cc..0000000 --- a/lib/LuaJIT/dynasm/dasm_arm.h +++ /dev/null @@ -1,458 +0,0 @@ -/* -** DynASM ARM encoding engine. -** Copyright (C) 2005-2017 Mike Pall. All rights reserved. -** Released under the MIT license. See dynasm.lua for full copyright notice. -*/ - -#include -#include -#include -#include - -#define DASM_ARCH "arm" - -#ifndef DASM_EXTERN -#define DASM_EXTERN(a,b,c,d) 0 -#endif - -/* Action definitions. */ -enum { - DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, - /* The following actions need a buffer position. */ - DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, - /* The following actions also have an argument. */ - DASM_REL_PC, DASM_LABEL_PC, - DASM_IMM, DASM_IMM12, DASM_IMM16, DASM_IMML8, DASM_IMML12, DASM_IMMV8, - DASM__MAX -}; - -/* Maximum number of section buffer positions for a single dasm_put() call. */ -#define DASM_MAXSECPOS 25 - -/* DynASM encoder status codes. Action list offset or number are or'ed in. */ -#define DASM_S_OK 0x00000000 -#define DASM_S_NOMEM 0x01000000 -#define DASM_S_PHASE 0x02000000 -#define DASM_S_MATCH_SEC 0x03000000 -#define DASM_S_RANGE_I 0x11000000 -#define DASM_S_RANGE_SEC 0x12000000 -#define DASM_S_RANGE_LG 0x13000000 -#define DASM_S_RANGE_PC 0x14000000 -#define DASM_S_RANGE_REL 0x15000000 -#define DASM_S_UNDEF_LG 0x21000000 -#define DASM_S_UNDEF_PC 0x22000000 - -/* Macros to convert positions (8 bit section + 24 bit index). */ -#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) -#define DASM_POS2BIAS(pos) ((pos)&0xff000000) -#define DASM_SEC2POS(sec) ((sec)<<24) -#define DASM_POS2SEC(pos) ((pos)>>24) -#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) - -/* Action list type. */ -typedef const unsigned int *dasm_ActList; - -/* Per-section structure. */ -typedef struct dasm_Section { - int *rbuf; /* Biased buffer pointer (negative section bias). */ - int *buf; /* True buffer pointer. */ - size_t bsize; /* Buffer size in bytes. */ - int pos; /* Biased buffer position. */ - int epos; /* End of biased buffer position - max single put. */ - int ofs; /* Byte offset into section. */ -} dasm_Section; - -/* Core structure holding the DynASM encoding state. */ -struct dasm_State { - size_t psize; /* Allocated size of this structure. */ - dasm_ActList actionlist; /* Current actionlist pointer. */ - int *lglabels; /* Local/global chain/pos ptrs. */ - size_t lgsize; - int *pclabels; /* PC label chains/pos ptrs. */ - size_t pcsize; - void **globals; /* Array of globals (bias -10). */ - dasm_Section *section; /* Pointer to active section. */ - size_t codesize; /* Total size of all code sections. */ - int maxsection; /* 0 <= sectionidx < maxsection. */ - int status; /* Status code. */ - dasm_Section sections[1]; /* All sections. Alloc-extended. */ -}; - -/* The size of the core structure depends on the max. number of sections. */ -#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) - - -/* Initialize DynASM state. */ -void dasm_init(Dst_DECL, int maxsection) -{ - dasm_State *D; - size_t psz = 0; - int i; - Dst_REF = NULL; - DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); - D = Dst_REF; - D->psize = psz; - D->lglabels = NULL; - D->lgsize = 0; - D->pclabels = NULL; - D->pcsize = 0; - D->globals = NULL; - D->maxsection = maxsection; - for (i = 0; i < maxsection; i++) { - D->sections[i].buf = NULL; /* Need this for pass3. */ - D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); - D->sections[i].bsize = 0; - D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ - } -} - -/* Free DynASM state. */ -void dasm_free(Dst_DECL) -{ - dasm_State *D = Dst_REF; - int i; - for (i = 0; i < D->maxsection; i++) - if (D->sections[i].buf) - DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); - if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); - if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); - DASM_M_FREE(Dst, D, D->psize); -} - -/* Setup global label array. Must be called before dasm_setup(). */ -void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) -{ - dasm_State *D = Dst_REF; - D->globals = gl - 10; /* Negative bias to compensate for locals. */ - DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); -} - -/* Grow PC label array. Can be called after dasm_setup(), too. */ -void dasm_growpc(Dst_DECL, unsigned int maxpc) -{ - dasm_State *D = Dst_REF; - size_t osz = D->pcsize; - DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); - memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); -} - -/* Setup encoder. */ -void dasm_setup(Dst_DECL, const void *actionlist) -{ - dasm_State *D = Dst_REF; - int i; - D->actionlist = (dasm_ActList)actionlist; - D->status = DASM_S_OK; - D->section = &D->sections[0]; - memset((void *)D->lglabels, 0, D->lgsize); - if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); - for (i = 0; i < D->maxsection; i++) { - D->sections[i].pos = DASM_SEC2POS(i); - D->sections[i].ofs = 0; - } -} - - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) { \ - D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) -#define CKPL(kind, st) \ - do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ - D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) -#else -#define CK(x, st) ((void)0) -#define CKPL(kind, st) ((void)0) -#endif - -static int dasm_imm12(unsigned int n) -{ - int i; - for (i = 0; i < 16; i++, n = (n << 2) | (n >> 30)) - if (n <= 255) return (int)(n + (i << 8)); - return -1; -} - -/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ -void dasm_put(Dst_DECL, int start, ...) -{ - va_list ap; - dasm_State *D = Dst_REF; - dasm_ActList p = D->actionlist + start; - dasm_Section *sec = D->section; - int pos = sec->pos, ofs = sec->ofs; - int *b; - - if (pos >= sec->epos) { - DASM_M_GROW(Dst, int, sec->buf, sec->bsize, - sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); - sec->rbuf = sec->buf - DASM_POS2BIAS(pos); - sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); - } - - b = sec->rbuf; - b[pos++] = start; - - va_start(ap, start); - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - if (action >= DASM__MAX) { - ofs += 4; - } else { - int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; - switch (action) { - case DASM_STOP: goto stop; - case DASM_SECTION: - n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); - D->section = &D->sections[n]; goto stop; - case DASM_ESC: p++; ofs += 4; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; - case DASM_REL_LG: - n = (ins & 2047) - 10; pl = D->lglabels + n; - /* Bkwd rel or global. */ - if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } - pl += 10; n = *pl; - if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ - goto linkrel; - case DASM_REL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putrel: - n = *pl; - if (n < 0) { /* Label exists. Get label pos and store it. */ - b[pos] = -n; - } else { - linkrel: - b[pos] = n; /* Else link to rel chain, anchored at label. */ - *pl = pos; - } - pos++; - break; - case DASM_LABEL_LG: - pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; - case DASM_LABEL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putlabel: - n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; - } - *pl = -pos; /* Label exists now. */ - b[pos++] = ofs; /* Store pass1 offset estimate. */ - break; - case DASM_IMM: - case DASM_IMM16: -#ifdef DASM_CHECKS - CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); - if ((ins & 0x8000)) - CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); - else - CK((n>>((ins>>5)&31)) == 0, RANGE_I); -#endif - b[pos++] = n; - break; - case DASM_IMMV8: - CK((n & 3) == 0, RANGE_I); - n >>= 2; - /* fallthrough */ - case DASM_IMML8: - case DASM_IMML12: - CK(n >= 0 ? ((n>>((ins>>5)&31)) == 0) : - (((-n)>>((ins>>5)&31)) == 0), RANGE_I); - b[pos++] = n; - break; - case DASM_IMM12: - CK(dasm_imm12((unsigned int)n) != -1, RANGE_I); - b[pos++] = n; - break; - } - } - } -stop: - va_end(ap); - sec->pos = pos; - sec->ofs = ofs; -} -#undef CK - -/* Pass 2: Link sections, shrink aligns, fix label offsets. */ -int dasm_link(Dst_DECL, size_t *szp) -{ - dasm_State *D = Dst_REF; - int secnum; - int ofs = 0; - -#ifdef DASM_CHECKS - *szp = 0; - if (D->status != DASM_S_OK) return D->status; - { - int pc; - for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) - if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; - } -#endif - - { /* Handle globals not defined in this translation unit. */ - int idx; - for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { - int n = D->lglabels[idx]; - /* Undefined label: Collapse rel chain and replace with marker (< 0). */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } - } - } - - /* Combine all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->rbuf; - int pos = DASM_SEC2POS(secnum); - int lastpos = sec->pos; - - while (pos != lastpos) { - dasm_ActList p = D->actionlist + b[pos++]; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: p++; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; - case DASM_REL_LG: case DASM_REL_PC: pos++; break; - case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; - case DASM_IMM: case DASM_IMM12: case DASM_IMM16: - case DASM_IMML8: case DASM_IMML12: case DASM_IMMV8: pos++; break; - } - } - stop: (void)0; - } - ofs += sec->ofs; /* Next section starts right after current section. */ - } - - D->codesize = ofs; /* Total size of all code sections */ - *szp = ofs; - return DASM_S_OK; -} - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) -#else -#define CK(x, st) ((void)0) -#endif - -/* Pass 3: Encode sections. */ -int dasm_encode(Dst_DECL, void *buffer) -{ - dasm_State *D = Dst_REF; - char *base = (char *)buffer; - unsigned int *cp = (unsigned int *)buffer; - int secnum; - - /* Encode all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->buf; - int *endb = sec->rbuf + sec->pos; - - while (b != endb) { - dasm_ActList p = D->actionlist + *b++; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: *cp++ = *p++; break; - case DASM_REL_EXT: - n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048)); - goto patchrel; - case DASM_ALIGN: - ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000; - break; - case DASM_REL_LG: - CK(n >= 0, UNDEF_LG); - /* fallthrough */ - case DASM_REL_PC: - CK(n >= 0, UNDEF_PC); - n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) - 4; - patchrel: - if ((ins & 0x800) == 0) { - CK((n & 3) == 0 && ((n+0x02000000) >> 26) == 0, RANGE_REL); - cp[-1] |= ((n >> 2) & 0x00ffffff); - } else if ((ins & 0x1000)) { - CK((n & 3) == 0 && -256 <= n && n <= 256, RANGE_REL); - goto patchimml8; - } else if ((ins & 0x2000) == 0) { - CK((n & 3) == 0 && -4096 <= n && n <= 4096, RANGE_REL); - goto patchimml; - } else { - CK((n & 3) == 0 && -1020 <= n && n <= 1020, RANGE_REL); - n >>= 2; - goto patchimml; - } - break; - case DASM_LABEL_LG: - ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); - break; - case DASM_LABEL_PC: break; - case DASM_IMM: - cp[-1] |= ((n>>((ins>>10)&31)) & ((1<<((ins>>5)&31))-1)) << (ins&31); - break; - case DASM_IMM12: - cp[-1] |= dasm_imm12((unsigned int)n); - break; - case DASM_IMM16: - cp[-1] |= ((n & 0xf000) << 4) | (n & 0x0fff); - break; - case DASM_IMML8: patchimml8: - cp[-1] |= n >= 0 ? (0x00800000 | (n & 0x0f) | ((n & 0xf0) << 4)) : - ((-n & 0x0f) | ((-n & 0xf0) << 4)); - break; - case DASM_IMML12: case DASM_IMMV8: patchimml: - cp[-1] |= n >= 0 ? (0x00800000 | n) : (-n); - break; - default: *cp++ = ins; break; - } - } - stop: (void)0; - } - } - - if (base + D->codesize != (char *)cp) /* Check for phase errors. */ - return DASM_S_PHASE; - return DASM_S_OK; -} -#undef CK - -/* Get PC label offset. */ -int dasm_getpclabel(Dst_DECL, unsigned int pc) -{ - dasm_State *D = Dst_REF; - if (pc*sizeof(int) < D->pcsize) { - int pos = D->pclabels[pc]; - if (pos < 0) return *DASM_POS2PTR(D, -pos); - if (pos > 0) return -1; /* Undefined. */ - } - return -2; /* Unused or out of range. */ -} - -#ifdef DASM_CHECKS -/* Optional sanity checker to call between isolated encoding steps. */ -int dasm_checkstep(Dst_DECL, int secmatch) -{ - dasm_State *D = Dst_REF; - if (D->status == DASM_S_OK) { - int i; - for (i = 1; i <= 9; i++) { - if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } - D->lglabels[i] = 0; - } - } - if (D->status == DASM_S_OK && secmatch >= 0 && - D->section != &D->sections[secmatch]) - D->status = DASM_S_MATCH_SEC|(D->section-D->sections); - return D->status; -} -#endif - diff --git a/lib/LuaJIT/dynasm/dasm_arm.lua b/lib/LuaJIT/dynasm/dasm_arm.lua deleted file mode 100644 index 32f595a..0000000 --- a/lib/LuaJIT/dynasm/dasm_arm.lua +++ /dev/null @@ -1,1125 +0,0 @@ ------------------------------------------------------------------------------- --- DynASM ARM module. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------- - --- Module information: -local _info = { - arch = "arm", - description = "DynASM ARM module", - version = "1.4.0", - vernum = 10400, - release = "2015-10-18", - author = "Mike Pall", - license = "MIT", -} - --- Exported glue functions for the arch-specific module. -local _M = { _info = _info } - --- Cache library functions. -local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs -local assert, setmetatable, rawget = assert, setmetatable, rawget -local _s = string -local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char -local match, gmatch, gsub = _s.match, _s.gmatch, _s.gsub -local concat, sort, insert = table.concat, table.sort, table.insert -local bit = bit or require("bit") -local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift -local ror, tohex = bit.ror, bit.tohex - --- Inherited tables and callbacks. -local g_opt, g_arch -local wline, werror, wfatal, wwarn - --- Action name list. --- CHECK: Keep this in sync with the C code! -local action_names = { - "STOP", "SECTION", "ESC", "REL_EXT", - "ALIGN", "REL_LG", "LABEL_LG", - "REL_PC", "LABEL_PC", "IMM", "IMM12", "IMM16", "IMML8", "IMML12", "IMMV8", -} - --- Maximum number of section buffer positions for dasm_put(). --- CHECK: Keep this in sync with the C code! -local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. - --- Action name -> action number. -local map_action = {} -for n,name in ipairs(action_names) do - map_action[name] = n-1 -end - --- Action list buffer. -local actlist = {} - --- Argument list for next dasm_put(). Start with offset 0 into action list. -local actargs = { 0 } - --- Current number of section buffer positions for dasm_put(). -local secpos = 1 - ------------------------------------------------------------------------------- - --- Dump action names and numbers. -local function dumpactions(out) - out:write("DynASM encoding engine action codes:\n") - for n,name in ipairs(action_names) do - local num = map_action[name] - out:write(format(" %-10s %02X %d\n", name, num, num)) - end - out:write("\n") -end - --- Write action list buffer as a huge static C array. -local function writeactions(out, name) - local nn = #actlist - if nn == 0 then nn = 1; actlist[0] = map_action.STOP end - out:write("static const unsigned int ", name, "[", nn, "] = {\n") - for i = 1,nn-1 do - assert(out:write("0x", tohex(actlist[i]), ",\n")) - end - assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) -end - ------------------------------------------------------------------------------- - --- Add word to action list. -local function wputxw(n) - assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") - actlist[#actlist+1] = n -end - --- Add action to list with optional arg. Advance buffer pos, too. -local function waction(action, val, a, num) - local w = assert(map_action[action], "bad action name `"..action.."'") - wputxw(w * 0x10000 + (val or 0)) - if a then actargs[#actargs+1] = a end - if a or num then secpos = secpos + (num or 1) end -end - --- Flush action list (intervening C code or buffer pos overflow). -local function wflush(term) - if #actlist == actargs[1] then return end -- Nothing to flush. - if not term then waction("STOP") end -- Terminate action list. - wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) - actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). - secpos = 1 -- The actionlist offset occupies a buffer position, too. -end - --- Put escaped word. -local function wputw(n) - if n <= 0x000fffff then waction("ESC") end - wputxw(n) -end - --- Reserve position for word. -local function wpos() - local pos = #actlist+1 - actlist[pos] = "" - return pos -end - --- Store word to reserved position. -local function wputpos(pos, n) - assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") - if n <= 0x000fffff then - insert(actlist, pos+1, n) - n = map_action.ESC * 0x10000 - end - actlist[pos] = n -end - ------------------------------------------------------------------------------- - --- Global label name -> global label number. With auto assignment on 1st use. -local next_global = 20 -local map_global = setmetatable({}, { __index = function(t, name) - if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end - local n = next_global - if n > 2047 then werror("too many global labels") end - next_global = n + 1 - t[name] = n - return n -end}) - --- Dump global labels. -local function dumpglobals(out, lvl) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("Global labels:\n") - for i=20,next_global-1 do - out:write(format(" %s\n", t[i])) - end - out:write("\n") -end - --- Write global label enum. -local function writeglobals(out, prefix) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("enum {\n") - for i=20,next_global-1 do - out:write(" ", prefix, t[i], ",\n") - end - out:write(" ", prefix, "_MAX\n};\n") -end - --- Write global label names. -local function writeglobalnames(out, name) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("static const char *const ", name, "[] = {\n") - for i=20,next_global-1 do - out:write(" \"", t[i], "\",\n") - end - out:write(" (const char *)0\n};\n") -end - ------------------------------------------------------------------------------- - --- Extern label name -> extern label number. With auto assignment on 1st use. -local next_extern = 0 -local map_extern_ = {} -local map_extern = setmetatable({}, { __index = function(t, name) - -- No restrictions on the name for now. - local n = next_extern - if n > 2047 then werror("too many extern labels") end - next_extern = n + 1 - t[name] = n - map_extern_[n] = name - return n -end}) - --- Dump extern labels. -local function dumpexterns(out, lvl) - out:write("Extern labels:\n") - for i=0,next_extern-1 do - out:write(format(" %s\n", map_extern_[i])) - end - out:write("\n") -end - --- Write extern label names. -local function writeexternnames(out, name) - out:write("static const char *const ", name, "[] = {\n") - for i=0,next_extern-1 do - out:write(" \"", map_extern_[i], "\",\n") - end - out:write(" (const char *)0\n};\n") -end - ------------------------------------------------------------------------------- - --- Arch-specific maps. - --- Ext. register name -> int. name. -local map_archdef = { sp = "r13", lr = "r14", pc = "r15", } - --- Int. register name -> ext. name. -local map_reg_rev = { r13 = "sp", r14 = "lr", r15 = "pc", } - -local map_type = {} -- Type name -> { ctype, reg } -local ctypenum = 0 -- Type number (for Dt... macros). - --- Reverse defines for registers. -function _M.revdef(s) - return map_reg_rev[s] or s -end - -local map_shift = { lsl = 0, lsr = 1, asr = 2, ror = 3, } - -local map_cond = { - eq = 0, ne = 1, cs = 2, cc = 3, mi = 4, pl = 5, vs = 6, vc = 7, - hi = 8, ls = 9, ge = 10, lt = 11, gt = 12, le = 13, al = 14, - hs = 2, lo = 3, -} - ------------------------------------------------------------------------------- - --- Template strings for ARM instructions. -local map_op = { - -- Basic data processing instructions. - and_3 = "e0000000DNPs", - eor_3 = "e0200000DNPs", - sub_3 = "e0400000DNPs", - rsb_3 = "e0600000DNPs", - add_3 = "e0800000DNPs", - adc_3 = "e0a00000DNPs", - sbc_3 = "e0c00000DNPs", - rsc_3 = "e0e00000DNPs", - tst_2 = "e1100000NP", - teq_2 = "e1300000NP", - cmp_2 = "e1500000NP", - cmn_2 = "e1700000NP", - orr_3 = "e1800000DNPs", - mov_2 = "e1a00000DPs", - bic_3 = "e1c00000DNPs", - mvn_2 = "e1e00000DPs", - - and_4 = "e0000000DNMps", - eor_4 = "e0200000DNMps", - sub_4 = "e0400000DNMps", - rsb_4 = "e0600000DNMps", - add_4 = "e0800000DNMps", - adc_4 = "e0a00000DNMps", - sbc_4 = "e0c00000DNMps", - rsc_4 = "e0e00000DNMps", - tst_3 = "e1100000NMp", - teq_3 = "e1300000NMp", - cmp_3 = "e1500000NMp", - cmn_3 = "e1700000NMp", - orr_4 = "e1800000DNMps", - mov_3 = "e1a00000DMps", - bic_4 = "e1c00000DNMps", - mvn_3 = "e1e00000DMps", - - lsl_3 = "e1a00000DMws", - lsr_3 = "e1a00020DMws", - asr_3 = "e1a00040DMws", - ror_3 = "e1a00060DMws", - rrx_2 = "e1a00060DMs", - - -- Multiply and multiply-accumulate. - mul_3 = "e0000090NMSs", - mla_4 = "e0200090NMSDs", - umaal_4 = "e0400090DNMSs", -- v6 - mls_4 = "e0600090DNMSs", -- v6T2 - umull_4 = "e0800090DNMSs", - umlal_4 = "e0a00090DNMSs", - smull_4 = "e0c00090DNMSs", - smlal_4 = "e0e00090DNMSs", - - -- Halfword multiply and multiply-accumulate. - smlabb_4 = "e1000080NMSD", -- v5TE - smlatb_4 = "e10000a0NMSD", -- v5TE - smlabt_4 = "e10000c0NMSD", -- v5TE - smlatt_4 = "e10000e0NMSD", -- v5TE - smlawb_4 = "e1200080NMSD", -- v5TE - smulwb_3 = "e12000a0NMS", -- v5TE - smlawt_4 = "e12000c0NMSD", -- v5TE - smulwt_3 = "e12000e0NMS", -- v5TE - smlalbb_4 = "e1400080NMSD", -- v5TE - smlaltb_4 = "e14000a0NMSD", -- v5TE - smlalbt_4 = "e14000c0NMSD", -- v5TE - smlaltt_4 = "e14000e0NMSD", -- v5TE - smulbb_3 = "e1600080NMS", -- v5TE - smultb_3 = "e16000a0NMS", -- v5TE - smulbt_3 = "e16000c0NMS", -- v5TE - smultt_3 = "e16000e0NMS", -- v5TE - - -- Miscellaneous data processing instructions. - clz_2 = "e16f0f10DM", -- v5T - rev_2 = "e6bf0f30DM", -- v6 - rev16_2 = "e6bf0fb0DM", -- v6 - revsh_2 = "e6ff0fb0DM", -- v6 - sel_3 = "e6800fb0DNM", -- v6 - usad8_3 = "e780f010NMS", -- v6 - usada8_4 = "e7800010NMSD", -- v6 - rbit_2 = "e6ff0f30DM", -- v6T2 - movw_2 = "e3000000DW", -- v6T2 - movt_2 = "e3400000DW", -- v6T2 - -- Note: the X encodes width-1, not width. - sbfx_4 = "e7a00050DMvX", -- v6T2 - ubfx_4 = "e7e00050DMvX", -- v6T2 - -- Note: the X encodes the msb field, not the width. - bfc_3 = "e7c0001fDvX", -- v6T2 - bfi_4 = "e7c00010DMvX", -- v6T2 - - -- Packing and unpacking instructions. - pkhbt_3 = "e6800010DNM", pkhbt_4 = "e6800010DNMv", -- v6 - pkhtb_3 = "e6800050DNM", pkhtb_4 = "e6800050DNMv", -- v6 - sxtab_3 = "e6a00070DNM", sxtab_4 = "e6a00070DNMv", -- v6 - sxtab16_3 = "e6800070DNM", sxtab16_4 = "e6800070DNMv", -- v6 - sxtah_3 = "e6b00070DNM", sxtah_4 = "e6b00070DNMv", -- v6 - sxtb_2 = "e6af0070DM", sxtb_3 = "e6af0070DMv", -- v6 - sxtb16_2 = "e68f0070DM", sxtb16_3 = "e68f0070DMv", -- v6 - sxth_2 = "e6bf0070DM", sxth_3 = "e6bf0070DMv", -- v6 - uxtab_3 = "e6e00070DNM", uxtab_4 = "e6e00070DNMv", -- v6 - uxtab16_3 = "e6c00070DNM", uxtab16_4 = "e6c00070DNMv", -- v6 - uxtah_3 = "e6f00070DNM", uxtah_4 = "e6f00070DNMv", -- v6 - uxtb_2 = "e6ef0070DM", uxtb_3 = "e6ef0070DMv", -- v6 - uxtb16_2 = "e6cf0070DM", uxtb16_3 = "e6cf0070DMv", -- v6 - uxth_2 = "e6ff0070DM", uxth_3 = "e6ff0070DMv", -- v6 - - -- Saturating instructions. - qadd_3 = "e1000050DMN", -- v5TE - qsub_3 = "e1200050DMN", -- v5TE - qdadd_3 = "e1400050DMN", -- v5TE - qdsub_3 = "e1600050DMN", -- v5TE - -- Note: the X for ssat* encodes sat_imm-1, not sat_imm. - ssat_3 = "e6a00010DXM", ssat_4 = "e6a00010DXMp", -- v6 - usat_3 = "e6e00010DXM", usat_4 = "e6e00010DXMp", -- v6 - ssat16_3 = "e6a00f30DXM", -- v6 - usat16_3 = "e6e00f30DXM", -- v6 - - -- Parallel addition and subtraction. - sadd16_3 = "e6100f10DNM", -- v6 - sasx_3 = "e6100f30DNM", -- v6 - ssax_3 = "e6100f50DNM", -- v6 - ssub16_3 = "e6100f70DNM", -- v6 - sadd8_3 = "e6100f90DNM", -- v6 - ssub8_3 = "e6100ff0DNM", -- v6 - qadd16_3 = "e6200f10DNM", -- v6 - qasx_3 = "e6200f30DNM", -- v6 - qsax_3 = "e6200f50DNM", -- v6 - qsub16_3 = "e6200f70DNM", -- v6 - qadd8_3 = "e6200f90DNM", -- v6 - qsub8_3 = "e6200ff0DNM", -- v6 - shadd16_3 = "e6300f10DNM", -- v6 - shasx_3 = "e6300f30DNM", -- v6 - shsax_3 = "e6300f50DNM", -- v6 - shsub16_3 = "e6300f70DNM", -- v6 - shadd8_3 = "e6300f90DNM", -- v6 - shsub8_3 = "e6300ff0DNM", -- v6 - uadd16_3 = "e6500f10DNM", -- v6 - uasx_3 = "e6500f30DNM", -- v6 - usax_3 = "e6500f50DNM", -- v6 - usub16_3 = "e6500f70DNM", -- v6 - uadd8_3 = "e6500f90DNM", -- v6 - usub8_3 = "e6500ff0DNM", -- v6 - uqadd16_3 = "e6600f10DNM", -- v6 - uqasx_3 = "e6600f30DNM", -- v6 - uqsax_3 = "e6600f50DNM", -- v6 - uqsub16_3 = "e6600f70DNM", -- v6 - uqadd8_3 = "e6600f90DNM", -- v6 - uqsub8_3 = "e6600ff0DNM", -- v6 - uhadd16_3 = "e6700f10DNM", -- v6 - uhasx_3 = "e6700f30DNM", -- v6 - uhsax_3 = "e6700f50DNM", -- v6 - uhsub16_3 = "e6700f70DNM", -- v6 - uhadd8_3 = "e6700f90DNM", -- v6 - uhsub8_3 = "e6700ff0DNM", -- v6 - - -- Load/store instructions. - str_2 = "e4000000DL", str_3 = "e4000000DL", str_4 = "e4000000DL", - strb_2 = "e4400000DL", strb_3 = "e4400000DL", strb_4 = "e4400000DL", - ldr_2 = "e4100000DL", ldr_3 = "e4100000DL", ldr_4 = "e4100000DL", - ldrb_2 = "e4500000DL", ldrb_3 = "e4500000DL", ldrb_4 = "e4500000DL", - strh_2 = "e00000b0DL", strh_3 = "e00000b0DL", - ldrh_2 = "e01000b0DL", ldrh_3 = "e01000b0DL", - ldrd_2 = "e00000d0DL", ldrd_3 = "e00000d0DL", -- v5TE - ldrsb_2 = "e01000d0DL", ldrsb_3 = "e01000d0DL", - strd_2 = "e00000f0DL", strd_3 = "e00000f0DL", -- v5TE - ldrsh_2 = "e01000f0DL", ldrsh_3 = "e01000f0DL", - - ldm_2 = "e8900000oR", ldmia_2 = "e8900000oR", ldmfd_2 = "e8900000oR", - ldmda_2 = "e8100000oR", ldmfa_2 = "e8100000oR", - ldmdb_2 = "e9100000oR", ldmea_2 = "e9100000oR", - ldmib_2 = "e9900000oR", ldmed_2 = "e9900000oR", - stm_2 = "e8800000oR", stmia_2 = "e8800000oR", stmfd_2 = "e8800000oR", - stmda_2 = "e8000000oR", stmfa_2 = "e8000000oR", - stmdb_2 = "e9000000oR", stmea_2 = "e9000000oR", - stmib_2 = "e9800000oR", stmed_2 = "e9800000oR", - pop_1 = "e8bd0000R", push_1 = "e92d0000R", - - -- Branch instructions. - b_1 = "ea000000B", - bl_1 = "eb000000B", - blx_1 = "e12fff30C", - bx_1 = "e12fff10M", - - -- Miscellaneous instructions. - nop_0 = "e1a00000", - mrs_1 = "e10f0000D", - bkpt_1 = "e1200070K", -- v5T - svc_1 = "ef000000T", swi_1 = "ef000000T", - ud_0 = "e7f001f0", - - -- VFP instructions. - ["vadd.f32_3"] = "ee300a00dnm", - ["vadd.f64_3"] = "ee300b00Gdnm", - ["vsub.f32_3"] = "ee300a40dnm", - ["vsub.f64_3"] = "ee300b40Gdnm", - ["vmul.f32_3"] = "ee200a00dnm", - ["vmul.f64_3"] = "ee200b00Gdnm", - ["vnmul.f32_3"] = "ee200a40dnm", - ["vnmul.f64_3"] = "ee200b40Gdnm", - ["vmla.f32_3"] = "ee000a00dnm", - ["vmla.f64_3"] = "ee000b00Gdnm", - ["vmls.f32_3"] = "ee000a40dnm", - ["vmls.f64_3"] = "ee000b40Gdnm", - ["vnmla.f32_3"] = "ee100a40dnm", - ["vnmla.f64_3"] = "ee100b40Gdnm", - ["vnmls.f32_3"] = "ee100a00dnm", - ["vnmls.f64_3"] = "ee100b00Gdnm", - ["vdiv.f32_3"] = "ee800a00dnm", - ["vdiv.f64_3"] = "ee800b00Gdnm", - - ["vabs.f32_2"] = "eeb00ac0dm", - ["vabs.f64_2"] = "eeb00bc0Gdm", - ["vneg.f32_2"] = "eeb10a40dm", - ["vneg.f64_2"] = "eeb10b40Gdm", - ["vsqrt.f32_2"] = "eeb10ac0dm", - ["vsqrt.f64_2"] = "eeb10bc0Gdm", - ["vcmp.f32_2"] = "eeb40a40dm", - ["vcmp.f64_2"] = "eeb40b40Gdm", - ["vcmpe.f32_2"] = "eeb40ac0dm", - ["vcmpe.f64_2"] = "eeb40bc0Gdm", - ["vcmpz.f32_1"] = "eeb50a40d", - ["vcmpz.f64_1"] = "eeb50b40Gd", - ["vcmpze.f32_1"] = "eeb50ac0d", - ["vcmpze.f64_1"] = "eeb50bc0Gd", - - vldr_2 = "ed100a00dl|ed100b00Gdl", - vstr_2 = "ed000a00dl|ed000b00Gdl", - vldm_2 = "ec900a00or", - vldmia_2 = "ec900a00or", - vldmdb_2 = "ed100a00or", - vpop_1 = "ecbd0a00r", - vstm_2 = "ec800a00or", - vstmia_2 = "ec800a00or", - vstmdb_2 = "ed000a00or", - vpush_1 = "ed2d0a00r", - - ["vmov.f32_2"] = "eeb00a40dm|eeb00a00dY", -- #imm is VFPv3 only - ["vmov.f64_2"] = "eeb00b40Gdm|eeb00b00GdY", -- #imm is VFPv3 only - vmov_2 = "ee100a10Dn|ee000a10nD", - vmov_3 = "ec500a10DNm|ec400a10mDN|ec500b10GDNm|ec400b10GmDN", - - vmrs_0 = "eef1fa10", - vmrs_1 = "eef10a10D", - vmsr_1 = "eee10a10D", - - ["vcvt.s32.f32_2"] = "eebd0ac0dm", - ["vcvt.s32.f64_2"] = "eebd0bc0dGm", - ["vcvt.u32.f32_2"] = "eebc0ac0dm", - ["vcvt.u32.f64_2"] = "eebc0bc0dGm", - ["vcvtr.s32.f32_2"] = "eebd0a40dm", - ["vcvtr.s32.f64_2"] = "eebd0b40dGm", - ["vcvtr.u32.f32_2"] = "eebc0a40dm", - ["vcvtr.u32.f64_2"] = "eebc0b40dGm", - ["vcvt.f32.s32_2"] = "eeb80ac0dm", - ["vcvt.f64.s32_2"] = "eeb80bc0GdFm", - ["vcvt.f32.u32_2"] = "eeb80a40dm", - ["vcvt.f64.u32_2"] = "eeb80b40GdFm", - ["vcvt.f32.f64_2"] = "eeb70bc0dGm", - ["vcvt.f64.f32_2"] = "eeb70ac0GdFm", - - -- VFPv4 only: - ["vfma.f32_3"] = "eea00a00dnm", - ["vfma.f64_3"] = "eea00b00Gdnm", - ["vfms.f32_3"] = "eea00a40dnm", - ["vfms.f64_3"] = "eea00b40Gdnm", - ["vfnma.f32_3"] = "ee900a40dnm", - ["vfnma.f64_3"] = "ee900b40Gdnm", - ["vfnms.f32_3"] = "ee900a00dnm", - ["vfnms.f64_3"] = "ee900b00Gdnm", - - -- NYI: Advanced SIMD instructions. - - -- NYI: I have no need for these instructions right now: - -- swp, swpb, strex, ldrex, strexd, ldrexd, strexb, ldrexb, strexh, ldrexh - -- msr, nopv6, yield, wfe, wfi, sev, dbg, bxj, smc, srs, rfe - -- cps, setend, pli, pld, pldw, clrex, dsb, dmb, isb - -- stc, ldc, mcr, mcr2, mrc, mrc2, mcrr, mcrr2, mrrc, mrrc2, cdp, cdp2 -} - --- Add mnemonics for "s" variants. -do - local t = {} - for k,v in pairs(map_op) do - if sub(v, -1) == "s" then - local v2 = sub(v, 1, 2)..char(byte(v, 3)+1)..sub(v, 4, -2) - t[sub(k, 1, -3).."s"..sub(k, -2)] = v2 - end - end - for k,v in pairs(t) do - map_op[k] = v - end -end - ------------------------------------------------------------------------------- - -local function parse_gpr(expr) - local tname, ovreg = match(expr, "^([%w_]+):(r1?[0-9])$") - local tp = map_type[tname or expr] - if tp then - local reg = ovreg or tp.reg - if not reg then - werror("type `"..(tname or expr).."' needs a register override") - end - expr = reg - end - local r = match(expr, "^r(1?[0-9])$") - if r then - r = tonumber(r) - if r <= 15 then return r, tp end - end - werror("bad register name `"..expr.."'") -end - -local function parse_gpr_pm(expr) - local pm, expr2 = match(expr, "^([+-]?)(.*)$") - return parse_gpr(expr2), (pm == "-") -end - -local function parse_vr(expr, tp) - local t, r = match(expr, "^([sd])([0-9]+)$") - if t == tp then - r = tonumber(r) - if r <= 31 then - if t == "s" then return shr(r, 1), band(r, 1) end - return band(r, 15), shr(r, 4) - end - end - werror("bad register name `"..expr.."'") -end - -local function parse_reglist(reglist) - reglist = match(reglist, "^{%s*([^}]*)}$") - if not reglist then werror("register list expected") end - local rr = 0 - for p in gmatch(reglist..",", "%s*([^,]*),") do - local rbit = shl(1, parse_gpr(gsub(p, "%s+$", ""))) - if band(rr, rbit) ~= 0 then - werror("duplicate register `"..p.."'") - end - rr = rr + rbit - end - return rr -end - -local function parse_vrlist(reglist) - local ta, ra, tb, rb = match(reglist, - "^{%s*([sd])([0-9]+)%s*%-%s*([sd])([0-9]+)%s*}$") - ra, rb = tonumber(ra), tonumber(rb) - if ta and ta == tb and ra and rb and ra <= 31 and rb <= 31 and ra <= rb then - local nr = rb+1 - ra - if ta == "s" then - return shl(shr(ra,1),12)+shl(band(ra,1),22) + nr - else - return shl(band(ra,15),12)+shl(shr(ra,4),22) + nr*2 + 0x100 - end - end - werror("register list expected") -end - -local function parse_imm(imm, bits, shift, scale, signed) - imm = match(imm, "^#(.*)$") - if not imm then werror("expected immediate operand") end - local n = tonumber(imm) - if n then - local m = sar(n, scale) - if shl(m, scale) == n then - if signed then - local s = sar(m, bits-1) - if s == 0 then return shl(m, shift) - elseif s == -1 then return shl(m + shl(1, bits), shift) end - else - if sar(m, bits) == 0 then return shl(m, shift) end - end - end - werror("out of range immediate `"..imm.."'") - else - waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) - return 0 - end -end - -local function parse_imm12(imm) - local n = tonumber(imm) - if n then - local m = band(n) - for i=0,-15,-1 do - if shr(m, 8) == 0 then return m + shl(band(i, 15), 8) end - m = ror(m, 2) - end - werror("out of range immediate `"..imm.."'") - else - waction("IMM12", 0, imm) - return 0 - end -end - -local function parse_imm16(imm) - imm = match(imm, "^#(.*)$") - if not imm then werror("expected immediate operand") end - local n = tonumber(imm) - if n then - if shr(n, 16) == 0 then return band(n, 0x0fff) + shl(band(n, 0xf000), 4) end - werror("out of range immediate `"..imm.."'") - else - waction("IMM16", 32*16, imm) - return 0 - end -end - -local function parse_imm_load(imm, ext) - local n = tonumber(imm) - if n then - if ext then - if n >= -255 and n <= 255 then - local up = 0x00800000 - if n < 0 then n = -n; up = 0 end - return shl(band(n, 0xf0), 4) + band(n, 0x0f) + up - end - else - if n >= -4095 and n <= 4095 then - if n >= 0 then return n+0x00800000 end - return -n - end - end - werror("out of range immediate `"..imm.."'") - else - waction(ext and "IMML8" or "IMML12", 32768 + shl(ext and 8 or 12, 5), imm) - return 0 - end -end - -local function parse_shift(shift, gprok) - if shift == "rrx" then - return 3 * 32 - else - local s, s2 = match(shift, "^(%S+)%s*(.*)$") - s = map_shift[s] - if not s then werror("expected shift operand") end - if sub(s2, 1, 1) == "#" then - return parse_imm(s2, 5, 7, 0, false) + shl(s, 5) - else - if not gprok then werror("expected immediate shift operand") end - return shl(parse_gpr(s2), 8) + shl(s, 5) + 16 - end - end -end - -local function parse_label(label, def) - local prefix = sub(label, 1, 2) - -- =>label (pc label reference) - if prefix == "=>" then - return "PC", 0, sub(label, 3) - end - -- ->name (global label reference) - if prefix == "->" then - return "LG", map_global[sub(label, 3)] - end - if def then - -- [1-9] (local label definition) - if match(label, "^[1-9]$") then - return "LG", 10+tonumber(label) - end - else - -- [<>][1-9] (local label reference) - local dir, lnum = match(label, "^([<>])([1-9])$") - if dir then -- Fwd: 1-9, Bkwd: 11-19. - return "LG", lnum + (dir == ">" and 0 or 10) - end - -- extern label (extern label reference) - local extname = match(label, "^extern%s+(%S+)$") - if extname then - return "EXT", map_extern[extname] - end - end - werror("bad label `"..label.."'") -end - -local function parse_load(params, nparams, n, op) - local oplo = band(op, 255) - local ext, ldrd = (oplo ~= 0), (oplo == 208) - local d - if (ldrd or oplo == 240) then - d = band(shr(op, 12), 15) - if band(d, 1) ~= 0 then werror("odd destination register") end - end - local pn = params[n] - local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$") - local p2 = params[n+1] - if not p1 then - if not p2 then - if match(pn, "^[<>=%-]") or match(pn, "^extern%s+") then - local mode, n, s = parse_label(pn, false) - waction("REL_"..mode, n + (ext and 0x1800 or 0x0800), s, 1) - return op + 15 * 65536 + 0x01000000 + (ext and 0x00400000 or 0) - end - local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$") - if reg and tailr ~= "" then - local d, tp = parse_gpr(reg) - if tp then - waction(ext and "IMML8" or "IMML12", 32768 + 32*(ext and 8 or 12), - format(tp.ctypefmt, tailr)) - return op + shl(d, 16) + 0x01000000 + (ext and 0x00400000 or 0) - end - end - end - werror("expected address operand") - end - if wb == "!" then op = op + 0x00200000 end - if p2 then - if wb == "!" then werror("bad use of '!'") end - local p3 = params[n+2] - op = op + shl(parse_gpr(p1), 16) - local imm = match(p2, "^#(.*)$") - if imm then - local m = parse_imm_load(imm, ext) - if p3 then werror("too many parameters") end - op = op + m + (ext and 0x00400000 or 0) - else - local m, neg = parse_gpr_pm(p2) - if ldrd and (m == d or m-1 == d) then werror("register conflict") end - op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000) - if p3 then op = op + parse_shift(p3) end - end - else - local p1a, p2 = match(p1, "^([^,%s]*)%s*(.*)$") - op = op + shl(parse_gpr(p1a), 16) + 0x01000000 - if p2 ~= "" then - local imm = match(p2, "^,%s*#(.*)$") - if imm then - local m = parse_imm_load(imm, ext) - op = op + m + (ext and 0x00400000 or 0) - else - local p2a, p3 = match(p2, "^,%s*([^,%s]*)%s*,?%s*(.*)$") - local m, neg = parse_gpr_pm(p2a) - if ldrd and (m == d or m-1 == d) then werror("register conflict") end - op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000) - if p3 ~= "" then - if ext then werror("too many parameters") end - op = op + parse_shift(p3) - end - end - else - if wb == "!" then werror("bad use of '!'") end - op = op + (ext and 0x00c00000 or 0x00800000) - end - end - return op -end - -local function parse_vload(q) - local reg, imm = match(q, "^%[%s*([^,%s]*)%s*(.*)%]$") - if reg then - local d = shl(parse_gpr(reg), 16) - if imm == "" then return d end - imm = match(imm, "^,%s*#(.*)$") - if imm then - local n = tonumber(imm) - if n then - if n >= -1020 and n <= 1020 and n%4 == 0 then - return d + (n >= 0 and n/4+0x00800000 or -n/4) - end - werror("out of range immediate `"..imm.."'") - else - waction("IMMV8", 32768 + 32*8, imm) - return d - end - end - else - if match(q, "^[<>=%-]") or match(q, "^extern%s+") then - local mode, n, s = parse_label(q, false) - waction("REL_"..mode, n + 0x2800, s, 1) - return 15 * 65536 - end - local reg, tailr = match(q, "^([%w_:]+)%s*(.*)$") - if reg and tailr ~= "" then - local d, tp = parse_gpr(reg) - if tp then - waction("IMMV8", 32768 + 32*8, format(tp.ctypefmt, tailr)) - return shl(d, 16) - end - end - end - werror("expected address operand") -end - ------------------------------------------------------------------------------- - --- Handle opcodes defined with template strings. -local function parse_template(params, template, nparams, pos) - local op = tonumber(sub(template, 1, 8), 16) - local n = 1 - local vr = "s" - - -- Process each character. - for p in gmatch(sub(template, 9), ".") do - local q = params[n] - if p == "D" then - op = op + shl(parse_gpr(q), 12); n = n + 1 - elseif p == "N" then - op = op + shl(parse_gpr(q), 16); n = n + 1 - elseif p == "S" then - op = op + shl(parse_gpr(q), 8); n = n + 1 - elseif p == "M" then - op = op + parse_gpr(q); n = n + 1 - elseif p == "d" then - local r,h = parse_vr(q, vr); op = op+shl(r,12)+shl(h,22); n = n + 1 - elseif p == "n" then - local r,h = parse_vr(q, vr); op = op+shl(r,16)+shl(h,7); n = n + 1 - elseif p == "m" then - local r,h = parse_vr(q, vr); op = op+r+shl(h,5); n = n + 1 - elseif p == "P" then - local imm = match(q, "^#(.*)$") - if imm then - op = op + parse_imm12(imm) + 0x02000000 - else - op = op + parse_gpr(q) - end - n = n + 1 - elseif p == "p" then - op = op + parse_shift(q, true); n = n + 1 - elseif p == "L" then - op = parse_load(params, nparams, n, op) - elseif p == "l" then - op = op + parse_vload(q) - elseif p == "B" then - local mode, n, s = parse_label(q, false) - waction("REL_"..mode, n, s, 1) - elseif p == "C" then -- blx gpr vs. blx label. - if match(q, "^([%w_]+):(r1?[0-9])$") or match(q, "^r(1?[0-9])$") then - op = op + parse_gpr(q) - else - if op < 0xe0000000 then werror("unconditional instruction") end - local mode, n, s = parse_label(q, false) - waction("REL_"..mode, n, s, 1) - op = 0xfa000000 - end - elseif p == "F" then - vr = "s" - elseif p == "G" then - vr = "d" - elseif p == "o" then - local r, wb = match(q, "^([^!]*)(!?)$") - op = op + shl(parse_gpr(r), 16) + (wb == "!" and 0x00200000 or 0) - n = n + 1 - elseif p == "R" then - op = op + parse_reglist(q); n = n + 1 - elseif p == "r" then - op = op + parse_vrlist(q); n = n + 1 - elseif p == "W" then - op = op + parse_imm16(q); n = n + 1 - elseif p == "v" then - op = op + parse_imm(q, 5, 7, 0, false); n = n + 1 - elseif p == "w" then - local imm = match(q, "^#(.*)$") - if imm then - op = op + parse_imm(q, 5, 7, 0, false); n = n + 1 - else - op = op + shl(parse_gpr(q), 8) + 16 - end - elseif p == "X" then - op = op + parse_imm(q, 5, 16, 0, false); n = n + 1 - elseif p == "Y" then - local imm = tonumber(match(q, "^#(.*)$")); n = n + 1 - if not imm or shr(imm, 8) ~= 0 then - werror("bad immediate operand") - end - op = op + shl(band(imm, 0xf0), 12) + band(imm, 0x0f) - elseif p == "K" then - local imm = tonumber(match(q, "^#(.*)$")); n = n + 1 - if not imm or shr(imm, 16) ~= 0 then - werror("bad immediate operand") - end - op = op + shl(band(imm, 0xfff0), 4) + band(imm, 0x000f) - elseif p == "T" then - op = op + parse_imm(q, 24, 0, 0, false); n = n + 1 - elseif p == "s" then - -- Ignored. - else - assert(false) - end - end - wputpos(pos, op) -end - -map_op[".template__"] = function(params, template, nparams) - if not params then return template:gsub("%x%x%x%x%x%x%x%x", "") end - - -- Limit number of section buffer positions used by a single dasm_put(). - -- A single opcode needs a maximum of 3 positions. - if secpos+3 > maxsecpos then wflush() end - local pos = wpos() - local lpos, apos, spos = #actlist, #actargs, secpos - - local ok, err - for t in gmatch(template, "[^|]+") do - ok, err = pcall(parse_template, params, t, nparams, pos) - if ok then return end - secpos = spos - actlist[lpos+1] = nil - actlist[lpos+2] = nil - actlist[lpos+3] = nil - actargs[apos+1] = nil - actargs[apos+2] = nil - actargs[apos+3] = nil - end - error(err, 0) -end - ------------------------------------------------------------------------------- - --- Pseudo-opcode to mark the position where the action list is to be emitted. -map_op[".actionlist_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeactions(out, name) end) -end - --- Pseudo-opcode to mark the position where the global enum is to be emitted. -map_op[".globals_1"] = function(params) - if not params then return "prefix" end - local prefix = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeglobals(out, prefix) end) -end - --- Pseudo-opcode to mark the position where the global names are to be emitted. -map_op[".globalnames_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeglobalnames(out, name) end) -end - --- Pseudo-opcode to mark the position where the extern names are to be emitted. -map_op[".externnames_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeexternnames(out, name) end) -end - ------------------------------------------------------------------------------- - --- Label pseudo-opcode (converted from trailing colon form). -map_op[".label_1"] = function(params) - if not params then return "[1-9] | ->global | =>pcexpr" end - if secpos+1 > maxsecpos then wflush() end - local mode, n, s = parse_label(params[1], true) - if mode == "EXT" then werror("bad label definition") end - waction("LABEL_"..mode, n, s, 1) -end - ------------------------------------------------------------------------------- - --- Pseudo-opcodes for data storage. -map_op[".long_*"] = function(params) - if not params then return "imm..." end - for _,p in ipairs(params) do - local n = tonumber(p) - if not n then werror("bad immediate `"..p.."'") end - if n < 0 then n = n + 2^32 end - wputw(n) - if secpos+2 > maxsecpos then wflush() end - end -end - --- Alignment pseudo-opcode. -map_op[".align_1"] = function(params) - if not params then return "numpow2" end - if secpos+1 > maxsecpos then wflush() end - local align = tonumber(params[1]) - if align then - local x = align - -- Must be a power of 2 in the range (2 ... 256). - for i=1,8 do - x = x / 2 - if x == 1 then - waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. - return - end - end - end - werror("bad alignment") -end - ------------------------------------------------------------------------------- - --- Pseudo-opcode for (primitive) type definitions (map to C types). -map_op[".type_3"] = function(params, nparams) - if not params then - return nparams == 2 and "name, ctype" or "name, ctype, reg" - end - local name, ctype, reg = params[1], params[2], params[3] - if not match(name, "^[%a_][%w_]*$") then - werror("bad type name `"..name.."'") - end - local tp = map_type[name] - if tp then - werror("duplicate type `"..name.."'") - end - -- Add #type to defines. A bit unclean to put it in map_archdef. - map_archdef["#"..name] = "sizeof("..ctype..")" - -- Add new type and emit shortcut define. - local num = ctypenum + 1 - map_type[name] = { - ctype = ctype, - ctypefmt = format("Dt%X(%%s)", num), - reg = reg, - } - wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) - ctypenum = num -end -map_op[".type_2"] = map_op[".type_3"] - --- Dump type definitions. -local function dumptypes(out, lvl) - local t = {} - for name in pairs(map_type) do t[#t+1] = name end - sort(t) - out:write("Type definitions:\n") - for _,name in ipairs(t) do - local tp = map_type[name] - local reg = tp.reg or "" - out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) - end - out:write("\n") -end - ------------------------------------------------------------------------------- - --- Set the current section. -function _M.section(num) - waction("SECTION", num) - wflush(true) -- SECTION is a terminal action. -end - ------------------------------------------------------------------------------- - --- Dump architecture description. -function _M.dumparch(out) - out:write(format("DynASM %s version %s, released %s\n\n", - _info.arch, _info.version, _info.release)) - dumpactions(out) -end - --- Dump all user defined elements. -function _M.dumpdef(out, lvl) - dumptypes(out, lvl) - dumpglobals(out, lvl) - dumpexterns(out, lvl) -end - ------------------------------------------------------------------------------- - --- Pass callbacks from/to the DynASM core. -function _M.passcb(wl, we, wf, ww) - wline, werror, wfatal, wwarn = wl, we, wf, ww - return wflush -end - --- Setup the arch-specific module. -function _M.setup(arch, opt) - g_arch, g_opt = arch, opt -end - --- Merge the core maps and the arch-specific maps. -function _M.mergemaps(map_coreop, map_def) - setmetatable(map_op, { __index = function(t, k) - local v = map_coreop[k] - if v then return v end - local k1, cc, k2 = match(k, "^(.-)(..)([._].*)$") - local cv = map_cond[cc] - if cv then - local v = rawget(t, k1..k2) - if type(v) == "string" then - local scv = format("%x", cv) - return gsub(scv..sub(v, 2), "|e", "|"..scv) - end - end - end }) - setmetatable(map_def, { __index = map_archdef }) - return map_op, map_def -end - -return _M - ------------------------------------------------------------------------------- - diff --git a/lib/LuaJIT/dynasm/dasm_arm64.h b/lib/LuaJIT/dynasm/dasm_arm64.h deleted file mode 100644 index ff21236..0000000 --- a/lib/LuaJIT/dynasm/dasm_arm64.h +++ /dev/null @@ -1,519 +0,0 @@ -/* -** DynASM ARM64 encoding engine. -** Copyright (C) 2005-2017 Mike Pall. All rights reserved. -** Released under the MIT license. See dynasm.lua for full copyright notice. -*/ - -#include -#include -#include -#include - -#define DASM_ARCH "arm64" - -#ifndef DASM_EXTERN -#define DASM_EXTERN(a,b,c,d) 0 -#endif - -/* Action definitions. */ -enum { - DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, - /* The following actions need a buffer position. */ - DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, - /* The following actions also have an argument. */ - DASM_REL_PC, DASM_LABEL_PC, - DASM_IMM, DASM_IMM6, DASM_IMM12, DASM_IMM13W, DASM_IMM13X, DASM_IMML, - DASM__MAX -}; - -/* Maximum number of section buffer positions for a single dasm_put() call. */ -#define DASM_MAXSECPOS 25 - -/* DynASM encoder status codes. Action list offset or number are or'ed in. */ -#define DASM_S_OK 0x00000000 -#define DASM_S_NOMEM 0x01000000 -#define DASM_S_PHASE 0x02000000 -#define DASM_S_MATCH_SEC 0x03000000 -#define DASM_S_RANGE_I 0x11000000 -#define DASM_S_RANGE_SEC 0x12000000 -#define DASM_S_RANGE_LG 0x13000000 -#define DASM_S_RANGE_PC 0x14000000 -#define DASM_S_RANGE_REL 0x15000000 -#define DASM_S_UNDEF_LG 0x21000000 -#define DASM_S_UNDEF_PC 0x22000000 - -/* Macros to convert positions (8 bit section + 24 bit index). */ -#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) -#define DASM_POS2BIAS(pos) ((pos)&0xff000000) -#define DASM_SEC2POS(sec) ((sec)<<24) -#define DASM_POS2SEC(pos) ((pos)>>24) -#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) - -/* Action list type. */ -typedef const unsigned int *dasm_ActList; - -/* Per-section structure. */ -typedef struct dasm_Section { - int *rbuf; /* Biased buffer pointer (negative section bias). */ - int *buf; /* True buffer pointer. */ - size_t bsize; /* Buffer size in bytes. */ - int pos; /* Biased buffer position. */ - int epos; /* End of biased buffer position - max single put. */ - int ofs; /* Byte offset into section. */ -} dasm_Section; - -/* Core structure holding the DynASM encoding state. */ -struct dasm_State { - size_t psize; /* Allocated size of this structure. */ - dasm_ActList actionlist; /* Current actionlist pointer. */ - int *lglabels; /* Local/global chain/pos ptrs. */ - size_t lgsize; - int *pclabels; /* PC label chains/pos ptrs. */ - size_t pcsize; - void **globals; /* Array of globals (bias -10). */ - dasm_Section *section; /* Pointer to active section. */ - size_t codesize; /* Total size of all code sections. */ - int maxsection; /* 0 <= sectionidx < maxsection. */ - int status; /* Status code. */ - dasm_Section sections[1]; /* All sections. Alloc-extended. */ -}; - -/* The size of the core structure depends on the max. number of sections. */ -#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) - - -/* Initialize DynASM state. */ -void dasm_init(Dst_DECL, int maxsection) -{ - dasm_State *D; - size_t psz = 0; - int i; - Dst_REF = NULL; - DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); - D = Dst_REF; - D->psize = psz; - D->lglabels = NULL; - D->lgsize = 0; - D->pclabels = NULL; - D->pcsize = 0; - D->globals = NULL; - D->maxsection = maxsection; - for (i = 0; i < maxsection; i++) { - D->sections[i].buf = NULL; /* Need this for pass3. */ - D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); - D->sections[i].bsize = 0; - D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ - } -} - -/* Free DynASM state. */ -void dasm_free(Dst_DECL) -{ - dasm_State *D = Dst_REF; - int i; - for (i = 0; i < D->maxsection; i++) - if (D->sections[i].buf) - DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); - if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); - if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); - DASM_M_FREE(Dst, D, D->psize); -} - -/* Setup global label array. Must be called before dasm_setup(). */ -void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) -{ - dasm_State *D = Dst_REF; - D->globals = gl - 10; /* Negative bias to compensate for locals. */ - DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); -} - -/* Grow PC label array. Can be called after dasm_setup(), too. */ -void dasm_growpc(Dst_DECL, unsigned int maxpc) -{ - dasm_State *D = Dst_REF; - size_t osz = D->pcsize; - DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); - memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); -} - -/* Setup encoder. */ -void dasm_setup(Dst_DECL, const void *actionlist) -{ - dasm_State *D = Dst_REF; - int i; - D->actionlist = (dasm_ActList)actionlist; - D->status = DASM_S_OK; - D->section = &D->sections[0]; - memset((void *)D->lglabels, 0, D->lgsize); - if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); - for (i = 0; i < D->maxsection; i++) { - D->sections[i].pos = DASM_SEC2POS(i); - D->sections[i].ofs = 0; - } -} - - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) { \ - D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) -#define CKPL(kind, st) \ - do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ - D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) -#else -#define CK(x, st) ((void)0) -#define CKPL(kind, st) ((void)0) -#endif - -static int dasm_imm12(unsigned int n) -{ - if ((n >> 12) == 0) - return n; - else if ((n & 0xff000fff) == 0) - return (n >> 12) | 0x1000; - else - return -1; -} - -static int dasm_ffs(unsigned long long x) -{ - int n = -1; - while (x) { x >>= 1; n++; } - return n; -} - -static int dasm_imm13(int lo, int hi) -{ - int inv = 0, w = 64, s = 0xfff, xa, xb; - unsigned long long n = (((unsigned long long)hi) << 32) | (unsigned int)lo; - unsigned long long m = 1ULL, a, b, c; - if (n & 1) { n = ~n; inv = 1; } - a = n & -n; b = (n+a)&-(n+a); c = (n+a-b)&-(n+a-b); - xa = dasm_ffs(a); xb = dasm_ffs(b); - if (c) { - w = dasm_ffs(c) - xa; - if (w == 32) m = 0x0000000100000001UL; - else if (w == 16) m = 0x0001000100010001UL; - else if (w == 8) m = 0x0101010101010101UL; - else if (w == 4) m = 0x1111111111111111UL; - else if (w == 2) m = 0x5555555555555555UL; - else return -1; - s = (-2*w & 0x3f) - 1; - } else if (!a) { - return -1; - } else if (xb == -1) { - xb = 64; - } - if ((b-a) * m != n) return -1; - if (inv) { - return ((w - xb) << 6) | (s+w+xa-xb); - } else { - return ((w - xa) << 6) | (s+xb-xa); - } - return -1; -} - -/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ -void dasm_put(Dst_DECL, int start, ...) -{ - va_list ap; - dasm_State *D = Dst_REF; - dasm_ActList p = D->actionlist + start; - dasm_Section *sec = D->section; - int pos = sec->pos, ofs = sec->ofs; - int *b; - - if (pos >= sec->epos) { - DASM_M_GROW(Dst, int, sec->buf, sec->bsize, - sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); - sec->rbuf = sec->buf - DASM_POS2BIAS(pos); - sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); - } - - b = sec->rbuf; - b[pos++] = start; - - va_start(ap, start); - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - if (action >= DASM__MAX) { - ofs += 4; - } else { - int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; - switch (action) { - case DASM_STOP: goto stop; - case DASM_SECTION: - n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); - D->section = &D->sections[n]; goto stop; - case DASM_ESC: p++; ofs += 4; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; - case DASM_REL_LG: - n = (ins & 2047) - 10; pl = D->lglabels + n; - /* Bkwd rel or global. */ - if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } - pl += 10; n = *pl; - if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ - goto linkrel; - case DASM_REL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putrel: - n = *pl; - if (n < 0) { /* Label exists. Get label pos and store it. */ - b[pos] = -n; - } else { - linkrel: - b[pos] = n; /* Else link to rel chain, anchored at label. */ - *pl = pos; - } - pos++; - break; - case DASM_LABEL_LG: - pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; - case DASM_LABEL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putlabel: - n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; - } - *pl = -pos; /* Label exists now. */ - b[pos++] = ofs; /* Store pass1 offset estimate. */ - break; - case DASM_IMM: - CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); - n >>= ((ins>>10)&31); -#ifdef DASM_CHECKS - if ((ins & 0x8000)) - CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); - else - CK((n>>((ins>>5)&31)) == 0, RANGE_I); -#endif - b[pos++] = n; - break; - case DASM_IMM6: - CK((n >> 6) == 0, RANGE_I); - b[pos++] = n; - break; - case DASM_IMM12: - CK(dasm_imm12((unsigned int)n) != -1, RANGE_I); - b[pos++] = n; - break; - case DASM_IMM13W: - CK(dasm_imm13(n, n) != -1, RANGE_I); - b[pos++] = n; - break; - case DASM_IMM13X: { - int m = va_arg(ap, int); - CK(dasm_imm13(n, m) != -1, RANGE_I); - b[pos++] = n; - b[pos++] = m; - break; - } - case DASM_IMML: { -#ifdef DASM_CHECKS - int scale = (p[-2] >> 30); - CK((!(n & ((1<>scale) < 4096) || - (unsigned int)(n+256) < 512, RANGE_I); -#endif - b[pos++] = n; - break; - } - } - } - } -stop: - va_end(ap); - sec->pos = pos; - sec->ofs = ofs; -} -#undef CK - -/* Pass 2: Link sections, shrink aligns, fix label offsets. */ -int dasm_link(Dst_DECL, size_t *szp) -{ - dasm_State *D = Dst_REF; - int secnum; - int ofs = 0; - -#ifdef DASM_CHECKS - *szp = 0; - if (D->status != DASM_S_OK) return D->status; - { - int pc; - for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) - if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; - } -#endif - - { /* Handle globals not defined in this translation unit. */ - int idx; - for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { - int n = D->lglabels[idx]; - /* Undefined label: Collapse rel chain and replace with marker (< 0). */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } - } - } - - /* Combine all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->rbuf; - int pos = DASM_SEC2POS(secnum); - int lastpos = sec->pos; - - while (pos != lastpos) { - dasm_ActList p = D->actionlist + b[pos++]; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: p++; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; - case DASM_REL_LG: case DASM_REL_PC: pos++; break; - case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; - case DASM_IMM: case DASM_IMM6: case DASM_IMM12: case DASM_IMM13W: - case DASM_IMML: pos++; break; - case DASM_IMM13X: pos += 2; break; - } - } - stop: (void)0; - } - ofs += sec->ofs; /* Next section starts right after current section. */ - } - - D->codesize = ofs; /* Total size of all code sections */ - *szp = ofs; - return DASM_S_OK; -} - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) -#else -#define CK(x, st) ((void)0) -#endif - -/* Pass 3: Encode sections. */ -int dasm_encode(Dst_DECL, void *buffer) -{ - dasm_State *D = Dst_REF; - char *base = (char *)buffer; - unsigned int *cp = (unsigned int *)buffer; - int secnum; - - /* Encode all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->buf; - int *endb = sec->rbuf + sec->pos; - - while (b != endb) { - dasm_ActList p = D->actionlist + *b++; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: *cp++ = *p++; break; - case DASM_REL_EXT: - n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048)); - goto patchrel; - case DASM_ALIGN: - ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000; - break; - case DASM_REL_LG: - CK(n >= 0, UNDEF_LG); - /* fallthrough */ - case DASM_REL_PC: - CK(n >= 0, UNDEF_PC); - n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) + 4; - patchrel: - if (!(ins & 0xf800)) { /* B, BL */ - CK((n & 3) == 0 && ((n+0x08000000) >> 28) == 0, RANGE_REL); - cp[-1] |= ((n >> 2) & 0x03ffffff); - } else if ((ins & 0x800)) { /* B.cond, CBZ, CBNZ, LDR* literal */ - CK((n & 3) == 0 && ((n+0x00100000) >> 21) == 0, RANGE_REL); - cp[-1] |= ((n << 3) & 0x00ffffe0); - } else if ((ins & 0x3000) == 0x2000) { /* ADR */ - CK(((n+0x00100000) >> 21) == 0, RANGE_REL); - cp[-1] |= ((n << 3) & 0x00ffffe0) | ((n & 3) << 29); - } else if ((ins & 0x3000) == 0x3000) { /* ADRP */ - cp[-1] |= ((n >> 9) & 0x00ffffe0) | (((n >> 12) & 3) << 29); - } else if ((ins & 0x1000)) { /* TBZ, TBNZ */ - CK((n & 3) == 0 && ((n+0x00008000) >> 16) == 0, RANGE_REL); - cp[-1] |= ((n << 3) & 0x0007ffe0); - } - break; - case DASM_LABEL_LG: - ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); - break; - case DASM_LABEL_PC: break; - case DASM_IMM: - cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); - break; - case DASM_IMM6: - cp[-1] |= ((n&31) << 19) | ((n&32) << 26); - break; - case DASM_IMM12: - cp[-1] |= (dasm_imm12((unsigned int)n) << 10); - break; - case DASM_IMM13W: - cp[-1] |= (dasm_imm13(n, n) << 10); - break; - case DASM_IMM13X: - cp[-1] |= (dasm_imm13(n, *b++) << 10); - break; - case DASM_IMML: { - int scale = (p[-2] >> 30); - cp[-1] |= (!(n & ((1<>scale) < 4096) ? - ((n << (10-scale)) | 0x01000000) : ((n & 511) << 12); - break; - } - default: *cp++ = ins; break; - } - } - stop: (void)0; - } - } - - if (base + D->codesize != (char *)cp) /* Check for phase errors. */ - return DASM_S_PHASE; - return DASM_S_OK; -} -#undef CK - -/* Get PC label offset. */ -int dasm_getpclabel(Dst_DECL, unsigned int pc) -{ - dasm_State *D = Dst_REF; - if (pc*sizeof(int) < D->pcsize) { - int pos = D->pclabels[pc]; - if (pos < 0) return *DASM_POS2PTR(D, -pos); - if (pos > 0) return -1; /* Undefined. */ - } - return -2; /* Unused or out of range. */ -} - -#ifdef DASM_CHECKS -/* Optional sanity checker to call between isolated encoding steps. */ -int dasm_checkstep(Dst_DECL, int secmatch) -{ - dasm_State *D = Dst_REF; - if (D->status == DASM_S_OK) { - int i; - for (i = 1; i <= 9; i++) { - if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } - D->lglabels[i] = 0; - } - } - if (D->status == DASM_S_OK && secmatch >= 0 && - D->section != &D->sections[secmatch]) - D->status = DASM_S_MATCH_SEC|(D->section-D->sections); - return D->status; -} -#endif - diff --git a/lib/LuaJIT/dynasm/dasm_arm64.lua b/lib/LuaJIT/dynasm/dasm_arm64.lua deleted file mode 100644 index 8a5f735..0000000 --- a/lib/LuaJIT/dynasm/dasm_arm64.lua +++ /dev/null @@ -1,1166 +0,0 @@ ------------------------------------------------------------------------------- --- DynASM ARM64 module. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------- - --- Module information: -local _info = { - arch = "arm", - description = "DynASM ARM64 module", - version = "1.4.0", - vernum = 10400, - release = "2015-10-18", - author = "Mike Pall", - license = "MIT", -} - --- Exported glue functions for the arch-specific module. -local _M = { _info = _info } - --- Cache library functions. -local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs -local assert, setmetatable, rawget = assert, setmetatable, rawget -local _s = string -local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char -local match, gmatch, gsub = _s.match, _s.gmatch, _s.gsub -local concat, sort, insert = table.concat, table.sort, table.insert -local bit = bit or require("bit") -local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift -local ror, tohex = bit.ror, bit.tohex - --- Inherited tables and callbacks. -local g_opt, g_arch -local wline, werror, wfatal, wwarn - --- Action name list. --- CHECK: Keep this in sync with the C code! -local action_names = { - "STOP", "SECTION", "ESC", "REL_EXT", - "ALIGN", "REL_LG", "LABEL_LG", - "REL_PC", "LABEL_PC", "IMM", "IMM6", "IMM12", "IMM13W", "IMM13X", "IMML", -} - --- Maximum number of section buffer positions for dasm_put(). --- CHECK: Keep this in sync with the C code! -local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. - --- Action name -> action number. -local map_action = {} -for n,name in ipairs(action_names) do - map_action[name] = n-1 -end - --- Action list buffer. -local actlist = {} - --- Argument list for next dasm_put(). Start with offset 0 into action list. -local actargs = { 0 } - --- Current number of section buffer positions for dasm_put(). -local secpos = 1 - ------------------------------------------------------------------------------- - --- Dump action names and numbers. -local function dumpactions(out) - out:write("DynASM encoding engine action codes:\n") - for n,name in ipairs(action_names) do - local num = map_action[name] - out:write(format(" %-10s %02X %d\n", name, num, num)) - end - out:write("\n") -end - --- Write action list buffer as a huge static C array. -local function writeactions(out, name) - local nn = #actlist - if nn == 0 then nn = 1; actlist[0] = map_action.STOP end - out:write("static const unsigned int ", name, "[", nn, "] = {\n") - for i = 1,nn-1 do - assert(out:write("0x", tohex(actlist[i]), ",\n")) - end - assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) -end - ------------------------------------------------------------------------------- - --- Add word to action list. -local function wputxw(n) - assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") - actlist[#actlist+1] = n -end - --- Add action to list with optional arg. Advance buffer pos, too. -local function waction(action, val, a, num) - local w = assert(map_action[action], "bad action name `"..action.."'") - wputxw(w * 0x10000 + (val or 0)) - if a then actargs[#actargs+1] = a end - if a or num then secpos = secpos + (num or 1) end -end - --- Flush action list (intervening C code or buffer pos overflow). -local function wflush(term) - if #actlist == actargs[1] then return end -- Nothing to flush. - if not term then waction("STOP") end -- Terminate action list. - wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) - actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). - secpos = 1 -- The actionlist offset occupies a buffer position, too. -end - --- Put escaped word. -local function wputw(n) - if n <= 0x000fffff then waction("ESC") end - wputxw(n) -end - --- Reserve position for word. -local function wpos() - local pos = #actlist+1 - actlist[pos] = "" - return pos -end - --- Store word to reserved position. -local function wputpos(pos, n) - assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") - if n <= 0x000fffff then - insert(actlist, pos+1, n) - n = map_action.ESC * 0x10000 - end - actlist[pos] = n -end - ------------------------------------------------------------------------------- - --- Global label name -> global label number. With auto assignment on 1st use. -local next_global = 20 -local map_global = setmetatable({}, { __index = function(t, name) - if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end - local n = next_global - if n > 2047 then werror("too many global labels") end - next_global = n + 1 - t[name] = n - return n -end}) - --- Dump global labels. -local function dumpglobals(out, lvl) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("Global labels:\n") - for i=20,next_global-1 do - out:write(format(" %s\n", t[i])) - end - out:write("\n") -end - --- Write global label enum. -local function writeglobals(out, prefix) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("enum {\n") - for i=20,next_global-1 do - out:write(" ", prefix, t[i], ",\n") - end - out:write(" ", prefix, "_MAX\n};\n") -end - --- Write global label names. -local function writeglobalnames(out, name) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("static const char *const ", name, "[] = {\n") - for i=20,next_global-1 do - out:write(" \"", t[i], "\",\n") - end - out:write(" (const char *)0\n};\n") -end - ------------------------------------------------------------------------------- - --- Extern label name -> extern label number. With auto assignment on 1st use. -local next_extern = 0 -local map_extern_ = {} -local map_extern = setmetatable({}, { __index = function(t, name) - -- No restrictions on the name for now. - local n = next_extern - if n > 2047 then werror("too many extern labels") end - next_extern = n + 1 - t[name] = n - map_extern_[n] = name - return n -end}) - --- Dump extern labels. -local function dumpexterns(out, lvl) - out:write("Extern labels:\n") - for i=0,next_extern-1 do - out:write(format(" %s\n", map_extern_[i])) - end - out:write("\n") -end - --- Write extern label names. -local function writeexternnames(out, name) - out:write("static const char *const ", name, "[] = {\n") - for i=0,next_extern-1 do - out:write(" \"", map_extern_[i], "\",\n") - end - out:write(" (const char *)0\n};\n") -end - ------------------------------------------------------------------------------- - --- Arch-specific maps. - --- Ext. register name -> int. name. -local map_archdef = { xzr = "@x31", wzr = "@w31", lr = "x30", } - --- Int. register name -> ext. name. -local map_reg_rev = { ["@x31"] = "xzr", ["@w31"] = "wzr", x30 = "lr", } - -local map_type = {} -- Type name -> { ctype, reg } -local ctypenum = 0 -- Type number (for Dt... macros). - --- Reverse defines for registers. -function _M.revdef(s) - return map_reg_rev[s] or s -end - -local map_shift = { lsl = 0, lsr = 1, asr = 2, } - -local map_extend = { - uxtb = 0, uxth = 1, uxtw = 2, uxtx = 3, - sxtb = 4, sxth = 5, sxtw = 6, sxtx = 7, -} - -local map_cond = { - eq = 0, ne = 1, cs = 2, cc = 3, mi = 4, pl = 5, vs = 6, vc = 7, - hi = 8, ls = 9, ge = 10, lt = 11, gt = 12, le = 13, al = 14, - hs = 2, lo = 3, -} - ------------------------------------------------------------------------------- - -local parse_reg_type - -local function parse_reg(expr) - if not expr then werror("expected register name") end - local tname, ovreg = match(expr, "^([%w_]+):(@?%l%d+)$") - local tp = map_type[tname or expr] - if tp then - local reg = ovreg or tp.reg - if not reg then - werror("type `"..(tname or expr).."' needs a register override") - end - expr = reg - end - local ok31, rt, r = match(expr, "^(@?)([xwqdshb])([123]?[0-9])$") - if r then - r = tonumber(r) - if r <= 30 or (r == 31 and ok31 ~= "" or (rt ~= "w" and rt ~= "x")) then - if not parse_reg_type then - parse_reg_type = rt - elseif parse_reg_type ~= rt then - werror("register size mismatch") - end - return r, tp - end - end - werror("bad register name `"..expr.."'") -end - -local function parse_reg_base(expr) - if expr == "sp" then return 0x3e0 end - local base, tp = parse_reg(expr) - if parse_reg_type ~= "x" then werror("bad register type") end - parse_reg_type = false - return shl(base, 5), tp -end - -local parse_ctx = {} - -local loadenv = setfenv and function(s) - local code = loadstring(s, "") - if code then setfenv(code, parse_ctx) end - return code -end or function(s) - return load(s, "", nil, parse_ctx) -end - --- Try to parse simple arithmetic, too, since some basic ops are aliases. -local function parse_number(n) - local x = tonumber(n) - if x then return x end - local code = loadenv("return "..n) - if code then - local ok, y = pcall(code) - if ok then return y end - end - return nil -end - -local function parse_imm(imm, bits, shift, scale, signed) - imm = match(imm, "^#(.*)$") - if not imm then werror("expected immediate operand") end - local n = parse_number(imm) - if n then - local m = sar(n, scale) - if shl(m, scale) == n then - if signed then - local s = sar(m, bits-1) - if s == 0 then return shl(m, shift) - elseif s == -1 then return shl(m + shl(1, bits), shift) end - else - if sar(m, bits) == 0 then return shl(m, shift) end - end - end - werror("out of range immediate `"..imm.."'") - else - waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) - return 0 - end -end - -local function parse_imm12(imm) - imm = match(imm, "^#(.*)$") - if not imm then werror("expected immediate operand") end - local n = parse_number(imm) - if n then - if shr(n, 12) == 0 then - return shl(n, 10) - elseif band(n, 0xff000fff) == 0 then - return shr(n, 2) + 0x00400000 - end - werror("out of range immediate `"..imm.."'") - else - waction("IMM12", 0, imm) - return 0 - end -end - -local function parse_imm13(imm) - imm = match(imm, "^#(.*)$") - if not imm then werror("expected immediate operand") end - local n = parse_number(imm) - local r64 = parse_reg_type == "x" - if n and n % 1 == 0 and n >= 0 and n <= 0xffffffff then - local inv = false - if band(n, 1) == 1 then n = bit.bnot(n); inv = true end - local t = {} - for i=1,32 do t[i] = band(n, 1); n = shr(n, 1) end - local b = table.concat(t) - b = b..(r64 and (inv and "1" or "0"):rep(32) or b) - local p0, p1, p0a, p1a = b:match("^(0+)(1+)(0*)(1*)") - if p0 then - local w = p1a == "" and (r64 and 64 or 32) or #p1+#p0a - if band(w, w-1) == 0 and b == b:sub(1, w):rep(64/w) then - local s = band(-2*w, 0x3f) - 1 - if w == 64 then s = s + 0x1000 end - if inv then - return shl(w-#p1-#p0, 16) + shl(s+w-#p1, 10) - else - return shl(w-#p0, 16) + shl(s+#p1, 10) - end - end - end - werror("out of range immediate `"..imm.."'") - elseif r64 then - waction("IMM13X", 0, format("(unsigned int)(%s)", imm)) - actargs[#actargs+1] = format("(unsigned int)((unsigned long long)(%s)>>32)", imm) - return 0 - else - waction("IMM13W", 0, imm) - return 0 - end -end - -local function parse_imm6(imm) - imm = match(imm, "^#(.*)$") - if not imm then werror("expected immediate operand") end - local n = parse_number(imm) - if n then - if n >= 0 and n <= 63 then - return shl(band(n, 0x1f), 19) + (n >= 32 and 0x80000000 or 0) - end - werror("out of range immediate `"..imm.."'") - else - waction("IMM6", 0, imm) - return 0 - end -end - -local function parse_imm_load(imm, scale) - local n = parse_number(imm) - if n then - local m = sar(n, scale) - if shl(m, scale) == n and m >= 0 and m < 0x1000 then - return shl(m, 10) + 0x01000000 -- Scaled, unsigned 12 bit offset. - elseif n >= -256 and n < 256 then - return shl(band(n, 511), 12) -- Unscaled, signed 9 bit offset. - end - werror("out of range immediate `"..imm.."'") - else - waction("IMML", 0, imm) - return 0 - end -end - -local function parse_fpimm(imm) - imm = match(imm, "^#(.*)$") - if not imm then werror("expected immediate operand") end - local n = parse_number(imm) - if n then - local m, e = math.frexp(n) - local s, e2 = 0, band(e-2, 7) - if m < 0 then m = -m; s = 0x00100000 end - m = m*32-16 - if m % 1 == 0 and m >= 0 and m <= 15 and sar(shl(e2, 29), 29)+2 == e then - return s + shl(e2, 17) + shl(m, 13) - end - werror("out of range immediate `"..imm.."'") - else - werror("NYI fpimm action") - end -end - -local function parse_shift(expr) - local s, s2 = match(expr, "^(%S+)%s*(.*)$") - s = map_shift[s] - if not s then werror("expected shift operand") end - return parse_imm(s2, 6, 10, 0, false) + shl(s, 22) -end - -local function parse_lslx16(expr) - local n = match(expr, "^lsl%s*#(%d+)$") - n = tonumber(n) - if not n then werror("expected shift operand") end - if band(n, parse_reg_type == "x" and 0xffffffcf or 0xffffffef) ~= 0 then - werror("bad shift amount") - end - return shl(n, 17) -end - -local function parse_extend(expr) - local s, s2 = match(expr, "^(%S+)%s*(.*)$") - if s == "lsl" then - s = parse_reg_type == "x" and 3 or 2 - else - s = map_extend[s] - end - if not s then werror("expected extend operand") end - return (s2 == "" and 0 or parse_imm(s2, 3, 10, 0, false)) + shl(s, 13) -end - -local function parse_cond(expr, inv) - local c = map_cond[expr] - if not c then werror("expected condition operand") end - return shl(bit.bxor(c, inv), 12) -end - -local function parse_load(params, nparams, n, op) - if params[n+2] then werror("too many operands") end - local pn, p2 = params[n], params[n+1] - local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$") - if not p1 then - if not p2 then - local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$") - if reg and tailr ~= "" then - local base, tp = parse_reg_base(reg) - if tp then - waction("IMML", 0, format(tp.ctypefmt, tailr)) - return op + base - end - end - end - werror("expected address operand") - end - local scale = shr(op, 30) - if p2 then - if wb == "!" then werror("bad use of '!'") end - op = op + parse_reg_base(p1) + parse_imm(p2, 9, 12, 0, true) + 0x400 - elseif wb == "!" then - local p1a, p2a = match(p1, "^([^,%s]*)%s*,%s*(.*)$") - if not p1a then werror("bad use of '!'") end - op = op + parse_reg_base(p1a) + parse_imm(p2a, 9, 12, 0, true) + 0xc00 - else - local p1a, p2a = match(p1, "^([^,%s]*)%s*(.*)$") - op = op + parse_reg_base(p1a) - if p2a ~= "" then - local imm = match(p2a, "^,%s*#(.*)$") - if imm then - op = op + parse_imm_load(imm, scale) - else - local p2b, p3b, p3s = match(p2a, "^,%s*([^,%s]*)%s*,?%s*(%S*)%s*(.*)$") - op = op + shl(parse_reg(p2b), 16) + 0x00200800 - if parse_reg_type ~= "x" and parse_reg_type ~= "w" then - werror("bad index register type") - end - if p3b == "" then - if parse_reg_type ~= "x" then werror("bad index register type") end - op = op + 0x6000 - else - if p3s == "" or p3s == "#0" then - elseif p3s == "#"..scale then - op = op + 0x1000 - else - werror("bad scale") - end - if parse_reg_type == "x" then - if p3b == "lsl" and p3s ~= "" then op = op + 0x6000 - elseif p3b == "sxtx" then op = op + 0xe000 - else - werror("bad extend/shift specifier") - end - else - if p3b == "uxtw" then op = op + 0x4000 - elseif p3b == "sxtw" then op = op + 0xc000 - else - werror("bad extend/shift specifier") - end - end - end - end - else - if wb == "!" then werror("bad use of '!'") end - op = op + 0x01000000 - end - end - return op -end - -local function parse_load_pair(params, nparams, n, op) - if params[n+2] then werror("too many operands") end - local pn, p2 = params[n], params[n+1] - local scale = shr(op, 30) == 0 and 2 or 3 - local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$") - if not p1 then - if not p2 then - local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$") - if reg and tailr ~= "" then - local base, tp = parse_reg_base(reg) - if tp then - waction("IMM", 32768+7*32+15+scale*1024, format(tp.ctypefmt, tailr)) - return op + base + 0x01000000 - end - end - end - werror("expected address operand") - end - if p2 then - if wb == "!" then werror("bad use of '!'") end - op = op + 0x00800000 - else - local p1a, p2a = match(p1, "^([^,%s]*)%s*,%s*(.*)$") - if p1a then p1, p2 = p1a, p2a else p2 = "#0" end - op = op + (wb == "!" and 0x01800000 or 0x01000000) - end - return op + parse_reg_base(p1) + parse_imm(p2, 7, 15, scale, true) -end - -local function parse_label(label, def) - local prefix = sub(label, 1, 2) - -- =>label (pc label reference) - if prefix == "=>" then - return "PC", 0, sub(label, 3) - end - -- ->name (global label reference) - if prefix == "->" then - return "LG", map_global[sub(label, 3)] - end - if def then - -- [1-9] (local label definition) - if match(label, "^[1-9]$") then - return "LG", 10+tonumber(label) - end - else - -- [<>][1-9] (local label reference) - local dir, lnum = match(label, "^([<>])([1-9])$") - if dir then -- Fwd: 1-9, Bkwd: 11-19. - return "LG", lnum + (dir == ">" and 0 or 10) - end - -- extern label (extern label reference) - local extname = match(label, "^extern%s+(%S+)$") - if extname then - return "EXT", map_extern[extname] - end - end - werror("bad label `"..label.."'") -end - -local function branch_type(op) - if band(op, 0x7c000000) == 0x14000000 then return 0 -- B, BL - elseif shr(op, 24) == 0x54 or band(op, 0x7e000000) == 0x34000000 or - band(op, 0x3b000000) == 0x18000000 then - return 0x800 -- B.cond, CBZ, CBNZ, LDR* literal - elseif band(op, 0x7e000000) == 0x36000000 then return 0x1000 -- TBZ, TBNZ - elseif band(op, 0x9f000000) == 0x10000000 then return 0x2000 -- ADR - elseif band(op, 0x9f000000) == band(0x90000000) then return 0x3000 -- ADRP - else - assert(false, "unknown branch type") - end -end - ------------------------------------------------------------------------------- - -local map_op, op_template - -local function op_alias(opname, f) - return function(params, nparams) - if not params then return "-> "..opname:sub(1, -3) end - f(params, nparams) - op_template(params, map_op[opname], nparams) - end -end - -local function alias_bfx(p) - p[4] = "#("..p[3]:sub(2)..")+("..p[4]:sub(2)..")-1" -end - -local function alias_bfiz(p) - parse_reg(p[1]) - if parse_reg_type == "w" then - p[3] = "#-("..p[3]:sub(2)..")%32" - p[4] = "#("..p[4]:sub(2)..")-1" - else - p[3] = "#-("..p[3]:sub(2)..")%64" - p[4] = "#("..p[4]:sub(2)..")-1" - end -end - -local alias_lslimm = op_alias("ubfm_4", function(p) - parse_reg(p[1]) - local sh = p[3]:sub(2) - if parse_reg_type == "w" then - p[3] = "#-("..sh..")%32" - p[4] = "#31-("..sh..")" - else - p[3] = "#-("..sh..")%64" - p[4] = "#63-("..sh..")" - end -end) - --- Template strings for ARM instructions. -map_op = { - -- Basic data processing instructions. - add_3 = "0b000000DNMg|11000000pDpNIg|8b206000pDpNMx", - add_4 = "0b000000DNMSg|0b200000DNMXg|8b200000pDpNMXx|8b200000pDpNxMwX", - adds_3 = "2b000000DNMg|31000000DpNIg|ab206000DpNMx", - adds_4 = "2b000000DNMSg|2b200000DNMXg|ab200000DpNMXx|ab200000DpNxMwX", - cmn_2 = "2b00001fNMg|3100001fpNIg|ab20601fpNMx", - cmn_3 = "2b00001fNMSg|2b20001fNMXg|ab20001fpNMXx|ab20001fpNxMwX", - - sub_3 = "4b000000DNMg|51000000pDpNIg|cb206000pDpNMx", - sub_4 = "4b000000DNMSg|4b200000DNMXg|cb200000pDpNMXx|cb200000pDpNxMwX", - subs_3 = "6b000000DNMg|71000000DpNIg|eb206000DpNMx", - subs_4 = "6b000000DNMSg|6b200000DNMXg|eb200000DpNMXx|eb200000DpNxMwX", - cmp_2 = "6b00001fNMg|7100001fpNIg|eb20601fpNMx", - cmp_3 = "6b00001fNMSg|6b20001fNMXg|eb20001fpNMXx|eb20001fpNxMwX", - - neg_2 = "4b0003e0DMg", - neg_3 = "4b0003e0DMSg", - negs_2 = "6b0003e0DMg", - negs_3 = "6b0003e0DMSg", - - adc_3 = "1a000000DNMg", - adcs_3 = "3a000000DNMg", - sbc_3 = "5a000000DNMg", - sbcs_3 = "7a000000DNMg", - ngc_2 = "5a0003e0DMg", - ngcs_2 = "7a0003e0DMg", - - and_3 = "0a000000DNMg|12000000pDNig", - and_4 = "0a000000DNMSg", - orr_3 = "2a000000DNMg|32000000pDNig", - orr_4 = "2a000000DNMSg", - eor_3 = "4a000000DNMg|52000000pDNig", - eor_4 = "4a000000DNMSg", - ands_3 = "6a000000DNMg|72000000DNig", - ands_4 = "6a000000DNMSg", - tst_2 = "6a00001fNMg|7200001fNig", - tst_3 = "6a00001fNMSg", - - bic_3 = "0a200000DNMg", - bic_4 = "0a200000DNMSg", - orn_3 = "2a200000DNMg", - orn_4 = "2a200000DNMSg", - eon_3 = "4a200000DNMg", - eon_4 = "4a200000DNMSg", - bics_3 = "6a200000DNMg", - bics_4 = "6a200000DNMSg", - - movn_2 = "12800000DWg", - movn_3 = "12800000DWRg", - movz_2 = "52800000DWg", - movz_3 = "52800000DWRg", - movk_2 = "72800000DWg", - movk_3 = "72800000DWRg", - - -- TODO: this doesn't cover all valid immediates for mov reg, #imm. - mov_2 = "2a0003e0DMg|52800000DW|320003e0pDig|11000000pDpNg", - mov_3 = "2a0003e0DMSg", - mvn_2 = "2a2003e0DMg", - mvn_3 = "2a2003e0DMSg", - - adr_2 = "10000000DBx", - adrp_2 = "90000000DBx", - - csel_4 = "1a800000DNMCg", - csinc_4 = "1a800400DNMCg", - csinv_4 = "5a800000DNMCg", - csneg_4 = "5a800400DNMCg", - cset_2 = "1a9f07e0Dcg", - csetm_2 = "5a9f03e0Dcg", - cinc_3 = "1a800400DNmcg", - cinv_3 = "5a800000DNmcg", - cneg_3 = "5a800400DNmcg", - - ccmn_4 = "3a400000NMVCg|3a400800N5VCg", - ccmp_4 = "7a400000NMVCg|7a400800N5VCg", - - madd_4 = "1b000000DNMAg", - msub_4 = "1b008000DNMAg", - mul_3 = "1b007c00DNMg", - mneg_3 = "1b00fc00DNMg", - - smaddl_4 = "9b200000DxNMwAx", - smsubl_4 = "9b208000DxNMwAx", - smull_3 = "9b207c00DxNMw", - smnegl_3 = "9b20fc00DxNMw", - smulh_3 = "9b407c00DNMx", - umaddl_4 = "9ba00000DxNMwAx", - umsubl_4 = "9ba08000DxNMwAx", - umull_3 = "9ba07c00DxNMw", - umnegl_3 = "9ba0fc00DxNMw", - umulh_3 = "9bc07c00DNMx", - - udiv_3 = "1ac00800DNMg", - sdiv_3 = "1ac00c00DNMg", - - -- Bit operations. - sbfm_4 = "13000000DN12w|93400000DN12x", - bfm_4 = "33000000DN12w|b3400000DN12x", - ubfm_4 = "53000000DN12w|d3400000DN12x", - extr_4 = "13800000DNM2w|93c00000DNM2x", - - sxtb_2 = "13001c00DNw|93401c00DNx", - sxth_2 = "13003c00DNw|93403c00DNx", - sxtw_2 = "93407c00DxNw", - uxtb_2 = "53001c00DNw", - uxth_2 = "53003c00DNw", - - sbfx_4 = op_alias("sbfm_4", alias_bfx), - bfxil_4 = op_alias("bfm_4", alias_bfx), - ubfx_4 = op_alias("ubfm_4", alias_bfx), - sbfiz_4 = op_alias("sbfm_4", alias_bfiz), - bfi_4 = op_alias("bfm_4", alias_bfiz), - ubfiz_4 = op_alias("ubfm_4", alias_bfiz), - - lsl_3 = function(params, nparams) - if params and params[3]:byte() == 35 then - return alias_lslimm(params, nparams) - else - return op_template(params, "1ac02000DNMg", nparams) - end - end, - lsr_3 = "1ac02400DNMg|53007c00DN1w|d340fc00DN1x", - asr_3 = "1ac02800DNMg|13007c00DN1w|9340fc00DN1x", - ror_3 = "1ac02c00DNMg|13800000DNm2w|93c00000DNm2x", - - clz_2 = "5ac01000DNg", - cls_2 = "5ac01400DNg", - rbit_2 = "5ac00000DNg", - rev_2 = "5ac00800DNw|dac00c00DNx", - rev16_2 = "5ac00400DNg", - rev32_2 = "dac00800DNx", - - -- Loads and stores. - ["strb_*"] = "38000000DwL", - ["ldrb_*"] = "38400000DwL", - ["ldrsb_*"] = "38c00000DwL|38800000DxL", - ["strh_*"] = "78000000DwL", - ["ldrh_*"] = "78400000DwL", - ["ldrsh_*"] = "78c00000DwL|78800000DxL", - ["str_*"] = "b8000000DwL|f8000000DxL|bc000000DsL|fc000000DdL", - ["ldr_*"] = "18000000DwB|58000000DxB|1c000000DsB|5c000000DdB|b8400000DwL|f8400000DxL|bc400000DsL|fc400000DdL", - ["ldrsw_*"] = "98000000DxB|b8800000DxL", - -- NOTE: ldur etc. are handled by ldr et al. - - ["stp_*"] = "28000000DAwP|a8000000DAxP|2c000000DAsP|6c000000DAdP", - ["ldp_*"] = "28400000DAwP|a8400000DAxP|2c400000DAsP|6c400000DAdP", - ["ldpsw_*"] = "68400000DAxP", - - -- Branches. - b_1 = "14000000B", - bl_1 = "94000000B", - blr_1 = "d63f0000Nx", - br_1 = "d61f0000Nx", - ret_0 = "d65f03c0", - ret_1 = "d65f0000Nx", - -- b.cond is added below. - cbz_2 = "34000000DBg", - cbnz_2 = "35000000DBg", - tbz_3 = "36000000DTBw|36000000DTBx", - tbnz_3 = "37000000DTBw|37000000DTBx", - - -- Miscellaneous instructions. - -- TODO: hlt, hvc, smc, svc, eret, dcps[123], drps, mrs, msr - -- TODO: sys, sysl, ic, dc, at, tlbi - -- TODO: hint, yield, wfe, wfi, sev, sevl - -- TODO: clrex, dsb, dmb, isb - nop_0 = "d503201f", - brk_0 = "d4200000", - brk_1 = "d4200000W", - - -- Floating point instructions. - fmov_2 = "1e204000DNf|1e260000DwNs|1e270000DsNw|9e660000DxNd|9e670000DdNx|1e201000DFf", - fabs_2 = "1e20c000DNf", - fneg_2 = "1e214000DNf", - fsqrt_2 = "1e21c000DNf", - - fcvt_2 = "1e22c000DdNs|1e624000DsNd", - - -- TODO: half-precision and fixed-point conversions. - fcvtas_2 = "1e240000DwNs|9e240000DxNs|1e640000DwNd|9e640000DxNd", - fcvtau_2 = "1e250000DwNs|9e250000DxNs|1e650000DwNd|9e650000DxNd", - fcvtms_2 = "1e300000DwNs|9e300000DxNs|1e700000DwNd|9e700000DxNd", - fcvtmu_2 = "1e310000DwNs|9e310000DxNs|1e710000DwNd|9e710000DxNd", - fcvtns_2 = "1e200000DwNs|9e200000DxNs|1e600000DwNd|9e600000DxNd", - fcvtnu_2 = "1e210000DwNs|9e210000DxNs|1e610000DwNd|9e610000DxNd", - fcvtps_2 = "1e280000DwNs|9e280000DxNs|1e680000DwNd|9e680000DxNd", - fcvtpu_2 = "1e290000DwNs|9e290000DxNs|1e690000DwNd|9e690000DxNd", - fcvtzs_2 = "1e380000DwNs|9e380000DxNs|1e780000DwNd|9e780000DxNd", - fcvtzu_2 = "1e390000DwNs|9e390000DxNs|1e790000DwNd|9e790000DxNd", - - scvtf_2 = "1e220000DsNw|9e220000DsNx|1e620000DdNw|9e620000DdNx", - ucvtf_2 = "1e230000DsNw|9e230000DsNx|1e630000DdNw|9e630000DdNx", - - frintn_2 = "1e244000DNf", - frintp_2 = "1e24c000DNf", - frintm_2 = "1e254000DNf", - frintz_2 = "1e25c000DNf", - frinta_2 = "1e264000DNf", - frintx_2 = "1e274000DNf", - frinti_2 = "1e27c000DNf", - - fadd_3 = "1e202800DNMf", - fsub_3 = "1e203800DNMf", - fmul_3 = "1e200800DNMf", - fnmul_3 = "1e208800DNMf", - fdiv_3 = "1e201800DNMf", - - fmadd_4 = "1f000000DNMAf", - fmsub_4 = "1f008000DNMAf", - fnmadd_4 = "1f200000DNMAf", - fnmsub_4 = "1f208000DNMAf", - - fmax_3 = "1e204800DNMf", - fmaxnm_3 = "1e206800DNMf", - fmin_3 = "1e205800DNMf", - fminnm_3 = "1e207800DNMf", - - fcmp_2 = "1e202000NMf|1e202008NZf", - fcmpe_2 = "1e202010NMf|1e202018NZf", - - fccmp_4 = "1e200400NMVCf", - fccmpe_4 = "1e200410NMVCf", - - fcsel_4 = "1e200c00DNMCf", - - -- TODO: crc32*, aes*, sha*, pmull - -- TODO: SIMD instructions. -} - -for cond,c in pairs(map_cond) do - map_op["b"..cond.."_1"] = tohex(0x54000000+c).."B" -end - ------------------------------------------------------------------------------- - --- Handle opcodes defined with template strings. -local function parse_template(params, template, nparams, pos) - local op = tonumber(sub(template, 1, 8), 16) - local n = 1 - local rtt = {} - - parse_reg_type = false - - -- Process each character. - for p in gmatch(sub(template, 9), ".") do - local q = params[n] - if p == "D" then - op = op + parse_reg(q); n = n + 1 - elseif p == "N" then - op = op + shl(parse_reg(q), 5); n = n + 1 - elseif p == "M" then - op = op + shl(parse_reg(q), 16); n = n + 1 - elseif p == "A" then - op = op + shl(parse_reg(q), 10); n = n + 1 - elseif p == "m" then - op = op + shl(parse_reg(params[n-1]), 16) - - elseif p == "p" then - if q == "sp" then params[n] = "@x31" end - elseif p == "g" then - if parse_reg_type == "x" then - op = op + 0x80000000 - elseif parse_reg_type ~= "w" then - werror("bad register type") - end - parse_reg_type = false - elseif p == "f" then - if parse_reg_type == "d" then - op = op + 0x00400000 - elseif parse_reg_type ~= "s" then - werror("bad register type") - end - parse_reg_type = false - elseif p == "x" or p == "w" or p == "d" or p == "s" then - if parse_reg_type ~= p then - werror("register size mismatch") - end - parse_reg_type = false - - elseif p == "L" then - op = parse_load(params, nparams, n, op) - elseif p == "P" then - op = parse_load_pair(params, nparams, n, op) - - elseif p == "B" then - local mode, v, s = parse_label(q, false); n = n + 1 - local m = branch_type(op) - waction("REL_"..mode, v+m, s, 1) - - elseif p == "I" then - op = op + parse_imm12(q); n = n + 1 - elseif p == "i" then - op = op + parse_imm13(q); n = n + 1 - elseif p == "W" then - op = op + parse_imm(q, 16, 5, 0, false); n = n + 1 - elseif p == "T" then - op = op + parse_imm6(q); n = n + 1 - elseif p == "1" then - op = op + parse_imm(q, 6, 16, 0, false); n = n + 1 - elseif p == "2" then - op = op + parse_imm(q, 6, 10, 0, false); n = n + 1 - elseif p == "5" then - op = op + parse_imm(q, 5, 16, 0, false); n = n + 1 - elseif p == "V" then - op = op + parse_imm(q, 4, 0, 0, false); n = n + 1 - elseif p == "F" then - op = op + parse_fpimm(q); n = n + 1 - elseif p == "Z" then - if q ~= "#0" and q ~= "#0.0" then werror("expected zero immediate") end - n = n + 1 - - elseif p == "S" then - op = op + parse_shift(q); n = n + 1 - elseif p == "X" then - op = op + parse_extend(q); n = n + 1 - elseif p == "R" then - op = op + parse_lslx16(q); n = n + 1 - elseif p == "C" then - op = op + parse_cond(q, 0); n = n + 1 - elseif p == "c" then - op = op + parse_cond(q, 1); n = n + 1 - - else - assert(false) - end - end - wputpos(pos, op) -end - -function op_template(params, template, nparams) - if not params then return template:gsub("%x%x%x%x%x%x%x%x", "") end - - -- Limit number of section buffer positions used by a single dasm_put(). - -- A single opcode needs a maximum of 3 positions. - if secpos+3 > maxsecpos then wflush() end - local pos = wpos() - local lpos, apos, spos = #actlist, #actargs, secpos - - local ok, err - for t in gmatch(template, "[^|]+") do - ok, err = pcall(parse_template, params, t, nparams, pos) - if ok then return end - secpos = spos - actlist[lpos+1] = nil - actlist[lpos+2] = nil - actlist[lpos+3] = nil - actargs[apos+1] = nil - actargs[apos+2] = nil - actargs[apos+3] = nil - end - error(err, 0) -end - -map_op[".template__"] = op_template - ------------------------------------------------------------------------------- - --- Pseudo-opcode to mark the position where the action list is to be emitted. -map_op[".actionlist_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeactions(out, name) end) -end - --- Pseudo-opcode to mark the position where the global enum is to be emitted. -map_op[".globals_1"] = function(params) - if not params then return "prefix" end - local prefix = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeglobals(out, prefix) end) -end - --- Pseudo-opcode to mark the position where the global names are to be emitted. -map_op[".globalnames_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeglobalnames(out, name) end) -end - --- Pseudo-opcode to mark the position where the extern names are to be emitted. -map_op[".externnames_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeexternnames(out, name) end) -end - ------------------------------------------------------------------------------- - --- Label pseudo-opcode (converted from trailing colon form). -map_op[".label_1"] = function(params) - if not params then return "[1-9] | ->global | =>pcexpr" end - if secpos+1 > maxsecpos then wflush() end - local mode, n, s = parse_label(params[1], true) - if mode == "EXT" then werror("bad label definition") end - waction("LABEL_"..mode, n, s, 1) -end - ------------------------------------------------------------------------------- - --- Pseudo-opcodes for data storage. -map_op[".long_*"] = function(params) - if not params then return "imm..." end - for _,p in ipairs(params) do - local n = tonumber(p) - if not n then werror("bad immediate `"..p.."'") end - if n < 0 then n = n + 2^32 end - wputw(n) - if secpos+2 > maxsecpos then wflush() end - end -end - --- Alignment pseudo-opcode. -map_op[".align_1"] = function(params) - if not params then return "numpow2" end - if secpos+1 > maxsecpos then wflush() end - local align = tonumber(params[1]) - if align then - local x = align - -- Must be a power of 2 in the range (2 ... 256). - for i=1,8 do - x = x / 2 - if x == 1 then - waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. - return - end - end - end - werror("bad alignment") -end - ------------------------------------------------------------------------------- - --- Pseudo-opcode for (primitive) type definitions (map to C types). -map_op[".type_3"] = function(params, nparams) - if not params then - return nparams == 2 and "name, ctype" or "name, ctype, reg" - end - local name, ctype, reg = params[1], params[2], params[3] - if not match(name, "^[%a_][%w_]*$") then - werror("bad type name `"..name.."'") - end - local tp = map_type[name] - if tp then - werror("duplicate type `"..name.."'") - end - -- Add #type to defines. A bit unclean to put it in map_archdef. - map_archdef["#"..name] = "sizeof("..ctype..")" - -- Add new type and emit shortcut define. - local num = ctypenum + 1 - map_type[name] = { - ctype = ctype, - ctypefmt = format("Dt%X(%%s)", num), - reg = reg, - } - wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) - ctypenum = num -end -map_op[".type_2"] = map_op[".type_3"] - --- Dump type definitions. -local function dumptypes(out, lvl) - local t = {} - for name in pairs(map_type) do t[#t+1] = name end - sort(t) - out:write("Type definitions:\n") - for _,name in ipairs(t) do - local tp = map_type[name] - local reg = tp.reg or "" - out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) - end - out:write("\n") -end - ------------------------------------------------------------------------------- - --- Set the current section. -function _M.section(num) - waction("SECTION", num) - wflush(true) -- SECTION is a terminal action. -end - ------------------------------------------------------------------------------- - --- Dump architecture description. -function _M.dumparch(out) - out:write(format("DynASM %s version %s, released %s\n\n", - _info.arch, _info.version, _info.release)) - dumpactions(out) -end - --- Dump all user defined elements. -function _M.dumpdef(out, lvl) - dumptypes(out, lvl) - dumpglobals(out, lvl) - dumpexterns(out, lvl) -end - ------------------------------------------------------------------------------- - --- Pass callbacks from/to the DynASM core. -function _M.passcb(wl, we, wf, ww) - wline, werror, wfatal, wwarn = wl, we, wf, ww - return wflush -end - --- Setup the arch-specific module. -function _M.setup(arch, opt) - g_arch, g_opt = arch, opt -end - --- Merge the core maps and the arch-specific maps. -function _M.mergemaps(map_coreop, map_def) - setmetatable(map_op, { __index = map_coreop }) - setmetatable(map_def, { __index = map_archdef }) - return map_op, map_def -end - -return _M - ------------------------------------------------------------------------------- - diff --git a/lib/LuaJIT/dynasm/dasm_mips.h b/lib/LuaJIT/dynasm/dasm_mips.h deleted file mode 100644 index 71a835b..0000000 --- a/lib/LuaJIT/dynasm/dasm_mips.h +++ /dev/null @@ -1,420 +0,0 @@ -/* -** DynASM MIPS encoding engine. -** Copyright (C) 2005-2017 Mike Pall. All rights reserved. -** Released under the MIT license. See dynasm.lua for full copyright notice. -*/ - -#include -#include -#include -#include - -#define DASM_ARCH "mips" - -#ifndef DASM_EXTERN -#define DASM_EXTERN(a,b,c,d) 0 -#endif - -/* Action definitions. */ -enum { - DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, - /* The following actions need a buffer position. */ - DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, - /* The following actions also have an argument. */ - DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, DASM_IMMS, - DASM__MAX -}; - -/* Maximum number of section buffer positions for a single dasm_put() call. */ -#define DASM_MAXSECPOS 25 - -/* DynASM encoder status codes. Action list offset or number are or'ed in. */ -#define DASM_S_OK 0x00000000 -#define DASM_S_NOMEM 0x01000000 -#define DASM_S_PHASE 0x02000000 -#define DASM_S_MATCH_SEC 0x03000000 -#define DASM_S_RANGE_I 0x11000000 -#define DASM_S_RANGE_SEC 0x12000000 -#define DASM_S_RANGE_LG 0x13000000 -#define DASM_S_RANGE_PC 0x14000000 -#define DASM_S_RANGE_REL 0x15000000 -#define DASM_S_UNDEF_LG 0x21000000 -#define DASM_S_UNDEF_PC 0x22000000 - -/* Macros to convert positions (8 bit section + 24 bit index). */ -#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) -#define DASM_POS2BIAS(pos) ((pos)&0xff000000) -#define DASM_SEC2POS(sec) ((sec)<<24) -#define DASM_POS2SEC(pos) ((pos)>>24) -#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) - -/* Action list type. */ -typedef const unsigned int *dasm_ActList; - -/* Per-section structure. */ -typedef struct dasm_Section { - int *rbuf; /* Biased buffer pointer (negative section bias). */ - int *buf; /* True buffer pointer. */ - size_t bsize; /* Buffer size in bytes. */ - int pos; /* Biased buffer position. */ - int epos; /* End of biased buffer position - max single put. */ - int ofs; /* Byte offset into section. */ -} dasm_Section; - -/* Core structure holding the DynASM encoding state. */ -struct dasm_State { - size_t psize; /* Allocated size of this structure. */ - dasm_ActList actionlist; /* Current actionlist pointer. */ - int *lglabels; /* Local/global chain/pos ptrs. */ - size_t lgsize; - int *pclabels; /* PC label chains/pos ptrs. */ - size_t pcsize; - void **globals; /* Array of globals (bias -10). */ - dasm_Section *section; /* Pointer to active section. */ - size_t codesize; /* Total size of all code sections. */ - int maxsection; /* 0 <= sectionidx < maxsection. */ - int status; /* Status code. */ - dasm_Section sections[1]; /* All sections. Alloc-extended. */ -}; - -/* The size of the core structure depends on the max. number of sections. */ -#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) - - -/* Initialize DynASM state. */ -void dasm_init(Dst_DECL, int maxsection) -{ - dasm_State *D; - size_t psz = 0; - int i; - Dst_REF = NULL; - DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); - D = Dst_REF; - D->psize = psz; - D->lglabels = NULL; - D->lgsize = 0; - D->pclabels = NULL; - D->pcsize = 0; - D->globals = NULL; - D->maxsection = maxsection; - for (i = 0; i < maxsection; i++) { - D->sections[i].buf = NULL; /* Need this for pass3. */ - D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); - D->sections[i].bsize = 0; - D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ - } -} - -/* Free DynASM state. */ -void dasm_free(Dst_DECL) -{ - dasm_State *D = Dst_REF; - int i; - for (i = 0; i < D->maxsection; i++) - if (D->sections[i].buf) - DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); - if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); - if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); - DASM_M_FREE(Dst, D, D->psize); -} - -/* Setup global label array. Must be called before dasm_setup(). */ -void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) -{ - dasm_State *D = Dst_REF; - D->globals = gl - 10; /* Negative bias to compensate for locals. */ - DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); -} - -/* Grow PC label array. Can be called after dasm_setup(), too. */ -void dasm_growpc(Dst_DECL, unsigned int maxpc) -{ - dasm_State *D = Dst_REF; - size_t osz = D->pcsize; - DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); - memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); -} - -/* Setup encoder. */ -void dasm_setup(Dst_DECL, const void *actionlist) -{ - dasm_State *D = Dst_REF; - int i; - D->actionlist = (dasm_ActList)actionlist; - D->status = DASM_S_OK; - D->section = &D->sections[0]; - memset((void *)D->lglabels, 0, D->lgsize); - if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); - for (i = 0; i < D->maxsection; i++) { - D->sections[i].pos = DASM_SEC2POS(i); - D->sections[i].ofs = 0; - } -} - - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) { \ - D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) -#define CKPL(kind, st) \ - do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ - D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) -#else -#define CK(x, st) ((void)0) -#define CKPL(kind, st) ((void)0) -#endif - -/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ -void dasm_put(Dst_DECL, int start, ...) -{ - va_list ap; - dasm_State *D = Dst_REF; - dasm_ActList p = D->actionlist + start; - dasm_Section *sec = D->section; - int pos = sec->pos, ofs = sec->ofs; - int *b; - - if (pos >= sec->epos) { - DASM_M_GROW(Dst, int, sec->buf, sec->bsize, - sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); - sec->rbuf = sec->buf - DASM_POS2BIAS(pos); - sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); - } - - b = sec->rbuf; - b[pos++] = start; - - va_start(ap, start); - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16) - 0xff00; - if (action >= DASM__MAX) { - ofs += 4; - } else { - int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; - switch (action) { - case DASM_STOP: goto stop; - case DASM_SECTION: - n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); - D->section = &D->sections[n]; goto stop; - case DASM_ESC: p++; ofs += 4; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; - case DASM_REL_LG: - n = (ins & 2047) - 10; pl = D->lglabels + n; - /* Bkwd rel or global. */ - if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } - pl += 10; n = *pl; - if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ - goto linkrel; - case DASM_REL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putrel: - n = *pl; - if (n < 0) { /* Label exists. Get label pos and store it. */ - b[pos] = -n; - } else { - linkrel: - b[pos] = n; /* Else link to rel chain, anchored at label. */ - *pl = pos; - } - pos++; - break; - case DASM_LABEL_LG: - pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; - case DASM_LABEL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putlabel: - n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; - } - *pl = -pos; /* Label exists now. */ - b[pos++] = ofs; /* Store pass1 offset estimate. */ - break; - case DASM_IMM: case DASM_IMMS: -#ifdef DASM_CHECKS - CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); -#endif - n >>= ((ins>>10)&31); -#ifdef DASM_CHECKS - if (ins & 0x8000) - CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); - else - CK((n>>((ins>>5)&31)) == 0, RANGE_I); -#endif - b[pos++] = n; - break; - } - } - } -stop: - va_end(ap); - sec->pos = pos; - sec->ofs = ofs; -} -#undef CK - -/* Pass 2: Link sections, shrink aligns, fix label offsets. */ -int dasm_link(Dst_DECL, size_t *szp) -{ - dasm_State *D = Dst_REF; - int secnum; - int ofs = 0; - -#ifdef DASM_CHECKS - *szp = 0; - if (D->status != DASM_S_OK) return D->status; - { - int pc; - for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) - if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; - } -#endif - - { /* Handle globals not defined in this translation unit. */ - int idx; - for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { - int n = D->lglabels[idx]; - /* Undefined label: Collapse rel chain and replace with marker (< 0). */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } - } - } - - /* Combine all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->rbuf; - int pos = DASM_SEC2POS(secnum); - int lastpos = sec->pos; - - while (pos != lastpos) { - dasm_ActList p = D->actionlist + b[pos++]; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16) - 0xff00; - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: p++; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; - case DASM_REL_LG: case DASM_REL_PC: pos++; break; - case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; - case DASM_IMM: case DASM_IMMS: pos++; break; - } - } - stop: (void)0; - } - ofs += sec->ofs; /* Next section starts right after current section. */ - } - - D->codesize = ofs; /* Total size of all code sections */ - *szp = ofs; - return DASM_S_OK; -} - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) -#else -#define CK(x, st) ((void)0) -#endif - -/* Pass 3: Encode sections. */ -int dasm_encode(Dst_DECL, void *buffer) -{ - dasm_State *D = Dst_REF; - char *base = (char *)buffer; - unsigned int *cp = (unsigned int *)buffer; - int secnum; - - /* Encode all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->buf; - int *endb = sec->rbuf + sec->pos; - - while (b != endb) { - dasm_ActList p = D->actionlist + *b++; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16) - 0xff00; - int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: *cp++ = *p++; break; - case DASM_REL_EXT: - n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1); - goto patchrel; - case DASM_ALIGN: - ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000; - break; - case DASM_REL_LG: - CK(n >= 0, UNDEF_LG); - /* fallthrough */ - case DASM_REL_PC: - CK(n >= 0, UNDEF_PC); - n = *DASM_POS2PTR(D, n); - if (ins & 2048) - n = n - (int)((char *)cp - base); - else - n = (n + (int)(size_t)base) & 0x0fffffff; - patchrel: - CK((n & 3) == 0 && - ((n + ((ins & 2048) ? 0x00020000 : 0)) >> - ((ins & 2048) ? 18 : 28)) == 0, RANGE_REL); - cp[-1] |= ((n>>2) & ((ins & 2048) ? 0x0000ffff: 0x03ffffff)); - break; - case DASM_LABEL_LG: - ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); - break; - case DASM_LABEL_PC: break; - case DASM_IMMS: - cp[-1] |= ((n>>3) & 4); n &= 0x1f; - /* fallthrough */ - case DASM_IMM: - cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); - break; - default: *cp++ = ins; break; - } - } - stop: (void)0; - } - } - - if (base + D->codesize != (char *)cp) /* Check for phase errors. */ - return DASM_S_PHASE; - return DASM_S_OK; -} -#undef CK - -/* Get PC label offset. */ -int dasm_getpclabel(Dst_DECL, unsigned int pc) -{ - dasm_State *D = Dst_REF; - if (pc*sizeof(int) < D->pcsize) { - int pos = D->pclabels[pc]; - if (pos < 0) return *DASM_POS2PTR(D, -pos); - if (pos > 0) return -1; /* Undefined. */ - } - return -2; /* Unused or out of range. */ -} - -#ifdef DASM_CHECKS -/* Optional sanity checker to call between isolated encoding steps. */ -int dasm_checkstep(Dst_DECL, int secmatch) -{ - dasm_State *D = Dst_REF; - if (D->status == DASM_S_OK) { - int i; - for (i = 1; i <= 9; i++) { - if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } - D->lglabels[i] = 0; - } - } - if (D->status == DASM_S_OK && secmatch >= 0 && - D->section != &D->sections[secmatch]) - D->status = DASM_S_MATCH_SEC|(D->section-D->sections); - return D->status; -} -#endif - diff --git a/lib/LuaJIT/dynasm/dasm_mips.lua b/lib/LuaJIT/dynasm/dasm_mips.lua deleted file mode 100644 index bd2a2b4..0000000 --- a/lib/LuaJIT/dynasm/dasm_mips.lua +++ /dev/null @@ -1,1008 +0,0 @@ ------------------------------------------------------------------------------- --- DynASM MIPS32/MIPS64 module. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------- - -local mips64 = mips64 - --- Module information: -local _info = { - arch = mips64 and "mips64" or "mips", - description = "DynASM MIPS32/MIPS64 module", - version = "1.4.0", - vernum = 10400, - release = "2016-05-24", - author = "Mike Pall", - license = "MIT", -} - --- Exported glue functions for the arch-specific module. -local _M = { _info = _info } - --- Cache library functions. -local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs -local assert, setmetatable = assert, setmetatable -local _s = string -local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char -local match, gmatch = _s.match, _s.gmatch -local concat, sort = table.concat, table.sort -local bit = bit or require("bit") -local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift -local tohex = bit.tohex - --- Inherited tables and callbacks. -local g_opt, g_arch -local wline, werror, wfatal, wwarn - --- Action name list. --- CHECK: Keep this in sync with the C code! -local action_names = { - "STOP", "SECTION", "ESC", "REL_EXT", - "ALIGN", "REL_LG", "LABEL_LG", - "REL_PC", "LABEL_PC", "IMM", "IMMS", -} - --- Maximum number of section buffer positions for dasm_put(). --- CHECK: Keep this in sync with the C code! -local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. - --- Action name -> action number. -local map_action = {} -for n,name in ipairs(action_names) do - map_action[name] = n-1 -end - --- Action list buffer. -local actlist = {} - --- Argument list for next dasm_put(). Start with offset 0 into action list. -local actargs = { 0 } - --- Current number of section buffer positions for dasm_put(). -local secpos = 1 - ------------------------------------------------------------------------------- - --- Dump action names and numbers. -local function dumpactions(out) - out:write("DynASM encoding engine action codes:\n") - for n,name in ipairs(action_names) do - local num = map_action[name] - out:write(format(" %-10s %02X %d\n", name, num, num)) - end - out:write("\n") -end - --- Write action list buffer as a huge static C array. -local function writeactions(out, name) - local nn = #actlist - if nn == 0 then nn = 1; actlist[0] = map_action.STOP end - out:write("static const unsigned int ", name, "[", nn, "] = {\n") - for i = 1,nn-1 do - assert(out:write("0x", tohex(actlist[i]), ",\n")) - end - assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) -end - ------------------------------------------------------------------------------- - --- Add word to action list. -local function wputxw(n) - assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") - actlist[#actlist+1] = n -end - --- Add action to list with optional arg. Advance buffer pos, too. -local function waction(action, val, a, num) - local w = assert(map_action[action], "bad action name `"..action.."'") - wputxw(0xff000000 + w * 0x10000 + (val or 0)) - if a then actargs[#actargs+1] = a end - if a or num then secpos = secpos + (num or 1) end -end - --- Flush action list (intervening C code or buffer pos overflow). -local function wflush(term) - if #actlist == actargs[1] then return end -- Nothing to flush. - if not term then waction("STOP") end -- Terminate action list. - wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) - actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). - secpos = 1 -- The actionlist offset occupies a buffer position, too. -end - --- Put escaped word. -local function wputw(n) - if n >= 0xff000000 then waction("ESC") end - wputxw(n) -end - --- Reserve position for word. -local function wpos() - local pos = #actlist+1 - actlist[pos] = "" - return pos -end - --- Store word to reserved position. -local function wputpos(pos, n) - assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") - actlist[pos] = n -end - ------------------------------------------------------------------------------- - --- Global label name -> global label number. With auto assignment on 1st use. -local next_global = 20 -local map_global = setmetatable({}, { __index = function(t, name) - if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end - local n = next_global - if n > 2047 then werror("too many global labels") end - next_global = n + 1 - t[name] = n - return n -end}) - --- Dump global labels. -local function dumpglobals(out, lvl) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("Global labels:\n") - for i=20,next_global-1 do - out:write(format(" %s\n", t[i])) - end - out:write("\n") -end - --- Write global label enum. -local function writeglobals(out, prefix) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("enum {\n") - for i=20,next_global-1 do - out:write(" ", prefix, t[i], ",\n") - end - out:write(" ", prefix, "_MAX\n};\n") -end - --- Write global label names. -local function writeglobalnames(out, name) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("static const char *const ", name, "[] = {\n") - for i=20,next_global-1 do - out:write(" \"", t[i], "\",\n") - end - out:write(" (const char *)0\n};\n") -end - ------------------------------------------------------------------------------- - --- Extern label name -> extern label number. With auto assignment on 1st use. -local next_extern = 0 -local map_extern_ = {} -local map_extern = setmetatable({}, { __index = function(t, name) - -- No restrictions on the name for now. - local n = next_extern - if n > 2047 then werror("too many extern labels") end - next_extern = n + 1 - t[name] = n - map_extern_[n] = name - return n -end}) - --- Dump extern labels. -local function dumpexterns(out, lvl) - out:write("Extern labels:\n") - for i=0,next_extern-1 do - out:write(format(" %s\n", map_extern_[i])) - end - out:write("\n") -end - --- Write extern label names. -local function writeexternnames(out, name) - out:write("static const char *const ", name, "[] = {\n") - for i=0,next_extern-1 do - out:write(" \"", map_extern_[i], "\",\n") - end - out:write(" (const char *)0\n};\n") -end - ------------------------------------------------------------------------------- - --- Arch-specific maps. -local map_archdef = { sp="r29", ra="r31" } -- Ext. register name -> int. name. - -local map_type = {} -- Type name -> { ctype, reg } -local ctypenum = 0 -- Type number (for Dt... macros). - --- Reverse defines for registers. -function _M.revdef(s) - if s == "r29" then return "sp" - elseif s == "r31" then return "ra" end - return s -end - ------------------------------------------------------------------------------- - --- Template strings for MIPS instructions. -local map_op = { - -- First-level opcodes. - j_1 = "08000000J", - jal_1 = "0c000000J", - b_1 = "10000000B", - beqz_2 = "10000000SB", - beq_3 = "10000000STB", - bnez_2 = "14000000SB", - bne_3 = "14000000STB", - blez_2 = "18000000SB", - bgtz_2 = "1c000000SB", - addi_3 = "20000000TSI", - li_2 = "24000000TI", - addiu_3 = "24000000TSI", - slti_3 = "28000000TSI", - sltiu_3 = "2c000000TSI", - andi_3 = "30000000TSU", - lu_2 = "34000000TU", - ori_3 = "34000000TSU", - xori_3 = "38000000TSU", - lui_2 = "3c000000TU", - beqzl_2 = "50000000SB", - beql_3 = "50000000STB", - bnezl_2 = "54000000SB", - bnel_3 = "54000000STB", - blezl_2 = "58000000SB", - bgtzl_2 = "5c000000SB", - daddi_3 = mips64 and "60000000TSI", - daddiu_3 = mips64 and "64000000TSI", - ldl_2 = mips64 and "68000000TO", - ldr_2 = mips64 and "6c000000TO", - lb_2 = "80000000TO", - lh_2 = "84000000TO", - lwl_2 = "88000000TO", - lw_2 = "8c000000TO", - lbu_2 = "90000000TO", - lhu_2 = "94000000TO", - lwr_2 = "98000000TO", - lwu_2 = mips64 and "9c000000TO", - sb_2 = "a0000000TO", - sh_2 = "a4000000TO", - swl_2 = "a8000000TO", - sw_2 = "ac000000TO", - sdl_2 = mips64 and "b0000000TO", - sdr_2 = mips64 and "b1000000TO", - swr_2 = "b8000000TO", - cache_2 = "bc000000NO", - ll_2 = "c0000000TO", - lwc1_2 = "c4000000HO", - pref_2 = "cc000000NO", - ldc1_2 = "d4000000HO", - ld_2 = mips64 and "dc000000TO", - sc_2 = "e0000000TO", - swc1_2 = "e4000000HO", - scd_2 = mips64 and "f0000000TO", - sdc1_2 = "f4000000HO", - sd_2 = mips64 and "fc000000TO", - - -- Opcode SPECIAL. - nop_0 = "00000000", - sll_3 = "00000000DTA", - sextw_2 = "00000000DT", - movf_2 = "00000001DS", - movf_3 = "00000001DSC", - movt_2 = "00010001DS", - movt_3 = "00010001DSC", - srl_3 = "00000002DTA", - rotr_3 = "00200002DTA", - sra_3 = "00000003DTA", - sllv_3 = "00000004DTS", - srlv_3 = "00000006DTS", - rotrv_3 = "00000046DTS", - drotrv_3 = mips64 and "00000056DTS", - srav_3 = "00000007DTS", - jr_1 = "00000008S", - jalr_1 = "0000f809S", - jalr_2 = "00000009DS", - movz_3 = "0000000aDST", - movn_3 = "0000000bDST", - syscall_0 = "0000000c", - syscall_1 = "0000000cY", - break_0 = "0000000d", - break_1 = "0000000dY", - sync_0 = "0000000f", - mfhi_1 = "00000010D", - mthi_1 = "00000011S", - mflo_1 = "00000012D", - mtlo_1 = "00000013S", - dsllv_3 = mips64 and "00000014DTS", - dsrlv_3 = mips64 and "00000016DTS", - dsrav_3 = mips64 and "00000017DTS", - mult_2 = "00000018ST", - multu_2 = "00000019ST", - div_2 = "0000001aST", - divu_2 = "0000001bST", - dmult_2 = mips64 and "0000001cST", - dmultu_2 = mips64 and "0000001dST", - ddiv_2 = mips64 and "0000001eST", - ddivu_2 = mips64 and "0000001fST", - add_3 = "00000020DST", - move_2 = mips64 and "00000025DS" or "00000021DS", - addu_3 = "00000021DST", - sub_3 = "00000022DST", - negu_2 = mips64 and "0000002fDT" or "00000023DT", - subu_3 = "00000023DST", - and_3 = "00000024DST", - or_3 = "00000025DST", - xor_3 = "00000026DST", - not_2 = "00000027DS", - nor_3 = "00000027DST", - slt_3 = "0000002aDST", - sltu_3 = "0000002bDST", - dadd_3 = mips64 and "0000002cDST", - daddu_3 = mips64 and "0000002dDST", - dsub_3 = mips64 and "0000002eDST", - dsubu_3 = mips64 and "0000002fDST", - tge_2 = "00000030ST", - tge_3 = "00000030STZ", - tgeu_2 = "00000031ST", - tgeu_3 = "00000031STZ", - tlt_2 = "00000032ST", - tlt_3 = "00000032STZ", - tltu_2 = "00000033ST", - tltu_3 = "00000033STZ", - teq_2 = "00000034ST", - teq_3 = "00000034STZ", - tne_2 = "00000036ST", - tne_3 = "00000036STZ", - dsll_3 = mips64 and "00000038DTa", - dsrl_3 = mips64 and "0000003aDTa", - drotr_3 = mips64 and "0020003aDTa", - dsra_3 = mips64 and "0000003bDTa", - dsll32_3 = mips64 and "0000003cDTA", - dsrl32_3 = mips64 and "0000003eDTA", - drotr32_3 = mips64 and "0020003eDTA", - dsra32_3 = mips64 and "0000003fDTA", - - -- Opcode REGIMM. - bltz_2 = "04000000SB", - bgez_2 = "04010000SB", - bltzl_2 = "04020000SB", - bgezl_2 = "04030000SB", - tgei_2 = "04080000SI", - tgeiu_2 = "04090000SI", - tlti_2 = "040a0000SI", - tltiu_2 = "040b0000SI", - teqi_2 = "040c0000SI", - tnei_2 = "040e0000SI", - bltzal_2 = "04100000SB", - bal_1 = "04110000B", - bgezal_2 = "04110000SB", - bltzall_2 = "04120000SB", - bgezall_2 = "04130000SB", - synci_1 = "041f0000O", - - -- Opcode SPECIAL2. - madd_2 = "70000000ST", - maddu_2 = "70000001ST", - mul_3 = "70000002DST", - msub_2 = "70000004ST", - msubu_2 = "70000005ST", - clz_2 = "70000020DS=", - clo_2 = "70000021DS=", - dclz_2 = mips64 and "70000024DS=", - dclo_2 = mips64 and "70000025DS=", - sdbbp_0 = "7000003f", - sdbbp_1 = "7000003fY", - - -- Opcode SPECIAL3. - ext_4 = "7c000000TSAM", -- Note: last arg is msbd = size-1 - dextm_4 = mips64 and "7c000001TSAM", -- Args: pos | size-1-32 - dextu_4 = mips64 and "7c000002TSAM", -- Args: pos-32 | size-1 - dext_4 = mips64 and "7c000003TSAM", -- Args: pos | size-1 - zextw_2 = mips64 and "7c00f803TS", - ins_4 = "7c000004TSAM", -- Note: last arg is msb = pos+size-1 - dinsm_4 = mips64 and "7c000005TSAM", -- Args: pos | pos+size-33 - dinsu_4 = mips64 and "7c000006TSAM", -- Args: pos-32 | pos+size-33 - dins_4 = mips64 and "7c000007TSAM", -- Args: pos | pos+size-1 - wsbh_2 = "7c0000a0DT", - dsbh_2 = mips64 and "7c0000a4DT", - dshd_2 = mips64 and "7c000164DT", - seb_2 = "7c000420DT", - seh_2 = "7c000620DT", - rdhwr_2 = "7c00003bTD", - - -- Opcode COP0. - mfc0_2 = "40000000TD", - mfc0_3 = "40000000TDW", - dmfc0_2 = mips64 and "40200000TD", - dmfc0_3 = mips64 and "40200000TDW", - mtc0_2 = "40800000TD", - mtc0_3 = "40800000TDW", - dmtc0_2 = mips64 and "40a00000TD", - dmtc0_3 = mips64 and "40a00000TDW", - rdpgpr_2 = "41400000DT", - di_0 = "41606000", - di_1 = "41606000T", - ei_0 = "41606020", - ei_1 = "41606020T", - wrpgpr_2 = "41c00000DT", - tlbr_0 = "42000001", - tlbwi_0 = "42000002", - tlbwr_0 = "42000006", - tlbp_0 = "42000008", - eret_0 = "42000018", - deret_0 = "4200001f", - wait_0 = "42000020", - - -- Opcode COP1. - mfc1_2 = "44000000TG", - dmfc1_2 = mips64 and "44200000TG", - cfc1_2 = "44400000TG", - mfhc1_2 = "44600000TG", - mtc1_2 = "44800000TG", - dmtc1_2 = mips64 and "44a00000TG", - ctc1_2 = "44c00000TG", - mthc1_2 = "44e00000TG", - - bc1f_1 = "45000000B", - bc1f_2 = "45000000CB", - bc1t_1 = "45010000B", - bc1t_2 = "45010000CB", - bc1fl_1 = "45020000B", - bc1fl_2 = "45020000CB", - bc1tl_1 = "45030000B", - bc1tl_2 = "45030000CB", - - ["add.s_3"] = "46000000FGH", - ["sub.s_3"] = "46000001FGH", - ["mul.s_3"] = "46000002FGH", - ["div.s_3"] = "46000003FGH", - ["sqrt.s_2"] = "46000004FG", - ["abs.s_2"] = "46000005FG", - ["mov.s_2"] = "46000006FG", - ["neg.s_2"] = "46000007FG", - ["round.l.s_2"] = "46000008FG", - ["trunc.l.s_2"] = "46000009FG", - ["ceil.l.s_2"] = "4600000aFG", - ["floor.l.s_2"] = "4600000bFG", - ["round.w.s_2"] = "4600000cFG", - ["trunc.w.s_2"] = "4600000dFG", - ["ceil.w.s_2"] = "4600000eFG", - ["floor.w.s_2"] = "4600000fFG", - ["movf.s_2"] = "46000011FG", - ["movf.s_3"] = "46000011FGC", - ["movt.s_2"] = "46010011FG", - ["movt.s_3"] = "46010011FGC", - ["movz.s_3"] = "46000012FGT", - ["movn.s_3"] = "46000013FGT", - ["recip.s_2"] = "46000015FG", - ["rsqrt.s_2"] = "46000016FG", - ["cvt.d.s_2"] = "46000021FG", - ["cvt.w.s_2"] = "46000024FG", - ["cvt.l.s_2"] = "46000025FG", - ["cvt.ps.s_3"] = "46000026FGH", - ["c.f.s_2"] = "46000030GH", - ["c.f.s_3"] = "46000030VGH", - ["c.un.s_2"] = "46000031GH", - ["c.un.s_3"] = "46000031VGH", - ["c.eq.s_2"] = "46000032GH", - ["c.eq.s_3"] = "46000032VGH", - ["c.ueq.s_2"] = "46000033GH", - ["c.ueq.s_3"] = "46000033VGH", - ["c.olt.s_2"] = "46000034GH", - ["c.olt.s_3"] = "46000034VGH", - ["c.ult.s_2"] = "46000035GH", - ["c.ult.s_3"] = "46000035VGH", - ["c.ole.s_2"] = "46000036GH", - ["c.ole.s_3"] = "46000036VGH", - ["c.ule.s_2"] = "46000037GH", - ["c.ule.s_3"] = "46000037VGH", - ["c.sf.s_2"] = "46000038GH", - ["c.sf.s_3"] = "46000038VGH", - ["c.ngle.s_2"] = "46000039GH", - ["c.ngle.s_3"] = "46000039VGH", - ["c.seq.s_2"] = "4600003aGH", - ["c.seq.s_3"] = "4600003aVGH", - ["c.ngl.s_2"] = "4600003bGH", - ["c.ngl.s_3"] = "4600003bVGH", - ["c.lt.s_2"] = "4600003cGH", - ["c.lt.s_3"] = "4600003cVGH", - ["c.nge.s_2"] = "4600003dGH", - ["c.nge.s_3"] = "4600003dVGH", - ["c.le.s_2"] = "4600003eGH", - ["c.le.s_3"] = "4600003eVGH", - ["c.ngt.s_2"] = "4600003fGH", - ["c.ngt.s_3"] = "4600003fVGH", - - ["add.d_3"] = "46200000FGH", - ["sub.d_3"] = "46200001FGH", - ["mul.d_3"] = "46200002FGH", - ["div.d_3"] = "46200003FGH", - ["sqrt.d_2"] = "46200004FG", - ["abs.d_2"] = "46200005FG", - ["mov.d_2"] = "46200006FG", - ["neg.d_2"] = "46200007FG", - ["round.l.d_2"] = "46200008FG", - ["trunc.l.d_2"] = "46200009FG", - ["ceil.l.d_2"] = "4620000aFG", - ["floor.l.d_2"] = "4620000bFG", - ["round.w.d_2"] = "4620000cFG", - ["trunc.w.d_2"] = "4620000dFG", - ["ceil.w.d_2"] = "4620000eFG", - ["floor.w.d_2"] = "4620000fFG", - ["movf.d_2"] = "46200011FG", - ["movf.d_3"] = "46200011FGC", - ["movt.d_2"] = "46210011FG", - ["movt.d_3"] = "46210011FGC", - ["movz.d_3"] = "46200012FGT", - ["movn.d_3"] = "46200013FGT", - ["recip.d_2"] = "46200015FG", - ["rsqrt.d_2"] = "46200016FG", - ["cvt.s.d_2"] = "46200020FG", - ["cvt.w.d_2"] = "46200024FG", - ["cvt.l.d_2"] = "46200025FG", - ["c.f.d_2"] = "46200030GH", - ["c.f.d_3"] = "46200030VGH", - ["c.un.d_2"] = "46200031GH", - ["c.un.d_3"] = "46200031VGH", - ["c.eq.d_2"] = "46200032GH", - ["c.eq.d_3"] = "46200032VGH", - ["c.ueq.d_2"] = "46200033GH", - ["c.ueq.d_3"] = "46200033VGH", - ["c.olt.d_2"] = "46200034GH", - ["c.olt.d_3"] = "46200034VGH", - ["c.ult.d_2"] = "46200035GH", - ["c.ult.d_3"] = "46200035VGH", - ["c.ole.d_2"] = "46200036GH", - ["c.ole.d_3"] = "46200036VGH", - ["c.ule.d_2"] = "46200037GH", - ["c.ule.d_3"] = "46200037VGH", - ["c.sf.d_2"] = "46200038GH", - ["c.sf.d_3"] = "46200038VGH", - ["c.ngle.d_2"] = "46200039GH", - ["c.ngle.d_3"] = "46200039VGH", - ["c.seq.d_2"] = "4620003aGH", - ["c.seq.d_3"] = "4620003aVGH", - ["c.ngl.d_2"] = "4620003bGH", - ["c.ngl.d_3"] = "4620003bVGH", - ["c.lt.d_2"] = "4620003cGH", - ["c.lt.d_3"] = "4620003cVGH", - ["c.nge.d_2"] = "4620003dGH", - ["c.nge.d_3"] = "4620003dVGH", - ["c.le.d_2"] = "4620003eGH", - ["c.le.d_3"] = "4620003eVGH", - ["c.ngt.d_2"] = "4620003fGH", - ["c.ngt.d_3"] = "4620003fVGH", - - ["add.ps_3"] = "46c00000FGH", - ["sub.ps_3"] = "46c00001FGH", - ["mul.ps_3"] = "46c00002FGH", - ["abs.ps_2"] = "46c00005FG", - ["mov.ps_2"] = "46c00006FG", - ["neg.ps_2"] = "46c00007FG", - ["movf.ps_2"] = "46c00011FG", - ["movf.ps_3"] = "46c00011FGC", - ["movt.ps_2"] = "46c10011FG", - ["movt.ps_3"] = "46c10011FGC", - ["movz.ps_3"] = "46c00012FGT", - ["movn.ps_3"] = "46c00013FGT", - ["cvt.s.pu_2"] = "46c00020FG", - ["cvt.s.pl_2"] = "46c00028FG", - ["pll.ps_3"] = "46c0002cFGH", - ["plu.ps_3"] = "46c0002dFGH", - ["pul.ps_3"] = "46c0002eFGH", - ["puu.ps_3"] = "46c0002fFGH", - ["c.f.ps_2"] = "46c00030GH", - ["c.f.ps_3"] = "46c00030VGH", - ["c.un.ps_2"] = "46c00031GH", - ["c.un.ps_3"] = "46c00031VGH", - ["c.eq.ps_2"] = "46c00032GH", - ["c.eq.ps_3"] = "46c00032VGH", - ["c.ueq.ps_2"] = "46c00033GH", - ["c.ueq.ps_3"] = "46c00033VGH", - ["c.olt.ps_2"] = "46c00034GH", - ["c.olt.ps_3"] = "46c00034VGH", - ["c.ult.ps_2"] = "46c00035GH", - ["c.ult.ps_3"] = "46c00035VGH", - ["c.ole.ps_2"] = "46c00036GH", - ["c.ole.ps_3"] = "46c00036VGH", - ["c.ule.ps_2"] = "46c00037GH", - ["c.ule.ps_3"] = "46c00037VGH", - ["c.sf.ps_2"] = "46c00038GH", - ["c.sf.ps_3"] = "46c00038VGH", - ["c.ngle.ps_2"] = "46c00039GH", - ["c.ngle.ps_3"] = "46c00039VGH", - ["c.seq.ps_2"] = "46c0003aGH", - ["c.seq.ps_3"] = "46c0003aVGH", - ["c.ngl.ps_2"] = "46c0003bGH", - ["c.ngl.ps_3"] = "46c0003bVGH", - ["c.lt.ps_2"] = "46c0003cGH", - ["c.lt.ps_3"] = "46c0003cVGH", - ["c.nge.ps_2"] = "46c0003dGH", - ["c.nge.ps_3"] = "46c0003dVGH", - ["c.le.ps_2"] = "46c0003eGH", - ["c.le.ps_3"] = "46c0003eVGH", - ["c.ngt.ps_2"] = "46c0003fGH", - ["c.ngt.ps_3"] = "46c0003fVGH", - - ["cvt.s.w_2"] = "46800020FG", - ["cvt.d.w_2"] = "46800021FG", - - ["cvt.s.l_2"] = "46a00020FG", - ["cvt.d.l_2"] = "46a00021FG", - - -- Opcode COP1X. - lwxc1_2 = "4c000000FX", - ldxc1_2 = "4c000001FX", - luxc1_2 = "4c000005FX", - swxc1_2 = "4c000008FX", - sdxc1_2 = "4c000009FX", - suxc1_2 = "4c00000dFX", - prefx_2 = "4c00000fMX", - ["alnv.ps_4"] = "4c00001eFGHS", - ["madd.s_4"] = "4c000020FRGH", - ["madd.d_4"] = "4c000021FRGH", - ["madd.ps_4"] = "4c000026FRGH", - ["msub.s_4"] = "4c000028FRGH", - ["msub.d_4"] = "4c000029FRGH", - ["msub.ps_4"] = "4c00002eFRGH", - ["nmadd.s_4"] = "4c000030FRGH", - ["nmadd.d_4"] = "4c000031FRGH", - ["nmadd.ps_4"] = "4c000036FRGH", - ["nmsub.s_4"] = "4c000038FRGH", - ["nmsub.d_4"] = "4c000039FRGH", - ["nmsub.ps_4"] = "4c00003eFRGH", -} - ------------------------------------------------------------------------------- - -local function parse_gpr(expr) - local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$") - local tp = map_type[tname or expr] - if tp then - local reg = ovreg or tp.reg - if not reg then - werror("type `"..(tname or expr).."' needs a register override") - end - expr = reg - end - local r = match(expr, "^r([1-3]?[0-9])$") - if r then - r = tonumber(r) - if r <= 31 then return r, tp end - end - werror("bad register name `"..expr.."'") -end - -local function parse_fpr(expr) - local r = match(expr, "^f([1-3]?[0-9])$") - if r then - r = tonumber(r) - if r <= 31 then return r end - end - werror("bad register name `"..expr.."'") -end - -local function parse_imm(imm, bits, shift, scale, signed, action) - local n = tonumber(imm) - if n then - local m = sar(n, scale) - if shl(m, scale) == n then - if signed then - local s = sar(m, bits-1) - if s == 0 then return shl(m, shift) - elseif s == -1 then return shl(m + shl(1, bits), shift) end - else - if sar(m, bits) == 0 then return shl(m, shift) end - end - end - werror("out of range immediate `"..imm.."'") - elseif match(imm, "^[rf]([1-3]?[0-9])$") or - match(imm, "^([%w_]+):([rf][1-3]?[0-9])$") then - werror("expected immediate operand, got register") - else - waction(action or "IMM", - (signed and 32768 or 0)+shl(scale, 10)+shl(bits, 5)+shift, imm) - return 0 - end -end - -local function parse_disp(disp) - local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$") - if imm then - local r = shl(parse_gpr(reg), 21) - local extname = match(imm, "^extern%s+(%S+)$") - if extname then - waction("REL_EXT", map_extern[extname], nil, 1) - return r - else - return r + parse_imm(imm, 16, 0, 0, true) - end - end - local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") - if reg and tailr ~= "" then - local r, tp = parse_gpr(reg) - if tp then - waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr)) - return shl(r, 21) - end - end - werror("bad displacement `"..disp.."'") -end - -local function parse_index(idx) - local rt, rs = match(idx, "^(.*)%(([%w_:]+)%)$") - if rt then - rt = parse_gpr(rt) - rs = parse_gpr(rs) - return shl(rt, 16) + shl(rs, 21) - end - werror("bad index `"..idx.."'") -end - -local function parse_label(label, def) - local prefix = sub(label, 1, 2) - -- =>label (pc label reference) - if prefix == "=>" then - return "PC", 0, sub(label, 3) - end - -- ->name (global label reference) - if prefix == "->" then - return "LG", map_global[sub(label, 3)] - end - if def then - -- [1-9] (local label definition) - if match(label, "^[1-9]$") then - return "LG", 10+tonumber(label) - end - else - -- [<>][1-9] (local label reference) - local dir, lnum = match(label, "^([<>])([1-9])$") - if dir then -- Fwd: 1-9, Bkwd: 11-19. - return "LG", lnum + (dir == ">" and 0 or 10) - end - -- extern label (extern label reference) - local extname = match(label, "^extern%s+(%S+)$") - if extname then - return "EXT", map_extern[extname] - end - end - werror("bad label `"..label.."'") -end - ------------------------------------------------------------------------------- - --- Handle opcodes defined with template strings. -map_op[".template__"] = function(params, template, nparams) - if not params then return sub(template, 9) end - local op = tonumber(sub(template, 1, 8), 16) - local n = 1 - - -- Limit number of section buffer positions used by a single dasm_put(). - -- A single opcode needs a maximum of 2 positions (ins/ext). - if secpos+2 > maxsecpos then wflush() end - local pos = wpos() - - -- Process each character. - for p in gmatch(sub(template, 9), ".") do - if p == "D" then - op = op + shl(parse_gpr(params[n]), 11); n = n + 1 - elseif p == "T" then - op = op + shl(parse_gpr(params[n]), 16); n = n + 1 - elseif p == "S" then - op = op + shl(parse_gpr(params[n]), 21); n = n + 1 - elseif p == "F" then - op = op + shl(parse_fpr(params[n]), 6); n = n + 1 - elseif p == "G" then - op = op + shl(parse_fpr(params[n]), 11); n = n + 1 - elseif p == "H" then - op = op + shl(parse_fpr(params[n]), 16); n = n + 1 - elseif p == "R" then - op = op + shl(parse_fpr(params[n]), 21); n = n + 1 - elseif p == "I" then - op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1 - elseif p == "U" then - op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1 - elseif p == "O" then - op = op + parse_disp(params[n]); n = n + 1 - elseif p == "X" then - op = op + parse_index(params[n]); n = n + 1 - elseif p == "B" or p == "J" then - local mode, m, s = parse_label(params[n], false) - if p == "B" then m = m + 2048 end - waction("REL_"..mode, m, s, 1) - n = n + 1 - elseif p == "A" then - op = op + parse_imm(params[n], 5, 6, 0, false); n = n + 1 - elseif p == "a" then - local m = parse_imm(params[n], 6, 6, 0, false, "IMMS"); n = n + 1 - op = op + band(m, 0x7c0) + band(shr(m, 9), 4) - elseif p == "M" then - op = op + parse_imm(params[n], 5, 11, 0, false); n = n + 1 - elseif p == "N" then - op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1 - elseif p == "C" then - op = op + parse_imm(params[n], 3, 18, 0, false); n = n + 1 - elseif p == "V" then - op = op + parse_imm(params[n], 3, 8, 0, false); n = n + 1 - elseif p == "W" then - op = op + parse_imm(params[n], 3, 0, 0, false); n = n + 1 - elseif p == "Y" then - op = op + parse_imm(params[n], 20, 6, 0, false); n = n + 1 - elseif p == "Z" then - op = op + parse_imm(params[n], 10, 6, 0, false); n = n + 1 - elseif p == "=" then - op = op + shl(band(op, 0xf800), 5) -- Copy D to T for clz, clo. - else - assert(false) - end - end - wputpos(pos, op) -end - ------------------------------------------------------------------------------- - --- Pseudo-opcode to mark the position where the action list is to be emitted. -map_op[".actionlist_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeactions(out, name) end) -end - --- Pseudo-opcode to mark the position where the global enum is to be emitted. -map_op[".globals_1"] = function(params) - if not params then return "prefix" end - local prefix = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeglobals(out, prefix) end) -end - --- Pseudo-opcode to mark the position where the global names are to be emitted. -map_op[".globalnames_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeglobalnames(out, name) end) -end - --- Pseudo-opcode to mark the position where the extern names are to be emitted. -map_op[".externnames_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeexternnames(out, name) end) -end - ------------------------------------------------------------------------------- - --- Label pseudo-opcode (converted from trailing colon form). -map_op[".label_1"] = function(params) - if not params then return "[1-9] | ->global | =>pcexpr" end - if secpos+1 > maxsecpos then wflush() end - local mode, n, s = parse_label(params[1], true) - if mode == "EXT" then werror("bad label definition") end - waction("LABEL_"..mode, n, s, 1) -end - ------------------------------------------------------------------------------- - --- Pseudo-opcodes for data storage. -map_op[".long_*"] = function(params) - if not params then return "imm..." end - for _,p in ipairs(params) do - local n = tonumber(p) - if not n then werror("bad immediate `"..p.."'") end - if n < 0 then n = n + 2^32 end - wputw(n) - if secpos+2 > maxsecpos then wflush() end - end -end - --- Alignment pseudo-opcode. -map_op[".align_1"] = function(params) - if not params then return "numpow2" end - if secpos+1 > maxsecpos then wflush() end - local align = tonumber(params[1]) - if align then - local x = align - -- Must be a power of 2 in the range (2 ... 256). - for i=1,8 do - x = x / 2 - if x == 1 then - waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. - return - end - end - end - werror("bad alignment") -end - ------------------------------------------------------------------------------- - --- Pseudo-opcode for (primitive) type definitions (map to C types). -map_op[".type_3"] = function(params, nparams) - if not params then - return nparams == 2 and "name, ctype" or "name, ctype, reg" - end - local name, ctype, reg = params[1], params[2], params[3] - if not match(name, "^[%a_][%w_]*$") then - werror("bad type name `"..name.."'") - end - local tp = map_type[name] - if tp then - werror("duplicate type `"..name.."'") - end - -- Add #type to defines. A bit unclean to put it in map_archdef. - map_archdef["#"..name] = "sizeof("..ctype..")" - -- Add new type and emit shortcut define. - local num = ctypenum + 1 - map_type[name] = { - ctype = ctype, - ctypefmt = format("Dt%X(%%s)", num), - reg = reg, - } - wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) - ctypenum = num -end -map_op[".type_2"] = map_op[".type_3"] - --- Dump type definitions. -local function dumptypes(out, lvl) - local t = {} - for name in pairs(map_type) do t[#t+1] = name end - sort(t) - out:write("Type definitions:\n") - for _,name in ipairs(t) do - local tp = map_type[name] - local reg = tp.reg or "" - out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) - end - out:write("\n") -end - ------------------------------------------------------------------------------- - --- Set the current section. -function _M.section(num) - waction("SECTION", num) - wflush(true) -- SECTION is a terminal action. -end - ------------------------------------------------------------------------------- - --- Dump architecture description. -function _M.dumparch(out) - out:write(format("DynASM %s version %s, released %s\n\n", - _info.arch, _info.version, _info.release)) - dumpactions(out) -end - --- Dump all user defined elements. -function _M.dumpdef(out, lvl) - dumptypes(out, lvl) - dumpglobals(out, lvl) - dumpexterns(out, lvl) -end - ------------------------------------------------------------------------------- - --- Pass callbacks from/to the DynASM core. -function _M.passcb(wl, we, wf, ww) - wline, werror, wfatal, wwarn = wl, we, wf, ww - return wflush -end - --- Setup the arch-specific module. -function _M.setup(arch, opt) - g_arch, g_opt = arch, opt -end - --- Merge the core maps and the arch-specific maps. -function _M.mergemaps(map_coreop, map_def) - setmetatable(map_op, { __index = map_coreop }) - setmetatable(map_def, { __index = map_archdef }) - return map_op, map_def -end - -return _M - ------------------------------------------------------------------------------- - diff --git a/lib/LuaJIT/dynasm/dasm_mips64.lua b/lib/LuaJIT/dynasm/dasm_mips64.lua deleted file mode 100644 index 5636b23..0000000 --- a/lib/LuaJIT/dynasm/dasm_mips64.lua +++ /dev/null @@ -1,12 +0,0 @@ ------------------------------------------------------------------------------- --- DynASM MIPS64 module. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------- --- This module just sets 64 bit mode for the combined MIPS/MIPS64 module. --- All the interesting stuff is there. ------------------------------------------------------------------------------- - -mips64 = true -- Using a global is an ugly, but effective solution. -return require("dasm_mips") diff --git a/lib/LuaJIT/dynasm/dasm_ppc.h b/lib/LuaJIT/dynasm/dasm_ppc.h deleted file mode 100644 index 83fc030..0000000 --- a/lib/LuaJIT/dynasm/dasm_ppc.h +++ /dev/null @@ -1,420 +0,0 @@ -/* -** DynASM PPC/PPC64 encoding engine. -** Copyright (C) 2005-2017 Mike Pall. All rights reserved. -** Released under the MIT license. See dynasm.lua for full copyright notice. -*/ - -#include -#include -#include -#include - -#define DASM_ARCH "ppc" - -#ifndef DASM_EXTERN -#define DASM_EXTERN(a,b,c,d) 0 -#endif - -/* Action definitions. */ -enum { - DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, - /* The following actions need a buffer position. */ - DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, - /* The following actions also have an argument. */ - DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, DASM_IMMSH, - DASM__MAX -}; - -/* Maximum number of section buffer positions for a single dasm_put() call. */ -#define DASM_MAXSECPOS 25 - -/* DynASM encoder status codes. Action list offset or number are or'ed in. */ -#define DASM_S_OK 0x00000000 -#define DASM_S_NOMEM 0x01000000 -#define DASM_S_PHASE 0x02000000 -#define DASM_S_MATCH_SEC 0x03000000 -#define DASM_S_RANGE_I 0x11000000 -#define DASM_S_RANGE_SEC 0x12000000 -#define DASM_S_RANGE_LG 0x13000000 -#define DASM_S_RANGE_PC 0x14000000 -#define DASM_S_RANGE_REL 0x15000000 -#define DASM_S_UNDEF_LG 0x21000000 -#define DASM_S_UNDEF_PC 0x22000000 - -/* Macros to convert positions (8 bit section + 24 bit index). */ -#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) -#define DASM_POS2BIAS(pos) ((pos)&0xff000000) -#define DASM_SEC2POS(sec) ((sec)<<24) -#define DASM_POS2SEC(pos) ((pos)>>24) -#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) - -/* Action list type. */ -typedef const unsigned int *dasm_ActList; - -/* Per-section structure. */ -typedef struct dasm_Section { - int *rbuf; /* Biased buffer pointer (negative section bias). */ - int *buf; /* True buffer pointer. */ - size_t bsize; /* Buffer size in bytes. */ - int pos; /* Biased buffer position. */ - int epos; /* End of biased buffer position - max single put. */ - int ofs; /* Byte offset into section. */ -} dasm_Section; - -/* Core structure holding the DynASM encoding state. */ -struct dasm_State { - size_t psize; /* Allocated size of this structure. */ - dasm_ActList actionlist; /* Current actionlist pointer. */ - int *lglabels; /* Local/global chain/pos ptrs. */ - size_t lgsize; - int *pclabels; /* PC label chains/pos ptrs. */ - size_t pcsize; - void **globals; /* Array of globals (bias -10). */ - dasm_Section *section; /* Pointer to active section. */ - size_t codesize; /* Total size of all code sections. */ - int maxsection; /* 0 <= sectionidx < maxsection. */ - int status; /* Status code. */ - dasm_Section sections[1]; /* All sections. Alloc-extended. */ -}; - -/* The size of the core structure depends on the max. number of sections. */ -#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) - - -/* Initialize DynASM state. */ -void dasm_init(Dst_DECL, int maxsection) -{ - dasm_State *D; - size_t psz = 0; - int i; - Dst_REF = NULL; - DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); - D = Dst_REF; - D->psize = psz; - D->lglabels = NULL; - D->lgsize = 0; - D->pclabels = NULL; - D->pcsize = 0; - D->globals = NULL; - D->maxsection = maxsection; - for (i = 0; i < maxsection; i++) { - D->sections[i].buf = NULL; /* Need this for pass3. */ - D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); - D->sections[i].bsize = 0; - D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ - } -} - -/* Free DynASM state. */ -void dasm_free(Dst_DECL) -{ - dasm_State *D = Dst_REF; - int i; - for (i = 0; i < D->maxsection; i++) - if (D->sections[i].buf) - DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); - if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); - if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); - DASM_M_FREE(Dst, D, D->psize); -} - -/* Setup global label array. Must be called before dasm_setup(). */ -void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) -{ - dasm_State *D = Dst_REF; - D->globals = gl - 10; /* Negative bias to compensate for locals. */ - DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); -} - -/* Grow PC label array. Can be called after dasm_setup(), too. */ -void dasm_growpc(Dst_DECL, unsigned int maxpc) -{ - dasm_State *D = Dst_REF; - size_t osz = D->pcsize; - DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); - memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); -} - -/* Setup encoder. */ -void dasm_setup(Dst_DECL, const void *actionlist) -{ - dasm_State *D = Dst_REF; - int i; - D->actionlist = (dasm_ActList)actionlist; - D->status = DASM_S_OK; - D->section = &D->sections[0]; - memset((void *)D->lglabels, 0, D->lgsize); - if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); - for (i = 0; i < D->maxsection; i++) { - D->sections[i].pos = DASM_SEC2POS(i); - D->sections[i].ofs = 0; - } -} - - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) { \ - D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) -#define CKPL(kind, st) \ - do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ - D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) -#else -#define CK(x, st) ((void)0) -#define CKPL(kind, st) ((void)0) -#endif - -/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ -void dasm_put(Dst_DECL, int start, ...) -{ - va_list ap; - dasm_State *D = Dst_REF; - dasm_ActList p = D->actionlist + start; - dasm_Section *sec = D->section; - int pos = sec->pos, ofs = sec->ofs; - int *b; - - if (pos >= sec->epos) { - DASM_M_GROW(Dst, int, sec->buf, sec->bsize, - sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); - sec->rbuf = sec->buf - DASM_POS2BIAS(pos); - sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); - } - - b = sec->rbuf; - b[pos++] = start; - - va_start(ap, start); - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - if (action >= DASM__MAX) { - ofs += 4; - } else { - int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; - switch (action) { - case DASM_STOP: goto stop; - case DASM_SECTION: - n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); - D->section = &D->sections[n]; goto stop; - case DASM_ESC: p++; ofs += 4; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; - case DASM_REL_LG: - n = (ins & 2047) - 10; pl = D->lglabels + n; - /* Bkwd rel or global. */ - if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } - pl += 10; n = *pl; - if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ - goto linkrel; - case DASM_REL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putrel: - n = *pl; - if (n < 0) { /* Label exists. Get label pos and store it. */ - b[pos] = -n; - } else { - linkrel: - b[pos] = n; /* Else link to rel chain, anchored at label. */ - *pl = pos; - } - pos++; - break; - case DASM_LABEL_LG: - pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; - case DASM_LABEL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putlabel: - n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; - } - *pl = -pos; /* Label exists now. */ - b[pos++] = ofs; /* Store pass1 offset estimate. */ - break; - case DASM_IMM: -#ifdef DASM_CHECKS - CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); -#endif - n >>= ((ins>>10)&31); -#ifdef DASM_CHECKS - if (ins & 0x8000) - CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); - else - CK((n>>((ins>>5)&31)) == 0, RANGE_I); -#endif - b[pos++] = n; - break; - case DASM_IMMSH: - CK((n >> 6) == 0, RANGE_I); - b[pos++] = n; - break; - } - } - } -stop: - va_end(ap); - sec->pos = pos; - sec->ofs = ofs; -} -#undef CK - -/* Pass 2: Link sections, shrink aligns, fix label offsets. */ -int dasm_link(Dst_DECL, size_t *szp) -{ - dasm_State *D = Dst_REF; - int secnum; - int ofs = 0; - -#ifdef DASM_CHECKS - *szp = 0; - if (D->status != DASM_S_OK) return D->status; - { - int pc; - for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) - if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; - } -#endif - - { /* Handle globals not defined in this translation unit. */ - int idx; - for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { - int n = D->lglabels[idx]; - /* Undefined label: Collapse rel chain and replace with marker (< 0). */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } - } - } - - /* Combine all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->rbuf; - int pos = DASM_SEC2POS(secnum); - int lastpos = sec->pos; - - while (pos != lastpos) { - dasm_ActList p = D->actionlist + b[pos++]; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: p++; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; - case DASM_REL_LG: case DASM_REL_PC: pos++; break; - case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; - case DASM_IMM: case DASM_IMMSH: pos++; break; - } - } - stop: (void)0; - } - ofs += sec->ofs; /* Next section starts right after current section. */ - } - - D->codesize = ofs; /* Total size of all code sections */ - *szp = ofs; - return DASM_S_OK; -} - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) -#else -#define CK(x, st) ((void)0) -#endif - -/* Pass 3: Encode sections. */ -int dasm_encode(Dst_DECL, void *buffer) -{ - dasm_State *D = Dst_REF; - char *base = (char *)buffer; - unsigned int *cp = (unsigned int *)buffer; - int secnum; - - /* Encode all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->buf; - int *endb = sec->rbuf + sec->pos; - - while (b != endb) { - dasm_ActList p = D->actionlist + *b++; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: *cp++ = *p++; break; - case DASM_REL_EXT: - n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1) - 4; - goto patchrel; - case DASM_ALIGN: - ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000; - break; - case DASM_REL_LG: - CK(n >= 0, UNDEF_LG); - /* fallthrough */ - case DASM_REL_PC: - CK(n >= 0, UNDEF_PC); - n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base); - patchrel: - CK((n & 3) == 0 && - (((n+4) + ((ins & 2048) ? 0x00008000 : 0x02000000)) >> - ((ins & 2048) ? 16 : 26)) == 0, RANGE_REL); - cp[-1] |= ((n+4) & ((ins & 2048) ? 0x0000fffc: 0x03fffffc)); - break; - case DASM_LABEL_LG: - ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); - break; - case DASM_LABEL_PC: break; - case DASM_IMM: - cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); - break; - case DASM_IMMSH: - cp[-1] |= (ins & 1) ? ((n&31)<<11)|((n&32)>>4) : ((n&31)<<6)|(n&32); - break; - default: *cp++ = ins; break; - } - } - stop: (void)0; - } - } - - if (base + D->codesize != (char *)cp) /* Check for phase errors. */ - return DASM_S_PHASE; - return DASM_S_OK; -} -#undef CK - -/* Get PC label offset. */ -int dasm_getpclabel(Dst_DECL, unsigned int pc) -{ - dasm_State *D = Dst_REF; - if (pc*sizeof(int) < D->pcsize) { - int pos = D->pclabels[pc]; - if (pos < 0) return *DASM_POS2PTR(D, -pos); - if (pos > 0) return -1; /* Undefined. */ - } - return -2; /* Unused or out of range. */ -} - -#ifdef DASM_CHECKS -/* Optional sanity checker to call between isolated encoding steps. */ -int dasm_checkstep(Dst_DECL, int secmatch) -{ - dasm_State *D = Dst_REF; - if (D->status == DASM_S_OK) { - int i; - for (i = 1; i <= 9; i++) { - if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } - D->lglabels[i] = 0; - } - } - if (D->status == DASM_S_OK && secmatch >= 0 && - D->section != &D->sections[secmatch]) - D->status = DASM_S_MATCH_SEC|(D->section-D->sections); - return D->status; -} -#endif - diff --git a/lib/LuaJIT/dynasm/dasm_ppc.lua b/lib/LuaJIT/dynasm/dasm_ppc.lua deleted file mode 100644 index 216f925..0000000 --- a/lib/LuaJIT/dynasm/dasm_ppc.lua +++ /dev/null @@ -1,1919 +0,0 @@ ------------------------------------------------------------------------------- --- DynASM PPC/PPC64 module. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- See dynasm.lua for full copyright notice. --- --- Support for various extensions contributed by Caio Souza Oliveira. ------------------------------------------------------------------------------- - --- Module information: -local _info = { - arch = "ppc", - description = "DynASM PPC module", - version = "1.4.0", - vernum = 10400, - release = "2015-10-18", - author = "Mike Pall", - license = "MIT", -} - --- Exported glue functions for the arch-specific module. -local _M = { _info = _info } - --- Cache library functions. -local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs -local assert, setmetatable = assert, setmetatable -local _s = string -local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char -local match, gmatch = _s.match, _s.gmatch -local concat, sort = table.concat, table.sort -local bit = bit or require("bit") -local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift -local tohex = bit.tohex - --- Inherited tables and callbacks. -local g_opt, g_arch -local wline, werror, wfatal, wwarn - --- Action name list. --- CHECK: Keep this in sync with the C code! -local action_names = { - "STOP", "SECTION", "ESC", "REL_EXT", - "ALIGN", "REL_LG", "LABEL_LG", - "REL_PC", "LABEL_PC", "IMM", "IMMSH" -} - --- Maximum number of section buffer positions for dasm_put(). --- CHECK: Keep this in sync with the C code! -local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. - --- Action name -> action number. -local map_action = {} -for n,name in ipairs(action_names) do - map_action[name] = n-1 -end - --- Action list buffer. -local actlist = {} - --- Argument list for next dasm_put(). Start with offset 0 into action list. -local actargs = { 0 } - --- Current number of section buffer positions for dasm_put(). -local secpos = 1 - ------------------------------------------------------------------------------- - --- Dump action names and numbers. -local function dumpactions(out) - out:write("DynASM encoding engine action codes:\n") - for n,name in ipairs(action_names) do - local num = map_action[name] - out:write(format(" %-10s %02X %d\n", name, num, num)) - end - out:write("\n") -end - --- Write action list buffer as a huge static C array. -local function writeactions(out, name) - local nn = #actlist - if nn == 0 then nn = 1; actlist[0] = map_action.STOP end - out:write("static const unsigned int ", name, "[", nn, "] = {\n") - for i = 1,nn-1 do - assert(out:write("0x", tohex(actlist[i]), ",\n")) - end - assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) -end - ------------------------------------------------------------------------------- - --- Add word to action list. -local function wputxw(n) - assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") - actlist[#actlist+1] = n -end - --- Add action to list with optional arg. Advance buffer pos, too. -local function waction(action, val, a, num) - local w = assert(map_action[action], "bad action name `"..action.."'") - wputxw(w * 0x10000 + (val or 0)) - if a then actargs[#actargs+1] = a end - if a or num then secpos = secpos + (num or 1) end -end - --- Flush action list (intervening C code or buffer pos overflow). -local function wflush(term) - if #actlist == actargs[1] then return end -- Nothing to flush. - if not term then waction("STOP") end -- Terminate action list. - wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) - actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). - secpos = 1 -- The actionlist offset occupies a buffer position, too. -end - --- Put escaped word. -local function wputw(n) - if n <= 0xffffff then waction("ESC") end - wputxw(n) -end - --- Reserve position for word. -local function wpos() - local pos = #actlist+1 - actlist[pos] = "" - return pos -end - --- Store word to reserved position. -local function wputpos(pos, n) - assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") - actlist[pos] = n -end - ------------------------------------------------------------------------------- - --- Global label name -> global label number. With auto assignment on 1st use. -local next_global = 20 -local map_global = setmetatable({}, { __index = function(t, name) - if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end - local n = next_global - if n > 2047 then werror("too many global labels") end - next_global = n + 1 - t[name] = n - return n -end}) - --- Dump global labels. -local function dumpglobals(out, lvl) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("Global labels:\n") - for i=20,next_global-1 do - out:write(format(" %s\n", t[i])) - end - out:write("\n") -end - --- Write global label enum. -local function writeglobals(out, prefix) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("enum {\n") - for i=20,next_global-1 do - out:write(" ", prefix, t[i], ",\n") - end - out:write(" ", prefix, "_MAX\n};\n") -end - --- Write global label names. -local function writeglobalnames(out, name) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("static const char *const ", name, "[] = {\n") - for i=20,next_global-1 do - out:write(" \"", t[i], "\",\n") - end - out:write(" (const char *)0\n};\n") -end - ------------------------------------------------------------------------------- - --- Extern label name -> extern label number. With auto assignment on 1st use. -local next_extern = 0 -local map_extern_ = {} -local map_extern = setmetatable({}, { __index = function(t, name) - -- No restrictions on the name for now. - local n = next_extern - if n > 2047 then werror("too many extern labels") end - next_extern = n + 1 - t[name] = n - map_extern_[n] = name - return n -end}) - --- Dump extern labels. -local function dumpexterns(out, lvl) - out:write("Extern labels:\n") - for i=0,next_extern-1 do - out:write(format(" %s\n", map_extern_[i])) - end - out:write("\n") -end - --- Write extern label names. -local function writeexternnames(out, name) - out:write("static const char *const ", name, "[] = {\n") - for i=0,next_extern-1 do - out:write(" \"", map_extern_[i], "\",\n") - end - out:write(" (const char *)0\n};\n") -end - ------------------------------------------------------------------------------- - --- Arch-specific maps. -local map_archdef = { sp = "r1" } -- Ext. register name -> int. name. - -local map_type = {} -- Type name -> { ctype, reg } -local ctypenum = 0 -- Type number (for Dt... macros). - --- Reverse defines for registers. -function _M.revdef(s) - if s == "r1" then return "sp" end - return s -end - -local map_cond = { - lt = 0, gt = 1, eq = 2, so = 3, - ge = 4, le = 5, ne = 6, ns = 7, -} - ------------------------------------------------------------------------------- - -local map_op, op_template - -local function op_alias(opname, f) - return function(params, nparams) - if not params then return "-> "..opname:sub(1, -3) end - f(params, nparams) - op_template(params, map_op[opname], nparams) - end -end - --- Template strings for PPC instructions. -map_op = { - tdi_3 = "08000000ARI", - twi_3 = "0c000000ARI", - mulli_3 = "1c000000RRI", - subfic_3 = "20000000RRI", - cmplwi_3 = "28000000XRU", - cmplwi_2 = "28000000-RU", - cmpldi_3 = "28200000XRU", - cmpldi_2 = "28200000-RU", - cmpwi_3 = "2c000000XRI", - cmpwi_2 = "2c000000-RI", - cmpdi_3 = "2c200000XRI", - cmpdi_2 = "2c200000-RI", - addic_3 = "30000000RRI", - ["addic._3"] = "34000000RRI", - addi_3 = "38000000RR0I", - li_2 = "38000000RI", - la_2 = "38000000RD", - addis_3 = "3c000000RR0I", - lis_2 = "3c000000RI", - lus_2 = "3c000000RU", - bc_3 = "40000000AAK", - bcl_3 = "40000001AAK", - bdnz_1 = "42000000K", - bdz_1 = "42400000K", - sc_0 = "44000000", - b_1 = "48000000J", - bl_1 = "48000001J", - rlwimi_5 = "50000000RR~AAA.", - rlwinm_5 = "54000000RR~AAA.", - rlwnm_5 = "5c000000RR~RAA.", - ori_3 = "60000000RR~U", - nop_0 = "60000000", - oris_3 = "64000000RR~U", - xori_3 = "68000000RR~U", - xoris_3 = "6c000000RR~U", - ["andi._3"] = "70000000RR~U", - ["andis._3"] = "74000000RR~U", - lwz_2 = "80000000RD", - lwzu_2 = "84000000RD", - lbz_2 = "88000000RD", - lbzu_2 = "8c000000RD", - stw_2 = "90000000RD", - stwu_2 = "94000000RD", - stb_2 = "98000000RD", - stbu_2 = "9c000000RD", - lhz_2 = "a0000000RD", - lhzu_2 = "a4000000RD", - lha_2 = "a8000000RD", - lhau_2 = "ac000000RD", - sth_2 = "b0000000RD", - sthu_2 = "b4000000RD", - lmw_2 = "b8000000RD", - stmw_2 = "bc000000RD", - lfs_2 = "c0000000FD", - lfsu_2 = "c4000000FD", - lfd_2 = "c8000000FD", - lfdu_2 = "cc000000FD", - stfs_2 = "d0000000FD", - stfsu_2 = "d4000000FD", - stfd_2 = "d8000000FD", - stfdu_2 = "dc000000FD", - ld_2 = "e8000000RD", -- NYI: displacement must be divisible by 4. - ldu_2 = "e8000001RD", - lwa_2 = "e8000002RD", - std_2 = "f8000000RD", - stdu_2 = "f8000001RD", - - subi_3 = op_alias("addi_3", function(p) p[3] = "-("..p[3]..")" end), - subis_3 = op_alias("addis_3", function(p) p[3] = "-("..p[3]..")" end), - subic_3 = op_alias("addic_3", function(p) p[3] = "-("..p[3]..")" end), - ["subic._3"] = op_alias("addic._3", function(p) p[3] = "-("..p[3]..")" end), - - rotlwi_3 = op_alias("rlwinm_5", function(p) - p[4] = "0"; p[5] = "31" - end), - rotrwi_3 = op_alias("rlwinm_5", function(p) - p[3] = "32-("..p[3]..")"; p[4] = "0"; p[5] = "31" - end), - rotlw_3 = op_alias("rlwnm_5", function(p) - p[4] = "0"; p[5] = "31" - end), - slwi_3 = op_alias("rlwinm_5", function(p) - p[5] = "31-("..p[3]..")"; p[4] = "0" - end), - srwi_3 = op_alias("rlwinm_5", function(p) - p[4] = p[3]; p[3] = "32-("..p[3]..")"; p[5] = "31" - end), - clrlwi_3 = op_alias("rlwinm_5", function(p) - p[4] = p[3]; p[3] = "0"; p[5] = "31" - end), - clrrwi_3 = op_alias("rlwinm_5", function(p) - p[5] = "31-("..p[3]..")"; p[3] = "0"; p[4] = "0" - end), - - -- Primary opcode 4: - mulhhwu_3 = "10000010RRR.", - machhwu_3 = "10000018RRR.", - mulhhw_3 = "10000050RRR.", - nmachhw_3 = "1000005cRRR.", - machhwsu_3 = "10000098RRR.", - machhws_3 = "100000d8RRR.", - nmachhws_3 = "100000dcRRR.", - mulchwu_3 = "10000110RRR.", - macchwu_3 = "10000118RRR.", - mulchw_3 = "10000150RRR.", - macchw_3 = "10000158RRR.", - nmacchw_3 = "1000015cRRR.", - macchwsu_3 = "10000198RRR.", - macchws_3 = "100001d8RRR.", - nmacchws_3 = "100001dcRRR.", - mullhw_3 = "10000350RRR.", - maclhw_3 = "10000358RRR.", - nmaclhw_3 = "1000035cRRR.", - maclhwsu_3 = "10000398RRR.", - maclhws_3 = "100003d8RRR.", - nmaclhws_3 = "100003dcRRR.", - machhwuo_3 = "10000418RRR.", - nmachhwo_3 = "1000045cRRR.", - machhwsuo_3 = "10000498RRR.", - machhwso_3 = "100004d8RRR.", - nmachhwso_3 = "100004dcRRR.", - macchwuo_3 = "10000518RRR.", - macchwo_3 = "10000558RRR.", - nmacchwo_3 = "1000055cRRR.", - macchwsuo_3 = "10000598RRR.", - macchwso_3 = "100005d8RRR.", - nmacchwso_3 = "100005dcRRR.", - maclhwo_3 = "10000758RRR.", - nmaclhwo_3 = "1000075cRRR.", - maclhwsuo_3 = "10000798RRR.", - maclhwso_3 = "100007d8RRR.", - nmaclhwso_3 = "100007dcRRR.", - - vaddubm_3 = "10000000VVV", - vmaxub_3 = "10000002VVV", - vrlb_3 = "10000004VVV", - vcmpequb_3 = "10000006VVV", - vmuloub_3 = "10000008VVV", - vaddfp_3 = "1000000aVVV", - vmrghb_3 = "1000000cVVV", - vpkuhum_3 = "1000000eVVV", - vmhaddshs_4 = "10000020VVVV", - vmhraddshs_4 = "10000021VVVV", - vmladduhm_4 = "10000022VVVV", - vmsumubm_4 = "10000024VVVV", - vmsummbm_4 = "10000025VVVV", - vmsumuhm_4 = "10000026VVVV", - vmsumuhs_4 = "10000027VVVV", - vmsumshm_4 = "10000028VVVV", - vmsumshs_4 = "10000029VVVV", - vsel_4 = "1000002aVVVV", - vperm_4 = "1000002bVVVV", - vsldoi_4 = "1000002cVVVP", - vpermxor_4 = "1000002dVVVV", - vmaddfp_4 = "1000002eVVVV~", - vnmsubfp_4 = "1000002fVVVV~", - vaddeuqm_4 = "1000003cVVVV", - vaddecuq_4 = "1000003dVVVV", - vsubeuqm_4 = "1000003eVVVV", - vsubecuq_4 = "1000003fVVVV", - vadduhm_3 = "10000040VVV", - vmaxuh_3 = "10000042VVV", - vrlh_3 = "10000044VVV", - vcmpequh_3 = "10000046VVV", - vmulouh_3 = "10000048VVV", - vsubfp_3 = "1000004aVVV", - vmrghh_3 = "1000004cVVV", - vpkuwum_3 = "1000004eVVV", - vadduwm_3 = "10000080VVV", - vmaxuw_3 = "10000082VVV", - vrlw_3 = "10000084VVV", - vcmpequw_3 = "10000086VVV", - vmulouw_3 = "10000088VVV", - vmuluwm_3 = "10000089VVV", - vmrghw_3 = "1000008cVVV", - vpkuhus_3 = "1000008eVVV", - vaddudm_3 = "100000c0VVV", - vmaxud_3 = "100000c2VVV", - vrld_3 = "100000c4VVV", - vcmpeqfp_3 = "100000c6VVV", - vcmpequd_3 = "100000c7VVV", - vpkuwus_3 = "100000ceVVV", - vadduqm_3 = "10000100VVV", - vmaxsb_3 = "10000102VVV", - vslb_3 = "10000104VVV", - vmulosb_3 = "10000108VVV", - vrefp_2 = "1000010aV-V", - vmrglb_3 = "1000010cVVV", - vpkshus_3 = "1000010eVVV", - vaddcuq_3 = "10000140VVV", - vmaxsh_3 = "10000142VVV", - vslh_3 = "10000144VVV", - vmulosh_3 = "10000148VVV", - vrsqrtefp_2 = "1000014aV-V", - vmrglh_3 = "1000014cVVV", - vpkswus_3 = "1000014eVVV", - vaddcuw_3 = "10000180VVV", - vmaxsw_3 = "10000182VVV", - vslw_3 = "10000184VVV", - vmulosw_3 = "10000188VVV", - vexptefp_2 = "1000018aV-V", - vmrglw_3 = "1000018cVVV", - vpkshss_3 = "1000018eVVV", - vmaxsd_3 = "100001c2VVV", - vsl_3 = "100001c4VVV", - vcmpgefp_3 = "100001c6VVV", - vlogefp_2 = "100001caV-V", - vpkswss_3 = "100001ceVVV", - vadduhs_3 = "10000240VVV", - vminuh_3 = "10000242VVV", - vsrh_3 = "10000244VVV", - vcmpgtuh_3 = "10000246VVV", - vmuleuh_3 = "10000248VVV", - vrfiz_2 = "1000024aV-V", - vsplth_3 = "1000024cVV3", - vupkhsh_2 = "1000024eV-V", - vminuw_3 = "10000282VVV", - vminud_3 = "100002c2VVV", - vcmpgtud_3 = "100002c7VVV", - vrfim_2 = "100002caV-V", - vcmpgtsb_3 = "10000306VVV", - vcfux_3 = "1000030aVVA~", - vaddshs_3 = "10000340VVV", - vminsh_3 = "10000342VVV", - vsrah_3 = "10000344VVV", - vcmpgtsh_3 = "10000346VVV", - vmulesh_3 = "10000348VVV", - vcfsx_3 = "1000034aVVA~", - vspltish_2 = "1000034cVS", - vupkhpx_2 = "1000034eV-V", - vaddsws_3 = "10000380VVV", - vminsw_3 = "10000382VVV", - vsraw_3 = "10000384VVV", - vcmpgtsw_3 = "10000386VVV", - vmulesw_3 = "10000388VVV", - vctuxs_3 = "1000038aVVA~", - vspltisw_2 = "1000038cVS", - vminsd_3 = "100003c2VVV", - vsrad_3 = "100003c4VVV", - vcmpbfp_3 = "100003c6VVV", - vcmpgtsd_3 = "100003c7VVV", - vctsxs_3 = "100003caVVA~", - vupklpx_2 = "100003ceV-V", - vsububm_3 = "10000400VVV", - ["bcdadd._4"] = "10000401VVVy.", - vavgub_3 = "10000402VVV", - vand_3 = "10000404VVV", - ["vcmpequb._3"] = "10000406VVV", - vmaxfp_3 = "1000040aVVV", - vsubuhm_3 = "10000440VVV", - ["bcdsub._4"] = "10000441VVVy.", - vavguh_3 = "10000442VVV", - vandc_3 = "10000444VVV", - ["vcmpequh._3"] = "10000446VVV", - vminfp_3 = "1000044aVVV", - vpkudum_3 = "1000044eVVV", - vsubuwm_3 = "10000480VVV", - vavguw_3 = "10000482VVV", - vor_3 = "10000484VVV", - ["vcmpequw._3"] = "10000486VVV", - vpmsumw_3 = "10000488VVV", - ["vcmpeqfp._3"] = "100004c6VVV", - ["vcmpequd._3"] = "100004c7VVV", - vpkudus_3 = "100004ceVVV", - vavgsb_3 = "10000502VVV", - vavgsh_3 = "10000542VVV", - vorc_3 = "10000544VVV", - vbpermq_3 = "1000054cVVV", - vpksdus_3 = "1000054eVVV", - vavgsw_3 = "10000582VVV", - vsld_3 = "100005c4VVV", - ["vcmpgefp._3"] = "100005c6VVV", - vpksdss_3 = "100005ceVVV", - vsububs_3 = "10000600VVV", - mfvscr_1 = "10000604V--", - vsum4ubs_3 = "10000608VVV", - vsubuhs_3 = "10000640VVV", - mtvscr_1 = "10000644--V", - ["vcmpgtuh._3"] = "10000646VVV", - vsum4shs_3 = "10000648VVV", - vupkhsw_2 = "1000064eV-V", - vsubuws_3 = "10000680VVV", - vshasigmaw_4 = "10000682VVYp", - veqv_3 = "10000684VVV", - vsum2sws_3 = "10000688VVV", - vmrgow_3 = "1000068cVVV", - vshasigmad_4 = "100006c2VVYp", - vsrd_3 = "100006c4VVV", - ["vcmpgtud._3"] = "100006c7VVV", - vupklsw_2 = "100006ceV-V", - vupkslw_2 = "100006ceV-V", - vsubsbs_3 = "10000700VVV", - vclzb_2 = "10000702V-V", - vpopcntb_2 = "10000703V-V", - ["vcmpgtsb._3"] = "10000706VVV", - vsum4sbs_3 = "10000708VVV", - vsubshs_3 = "10000740VVV", - vclzh_2 = "10000742V-V", - vpopcnth_2 = "10000743V-V", - ["vcmpgtsh._3"] = "10000746VVV", - vsubsws_3 = "10000780VVV", - vclzw_2 = "10000782V-V", - vpopcntw_2 = "10000783V-V", - ["vcmpgtsw._3"] = "10000786VVV", - vsumsws_3 = "10000788VVV", - vmrgew_3 = "1000078cVVV", - vclzd_2 = "100007c2V-V", - vpopcntd_2 = "100007c3V-V", - ["vcmpbfp._3"] = "100007c6VVV", - ["vcmpgtsd._3"] = "100007c7VVV", - - -- Primary opcode 19: - mcrf_2 = "4c000000XX", - isync_0 = "4c00012c", - crnor_3 = "4c000042CCC", - crnot_2 = "4c000042CC=", - crandc_3 = "4c000102CCC", - crxor_3 = "4c000182CCC", - crclr_1 = "4c000182C==", - crnand_3 = "4c0001c2CCC", - crand_3 = "4c000202CCC", - creqv_3 = "4c000242CCC", - crset_1 = "4c000242C==", - crorc_3 = "4c000342CCC", - cror_3 = "4c000382CCC", - crmove_2 = "4c000382CC=", - bclr_2 = "4c000020AA", - bclrl_2 = "4c000021AA", - bcctr_2 = "4c000420AA", - bcctrl_2 = "4c000421AA", - bctar_2 = "4c000460AA", - bctarl_2 = "4c000461AA", - blr_0 = "4e800020", - blrl_0 = "4e800021", - bctr_0 = "4e800420", - bctrl_0 = "4e800421", - - -- Primary opcode 31: - cmpw_3 = "7c000000XRR", - cmpw_2 = "7c000000-RR", - cmpd_3 = "7c200000XRR", - cmpd_2 = "7c200000-RR", - tw_3 = "7c000008ARR", - lvsl_3 = "7c00000cVRR", - subfc_3 = "7c000010RRR.", - subc_3 = "7c000010RRR~.", - mulhdu_3 = "7c000012RRR.", - addc_3 = "7c000014RRR.", - mulhwu_3 = "7c000016RRR.", - isel_4 = "7c00001eRRRC", - isellt_3 = "7c00001eRRR", - iselgt_3 = "7c00005eRRR", - iseleq_3 = "7c00009eRRR", - mfcr_1 = "7c000026R", - mfocrf_2 = "7c100026RG", - mtcrf_2 = "7c000120GR", - mtocrf_2 = "7c100120GR", - lwarx_3 = "7c000028RR0R", - ldx_3 = "7c00002aRR0R", - lwzx_3 = "7c00002eRR0R", - slw_3 = "7c000030RR~R.", - cntlzw_2 = "7c000034RR~", - sld_3 = "7c000036RR~R.", - and_3 = "7c000038RR~R.", - cmplw_3 = "7c000040XRR", - cmplw_2 = "7c000040-RR", - cmpld_3 = "7c200040XRR", - cmpld_2 = "7c200040-RR", - lvsr_3 = "7c00004cVRR", - subf_3 = "7c000050RRR.", - sub_3 = "7c000050RRR~.", - lbarx_3 = "7c000068RR0R", - ldux_3 = "7c00006aRR0R", - dcbst_2 = "7c00006c-RR", - lwzux_3 = "7c00006eRR0R", - cntlzd_2 = "7c000074RR~", - andc_3 = "7c000078RR~R.", - td_3 = "7c000088ARR", - lvewx_3 = "7c00008eVRR", - mulhd_3 = "7c000092RRR.", - addg6s_3 = "7c000094RRR", - mulhw_3 = "7c000096RRR.", - dlmzb_3 = "7c00009cRR~R.", - ldarx_3 = "7c0000a8RR0R", - dcbf_2 = "7c0000ac-RR", - lbzx_3 = "7c0000aeRR0R", - lvx_3 = "7c0000ceVRR", - neg_2 = "7c0000d0RR.", - lharx_3 = "7c0000e8RR0R", - lbzux_3 = "7c0000eeRR0R", - popcntb_2 = "7c0000f4RR~", - not_2 = "7c0000f8RR~%.", - nor_3 = "7c0000f8RR~R.", - stvebx_3 = "7c00010eVRR", - subfe_3 = "7c000110RRR.", - sube_3 = "7c000110RRR~.", - adde_3 = "7c000114RRR.", - stdx_3 = "7c00012aRR0R", - ["stwcx._3"] = "7c00012dRR0R.", - stwx_3 = "7c00012eRR0R", - prtyw_2 = "7c000134RR~", - stvehx_3 = "7c00014eVRR", - stdux_3 = "7c00016aRR0R", - ["stqcx._3"] = "7c00016dR:R0R.", - stwux_3 = "7c00016eRR0R", - prtyd_2 = "7c000174RR~", - stvewx_3 = "7c00018eVRR", - subfze_2 = "7c000190RR.", - addze_2 = "7c000194RR.", - ["stdcx._3"] = "7c0001adRR0R.", - stbx_3 = "7c0001aeRR0R", - stvx_3 = "7c0001ceVRR", - subfme_2 = "7c0001d0RR.", - mulld_3 = "7c0001d2RRR.", - addme_2 = "7c0001d4RR.", - mullw_3 = "7c0001d6RRR.", - dcbtst_2 = "7c0001ec-RR", - stbux_3 = "7c0001eeRR0R", - bpermd_3 = "7c0001f8RR~R", - lvepxl_3 = "7c00020eVRR", - add_3 = "7c000214RRR.", - lqarx_3 = "7c000228R:R0R", - dcbt_2 = "7c00022c-RR", - lhzx_3 = "7c00022eRR0R", - cdtbcd_2 = "7c000234RR~", - eqv_3 = "7c000238RR~R.", - lvepx_3 = "7c00024eVRR", - eciwx_3 = "7c00026cRR0R", - lhzux_3 = "7c00026eRR0R", - cbcdtd_2 = "7c000274RR~", - xor_3 = "7c000278RR~R.", - mfspefscr_1 = "7c0082a6R", - mfxer_1 = "7c0102a6R", - mflr_1 = "7c0802a6R", - mfctr_1 = "7c0902a6R", - lwax_3 = "7c0002aaRR0R", - lhax_3 = "7c0002aeRR0R", - mftb_1 = "7c0c42e6R", - mftbu_1 = "7c0d42e6R", - lvxl_3 = "7c0002ceVRR", - lwaux_3 = "7c0002eaRR0R", - lhaux_3 = "7c0002eeRR0R", - popcntw_2 = "7c0002f4RR~", - divdeu_3 = "7c000312RRR.", - divweu_3 = "7c000316RRR.", - sthx_3 = "7c00032eRR0R", - orc_3 = "7c000338RR~R.", - ecowx_3 = "7c00036cRR0R", - sthux_3 = "7c00036eRR0R", - or_3 = "7c000378RR~R.", - mr_2 = "7c000378RR~%.", - divdu_3 = "7c000392RRR.", - divwu_3 = "7c000396RRR.", - mtspefscr_1 = "7c0083a6R", - mtxer_1 = "7c0103a6R", - mtlr_1 = "7c0803a6R", - mtctr_1 = "7c0903a6R", - dcbi_2 = "7c0003ac-RR", - nand_3 = "7c0003b8RR~R.", - dsn_2 = "7c0003c6-RR", - stvxl_3 = "7c0003ceVRR", - divd_3 = "7c0003d2RRR.", - divw_3 = "7c0003d6RRR.", - popcntd_2 = "7c0003f4RR~", - cmpb_3 = "7c0003f8RR~R.", - mcrxr_1 = "7c000400X", - lbdx_3 = "7c000406RRR", - subfco_3 = "7c000410RRR.", - subco_3 = "7c000410RRR~.", - addco_3 = "7c000414RRR.", - ldbrx_3 = "7c000428RR0R", - lswx_3 = "7c00042aRR0R", - lwbrx_3 = "7c00042cRR0R", - lfsx_3 = "7c00042eFR0R", - srw_3 = "7c000430RR~R.", - srd_3 = "7c000436RR~R.", - lhdx_3 = "7c000446RRR", - subfo_3 = "7c000450RRR.", - subo_3 = "7c000450RRR~.", - lfsux_3 = "7c00046eFR0R", - lwdx_3 = "7c000486RRR", - lswi_3 = "7c0004aaRR0A", - sync_0 = "7c0004ac", - lwsync_0 = "7c2004ac", - ptesync_0 = "7c4004ac", - lfdx_3 = "7c0004aeFR0R", - lddx_3 = "7c0004c6RRR", - nego_2 = "7c0004d0RR.", - lfdux_3 = "7c0004eeFR0R", - stbdx_3 = "7c000506RRR", - subfeo_3 = "7c000510RRR.", - subeo_3 = "7c000510RRR~.", - addeo_3 = "7c000514RRR.", - stdbrx_3 = "7c000528RR0R", - stswx_3 = "7c00052aRR0R", - stwbrx_3 = "7c00052cRR0R", - stfsx_3 = "7c00052eFR0R", - sthdx_3 = "7c000546RRR", - ["stbcx._3"] = "7c00056dRRR", - stfsux_3 = "7c00056eFR0R", - stwdx_3 = "7c000586RRR", - subfzeo_2 = "7c000590RR.", - addzeo_2 = "7c000594RR.", - stswi_3 = "7c0005aaRR0A", - ["sthcx._3"] = "7c0005adRRR", - stfdx_3 = "7c0005aeFR0R", - stddx_3 = "7c0005c6RRR", - subfmeo_2 = "7c0005d0RR.", - mulldo_3 = "7c0005d2RRR.", - addmeo_2 = "7c0005d4RR.", - mullwo_3 = "7c0005d6RRR.", - dcba_2 = "7c0005ec-RR", - stfdux_3 = "7c0005eeFR0R", - stvepxl_3 = "7c00060eVRR", - addo_3 = "7c000614RRR.", - lhbrx_3 = "7c00062cRR0R", - lfdpx_3 = "7c00062eF:RR", - sraw_3 = "7c000630RR~R.", - srad_3 = "7c000634RR~R.", - lfddx_3 = "7c000646FRR", - stvepx_3 = "7c00064eVRR", - srawi_3 = "7c000670RR~A.", - sradi_3 = "7c000674RR~H.", - eieio_0 = "7c0006ac", - lfiwax_3 = "7c0006aeFR0R", - divdeuo_3 = "7c000712RRR.", - divweuo_3 = "7c000716RRR.", - sthbrx_3 = "7c00072cRR0R", - stfdpx_3 = "7c00072eF:RR", - extsh_2 = "7c000734RR~.", - stfddx_3 = "7c000746FRR", - divdeo_3 = "7c000752RRR.", - divweo_3 = "7c000756RRR.", - extsb_2 = "7c000774RR~.", - divduo_3 = "7c000792RRR.", - divwou_3 = "7c000796RRR.", - icbi_2 = "7c0007ac-RR", - stfiwx_3 = "7c0007aeFR0R", - extsw_2 = "7c0007b4RR~.", - divdo_3 = "7c0007d2RRR.", - divwo_3 = "7c0007d6RRR.", - dcbz_2 = "7c0007ec-RR", - - ["tbegin._1"] = "7c00051d1", - ["tbegin._0"] = "7c00051d", - ["tend._1"] = "7c00055dY", - ["tend._0"] = "7c00055d", - ["tendall._0"] = "7e00055d", - tcheck_1 = "7c00059cX", - ["tsr._1"] = "7c0005dd1", - ["tsuspend._0"] = "7c0005dd", - ["tresume._0"] = "7c2005dd", - ["tabortwc._3"] = "7c00061dARR", - ["tabortdc._3"] = "7c00065dARR", - ["tabortwci._3"] = "7c00069dARS", - ["tabortdci._3"] = "7c0006ddARS", - ["tabort._1"] = "7c00071d-R-", - ["treclaim._1"] = "7c00075d-R", - ["trechkpt._0"] = "7c0007dd", - - lxsiwzx_3 = "7c000018QRR", - lxsiwax_3 = "7c000098QRR", - mfvsrd_2 = "7c000066-Rq", - mfvsrwz_2 = "7c0000e6-Rq", - stxsiwx_3 = "7c000118QRR", - mtvsrd_2 = "7c000166QR", - mtvsrwa_2 = "7c0001a6QR", - lxvdsx_3 = "7c000298QRR", - lxsspx_3 = "7c000418QRR", - lxsdx_3 = "7c000498QRR", - stxsspx_3 = "7c000518QRR", - stxsdx_3 = "7c000598QRR", - lxvw4x_3 = "7c000618QRR", - lxvd2x_3 = "7c000698QRR", - stxvw4x_3 = "7c000718QRR", - stxvd2x_3 = "7c000798QRR", - - -- Primary opcode 30: - rldicl_4 = "78000000RR~HM.", - rldicr_4 = "78000004RR~HM.", - rldic_4 = "78000008RR~HM.", - rldimi_4 = "7800000cRR~HM.", - rldcl_4 = "78000010RR~RM.", - rldcr_4 = "78000012RR~RM.", - - rotldi_3 = op_alias("rldicl_4", function(p) - p[4] = "0" - end), - rotrdi_3 = op_alias("rldicl_4", function(p) - p[3] = "64-("..p[3]..")"; p[4] = "0" - end), - rotld_3 = op_alias("rldcl_4", function(p) - p[4] = "0" - end), - sldi_3 = op_alias("rldicr_4", function(p) - p[4] = "63-("..p[3]..")" - end), - srdi_3 = op_alias("rldicl_4", function(p) - p[4] = p[3]; p[3] = "64-("..p[3]..")" - end), - clrldi_3 = op_alias("rldicl_4", function(p) - p[4] = p[3]; p[3] = "0" - end), - clrrdi_3 = op_alias("rldicr_4", function(p) - p[4] = "63-("..p[3]..")"; p[3] = "0" - end), - - -- Primary opcode 56: - lq_2 = "e0000000R:D", -- NYI: displacement must be divisible by 8. - - -- Primary opcode 57: - lfdp_2 = "e4000000F:D", -- NYI: displacement must be divisible by 4. - - -- Primary opcode 59: - fdivs_3 = "ec000024FFF.", - fsubs_3 = "ec000028FFF.", - fadds_3 = "ec00002aFFF.", - fsqrts_2 = "ec00002cF-F.", - fres_2 = "ec000030F-F.", - fmuls_3 = "ec000032FF-F.", - frsqrtes_2 = "ec000034F-F.", - fmsubs_4 = "ec000038FFFF~.", - fmadds_4 = "ec00003aFFFF~.", - fnmsubs_4 = "ec00003cFFFF~.", - fnmadds_4 = "ec00003eFFFF~.", - fcfids_2 = "ec00069cF-F.", - fcfidus_2 = "ec00079cF-F.", - - dadd_3 = "ec000004FFF.", - dqua_4 = "ec000006FFFZ.", - dmul_3 = "ec000044FFF.", - drrnd_4 = "ec000046FFFZ.", - dscli_3 = "ec000084FF6.", - dquai_4 = "ec000086SF~FZ.", - dscri_3 = "ec0000c4FF6.", - drintx_4 = "ec0000c61F~FZ.", - dcmpo_3 = "ec000104XFF", - dtstex_3 = "ec000144XFF", - dtstdc_3 = "ec000184XF6", - dtstdg_3 = "ec0001c4XF6", - drintn_4 = "ec0001c61F~FZ.", - dctdp_2 = "ec000204F-F.", - dctfix_2 = "ec000244F-F.", - ddedpd_3 = "ec000284ZF~F.", - dxex_2 = "ec0002c4F-F.", - dsub_3 = "ec000404FFF.", - ddiv_3 = "ec000444FFF.", - dcmpu_3 = "ec000504XFF", - dtstsf_3 = "ec000544XFF", - drsp_2 = "ec000604F-F.", - dcffix_2 = "ec000644F-F.", - denbcd_3 = "ec000684YF~F.", - diex_3 = "ec0006c4FFF.", - - -- Primary opcode 60: - xsaddsp_3 = "f0000000QQQ", - xsmaddasp_3 = "f0000008QQQ", - xxsldwi_4 = "f0000010QQQz", - xsrsqrtesp_2 = "f0000028Q-Q", - xssqrtsp_2 = "f000002cQ-Q", - xxsel_4 = "f0000030QQQQ", - xssubsp_3 = "f0000040QQQ", - xsmaddmsp_3 = "f0000048QQQ", - xxpermdi_4 = "f0000050QQQz", - xsresp_2 = "f0000068Q-Q", - xsmulsp_3 = "f0000080QQQ", - xsmsubasp_3 = "f0000088QQQ", - xxmrghw_3 = "f0000090QQQ", - xsdivsp_3 = "f00000c0QQQ", - xsmsubmsp_3 = "f00000c8QQQ", - xsadddp_3 = "f0000100QQQ", - xsmaddadp_3 = "f0000108QQQ", - xscmpudp_3 = "f0000118XQQ", - xscvdpuxws_2 = "f0000120Q-Q", - xsrdpi_2 = "f0000124Q-Q", - xsrsqrtedp_2 = "f0000128Q-Q", - xssqrtdp_2 = "f000012cQ-Q", - xssubdp_3 = "f0000140QQQ", - xsmaddmdp_3 = "f0000148QQQ", - xscmpodp_3 = "f0000158XQQ", - xscvdpsxws_2 = "f0000160Q-Q", - xsrdpiz_2 = "f0000164Q-Q", - xsredp_2 = "f0000168Q-Q", - xsmuldp_3 = "f0000180QQQ", - xsmsubadp_3 = "f0000188QQQ", - xxmrglw_3 = "f0000190QQQ", - xsrdpip_2 = "f00001a4Q-Q", - xstsqrtdp_2 = "f00001a8X-Q", - xsrdpic_2 = "f00001acQ-Q", - xsdivdp_3 = "f00001c0QQQ", - xsmsubmdp_3 = "f00001c8QQQ", - xsrdpim_2 = "f00001e4Q-Q", - xstdivdp_3 = "f00001e8XQQ", - xvaddsp_3 = "f0000200QQQ", - xvmaddasp_3 = "f0000208QQQ", - xvcmpeqsp_3 = "f0000218QQQ", - xvcvspuxws_2 = "f0000220Q-Q", - xvrspi_2 = "f0000224Q-Q", - xvrsqrtesp_2 = "f0000228Q-Q", - xvsqrtsp_2 = "f000022cQ-Q", - xvsubsp_3 = "f0000240QQQ", - xvmaddmsp_3 = "f0000248QQQ", - xvcmpgtsp_3 = "f0000258QQQ", - xvcvspsxws_2 = "f0000260Q-Q", - xvrspiz_2 = "f0000264Q-Q", - xvresp_2 = "f0000268Q-Q", - xvmulsp_3 = "f0000280QQQ", - xvmsubasp_3 = "f0000288QQQ", - xxspltw_3 = "f0000290QQg~", - xvcmpgesp_3 = "f0000298QQQ", - xvcvuxwsp_2 = "f00002a0Q-Q", - xvrspip_2 = "f00002a4Q-Q", - xvtsqrtsp_2 = "f00002a8X-Q", - xvrspic_2 = "f00002acQ-Q", - xvdivsp_3 = "f00002c0QQQ", - xvmsubmsp_3 = "f00002c8QQQ", - xvcvsxwsp_2 = "f00002e0Q-Q", - xvrspim_2 = "f00002e4Q-Q", - xvtdivsp_3 = "f00002e8XQQ", - xvadddp_3 = "f0000300QQQ", - xvmaddadp_3 = "f0000308QQQ", - xvcmpeqdp_3 = "f0000318QQQ", - xvcvdpuxws_2 = "f0000320Q-Q", - xvrdpi_2 = "f0000324Q-Q", - xvrsqrtedp_2 = "f0000328Q-Q", - xvsqrtdp_2 = "f000032cQ-Q", - xvsubdp_3 = "f0000340QQQ", - xvmaddmdp_3 = "f0000348QQQ", - xvcmpgtdp_3 = "f0000358QQQ", - xvcvdpsxws_2 = "f0000360Q-Q", - xvrdpiz_2 = "f0000364Q-Q", - xvredp_2 = "f0000368Q-Q", - xvmuldp_3 = "f0000380QQQ", - xvmsubadp_3 = "f0000388QQQ", - xvcmpgedp_3 = "f0000398QQQ", - xvcvuxwdp_2 = "f00003a0Q-Q", - xvrdpip_2 = "f00003a4Q-Q", - xvtsqrtdp_2 = "f00003a8X-Q", - xvrdpic_2 = "f00003acQ-Q", - xvdivdp_3 = "f00003c0QQQ", - xvmsubmdp_3 = "f00003c8QQQ", - xvcvsxwdp_2 = "f00003e0Q-Q", - xvrdpim_2 = "f00003e4Q-Q", - xvtdivdp_3 = "f00003e8XQQ", - xsnmaddasp_3 = "f0000408QQQ", - xxland_3 = "f0000410QQQ", - xscvdpsp_2 = "f0000424Q-Q", - xscvdpspn_2 = "f000042cQ-Q", - xsnmaddmsp_3 = "f0000448QQQ", - xxlandc_3 = "f0000450QQQ", - xsrsp_2 = "f0000464Q-Q", - xsnmsubasp_3 = "f0000488QQQ", - xxlor_3 = "f0000490QQQ", - xscvuxdsp_2 = "f00004a0Q-Q", - xsnmsubmsp_3 = "f00004c8QQQ", - xxlxor_3 = "f00004d0QQQ", - xscvsxdsp_2 = "f00004e0Q-Q", - xsmaxdp_3 = "f0000500QQQ", - xsnmaddadp_3 = "f0000508QQQ", - xxlnor_3 = "f0000510QQQ", - xscvdpuxds_2 = "f0000520Q-Q", - xscvspdp_2 = "f0000524Q-Q", - xscvspdpn_2 = "f000052cQ-Q", - xsmindp_3 = "f0000540QQQ", - xsnmaddmdp_3 = "f0000548QQQ", - xxlorc_3 = "f0000550QQQ", - xscvdpsxds_2 = "f0000560Q-Q", - xsabsdp_2 = "f0000564Q-Q", - xscpsgndp_3 = "f0000580QQQ", - xsnmsubadp_3 = "f0000588QQQ", - xxlnand_3 = "f0000590QQQ", - xscvuxddp_2 = "f00005a0Q-Q", - xsnabsdp_2 = "f00005a4Q-Q", - xsnmsubmdp_3 = "f00005c8QQQ", - xxleqv_3 = "f00005d0QQQ", - xscvsxddp_2 = "f00005e0Q-Q", - xsnegdp_2 = "f00005e4Q-Q", - xvmaxsp_3 = "f0000600QQQ", - xvnmaddasp_3 = "f0000608QQQ", - ["xvcmpeqsp._3"] = "f0000618QQQ", - xvcvspuxds_2 = "f0000620Q-Q", - xvcvdpsp_2 = "f0000624Q-Q", - xvminsp_3 = "f0000640QQQ", - xvnmaddmsp_3 = "f0000648QQQ", - ["xvcmpgtsp._3"] = "f0000658QQQ", - xvcvspsxds_2 = "f0000660Q-Q", - xvabssp_2 = "f0000664Q-Q", - xvcpsgnsp_3 = "f0000680QQQ", - xvnmsubasp_3 = "f0000688QQQ", - ["xvcmpgesp._3"] = "f0000698QQQ", - xvcvuxdsp_2 = "f00006a0Q-Q", - xvnabssp_2 = "f00006a4Q-Q", - xvnmsubmsp_3 = "f00006c8QQQ", - xvcvsxdsp_2 = "f00006e0Q-Q", - xvnegsp_2 = "f00006e4Q-Q", - xvmaxdp_3 = "f0000700QQQ", - xvnmaddadp_3 = "f0000708QQQ", - ["xvcmpeqdp._3"] = "f0000718QQQ", - xvcvdpuxds_2 = "f0000720Q-Q", - xvcvspdp_2 = "f0000724Q-Q", - xvmindp_3 = "f0000740QQQ", - xvnmaddmdp_3 = "f0000748QQQ", - ["xvcmpgtdp._3"] = "f0000758QQQ", - xvcvdpsxds_2 = "f0000760Q-Q", - xvabsdp_2 = "f0000764Q-Q", - xvcpsgndp_3 = "f0000780QQQ", - xvnmsubadp_3 = "f0000788QQQ", - ["xvcmpgedp._3"] = "f0000798QQQ", - xvcvuxddp_2 = "f00007a0Q-Q", - xvnabsdp_2 = "f00007a4Q-Q", - xvnmsubmdp_3 = "f00007c8QQQ", - xvcvsxddp_2 = "f00007e0Q-Q", - xvnegdp_2 = "f00007e4Q-Q", - - -- Primary opcode 61: - stfdp_2 = "f4000000F:D", -- NYI: displacement must be divisible by 4. - - -- Primary opcode 62: - stq_2 = "f8000002R:D", -- NYI: displacement must be divisible by 8. - - -- Primary opcode 63: - fdiv_3 = "fc000024FFF.", - fsub_3 = "fc000028FFF.", - fadd_3 = "fc00002aFFF.", - fsqrt_2 = "fc00002cF-F.", - fsel_4 = "fc00002eFFFF~.", - fre_2 = "fc000030F-F.", - fmul_3 = "fc000032FF-F.", - frsqrte_2 = "fc000034F-F.", - fmsub_4 = "fc000038FFFF~.", - fmadd_4 = "fc00003aFFFF~.", - fnmsub_4 = "fc00003cFFFF~.", - fnmadd_4 = "fc00003eFFFF~.", - fcmpu_3 = "fc000000XFF", - fcpsgn_3 = "fc000010FFF.", - fcmpo_3 = "fc000040XFF", - mtfsb1_1 = "fc00004cA", - fneg_2 = "fc000050F-F.", - mcrfs_2 = "fc000080XX", - mtfsb0_1 = "fc00008cA", - fmr_2 = "fc000090F-F.", - frsp_2 = "fc000018F-F.", - fctiw_2 = "fc00001cF-F.", - fctiwz_2 = "fc00001eF-F.", - ftdiv_2 = "fc000100X-F.", - fctiwu_2 = "fc00011cF-F.", - fctiwuz_2 = "fc00011eF-F.", - mtfsfi_2 = "fc00010cAA", -- NYI: upshift. - fnabs_2 = "fc000110F-F.", - ftsqrt_2 = "fc000140X-F.", - fabs_2 = "fc000210F-F.", - frin_2 = "fc000310F-F.", - friz_2 = "fc000350F-F.", - frip_2 = "fc000390F-F.", - frim_2 = "fc0003d0F-F.", - mffs_1 = "fc00048eF.", - -- NYI: mtfsf, mtfsb0, mtfsb1. - fctid_2 = "fc00065cF-F.", - fctidz_2 = "fc00065eF-F.", - fmrgow_3 = "fc00068cFFF", - fcfid_2 = "fc00069cF-F.", - fctidu_2 = "fc00075cF-F.", - fctiduz_2 = "fc00075eF-F.", - fmrgew_3 = "fc00078cFFF", - fcfidu_2 = "fc00079cF-F.", - - daddq_3 = "fc000004F:F:F:.", - dquaq_4 = "fc000006F:F:F:Z.", - dmulq_3 = "fc000044F:F:F:.", - drrndq_4 = "fc000046F:F:F:Z.", - dscliq_3 = "fc000084F:F:6.", - dquaiq_4 = "fc000086SF:~F:Z.", - dscriq_3 = "fc0000c4F:F:6.", - drintxq_4 = "fc0000c61F:~F:Z.", - dcmpoq_3 = "fc000104XF:F:", - dtstexq_3 = "fc000144XF:F:", - dtstdcq_3 = "fc000184XF:6", - dtstdgq_3 = "fc0001c4XF:6", - drintnq_4 = "fc0001c61F:~F:Z.", - dctqpq_2 = "fc000204F:-F:.", - dctfixq_2 = "fc000244F:-F:.", - ddedpdq_3 = "fc000284ZF:~F:.", - dxexq_2 = "fc0002c4F:-F:.", - dsubq_3 = "fc000404F:F:F:.", - ddivq_3 = "fc000444F:F:F:.", - dcmpuq_3 = "fc000504XF:F:", - dtstsfq_3 = "fc000544XF:F:", - drdpq_2 = "fc000604F:-F:.", - dcffixq_2 = "fc000644F:-F:.", - denbcdq_3 = "fc000684YF:~F:.", - diexq_3 = "fc0006c4F:FF:.", - - -- Primary opcode 4, SPE APU extension: - evaddw_3 = "10000200RRR", - evaddiw_3 = "10000202RAR~", - evsubw_3 = "10000204RRR~", - evsubiw_3 = "10000206RAR~", - evabs_2 = "10000208RR", - evneg_2 = "10000209RR", - evextsb_2 = "1000020aRR", - evextsh_2 = "1000020bRR", - evrndw_2 = "1000020cRR", - evcntlzw_2 = "1000020dRR", - evcntlsw_2 = "1000020eRR", - brinc_3 = "1000020fRRR", - evand_3 = "10000211RRR", - evandc_3 = "10000212RRR", - evxor_3 = "10000216RRR", - evor_3 = "10000217RRR", - evmr_2 = "10000217RR=", - evnor_3 = "10000218RRR", - evnot_2 = "10000218RR=", - eveqv_3 = "10000219RRR", - evorc_3 = "1000021bRRR", - evnand_3 = "1000021eRRR", - evsrwu_3 = "10000220RRR", - evsrws_3 = "10000221RRR", - evsrwiu_3 = "10000222RRA", - evsrwis_3 = "10000223RRA", - evslw_3 = "10000224RRR", - evslwi_3 = "10000226RRA", - evrlw_3 = "10000228RRR", - evsplati_2 = "10000229RS", - evrlwi_3 = "1000022aRRA", - evsplatfi_2 = "1000022bRS", - evmergehi_3 = "1000022cRRR", - evmergelo_3 = "1000022dRRR", - evcmpgtu_3 = "10000230XRR", - evcmpgtu_2 = "10000230-RR", - evcmpgts_3 = "10000231XRR", - evcmpgts_2 = "10000231-RR", - evcmpltu_3 = "10000232XRR", - evcmpltu_2 = "10000232-RR", - evcmplts_3 = "10000233XRR", - evcmplts_2 = "10000233-RR", - evcmpeq_3 = "10000234XRR", - evcmpeq_2 = "10000234-RR", - evsel_4 = "10000278RRRW", - evsel_3 = "10000278RRR", - evfsadd_3 = "10000280RRR", - evfssub_3 = "10000281RRR", - evfsabs_2 = "10000284RR", - evfsnabs_2 = "10000285RR", - evfsneg_2 = "10000286RR", - evfsmul_3 = "10000288RRR", - evfsdiv_3 = "10000289RRR", - evfscmpgt_3 = "1000028cXRR", - evfscmpgt_2 = "1000028c-RR", - evfscmplt_3 = "1000028dXRR", - evfscmplt_2 = "1000028d-RR", - evfscmpeq_3 = "1000028eXRR", - evfscmpeq_2 = "1000028e-RR", - evfscfui_2 = "10000290R-R", - evfscfsi_2 = "10000291R-R", - evfscfuf_2 = "10000292R-R", - evfscfsf_2 = "10000293R-R", - evfsctui_2 = "10000294R-R", - evfsctsi_2 = "10000295R-R", - evfsctuf_2 = "10000296R-R", - evfsctsf_2 = "10000297R-R", - evfsctuiz_2 = "10000298R-R", - evfsctsiz_2 = "1000029aR-R", - evfststgt_3 = "1000029cXRR", - evfststgt_2 = "1000029c-RR", - evfststlt_3 = "1000029dXRR", - evfststlt_2 = "1000029d-RR", - evfststeq_3 = "1000029eXRR", - evfststeq_2 = "1000029e-RR", - efsadd_3 = "100002c0RRR", - efssub_3 = "100002c1RRR", - efsabs_2 = "100002c4RR", - efsnabs_2 = "100002c5RR", - efsneg_2 = "100002c6RR", - efsmul_3 = "100002c8RRR", - efsdiv_3 = "100002c9RRR", - efscmpgt_3 = "100002ccXRR", - efscmpgt_2 = "100002cc-RR", - efscmplt_3 = "100002cdXRR", - efscmplt_2 = "100002cd-RR", - efscmpeq_3 = "100002ceXRR", - efscmpeq_2 = "100002ce-RR", - efscfd_2 = "100002cfR-R", - efscfui_2 = "100002d0R-R", - efscfsi_2 = "100002d1R-R", - efscfuf_2 = "100002d2R-R", - efscfsf_2 = "100002d3R-R", - efsctui_2 = "100002d4R-R", - efsctsi_2 = "100002d5R-R", - efsctuf_2 = "100002d6R-R", - efsctsf_2 = "100002d7R-R", - efsctuiz_2 = "100002d8R-R", - efsctsiz_2 = "100002daR-R", - efststgt_3 = "100002dcXRR", - efststgt_2 = "100002dc-RR", - efststlt_3 = "100002ddXRR", - efststlt_2 = "100002dd-RR", - efststeq_3 = "100002deXRR", - efststeq_2 = "100002de-RR", - efdadd_3 = "100002e0RRR", - efdsub_3 = "100002e1RRR", - efdcfuid_2 = "100002e2R-R", - efdcfsid_2 = "100002e3R-R", - efdabs_2 = "100002e4RR", - efdnabs_2 = "100002e5RR", - efdneg_2 = "100002e6RR", - efdmul_3 = "100002e8RRR", - efddiv_3 = "100002e9RRR", - efdctuidz_2 = "100002eaR-R", - efdctsidz_2 = "100002ebR-R", - efdcmpgt_3 = "100002ecXRR", - efdcmpgt_2 = "100002ec-RR", - efdcmplt_3 = "100002edXRR", - efdcmplt_2 = "100002ed-RR", - efdcmpeq_3 = "100002eeXRR", - efdcmpeq_2 = "100002ee-RR", - efdcfs_2 = "100002efR-R", - efdcfui_2 = "100002f0R-R", - efdcfsi_2 = "100002f1R-R", - efdcfuf_2 = "100002f2R-R", - efdcfsf_2 = "100002f3R-R", - efdctui_2 = "100002f4R-R", - efdctsi_2 = "100002f5R-R", - efdctuf_2 = "100002f6R-R", - efdctsf_2 = "100002f7R-R", - efdctuiz_2 = "100002f8R-R", - efdctsiz_2 = "100002faR-R", - efdtstgt_3 = "100002fcXRR", - efdtstgt_2 = "100002fc-RR", - efdtstlt_3 = "100002fdXRR", - efdtstlt_2 = "100002fd-RR", - efdtsteq_3 = "100002feXRR", - efdtsteq_2 = "100002fe-RR", - evlddx_3 = "10000300RR0R", - evldd_2 = "10000301R8", - evldwx_3 = "10000302RR0R", - evldw_2 = "10000303R8", - evldhx_3 = "10000304RR0R", - evldh_2 = "10000305R8", - evlwhex_3 = "10000310RR0R", - evlwhe_2 = "10000311R4", - evlwhoux_3 = "10000314RR0R", - evlwhou_2 = "10000315R4", - evlwhosx_3 = "10000316RR0R", - evlwhos_2 = "10000317R4", - evstddx_3 = "10000320RR0R", - evstdd_2 = "10000321R8", - evstdwx_3 = "10000322RR0R", - evstdw_2 = "10000323R8", - evstdhx_3 = "10000324RR0R", - evstdh_2 = "10000325R8", - evstwhex_3 = "10000330RR0R", - evstwhe_2 = "10000331R4", - evstwhox_3 = "10000334RR0R", - evstwho_2 = "10000335R4", - evstwwex_3 = "10000338RR0R", - evstwwe_2 = "10000339R4", - evstwwox_3 = "1000033cRR0R", - evstwwo_2 = "1000033dR4", - evmhessf_3 = "10000403RRR", - evmhossf_3 = "10000407RRR", - evmheumi_3 = "10000408RRR", - evmhesmi_3 = "10000409RRR", - evmhesmf_3 = "1000040bRRR", - evmhoumi_3 = "1000040cRRR", - evmhosmi_3 = "1000040dRRR", - evmhosmf_3 = "1000040fRRR", - evmhessfa_3 = "10000423RRR", - evmhossfa_3 = "10000427RRR", - evmheumia_3 = "10000428RRR", - evmhesmia_3 = "10000429RRR", - evmhesmfa_3 = "1000042bRRR", - evmhoumia_3 = "1000042cRRR", - evmhosmia_3 = "1000042dRRR", - evmhosmfa_3 = "1000042fRRR", - evmwhssf_3 = "10000447RRR", - evmwlumi_3 = "10000448RRR", - evmwhumi_3 = "1000044cRRR", - evmwhsmi_3 = "1000044dRRR", - evmwhsmf_3 = "1000044fRRR", - evmwssf_3 = "10000453RRR", - evmwumi_3 = "10000458RRR", - evmwsmi_3 = "10000459RRR", - evmwsmf_3 = "1000045bRRR", - evmwhssfa_3 = "10000467RRR", - evmwlumia_3 = "10000468RRR", - evmwhumia_3 = "1000046cRRR", - evmwhsmia_3 = "1000046dRRR", - evmwhsmfa_3 = "1000046fRRR", - evmwssfa_3 = "10000473RRR", - evmwumia_3 = "10000478RRR", - evmwsmia_3 = "10000479RRR", - evmwsmfa_3 = "1000047bRRR", - evmra_2 = "100004c4RR", - evdivws_3 = "100004c6RRR", - evdivwu_3 = "100004c7RRR", - evmwssfaa_3 = "10000553RRR", - evmwumiaa_3 = "10000558RRR", - evmwsmiaa_3 = "10000559RRR", - evmwsmfaa_3 = "1000055bRRR", - evmwssfan_3 = "100005d3RRR", - evmwumian_3 = "100005d8RRR", - evmwsmian_3 = "100005d9RRR", - evmwsmfan_3 = "100005dbRRR", - evmergehilo_3 = "1000022eRRR", - evmergelohi_3 = "1000022fRRR", - evlhhesplatx_3 = "10000308RR0R", - evlhhesplat_2 = "10000309R2", - evlhhousplatx_3 = "1000030cRR0R", - evlhhousplat_2 = "1000030dR2", - evlhhossplatx_3 = "1000030eRR0R", - evlhhossplat_2 = "1000030fR2", - evlwwsplatx_3 = "10000318RR0R", - evlwwsplat_2 = "10000319R4", - evlwhsplatx_3 = "1000031cRR0R", - evlwhsplat_2 = "1000031dR4", - evaddusiaaw_2 = "100004c0RR", - evaddssiaaw_2 = "100004c1RR", - evsubfusiaaw_2 = "100004c2RR", - evsubfssiaaw_2 = "100004c3RR", - evaddumiaaw_2 = "100004c8RR", - evaddsmiaaw_2 = "100004c9RR", - evsubfumiaaw_2 = "100004caRR", - evsubfsmiaaw_2 = "100004cbRR", - evmheusiaaw_3 = "10000500RRR", - evmhessiaaw_3 = "10000501RRR", - evmhessfaaw_3 = "10000503RRR", - evmhousiaaw_3 = "10000504RRR", - evmhossiaaw_3 = "10000505RRR", - evmhossfaaw_3 = "10000507RRR", - evmheumiaaw_3 = "10000508RRR", - evmhesmiaaw_3 = "10000509RRR", - evmhesmfaaw_3 = "1000050bRRR", - evmhoumiaaw_3 = "1000050cRRR", - evmhosmiaaw_3 = "1000050dRRR", - evmhosmfaaw_3 = "1000050fRRR", - evmhegumiaa_3 = "10000528RRR", - evmhegsmiaa_3 = "10000529RRR", - evmhegsmfaa_3 = "1000052bRRR", - evmhogumiaa_3 = "1000052cRRR", - evmhogsmiaa_3 = "1000052dRRR", - evmhogsmfaa_3 = "1000052fRRR", - evmwlusiaaw_3 = "10000540RRR", - evmwlssiaaw_3 = "10000541RRR", - evmwlumiaaw_3 = "10000548RRR", - evmwlsmiaaw_3 = "10000549RRR", - evmheusianw_3 = "10000580RRR", - evmhessianw_3 = "10000581RRR", - evmhessfanw_3 = "10000583RRR", - evmhousianw_3 = "10000584RRR", - evmhossianw_3 = "10000585RRR", - evmhossfanw_3 = "10000587RRR", - evmheumianw_3 = "10000588RRR", - evmhesmianw_3 = "10000589RRR", - evmhesmfanw_3 = "1000058bRRR", - evmhoumianw_3 = "1000058cRRR", - evmhosmianw_3 = "1000058dRRR", - evmhosmfanw_3 = "1000058fRRR", - evmhegumian_3 = "100005a8RRR", - evmhegsmian_3 = "100005a9RRR", - evmhegsmfan_3 = "100005abRRR", - evmhogumian_3 = "100005acRRR", - evmhogsmian_3 = "100005adRRR", - evmhogsmfan_3 = "100005afRRR", - evmwlusianw_3 = "100005c0RRR", - evmwlssianw_3 = "100005c1RRR", - evmwlumianw_3 = "100005c8RRR", - evmwlsmianw_3 = "100005c9RRR", - - -- NYI: Book E instructions. -} - --- Add mnemonics for "." variants. -do - local t = {} - for k,v in pairs(map_op) do - if type(v) == "string" and sub(v, -1) == "." then - local v2 = sub(v, 1, 7)..char(byte(v, 8)+1)..sub(v, 9, -2) - t[sub(k, 1, -3).."."..sub(k, -2)] = v2 - end - end - for k,v in pairs(t) do - map_op[k] = v - end -end - --- Add more branch mnemonics. -for cond,c in pairs(map_cond) do - local b1 = "b"..cond - local c1 = shl(band(c, 3), 16) + (c < 4 and 0x01000000 or 0) - -- bX[l] - map_op[b1.."_1"] = tohex(0x40800000 + c1).."K" - map_op[b1.."y_1"] = tohex(0x40a00000 + c1).."K" - map_op[b1.."l_1"] = tohex(0x40800001 + c1).."K" - map_op[b1.."_2"] = tohex(0x40800000 + c1).."-XK" - map_op[b1.."y_2"] = tohex(0x40a00000 + c1).."-XK" - map_op[b1.."l_2"] = tohex(0x40800001 + c1).."-XK" - -- bXlr[l] - map_op[b1.."lr_0"] = tohex(0x4c800020 + c1) - map_op[b1.."lrl_0"] = tohex(0x4c800021 + c1) - map_op[b1.."ctr_0"] = tohex(0x4c800420 + c1) - map_op[b1.."ctrl_0"] = tohex(0x4c800421 + c1) - -- bXctr[l] - map_op[b1.."lr_1"] = tohex(0x4c800020 + c1).."-X" - map_op[b1.."lrl_1"] = tohex(0x4c800021 + c1).."-X" - map_op[b1.."ctr_1"] = tohex(0x4c800420 + c1).."-X" - map_op[b1.."ctrl_1"] = tohex(0x4c800421 + c1).."-X" -end - ------------------------------------------------------------------------------- - -local function parse_gpr(expr) - local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$") - local tp = map_type[tname or expr] - if tp then - local reg = ovreg or tp.reg - if not reg then - werror("type `"..(tname or expr).."' needs a register override") - end - expr = reg - end - local r = match(expr, "^r([1-3]?[0-9])$") - if r then - r = tonumber(r) - if r <= 31 then return r, tp end - end - werror("bad register name `"..expr.."'") -end - -local function parse_fpr(expr) - local r = match(expr, "^f([1-3]?[0-9])$") - if r then - r = tonumber(r) - if r <= 31 then return r end - end - werror("bad register name `"..expr.."'") -end - -local function parse_vr(expr) - local r = match(expr, "^v([1-3]?[0-9])$") - if r then - r = tonumber(r) - if r <= 31 then return r end - end - werror("bad register name `"..expr.."'") -end - -local function parse_vs(expr) - local r = match(expr, "^vs([1-6]?[0-9])$") - if r then - r = tonumber(r) - if r <= 63 then return r end - end - werror("bad register name `"..expr.."'") -end - -local function parse_cr(expr) - local r = match(expr, "^cr([0-7])$") - if r then return tonumber(r) end - werror("bad condition register name `"..expr.."'") -end - -local function parse_cond(expr) - local r, cond = match(expr, "^4%*cr([0-7])%+(%w%w)$") - if r then - r = tonumber(r) - local c = map_cond[cond] - if c and c < 4 then return r*4+c end - end - werror("bad condition bit name `"..expr.."'") -end - -local parse_ctx = {} - -local loadenv = setfenv and function(s) - local code = loadstring(s, "") - if code then setfenv(code, parse_ctx) end - return code -end or function(s) - return load(s, "", nil, parse_ctx) -end - --- Try to parse simple arithmetic, too, since some basic ops are aliases. -local function parse_number(n) - local x = tonumber(n) - if x then return x end - local code = loadenv("return "..n) - if code then - local ok, y = pcall(code) - if ok then return y end - end - return nil -end - -local function parse_imm(imm, bits, shift, scale, signed) - local n = parse_number(imm) - if n then - local m = sar(n, scale) - if shl(m, scale) == n then - if signed then - local s = sar(m, bits-1) - if s == 0 then return shl(m, shift) - elseif s == -1 then return shl(m + shl(1, bits), shift) end - else - if sar(m, bits) == 0 then return shl(m, shift) end - end - end - werror("out of range immediate `"..imm.."'") - elseif match(imm, "^[rfv]([1-3]?[0-9])$") or - match(imm, "^vs([1-6]?[0-9])$") or - match(imm, "^([%w_]+):(r[1-3]?[0-9])$") then - werror("expected immediate operand, got register") - else - waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) - return 0 - end -end - -local function parse_shiftmask(imm, isshift) - local n = parse_number(imm) - if n then - if shr(n, 6) == 0 then - local lsb = band(n, 31) - local msb = n - lsb - return isshift and (shl(lsb, 11)+shr(msb, 4)) or (shl(lsb, 6)+msb) - end - werror("out of range immediate `"..imm.."'") - elseif match(imm, "^r([1-3]?[0-9])$") or - match(imm, "^([%w_]+):(r[1-3]?[0-9])$") then - werror("expected immediate operand, got register") - else - waction("IMMSH", isshift and 1 or 0, imm) - return 0; - end -end - -local function parse_disp(disp) - local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$") - if imm then - local r = parse_gpr(reg) - if r == 0 then werror("cannot use r0 in displacement") end - return shl(r, 16) + parse_imm(imm, 16, 0, 0, true) - end - local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") - if reg and tailr ~= "" then - local r, tp = parse_gpr(reg) - if r == 0 then werror("cannot use r0 in displacement") end - if tp then - waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr)) - return shl(r, 16) - end - end - werror("bad displacement `"..disp.."'") -end - -local function parse_u5disp(disp, scale) - local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$") - if imm then - local r = parse_gpr(reg) - if r == 0 then werror("cannot use r0 in displacement") end - return shl(r, 16) + parse_imm(imm, 5, 11, scale, false) - end - local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") - if reg and tailr ~= "" then - local r, tp = parse_gpr(reg) - if r == 0 then werror("cannot use r0 in displacement") end - if tp then - waction("IMM", scale*1024+5*32+11, format(tp.ctypefmt, tailr)) - return shl(r, 16) - end - end - werror("bad displacement `"..disp.."'") -end - -local function parse_label(label, def) - local prefix = sub(label, 1, 2) - -- =>label (pc label reference) - if prefix == "=>" then - return "PC", 0, sub(label, 3) - end - -- ->name (global label reference) - if prefix == "->" then - return "LG", map_global[sub(label, 3)] - end - if def then - -- [1-9] (local label definition) - if match(label, "^[1-9]$") then - return "LG", 10+tonumber(label) - end - else - -- [<>][1-9] (local label reference) - local dir, lnum = match(label, "^([<>])([1-9])$") - if dir then -- Fwd: 1-9, Bkwd: 11-19. - return "LG", lnum + (dir == ">" and 0 or 10) - end - -- extern label (extern label reference) - local extname = match(label, "^extern%s+(%S+)$") - if extname then - return "EXT", map_extern[extname] - end - end - werror("bad label `"..label.."'") -end - ------------------------------------------------------------------------------- - --- Handle opcodes defined with template strings. -op_template = function(params, template, nparams) - if not params then return sub(template, 9) end - local op = tonumber(sub(template, 1, 8), 16) - local n, rs = 1, 26 - - -- Limit number of section buffer positions used by a single dasm_put(). - -- A single opcode needs a maximum of 3 positions (rlwinm). - if secpos+3 > maxsecpos then wflush() end - local pos = wpos() - - -- Process each character. - for p in gmatch(sub(template, 9), ".") do - if p == "R" then - rs = rs - 5; op = op + shl(parse_gpr(params[n]), rs); n = n + 1 - elseif p == "F" then - rs = rs - 5; op = op + shl(parse_fpr(params[n]), rs); n = n + 1 - elseif p == "V" then - rs = rs - 5; op = op + shl(parse_vr(params[n]), rs); n = n + 1 - elseif p == "Q" then - local vs = parse_vs(params[n]); n = n + 1; rs = rs - 5 - local sh = rs == 6 and 2 or 3 + band(shr(rs, 1), 3) - op = op + shl(band(vs, 31), rs) + shr(band(vs, 32), sh) - elseif p == "q" then - local vs = parse_vs(params[n]); n = n + 1 - op = op + shl(band(vs, 31), 21) + shr(band(vs, 32), 5) - elseif p == "A" then - rs = rs - 5; op = op + parse_imm(params[n], 5, rs, 0, false); n = n + 1 - elseif p == "S" then - rs = rs - 5; op = op + parse_imm(params[n], 5, rs, 0, true); n = n + 1 - elseif p == "I" then - op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1 - elseif p == "U" then - op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1 - elseif p == "D" then - op = op + parse_disp(params[n]); n = n + 1 - elseif p == "2" then - op = op + parse_u5disp(params[n], 1); n = n + 1 - elseif p == "4" then - op = op + parse_u5disp(params[n], 2); n = n + 1 - elseif p == "8" then - op = op + parse_u5disp(params[n], 3); n = n + 1 - elseif p == "C" then - rs = rs - 5; op = op + shl(parse_cond(params[n]), rs); n = n + 1 - elseif p == "X" then - rs = rs - 5; op = op + shl(parse_cr(params[n]), rs+2); n = n + 1 - elseif p == "1" then - rs = rs - 5; op = op + parse_imm(params[n], 1, rs, 0, false); n = n + 1 - elseif p == "g" then - rs = rs - 5; op = op + parse_imm(params[n], 2, rs, 0, false); n = n + 1 - elseif p == "3" then - rs = rs - 5; op = op + parse_imm(params[n], 3, rs, 0, false); n = n + 1 - elseif p == "P" then - rs = rs - 5; op = op + parse_imm(params[n], 4, rs, 0, false); n = n + 1 - elseif p == "p" then - op = op + parse_imm(params[n], 4, rs, 0, false); n = n + 1 - elseif p == "6" then - rs = rs - 6; op = op + parse_imm(params[n], 6, rs, 0, false); n = n + 1 - elseif p == "Y" then - rs = rs - 5; op = op + parse_imm(params[n], 1, rs+4, 0, false); n = n + 1 - elseif p == "y" then - rs = rs - 5; op = op + parse_imm(params[n], 1, rs+3, 0, false); n = n + 1 - elseif p == "Z" then - rs = rs - 5; op = op + parse_imm(params[n], 2, rs+3, 0, false); n = n + 1 - elseif p == "z" then - rs = rs - 5; op = op + parse_imm(params[n], 2, rs+2, 0, false); n = n + 1 - elseif p == "W" then - op = op + parse_cr(params[n]); n = n + 1 - elseif p == "G" then - op = op + parse_imm(params[n], 8, 12, 0, false); n = n + 1 - elseif p == "H" then - op = op + parse_shiftmask(params[n], true); n = n + 1 - elseif p == "M" then - op = op + parse_shiftmask(params[n], false); n = n + 1 - elseif p == "J" or p == "K" then - local mode, m, s = parse_label(params[n], false) - if p == "K" then m = m + 2048 end - waction("REL_"..mode, m, s, 1) - n = n + 1 - elseif p == "0" then - if band(shr(op, rs), 31) == 0 then werror("cannot use r0") end - elseif p == "=" or p == "%" then - local t = band(shr(op, p == "%" and rs+5 or rs), 31) - rs = rs - 5 - op = op + shl(t, rs) - elseif p == "~" then - local mm = shl(31, rs) - local lo = band(op, mm) - local hi = band(op, shl(mm, 5)) - op = op - lo - hi + shl(lo, 5) + shr(hi, 5) - elseif p == ":" then - if band(shr(op, rs), 1) ~= 0 then werror("register pair expected") end - elseif p == "-" then - rs = rs - 5 - elseif p == "." then - -- Ignored. - else - assert(false) - end - end - wputpos(pos, op) -end - -map_op[".template__"] = op_template - ------------------------------------------------------------------------------- - --- Pseudo-opcode to mark the position where the action list is to be emitted. -map_op[".actionlist_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeactions(out, name) end) -end - --- Pseudo-opcode to mark the position where the global enum is to be emitted. -map_op[".globals_1"] = function(params) - if not params then return "prefix" end - local prefix = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeglobals(out, prefix) end) -end - --- Pseudo-opcode to mark the position where the global names are to be emitted. -map_op[".globalnames_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeglobalnames(out, name) end) -end - --- Pseudo-opcode to mark the position where the extern names are to be emitted. -map_op[".externnames_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeexternnames(out, name) end) -end - ------------------------------------------------------------------------------- - --- Label pseudo-opcode (converted from trailing colon form). -map_op[".label_1"] = function(params) - if not params then return "[1-9] | ->global | =>pcexpr" end - if secpos+1 > maxsecpos then wflush() end - local mode, n, s = parse_label(params[1], true) - if mode == "EXT" then werror("bad label definition") end - waction("LABEL_"..mode, n, s, 1) -end - ------------------------------------------------------------------------------- - --- Pseudo-opcodes for data storage. -map_op[".long_*"] = function(params) - if not params then return "imm..." end - for _,p in ipairs(params) do - local n = tonumber(p) - if not n then werror("bad immediate `"..p.."'") end - if n < 0 then n = n + 2^32 end - wputw(n) - if secpos+2 > maxsecpos then wflush() end - end -end - --- Alignment pseudo-opcode. -map_op[".align_1"] = function(params) - if not params then return "numpow2" end - if secpos+1 > maxsecpos then wflush() end - local align = tonumber(params[1]) - if align then - local x = align - -- Must be a power of 2 in the range (2 ... 256). - for i=1,8 do - x = x / 2 - if x == 1 then - waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. - return - end - end - end - werror("bad alignment") -end - ------------------------------------------------------------------------------- - --- Pseudo-opcode for (primitive) type definitions (map to C types). -map_op[".type_3"] = function(params, nparams) - if not params then - return nparams == 2 and "name, ctype" or "name, ctype, reg" - end - local name, ctype, reg = params[1], params[2], params[3] - if not match(name, "^[%a_][%w_]*$") then - werror("bad type name `"..name.."'") - end - local tp = map_type[name] - if tp then - werror("duplicate type `"..name.."'") - end - -- Add #type to defines. A bit unclean to put it in map_archdef. - map_archdef["#"..name] = "sizeof("..ctype..")" - -- Add new type and emit shortcut define. - local num = ctypenum + 1 - map_type[name] = { - ctype = ctype, - ctypefmt = format("Dt%X(%%s)", num), - reg = reg, - } - wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) - ctypenum = num -end -map_op[".type_2"] = map_op[".type_3"] - --- Dump type definitions. -local function dumptypes(out, lvl) - local t = {} - for name in pairs(map_type) do t[#t+1] = name end - sort(t) - out:write("Type definitions:\n") - for _,name in ipairs(t) do - local tp = map_type[name] - local reg = tp.reg or "" - out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) - end - out:write("\n") -end - ------------------------------------------------------------------------------- - --- Set the current section. -function _M.section(num) - waction("SECTION", num) - wflush(true) -- SECTION is a terminal action. -end - ------------------------------------------------------------------------------- - --- Dump architecture description. -function _M.dumparch(out) - out:write(format("DynASM %s version %s, released %s\n\n", - _info.arch, _info.version, _info.release)) - dumpactions(out) -end - --- Dump all user defined elements. -function _M.dumpdef(out, lvl) - dumptypes(out, lvl) - dumpglobals(out, lvl) - dumpexterns(out, lvl) -end - ------------------------------------------------------------------------------- - --- Pass callbacks from/to the DynASM core. -function _M.passcb(wl, we, wf, ww) - wline, werror, wfatal, wwarn = wl, we, wf, ww - return wflush -end - --- Setup the arch-specific module. -function _M.setup(arch, opt) - g_arch, g_opt = arch, opt -end - --- Merge the core maps and the arch-specific maps. -function _M.mergemaps(map_coreop, map_def) - setmetatable(map_op, { __index = map_coreop }) - setmetatable(map_def, { __index = map_archdef }) - return map_op, map_def -end - -return _M - ------------------------------------------------------------------------------- - diff --git a/lib/LuaJIT/dynasm/dasm_proto.h b/lib/LuaJIT/dynasm/dasm_proto.h deleted file mode 100644 index 59d9e2b..0000000 --- a/lib/LuaJIT/dynasm/dasm_proto.h +++ /dev/null @@ -1,83 +0,0 @@ -/* -** DynASM encoding engine prototypes. -** Copyright (C) 2005-2017 Mike Pall. All rights reserved. -** Released under the MIT license. See dynasm.lua for full copyright notice. -*/ - -#ifndef _DASM_PROTO_H -#define _DASM_PROTO_H - -#include -#include - -#define DASM_IDENT "DynASM 1.4.0" -#define DASM_VERSION 10400 /* 1.4.0 */ - -#ifndef Dst_DECL -#define Dst_DECL dasm_State **Dst -#endif - -#ifndef Dst_REF -#define Dst_REF (*Dst) -#endif - -#ifndef DASM_FDEF -#define DASM_FDEF extern -#endif - -#ifndef DASM_M_GROW -#define DASM_M_GROW(ctx, t, p, sz, need) \ - do { \ - size_t _sz = (sz), _need = (need); \ - if (_sz < _need) { \ - if (_sz < 16) _sz = 16; \ - while (_sz < _need) _sz += _sz; \ - (p) = (t *)realloc((p), _sz); \ - if ((p) == NULL) exit(1); \ - (sz) = _sz; \ - } \ - } while(0) -#endif - -#ifndef DASM_M_FREE -#define DASM_M_FREE(ctx, p, sz) free(p) -#endif - -/* Internal DynASM encoder state. */ -typedef struct dasm_State dasm_State; - - -/* Initialize and free DynASM state. */ -DASM_FDEF void dasm_init(Dst_DECL, int maxsection); -DASM_FDEF void dasm_free(Dst_DECL); - -/* Setup global array. Must be called before dasm_setup(). */ -DASM_FDEF void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl); - -/* Grow PC label array. Can be called after dasm_setup(), too. */ -DASM_FDEF void dasm_growpc(Dst_DECL, unsigned int maxpc); - -/* Setup encoder. */ -DASM_FDEF void dasm_setup(Dst_DECL, const void *actionlist); - -/* Feed encoder with actions. Calls are generated by pre-processor. */ -DASM_FDEF void dasm_put(Dst_DECL, int start, ...); - -/* Link sections and return the resulting size. */ -DASM_FDEF int dasm_link(Dst_DECL, size_t *szp); - -/* Encode sections into buffer. */ -DASM_FDEF int dasm_encode(Dst_DECL, void *buffer); - -/* Get PC label offset. */ -DASM_FDEF int dasm_getpclabel(Dst_DECL, unsigned int pc); - -#ifdef DASM_CHECKS -/* Optional sanity checker to call between isolated encoding steps. */ -DASM_FDEF int dasm_checkstep(Dst_DECL, int secmatch); -#else -#define dasm_checkstep(a, b) 0 -#endif - - -#endif /* _DASM_PROTO_H */ diff --git a/lib/LuaJIT/dynasm/dasm_x64.lua b/lib/LuaJIT/dynasm/dasm_x64.lua deleted file mode 100644 index e8bdeb3..0000000 --- a/lib/LuaJIT/dynasm/dasm_x64.lua +++ /dev/null @@ -1,12 +0,0 @@ ------------------------------------------------------------------------------- --- DynASM x64 module. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------- --- This module just sets 64 bit mode for the combined x86/x64 module. --- All the interesting stuff is there. ------------------------------------------------------------------------------- - -x64 = true -- Using a global is an ugly, but effective solution. -return require("dasm_x86") diff --git a/lib/LuaJIT/dynasm/dasm_x86.h b/lib/LuaJIT/dynasm/dasm_x86.h deleted file mode 100644 index dc14d88..0000000 --- a/lib/LuaJIT/dynasm/dasm_x86.h +++ /dev/null @@ -1,509 +0,0 @@ -/* -** DynASM x86 encoding engine. -** Copyright (C) 2005-2017 Mike Pall. All rights reserved. -** Released under the MIT license. See dynasm.lua for full copyright notice. -*/ - -#include -#include -#include -#include - -#define DASM_ARCH "x86" - -#ifndef DASM_EXTERN -#define DASM_EXTERN(a,b,c,d) 0 -#endif - -/* Action definitions. DASM_STOP must be 255. */ -enum { - DASM_DISP = 233, - DASM_IMM_S, DASM_IMM_B, DASM_IMM_W, DASM_IMM_D, DASM_IMM_WB, DASM_IMM_DB, - DASM_VREG, DASM_SPACE, DASM_SETLABEL, DASM_REL_A, DASM_REL_LG, DASM_REL_PC, - DASM_IMM_LG, DASM_IMM_PC, DASM_LABEL_LG, DASM_LABEL_PC, DASM_ALIGN, - DASM_EXTERN, DASM_ESC, DASM_MARK, DASM_SECTION, DASM_STOP -}; - -/* Maximum number of section buffer positions for a single dasm_put() call. */ -#define DASM_MAXSECPOS 25 - -/* DynASM encoder status codes. Action list offset or number are or'ed in. */ -#define DASM_S_OK 0x00000000 -#define DASM_S_NOMEM 0x01000000 -#define DASM_S_PHASE 0x02000000 -#define DASM_S_MATCH_SEC 0x03000000 -#define DASM_S_RANGE_I 0x11000000 -#define DASM_S_RANGE_SEC 0x12000000 -#define DASM_S_RANGE_LG 0x13000000 -#define DASM_S_RANGE_PC 0x14000000 -#define DASM_S_RANGE_VREG 0x15000000 -#define DASM_S_UNDEF_L 0x21000000 -#define DASM_S_UNDEF_PC 0x22000000 - -/* Macros to convert positions (8 bit section + 24 bit index). */ -#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) -#define DASM_POS2BIAS(pos) ((pos)&0xff000000) -#define DASM_SEC2POS(sec) ((sec)<<24) -#define DASM_POS2SEC(pos) ((pos)>>24) -#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) - -/* Action list type. */ -typedef const unsigned char *dasm_ActList; - -/* Per-section structure. */ -typedef struct dasm_Section { - int *rbuf; /* Biased buffer pointer (negative section bias). */ - int *buf; /* True buffer pointer. */ - size_t bsize; /* Buffer size in bytes. */ - int pos; /* Biased buffer position. */ - int epos; /* End of biased buffer position - max single put. */ - int ofs; /* Byte offset into section. */ -} dasm_Section; - -/* Core structure holding the DynASM encoding state. */ -struct dasm_State { - size_t psize; /* Allocated size of this structure. */ - dasm_ActList actionlist; /* Current actionlist pointer. */ - int *lglabels; /* Local/global chain/pos ptrs. */ - size_t lgsize; - int *pclabels; /* PC label chains/pos ptrs. */ - size_t pcsize; - void **globals; /* Array of globals (bias -10). */ - dasm_Section *section; /* Pointer to active section. */ - size_t codesize; /* Total size of all code sections. */ - int maxsection; /* 0 <= sectionidx < maxsection. */ - int status; /* Status code. */ - dasm_Section sections[1]; /* All sections. Alloc-extended. */ -}; - -/* The size of the core structure depends on the max. number of sections. */ -#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) - - -/* Initialize DynASM state. */ -void dasm_init(Dst_DECL, int maxsection) -{ - dasm_State *D; - size_t psz = 0; - int i; - Dst_REF = NULL; - DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); - D = Dst_REF; - D->psize = psz; - D->lglabels = NULL; - D->lgsize = 0; - D->pclabels = NULL; - D->pcsize = 0; - D->globals = NULL; - D->maxsection = maxsection; - for (i = 0; i < maxsection; i++) { - D->sections[i].buf = NULL; /* Need this for pass3. */ - D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); - D->sections[i].bsize = 0; - D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ - } -} - -/* Free DynASM state. */ -void dasm_free(Dst_DECL) -{ - dasm_State *D = Dst_REF; - int i; - for (i = 0; i < D->maxsection; i++) - if (D->sections[i].buf) - DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); - if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); - if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); - DASM_M_FREE(Dst, D, D->psize); -} - -/* Setup global label array. Must be called before dasm_setup(). */ -void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) -{ - dasm_State *D = Dst_REF; - D->globals = gl - 10; /* Negative bias to compensate for locals. */ - DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); -} - -/* Grow PC label array. Can be called after dasm_setup(), too. */ -void dasm_growpc(Dst_DECL, unsigned int maxpc) -{ - dasm_State *D = Dst_REF; - size_t osz = D->pcsize; - DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); - memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); -} - -/* Setup encoder. */ -void dasm_setup(Dst_DECL, const void *actionlist) -{ - dasm_State *D = Dst_REF; - int i; - D->actionlist = (dasm_ActList)actionlist; - D->status = DASM_S_OK; - D->section = &D->sections[0]; - memset((void *)D->lglabels, 0, D->lgsize); - if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); - for (i = 0; i < D->maxsection; i++) { - D->sections[i].pos = DASM_SEC2POS(i); - D->sections[i].ofs = 0; - } -} - - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) { \ - D->status = DASM_S_##st|(int)(p-D->actionlist-1); return; } } while (0) -#define CKPL(kind, st) \ - do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ - D->status=DASM_S_RANGE_##st|(int)(p-D->actionlist-1); return; } } while (0) -#else -#define CK(x, st) ((void)0) -#define CKPL(kind, st) ((void)0) -#endif - -/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ -void dasm_put(Dst_DECL, int start, ...) -{ - va_list ap; - dasm_State *D = Dst_REF; - dasm_ActList p = D->actionlist + start; - dasm_Section *sec = D->section; - int pos = sec->pos, ofs = sec->ofs, mrm = -1; - int *b; - - if (pos >= sec->epos) { - DASM_M_GROW(Dst, int, sec->buf, sec->bsize, - sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); - sec->rbuf = sec->buf - DASM_POS2BIAS(pos); - sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); - } - - b = sec->rbuf; - b[pos++] = start; - - va_start(ap, start); - while (1) { - int action = *p++; - if (action < DASM_DISP) { - ofs++; - } else if (action <= DASM_REL_A) { - int n = va_arg(ap, int); - b[pos++] = n; - switch (action) { - case DASM_DISP: - if (n == 0) { if (mrm < 0) mrm = p[-2]; if ((mrm&7) != 5) break; } - /* fallthrough */ - case DASM_IMM_DB: if (((n+128)&-256) == 0) goto ob; /* fallthrough */ - case DASM_REL_A: /* Assumes ptrdiff_t is int. !x64 */ - case DASM_IMM_D: ofs += 4; break; - case DASM_IMM_S: CK(((n+128)&-256) == 0, RANGE_I); goto ob; - case DASM_IMM_B: CK((n&-256) == 0, RANGE_I); ob: ofs++; break; - case DASM_IMM_WB: if (((n+128)&-256) == 0) goto ob; /* fallthrough */ - case DASM_IMM_W: CK((n&-65536) == 0, RANGE_I); ofs += 2; break; - case DASM_SPACE: p++; ofs += n; break; - case DASM_SETLABEL: b[pos-2] = -0x40000000; break; /* Neg. label ofs. */ - case DASM_VREG: CK((n&-16) == 0 && (n != 4 || (*p>>5) != 2), RANGE_VREG); - if (*p < 0x40 && p[1] == DASM_DISP) mrm = n; - if (*p < 0x20 && (n&7) == 4) ofs++; - switch ((*p++ >> 3) & 3) { - case 3: n |= b[pos-3]; /* fallthrough */ - case 2: n |= b[pos-2]; /* fallthrough */ - case 1: if (n <= 7) { b[pos-1] |= 0x10; ofs--; } - } - continue; - } - mrm = -1; - } else { - int *pl, n; - switch (action) { - case DASM_REL_LG: - case DASM_IMM_LG: - n = *p++; pl = D->lglabels + n; - /* Bkwd rel or global. */ - if (n <= 246) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } - pl -= 246; n = *pl; - if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ - goto linkrel; - case DASM_REL_PC: - case DASM_IMM_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC); - putrel: - n = *pl; - if (n < 0) { /* Label exists. Get label pos and store it. */ - b[pos] = -n; - } else { - linkrel: - b[pos] = n; /* Else link to rel chain, anchored at label. */ - *pl = pos; - } - pos++; - ofs += 4; /* Maximum offset needed. */ - if (action == DASM_REL_LG || action == DASM_REL_PC) - b[pos++] = ofs; /* Store pass1 offset estimate. */ - break; - case DASM_LABEL_LG: pl = D->lglabels + *p++; CKPL(lg, LG); goto putlabel; - case DASM_LABEL_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC); - putlabel: - n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; } - *pl = -pos; /* Label exists now. */ - b[pos++] = ofs; /* Store pass1 offset estimate. */ - break; - case DASM_ALIGN: - ofs += *p++; /* Maximum alignment needed (arg is 2**n-1). */ - b[pos++] = ofs; /* Store pass1 offset estimate. */ - break; - case DASM_EXTERN: p += 2; ofs += 4; break; - case DASM_ESC: p++; ofs++; break; - case DASM_MARK: mrm = p[-2]; break; - case DASM_SECTION: - n = *p; CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n]; - case DASM_STOP: goto stop; - } - } - } -stop: - va_end(ap); - sec->pos = pos; - sec->ofs = ofs; -} -#undef CK - -/* Pass 2: Link sections, shrink branches/aligns, fix label offsets. */ -int dasm_link(Dst_DECL, size_t *szp) -{ - dasm_State *D = Dst_REF; - int secnum; - int ofs = 0; - -#ifdef DASM_CHECKS - *szp = 0; - if (D->status != DASM_S_OK) return D->status; - { - int pc; - for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) - if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; - } -#endif - - { /* Handle globals not defined in this translation unit. */ - int idx; - for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) { - int n = D->lglabels[idx]; - /* Undefined label: Collapse rel chain and replace with marker (< 0). */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } - } - } - - /* Combine all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->rbuf; - int pos = DASM_SEC2POS(secnum); - int lastpos = sec->pos; - - while (pos != lastpos) { - dasm_ActList p = D->actionlist + b[pos++]; - while (1) { - int op, action = *p++; - switch (action) { - case DASM_REL_LG: p++; op = p[-3]; goto rel_pc; - case DASM_REL_PC: op = p[-2]; rel_pc: { - int shrink = op == 0xe9 ? 3 : ((op&0xf0) == 0x80 ? 4 : 0); - if (shrink) { /* Shrinkable branch opcode? */ - int lofs, lpos = b[pos]; - if (lpos < 0) goto noshrink; /* Ext global? */ - lofs = *DASM_POS2PTR(D, lpos); - if (lpos > pos) { /* Fwd label: add cumulative section offsets. */ - int i; - for (i = secnum; i < DASM_POS2SEC(lpos); i++) - lofs += D->sections[i].ofs; - } else { - lofs -= ofs; /* Bkwd label: unfix offset. */ - } - lofs -= b[pos+1]; /* Short branch ok? */ - if (lofs >= -128-shrink && lofs <= 127) ofs -= shrink; /* Yes. */ - else { noshrink: shrink = 0; } /* No, cannot shrink op. */ - } - b[pos+1] = shrink; - pos += 2; - break; - } - /* fallthrough */ - case DASM_SPACE: case DASM_IMM_LG: case DASM_VREG: p++; - /* fallthrough */ - case DASM_DISP: case DASM_IMM_S: case DASM_IMM_B: case DASM_IMM_W: - case DASM_IMM_D: case DASM_IMM_WB: case DASM_IMM_DB: - case DASM_SETLABEL: case DASM_REL_A: case DASM_IMM_PC: pos++; break; - case DASM_LABEL_LG: p++; - /* fallthrough */ - case DASM_LABEL_PC: b[pos++] += ofs; break; /* Fix label offset. */ - case DASM_ALIGN: ofs -= (b[pos++]+ofs)&*p++; break; /* Adjust ofs. */ - case DASM_EXTERN: p += 2; break; - case DASM_ESC: p++; break; - case DASM_MARK: break; - case DASM_SECTION: case DASM_STOP: goto stop; - } - } - stop: (void)0; - } - ofs += sec->ofs; /* Next section starts right after current section. */ - } - - D->codesize = ofs; /* Total size of all code sections */ - *szp = ofs; - return DASM_S_OK; -} - -#define dasmb(x) *cp++ = (unsigned char)(x) -#ifndef DASM_ALIGNED_WRITES -#define dasmw(x) \ - do { *((unsigned short *)cp) = (unsigned short)(x); cp+=2; } while (0) -#define dasmd(x) \ - do { *((unsigned int *)cp) = (unsigned int)(x); cp+=4; } while (0) -#else -#define dasmw(x) do { dasmb(x); dasmb((x)>>8); } while (0) -#define dasmd(x) do { dasmw(x); dasmw((x)>>16); } while (0) -#endif - -/* Pass 3: Encode sections. */ -int dasm_encode(Dst_DECL, void *buffer) -{ - dasm_State *D = Dst_REF; - unsigned char *base = (unsigned char *)buffer; - unsigned char *cp = base; - int secnum; - - /* Encode all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->buf; - int *endb = sec->rbuf + sec->pos; - - while (b != endb) { - dasm_ActList p = D->actionlist + *b++; - unsigned char *mark = NULL; - while (1) { - int action = *p++; - int n = (action >= DASM_DISP && action <= DASM_ALIGN) ? *b++ : 0; - switch (action) { - case DASM_DISP: if (!mark) mark = cp; { - unsigned char *mm = mark; - if (*p != DASM_IMM_DB && *p != DASM_IMM_WB) mark = NULL; - if (n == 0) { int mrm = mm[-1]&7; if (mrm == 4) mrm = mm[0]&7; - if (mrm != 5) { mm[-1] -= 0x80; break; } } - if (((n+128) & -256) != 0) goto wd; else mm[-1] -= 0x40; - } - /* fallthrough */ - case DASM_IMM_S: case DASM_IMM_B: wb: dasmb(n); break; - case DASM_IMM_DB: if (((n+128)&-256) == 0) { - db: if (!mark) mark = cp; mark[-2] += 2; mark = NULL; goto wb; - } else mark = NULL; - /* fallthrough */ - case DASM_IMM_D: wd: dasmd(n); break; - case DASM_IMM_WB: if (((n+128)&-256) == 0) goto db; else mark = NULL; - /* fallthrough */ - case DASM_IMM_W: dasmw(n); break; - case DASM_VREG: { - int t = *p++; - unsigned char *ex = cp - (t&7); - if ((n & 8) && t < 0xa0) { - if (*ex & 0x80) ex[1] ^= 0x20 << (t>>6); else *ex ^= 1 << (t>>6); - n &= 7; - } else if (n & 0x10) { - if (*ex & 0x80) { - *ex = 0xc5; ex[1] = (ex[1] & 0x80) | ex[2]; ex += 2; - } - while (++ex < cp) ex[-1] = *ex; - if (mark) mark--; - cp--; - n &= 7; - } - if (t >= 0xc0) n <<= 4; - else if (t >= 0x40) n <<= 3; - else if (n == 4 && t < 0x20) { cp[-1] ^= n; *cp++ = 0x20; } - cp[-1] ^= n; - break; - } - case DASM_REL_LG: p++; if (n >= 0) goto rel_pc; - b++; n = (int)(ptrdiff_t)D->globals[-n]; - /* fallthrough */ - case DASM_REL_A: rel_a: - n -= (unsigned int)(ptrdiff_t)(cp+4); goto wd; /* !x64 */ - case DASM_REL_PC: rel_pc: { - int shrink = *b++; - int *pb = DASM_POS2PTR(D, n); if (*pb < 0) { n = pb[1]; goto rel_a; } - n = *pb - ((int)(cp-base) + 4-shrink); - if (shrink == 0) goto wd; - if (shrink == 4) { cp--; cp[-1] = *cp-0x10; } else cp[-1] = 0xeb; - goto wb; - } - case DASM_IMM_LG: - p++; if (n < 0) { n = (int)(ptrdiff_t)D->globals[-n]; goto wd; } - /* fallthrough */ - case DASM_IMM_PC: { - int *pb = DASM_POS2PTR(D, n); - n = *pb < 0 ? pb[1] : (*pb + (int)(ptrdiff_t)base); - goto wd; - } - case DASM_LABEL_LG: { - int idx = *p++; - if (idx >= 10) - D->globals[idx] = (void *)(base + (*p == DASM_SETLABEL ? *b : n)); - break; - } - case DASM_LABEL_PC: case DASM_SETLABEL: break; - case DASM_SPACE: { int fill = *p++; while (n--) *cp++ = fill; break; } - case DASM_ALIGN: - n = *p++; - while (((cp-base) & n)) *cp++ = 0x90; /* nop */ - break; - case DASM_EXTERN: n = DASM_EXTERN(Dst, cp, p[1], *p); p += 2; goto wd; - case DASM_MARK: mark = cp; break; - case DASM_ESC: action = *p++; - /* fallthrough */ - default: *cp++ = action; break; - case DASM_SECTION: case DASM_STOP: goto stop; - } - } - stop: (void)0; - } - } - - if (base + D->codesize != cp) /* Check for phase errors. */ - return DASM_S_PHASE; - return DASM_S_OK; -} - -/* Get PC label offset. */ -int dasm_getpclabel(Dst_DECL, unsigned int pc) -{ - dasm_State *D = Dst_REF; - if (pc*sizeof(int) < D->pcsize) { - int pos = D->pclabels[pc]; - if (pos < 0) return *DASM_POS2PTR(D, -pos); - if (pos > 0) return -1; /* Undefined. */ - } - return -2; /* Unused or out of range. */ -} - -#ifdef DASM_CHECKS -/* Optional sanity checker to call between isolated encoding steps. */ -int dasm_checkstep(Dst_DECL, int secmatch) -{ - dasm_State *D = Dst_REF; - if (D->status == DASM_S_OK) { - int i; - for (i = 1; i <= 9; i++) { - if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_L|i; break; } - D->lglabels[i] = 0; - } - } - if (D->status == DASM_S_OK && secmatch >= 0 && - D->section != &D->sections[secmatch]) - D->status = DASM_S_MATCH_SEC|(int)(D->section-D->sections); - return D->status; -} -#endif - diff --git a/lib/LuaJIT/dynasm/dasm_x86.lua b/lib/LuaJIT/dynasm/dasm_x86.lua deleted file mode 100644 index 7f536af..0000000 --- a/lib/LuaJIT/dynasm/dasm_x86.lua +++ /dev/null @@ -1,2360 +0,0 @@ ------------------------------------------------------------------------------- --- DynASM x86/x64 module. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------- - -local x64 = x64 - --- Module information: -local _info = { - arch = x64 and "x64" or "x86", - description = "DynASM x86/x64 module", - version = "1.4.0", - vernum = 10400, - release = "2015-10-18", - author = "Mike Pall", - license = "MIT", -} - --- Exported glue functions for the arch-specific module. -local _M = { _info = _info } - --- Cache library functions. -local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs -local assert, unpack, setmetatable = assert, unpack or table.unpack, setmetatable -local _s = string -local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char -local find, match, gmatch, gsub = _s.find, _s.match, _s.gmatch, _s.gsub -local concat, sort, remove = table.concat, table.sort, table.remove -local bit = bit or require("bit") -local band, bxor, shl, shr = bit.band, bit.bxor, bit.lshift, bit.rshift - --- Inherited tables and callbacks. -local g_opt, g_arch -local wline, werror, wfatal, wwarn - --- Action name list. --- CHECK: Keep this in sync with the C code! -local action_names = { - -- int arg, 1 buffer pos: - "DISP", "IMM_S", "IMM_B", "IMM_W", "IMM_D", "IMM_WB", "IMM_DB", - -- action arg (1 byte), int arg, 1 buffer pos (reg/num): - "VREG", "SPACE", - -- ptrdiff_t arg, 1 buffer pos (address): !x64 - "SETLABEL", "REL_A", - -- action arg (1 byte) or int arg, 2 buffer pos (link, offset): - "REL_LG", "REL_PC", - -- action arg (1 byte) or int arg, 1 buffer pos (link): - "IMM_LG", "IMM_PC", - -- action arg (1 byte) or int arg, 1 buffer pos (offset): - "LABEL_LG", "LABEL_PC", - -- action arg (1 byte), 1 buffer pos (offset): - "ALIGN", - -- action args (2 bytes), no buffer pos. - "EXTERN", - -- action arg (1 byte), no buffer pos. - "ESC", - -- no action arg, no buffer pos. - "MARK", - -- action arg (1 byte), no buffer pos, terminal action: - "SECTION", - -- no args, no buffer pos, terminal action: - "STOP" -} - --- Maximum number of section buffer positions for dasm_put(). --- CHECK: Keep this in sync with the C code! -local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. - --- Action name -> action number (dynamically generated below). -local map_action = {} --- First action number. Everything below does not need to be escaped. -local actfirst = 256-#action_names - --- Action list buffer and string (only used to remove dupes). -local actlist = {} -local actstr = "" - --- Argument list for next dasm_put(). Start with offset 0 into action list. -local actargs = { 0 } - --- Current number of section buffer positions for dasm_put(). -local secpos = 1 - --- VREG kind encodings, pre-shifted by 5 bits. -local map_vreg = { - ["modrm.rm.m"] = 0x00, - ["modrm.rm.r"] = 0x20, - ["opcode"] = 0x20, - ["sib.base"] = 0x20, - ["sib.index"] = 0x40, - ["modrm.reg"] = 0x80, - ["vex.v"] = 0xa0, - ["imm.hi"] = 0xc0, -} - --- Current number of VREG actions contributing to REX/VEX shrinkage. -local vreg_shrink_count = 0 - ------------------------------------------------------------------------------- - --- Compute action numbers for action names. -for n,name in ipairs(action_names) do - local num = actfirst + n - 1 - map_action[name] = num -end - --- Dump action names and numbers. -local function dumpactions(out) - out:write("DynASM encoding engine action codes:\n") - for n,name in ipairs(action_names) do - local num = map_action[name] - out:write(format(" %-10s %02X %d\n", name, num, num)) - end - out:write("\n") -end - --- Write action list buffer as a huge static C array. -local function writeactions(out, name) - local nn = #actlist - local last = actlist[nn] or 255 - actlist[nn] = nil -- Remove last byte. - if nn == 0 then nn = 1 end - out:write("static const unsigned char ", name, "[", nn, "] = {\n") - local s = " " - for n,b in ipairs(actlist) do - s = s..b.."," - if #s >= 75 then - assert(out:write(s, "\n")) - s = " " - end - end - out:write(s, last, "\n};\n\n") -- Add last byte back. -end - ------------------------------------------------------------------------------- - --- Add byte to action list. -local function wputxb(n) - assert(n >= 0 and n <= 255 and n % 1 == 0, "byte out of range") - actlist[#actlist+1] = n -end - --- Add action to list with optional arg. Advance buffer pos, too. -local function waction(action, a, num) - wputxb(assert(map_action[action], "bad action name `"..action.."'")) - if a then actargs[#actargs+1] = a end - if a or num then secpos = secpos + (num or 1) end -end - --- Optionally add a VREG action. -local function wvreg(kind, vreg, psz, sk, defer) - if not vreg then return end - waction("VREG", vreg) - local b = assert(map_vreg[kind], "bad vreg kind `"..vreg.."'") - if b < (sk or 0) then - vreg_shrink_count = vreg_shrink_count + 1 - end - if not defer then - b = b + vreg_shrink_count * 8 - vreg_shrink_count = 0 - end - wputxb(b + (psz or 0)) -end - --- Add call to embedded DynASM C code. -local function wcall(func, args) - wline(format("dasm_%s(Dst, %s);", func, concat(args, ", ")), true) -end - --- Delete duplicate action list chunks. A tad slow, but so what. -local function dedupechunk(offset) - local al, as = actlist, actstr - local chunk = char(unpack(al, offset+1, #al)) - local orig = find(as, chunk, 1, true) - if orig then - actargs[1] = orig-1 -- Replace with original offset. - for i=offset+1,#al do al[i] = nil end -- Kill dupe. - else - actstr = as..chunk - end -end - --- Flush action list (intervening C code or buffer pos overflow). -local function wflush(term) - local offset = actargs[1] - if #actlist == offset then return end -- Nothing to flush. - if not term then waction("STOP") end -- Terminate action list. - dedupechunk(offset) - wcall("put", actargs) -- Add call to dasm_put(). - actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). - secpos = 1 -- The actionlist offset occupies a buffer position, too. -end - --- Put escaped byte. -local function wputb(n) - if n >= actfirst then waction("ESC") end -- Need to escape byte. - wputxb(n) -end - ------------------------------------------------------------------------------- - --- Global label name -> global label number. With auto assignment on 1st use. -local next_global = 10 -local map_global = setmetatable({}, { __index = function(t, name) - if not match(name, "^[%a_][%w_@]*$") then werror("bad global label") end - local n = next_global - if n > 246 then werror("too many global labels") end - next_global = n + 1 - t[name] = n - return n -end}) - --- Dump global labels. -local function dumpglobals(out, lvl) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("Global labels:\n") - for i=10,next_global-1 do - out:write(format(" %s\n", t[i])) - end - out:write("\n") -end - --- Write global label enum. -local function writeglobals(out, prefix) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("enum {\n") - for i=10,next_global-1 do - out:write(" ", prefix, gsub(t[i], "@.*", ""), ",\n") - end - out:write(" ", prefix, "_MAX\n};\n") -end - --- Write global label names. -local function writeglobalnames(out, name) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("static const char *const ", name, "[] = {\n") - for i=10,next_global-1 do - out:write(" \"", t[i], "\",\n") - end - out:write(" (const char *)0\n};\n") -end - ------------------------------------------------------------------------------- - --- Extern label name -> extern label number. With auto assignment on 1st use. -local next_extern = -1 -local map_extern = setmetatable({}, { __index = function(t, name) - -- No restrictions on the name for now. - local n = next_extern - if n < -256 then werror("too many extern labels") end - next_extern = n - 1 - t[name] = n - return n -end}) - --- Dump extern labels. -local function dumpexterns(out, lvl) - local t = {} - for name, n in pairs(map_extern) do t[-n] = name end - out:write("Extern labels:\n") - for i=1,-next_extern-1 do - out:write(format(" %s\n", t[i])) - end - out:write("\n") -end - --- Write extern label names. -local function writeexternnames(out, name) - local t = {} - for name, n in pairs(map_extern) do t[-n] = name end - out:write("static const char *const ", name, "[] = {\n") - for i=1,-next_extern-1 do - out:write(" \"", t[i], "\",\n") - end - out:write(" (const char *)0\n};\n") -end - ------------------------------------------------------------------------------- - --- Arch-specific maps. -local map_archdef = {} -- Ext. register name -> int. name. -local map_reg_rev = {} -- Int. register name -> ext. name. -local map_reg_num = {} -- Int. register name -> register number. -local map_reg_opsize = {} -- Int. register name -> operand size. -local map_reg_valid_base = {} -- Int. register name -> valid base register? -local map_reg_valid_index = {} -- Int. register name -> valid index register? -local map_reg_needrex = {} -- Int. register name -> need rex vs. no rex. -local reg_list = {} -- Canonical list of int. register names. - -local map_type = {} -- Type name -> { ctype, reg } -local ctypenum = 0 -- Type number (for _PTx macros). - -local addrsize = x64 and "q" or "d" -- Size for address operands. - --- Helper functions to fill register maps. -local function mkrmap(sz, cl, names) - local cname = format("@%s", sz) - reg_list[#reg_list+1] = cname - map_archdef[cl] = cname - map_reg_rev[cname] = cl - map_reg_num[cname] = -1 - map_reg_opsize[cname] = sz - if sz == addrsize or sz == "d" then - map_reg_valid_base[cname] = true - map_reg_valid_index[cname] = true - end - if names then - for n,name in ipairs(names) do - local iname = format("@%s%x", sz, n-1) - reg_list[#reg_list+1] = iname - map_archdef[name] = iname - map_reg_rev[iname] = name - map_reg_num[iname] = n-1 - map_reg_opsize[iname] = sz - if sz == "b" and n > 4 then map_reg_needrex[iname] = false end - if sz == addrsize or sz == "d" then - map_reg_valid_base[iname] = true - map_reg_valid_index[iname] = true - end - end - end - for i=0,(x64 and sz ~= "f") and 15 or 7 do - local needrex = sz == "b" and i > 3 - local iname = format("@%s%x%s", sz, i, needrex and "R" or "") - if needrex then map_reg_needrex[iname] = true end - local name - if sz == "o" or sz == "y" then name = format("%s%d", cl, i) - elseif sz == "f" then name = format("st%d", i) - else name = format("r%d%s", i, sz == addrsize and "" or sz) end - map_archdef[name] = iname - if not map_reg_rev[iname] then - reg_list[#reg_list+1] = iname - map_reg_rev[iname] = name - map_reg_num[iname] = i - map_reg_opsize[iname] = sz - if sz == addrsize or sz == "d" then - map_reg_valid_base[iname] = true - map_reg_valid_index[iname] = true - end - end - end - reg_list[#reg_list+1] = "" -end - --- Integer registers (qword, dword, word and byte sized). -if x64 then - mkrmap("q", "Rq", {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"}) -end -mkrmap("d", "Rd", {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"}) -mkrmap("w", "Rw", {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"}) -mkrmap("b", "Rb", {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"}) -map_reg_valid_index[map_archdef.esp] = false -if x64 then map_reg_valid_index[map_archdef.rsp] = false end -if x64 then map_reg_needrex[map_archdef.Rb] = true end -map_archdef["Ra"] = "@"..addrsize - --- FP registers (internally tword sized, but use "f" as operand size). -mkrmap("f", "Rf") - --- SSE registers (oword sized, but qword and dword accessible). -mkrmap("o", "xmm") - --- AVX registers (yword sized, but oword, qword and dword accessible). -mkrmap("y", "ymm") - --- Operand size prefixes to codes. -local map_opsize = { - byte = "b", word = "w", dword = "d", qword = "q", oword = "o", yword = "y", - tword = "t", aword = addrsize, -} - --- Operand size code to number. -local map_opsizenum = { - b = 1, w = 2, d = 4, q = 8, o = 16, y = 32, t = 10, -} - --- Operand size code to name. -local map_opsizename = { - b = "byte", w = "word", d = "dword", q = "qword", o = "oword", y = "yword", - t = "tword", f = "fpword", -} - --- Valid index register scale factors. -local map_xsc = { - ["1"] = 0, ["2"] = 1, ["4"] = 2, ["8"] = 3, -} - --- Condition codes. -local map_cc = { - o = 0, no = 1, b = 2, nb = 3, e = 4, ne = 5, be = 6, nbe = 7, - s = 8, ns = 9, p = 10, np = 11, l = 12, nl = 13, le = 14, nle = 15, - c = 2, nae = 2, nc = 3, ae = 3, z = 4, nz = 5, na = 6, a = 7, - pe = 10, po = 11, nge = 12, ge = 13, ng = 14, g = 15, -} - - --- Reverse defines for registers. -function _M.revdef(s) - return gsub(s, "@%w+", map_reg_rev) -end - --- Dump register names and numbers -local function dumpregs(out) - out:write("Register names, sizes and internal numbers:\n") - for _,reg in ipairs(reg_list) do - if reg == "" then - out:write("\n") - else - local name = map_reg_rev[reg] - local num = map_reg_num[reg] - local opsize = map_opsizename[map_reg_opsize[reg]] - out:write(format(" %-5s %-8s %s\n", name, opsize, - num < 0 and "(variable)" or num)) - end - end -end - ------------------------------------------------------------------------------- - --- Put action for label arg (IMM_LG, IMM_PC, REL_LG, REL_PC). -local function wputlabel(aprefix, imm, num) - if type(imm) == "number" then - if imm < 0 then - waction("EXTERN") - wputxb(aprefix == "IMM_" and 0 or 1) - imm = -imm-1 - else - waction(aprefix.."LG", nil, num); - end - wputxb(imm) - else - waction(aprefix.."PC", imm, num) - end -end - --- Put signed byte or arg. -local function wputsbarg(n) - if type(n) == "number" then - if n < -128 or n > 127 then - werror("signed immediate byte out of range") - end - if n < 0 then n = n + 256 end - wputb(n) - else waction("IMM_S", n) end -end - --- Put unsigned byte or arg. -local function wputbarg(n) - if type(n) == "number" then - if n < 0 or n > 255 then - werror("unsigned immediate byte out of range") - end - wputb(n) - else waction("IMM_B", n) end -end - --- Put unsigned word or arg. -local function wputwarg(n) - if type(n) == "number" then - if shr(n, 16) ~= 0 then - werror("unsigned immediate word out of range") - end - wputb(band(n, 255)); wputb(shr(n, 8)); - else waction("IMM_W", n) end -end - --- Put signed or unsigned dword or arg. -local function wputdarg(n) - local tn = type(n) - if tn == "number" then - wputb(band(n, 255)) - wputb(band(shr(n, 8), 255)) - wputb(band(shr(n, 16), 255)) - wputb(shr(n, 24)) - elseif tn == "table" then - wputlabel("IMM_", n[1], 1) - else - waction("IMM_D", n) - end -end - --- Put operand-size dependent number or arg (defaults to dword). -local function wputszarg(sz, n) - if not sz or sz == "d" or sz == "q" then wputdarg(n) - elseif sz == "w" then wputwarg(n) - elseif sz == "b" then wputbarg(n) - elseif sz == "s" then wputsbarg(n) - else werror("bad operand size") end -end - --- Put multi-byte opcode with operand-size dependent modifications. -local function wputop(sz, op, rex, vex, vregr, vregxb) - local psz, sk = 0, nil - if vex then - local tail - if vex.m == 1 and band(rex, 11) == 0 then - if x64 and vregxb then - sk = map_vreg["modrm.reg"] - else - wputb(0xc5) - tail = shl(bxor(band(rex, 4), 4), 5) - psz = 3 - end - end - if not tail then - wputb(0xc4) - wputb(shl(bxor(band(rex, 7), 7), 5) + vex.m) - tail = shl(band(rex, 8), 4) - psz = 4 - end - local reg, vreg = 0, nil - if vex.v then - reg = vex.v.reg - if not reg then werror("bad vex operand") end - if reg < 0 then reg = 0; vreg = vex.v.vreg end - end - if sz == "y" or vex.l then tail = tail + 4 end - wputb(tail + shl(bxor(reg, 15), 3) + vex.p) - wvreg("vex.v", vreg) - rex = 0 - if op >= 256 then werror("bad vex opcode") end - else - if rex ~= 0 then - if not x64 then werror("bad operand size") end - elseif (vregr or vregxb) and x64 then - rex = 0x10 - sk = map_vreg["vex.v"] - end - end - local r - if sz == "w" then wputb(102) end - -- Needs >32 bit numbers, but only for crc32 eax, word [ebx] - if op >= 4294967296 then r = op%4294967296 wputb((op-r)/4294967296) op = r end - if op >= 16777216 then wputb(shr(op, 24)); op = band(op, 0xffffff) end - if op >= 65536 then - if rex ~= 0 then - local opc3 = band(op, 0xffff00) - if opc3 == 0x0f3a00 or opc3 == 0x0f3800 then - wputb(64 + band(rex, 15)); rex = 0; psz = 2 - end - end - wputb(shr(op, 16)); op = band(op, 0xffff); psz = psz + 1 - end - if op >= 256 then - local b = shr(op, 8) - if b == 15 and rex ~= 0 then wputb(64 + band(rex, 15)); rex = 0; psz = 2 end - wputb(b); op = band(op, 255); psz = psz + 1 - end - if rex ~= 0 then wputb(64 + band(rex, 15)); psz = 2 end - if sz == "b" then op = op - 1 end - wputb(op) - return psz, sk -end - --- Put ModRM or SIB formatted byte. -local function wputmodrm(m, s, rm, vs, vrm) - assert(m < 4 and s < 16 and rm < 16, "bad modrm operands") - wputb(shl(m, 6) + shl(band(s, 7), 3) + band(rm, 7)) -end - --- Put ModRM/SIB plus optional displacement. -local function wputmrmsib(t, imark, s, vsreg, psz, sk) - local vreg, vxreg - local reg, xreg = t.reg, t.xreg - if reg and reg < 0 then reg = 0; vreg = t.vreg end - if xreg and xreg < 0 then xreg = 0; vxreg = t.vxreg end - if s < 0 then s = 0 end - - -- Register mode. - if sub(t.mode, 1, 1) == "r" then - wputmodrm(3, s, reg) - wvreg("modrm.reg", vsreg, psz+1, sk, vreg) - wvreg("modrm.rm.r", vreg, psz+1, sk) - return - end - - local disp = t.disp - local tdisp = type(disp) - -- No base register? - if not reg then - local riprel = false - if xreg then - -- Indexed mode with index register only. - -- [xreg*xsc+disp] -> (0, s, esp) (xsc, xreg, ebp) - wputmodrm(0, s, 4) - if imark == "I" then waction("MARK") end - wvreg("modrm.reg", vsreg, psz+1, sk, vxreg) - wputmodrm(t.xsc, xreg, 5) - wvreg("sib.index", vxreg, psz+2, sk) - else - -- Pure 32 bit displacement. - if x64 and tdisp ~= "table" then - wputmodrm(0, s, 4) -- [disp] -> (0, s, esp) (0, esp, ebp) - wvreg("modrm.reg", vsreg, psz+1, sk) - if imark == "I" then waction("MARK") end - wputmodrm(0, 4, 5) - else - riprel = x64 - wputmodrm(0, s, 5) -- [disp|rip-label] -> (0, s, ebp) - wvreg("modrm.reg", vsreg, psz+1, sk) - if imark == "I" then waction("MARK") end - end - end - if riprel then -- Emit rip-relative displacement. - if match("UWSiI", imark) then - werror("NYI: rip-relative displacement followed by immediate") - end - -- The previous byte in the action buffer cannot be 0xe9 or 0x80-0x8f. - wputlabel("REL_", disp[1], 2) - else - wputdarg(disp) - end - return - end - - local m - if tdisp == "number" then -- Check displacement size at assembly time. - if disp == 0 and band(reg, 7) ~= 5 then -- [ebp] -> [ebp+0] (in SIB, too) - if not vreg then m = 0 end -- Force DISP to allow [Rd(5)] -> [ebp+0] - elseif disp >= -128 and disp <= 127 then m = 1 - else m = 2 end - elseif tdisp == "table" then - m = 2 - end - - -- Index register present or esp as base register: need SIB encoding. - if xreg or band(reg, 7) == 4 then - wputmodrm(m or 2, s, 4) -- ModRM. - if m == nil or imark == "I" then waction("MARK") end - wvreg("modrm.reg", vsreg, psz+1, sk, vxreg or vreg) - wputmodrm(t.xsc or 0, xreg or 4, reg) -- SIB. - wvreg("sib.index", vxreg, psz+2, sk, vreg) - wvreg("sib.base", vreg, psz+2, sk) - else - wputmodrm(m or 2, s, reg) -- ModRM. - if (imark == "I" and (m == 1 or m == 2)) or - (m == nil and (vsreg or vreg)) then waction("MARK") end - wvreg("modrm.reg", vsreg, psz+1, sk, vreg) - wvreg("modrm.rm.m", vreg, psz+1, sk) - end - - -- Put displacement. - if m == 1 then wputsbarg(disp) - elseif m == 2 then wputdarg(disp) - elseif m == nil then waction("DISP", disp) end -end - ------------------------------------------------------------------------------- - --- Return human-readable operand mode string. -local function opmodestr(op, args) - local m = {} - for i=1,#args do - local a = args[i] - m[#m+1] = sub(a.mode, 1, 1)..(a.opsize or "?") - end - return op.." "..concat(m, ",") -end - --- Convert number to valid integer or nil. -local function toint(expr) - local n = tonumber(expr) - if n then - if n % 1 ~= 0 or n < -2147483648 or n > 4294967295 then - werror("bad integer number `"..expr.."'") - end - return n - end -end - --- Parse immediate expression. -local function immexpr(expr) - -- &expr (pointer) - if sub(expr, 1, 1) == "&" then - return "iPJ", format("(ptrdiff_t)(%s)", sub(expr,2)) - end - - local prefix = sub(expr, 1, 2) - -- =>expr (pc label reference) - if prefix == "=>" then - return "iJ", sub(expr, 3) - end - -- ->name (global label reference) - if prefix == "->" then - return "iJ", map_global[sub(expr, 3)] - end - - -- [<>][1-9] (local label reference) - local dir, lnum = match(expr, "^([<>])([1-9])$") - if dir then -- Fwd: 247-255, Bkwd: 1-9. - return "iJ", lnum + (dir == ">" and 246 or 0) - end - - local extname = match(expr, "^extern%s+(%S+)$") - if extname then - return "iJ", map_extern[extname] - end - - -- expr (interpreted as immediate) - return "iI", expr -end - --- Parse displacement expression: +-num, +-expr, +-opsize*num -local function dispexpr(expr) - local disp = expr == "" and 0 or toint(expr) - if disp then return disp end - local c, dispt = match(expr, "^([+-])%s*(.+)$") - if c == "+" then - expr = dispt - elseif not c then - werror("bad displacement expression `"..expr.."'") - end - local opsize, tailops = match(dispt, "^(%w+)%s*%*%s*(.+)$") - local ops, imm = map_opsize[opsize], toint(tailops) - if ops and imm then - if c == "-" then imm = -imm end - return imm*map_opsizenum[ops] - end - local mode, iexpr = immexpr(dispt) - if mode == "iJ" then - if c == "-" then werror("cannot invert label reference") end - return { iexpr } - end - return expr -- Need to return original signed expression. -end - --- Parse register or type expression. -local function rtexpr(expr) - if not expr then return end - local tname, ovreg = match(expr, "^([%w_]+):(@[%w_]+)$") - local tp = map_type[tname or expr] - if tp then - local reg = ovreg or tp.reg - local rnum = map_reg_num[reg] - if not rnum then - werror("type `"..(tname or expr).."' needs a register override") - end - if not map_reg_valid_base[reg] then - werror("bad base register override `"..(map_reg_rev[reg] or reg).."'") - end - return reg, rnum, tp - end - return expr, map_reg_num[expr] -end - --- Parse operand and return { mode, opsize, reg, xreg, xsc, disp, imm }. -local function parseoperand(param) - local t = {} - - local expr = param - local opsize, tailops = match(param, "^(%w+)%s*(.+)$") - if opsize then - t.opsize = map_opsize[opsize] - if t.opsize then expr = tailops end - end - - local br = match(expr, "^%[%s*(.-)%s*%]$") - repeat - if br then - t.mode = "xm" - - -- [disp] - t.disp = toint(br) - if t.disp then - t.mode = x64 and "xm" or "xmO" - break - end - - -- [reg...] - local tp - local reg, tailr = match(br, "^([@%w_:]+)%s*(.*)$") - reg, t.reg, tp = rtexpr(reg) - if not t.reg then - -- [expr] - t.mode = x64 and "xm" or "xmO" - t.disp = dispexpr("+"..br) - break - end - - if t.reg == -1 then - t.vreg, tailr = match(tailr, "^(%b())(.*)$") - if not t.vreg then werror("bad variable register expression") end - end - - -- [xreg*xsc] or [xreg*xsc+-disp] or [xreg*xsc+-expr] - local xsc, tailsc = match(tailr, "^%*%s*([1248])%s*(.*)$") - if xsc then - if not map_reg_valid_index[reg] then - werror("bad index register `"..map_reg_rev[reg].."'") - end - t.xsc = map_xsc[xsc] - t.xreg = t.reg - t.vxreg = t.vreg - t.reg = nil - t.vreg = nil - t.disp = dispexpr(tailsc) - break - end - if not map_reg_valid_base[reg] then - werror("bad base register `"..map_reg_rev[reg].."'") - end - - -- [reg] or [reg+-disp] - t.disp = toint(tailr) or (tailr == "" and 0) - if t.disp then break end - - -- [reg+xreg...] - local xreg, tailx = match(tailr, "^+%s*([@%w_:]+)%s*(.*)$") - xreg, t.xreg, tp = rtexpr(xreg) - if not t.xreg then - -- [reg+-expr] - t.disp = dispexpr(tailr) - break - end - if not map_reg_valid_index[xreg] then - werror("bad index register `"..map_reg_rev[xreg].."'") - end - - if t.xreg == -1 then - t.vxreg, tailx = match(tailx, "^(%b())(.*)$") - if not t.vxreg then werror("bad variable register expression") end - end - - -- [reg+xreg*xsc...] - local xsc, tailsc = match(tailx, "^%*%s*([1248])%s*(.*)$") - if xsc then - t.xsc = map_xsc[xsc] - tailx = tailsc - end - - -- [...] or [...+-disp] or [...+-expr] - t.disp = dispexpr(tailx) - else - -- imm or opsize*imm - local imm = toint(expr) - if not imm and sub(expr, 1, 1) == "*" and t.opsize then - imm = toint(sub(expr, 2)) - if imm then - imm = imm * map_opsizenum[t.opsize] - t.opsize = nil - end - end - if imm then - if t.opsize then werror("bad operand size override") end - local m = "i" - if imm == 1 then m = m.."1" end - if imm >= 4294967168 and imm <= 4294967295 then imm = imm-4294967296 end - if imm >= -128 and imm <= 127 then m = m.."S" end - t.imm = imm - t.mode = m - break - end - - local tp - local reg, tailr = match(expr, "^([@%w_:]+)%s*(.*)$") - reg, t.reg, tp = rtexpr(reg) - if t.reg then - if t.reg == -1 then - t.vreg, tailr = match(tailr, "^(%b())(.*)$") - if not t.vreg then werror("bad variable register expression") end - end - -- reg - if tailr == "" then - if t.opsize then werror("bad operand size override") end - t.opsize = map_reg_opsize[reg] - if t.opsize == "f" then - t.mode = t.reg == 0 and "fF" or "f" - else - if reg == "@w4" or (x64 and reg == "@d4") then - wwarn("bad idea, try again with `"..(x64 and "rsp'" or "esp'")) - end - t.mode = t.reg == 0 and "rmR" or (reg == "@b1" and "rmC" or "rm") - end - t.needrex = map_reg_needrex[reg] - break - end - - -- type[idx], type[idx].field, type->field -> [reg+offset_expr] - if not tp then werror("bad operand `"..param.."'") end - t.mode = "xm" - t.disp = format(tp.ctypefmt, tailr) - else - t.mode, t.imm = immexpr(expr) - if sub(t.mode, -1) == "J" then - if t.opsize and t.opsize ~= addrsize then - werror("bad operand size override") - end - t.opsize = addrsize - end - end - end - until true - return t -end - ------------------------------------------------------------------------------- --- x86 Template String Description --- =============================== --- --- Each template string is a list of [match:]pattern pairs, --- separated by "|". The first match wins. No match means a --- bad or unsupported combination of operand modes or sizes. --- --- The match part and the ":" is omitted if the operation has --- no operands. Otherwise the first N characters are matched --- against the mode strings of each of the N operands. --- --- The mode string for each operand type is (see parseoperand()): --- Integer register: "rm", +"R" for eax, ax, al, +"C" for cl --- FP register: "f", +"F" for st0 --- Index operand: "xm", +"O" for [disp] (pure offset) --- Immediate: "i", +"S" for signed 8 bit, +"1" for 1, --- +"I" for arg, +"P" for pointer --- Any: +"J" for valid jump targets --- --- So a match character "m" (mixed) matches both an integer register --- and an index operand (to be encoded with the ModRM/SIB scheme). --- But "r" matches only a register and "x" only an index operand --- (e.g. for FP memory access operations). --- --- The operand size match string starts right after the mode match --- characters and ends before the ":". "dwb" or "qdwb" is assumed, if empty. --- The effective data size of the operation is matched against this list. --- --- If only the regular "b", "w", "d", "q", "t" operand sizes are --- present, then all operands must be the same size. Unspecified sizes --- are ignored, but at least one operand must have a size or the pattern --- won't match (use the "byte", "word", "dword", "qword", "tword" --- operand size overrides. E.g.: mov dword [eax], 1). --- --- If the list has a "1" or "2" prefix, the operand size is taken --- from the respective operand and any other operand sizes are ignored. --- If the list contains only ".", all operand sizes are ignored. --- If the list has a "/" prefix, the concatenated (mixed) operand sizes --- are compared to the match. --- --- E.g. "rrdw" matches for either two dword registers or two word --- registers. "Fx2dq" matches an st0 operand plus an index operand --- pointing to a dword (float) or qword (double). --- --- Every character after the ":" is part of the pattern string: --- Hex chars are accumulated to form the opcode (left to right). --- "n" disables the standard opcode mods --- (otherwise: -1 for "b", o16 prefix for "w", rex.w for "q") --- "X" Force REX.W. --- "r"/"R" adds the reg. number from the 1st/2nd operand to the opcode. --- "m"/"M" generates ModRM/SIB from the 1st/2nd operand. --- The spare 3 bits are either filled with the last hex digit or --- the result from a previous "r"/"R". The opcode is restored. --- "u" Use VEX encoding, vvvv unused. --- "v"/"V" Use VEX encoding, vvvv from 1st/2nd operand (the operand is --- removed from the list used by future characters). --- "w" Use VEX encoding, vvvv from 3rd operand. --- "L" Force VEX.L --- --- All of the following characters force a flush of the opcode: --- "o"/"O" stores a pure 32 bit disp (offset) from the 1st/2nd operand. --- "s" stores a 4 bit immediate from the last register operand, --- followed by 4 zero bits. --- "S" stores a signed 8 bit immediate from the last operand. --- "U" stores an unsigned 8 bit immediate from the last operand. --- "W" stores an unsigned 16 bit immediate from the last operand. --- "i" stores an operand sized immediate from the last operand. --- "I" dito, but generates an action code to optionally modify --- the opcode (+2) for a signed 8 bit immediate. --- "J" generates one of the REL action codes from the last operand. --- ------------------------------------------------------------------------------- - --- Template strings for x86 instructions. Ordered by first opcode byte. --- Unimplemented opcodes (deliberate omissions) are marked with *. -local map_op = { - -- 00-05: add... - -- 06: *push es - -- 07: *pop es - -- 08-0D: or... - -- 0E: *push cs - -- 0F: two byte opcode prefix - -- 10-15: adc... - -- 16: *push ss - -- 17: *pop ss - -- 18-1D: sbb... - -- 1E: *push ds - -- 1F: *pop ds - -- 20-25: and... - es_0 = "26", - -- 27: *daa - -- 28-2D: sub... - cs_0 = "2E", - -- 2F: *das - -- 30-35: xor... - ss_0 = "36", - -- 37: *aaa - -- 38-3D: cmp... - ds_0 = "3E", - -- 3F: *aas - inc_1 = x64 and "m:FF0m" or "rdw:40r|m:FF0m", - dec_1 = x64 and "m:FF1m" or "rdw:48r|m:FF1m", - push_1 = (x64 and "rq:n50r|rw:50r|mq:nFF6m|mw:FF6m" or - "rdw:50r|mdw:FF6m").."|S.:6AS|ib:n6Ai|i.:68i", - pop_1 = x64 and "rq:n58r|rw:58r|mq:n8F0m|mw:8F0m" or "rdw:58r|mdw:8F0m", - -- 60: *pusha, *pushad, *pushaw - -- 61: *popa, *popad, *popaw - -- 62: *bound rdw,x - -- 63: x86: *arpl mw,rw - movsxd_2 = x64 and "rm/qd:63rM", - fs_0 = "64", - gs_0 = "65", - o16_0 = "66", - a16_0 = not x64 and "67" or nil, - a32_0 = x64 and "67", - -- 68: push idw - -- 69: imul rdw,mdw,idw - -- 6A: push ib - -- 6B: imul rdw,mdw,S - -- 6C: *insb - -- 6D: *insd, *insw - -- 6E: *outsb - -- 6F: *outsd, *outsw - -- 70-7F: jcc lb - -- 80: add... mb,i - -- 81: add... mdw,i - -- 82: *undefined - -- 83: add... mdw,S - test_2 = "mr:85Rm|rm:85rM|Ri:A9ri|mi:F70mi", - -- 86: xchg rb,mb - -- 87: xchg rdw,mdw - -- 88: mov mb,r - -- 89: mov mdw,r - -- 8A: mov r,mb - -- 8B: mov r,mdw - -- 8C: *mov mdw,seg - lea_2 = "rx1dq:8DrM", - -- 8E: *mov seg,mdw - -- 8F: pop mdw - nop_0 = "90", - xchg_2 = "Rrqdw:90R|rRqdw:90r|rm:87rM|mr:87Rm", - cbw_0 = "6698", - cwde_0 = "98", - cdqe_0 = "4898", - cwd_0 = "6699", - cdq_0 = "99", - cqo_0 = "4899", - -- 9A: *call iw:idw - wait_0 = "9B", - fwait_0 = "9B", - pushf_0 = "9C", - pushfd_0 = not x64 and "9C", - pushfq_0 = x64 and "9C", - popf_0 = "9D", - popfd_0 = not x64 and "9D", - popfq_0 = x64 and "9D", - sahf_0 = "9E", - lahf_0 = "9F", - mov_2 = "OR:A3o|RO:A1O|mr:89Rm|rm:8BrM|rib:nB0ri|ridw:B8ri|mi:C70mi", - movsb_0 = "A4", - movsw_0 = "66A5", - movsd_0 = "A5", - cmpsb_0 = "A6", - cmpsw_0 = "66A7", - cmpsd_0 = "A7", - -- A8: test Rb,i - -- A9: test Rdw,i - stosb_0 = "AA", - stosw_0 = "66AB", - stosd_0 = "AB", - lodsb_0 = "AC", - lodsw_0 = "66AD", - lodsd_0 = "AD", - scasb_0 = "AE", - scasw_0 = "66AF", - scasd_0 = "AF", - -- B0-B7: mov rb,i - -- B8-BF: mov rdw,i - -- C0: rol... mb,i - -- C1: rol... mdw,i - ret_1 = "i.:nC2W", - ret_0 = "C3", - -- C4: *les rdw,mq - -- C5: *lds rdw,mq - -- C6: mov mb,i - -- C7: mov mdw,i - -- C8: *enter iw,ib - leave_0 = "C9", - -- CA: *retf iw - -- CB: *retf - int3_0 = "CC", - int_1 = "i.:nCDU", - into_0 = "CE", - -- CF: *iret - -- D0: rol... mb,1 - -- D1: rol... mdw,1 - -- D2: rol... mb,cl - -- D3: rol... mb,cl - -- D4: *aam ib - -- D5: *aad ib - -- D6: *salc - -- D7: *xlat - -- D8-DF: floating point ops - -- E0: *loopne - -- E1: *loope - -- E2: *loop - -- E3: *jcxz, *jecxz - -- E4: *in Rb,ib - -- E5: *in Rdw,ib - -- E6: *out ib,Rb - -- E7: *out ib,Rdw - call_1 = x64 and "mq:nFF2m|J.:E8nJ" or "md:FF2m|J.:E8J", - jmp_1 = x64 and "mq:nFF4m|J.:E9nJ" or "md:FF4m|J.:E9J", -- short: EB - -- EA: *jmp iw:idw - -- EB: jmp ib - -- EC: *in Rb,dx - -- ED: *in Rdw,dx - -- EE: *out dx,Rb - -- EF: *out dx,Rdw - lock_0 = "F0", - int1_0 = "F1", - repne_0 = "F2", - repnz_0 = "F2", - rep_0 = "F3", - repe_0 = "F3", - repz_0 = "F3", - -- F4: *hlt - cmc_0 = "F5", - -- F6: test... mb,i; div... mb - -- F7: test... mdw,i; div... mdw - clc_0 = "F8", - stc_0 = "F9", - -- FA: *cli - cld_0 = "FC", - std_0 = "FD", - -- FE: inc... mb - -- FF: inc... mdw - - -- misc ops - not_1 = "m:F72m", - neg_1 = "m:F73m", - mul_1 = "m:F74m", - imul_1 = "m:F75m", - div_1 = "m:F76m", - idiv_1 = "m:F77m", - - imul_2 = "rmqdw:0FAFrM|rIqdw:69rmI|rSqdw:6BrmS|riqdw:69rmi", - imul_3 = "rmIqdw:69rMI|rmSqdw:6BrMS|rmiqdw:69rMi", - - movzx_2 = "rm/db:0FB6rM|rm/qb:|rm/wb:0FB6rM|rm/dw:0FB7rM|rm/qw:", - movsx_2 = "rm/db:0FBErM|rm/qb:|rm/wb:0FBErM|rm/dw:0FBFrM|rm/qw:", - - bswap_1 = "rqd:0FC8r", - bsf_2 = "rmqdw:0FBCrM", - bsr_2 = "rmqdw:0FBDrM", - bt_2 = "mrqdw:0FA3Rm|miqdw:0FBA4mU", - btc_2 = "mrqdw:0FBBRm|miqdw:0FBA7mU", - btr_2 = "mrqdw:0FB3Rm|miqdw:0FBA6mU", - bts_2 = "mrqdw:0FABRm|miqdw:0FBA5mU", - - shld_3 = "mriqdw:0FA4RmU|mrC/qq:0FA5Rm|mrC/dd:|mrC/ww:", - shrd_3 = "mriqdw:0FACRmU|mrC/qq:0FADRm|mrC/dd:|mrC/ww:", - - rdtsc_0 = "0F31", -- P1+ - rdpmc_0 = "0F33", -- P6+ - cpuid_0 = "0FA2", -- P1+ - - -- floating point ops - fst_1 = "ff:DDD0r|xd:D92m|xq:nDD2m", - fstp_1 = "ff:DDD8r|xd:D93m|xq:nDD3m|xt:DB7m", - fld_1 = "ff:D9C0r|xd:D90m|xq:nDD0m|xt:DB5m", - - fpop_0 = "DDD8", -- Alias for fstp st0. - - fist_1 = "xw:nDF2m|xd:DB2m", - fistp_1 = "xw:nDF3m|xd:DB3m|xq:nDF7m", - fild_1 = "xw:nDF0m|xd:DB0m|xq:nDF5m", - - fxch_0 = "D9C9", - fxch_1 = "ff:D9C8r", - fxch_2 = "fFf:D9C8r|Fff:D9C8R", - - fucom_1 = "ff:DDE0r", - fucom_2 = "Fff:DDE0R", - fucomp_1 = "ff:DDE8r", - fucomp_2 = "Fff:DDE8R", - fucomi_1 = "ff:DBE8r", -- P6+ - fucomi_2 = "Fff:DBE8R", -- P6+ - fucomip_1 = "ff:DFE8r", -- P6+ - fucomip_2 = "Fff:DFE8R", -- P6+ - fcomi_1 = "ff:DBF0r", -- P6+ - fcomi_2 = "Fff:DBF0R", -- P6+ - fcomip_1 = "ff:DFF0r", -- P6+ - fcomip_2 = "Fff:DFF0R", -- P6+ - fucompp_0 = "DAE9", - fcompp_0 = "DED9", - - fldenv_1 = "x.:D94m", - fnstenv_1 = "x.:D96m", - fstenv_1 = "x.:9BD96m", - fldcw_1 = "xw:nD95m", - fstcw_1 = "xw:n9BD97m", - fnstcw_1 = "xw:nD97m", - fstsw_1 = "Rw:n9BDFE0|xw:n9BDD7m", - fnstsw_1 = "Rw:nDFE0|xw:nDD7m", - fclex_0 = "9BDBE2", - fnclex_0 = "DBE2", - - fnop_0 = "D9D0", - -- D9D1-D9DF: unassigned - - fchs_0 = "D9E0", - fabs_0 = "D9E1", - -- D9E2: unassigned - -- D9E3: unassigned - ftst_0 = "D9E4", - fxam_0 = "D9E5", - -- D9E6: unassigned - -- D9E7: unassigned - fld1_0 = "D9E8", - fldl2t_0 = "D9E9", - fldl2e_0 = "D9EA", - fldpi_0 = "D9EB", - fldlg2_0 = "D9EC", - fldln2_0 = "D9ED", - fldz_0 = "D9EE", - -- D9EF: unassigned - - f2xm1_0 = "D9F0", - fyl2x_0 = "D9F1", - fptan_0 = "D9F2", - fpatan_0 = "D9F3", - fxtract_0 = "D9F4", - fprem1_0 = "D9F5", - fdecstp_0 = "D9F6", - fincstp_0 = "D9F7", - fprem_0 = "D9F8", - fyl2xp1_0 = "D9F9", - fsqrt_0 = "D9FA", - fsincos_0 = "D9FB", - frndint_0 = "D9FC", - fscale_0 = "D9FD", - fsin_0 = "D9FE", - fcos_0 = "D9FF", - - -- SSE, SSE2 - andnpd_2 = "rmo:660F55rM", - andnps_2 = "rmo:0F55rM", - andpd_2 = "rmo:660F54rM", - andps_2 = "rmo:0F54rM", - clflush_1 = "x.:0FAE7m", - cmppd_3 = "rmio:660FC2rMU", - cmpps_3 = "rmio:0FC2rMU", - cmpsd_3 = "rrio:F20FC2rMU|rxi/oq:", - cmpss_3 = "rrio:F30FC2rMU|rxi/od:", - comisd_2 = "rro:660F2FrM|rx/oq:", - comiss_2 = "rro:0F2FrM|rx/od:", - cvtdq2pd_2 = "rro:F30FE6rM|rx/oq:", - cvtdq2ps_2 = "rmo:0F5BrM", - cvtpd2dq_2 = "rmo:F20FE6rM", - cvtpd2ps_2 = "rmo:660F5ArM", - cvtpi2pd_2 = "rx/oq:660F2ArM", - cvtpi2ps_2 = "rx/oq:0F2ArM", - cvtps2dq_2 = "rmo:660F5BrM", - cvtps2pd_2 = "rro:0F5ArM|rx/oq:", - cvtsd2si_2 = "rr/do:F20F2DrM|rr/qo:|rx/dq:|rxq:", - cvtsd2ss_2 = "rro:F20F5ArM|rx/oq:", - cvtsi2sd_2 = "rm/od:F20F2ArM|rm/oq:F20F2ArXM", - cvtsi2ss_2 = "rm/od:F30F2ArM|rm/oq:F30F2ArXM", - cvtss2sd_2 = "rro:F30F5ArM|rx/od:", - cvtss2si_2 = "rr/do:F30F2DrM|rr/qo:|rxd:|rx/qd:", - cvttpd2dq_2 = "rmo:660FE6rM", - cvttps2dq_2 = "rmo:F30F5BrM", - cvttsd2si_2 = "rr/do:F20F2CrM|rr/qo:|rx/dq:|rxq:", - cvttss2si_2 = "rr/do:F30F2CrM|rr/qo:|rxd:|rx/qd:", - fxsave_1 = "x.:0FAE0m", - fxrstor_1 = "x.:0FAE1m", - ldmxcsr_1 = "xd:0FAE2m", - lfence_0 = "0FAEE8", - maskmovdqu_2 = "rro:660FF7rM", - mfence_0 = "0FAEF0", - movapd_2 = "rmo:660F28rM|mro:660F29Rm", - movaps_2 = "rmo:0F28rM|mro:0F29Rm", - movd_2 = "rm/od:660F6ErM|rm/oq:660F6ErXM|mr/do:660F7ERm|mr/qo:", - movdqa_2 = "rmo:660F6FrM|mro:660F7FRm", - movdqu_2 = "rmo:F30F6FrM|mro:F30F7FRm", - movhlps_2 = "rro:0F12rM", - movhpd_2 = "rx/oq:660F16rM|xr/qo:n660F17Rm", - movhps_2 = "rx/oq:0F16rM|xr/qo:n0F17Rm", - movlhps_2 = "rro:0F16rM", - movlpd_2 = "rx/oq:660F12rM|xr/qo:n660F13Rm", - movlps_2 = "rx/oq:0F12rM|xr/qo:n0F13Rm", - movmskpd_2 = "rr/do:660F50rM", - movmskps_2 = "rr/do:0F50rM", - movntdq_2 = "xro:660FE7Rm", - movnti_2 = "xrqd:0FC3Rm", - movntpd_2 = "xro:660F2BRm", - movntps_2 = "xro:0F2BRm", - movq_2 = "rro:F30F7ErM|rx/oq:|xr/qo:n660FD6Rm", - movsd_2 = "rro:F20F10rM|rx/oq:|xr/qo:nF20F11Rm", - movss_2 = "rro:F30F10rM|rx/od:|xr/do:F30F11Rm", - movupd_2 = "rmo:660F10rM|mro:660F11Rm", - movups_2 = "rmo:0F10rM|mro:0F11Rm", - orpd_2 = "rmo:660F56rM", - orps_2 = "rmo:0F56rM", - pause_0 = "F390", - pextrw_3 = "rri/do:660FC5rMU|xri/wo:660F3A15nRmU", -- Mem op: SSE4.1 only. - pinsrw_3 = "rri/od:660FC4rMU|rxi/ow:", - pmovmskb_2 = "rr/do:660FD7rM", - prefetchnta_1 = "xb:n0F180m", - prefetcht0_1 = "xb:n0F181m", - prefetcht1_1 = "xb:n0F182m", - prefetcht2_1 = "xb:n0F183m", - pshufd_3 = "rmio:660F70rMU", - pshufhw_3 = "rmio:F30F70rMU", - pshuflw_3 = "rmio:F20F70rMU", - pslld_2 = "rmo:660FF2rM|rio:660F726mU", - pslldq_2 = "rio:660F737mU", - psllq_2 = "rmo:660FF3rM|rio:660F736mU", - psllw_2 = "rmo:660FF1rM|rio:660F716mU", - psrad_2 = "rmo:660FE2rM|rio:660F724mU", - psraw_2 = "rmo:660FE1rM|rio:660F714mU", - psrld_2 = "rmo:660FD2rM|rio:660F722mU", - psrldq_2 = "rio:660F733mU", - psrlq_2 = "rmo:660FD3rM|rio:660F732mU", - psrlw_2 = "rmo:660FD1rM|rio:660F712mU", - rcpps_2 = "rmo:0F53rM", - rcpss_2 = "rro:F30F53rM|rx/od:", - rsqrtps_2 = "rmo:0F52rM", - rsqrtss_2 = "rmo:F30F52rM", - sfence_0 = "0FAEF8", - shufpd_3 = "rmio:660FC6rMU", - shufps_3 = "rmio:0FC6rMU", - stmxcsr_1 = "xd:0FAE3m", - ucomisd_2 = "rro:660F2ErM|rx/oq:", - ucomiss_2 = "rro:0F2ErM|rx/od:", - unpckhpd_2 = "rmo:660F15rM", - unpckhps_2 = "rmo:0F15rM", - unpcklpd_2 = "rmo:660F14rM", - unpcklps_2 = "rmo:0F14rM", - xorpd_2 = "rmo:660F57rM", - xorps_2 = "rmo:0F57rM", - - -- SSE3 ops - fisttp_1 = "xw:nDF1m|xd:DB1m|xq:nDD1m", - addsubpd_2 = "rmo:660FD0rM", - addsubps_2 = "rmo:F20FD0rM", - haddpd_2 = "rmo:660F7CrM", - haddps_2 = "rmo:F20F7CrM", - hsubpd_2 = "rmo:660F7DrM", - hsubps_2 = "rmo:F20F7DrM", - lddqu_2 = "rxo:F20FF0rM", - movddup_2 = "rmo:F20F12rM", - movshdup_2 = "rmo:F30F16rM", - movsldup_2 = "rmo:F30F12rM", - - -- SSSE3 ops - pabsb_2 = "rmo:660F381CrM", - pabsd_2 = "rmo:660F381ErM", - pabsw_2 = "rmo:660F381DrM", - palignr_3 = "rmio:660F3A0FrMU", - phaddd_2 = "rmo:660F3802rM", - phaddsw_2 = "rmo:660F3803rM", - phaddw_2 = "rmo:660F3801rM", - phsubd_2 = "rmo:660F3806rM", - phsubsw_2 = "rmo:660F3807rM", - phsubw_2 = "rmo:660F3805rM", - pmaddubsw_2 = "rmo:660F3804rM", - pmulhrsw_2 = "rmo:660F380BrM", - pshufb_2 = "rmo:660F3800rM", - psignb_2 = "rmo:660F3808rM", - psignd_2 = "rmo:660F380ArM", - psignw_2 = "rmo:660F3809rM", - - -- SSE4.1 ops - blendpd_3 = "rmio:660F3A0DrMU", - blendps_3 = "rmio:660F3A0CrMU", - blendvpd_3 = "rmRo:660F3815rM", - blendvps_3 = "rmRo:660F3814rM", - dppd_3 = "rmio:660F3A41rMU", - dpps_3 = "rmio:660F3A40rMU", - extractps_3 = "mri/do:660F3A17RmU|rri/qo:660F3A17RXmU", - insertps_3 = "rrio:660F3A41rMU|rxi/od:", - movntdqa_2 = "rxo:660F382ArM", - mpsadbw_3 = "rmio:660F3A42rMU", - packusdw_2 = "rmo:660F382BrM", - pblendvb_3 = "rmRo:660F3810rM", - pblendw_3 = "rmio:660F3A0ErMU", - pcmpeqq_2 = "rmo:660F3829rM", - pextrb_3 = "rri/do:660F3A14nRmU|rri/qo:|xri/bo:", - pextrd_3 = "mri/do:660F3A16RmU", - pextrq_3 = "mri/qo:660F3A16RmU", - -- pextrw is SSE2, mem operand is SSE4.1 only - phminposuw_2 = "rmo:660F3841rM", - pinsrb_3 = "rri/od:660F3A20nrMU|rxi/ob:", - pinsrd_3 = "rmi/od:660F3A22rMU", - pinsrq_3 = "rmi/oq:660F3A22rXMU", - pmaxsb_2 = "rmo:660F383CrM", - pmaxsd_2 = "rmo:660F383DrM", - pmaxud_2 = "rmo:660F383FrM", - pmaxuw_2 = "rmo:660F383ErM", - pminsb_2 = "rmo:660F3838rM", - pminsd_2 = "rmo:660F3839rM", - pminud_2 = "rmo:660F383BrM", - pminuw_2 = "rmo:660F383ArM", - pmovsxbd_2 = "rro:660F3821rM|rx/od:", - pmovsxbq_2 = "rro:660F3822rM|rx/ow:", - pmovsxbw_2 = "rro:660F3820rM|rx/oq:", - pmovsxdq_2 = "rro:660F3825rM|rx/oq:", - pmovsxwd_2 = "rro:660F3823rM|rx/oq:", - pmovsxwq_2 = "rro:660F3824rM|rx/od:", - pmovzxbd_2 = "rro:660F3831rM|rx/od:", - pmovzxbq_2 = "rro:660F3832rM|rx/ow:", - pmovzxbw_2 = "rro:660F3830rM|rx/oq:", - pmovzxdq_2 = "rro:660F3835rM|rx/oq:", - pmovzxwd_2 = "rro:660F3833rM|rx/oq:", - pmovzxwq_2 = "rro:660F3834rM|rx/od:", - pmuldq_2 = "rmo:660F3828rM", - pmulld_2 = "rmo:660F3840rM", - ptest_2 = "rmo:660F3817rM", - roundpd_3 = "rmio:660F3A09rMU", - roundps_3 = "rmio:660F3A08rMU", - roundsd_3 = "rrio:660F3A0BrMU|rxi/oq:", - roundss_3 = "rrio:660F3A0ArMU|rxi/od:", - - -- SSE4.2 ops - crc32_2 = "rmqd:F20F38F1rM|rm/dw:66F20F38F1rM|rm/db:F20F38F0rM|rm/qb:", - pcmpestri_3 = "rmio:660F3A61rMU", - pcmpestrm_3 = "rmio:660F3A60rMU", - pcmpgtq_2 = "rmo:660F3837rM", - pcmpistri_3 = "rmio:660F3A63rMU", - pcmpistrm_3 = "rmio:660F3A62rMU", - popcnt_2 = "rmqdw:F30FB8rM", - - -- SSE4a - extrq_2 = "rro:660F79rM", - extrq_3 = "riio:660F780mUU", - insertq_2 = "rro:F20F79rM", - insertq_4 = "rriio:F20F78rMUU", - lzcnt_2 = "rmqdw:F30FBDrM", - movntsd_2 = "xr/qo:nF20F2BRm", - movntss_2 = "xr/do:F30F2BRm", - -- popcnt is also in SSE4.2 - - -- AES-NI - aesdec_2 = "rmo:660F38DErM", - aesdeclast_2 = "rmo:660F38DFrM", - aesenc_2 = "rmo:660F38DCrM", - aesenclast_2 = "rmo:660F38DDrM", - aesimc_2 = "rmo:660F38DBrM", - aeskeygenassist_3 = "rmio:660F3ADFrMU", - pclmulqdq_3 = "rmio:660F3A44rMU", - - -- AVX FP ops - vaddsubpd_3 = "rrmoy:660FVD0rM", - vaddsubps_3 = "rrmoy:F20FVD0rM", - vandpd_3 = "rrmoy:660FV54rM", - vandps_3 = "rrmoy:0FV54rM", - vandnpd_3 = "rrmoy:660FV55rM", - vandnps_3 = "rrmoy:0FV55rM", - vblendpd_4 = "rrmioy:660F3AV0DrMU", - vblendps_4 = "rrmioy:660F3AV0CrMU", - vblendvpd_4 = "rrmroy:660F3AV4BrMs", - vblendvps_4 = "rrmroy:660F3AV4ArMs", - vbroadcastf128_2 = "rx/yo:660F38u1ArM", - vcmppd_4 = "rrmioy:660FVC2rMU", - vcmpps_4 = "rrmioy:0FVC2rMU", - vcmpsd_4 = "rrrio:F20FVC2rMU|rrxi/ooq:", - vcmpss_4 = "rrrio:F30FVC2rMU|rrxi/ood:", - vcomisd_2 = "rro:660Fu2FrM|rx/oq:", - vcomiss_2 = "rro:0Fu2FrM|rx/od:", - vcvtdq2pd_2 = "rro:F30FuE6rM|rx/oq:|rm/yo:", - vcvtdq2ps_2 = "rmoy:0Fu5BrM", - vcvtpd2dq_2 = "rmoy:F20FuE6rM", - vcvtpd2ps_2 = "rmoy:660Fu5ArM", - vcvtps2dq_2 = "rmoy:660Fu5BrM", - vcvtps2pd_2 = "rro:0Fu5ArM|rx/oq:|rm/yo:", - vcvtsd2si_2 = "rr/do:F20Fu2DrM|rx/dq:|rr/qo:|rxq:", - vcvtsd2ss_3 = "rrro:F20FV5ArM|rrx/ooq:", - vcvtsi2sd_3 = "rrm/ood:F20FV2ArM|rrm/ooq:F20FVX2ArM", - vcvtsi2ss_3 = "rrm/ood:F30FV2ArM|rrm/ooq:F30FVX2ArM", - vcvtss2sd_3 = "rrro:F30FV5ArM|rrx/ood:", - vcvtss2si_2 = "rr/do:F30Fu2DrM|rxd:|rr/qo:|rx/qd:", - vcvttpd2dq_2 = "rmo:660FuE6rM|rm/oy:660FuLE6rM", - vcvttps2dq_2 = "rmoy:F30Fu5BrM", - vcvttsd2si_2 = "rr/do:F20Fu2CrM|rx/dq:|rr/qo:|rxq:", - vcvttss2si_2 = "rr/do:F30Fu2CrM|rxd:|rr/qo:|rx/qd:", - vdppd_4 = "rrmio:660F3AV41rMU", - vdpps_4 = "rrmioy:660F3AV40rMU", - vextractf128_3 = "mri/oy:660F3AuL19RmU", - vextractps_3 = "mri/do:660F3Au17RmU", - vhaddpd_3 = "rrmoy:660FV7CrM", - vhaddps_3 = "rrmoy:F20FV7CrM", - vhsubpd_3 = "rrmoy:660FV7DrM", - vhsubps_3 = "rrmoy:F20FV7DrM", - vinsertf128_4 = "rrmi/yyo:660F3AV18rMU", - vinsertps_4 = "rrrio:660F3AV21rMU|rrxi/ood:", - vldmxcsr_1 = "xd:0FuAE2m", - vmaskmovps_3 = "rrxoy:660F38V2CrM|xrroy:660F38V2ERm", - vmaskmovpd_3 = "rrxoy:660F38V2DrM|xrroy:660F38V2FRm", - vmovapd_2 = "rmoy:660Fu28rM|mroy:660Fu29Rm", - vmovaps_2 = "rmoy:0Fu28rM|mroy:0Fu29Rm", - vmovd_2 = "rm/od:660Fu6ErM|rm/oq:660FuX6ErM|mr/do:660Fu7ERm|mr/qo:", - vmovq_2 = "rro:F30Fu7ErM|rx/oq:|xr/qo:660FuD6Rm", - vmovddup_2 = "rmy:F20Fu12rM|rro:|rx/oq:", - vmovhlps_3 = "rrro:0FV12rM", - vmovhpd_2 = "xr/qo:660Fu17Rm", - vmovhpd_3 = "rrx/ooq:660FV16rM", - vmovhps_2 = "xr/qo:0Fu17Rm", - vmovhps_3 = "rrx/ooq:0FV16rM", - vmovlhps_3 = "rrro:0FV16rM", - vmovlpd_2 = "xr/qo:660Fu13Rm", - vmovlpd_3 = "rrx/ooq:660FV12rM", - vmovlps_2 = "xr/qo:0Fu13Rm", - vmovlps_3 = "rrx/ooq:0FV12rM", - vmovmskpd_2 = "rr/do:660Fu50rM|rr/dy:660FuL50rM", - vmovmskps_2 = "rr/do:0Fu50rM|rr/dy:0FuL50rM", - vmovntpd_2 = "xroy:660Fu2BRm", - vmovntps_2 = "xroy:0Fu2BRm", - vmovsd_2 = "rx/oq:F20Fu10rM|xr/qo:F20Fu11Rm", - vmovsd_3 = "rrro:F20FV10rM", - vmovshdup_2 = "rmoy:F30Fu16rM", - vmovsldup_2 = "rmoy:F30Fu12rM", - vmovss_2 = "rx/od:F30Fu10rM|xr/do:F30Fu11Rm", - vmovss_3 = "rrro:F30FV10rM", - vmovupd_2 = "rmoy:660Fu10rM|mroy:660Fu11Rm", - vmovups_2 = "rmoy:0Fu10rM|mroy:0Fu11Rm", - vorpd_3 = "rrmoy:660FV56rM", - vorps_3 = "rrmoy:0FV56rM", - vpermilpd_3 = "rrmoy:660F38V0DrM|rmioy:660F3Au05rMU", - vpermilps_3 = "rrmoy:660F38V0CrM|rmioy:660F3Au04rMU", - vperm2f128_4 = "rrmiy:660F3AV06rMU", - vptestpd_2 = "rmoy:660F38u0FrM", - vptestps_2 = "rmoy:660F38u0ErM", - vrcpps_2 = "rmoy:0Fu53rM", - vrcpss_3 = "rrro:F30FV53rM|rrx/ood:", - vrsqrtps_2 = "rmoy:0Fu52rM", - vrsqrtss_3 = "rrro:F30FV52rM|rrx/ood:", - vroundpd_3 = "rmioy:660F3Au09rMU", - vroundps_3 = "rmioy:660F3Au08rMU", - vroundsd_4 = "rrrio:660F3AV0BrMU|rrxi/ooq:", - vroundss_4 = "rrrio:660F3AV0ArMU|rrxi/ood:", - vshufpd_4 = "rrmioy:660FVC6rMU", - vshufps_4 = "rrmioy:0FVC6rMU", - vsqrtps_2 = "rmoy:0Fu51rM", - vsqrtss_2 = "rro:F30Fu51rM|rx/od:", - vsqrtpd_2 = "rmoy:660Fu51rM", - vsqrtsd_2 = "rro:F20Fu51rM|rx/oq:", - vstmxcsr_1 = "xd:0FuAE3m", - vucomisd_2 = "rro:660Fu2ErM|rx/oq:", - vucomiss_2 = "rro:0Fu2ErM|rx/od:", - vunpckhpd_3 = "rrmoy:660FV15rM", - vunpckhps_3 = "rrmoy:0FV15rM", - vunpcklpd_3 = "rrmoy:660FV14rM", - vunpcklps_3 = "rrmoy:0FV14rM", - vxorpd_3 = "rrmoy:660FV57rM", - vxorps_3 = "rrmoy:0FV57rM", - vzeroall_0 = "0FuL77", - vzeroupper_0 = "0Fu77", - - -- AVX2 FP ops - vbroadcastss_2 = "rx/od:660F38u18rM|rx/yd:|rro:|rr/yo:", - vbroadcastsd_2 = "rx/yq:660F38u19rM|rr/yo:", - -- *vgather* (!vsib) - vpermpd_3 = "rmiy:660F3AuX01rMU", - vpermps_3 = "rrmy:660F38V16rM", - - -- AVX, AVX2 integer ops - -- In general, xmm requires AVX, ymm requires AVX2. - vaesdec_3 = "rrmo:660F38VDErM", - vaesdeclast_3 = "rrmo:660F38VDFrM", - vaesenc_3 = "rrmo:660F38VDCrM", - vaesenclast_3 = "rrmo:660F38VDDrM", - vaesimc_2 = "rmo:660F38uDBrM", - vaeskeygenassist_3 = "rmio:660F3AuDFrMU", - vlddqu_2 = "rxoy:F20FuF0rM", - vmaskmovdqu_2 = "rro:660FuF7rM", - vmovdqa_2 = "rmoy:660Fu6FrM|mroy:660Fu7FRm", - vmovdqu_2 = "rmoy:F30Fu6FrM|mroy:F30Fu7FRm", - vmovntdq_2 = "xroy:660FuE7Rm", - vmovntdqa_2 = "rxoy:660F38u2ArM", - vmpsadbw_4 = "rrmioy:660F3AV42rMU", - vpabsb_2 = "rmoy:660F38u1CrM", - vpabsd_2 = "rmoy:660F38u1ErM", - vpabsw_2 = "rmoy:660F38u1DrM", - vpackusdw_3 = "rrmoy:660F38V2BrM", - vpalignr_4 = "rrmioy:660F3AV0FrMU", - vpblendvb_4 = "rrmroy:660F3AV4CrMs", - vpblendw_4 = "rrmioy:660F3AV0ErMU", - vpclmulqdq_4 = "rrmio:660F3AV44rMU", - vpcmpeqq_3 = "rrmoy:660F38V29rM", - vpcmpestri_3 = "rmio:660F3Au61rMU", - vpcmpestrm_3 = "rmio:660F3Au60rMU", - vpcmpgtq_3 = "rrmoy:660F38V37rM", - vpcmpistri_3 = "rmio:660F3Au63rMU", - vpcmpistrm_3 = "rmio:660F3Au62rMU", - vpextrb_3 = "rri/do:660F3Au14nRmU|rri/qo:|xri/bo:", - vpextrw_3 = "rri/do:660FuC5rMU|xri/wo:660F3Au15nRmU", - vpextrd_3 = "mri/do:660F3Au16RmU", - vpextrq_3 = "mri/qo:660F3Au16RmU", - vphaddw_3 = "rrmoy:660F38V01rM", - vphaddd_3 = "rrmoy:660F38V02rM", - vphaddsw_3 = "rrmoy:660F38V03rM", - vphminposuw_2 = "rmo:660F38u41rM", - vphsubw_3 = "rrmoy:660F38V05rM", - vphsubd_3 = "rrmoy:660F38V06rM", - vphsubsw_3 = "rrmoy:660F38V07rM", - vpinsrb_4 = "rrri/ood:660F3AV20rMU|rrxi/oob:", - vpinsrw_4 = "rrri/ood:660FVC4rMU|rrxi/oow:", - vpinsrd_4 = "rrmi/ood:660F3AV22rMU", - vpinsrq_4 = "rrmi/ooq:660F3AVX22rMU", - vpmaddubsw_3 = "rrmoy:660F38V04rM", - vpmaxsb_3 = "rrmoy:660F38V3CrM", - vpmaxsd_3 = "rrmoy:660F38V3DrM", - vpmaxuw_3 = "rrmoy:660F38V3ErM", - vpmaxud_3 = "rrmoy:660F38V3FrM", - vpminsb_3 = "rrmoy:660F38V38rM", - vpminsd_3 = "rrmoy:660F38V39rM", - vpminuw_3 = "rrmoy:660F38V3ArM", - vpminud_3 = "rrmoy:660F38V3BrM", - vpmovmskb_2 = "rr/do:660FuD7rM|rr/dy:660FuLD7rM", - vpmovsxbw_2 = "rroy:660F38u20rM|rx/oq:|rx/yo:", - vpmovsxbd_2 = "rroy:660F38u21rM|rx/od:|rx/yq:", - vpmovsxbq_2 = "rroy:660F38u22rM|rx/ow:|rx/yd:", - vpmovsxwd_2 = "rroy:660F38u23rM|rx/oq:|rx/yo:", - vpmovsxwq_2 = "rroy:660F38u24rM|rx/od:|rx/yq:", - vpmovsxdq_2 = "rroy:660F38u25rM|rx/oq:|rx/yo:", - vpmovzxbw_2 = "rroy:660F38u30rM|rx/oq:|rx/yo:", - vpmovzxbd_2 = "rroy:660F38u31rM|rx/od:|rx/yq:", - vpmovzxbq_2 = "rroy:660F38u32rM|rx/ow:|rx/yd:", - vpmovzxwd_2 = "rroy:660F38u33rM|rx/oq:|rx/yo:", - vpmovzxwq_2 = "rroy:660F38u34rM|rx/od:|rx/yq:", - vpmovzxdq_2 = "rroy:660F38u35rM|rx/oq:|rx/yo:", - vpmuldq_3 = "rrmoy:660F38V28rM", - vpmulhrsw_3 = "rrmoy:660F38V0BrM", - vpmulld_3 = "rrmoy:660F38V40rM", - vpshufb_3 = "rrmoy:660F38V00rM", - vpshufd_3 = "rmioy:660Fu70rMU", - vpshufhw_3 = "rmioy:F30Fu70rMU", - vpshuflw_3 = "rmioy:F20Fu70rMU", - vpsignb_3 = "rrmoy:660F38V08rM", - vpsignw_3 = "rrmoy:660F38V09rM", - vpsignd_3 = "rrmoy:660F38V0ArM", - vpslldq_3 = "rrioy:660Fv737mU", - vpsllw_3 = "rrmoy:660FVF1rM|rrioy:660Fv716mU", - vpslld_3 = "rrmoy:660FVF2rM|rrioy:660Fv726mU", - vpsllq_3 = "rrmoy:660FVF3rM|rrioy:660Fv736mU", - vpsraw_3 = "rrmoy:660FVE1rM|rrioy:660Fv714mU", - vpsrad_3 = "rrmoy:660FVE2rM|rrioy:660Fv724mU", - vpsrldq_3 = "rrioy:660Fv733mU", - vpsrlw_3 = "rrmoy:660FVD1rM|rrioy:660Fv712mU", - vpsrld_3 = "rrmoy:660FVD2rM|rrioy:660Fv722mU", - vpsrlq_3 = "rrmoy:660FVD3rM|rrioy:660Fv732mU", - vptest_2 = "rmoy:660F38u17rM", - - -- AVX2 integer ops - vbroadcasti128_2 = "rx/yo:660F38u5ArM", - vinserti128_4 = "rrmi/yyo:660F3AV38rMU", - vextracti128_3 = "mri/oy:660F3AuL39RmU", - vpblendd_4 = "rrmioy:660F3AV02rMU", - vpbroadcastb_2 = "rro:660F38u78rM|rx/ob:|rr/yo:|rx/yb:", - vpbroadcastw_2 = "rro:660F38u79rM|rx/ow:|rr/yo:|rx/yw:", - vpbroadcastd_2 = "rro:660F38u58rM|rx/od:|rr/yo:|rx/yd:", - vpbroadcastq_2 = "rro:660F38u59rM|rx/oq:|rr/yo:|rx/yq:", - vpermd_3 = "rrmy:660F38V36rM", - vpermq_3 = "rmiy:660F3AuX00rMU", - -- *vpgather* (!vsib) - vperm2i128_4 = "rrmiy:660F3AV46rMU", - vpmaskmovd_3 = "rrxoy:660F38V8CrM|xrroy:660F38V8ERm", - vpmaskmovq_3 = "rrxoy:660F38VX8CrM|xrroy:660F38VX8ERm", - vpsllvd_3 = "rrmoy:660F38V47rM", - vpsllvq_3 = "rrmoy:660F38VX47rM", - vpsravd_3 = "rrmoy:660F38V46rM", - vpsrlvd_3 = "rrmoy:660F38V45rM", - vpsrlvq_3 = "rrmoy:660F38VX45rM", - - -- Intel ADX - adcx_2 = "rmqd:660F38F6rM", - adox_2 = "rmqd:F30F38F6rM", - - -- BMI1 - andn_3 = "rrmqd:0F38VF2rM", - bextr_3 = "rmrqd:0F38wF7rM", - blsi_2 = "rmqd:0F38vF33m", - blsmsk_2 = "rmqd:0F38vF32m", - blsr_2 = "rmqd:0F38vF31m", - tzcnt_2 = "rmqdw:F30FBCrM", - - -- BMI2 - bzhi_3 = "rmrqd:0F38wF5rM", - mulx_3 = "rrmqd:F20F38VF6rM", - pdep_3 = "rrmqd:F20F38VF5rM", - pext_3 = "rrmqd:F30F38VF5rM", - rorx_3 = "rmSqd:F20F3AuF0rMS", - sarx_3 = "rmrqd:F30F38wF7rM", - shrx_3 = "rmrqd:F20F38wF7rM", - shlx_3 = "rmrqd:660F38wF7rM", - - -- FMA3 - vfmaddsub132pd_3 = "rrmoy:660F38VX96rM", - vfmaddsub132ps_3 = "rrmoy:660F38V96rM", - vfmaddsub213pd_3 = "rrmoy:660F38VXA6rM", - vfmaddsub213ps_3 = "rrmoy:660F38VA6rM", - vfmaddsub231pd_3 = "rrmoy:660F38VXB6rM", - vfmaddsub231ps_3 = "rrmoy:660F38VB6rM", - - vfmsubadd132pd_3 = "rrmoy:660F38VX97rM", - vfmsubadd132ps_3 = "rrmoy:660F38V97rM", - vfmsubadd213pd_3 = "rrmoy:660F38VXA7rM", - vfmsubadd213ps_3 = "rrmoy:660F38VA7rM", - vfmsubadd231pd_3 = "rrmoy:660F38VXB7rM", - vfmsubadd231ps_3 = "rrmoy:660F38VB7rM", - - vfmadd132pd_3 = "rrmoy:660F38VX98rM", - vfmadd132ps_3 = "rrmoy:660F38V98rM", - vfmadd132sd_3 = "rrro:660F38VX99rM|rrx/ooq:", - vfmadd132ss_3 = "rrro:660F38V99rM|rrx/ood:", - vfmadd213pd_3 = "rrmoy:660F38VXA8rM", - vfmadd213ps_3 = "rrmoy:660F38VA8rM", - vfmadd213sd_3 = "rrro:660F38VXA9rM|rrx/ooq:", - vfmadd213ss_3 = "rrro:660F38VA9rM|rrx/ood:", - vfmadd231pd_3 = "rrmoy:660F38VXB8rM", - vfmadd231ps_3 = "rrmoy:660F38VB8rM", - vfmadd231sd_3 = "rrro:660F38VXB9rM|rrx/ooq:", - vfmadd231ss_3 = "rrro:660F38VB9rM|rrx/ood:", - - vfmsub132pd_3 = "rrmoy:660F38VX9ArM", - vfmsub132ps_3 = "rrmoy:660F38V9ArM", - vfmsub132sd_3 = "rrro:660F38VX9BrM|rrx/ooq:", - vfmsub132ss_3 = "rrro:660F38V9BrM|rrx/ood:", - vfmsub213pd_3 = "rrmoy:660F38VXAArM", - vfmsub213ps_3 = "rrmoy:660F38VAArM", - vfmsub213sd_3 = "rrro:660F38VXABrM|rrx/ooq:", - vfmsub213ss_3 = "rrro:660F38VABrM|rrx/ood:", - vfmsub231pd_3 = "rrmoy:660F38VXBArM", - vfmsub231ps_3 = "rrmoy:660F38VBArM", - vfmsub231sd_3 = "rrro:660F38VXBBrM|rrx/ooq:", - vfmsub231ss_3 = "rrro:660F38VBBrM|rrx/ood:", - - vfnmadd132pd_3 = "rrmoy:660F38VX9CrM", - vfnmadd132ps_3 = "rrmoy:660F38V9CrM", - vfnmadd132sd_3 = "rrro:660F38VX9DrM|rrx/ooq:", - vfnmadd132ss_3 = "rrro:660F38V9DrM|rrx/ood:", - vfnmadd213pd_3 = "rrmoy:660F38VXACrM", - vfnmadd213ps_3 = "rrmoy:660F38VACrM", - vfnmadd213sd_3 = "rrro:660F38VXADrM|rrx/ooq:", - vfnmadd213ss_3 = "rrro:660F38VADrM|rrx/ood:", - vfnmadd231pd_3 = "rrmoy:660F38VXBCrM", - vfnmadd231ps_3 = "rrmoy:660F38VBCrM", - vfnmadd231sd_3 = "rrro:660F38VXBDrM|rrx/ooq:", - vfnmadd231ss_3 = "rrro:660F38VBDrM|rrx/ood:", - - vfnmsub132pd_3 = "rrmoy:660F38VX9ErM", - vfnmsub132ps_3 = "rrmoy:660F38V9ErM", - vfnmsub132sd_3 = "rrro:660F38VX9FrM|rrx/ooq:", - vfnmsub132ss_3 = "rrro:660F38V9FrM|rrx/ood:", - vfnmsub213pd_3 = "rrmoy:660F38VXAErM", - vfnmsub213ps_3 = "rrmoy:660F38VAErM", - vfnmsub213sd_3 = "rrro:660F38VXAFrM|rrx/ooq:", - vfnmsub213ss_3 = "rrro:660F38VAFrM|rrx/ood:", - vfnmsub231pd_3 = "rrmoy:660F38VXBErM", - vfnmsub231ps_3 = "rrmoy:660F38VBErM", - vfnmsub231sd_3 = "rrro:660F38VXBFrM|rrx/ooq:", - vfnmsub231ss_3 = "rrro:660F38VBFrM|rrx/ood:", -} - ------------------------------------------------------------------------------- - --- Arithmetic ops. -for name,n in pairs{ add = 0, ["or"] = 1, adc = 2, sbb = 3, - ["and"] = 4, sub = 5, xor = 6, cmp = 7 } do - local n8 = shl(n, 3) - map_op[name.."_2"] = format( - "mr:%02XRm|rm:%02XrM|mI1qdw:81%XmI|mS1qdw:83%XmS|Ri1qdwb:%02Xri|mi1qdwb:81%Xmi", - 1+n8, 3+n8, n, n, 5+n8, n) -end - --- Shift ops. -for name,n in pairs{ rol = 0, ror = 1, rcl = 2, rcr = 3, - shl = 4, shr = 5, sar = 7, sal = 4 } do - map_op[name.."_2"] = format("m1:D1%Xm|mC1qdwb:D3%Xm|mi:C1%XmU", n, n, n) -end - --- Conditional ops. -for cc,n in pairs(map_cc) do - map_op["j"..cc.."_1"] = format("J.:n0F8%XJ", n) -- short: 7%X - map_op["set"..cc.."_1"] = format("mb:n0F9%X2m", n) - map_op["cmov"..cc.."_2"] = format("rmqdw:0F4%XrM", n) -- P6+ -end - --- FP arithmetic ops. -for name,n in pairs{ add = 0, mul = 1, com = 2, comp = 3, - sub = 4, subr = 5, div = 6, divr = 7 } do - local nc = 0xc0 + shl(n, 3) - local nr = nc + (n < 4 and 0 or (n % 2 == 0 and 8 or -8)) - local fn = "f"..name - map_op[fn.."_1"] = format("ff:D8%02Xr|xd:D8%Xm|xq:nDC%Xm", nc, n, n) - if n == 2 or n == 3 then - map_op[fn.."_2"] = format("Fff:D8%02XR|Fx2d:D8%XM|Fx2q:nDC%XM", nc, n, n) - else - map_op[fn.."_2"] = format("Fff:D8%02XR|fFf:DC%02Xr|Fx2d:D8%XM|Fx2q:nDC%XM", nc, nr, n, n) - map_op[fn.."p_1"] = format("ff:DE%02Xr", nr) - map_op[fn.."p_2"] = format("fFf:DE%02Xr", nr) - end - map_op["fi"..name.."_1"] = format("xd:DA%Xm|xw:nDE%Xm", n, n) -end - --- FP conditional moves. -for cc,n in pairs{ b=0, e=1, be=2, u=3, nb=4, ne=5, nbe=6, nu=7 } do - local nc = 0xdac0 + shl(band(n, 3), 3) + shl(band(n, 4), 6) - map_op["fcmov"..cc.."_1"] = format("ff:%04Xr", nc) -- P6+ - map_op["fcmov"..cc.."_2"] = format("Fff:%04XR", nc) -- P6+ -end - --- SSE / AVX FP arithmetic ops. -for name,n in pairs{ sqrt = 1, add = 8, mul = 9, - sub = 12, min = 13, div = 14, max = 15 } do - map_op[name.."ps_2"] = format("rmo:0F5%XrM", n) - map_op[name.."ss_2"] = format("rro:F30F5%XrM|rx/od:", n) - map_op[name.."pd_2"] = format("rmo:660F5%XrM", n) - map_op[name.."sd_2"] = format("rro:F20F5%XrM|rx/oq:", n) - if n ~= 1 then - map_op["v"..name.."ps_3"] = format("rrmoy:0FV5%XrM", n) - map_op["v"..name.."ss_3"] = format("rrro:F30FV5%XrM|rrx/ood:", n) - map_op["v"..name.."pd_3"] = format("rrmoy:660FV5%XrM", n) - map_op["v"..name.."sd_3"] = format("rrro:F20FV5%XrM|rrx/ooq:", n) - end -end - --- SSE2 / AVX / AVX2 integer arithmetic ops (66 0F leaf). -for name,n in pairs{ - paddb = 0xFC, paddw = 0xFD, paddd = 0xFE, paddq = 0xD4, - paddsb = 0xEC, paddsw = 0xED, packssdw = 0x6B, - packsswb = 0x63, packuswb = 0x67, paddusb = 0xDC, - paddusw = 0xDD, pand = 0xDB, pandn = 0xDF, pavgb = 0xE0, - pavgw = 0xE3, pcmpeqb = 0x74, pcmpeqd = 0x76, - pcmpeqw = 0x75, pcmpgtb = 0x64, pcmpgtd = 0x66, - pcmpgtw = 0x65, pmaddwd = 0xF5, pmaxsw = 0xEE, - pmaxub = 0xDE, pminsw = 0xEA, pminub = 0xDA, - pmulhuw = 0xE4, pmulhw = 0xE5, pmullw = 0xD5, - pmuludq = 0xF4, por = 0xEB, psadbw = 0xF6, psubb = 0xF8, - psubw = 0xF9, psubd = 0xFA, psubq = 0xFB, psubsb = 0xE8, - psubsw = 0xE9, psubusb = 0xD8, psubusw = 0xD9, - punpckhbw = 0x68, punpckhwd = 0x69, punpckhdq = 0x6A, - punpckhqdq = 0x6D, punpcklbw = 0x60, punpcklwd = 0x61, - punpckldq = 0x62, punpcklqdq = 0x6C, pxor = 0xEF -} do - map_op[name.."_2"] = format("rmo:660F%02XrM", n) - map_op["v"..name.."_3"] = format("rrmoy:660FV%02XrM", n) -end - ------------------------------------------------------------------------------- - -local map_vexarg = { u = false, v = 1, V = 2 } - --- Process pattern string. -local function dopattern(pat, args, sz, op, needrex) - local digit, addin, vex - local opcode = 0 - local szov = sz - local narg = 1 - local rex = 0 - - -- Limit number of section buffer positions used by a single dasm_put(). - -- A single opcode needs a maximum of 6 positions. - if secpos+6 > maxsecpos then wflush() end - - -- Process each character. - for c in gmatch(pat.."|", ".") do - if match(c, "%x") then -- Hex digit. - digit = byte(c) - 48 - if digit > 48 then digit = digit - 39 - elseif digit > 16 then digit = digit - 7 end - opcode = opcode*16 + digit - addin = nil - elseif c == "n" then -- Disable operand size mods for opcode. - szov = nil - elseif c == "X" then -- Force REX.W. - rex = 8 - elseif c == "L" then -- Force VEX.L. - vex.l = true - elseif c == "r" then -- Merge 1st operand regno. into opcode. - addin = args[1]; opcode = opcode + (addin.reg % 8) - if narg < 2 then narg = 2 end - elseif c == "R" then -- Merge 2nd operand regno. into opcode. - addin = args[2]; opcode = opcode + (addin.reg % 8) - narg = 3 - elseif c == "m" or c == "M" then -- Encode ModRM/SIB. - local s - if addin then - s = addin.reg - opcode = opcode - band(s, 7) -- Undo regno opcode merge. - else - s = band(opcode, 15) -- Undo last digit. - opcode = shr(opcode, 4) - end - local nn = c == "m" and 1 or 2 - local t = args[nn] - if narg <= nn then narg = nn + 1 end - if szov == "q" and rex == 0 then rex = rex + 8 end - if t.reg and t.reg > 7 then rex = rex + 1 end - if t.xreg and t.xreg > 7 then rex = rex + 2 end - if s > 7 then rex = rex + 4 end - if needrex then rex = rex + 16 end - local psz, sk = wputop(szov, opcode, rex, vex, s < 0, t.vreg or t.vxreg) - opcode = nil - local imark = sub(pat, -1) -- Force a mark (ugly). - -- Put ModRM/SIB with regno/last digit as spare. - wputmrmsib(t, imark, s, addin and addin.vreg, psz, sk) - addin = nil - elseif map_vexarg[c] ~= nil then -- Encode using VEX prefix - local b = band(opcode, 255); opcode = shr(opcode, 8) - local m = 1 - if b == 0x38 then m = 2 - elseif b == 0x3a then m = 3 end - if m ~= 1 then b = band(opcode, 255); opcode = shr(opcode, 8) end - if b ~= 0x0f then - werror("expected `0F', `0F38', or `0F3A' to precede `"..c.. - "' in pattern `"..pat.."' for `"..op.."'") - end - local v = map_vexarg[c] - if v then v = remove(args, v) end - b = band(opcode, 255) - local p = 0 - if b == 0x66 then p = 1 - elseif b == 0xf3 then p = 2 - elseif b == 0xf2 then p = 3 end - if p ~= 0 then opcode = shr(opcode, 8) end - if opcode ~= 0 then wputop(nil, opcode, 0); opcode = 0 end - vex = { m = m, p = p, v = v } - else - if opcode then -- Flush opcode. - if szov == "q" and rex == 0 then rex = rex + 8 end - if needrex then rex = rex + 16 end - if addin and addin.reg == -1 then - local psz, sk = wputop(szov, opcode - 7, rex, vex, true) - wvreg("opcode", addin.vreg, psz, sk) - else - if addin and addin.reg > 7 then rex = rex + 1 end - wputop(szov, opcode, rex, vex) - end - opcode = nil - end - if c == "|" then break end - if c == "o" then -- Offset (pure 32 bit displacement). - wputdarg(args[1].disp); if narg < 2 then narg = 2 end - elseif c == "O" then - wputdarg(args[2].disp); narg = 3 - else - -- Anything else is an immediate operand. - local a = args[narg] - narg = narg + 1 - local mode, imm = a.mode, a.imm - if mode == "iJ" and not match("iIJ", c) then - werror("bad operand size for label") - end - if c == "S" then - wputsbarg(imm) - elseif c == "U" then - wputbarg(imm) - elseif c == "W" then - wputwarg(imm) - elseif c == "i" or c == "I" then - if mode == "iJ" then - wputlabel("IMM_", imm, 1) - elseif mode == "iI" and c == "I" then - waction(sz == "w" and "IMM_WB" or "IMM_DB", imm) - else - wputszarg(sz, imm) - end - elseif c == "J" then - if mode == "iPJ" then - waction("REL_A", imm) -- !x64 (secpos) - else - wputlabel("REL_", imm, 2) - end - elseif c == "s" then - local reg = a.reg - if reg < 0 then - wputb(0) - wvreg("imm.hi", a.vreg) - else - wputb(shl(reg, 4)) - end - else - werror("bad char `"..c.."' in pattern `"..pat.."' for `"..op.."'") - end - end - end - end -end - ------------------------------------------------------------------------------- - --- Mapping of operand modes to short names. Suppress output with '#'. -local map_modename = { - r = "reg", R = "eax", C = "cl", x = "mem", m = "mrm", i = "imm", - f = "stx", F = "st0", J = "lbl", ["1"] = "1", - I = "#", S = "#", O = "#", -} - --- Return a table/string showing all possible operand modes. -local function templatehelp(template, nparams) - if nparams == 0 then return "" end - local t = {} - for tm in gmatch(template, "[^%|]+") do - local s = map_modename[sub(tm, 1, 1)] - s = s..gsub(sub(tm, 2, nparams), ".", function(c) - return ", "..map_modename[c] - end) - if not match(s, "#") then t[#t+1] = s end - end - return t -end - --- Match operand modes against mode match part of template. -local function matchtm(tm, args) - for i=1,#args do - if not match(args[i].mode, sub(tm, i, i)) then return end - end - return true -end - --- Handle opcodes defined with template strings. -map_op[".template__"] = function(params, template, nparams) - if not params then return templatehelp(template, nparams) end - local args = {} - - -- Zero-operand opcodes have no match part. - if #params == 0 then - dopattern(template, args, "d", params.op, nil) - return - end - - -- Determine common operand size (coerce undefined size) or flag as mixed. - local sz, szmix, needrex - for i,p in ipairs(params) do - args[i] = parseoperand(p) - local nsz = args[i].opsize - if nsz then - if sz and sz ~= nsz then szmix = true else sz = nsz end - end - local nrex = args[i].needrex - if nrex ~= nil then - if needrex == nil then - needrex = nrex - elseif needrex ~= nrex then - werror("bad mix of byte-addressable registers") - end - end - end - - -- Try all match:pattern pairs (separated by '|'). - local gotmatch, lastpat - for tm in gmatch(template, "[^%|]+") do - -- Split off size match (starts after mode match) and pattern string. - local szm, pat = match(tm, "^(.-):(.*)$", #args+1) - if pat == "" then pat = lastpat else lastpat = pat end - if matchtm(tm, args) then - local prefix = sub(szm, 1, 1) - if prefix == "/" then -- Exactly match leading operand sizes. - for i = #szm,1,-1 do - if i == 1 then - dopattern(pat, args, sz, params.op, needrex) -- Process pattern. - return - elseif args[i-1].opsize ~= sub(szm, i, i) then - break - end - end - else -- Match common operand size. - local szp = sz - if szm == "" then szm = x64 and "qdwb" or "dwb" end -- Default sizes. - if prefix == "1" then szp = args[1].opsize; szmix = nil - elseif prefix == "2" then szp = args[2].opsize; szmix = nil end - if not szmix and (prefix == "." or match(szm, szp or "#")) then - dopattern(pat, args, szp, params.op, needrex) -- Process pattern. - return - end - end - gotmatch = true - end - end - - local msg = "bad operand mode" - if gotmatch then - if szmix then - msg = "mixed operand size" - else - msg = sz and "bad operand size" or "missing operand size" - end - end - - werror(msg.." in `"..opmodestr(params.op, args).."'") -end - ------------------------------------------------------------------------------- - --- x64-specific opcode for 64 bit immediates and displacements. -if x64 then - function map_op.mov64_2(params) - if not params then return { "reg, imm", "reg, [disp]", "[disp], reg" } end - if secpos+2 > maxsecpos then wflush() end - local opcode, op64, sz, rex, vreg - local op64 = match(params[1], "^%[%s*(.-)%s*%]$") - if op64 then - local a = parseoperand(params[2]) - if a.mode ~= "rmR" then werror("bad operand mode") end - sz = a.opsize - rex = sz == "q" and 8 or 0 - opcode = 0xa3 - else - op64 = match(params[2], "^%[%s*(.-)%s*%]$") - local a = parseoperand(params[1]) - if op64 then - if a.mode ~= "rmR" then werror("bad operand mode") end - sz = a.opsize - rex = sz == "q" and 8 or 0 - opcode = 0xa1 - else - if sub(a.mode, 1, 1) ~= "r" or a.opsize ~= "q" then - werror("bad operand mode") - end - op64 = params[2] - if a.reg == -1 then - vreg = a.vreg - opcode = 0xb8 - else - opcode = 0xb8 + band(a.reg, 7) - end - rex = a.reg > 7 and 9 or 8 - end - end - local psz, sk = wputop(sz, opcode, rex, nil, vreg) - wvreg("opcode", vreg, psz, sk) - waction("IMM_D", format("(unsigned int)(%s)", op64)) - waction("IMM_D", format("(unsigned int)((%s)>>32)", op64)) - end -end - ------------------------------------------------------------------------------- - --- Pseudo-opcodes for data storage. -local function op_data(params) - if not params then return "imm..." end - local sz = sub(params.op, 2, 2) - if sz == "a" then sz = addrsize end - for _,p in ipairs(params) do - local a = parseoperand(p) - if sub(a.mode, 1, 1) ~= "i" or (a.opsize and a.opsize ~= sz) then - werror("bad mode or size in `"..p.."'") - end - if a.mode == "iJ" then - wputlabel("IMM_", a.imm, 1) - else - wputszarg(sz, a.imm) - end - if secpos+2 > maxsecpos then wflush() end - end -end - -map_op[".byte_*"] = op_data -map_op[".sbyte_*"] = op_data -map_op[".word_*"] = op_data -map_op[".dword_*"] = op_data -map_op[".aword_*"] = op_data - ------------------------------------------------------------------------------- - --- Pseudo-opcode to mark the position where the action list is to be emitted. -map_op[".actionlist_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeactions(out, name) end) -end - --- Pseudo-opcode to mark the position where the global enum is to be emitted. -map_op[".globals_1"] = function(params) - if not params then return "prefix" end - local prefix = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeglobals(out, prefix) end) -end - --- Pseudo-opcode to mark the position where the global names are to be emitted. -map_op[".globalnames_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeglobalnames(out, name) end) -end - --- Pseudo-opcode to mark the position where the extern names are to be emitted. -map_op[".externnames_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeexternnames(out, name) end) -end - ------------------------------------------------------------------------------- - --- Label pseudo-opcode (converted from trailing colon form). -map_op[".label_2"] = function(params) - if not params then return "[1-9] | ->global | =>pcexpr [, addr]" end - if secpos+2 > maxsecpos then wflush() end - local a = parseoperand(params[1]) - local mode, imm = a.mode, a.imm - if type(imm) == "number" and (mode == "iJ" or (imm >= 1 and imm <= 9)) then - -- Local label (1: ... 9:) or global label (->global:). - waction("LABEL_LG", nil, 1) - wputxb(imm) - elseif mode == "iJ" then - -- PC label (=>pcexpr:). - waction("LABEL_PC", imm) - else - werror("bad label definition") - end - -- SETLABEL must immediately follow LABEL_LG/LABEL_PC. - local addr = params[2] - if addr then - local a = parseoperand(addr) - if a.mode == "iPJ" then - waction("SETLABEL", a.imm) - else - werror("bad label assignment") - end - end -end -map_op[".label_1"] = map_op[".label_2"] - ------------------------------------------------------------------------------- - --- Alignment pseudo-opcode. -map_op[".align_1"] = function(params) - if not params then return "numpow2" end - if secpos+1 > maxsecpos then wflush() end - local align = tonumber(params[1]) or map_opsizenum[map_opsize[params[1]]] - if align then - local x = align - -- Must be a power of 2 in the range (2 ... 256). - for i=1,8 do - x = x / 2 - if x == 1 then - waction("ALIGN", nil, 1) - wputxb(align-1) -- Action byte is 2**n-1. - return - end - end - end - werror("bad alignment") -end - --- Spacing pseudo-opcode. -map_op[".space_2"] = function(params) - if not params then return "num [, filler]" end - if secpos+1 > maxsecpos then wflush() end - waction("SPACE", params[1]) - local fill = params[2] - if fill then - fill = tonumber(fill) - if not fill or fill < 0 or fill > 255 then werror("bad filler") end - end - wputxb(fill or 0) -end -map_op[".space_1"] = map_op[".space_2"] - ------------------------------------------------------------------------------- - --- Pseudo-opcode for (primitive) type definitions (map to C types). -map_op[".type_3"] = function(params, nparams) - if not params then - return nparams == 2 and "name, ctype" or "name, ctype, reg" - end - local name, ctype, reg = params[1], params[2], params[3] - if not match(name, "^[%a_][%w_]*$") then - werror("bad type name `"..name.."'") - end - local tp = map_type[name] - if tp then - werror("duplicate type `"..name.."'") - end - if reg and not map_reg_valid_base[reg] then - werror("bad base register `"..(map_reg_rev[reg] or reg).."'") - end - -- Add #type to defines. A bit unclean to put it in map_archdef. - map_archdef["#"..name] = "sizeof("..ctype..")" - -- Add new type and emit shortcut define. - local num = ctypenum + 1 - map_type[name] = { - ctype = ctype, - ctypefmt = format("Dt%X(%%s)", num), - reg = reg, - } - wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) - ctypenum = num -end -map_op[".type_2"] = map_op[".type_3"] - --- Dump type definitions. -local function dumptypes(out, lvl) - local t = {} - for name in pairs(map_type) do t[#t+1] = name end - sort(t) - out:write("Type definitions:\n") - for _,name in ipairs(t) do - local tp = map_type[name] - local reg = tp.reg and map_reg_rev[tp.reg] or "" - out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) - end - out:write("\n") -end - ------------------------------------------------------------------------------- - --- Set the current section. -function _M.section(num) - waction("SECTION") - wputxb(num) - wflush(true) -- SECTION is a terminal action. -end - ------------------------------------------------------------------------------- - --- Dump architecture description. -function _M.dumparch(out) - out:write(format("DynASM %s version %s, released %s\n\n", - _info.arch, _info.version, _info.release)) - dumpregs(out) - dumpactions(out) -end - --- Dump all user defined elements. -function _M.dumpdef(out, lvl) - dumptypes(out, lvl) - dumpglobals(out, lvl) - dumpexterns(out, lvl) -end - ------------------------------------------------------------------------------- - --- Pass callbacks from/to the DynASM core. -function _M.passcb(wl, we, wf, ww) - wline, werror, wfatal, wwarn = wl, we, wf, ww - return wflush -end - --- Setup the arch-specific module. -function _M.setup(arch, opt) - g_arch, g_opt = arch, opt -end - --- Merge the core maps and the arch-specific maps. -function _M.mergemaps(map_coreop, map_def) - setmetatable(map_op, { __index = map_coreop }) - setmetatable(map_def, { __index = map_archdef }) - return map_op, map_def -end - -return _M - ------------------------------------------------------------------------------- - diff --git a/lib/LuaJIT/dynasm/dynasm.lua b/lib/LuaJIT/dynasm/dynasm.lua deleted file mode 100644 index 5ec21a7..0000000 --- a/lib/LuaJIT/dynasm/dynasm.lua +++ /dev/null @@ -1,1094 +0,0 @@ ------------------------------------------------------------------------------- --- DynASM. A dynamic assembler for code generation engines. --- Originally designed and implemented for LuaJIT. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- See below for full copyright notice. ------------------------------------------------------------------------------- - --- Application information. -local _info = { - name = "DynASM", - description = "A dynamic assembler for code generation engines", - version = "1.4.0", - vernum = 10400, - release = "2015-10-18", - author = "Mike Pall", - url = "http://luajit.org/dynasm.html", - license = "MIT", - copyright = [[ -Copyright (C) 2005-2017 Mike Pall. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -[ MIT license: http://www.opensource.org/licenses/mit-license.php ] -]], -} - --- Cache library functions. -local type, pairs, ipairs = type, pairs, ipairs -local pcall, error, assert = pcall, error, assert -local _s = string -local sub, match, gmatch, gsub = _s.sub, _s.match, _s.gmatch, _s.gsub -local format, rep, upper = _s.format, _s.rep, _s.upper -local _t = table -local insert, remove, concat, sort = _t.insert, _t.remove, _t.concat, _t.sort -local exit = os.exit -local io = io -local stdin, stdout, stderr = io.stdin, io.stdout, io.stderr - ------------------------------------------------------------------------------- - --- Program options. -local g_opt = {} - --- Global state for current file. -local g_fname, g_curline, g_indent, g_lineno, g_synclineno, g_arch -local g_errcount = 0 - --- Write buffer for output file. -local g_wbuffer, g_capbuffer - ------------------------------------------------------------------------------- - --- Write an output line (or callback function) to the buffer. -local function wline(line, needindent) - local buf = g_capbuffer or g_wbuffer - buf[#buf+1] = needindent and g_indent..line or line - g_synclineno = g_synclineno + 1 -end - --- Write assembler line as a comment, if requestd. -local function wcomment(aline) - if g_opt.comment then - wline(g_opt.comment..aline..g_opt.endcomment, true) - end -end - --- Resync CPP line numbers. -local function wsync() - if g_synclineno ~= g_lineno and g_opt.cpp then - wline("#line "..g_lineno..' "'..g_fname..'"') - g_synclineno = g_lineno - end -end - --- Dummy action flush function. Replaced with arch-specific function later. -local function wflush(term) -end - --- Dump all buffered output lines. -local function wdumplines(out, buf) - for _,line in ipairs(buf) do - if type(line) == "string" then - assert(out:write(line, "\n")) - else - -- Special callback to dynamically insert lines after end of processing. - line(out) - end - end -end - ------------------------------------------------------------------------------- - --- Emit an error. Processing continues with next statement. -local function werror(msg) - error(format("%s:%s: error: %s:\n%s", g_fname, g_lineno, msg, g_curline), 0) -end - --- Emit a fatal error. Processing stops. -local function wfatal(msg) - g_errcount = "fatal" - werror(msg) -end - --- Print a warning. Processing continues. -local function wwarn(msg) - stderr:write(format("%s:%s: warning: %s:\n%s\n", - g_fname, g_lineno, msg, g_curline)) -end - --- Print caught error message. But suppress excessive errors. -local function wprinterr(...) - if type(g_errcount) == "number" then - -- Regular error. - g_errcount = g_errcount + 1 - if g_errcount < 21 then -- Seems to be a reasonable limit. - stderr:write(...) - elseif g_errcount == 21 then - stderr:write(g_fname, - ":*: warning: too many errors (suppressed further messages).\n") - end - else - -- Fatal error. - stderr:write(...) - return true -- Stop processing. - end -end - ------------------------------------------------------------------------------- - --- Map holding all option handlers. -local opt_map = {} -local opt_current - --- Print error and exit with error status. -local function opterror(...) - stderr:write("dynasm.lua: ERROR: ", ...) - stderr:write("\n") - exit(1) -end - --- Get option parameter. -local function optparam(args) - local argn = args.argn - local p = args[argn] - if not p then - opterror("missing parameter for option `", opt_current, "'.") - end - args.argn = argn + 1 - return p -end - ------------------------------------------------------------------------------- - --- Core pseudo-opcodes. -local map_coreop = {} --- Dummy opcode map. Replaced by arch-specific map. -local map_op = {} - --- Forward declarations. -local dostmt -local readfile - ------------------------------------------------------------------------------- - --- Map for defines (initially empty, chains to arch-specific map). -local map_def = {} - --- Pseudo-opcode to define a substitution. -map_coreop[".define_2"] = function(params, nparams) - if not params then return nparams == 1 and "name" or "name, subst" end - local name, def = params[1], params[2] or "1" - if not match(name, "^[%a_][%w_]*$") then werror("bad or duplicate define") end - map_def[name] = def -end -map_coreop[".define_1"] = map_coreop[".define_2"] - --- Define a substitution on the command line. -function opt_map.D(args) - local namesubst = optparam(args) - local name, subst = match(namesubst, "^([%a_][%w_]*)=(.*)$") - if name then - map_def[name] = subst - elseif match(namesubst, "^[%a_][%w_]*$") then - map_def[namesubst] = "1" - else - opterror("bad define") - end -end - --- Undefine a substitution on the command line. -function opt_map.U(args) - local name = optparam(args) - if match(name, "^[%a_][%w_]*$") then - map_def[name] = nil - else - opterror("bad define") - end -end - --- Helper for definesubst. -local gotsubst - -local function definesubst_one(word) - local subst = map_def[word] - if subst then gotsubst = word; return subst else return word end -end - --- Iteratively substitute defines. -local function definesubst(stmt) - -- Limit number of iterations. - for i=1,100 do - gotsubst = false - stmt = gsub(stmt, "#?[%w_]+", definesubst_one) - if not gotsubst then break end - end - if gotsubst then wfatal("recursive define involving `"..gotsubst.."'") end - return stmt -end - --- Dump all defines. -local function dumpdefines(out, lvl) - local t = {} - for name in pairs(map_def) do - t[#t+1] = name - end - sort(t) - out:write("Defines:\n") - for _,name in ipairs(t) do - local subst = map_def[name] - if g_arch then subst = g_arch.revdef(subst) end - out:write(format(" %-20s %s\n", name, subst)) - end - out:write("\n") -end - ------------------------------------------------------------------------------- - --- Support variables for conditional assembly. -local condlevel = 0 -local condstack = {} - --- Evaluate condition with a Lua expression. Substitutions already performed. -local function cond_eval(cond) - local func, err - if setfenv then - func, err = loadstring("return "..cond, "=expr") - else - -- No globals. All unknown identifiers evaluate to nil. - func, err = load("return "..cond, "=expr", "t", {}) - end - if func then - if setfenv then - setfenv(func, {}) -- No globals. All unknown identifiers evaluate to nil. - end - local ok, res = pcall(func) - if ok then - if res == 0 then return false end -- Oh well. - return not not res - end - err = res - end - wfatal("bad condition: "..err) -end - --- Skip statements until next conditional pseudo-opcode at the same level. -local function stmtskip() - local dostmt_save = dostmt - local lvl = 0 - dostmt = function(stmt) - local op = match(stmt, "^%s*(%S+)") - if op == ".if" then - lvl = lvl + 1 - elseif lvl ~= 0 then - if op == ".endif" then lvl = lvl - 1 end - elseif op == ".elif" or op == ".else" or op == ".endif" then - dostmt = dostmt_save - dostmt(stmt) - end - end -end - --- Pseudo-opcodes for conditional assembly. -map_coreop[".if_1"] = function(params) - if not params then return "condition" end - local lvl = condlevel + 1 - local res = cond_eval(params[1]) - condlevel = lvl - condstack[lvl] = res - if not res then stmtskip() end -end - -map_coreop[".elif_1"] = function(params) - if not params then return "condition" end - if condlevel == 0 then wfatal(".elif without .if") end - local lvl = condlevel - local res = condstack[lvl] - if res then - if res == "else" then wfatal(".elif after .else") end - else - res = cond_eval(params[1]) - if res then - condstack[lvl] = res - return - end - end - stmtskip() -end - -map_coreop[".else_0"] = function(params) - if condlevel == 0 then wfatal(".else without .if") end - local lvl = condlevel - local res = condstack[lvl] - condstack[lvl] = "else" - if res then - if res == "else" then wfatal(".else after .else") end - stmtskip() - end -end - -map_coreop[".endif_0"] = function(params) - local lvl = condlevel - if lvl == 0 then wfatal(".endif without .if") end - condlevel = lvl - 1 -end - --- Check for unfinished conditionals. -local function checkconds() - if g_errcount ~= "fatal" and condlevel ~= 0 then - wprinterr(g_fname, ":*: error: unbalanced conditional\n") - end -end - ------------------------------------------------------------------------------- - --- Search for a file in the given path and open it for reading. -local function pathopen(path, name) - local dirsep = package and match(package.path, "\\") and "\\" or "/" - for _,p in ipairs(path) do - local fullname = p == "" and name or p..dirsep..name - local fin = io.open(fullname, "r") - if fin then - g_fname = fullname - return fin - end - end -end - --- Include a file. -map_coreop[".include_1"] = function(params) - if not params then return "filename" end - local name = params[1] - -- Save state. Ugly, I know. but upvalues are fast. - local gf, gl, gcl, gi = g_fname, g_lineno, g_curline, g_indent - -- Read the included file. - local fatal = readfile(pathopen(g_opt.include, name) or - wfatal("include file `"..name.."' not found")) - -- Restore state. - g_synclineno = -1 - g_fname, g_lineno, g_curline, g_indent = gf, gl, gcl, gi - if fatal then wfatal("in include file") end -end - --- Make .include and conditionals initially available, too. -map_op[".include_1"] = map_coreop[".include_1"] -map_op[".if_1"] = map_coreop[".if_1"] -map_op[".elif_1"] = map_coreop[".elif_1"] -map_op[".else_0"] = map_coreop[".else_0"] -map_op[".endif_0"] = map_coreop[".endif_0"] - ------------------------------------------------------------------------------- - --- Support variables for macros. -local mac_capture, mac_lineno, mac_name -local mac_active = {} -local mac_list = {} - --- Pseudo-opcode to define a macro. -map_coreop[".macro_*"] = function(mparams) - if not mparams then return "name [, params...]" end - -- Split off and validate macro name. - local name = remove(mparams, 1) - if not name then werror("missing macro name") end - if not (match(name, "^[%a_][%w_%.]*$") or match(name, "^%.[%w_%.]*$")) then - wfatal("bad macro name `"..name.."'") - end - -- Validate macro parameter names. - local mdup = {} - for _,mp in ipairs(mparams) do - if not match(mp, "^[%a_][%w_]*$") then - wfatal("bad macro parameter name `"..mp.."'") - end - if mdup[mp] then wfatal("duplicate macro parameter name `"..mp.."'") end - mdup[mp] = true - end - -- Check for duplicate or recursive macro definitions. - local opname = name.."_"..#mparams - if map_op[opname] or map_op[name.."_*"] then - wfatal("duplicate macro `"..name.."' ("..#mparams.." parameters)") - end - if mac_capture then wfatal("recursive macro definition") end - - -- Enable statement capture. - local lines = {} - mac_lineno = g_lineno - mac_name = name - mac_capture = function(stmt) -- Statement capture function. - -- Stop macro definition with .endmacro pseudo-opcode. - if not match(stmt, "^%s*.endmacro%s*$") then - lines[#lines+1] = stmt - return - end - mac_capture = nil - mac_lineno = nil - mac_name = nil - mac_list[#mac_list+1] = opname - -- Add macro-op definition. - map_op[opname] = function(params) - if not params then return mparams, lines end - -- Protect against recursive macro invocation. - if mac_active[opname] then wfatal("recursive macro invocation") end - mac_active[opname] = true - -- Setup substitution map. - local subst = {} - for i,mp in ipairs(mparams) do subst[mp] = params[i] end - local mcom - if g_opt.maccomment and g_opt.comment then - mcom = " MACRO "..name.." ("..#mparams..")" - wcomment("{"..mcom) - end - -- Loop through all captured statements - for _,stmt in ipairs(lines) do - -- Substitute macro parameters. - local st = gsub(stmt, "[%w_]+", subst) - st = definesubst(st) - st = gsub(st, "%s*%.%.%s*", "") -- Token paste a..b. - if mcom and sub(st, 1, 1) ~= "|" then wcomment(st) end - -- Emit statement. Use a protected call for better diagnostics. - local ok, err = pcall(dostmt, st) - if not ok then - -- Add the captured statement to the error. - wprinterr(err, "\n", g_indent, "| ", stmt, - "\t[MACRO ", name, " (", #mparams, ")]\n") - end - end - if mcom then wcomment("}"..mcom) end - mac_active[opname] = nil - end - end -end - --- An .endmacro pseudo-opcode outside of a macro definition is an error. -map_coreop[".endmacro_0"] = function(params) - wfatal(".endmacro without .macro") -end - --- Dump all macros and their contents (with -PP only). -local function dumpmacros(out, lvl) - sort(mac_list) - out:write("Macros:\n") - for _,opname in ipairs(mac_list) do - local name = sub(opname, 1, -3) - local params, lines = map_op[opname]() - out:write(format(" %-20s %s\n", name, concat(params, ", "))) - if lvl > 1 then - for _,line in ipairs(lines) do - out:write(" |", line, "\n") - end - out:write("\n") - end - end - out:write("\n") -end - --- Check for unfinished macro definitions. -local function checkmacros() - if mac_capture then - wprinterr(g_fname, ":", mac_lineno, - ": error: unfinished .macro `", mac_name ,"'\n") - end -end - ------------------------------------------------------------------------------- - --- Support variables for captures. -local cap_lineno, cap_name -local cap_buffers = {} -local cap_used = {} - --- Start a capture. -map_coreop[".capture_1"] = function(params) - if not params then return "name" end - wflush() - local name = params[1] - if not match(name, "^[%a_][%w_]*$") then - wfatal("bad capture name `"..name.."'") - end - if cap_name then - wfatal("already capturing to `"..cap_name.."' since line "..cap_lineno) - end - cap_name = name - cap_lineno = g_lineno - -- Create or continue a capture buffer and start the output line capture. - local buf = cap_buffers[name] - if not buf then buf = {}; cap_buffers[name] = buf end - g_capbuffer = buf - g_synclineno = 0 -end - --- Stop a capture. -map_coreop[".endcapture_0"] = function(params) - wflush() - if not cap_name then wfatal(".endcapture without a valid .capture") end - cap_name = nil - cap_lineno = nil - g_capbuffer = nil - g_synclineno = 0 -end - --- Dump a capture buffer. -map_coreop[".dumpcapture_1"] = function(params) - if not params then return "name" end - wflush() - local name = params[1] - if not match(name, "^[%a_][%w_]*$") then - wfatal("bad capture name `"..name.."'") - end - cap_used[name] = true - wline(function(out) - local buf = cap_buffers[name] - if buf then wdumplines(out, buf) end - end) - g_synclineno = 0 -end - --- Dump all captures and their buffers (with -PP only). -local function dumpcaptures(out, lvl) - out:write("Captures:\n") - for name,buf in pairs(cap_buffers) do - out:write(format(" %-20s %4s)\n", name, "("..#buf)) - if lvl > 1 then - local bar = rep("=", 76) - out:write(" ", bar, "\n") - for _,line in ipairs(buf) do - out:write(" ", line, "\n") - end - out:write(" ", bar, "\n\n") - end - end - out:write("\n") -end - --- Check for unfinished or unused captures. -local function checkcaptures() - if cap_name then - wprinterr(g_fname, ":", cap_lineno, - ": error: unfinished .capture `", cap_name,"'\n") - return - end - for name in pairs(cap_buffers) do - if not cap_used[name] then - wprinterr(g_fname, ":*: error: missing .dumpcapture ", name ,"\n") - end - end -end - ------------------------------------------------------------------------------- - --- Sections names. -local map_sections = {} - --- Pseudo-opcode to define code sections. --- TODO: Data sections, BSS sections. Needs extra C code and API. -map_coreop[".section_*"] = function(params) - if not params then return "name..." end - if #map_sections > 0 then werror("duplicate section definition") end - wflush() - for sn,name in ipairs(params) do - local opname = "."..name.."_0" - if not match(name, "^[%a][%w_]*$") or - map_op[opname] or map_op["."..name.."_*"] then - werror("bad section name `"..name.."'") - end - map_sections[#map_sections+1] = name - wline(format("#define DASM_SECTION_%s\t%d", upper(name), sn-1)) - map_op[opname] = function(params) g_arch.section(sn-1) end - end - wline(format("#define DASM_MAXSECTION\t\t%d", #map_sections)) -end - --- Dump all sections. -local function dumpsections(out, lvl) - out:write("Sections:\n") - for _,name in ipairs(map_sections) do - out:write(format(" %s\n", name)) - end - out:write("\n") -end - ------------------------------------------------------------------------------- - --- Replacement for customized Lua, which lacks the package library. -local prefix = "" -if not require then - function require(name) - local fp = assert(io.open(prefix..name..".lua")) - local s = fp:read("*a") - assert(fp:close()) - return assert(loadstring(s, "@"..name..".lua"))() - end -end - --- Load architecture-specific module. -local function loadarch(arch) - if not match(arch, "^[%w_]+$") then return "bad arch name" end - local ok, m_arch = pcall(require, "dasm_"..arch) - if not ok then return "cannot load module: "..m_arch end - g_arch = m_arch - wflush = m_arch.passcb(wline, werror, wfatal, wwarn) - m_arch.setup(arch, g_opt) - map_op, map_def = m_arch.mergemaps(map_coreop, map_def) -end - --- Dump architecture description. -function opt_map.dumparch(args) - local name = optparam(args) - if not g_arch then - local err = loadarch(name) - if err then opterror(err) end - end - - local t = {} - for name in pairs(map_coreop) do t[#t+1] = name end - for name in pairs(map_op) do t[#t+1] = name end - sort(t) - - local out = stdout - local _arch = g_arch._info - out:write(format("%s version %s, released %s, %s\n", - _info.name, _info.version, _info.release, _info.url)) - g_arch.dumparch(out) - - local pseudo = true - out:write("Pseudo-Opcodes:\n") - for _,sname in ipairs(t) do - local name, nparam = match(sname, "^(.+)_([0-9%*])$") - if name then - if pseudo and sub(name, 1, 1) ~= "." then - out:write("\nOpcodes:\n") - pseudo = false - end - local f = map_op[sname] - local s - if nparam ~= "*" then nparam = nparam + 0 end - if nparam == 0 then - s = "" - elseif type(f) == "string" then - s = map_op[".template__"](nil, f, nparam) - else - s = f(nil, nparam) - end - if type(s) == "table" then - for _,s2 in ipairs(s) do - out:write(format(" %-12s %s\n", name, s2)) - end - else - out:write(format(" %-12s %s\n", name, s)) - end - end - end - out:write("\n") - exit(0) -end - --- Pseudo-opcode to set the architecture. --- Only initially available (map_op is replaced when called). -map_op[".arch_1"] = function(params) - if not params then return "name" end - local err = loadarch(params[1]) - if err then wfatal(err) end - wline(format("#if DASM_VERSION != %d", _info.vernum)) - wline('#error "Version mismatch between DynASM and included encoding engine"') - wline("#endif") -end - --- Dummy .arch pseudo-opcode to improve the error report. -map_coreop[".arch_1"] = function(params) - if not params then return "name" end - wfatal("duplicate .arch statement") -end - ------------------------------------------------------------------------------- - --- Dummy pseudo-opcode. Don't confuse '.nop' with 'nop'. -map_coreop[".nop_*"] = function(params) - if not params then return "[ignored...]" end -end - --- Pseudo-opcodes to raise errors. -map_coreop[".error_1"] = function(params) - if not params then return "message" end - werror(params[1]) -end - -map_coreop[".fatal_1"] = function(params) - if not params then return "message" end - wfatal(params[1]) -end - --- Dump all user defined elements. -local function dumpdef(out) - local lvl = g_opt.dumpdef - if lvl == 0 then return end - dumpsections(out, lvl) - dumpdefines(out, lvl) - if g_arch then g_arch.dumpdef(out, lvl) end - dumpmacros(out, lvl) - dumpcaptures(out, lvl) -end - ------------------------------------------------------------------------------- - --- Helper for splitstmt. -local splitlvl - -local function splitstmt_one(c) - if c == "(" then - splitlvl = ")"..splitlvl - elseif c == "[" then - splitlvl = "]"..splitlvl - elseif c == "{" then - splitlvl = "}"..splitlvl - elseif c == ")" or c == "]" or c == "}" then - if sub(splitlvl, 1, 1) ~= c then werror("unbalanced (), [] or {}") end - splitlvl = sub(splitlvl, 2) - elseif splitlvl == "" then - return " \0 " - end - return c -end - --- Split statement into (pseudo-)opcode and params. -local function splitstmt(stmt) - -- Convert label with trailing-colon into .label statement. - local label = match(stmt, "^%s*(.+):%s*$") - if label then return ".label", {label} end - - -- Split at commas and equal signs, but obey parentheses and brackets. - splitlvl = "" - stmt = gsub(stmt, "[,%(%)%[%]{}]", splitstmt_one) - if splitlvl ~= "" then werror("unbalanced () or []") end - - -- Split off opcode. - local op, other = match(stmt, "^%s*([^%s%z]+)%s*(.*)$") - if not op then werror("bad statement syntax") end - - -- Split parameters. - local params = {} - for p in gmatch(other, "%s*(%Z+)%z?") do - params[#params+1] = gsub(p, "%s+$", "") - end - if #params > 16 then werror("too many parameters") end - - params.op = op - return op, params -end - --- Process a single statement. -dostmt = function(stmt) - -- Ignore empty statements. - if match(stmt, "^%s*$") then return end - - -- Capture macro defs before substitution. - if mac_capture then return mac_capture(stmt) end - stmt = definesubst(stmt) - - -- Emit C code without parsing the line. - if sub(stmt, 1, 1) == "|" then - local tail = sub(stmt, 2) - wflush() - if sub(tail, 1, 2) == "//" then wcomment(tail) else wline(tail, true) end - return - end - - -- Split into (pseudo-)opcode and params. - local op, params = splitstmt(stmt) - - -- Get opcode handler (matching # of parameters or generic handler). - local f = map_op[op.."_"..#params] or map_op[op.."_*"] - if not f then - if not g_arch then wfatal("first statement must be .arch") end - -- Improve error report. - for i=0,9 do - if map_op[op.."_"..i] then - werror("wrong number of parameters for `"..op.."'") - end - end - werror("unknown statement `"..op.."'") - end - - -- Call opcode handler or special handler for template strings. - if type(f) == "string" then - map_op[".template__"](params, f) - else - f(params) - end -end - --- Process a single line. -local function doline(line) - if g_opt.flushline then wflush() end - - -- Assembler line? - local indent, aline = match(line, "^(%s*)%|(.*)$") - if not aline then - -- No, plain C code line, need to flush first. - wflush() - wsync() - wline(line, false) - return - end - - g_indent = indent -- Remember current line indentation. - - -- Emit C code (even from macros). Avoids echo and line parsing. - if sub(aline, 1, 1) == "|" then - if not mac_capture then - wsync() - elseif g_opt.comment then - wsync() - wcomment(aline) - end - dostmt(aline) - return - end - - -- Echo assembler line as a comment. - if g_opt.comment then - wsync() - wcomment(aline) - end - - -- Strip assembler comments. - aline = gsub(aline, "//.*$", "") - - -- Split line into statements at semicolons. - if match(aline, ";") then - for stmt in gmatch(aline, "[^;]+") do dostmt(stmt) end - else - dostmt(aline) - end -end - ------------------------------------------------------------------------------- - --- Write DynASM header. -local function dasmhead(out) - out:write(format([[ -/* -** This file has been pre-processed with DynASM. -** %s -** DynASM version %s, DynASM %s version %s -** DO NOT EDIT! The original file is in "%s". -*/ - -]], _info.url, - _info.version, g_arch._info.arch, g_arch._info.version, - g_fname)) -end - --- Read input file. -readfile = function(fin) - g_indent = "" - g_lineno = 0 - g_synclineno = -1 - - -- Process all lines. - for line in fin:lines() do - g_lineno = g_lineno + 1 - g_curline = line - local ok, err = pcall(doline, line) - if not ok and wprinterr(err, "\n") then return true end - end - wflush() - - -- Close input file. - assert(fin == stdin or fin:close()) -end - --- Write output file. -local function writefile(outfile) - local fout - - -- Open output file. - if outfile == nil or outfile == "-" then - fout = stdout - else - fout = assert(io.open(outfile, "w")) - end - - -- Write all buffered lines - wdumplines(fout, g_wbuffer) - - -- Close output file. - assert(fout == stdout or fout:close()) - - -- Optionally dump definitions. - dumpdef(fout == stdout and stderr or stdout) -end - --- Translate an input file to an output file. -local function translate(infile, outfile) - g_wbuffer = {} - g_indent = "" - g_lineno = 0 - g_synclineno = -1 - - -- Put header. - wline(dasmhead) - - -- Read input file. - local fin - if infile == "-" then - g_fname = "(stdin)" - fin = stdin - else - g_fname = infile - fin = assert(io.open(infile, "r")) - end - readfile(fin) - - -- Check for errors. - if not g_arch then - wprinterr(g_fname, ":*: error: missing .arch directive\n") - end - checkconds() - checkmacros() - checkcaptures() - - if g_errcount ~= 0 then - stderr:write(g_fname, ":*: info: ", g_errcount, " error", - (type(g_errcount) == "number" and g_errcount > 1) and "s" or "", - " in input file -- no output file generated.\n") - dumpdef(stderr) - exit(1) - end - - -- Write output file. - writefile(outfile) -end - ------------------------------------------------------------------------------- - --- Print help text. -function opt_map.help() - stdout:write("DynASM -- ", _info.description, ".\n") - stdout:write("DynASM ", _info.version, " ", _info.release, " ", _info.url, "\n") - stdout:write[[ - -Usage: dynasm [OPTION]... INFILE.dasc|- - - -h, --help Display this help text. - -V, --version Display version and copyright information. - - -o, --outfile FILE Output file name (default is stdout). - -I, --include DIR Add directory to the include search path. - - -c, --ccomment Use /* */ comments for assembler lines. - -C, --cppcomment Use // comments for assembler lines (default). - -N, --nocomment Suppress assembler lines in output. - -M, --maccomment Show macro expansions as comments (default off). - - -L, --nolineno Suppress CPP line number information in output. - -F, --flushline Flush action list for every line. - - -D NAME[=SUBST] Define a substitution. - -U NAME Undefine a substitution. - - -P, --dumpdef Dump defines, macros, etc. Repeat for more output. - -A, --dumparch ARCH Load architecture ARCH and dump description. -]] - exit(0) -end - --- Print version information. -function opt_map.version() - stdout:write(format("%s version %s, released %s\n%s\n\n%s", - _info.name, _info.version, _info.release, _info.url, _info.copyright)) - exit(0) -end - --- Misc. options. -function opt_map.outfile(args) g_opt.outfile = optparam(args) end -function opt_map.include(args) insert(g_opt.include, 1, optparam(args)) end -function opt_map.ccomment() g_opt.comment = "/*|"; g_opt.endcomment = " */" end -function opt_map.cppcomment() g_opt.comment = "//|"; g_opt.endcomment = "" end -function opt_map.nocomment() g_opt.comment = false end -function opt_map.maccomment() g_opt.maccomment = true end -function opt_map.nolineno() g_opt.cpp = false end -function opt_map.flushline() g_opt.flushline = true end -function opt_map.dumpdef() g_opt.dumpdef = g_opt.dumpdef + 1 end - ------------------------------------------------------------------------------- - --- Short aliases for long options. -local opt_alias = { - h = "help", ["?"] = "help", V = "version", - o = "outfile", I = "include", - c = "ccomment", C = "cppcomment", N = "nocomment", M = "maccomment", - L = "nolineno", F = "flushline", - P = "dumpdef", A = "dumparch", -} - --- Parse single option. -local function parseopt(opt, args) - opt_current = #opt == 1 and "-"..opt or "--"..opt - local f = opt_map[opt] or opt_map[opt_alias[opt]] - if not f then - opterror("unrecognized option `", opt_current, "'. Try `--help'.\n") - end - f(args) -end - --- Parse arguments. -local function parseargs(args) - -- Default options. - g_opt.comment = "//|" - g_opt.endcomment = "" - g_opt.cpp = true - g_opt.dumpdef = 0 - g_opt.include = { "" } - - -- Process all option arguments. - args.argn = 1 - repeat - local a = args[args.argn] - if not a then break end - local lopt, opt = match(a, "^%-(%-?)(.+)") - if not opt then break end - args.argn = args.argn + 1 - if lopt == "" then - -- Loop through short options. - for o in gmatch(opt, ".") do parseopt(o, args) end - else - -- Long option. - parseopt(opt, args) - end - until false - - -- Check for proper number of arguments. - local nargs = #args - args.argn + 1 - if nargs ~= 1 then - if nargs == 0 then - if g_opt.dumpdef > 0 then return dumpdef(stdout) end - end - opt_map.help() - end - - -- Translate a single input file to a single output file - -- TODO: Handle multiple files? - translate(args[args.argn], g_opt.outfile) -end - ------------------------------------------------------------------------------- - --- Add the directory dynasm.lua resides in to the Lua module search path. -local arg = arg -if arg and arg[0] then - prefix = match(arg[0], "^(.*[/\\])") - if package and prefix then package.path = prefix.."?.lua;"..package.path end -end - --- Start DynASM. -parseargs{...} - ------------------------------------------------------------------------------- - diff --git a/lib/LuaJIT/etc/luajit.1 b/lib/LuaJIT/etc/luajit.1 deleted file mode 100644 index 0d263db..0000000 --- a/lib/LuaJIT/etc/luajit.1 +++ /dev/null @@ -1,88 +0,0 @@ -.TH luajit 1 "" "" "LuaJIT documentation" -.SH NAME -luajit \- Just-In-Time Compiler for the Lua Language -\fB -.SH SYNOPSIS -.B luajit -[\fIoptions\fR]... [\fIscript\fR [\fIargs\fR]...] -.SH "WEB SITE" -.IR http://luajit.org -.SH DESCRIPTION -.PP -This is the command-line program to run Lua programs with \fBLuaJIT\fR. -.PP -\fBLuaJIT\fR is a just-in-time (JIT) compiler for the Lua language. -The virtual machine (VM) is based on a fast interpreter combined with -a trace compiler. It can significantly improve the performance of Lua programs. -.PP -\fBLuaJIT\fR is API\- and ABI-compatible with the VM of the standard -Lua\ 5.1 interpreter. When embedding the VM into an application, -the built library can be used as a drop-in replacement. -.SH OPTIONS -.TP -.BI "\-e " chunk -Run the given chunk of Lua code. -.TP -.BI "\-l " library -Load the named library, just like \fBrequire("\fR\fIlibrary\fR\fB")\fR. -.TP -.BI "\-b " ... -Save or list bytecode. Run without arguments to get help on options. -.TP -.BI "\-j " command -Perform LuaJIT control command (optional space after \fB\-j\fR). -.TP -.BI "\-O" [opt] -Control LuaJIT optimizations. -.TP -.B "\-i" -Run in interactive mode. -.TP -.B "\-v" -Show \fBLuaJIT\fR version. -.TP -.B "\-E" -Ignore environment variables. -.TP -.B "\-\-" -Stop processing options. -.TP -.B "\-" -Read script from stdin instead. -.PP -After all options are processed, the given \fIscript\fR is run. -The arguments are passed in the global \fIarg\fR table. -.PP -Interactive mode is only entered, if no \fIscript\fR and no \fB\-e\fR -option is given. Interactive mode can be left with EOF (\fICtrl\-Z\fB). -.SH EXAMPLES -.TP -luajit hello.lua world - -Prints "Hello world", assuming \fIhello.lua\fR contains: -.br - print("Hello", arg[1]) -.TP -luajit \-e "local x=0; for i=1,1e9 do x=x+i end; print(x)" - -Calculates the sum of the numbers from 1 to 1000000000. -.br -And finishes in a reasonable amount of time, too. -.TP -luajit \-jv \-e "for i=1,10 do for j=1,10 do for k=1,100 do end end end" - -Runs some nested loops and shows the resulting traces. -.SH COPYRIGHT -.PP -\fBLuaJIT\fR is Copyright \(co 2005-2017 Mike Pall. -.br -\fBLuaJIT\fR is open source software, released under the MIT license. -.SH SEE ALSO -.PP -More details in the provided HTML docs or at: -.IR http://luajit.org -.br -More about the Lua language can be found at: -.IR http://lua.org/docs.html -.PP -lua(1) diff --git a/lib/LuaJIT/etc/luajit.pc b/lib/LuaJIT/etc/luajit.pc deleted file mode 100644 index a78f174..0000000 --- a/lib/LuaJIT/etc/luajit.pc +++ /dev/null @@ -1,25 +0,0 @@ -# Package information for LuaJIT to be used by pkg-config. -majver=2 -minver=1 -relver=0 -version=${majver}.${minver}.${relver}-beta3 -abiver=5.1 - -prefix=/usr/local -multilib=lib -exec_prefix=${prefix} -libdir=${exec_prefix}/${multilib} -libname=luajit-${abiver} -includedir=${prefix}/include/luajit-${majver}.${minver} - -INSTALL_LMOD=${prefix}/share/lua/${abiver} -INSTALL_CMOD=${prefix}/${multilib}/lua/${abiver} - -Name: LuaJIT -Description: Just-in-time compiler for Lua -URL: http://luajit.org -Version: ${version} -Requires: -Libs: -L${libdir} -l${libname} -Libs.private: -Wl,-E -lm -ldl -Cflags: -I${includedir} diff --git a/lib/LuaJIT/src/.gitignore b/lib/LuaJIT/src/.gitignore deleted file mode 100644 index 1a30573..0000000 --- a/lib/LuaJIT/src/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -luajit -lj_bcdef.h -lj_ffdef.h -lj_libdef.h -lj_recdef.h -lj_folddef.h -lj_vm.[sS] diff --git a/lib/LuaJIT/src/Makefile b/lib/LuaJIT/src/Makefile deleted file mode 100644 index 1b70b05..0000000 --- a/lib/LuaJIT/src/Makefile +++ /dev/null @@ -1,722 +0,0 @@ -############################################################################## -# LuaJIT Makefile. Requires GNU Make. -# -# Please read doc/install.html before changing any variables! -# -# Suitable for POSIX platforms (Linux, *BSD, OSX etc.). -# Also works with MinGW and Cygwin on Windows. -# Please check msvcbuild.bat for building with MSVC on Windows. -# -# Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -############################################################################## - -MAJVER= 2 -MINVER= 1 -RELVER= 0 -ABIVER= 5.1 -NODOTABIVER= 51 - -############################################################################## -############################# COMPILER OPTIONS ############################# -############################################################################## -# These options mainly affect the speed of the JIT compiler itself, not the -# speed of the JIT-compiled code. Turn any of the optional settings on by -# removing the '#' in front of them. Make sure you force a full recompile -# with "make clean", followed by "make" if you change any options. -# -DEFAULT_CC = gcc -# -# LuaJIT builds as a native 32 or 64 bit binary by default. -CC= $(DEFAULT_CC) -# -# Use this if you want to force a 32 bit build on a 64 bit multilib OS. -#CC= $(DEFAULT_CC) -m32 -# -# Since the assembler part does NOT maintain a frame pointer, it's pointless -# to slow down the C part by not omitting it. Debugging, tracebacks and -# unwinding are not affected -- the assembler part has frame unwind -# information and GCC emits it where needed (x64) or with -g (see CCDEBUG). -CCOPT= -O2 -fomit-frame-pointer -# Use this if you want to generate a smaller binary (but it's slower): -#CCOPT= -Os -fomit-frame-pointer -# Note: it's no longer recommended to use -O3 with GCC 4.x. -# The I-Cache bloat usually outweighs the benefits from aggressive inlining. -# -# Target-specific compiler options: -# -# x86/x64 only: For GCC 4.2 or higher and if you don't intend to distribute -# the binaries to a different machine you could also use: -march=native -# -CCOPT_x86= -march=i686 -msse -msse2 -mfpmath=sse -CCOPT_x64= -CCOPT_arm= -CCOPT_arm64= -CCOPT_ppc= -CCOPT_mips= -# -CCDEBUG= -# Uncomment the next line to generate debug information: -#CCDEBUG= -g -# -CCWARN= -Wall -# Uncomment the next line to enable more warnings: -#CCWARN+= -Wextra -Wdeclaration-after-statement -Wredundant-decls -Wshadow -Wpointer-arith -# -############################################################################## - -############################################################################## -################################ BUILD MODE ################################ -############################################################################## -# The default build mode is mixed mode on POSIX. On Windows this is the same -# as dynamic mode. -# -# Mixed mode creates a static + dynamic library and a statically linked luajit. -BUILDMODE= mixed -# -# Static mode creates a static library and a statically linked luajit. -#BUILDMODE= static -# -# Dynamic mode creates a dynamic library and a dynamically linked luajit. -# Note: this executable will only run when the library is installed! -#BUILDMODE= dynamic -# -############################################################################## - -############################################################################## -################################# FEATURES ################################# -############################################################################## -# Enable/disable these features as needed, but make sure you force a full -# recompile with "make clean", followed by "make". -XCFLAGS= -# -# Permanently disable the FFI extension to reduce the size of the LuaJIT -# executable. But please consider that the FFI library is compiled-in, -# but NOT loaded by default. It only allocates any memory, if you actually -# make use of it. -#XCFLAGS+= -DLUAJIT_DISABLE_FFI -# -# Features from Lua 5.2 that are unlikely to break existing code are -# enabled by default. Some other features that *might* break some existing -# code (e.g. __pairs or os.execute() return values) can be enabled here. -# Note: this does not provide full compatibility with Lua 5.2 at this time. -#XCFLAGS+= -DLUAJIT_ENABLE_LUA52COMPAT -# -# Disable the JIT compiler, i.e. turn LuaJIT into a pure interpreter. -#XCFLAGS+= -DLUAJIT_DISABLE_JIT -# -# Some architectures (e.g. PPC) can use either single-number (1) or -# dual-number (2) mode. Uncomment one of these lines to override the -# default mode. Please see LJ_ARCH_NUMMODE in lj_arch.h for details. -#XCFLAGS+= -DLUAJIT_NUMMODE=1 -#XCFLAGS+= -DLUAJIT_NUMMODE=2 -# -# Enable GC64 mode for x64. -#XCFLAGS+= -DLUAJIT_ENABLE_GC64 -# -############################################################################## - -############################################################################## -############################ DEBUGGING SUPPORT ############################# -############################################################################## -# Enable these options as needed, but make sure you force a full recompile -# with "make clean", followed by "make". -# Note that most of these are NOT suitable for benchmarking or release mode! -# -# Use the system provided memory allocator (realloc) instead of the -# bundled memory allocator. This is slower, but sometimes helpful for -# debugging. This option cannot be enabled on x64 without GC64, since -# realloc usually doesn't return addresses in the right address range. -# OTOH this option is mandatory for Valgrind's memcheck tool on x64 and -# the only way to get useful results from it for all other architectures. -#XCFLAGS+= -DLUAJIT_USE_SYSMALLOC -# -# This define is required to run LuaJIT under Valgrind. The Valgrind -# header files must be installed. You should enable debug information, too. -# Use --suppressions=lj.supp to avoid some false positives. -#XCFLAGS+= -DLUAJIT_USE_VALGRIND -# -# This is the client for the GDB JIT API. GDB 7.0 or higher is required -# to make use of it. See lj_gdbjit.c for details. Enabling this causes -# a non-negligible overhead, even when not running under GDB. -#XCFLAGS+= -DLUAJIT_USE_GDBJIT -# -# Turn on assertions for the Lua/C API to debug problems with lua_* calls. -# This is rather slow -- use only while developing C libraries/embeddings. -#XCFLAGS+= -DLUA_USE_APICHECK -# -# Turn on assertions for the whole LuaJIT VM. This significantly slows down -# everything. Use only if you suspect a problem with LuaJIT itself. -#XCFLAGS+= -DLUA_USE_ASSERT -# -############################################################################## -# You probably don't need to change anything below this line! -############################################################################## - -############################################################################## -# Host system detection. -############################################################################## - -ifeq (Windows,$(findstring Windows,$(OS))$(MSYSTEM)$(TERM)) - HOST_SYS= Windows - HOST_RM= del -else - HOST_SYS:= $(shell uname -s) - ifneq (,$(findstring MINGW,$(HOST_SYS))) - HOST_SYS= Windows - HOST_MSYS= mingw - endif - ifneq (,$(findstring MSYS,$(HOST_SYS))) - HOST_SYS= Windows - HOST_MSYS= mingw - endif - ifneq (,$(findstring CYGWIN,$(HOST_SYS))) - HOST_SYS= Windows - HOST_MSYS= cygwin - endif -endif - -############################################################################## -# Flags and options for host and target. -############################################################################## - -# You can override the following variables at the make command line: -# CC HOST_CC STATIC_CC DYNAMIC_CC -# CFLAGS HOST_CFLAGS TARGET_CFLAGS -# LDFLAGS HOST_LDFLAGS TARGET_LDFLAGS TARGET_SHLDFLAGS -# LIBS HOST_LIBS TARGET_LIBS -# CROSS HOST_SYS TARGET_SYS TARGET_FLAGS -# -# Cross-compilation examples: -# make HOST_CC="gcc -m32" CROSS=i586-mingw32msvc- TARGET_SYS=Windows -# make HOST_CC="gcc -m32" CROSS=powerpc-linux-gnu- - -ASOPTIONS= $(CCOPT) $(CCWARN) $(XCFLAGS) $(CFLAGS) -CCOPTIONS= $(CCDEBUG) $(ASOPTIONS) -LDOPTIONS= $(CCDEBUG) $(LDFLAGS) - -HOST_CC= $(CC) -HOST_RM?= rm -f -# If left blank, minilua is built and used. You can supply an installed -# copy of (plain) Lua 5.1 or 5.2, plus Lua BitOp. E.g. with: HOST_LUA=lua -HOST_LUA= - -HOST_XCFLAGS= -I. -HOST_XLDFLAGS= -HOST_XLIBS= -HOST_ACFLAGS= $(CCOPTIONS) $(HOST_XCFLAGS) $(TARGET_ARCH) $(HOST_CFLAGS) -HOST_ALDFLAGS= $(LDOPTIONS) $(HOST_XLDFLAGS) $(HOST_LDFLAGS) -HOST_ALIBS= $(HOST_XLIBS) $(LIBS) $(HOST_LIBS) - -STATIC_CC = $(CROSS)$(CC) -DYNAMIC_CC = $(CROSS)$(CC) -fPIC -TARGET_CC= $(STATIC_CC) -TARGET_STCC= $(STATIC_CC) -TARGET_DYNCC= $(DYNAMIC_CC) -TARGET_LD= $(CROSS)$(CC) -TARGET_AR= $(CROSS)ar rcus -TARGET_STRIP= $(CROSS)strip - -TARGET_LIBPATH= $(or $(PREFIX),/usr/local)/$(or $(MULTILIB),lib) -TARGET_SONAME= libluajit-$(ABIVER).so.$(MAJVER) -TARGET_DYLIBNAME= libluajit-$(ABIVER).$(MAJVER).dylib -TARGET_DYLIBPATH= $(TARGET_LIBPATH)/$(TARGET_DYLIBNAME) -TARGET_DLLNAME= lua$(NODOTABIVER).dll -TARGET_XSHLDFLAGS= -shared -fPIC -Wl,-soname,$(TARGET_SONAME) -TARGET_DYNXLDOPTS= - -TARGET_LFSFLAGS= -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -TARGET_XCFLAGS= $(TARGET_LFSFLAGS) -U_FORTIFY_SOURCE -TARGET_XLDFLAGS= -TARGET_XLIBS= -lm -TARGET_TCFLAGS= $(CCOPTIONS) $(TARGET_XCFLAGS) $(TARGET_FLAGS) $(TARGET_CFLAGS) -TARGET_ACFLAGS= $(CCOPTIONS) $(TARGET_XCFLAGS) $(TARGET_FLAGS) $(TARGET_CFLAGS) -TARGET_ASFLAGS= $(ASOPTIONS) $(TARGET_XCFLAGS) $(TARGET_FLAGS) $(TARGET_CFLAGS) -TARGET_ALDFLAGS= $(LDOPTIONS) $(TARGET_XLDFLAGS) $(TARGET_FLAGS) $(TARGET_LDFLAGS) -TARGET_ASHLDFLAGS= $(LDOPTIONS) $(TARGET_XSHLDFLAGS) $(TARGET_FLAGS) $(TARGET_SHLDFLAGS) -TARGET_ALIBS= $(TARGET_XLIBS) $(LIBS) $(TARGET_LIBS) - -TARGET_TESTARCH=$(shell $(TARGET_CC) $(TARGET_TCFLAGS) -E lj_arch.h -dM) -ifneq (,$(findstring LJ_TARGET_X64 ,$(TARGET_TESTARCH))) - TARGET_LJARCH= x64 -else -ifneq (,$(findstring LJ_TARGET_X86 ,$(TARGET_TESTARCH))) - TARGET_LJARCH= x86 -else -ifneq (,$(findstring LJ_TARGET_ARM ,$(TARGET_TESTARCH))) - TARGET_LJARCH= arm -else -ifneq (,$(findstring LJ_TARGET_ARM64 ,$(TARGET_TESTARCH))) - ifneq (,$(findstring __AARCH64EB__ ,$(TARGET_TESTARCH))) - TARGET_ARCH= -D__AARCH64EB__=1 - endif - TARGET_LJARCH= arm64 -else -ifneq (,$(findstring LJ_TARGET_PPC ,$(TARGET_TESTARCH))) - ifneq (,$(findstring LJ_LE 1,$(TARGET_TESTARCH))) - TARGET_ARCH= -DLJ_ARCH_ENDIAN=LUAJIT_LE - else - TARGET_ARCH= -DLJ_ARCH_ENDIAN=LUAJIT_BE - endif - TARGET_LJARCH= ppc -else -ifneq (,$(findstring LJ_TARGET_MIPS ,$(TARGET_TESTARCH))) - ifneq (,$(findstring MIPSEL ,$(TARGET_TESTARCH))) - TARGET_ARCH= -D__MIPSEL__=1 - endif - ifneq (,$(findstring LJ_TARGET_MIPS64 ,$(TARGET_TESTARCH))) - TARGET_LJARCH= mips64 - else - TARGET_LJARCH= mips - endif -else - $(error Unsupported target architecture) -endif -endif -endif -endif -endif -endif - -ifneq (,$(findstring LJ_TARGET_PS3 1,$(TARGET_TESTARCH))) - TARGET_SYS= PS3 - TARGET_ARCH+= -D__CELLOS_LV2__ - TARGET_XCFLAGS+= -DLUAJIT_USE_SYSMALLOC - TARGET_XLIBS+= -lpthread -endif - -TARGET_XCFLAGS+= $(CCOPT_$(TARGET_LJARCH)) -TARGET_ARCH+= $(patsubst %,-DLUAJIT_TARGET=LUAJIT_ARCH_%,$(TARGET_LJARCH)) - -ifneq (,$(PREFIX)) -ifneq (/usr/local,$(PREFIX)) - TARGET_XCFLAGS+= -DLUA_ROOT=\"$(PREFIX)\" - ifneq (/usr,$(PREFIX)) - TARGET_DYNXLDOPTS= -Wl,-rpath,$(TARGET_LIBPATH) - endif -endif -endif -ifneq (,$(MULTILIB)) - TARGET_XCFLAGS+= -DLUA_MULTILIB=\"$(MULTILIB)\" -endif -ifneq (,$(LMULTILIB)) - TARGET_XCFLAGS+= -DLUA_LMULTILIB=\"$(LMULTILIB)\" -endif - -############################################################################## -# Target system detection. -############################################################################## - -TARGET_SYS?= $(HOST_SYS) -ifeq (Windows,$(TARGET_SYS)) - TARGET_STRIP+= --strip-unneeded - TARGET_XSHLDFLAGS= -shared - TARGET_DYNXLDOPTS= -else - TARGET_AR+= 2>/dev/null -ifeq (,$(shell $(TARGET_CC) -o /dev/null -c -x c /dev/null -fno-stack-protector 2>/dev/null || echo 1)) - TARGET_XCFLAGS+= -fno-stack-protector -endif -ifeq (Darwin,$(TARGET_SYS)) - ifeq (,$(MACOSX_DEPLOYMENT_TARGET)) - export MACOSX_DEPLOYMENT_TARGET=10.4 - endif - TARGET_STRIP+= -x - TARGET_XSHLDFLAGS= -dynamiclib -single_module -undefined dynamic_lookup -fPIC - TARGET_DYNXLDOPTS= - TARGET_XSHLDFLAGS+= -install_name $(TARGET_DYLIBPATH) -compatibility_version $(MAJVER).$(MINVER) -current_version $(MAJVER).$(MINVER).$(RELVER) - ifeq (x64,$(TARGET_LJARCH)) - TARGET_XLDFLAGS+= -pagezero_size 10000 -image_base 100000000 - TARGET_XSHLDFLAGS+= -image_base 7fff04c4a000 - endif -else -ifeq (iOS,$(TARGET_SYS)) - TARGET_STRIP+= -x - TARGET_XSHLDFLAGS= -dynamiclib -single_module -undefined dynamic_lookup -fPIC - TARGET_DYNXLDOPTS= - TARGET_XSHLDFLAGS+= -install_name $(TARGET_DYLIBPATH) -compatibility_version $(MAJVER).$(MINVER) -current_version $(MAJVER).$(MINVER).$(RELVER) - ifeq (arm64,$(TARGET_LJARCH)) - TARGET_XCFLAGS+= -fno-omit-frame-pointer - endif -else - ifneq (SunOS,$(TARGET_SYS)) - ifneq (PS3,$(TARGET_SYS)) - TARGET_XLDFLAGS+= -Wl,-E - endif - endif - ifeq (Linux,$(TARGET_SYS)) - TARGET_XLIBS+= -ldl - endif - ifeq (GNU/kFreeBSD,$(TARGET_SYS)) - TARGET_XLIBS+= -ldl - endif -endif -endif -endif - -ifneq ($(HOST_SYS),$(TARGET_SYS)) - ifeq (Windows,$(TARGET_SYS)) - HOST_XCFLAGS+= -malign-double -DLUAJIT_OS=LUAJIT_OS_WINDOWS - else - ifeq (Linux,$(TARGET_SYS)) - HOST_XCFLAGS+= -DLUAJIT_OS=LUAJIT_OS_LINUX - else - ifeq (Darwin,$(TARGET_SYS)) - HOST_XCFLAGS+= -DLUAJIT_OS=LUAJIT_OS_OSX - else - ifeq (iOS,$(TARGET_SYS)) - HOST_XCFLAGS+= -DLUAJIT_OS=LUAJIT_OS_OSX - else - HOST_XCFLAGS+= -DLUAJIT_OS=LUAJIT_OS_OTHER - endif - endif - endif - endif -endif - -ifneq (,$(CCDEBUG)) - TARGET_STRIP= @: -endif - -############################################################################## -# Files and pathnames. -############################################################################## - -MINILUA_O= host/minilua.o -MINILUA_LIBS= -lm -MINILUA_T= host/minilua -MINILUA_X= $(MINILUA_T) - -ifeq (,$(HOST_LUA)) - HOST_LUA= $(MINILUA_X) - DASM_DEP= $(MINILUA_T) -endif - -DASM_DIR= ../dynasm -DASM= $(HOST_LUA) $(DASM_DIR)/dynasm.lua -DASM_XFLAGS= -DASM_AFLAGS= -DASM_ARCH= $(TARGET_LJARCH) - -ifneq (,$(findstring LJ_LE 1,$(TARGET_TESTARCH))) - DASM_AFLAGS+= -D ENDIAN_LE -else - DASM_AFLAGS+= -D ENDIAN_BE -endif -ifneq (,$(findstring LJ_ARCH_BITS 64,$(TARGET_TESTARCH))) - DASM_AFLAGS+= -D P64 -endif -ifneq (,$(findstring LJ_HASJIT 1,$(TARGET_TESTARCH))) - DASM_AFLAGS+= -D JIT -endif -ifneq (,$(findstring LJ_HASFFI 1,$(TARGET_TESTARCH))) - DASM_AFLAGS+= -D FFI -endif -ifneq (,$(findstring LJ_DUALNUM 1,$(TARGET_TESTARCH))) - DASM_AFLAGS+= -D DUALNUM -endif -ifneq (,$(findstring LJ_ARCH_HASFPU 1,$(TARGET_TESTARCH))) - DASM_AFLAGS+= -D FPU - TARGET_ARCH+= -DLJ_ARCH_HASFPU=1 -else - TARGET_ARCH+= -DLJ_ARCH_HASFPU=0 -endif -ifeq (,$(findstring LJ_ABI_SOFTFP 1,$(TARGET_TESTARCH))) - DASM_AFLAGS+= -D HFABI - TARGET_ARCH+= -DLJ_ABI_SOFTFP=0 -else - TARGET_ARCH+= -DLJ_ABI_SOFTFP=1 -endif -ifneq (,$(findstring LJ_NO_UNWIND 1,$(TARGET_TESTARCH))) - DASM_AFLAGS+= -D NO_UNWIND - TARGET_ARCH+= -DLUAJIT_NO_UNWIND -endif -DASM_AFLAGS+= -D VER=$(subst LJ_ARCH_VERSION_,,$(filter LJ_ARCH_VERSION_%,$(subst LJ_ARCH_VERSION ,LJ_ARCH_VERSION_,$(TARGET_TESTARCH)))) -ifeq (Windows,$(TARGET_SYS)) - DASM_AFLAGS+= -D WIN -endif -ifeq (x64,$(TARGET_LJARCH)) - ifeq (,$(findstring LJ_FR2 1,$(TARGET_TESTARCH))) - DASM_ARCH= x86 - endif -else -ifeq (arm,$(TARGET_LJARCH)) - ifeq (iOS,$(TARGET_SYS)) - DASM_AFLAGS+= -D IOS - endif -else -ifeq (ppc,$(TARGET_LJARCH)) - ifneq (,$(findstring LJ_ARCH_SQRT 1,$(TARGET_TESTARCH))) - DASM_AFLAGS+= -D SQRT - endif - ifneq (,$(findstring LJ_ARCH_ROUND 1,$(TARGET_TESTARCH))) - DASM_AFLAGS+= -D ROUND - endif - ifneq (,$(findstring LJ_ARCH_PPC32ON64 1,$(TARGET_TESTARCH))) - DASM_AFLAGS+= -D GPR64 - endif - ifeq (PS3,$(TARGET_SYS)) - DASM_AFLAGS+= -D PPE -D TOC - endif - ifneq (,$(findstring LJ_ARCH_PPC64 ,$(TARGET_TESTARCH))) - DASM_ARCH= ppc64 - endif -endif -endif -endif - -DASM_FLAGS= $(DASM_XFLAGS) $(DASM_AFLAGS) -DASM_DASC= vm_$(DASM_ARCH).dasc - -BUILDVM_O= host/buildvm.o host/buildvm_asm.o host/buildvm_peobj.o \ - host/buildvm_lib.o host/buildvm_fold.o -BUILDVM_T= host/buildvm -BUILDVM_X= $(BUILDVM_T) - -HOST_O= $(MINILUA_O) $(BUILDVM_O) -HOST_T= $(MINILUA_T) $(BUILDVM_T) - -LJVM_S= lj_vm.S -LJVM_O= lj_vm.o -LJVM_BOUT= $(LJVM_S) -LJVM_MODE= elfasm - -LJLIB_O= lib_base.o lib_math.o lib_bit.o lib_string.o lib_table.o \ - lib_io.o lib_os.o lib_package.o lib_debug.o lib_jit.o lib_ffi.o -LJLIB_C= $(LJLIB_O:.o=.c) - -LJCORE_O= lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o lj_buf.o \ - lj_str.o lj_tab.o lj_func.o lj_udata.o lj_meta.o lj_debug.o \ - lj_state.o lj_dispatch.o lj_vmevent.o lj_vmmath.o lj_strscan.o \ - lj_strfmt.o lj_strfmt_num.o lj_api.o lj_profile.o \ - lj_lex.o lj_parse.o lj_bcread.o lj_bcwrite.o lj_load.o \ - lj_ir.o lj_opt_mem.o lj_opt_fold.o lj_opt_narrow.o \ - lj_opt_dce.o lj_opt_loop.o lj_opt_split.o lj_opt_sink.o \ - lj_mcode.o lj_snap.o lj_record.o lj_crecord.o lj_ffrecord.o \ - lj_asm.o lj_trace.o lj_gdbjit.o \ - lj_ctype.o lj_cdata.o lj_cconv.o lj_ccall.o lj_ccallback.o \ - lj_carith.o lj_clib.o lj_cparse.o \ - lj_lib.o lj_alloc.o lib_aux.o \ - $(LJLIB_O) lib_init.o - -LJVMCORE_O= $(LJVM_O) $(LJCORE_O) -LJVMCORE_DYNO= $(LJVMCORE_O:.o=_dyn.o) - -LIB_VMDEF= jit/vmdef.lua -LIB_VMDEFP= $(LIB_VMDEF) - -LUAJIT_O= luajit.o -LUAJIT_A= libluajit.a -LUAJIT_SO= libluajit.so -LUAJIT_T= luajit - -ALL_T= $(LUAJIT_T) $(LUAJIT_A) $(LUAJIT_SO) $(HOST_T) -ALL_HDRGEN= lj_bcdef.h lj_ffdef.h lj_libdef.h lj_recdef.h lj_folddef.h \ - host/buildvm_arch.h -ALL_GEN= $(LJVM_S) $(ALL_HDRGEN) $(LIB_VMDEFP) -WIN_RM= *.obj *.lib *.exp *.dll *.exe *.manifest *.pdb *.ilk -ALL_RM= $(ALL_T) $(ALL_GEN) *.o host/*.o $(WIN_RM) - -############################################################################## -# Build mode handling. -############################################################################## - -# Mixed mode defaults. -TARGET_O= $(LUAJIT_A) -TARGET_T= $(LUAJIT_T) $(LUAJIT_SO) -TARGET_DEP= $(LIB_VMDEF) $(LUAJIT_SO) - -ifeq (Windows,$(TARGET_SYS)) - TARGET_DYNCC= $(STATIC_CC) - LJVM_MODE= peobj - LJVM_BOUT= $(LJVM_O) - LUAJIT_T= luajit.exe - ifeq (cygwin,$(HOST_MSYS)) - LUAJIT_SO= cyg$(TARGET_DLLNAME) - else - LUAJIT_SO= $(TARGET_DLLNAME) - endif - # Mixed mode is not supported on Windows. And static mode doesn't work well. - # C modules cannot be loaded, because they bind to lua51.dll. - ifneq (static,$(BUILDMODE)) - BUILDMODE= dynamic - TARGET_XCFLAGS+= -DLUA_BUILD_AS_DLL - endif -endif -ifeq (Darwin,$(TARGET_SYS)) - LJVM_MODE= machasm -endif -ifeq (iOS,$(TARGET_SYS)) - LJVM_MODE= machasm -endif -ifeq (SunOS,$(TARGET_SYS)) - BUILDMODE= static -endif -ifeq (PS3,$(TARGET_SYS)) - BUILDMODE= static -endif - -ifeq (Windows,$(HOST_SYS)) - MINILUA_T= host/minilua.exe - BUILDVM_T= host/buildvm.exe - ifeq (,$(HOST_MSYS)) - MINILUA_X= host\minilua - BUILDVM_X= host\buildvm - ALL_RM:= $(subst /,\,$(ALL_RM)) - endif -endif - -ifeq (static,$(BUILDMODE)) - TARGET_DYNCC= @: - TARGET_T= $(LUAJIT_T) - TARGET_DEP= $(LIB_VMDEF) -else -ifeq (dynamic,$(BUILDMODE)) - ifneq (Windows,$(TARGET_SYS)) - TARGET_CC= $(DYNAMIC_CC) - endif - TARGET_DYNCC= @: - LJVMCORE_DYNO= $(LJVMCORE_O) - TARGET_O= $(LUAJIT_SO) - TARGET_XLDFLAGS+= $(TARGET_DYNXLDOPTS) -else -ifeq (Darwin,$(TARGET_SYS)) - TARGET_DYNCC= @: - LJVMCORE_DYNO= $(LJVMCORE_O) -endif -ifeq (iOS,$(TARGET_SYS)) - TARGET_DYNCC= @: - LJVMCORE_DYNO= $(LJVMCORE_O) -endif -endif -endif - -Q= @ -E= @echo -#Q= -#E= @: - -############################################################################## -# Make targets. -############################################################################## - -default all: $(TARGET_T) - @cp $(LUAJIT_A) ../.. - -amalg: - @grep "^[+|]" ljamalg.c - $(MAKE) all "LJCORE_O=ljamalg.o" - -clean: - $(HOST_RM) $(ALL_RM) - -libbc: - ./$(LUAJIT_T) host/genlibbc.lua -o host/buildvm_libbc.h $(LJLIB_C) - $(MAKE) all - -depend: - @for file in $(ALL_HDRGEN); do \ - test -f $$file || touch $$file; \ - done - @$(HOST_CC) $(HOST_ACFLAGS) -MM *.c host/*.c | \ - sed -e "s| [^ ]*/dasm_\S*\.h||g" \ - -e "s|^\([^l ]\)|host/\1|" \ - -e "s| lj_target_\S*\.h| lj_target_*.h|g" \ - -e "s| lj_emit_\S*\.h| lj_emit_*.h|g" \ - -e "s| lj_asm_\S*\.h| lj_asm_*.h|g" >Makefile.dep - @for file in $(ALL_HDRGEN); do \ - test -s $$file || $(HOST_RM) $$file; \ - done - -.PHONY: default all amalg clean libbc depend - -############################################################################## -# Rules for generated files. -############################################################################## - -$(MINILUA_T): $(MINILUA_O) - $(E) "HOSTLINK $@" - $(Q)$(HOST_CC) $(HOST_ALDFLAGS) -o $@ $(MINILUA_O) $(MINILUA_LIBS) $(HOST_ALIBS) - -host/buildvm_arch.h: $(DASM_DASC) $(DASM_DEP) $(DASM_DIR)/*.lua - $(E) "DYNASM $@" - $(Q)$(DASM) $(DASM_FLAGS) -o $@ $(DASM_DASC) - -host/buildvm.o: $(DASM_DIR)/dasm_*.h - -$(BUILDVM_T): $(BUILDVM_O) - $(E) "HOSTLINK $@" - $(Q)$(HOST_CC) $(HOST_ALDFLAGS) -o $@ $(BUILDVM_O) $(HOST_ALIBS) - -$(LJVM_BOUT): $(BUILDVM_T) - $(E) "BUILDVM $@" - $(Q)$(BUILDVM_X) -m $(LJVM_MODE) -o $@ - -lj_bcdef.h: $(BUILDVM_T) $(LJLIB_C) - $(E) "BUILDVM $@" - $(Q)$(BUILDVM_X) -m bcdef -o $@ $(LJLIB_C) - -lj_ffdef.h: $(BUILDVM_T) $(LJLIB_C) - $(E) "BUILDVM $@" - $(Q)$(BUILDVM_X) -m ffdef -o $@ $(LJLIB_C) - -lj_libdef.h: $(BUILDVM_T) $(LJLIB_C) - $(E) "BUILDVM $@" - $(Q)$(BUILDVM_X) -m libdef -o $@ $(LJLIB_C) - -lj_recdef.h: $(BUILDVM_T) $(LJLIB_C) - $(E) "BUILDVM $@" - $(Q)$(BUILDVM_X) -m recdef -o $@ $(LJLIB_C) - -$(LIB_VMDEF): $(BUILDVM_T) $(LJLIB_C) - $(E) "BUILDVM $@" - $(Q)$(BUILDVM_X) -m vmdef -o $(LIB_VMDEFP) $(LJLIB_C) - -lj_folddef.h: $(BUILDVM_T) lj_opt_fold.c - $(E) "BUILDVM $@" - $(Q)$(BUILDVM_X) -m folddef -o $@ lj_opt_fold.c - -############################################################################## -# Object file rules. -############################################################################## - -%.o: %.c - $(E) "CC $@" - $(Q)$(TARGET_DYNCC) $(TARGET_ACFLAGS) -c -o $(@:.o=_dyn.o) $< - $(Q)$(TARGET_CC) $(TARGET_ACFLAGS) -c -o $@ $< - -%.o: %.S - $(E) "ASM $@" - $(Q)$(TARGET_DYNCC) $(TARGET_ASFLAGS) -c -o $(@:.o=_dyn.o) $< - $(Q)$(TARGET_CC) $(TARGET_ASFLAGS) -c -o $@ $< - -$(LUAJIT_O): - $(E) "CC $@" - $(Q)$(TARGET_STCC) $(TARGET_ACFLAGS) -c -o $@ $< - -$(HOST_O): %.o: %.c - $(E) "HOSTCC $@" - $(Q)$(HOST_CC) $(HOST_ACFLAGS) -c -o $@ $< - -include Makefile.dep - -############################################################################## -# Target file rules. -############################################################################## - -$(LUAJIT_A): $(LJVMCORE_O) - $(E) "AR $@" - $(Q)$(TARGET_AR) $@ $(LJVMCORE_O) - -# The dependency on _O, but linking with _DYNO is intentional. -$(LUAJIT_SO): $(LJVMCORE_O) - $(E) "DYNLINK $@" - $(Q)$(TARGET_LD) $(TARGET_ASHLDFLAGS) -o $@ $(LJVMCORE_DYNO) $(TARGET_ALIBS) - $(Q)$(TARGET_STRIP) $@ - -$(LUAJIT_T): $(TARGET_O) $(LUAJIT_O) $(TARGET_DEP) - $(E) "LINK $@" - $(Q)$(TARGET_LD) $(TARGET_ALDFLAGS) -o $@ $(LUAJIT_O) $(TARGET_O) $(TARGET_ALIBS) - $(Q)$(TARGET_STRIP) $@ - $(E) "OK Successfully built LuaJIT" - -############################################################################## diff --git a/lib/LuaJIT/src/Makefile.dep b/lib/LuaJIT/src/Makefile.dep deleted file mode 100644 index 2b1cb5e..0000000 --- a/lib/LuaJIT/src/Makefile.dep +++ /dev/null @@ -1,246 +0,0 @@ -lib_aux.o: lib_aux.c lua.h luaconf.h lauxlib.h lj_obj.h lj_def.h \ - lj_arch.h lj_err.h lj_errmsg.h lj_state.h lj_trace.h lj_jit.h lj_ir.h \ - lj_dispatch.h lj_bc.h lj_traceerr.h lj_lib.h lj_alloc.h -lib_base.o: lib_base.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \ - lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_str.h \ - lj_tab.h lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h lj_cconv.h \ - lj_ff.h lj_ffdef.h lj_dispatch.h lj_jit.h lj_ir.h lj_char.h lj_strscan.h \ - lj_strfmt.h lj_lib.h lj_libdef.h -lib_bit.o: lib_bit.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \ - lj_arch.h lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_strscan.h \ - lj_strfmt.h lj_ctype.h lj_cdata.h lj_cconv.h lj_carith.h lj_ff.h \ - lj_ffdef.h lj_lib.h lj_libdef.h -lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \ - lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_lib.h \ - lj_libdef.h -lib_ffi.o: lib_ffi.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \ - lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h \ - lj_ctype.h lj_cparse.h lj_cdata.h lj_cconv.h lj_carith.h lj_ccall.h \ - lj_ccallback.h lj_clib.h lj_strfmt.h lj_ff.h lj_ffdef.h lj_lib.h \ - lj_libdef.h -lib_init.o: lib_init.c lua.h luaconf.h lauxlib.h lualib.h lj_arch.h -lib_io.o: lib_io.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \ - lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_state.h \ - lj_strfmt.h lj_ff.h lj_ffdef.h lj_lib.h lj_libdef.h -lib_jit.o: lib_jit.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \ - lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_tab.h \ - lj_state.h lj_bc.h lj_ctype.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h \ - lj_target.h lj_target_*.h lj_trace.h lj_dispatch.h lj_traceerr.h \ - lj_vm.h lj_vmevent.h lj_lib.h luajit.h lj_libdef.h -lib_math.o: lib_math.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \ - lj_def.h lj_arch.h lj_lib.h lj_vm.h lj_libdef.h -lib_os.o: lib_os.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \ - lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_lib.h \ - lj_libdef.h -lib_package.o: lib_package.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \ - lj_def.h lj_arch.h lj_err.h lj_errmsg.h lj_lib.h -lib_string.o: lib_string.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \ - lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h \ - lj_tab.h lj_meta.h lj_state.h lj_ff.h lj_ffdef.h lj_bcdump.h lj_lex.h \ - lj_char.h lj_strfmt.h lj_lib.h lj_libdef.h -lib_table.o: lib_table.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \ - lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h \ - lj_tab.h lj_ff.h lj_ffdef.h lj_lib.h lj_libdef.h -lj_alloc.o: lj_alloc.c lj_def.h lua.h luaconf.h lj_arch.h lj_alloc.h -lj_api.o: lj_api.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ - lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_tab.h lj_func.h lj_udata.h \ - lj_meta.h lj_state.h lj_bc.h lj_frame.h lj_trace.h lj_jit.h lj_ir.h \ - lj_dispatch.h lj_traceerr.h lj_vm.h lj_strscan.h lj_strfmt.h -lj_asm.o: lj_asm.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ - lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h lj_ir.h lj_jit.h \ - lj_ircall.h lj_iropt.h lj_mcode.h lj_trace.h lj_dispatch.h lj_traceerr.h \ - lj_snap.h lj_asm.h lj_vm.h lj_target.h lj_target_*.h lj_emit_*.h \ - lj_asm_*.h -lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \ - lj_bcdef.h -lj_bcread.o: lj_bcread.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_bc.h \ - lj_ctype.h lj_cdata.h lualib.h lj_lex.h lj_bcdump.h lj_state.h \ - lj_strfmt.h -lj_bcwrite.o: lj_bcwrite.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_gc.h lj_buf.h lj_str.h lj_bc.h lj_ctype.h lj_dispatch.h lj_jit.h \ - lj_ir.h lj_strfmt.h lj_bcdump.h lj_lex.h lj_err.h lj_errmsg.h lj_vm.h -lj_buf.o: lj_buf.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ - lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_strfmt.h -lj_carith.o: lj_carith.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_meta.h lj_ir.h lj_ctype.h \ - lj_cconv.h lj_cdata.h lj_carith.h lj_strscan.h -lj_ccall.o: lj_ccall.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_ctype.h lj_cconv.h lj_cdata.h \ - lj_ccall.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_bc.h \ - lj_traceerr.h -lj_ccallback.o: lj_ccallback.c lj_obj.h lua.h luaconf.h lj_def.h \ - lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_state.h lj_frame.h \ - lj_bc.h lj_ctype.h lj_cconv.h lj_ccall.h lj_ccallback.h lj_target.h \ - lj_target_*.h lj_mcode.h lj_jit.h lj_ir.h lj_trace.h lj_dispatch.h \ - lj_traceerr.h lj_vm.h -lj_cconv.o: lj_cconv.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_err.h lj_errmsg.h lj_tab.h lj_ctype.h lj_gc.h lj_cdata.h lj_cconv.h \ - lj_ccallback.h -lj_cdata.o: lj_cdata.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_ctype.h lj_cconv.h lj_cdata.h -lj_char.o: lj_char.c lj_char.h lj_def.h lua.h luaconf.h -lj_clib.o: lj_clib.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ - lj_err.h lj_errmsg.h lj_tab.h lj_str.h lj_udata.h lj_ctype.h lj_cconv.h \ - lj_cdata.h lj_clib.h lj_strfmt.h -lj_cparse.o: lj_cparse.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_ctype.h lj_cparse.h \ - lj_frame.h lj_bc.h lj_vm.h lj_char.h lj_strscan.h lj_strfmt.h -lj_crecord.o: lj_crecord.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_err.h lj_errmsg.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h lj_gc.h \ - lj_cdata.h lj_cparse.h lj_cconv.h lj_carith.h lj_clib.h lj_ccall.h \ - lj_ff.h lj_ffdef.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h lj_trace.h \ - lj_dispatch.h lj_traceerr.h lj_record.h lj_ffrecord.h lj_snap.h \ - lj_crecord.h lj_strfmt.h -lj_ctype.o: lj_ctype.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_strfmt.h lj_ctype.h \ - lj_ccallback.h lj_buf.h -lj_debug.o: lj_debug.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_err.h lj_errmsg.h lj_debug.h lj_buf.h lj_gc.h lj_str.h lj_tab.h \ - lj_state.h lj_frame.h lj_bc.h lj_strfmt.h lj_jit.h lj_ir.h -lj_dispatch.o: lj_dispatch.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_func.h lj_tab.h \ - lj_meta.h lj_debug.h lj_state.h lj_frame.h lj_bc.h lj_ff.h lj_ffdef.h \ - lj_strfmt.h lj_jit.h lj_ir.h lj_ccallback.h lj_ctype.h lj_trace.h \ - lj_dispatch.h lj_traceerr.h lj_profile.h lj_vm.h luajit.h -lj_err.o: lj_err.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_err.h \ - lj_errmsg.h lj_debug.h lj_str.h lj_func.h lj_state.h lj_frame.h lj_bc.h \ - lj_ff.h lj_ffdef.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h \ - lj_traceerr.h lj_vm.h lj_strfmt.h -lj_ffrecord.o: lj_ffrecord.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ff.h \ - lj_ffdef.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h lj_trace.h \ - lj_dispatch.h lj_traceerr.h lj_record.h lj_ffrecord.h lj_crecord.h \ - lj_vm.h lj_strscan.h lj_strfmt.h lj_recdef.h -lj_func.o: lj_func.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ - lj_func.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_bc.h \ - lj_traceerr.h lj_vm.h -lj_gc.o: lj_gc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ - lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_func.h lj_udata.h \ - lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h lj_cdata.h lj_trace.h \ - lj_jit.h lj_ir.h lj_dispatch.h lj_traceerr.h lj_vm.h -lj_gdbjit.o: lj_gdbjit.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_frame.h lj_bc.h lj_buf.h \ - lj_str.h lj_strfmt.h lj_jit.h lj_ir.h lj_dispatch.h -lj_ir.o: lj_ir.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ - lj_buf.h lj_str.h lj_tab.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h \ - lj_trace.h lj_dispatch.h lj_bc.h lj_traceerr.h lj_ctype.h lj_cdata.h \ - lj_carith.h lj_vm.h lj_strscan.h lj_strfmt.h lj_lib.h -lj_lex.o: lj_lex.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ - lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_ctype.h lj_cdata.h \ - lualib.h lj_state.h lj_lex.h lj_parse.h lj_char.h lj_strscan.h \ - lj_strfmt.h -lj_lib.o: lj_lib.c lauxlib.h lua.h luaconf.h lj_obj.h lj_def.h lj_arch.h \ - lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_func.h lj_bc.h \ - lj_dispatch.h lj_jit.h lj_ir.h lj_vm.h lj_strscan.h lj_strfmt.h lj_lex.h \ - lj_bcdump.h lj_lib.h -lj_load.o: lj_load.c lua.h luaconf.h lauxlib.h lj_obj.h lj_def.h \ - lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_func.h \ - lj_frame.h lj_bc.h lj_vm.h lj_lex.h lj_bcdump.h lj_parse.h -lj_mcode.o: lj_mcode.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_gc.h lj_err.h lj_errmsg.h lj_jit.h lj_ir.h lj_mcode.h lj_trace.h \ - lj_dispatch.h lj_bc.h lj_traceerr.h lj_vm.h -lj_meta.o: lj_meta.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ - lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_meta.h lj_frame.h \ - lj_bc.h lj_vm.h lj_strscan.h lj_strfmt.h lj_lib.h -lj_obj.o: lj_obj.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h -lj_opt_dce.o: lj_opt_dce.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_ir.h lj_jit.h lj_iropt.h -lj_opt_fold.o: lj_opt_fold.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_buf.h lj_gc.h lj_str.h lj_tab.h lj_ir.h lj_jit.h lj_ircall.h \ - lj_iropt.h lj_trace.h lj_dispatch.h lj_bc.h lj_traceerr.h lj_ctype.h \ - lj_carith.h lj_vm.h lj_strscan.h lj_strfmt.h lj_folddef.h -lj_opt_loop.o: lj_opt_loop.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_ir.h lj_jit.h \ - lj_iropt.h lj_trace.h lj_dispatch.h lj_bc.h lj_traceerr.h lj_snap.h \ - lj_vm.h -lj_opt_mem.o: lj_opt_mem.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_tab.h lj_ir.h lj_jit.h lj_iropt.h lj_ircall.h -lj_opt_narrow.o: lj_opt_narrow.c lj_obj.h lua.h luaconf.h lj_def.h \ - lj_arch.h lj_bc.h lj_ir.h lj_jit.h lj_iropt.h lj_trace.h lj_dispatch.h \ - lj_traceerr.h lj_vm.h lj_strscan.h -lj_opt_sink.o: lj_opt_sink.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_ir.h lj_jit.h lj_iropt.h lj_target.h lj_target_*.h -lj_opt_split.o: lj_opt_split.c lj_obj.h lua.h luaconf.h lj_def.h \ - lj_arch.h lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_ir.h \ - lj_jit.h lj_ircall.h lj_iropt.h lj_dispatch.h lj_bc.h lj_vm.h -lj_parse.o: lj_parse.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_buf.h lj_str.h lj_tab.h \ - lj_func.h lj_state.h lj_bc.h lj_ctype.h lj_strfmt.h lj_lex.h lj_parse.h \ - lj_vm.h lj_vmevent.h -lj_profile.o: lj_profile.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_buf.h lj_gc.h lj_str.h lj_frame.h lj_bc.h lj_debug.h lj_dispatch.h \ - lj_jit.h lj_ir.h lj_trace.h lj_traceerr.h lj_profile.h luajit.h -lj_record.o: lj_record.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h lj_frame.h lj_bc.h \ - lj_ctype.h lj_gc.h lj_ff.h lj_ffdef.h lj_debug.h lj_ir.h lj_jit.h \ - lj_ircall.h lj_iropt.h lj_trace.h lj_dispatch.h lj_traceerr.h \ - lj_record.h lj_ffrecord.h lj_snap.h lj_vm.h -lj_snap.o: lj_snap.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ - lj_tab.h lj_state.h lj_frame.h lj_bc.h lj_ir.h lj_jit.h lj_iropt.h \ - lj_trace.h lj_dispatch.h lj_traceerr.h lj_snap.h lj_target.h \ - lj_target_*.h lj_ctype.h lj_cdata.h -lj_state.o: lj_state.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_func.h \ - lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h lj_trace.h lj_jit.h \ - lj_ir.h lj_dispatch.h lj_traceerr.h lj_vm.h lj_lex.h lj_alloc.h luajit.h -lj_str.o: lj_str.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ - lj_err.h lj_errmsg.h lj_str.h lj_char.h -lj_strfmt.o: lj_strfmt.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_buf.h lj_gc.h lj_str.h lj_state.h lj_char.h lj_strfmt.h -lj_strfmt_num.o: lj_strfmt_num.c lj_obj.h lua.h luaconf.h lj_def.h \ - lj_arch.h lj_buf.h lj_gc.h lj_str.h lj_strfmt.h -lj_strscan.o: lj_strscan.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_char.h lj_strscan.h -lj_tab.o: lj_tab.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ - lj_err.h lj_errmsg.h lj_tab.h -lj_trace.o: lj_trace.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_frame.h lj_bc.h \ - lj_state.h lj_ir.h lj_jit.h lj_iropt.h lj_mcode.h lj_trace.h \ - lj_dispatch.h lj_traceerr.h lj_snap.h lj_gdbjit.h lj_record.h lj_asm.h \ - lj_vm.h lj_vmevent.h lj_target.h lj_target_*.h -lj_udata.o: lj_udata.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_gc.h lj_udata.h -lj_vmevent.o: lj_vmevent.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_str.h lj_tab.h lj_state.h lj_dispatch.h lj_bc.h lj_jit.h lj_ir.h \ - lj_vm.h lj_vmevent.h -lj_vmmath.o: lj_vmmath.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ - lj_ir.h lj_vm.h -ljamalg.o: ljamalg.c lua.h luaconf.h lauxlib.h lj_gc.c lj_obj.h lj_def.h \ - lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h \ - lj_func.h lj_udata.h lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h \ - lj_cdata.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_traceerr.h \ - lj_vm.h lj_err.c lj_debug.h lj_ff.h lj_ffdef.h lj_strfmt.h lj_char.c \ - lj_char.h lj_bc.c lj_bcdef.h lj_obj.c lj_buf.c lj_str.c lj_tab.c \ - lj_func.c lj_udata.c lj_meta.c lj_strscan.h lj_lib.h lj_debug.c \ - lj_state.c lj_lex.h lj_alloc.h luajit.h lj_dispatch.c lj_ccallback.h \ - lj_profile.h lj_vmevent.c lj_vmevent.h lj_vmmath.c lj_strscan.c \ - lj_strfmt.c lj_strfmt_num.c lj_api.c lj_profile.c lj_lex.c lualib.h \ - lj_parse.h lj_parse.c lj_bcread.c lj_bcdump.h lj_bcwrite.c lj_load.c \ - lj_ctype.c lj_cdata.c lj_cconv.h lj_cconv.c lj_ccall.c lj_ccall.h \ - lj_ccallback.c lj_target.h lj_target_*.h lj_mcode.h lj_carith.c \ - lj_carith.h lj_clib.c lj_clib.h lj_cparse.c lj_cparse.h lj_lib.c lj_ir.c \ - lj_ircall.h lj_iropt.h lj_opt_mem.c lj_opt_fold.c lj_folddef.h \ - lj_opt_narrow.c lj_opt_dce.c lj_opt_loop.c lj_snap.h lj_opt_split.c \ - lj_opt_sink.c lj_mcode.c lj_snap.c lj_record.c lj_record.h lj_ffrecord.h \ - lj_crecord.c lj_crecord.h lj_ffrecord.c lj_recdef.h lj_asm.c lj_asm.h \ - lj_emit_*.h lj_asm_*.h lj_trace.c lj_gdbjit.h lj_gdbjit.c lj_alloc.c \ - lib_aux.c lib_base.c lj_libdef.h lib_math.c lib_string.c lib_table.c \ - lib_io.c lib_os.c lib_package.c lib_debug.c lib_bit.c lib_jit.c \ - lib_ffi.c lib_init.c -luajit.o: luajit.c lua.h luaconf.h lauxlib.h lualib.h luajit.h lj_arch.h -host/buildvm.o: host/buildvm.c host/buildvm.h lj_def.h lua.h luaconf.h \ - lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_gc.h lj_obj.h lj_bc.h lj_ir.h \ - lj_ircall.h lj_ir.h lj_jit.h lj_frame.h lj_bc.h lj_dispatch.h lj_ctype.h \ - lj_gc.h lj_ccall.h lj_ctype.h luajit.h \ - host/buildvm_arch.h lj_traceerr.h -host/buildvm_asm.o: host/buildvm_asm.c host/buildvm.h lj_def.h lua.h luaconf.h \ - lj_arch.h lj_bc.h lj_def.h lj_arch.h -host/buildvm_fold.o: host/buildvm_fold.c host/buildvm.h lj_def.h lua.h \ - luaconf.h lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_ir.h lj_obj.h -host/buildvm_lib.o: host/buildvm_lib.c host/buildvm.h lj_def.h lua.h luaconf.h \ - lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_bc.h lj_lib.h lj_obj.h \ - host/buildvm_libbc.h -host/buildvm_peobj.o: host/buildvm_peobj.c host/buildvm.h lj_def.h lua.h \ - luaconf.h lj_arch.h lj_bc.h lj_def.h lj_arch.h -host/minilua.o: host/minilua.c diff --git a/lib/LuaJIT/src/host/.gitignore b/lib/LuaJIT/src/host/.gitignore deleted file mode 100644 index 762ac2a..0000000 --- a/lib/LuaJIT/src/host/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -minilua -buildvm -buildvm_arch.h diff --git a/lib/LuaJIT/src/host/README b/lib/LuaJIT/src/host/README deleted file mode 100644 index abfcdaa..0000000 --- a/lib/LuaJIT/src/host/README +++ /dev/null @@ -1,4 +0,0 @@ -The files in this directory are only used during the build process of LuaJIT. -For cross-compilation, they must be executed on the host, not on the target. - -These files should NOT be installed! diff --git a/lib/LuaJIT/src/host/buildvm.c b/lib/LuaJIT/src/host/buildvm.c deleted file mode 100644 index de23fab..0000000 --- a/lib/LuaJIT/src/host/buildvm.c +++ /dev/null @@ -1,518 +0,0 @@ -/* -** LuaJIT VM builder. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** This is a tool to build the hand-tuned assembler code required for -** LuaJIT's bytecode interpreter. It supports a variety of output formats -** to feed different toolchains (see usage() below). -** -** This tool is not particularly optimized because it's only used while -** _building_ LuaJIT. There's no point in distributing or installing it. -** Only the object code generated by this tool is linked into LuaJIT. -** -** Caveat: some memory is not free'd, error handling is lazy. -** It's a one-shot tool -- any effort fixing this would be wasted. -*/ - -#include "buildvm.h" -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_bc.h" -#include "lj_ir.h" -#include "lj_ircall.h" -#include "lj_frame.h" -#include "lj_dispatch.h" -#if LJ_HASFFI -#include "lj_ctype.h" -#include "lj_ccall.h" -#endif -#include "luajit.h" - -#if defined(_WIN32) -#include -#include -#endif - -/* ------------------------------------------------------------------------ */ - -/* DynASM glue definitions. */ -#define Dst ctx -#define Dst_DECL BuildCtx *ctx -#define Dst_REF (ctx->D) -#define DASM_CHECKS 1 - -#include "../dynasm/dasm_proto.h" - -/* Glue macros for DynASM. */ -static int collect_reloc(BuildCtx *ctx, uint8_t *addr, int idx, int type); - -#define DASM_EXTERN(ctx, addr, idx, type) \ - collect_reloc(ctx, addr, idx, type) - -/* ------------------------------------------------------------------------ */ - -/* Avoid trouble if cross-compiling for an x86 target. Speed doesn't matter. */ -#define DASM_ALIGNED_WRITES 1 - -/* Embed architecture-specific DynASM encoder. */ -#if LJ_TARGET_X86ORX64 -#include "../dynasm/dasm_x86.h" -#elif LJ_TARGET_ARM -#include "../dynasm/dasm_arm.h" -#elif LJ_TARGET_ARM64 -#include "../dynasm/dasm_arm64.h" -#elif LJ_TARGET_PPC -#include "../dynasm/dasm_ppc.h" -#elif LJ_TARGET_MIPS -#include "../dynasm/dasm_mips.h" -#else -#error "No support for this architecture (yet)" -#endif - -/* Embed generated architecture-specific backend. */ -#include "buildvm_arch.h" - -/* ------------------------------------------------------------------------ */ - -void owrite(BuildCtx *ctx, const void *ptr, size_t sz) -{ - if (fwrite(ptr, 1, sz, ctx->fp) != sz) { - fprintf(stderr, "Error: cannot write to output file: %s\n", - strerror(errno)); - exit(1); - } -} - -/* ------------------------------------------------------------------------ */ - -/* Emit code as raw bytes. Only used for DynASM debugging. */ -static void emit_raw(BuildCtx *ctx) -{ - owrite(ctx, ctx->code, ctx->codesz); -} - -/* -- Build machine code -------------------------------------------------- */ - -static const char *sym_decorate(BuildCtx *ctx, - const char *prefix, const char *suffix) -{ - char name[256]; - char *p; -#if LJ_64 - const char *symprefix = ctx->mode == BUILD_machasm ? "_" : ""; -#elif LJ_TARGET_XBOX360 - const char *symprefix = ""; -#else - const char *symprefix = ctx->mode != BUILD_elfasm ? "_" : ""; -#endif - sprintf(name, "%s%s%s", symprefix, prefix, suffix); - p = strchr(name, '@'); - if (p) { -#if LJ_TARGET_X86ORX64 - if (!LJ_64 && (ctx->mode == BUILD_coffasm || ctx->mode == BUILD_peobj)) - name[0] = name[1] == 'R' ? '_' : '@'; /* Just for _RtlUnwind@16. */ - else - *p = '\0'; -#elif LJ_TARGET_PPC && !LJ_TARGET_CONSOLE - /* Keep @plt etc. */ -#else - *p = '\0'; -#endif - } - p = (char *)malloc(strlen(name)+1); /* MSVC doesn't like strdup. */ - strcpy(p, name); - return p; -} - -#define NRELOCSYM (sizeof(extnames)/sizeof(extnames[0])-1) - -static int relocmap[NRELOCSYM]; - -/* Collect external relocations. */ -static int collect_reloc(BuildCtx *ctx, uint8_t *addr, int idx, int type) -{ - if (ctx->nreloc >= BUILD_MAX_RELOC) { - fprintf(stderr, "Error: too many relocations, increase BUILD_MAX_RELOC.\n"); - exit(1); - } - if (relocmap[idx] < 0) { - relocmap[idx] = ctx->nrelocsym; - ctx->relocsym[ctx->nrelocsym] = sym_decorate(ctx, "", extnames[idx]); - ctx->nrelocsym++; - } - ctx->reloc[ctx->nreloc].ofs = (int32_t)(addr - ctx->code); - ctx->reloc[ctx->nreloc].sym = relocmap[idx]; - ctx->reloc[ctx->nreloc].type = type; - ctx->nreloc++; -#if LJ_TARGET_XBOX360 - return (int)(ctx->code - addr) + 4; /* Encode symbol offset of .text. */ -#else - return 0; /* Encode symbol offset of 0. */ -#endif -} - -/* Naive insertion sort. Performance doesn't matter here. */ -static void sym_insert(BuildCtx *ctx, int32_t ofs, - const char *prefix, const char *suffix) -{ - ptrdiff_t i = ctx->nsym++; - while (i > 0) { - if (ctx->sym[i-1].ofs <= ofs) - break; - ctx->sym[i] = ctx->sym[i-1]; - i--; - } - ctx->sym[i].ofs = ofs; - ctx->sym[i].name = sym_decorate(ctx, prefix, suffix); -} - -/* Build the machine code. */ -static int build_code(BuildCtx *ctx) -{ - int status; - int i; - - /* Initialize DynASM structures. */ - ctx->nglob = GLOB__MAX; - ctx->glob = (void **)malloc(ctx->nglob*sizeof(void *)); - memset(ctx->glob, 0, ctx->nglob*sizeof(void *)); - ctx->nreloc = 0; - - ctx->globnames = globnames; - ctx->extnames = extnames; - ctx->relocsym = (const char **)malloc(NRELOCSYM*sizeof(const char *)); - ctx->nrelocsym = 0; - for (i = 0; i < (int)NRELOCSYM; i++) relocmap[i] = -1; - - ctx->dasm_ident = DASM_IDENT; - ctx->dasm_arch = DASM_ARCH; - - dasm_init(Dst, DASM_MAXSECTION); - dasm_setupglobal(Dst, ctx->glob, ctx->nglob); - dasm_setup(Dst, build_actionlist); - - /* Call arch-specific backend to emit the code. */ - ctx->npc = build_backend(ctx); - - /* Finalize the code. */ - (void)dasm_checkstep(Dst, -1); - if ((status = dasm_link(Dst, &ctx->codesz))) return status; - ctx->code = (uint8_t *)malloc(ctx->codesz); - if ((status = dasm_encode(Dst, (void *)ctx->code))) return status; - - /* Allocate symbol table and bytecode offsets. */ - ctx->beginsym = sym_decorate(ctx, "", LABEL_PREFIX "vm_asm_begin"); - ctx->sym = (BuildSym *)malloc((ctx->npc+ctx->nglob+1)*sizeof(BuildSym)); - ctx->nsym = 0; - ctx->bc_ofs = (int32_t *)malloc(ctx->npc*sizeof(int32_t)); - - /* Collect the opcodes (PC labels). */ - for (i = 0; i < ctx->npc; i++) { - int32_t ofs = dasm_getpclabel(Dst, i); - if (ofs < 0) return 0x22000000|i; - ctx->bc_ofs[i] = ofs; - if ((LJ_HASJIT || - !(i == BC_JFORI || i == BC_JFORL || i == BC_JITERL || i == BC_JLOOP || - i == BC_IFORL || i == BC_IITERL || i == BC_ILOOP)) && - (LJ_HASFFI || i != BC_KCDATA)) - sym_insert(ctx, ofs, LABEL_PREFIX_BC, bc_names[i]); - } - - /* Collect the globals (named labels). */ - for (i = 0; i < ctx->nglob; i++) { - const char *gl = globnames[i]; - int len = (int)strlen(gl); - if (!ctx->glob[i]) { - fprintf(stderr, "Error: undefined global %s\n", gl); - exit(2); - } - /* Skip the _Z symbols. */ - if (!(len >= 2 && gl[len-2] == '_' && gl[len-1] == 'Z')) - sym_insert(ctx, (int32_t)((uint8_t *)(ctx->glob[i]) - ctx->code), - LABEL_PREFIX, globnames[i]); - } - - /* Close the address range. */ - sym_insert(ctx, (int32_t)ctx->codesz, "", ""); - ctx->nsym--; - - dasm_free(Dst); - - return 0; -} - -/* -- Generate VM enums --------------------------------------------------- */ - -const char *const bc_names[] = { -#define BCNAME(name, ma, mb, mc, mt) #name, -BCDEF(BCNAME) -#undef BCNAME - NULL -}; - -const char *const ir_names[] = { -#define IRNAME(name, m, m1, m2) #name, -IRDEF(IRNAME) -#undef IRNAME - NULL -}; - -const char *const irt_names[] = { -#define IRTNAME(name, size) #name, -IRTDEF(IRTNAME) -#undef IRTNAME - NULL -}; - -const char *const irfpm_names[] = { -#define FPMNAME(name) #name, -IRFPMDEF(FPMNAME) -#undef FPMNAME - NULL -}; - -const char *const irfield_names[] = { -#define FLNAME(name, ofs) #name, -IRFLDEF(FLNAME) -#undef FLNAME - NULL -}; - -const char *const ircall_names[] = { -#define IRCALLNAME(cond, name, nargs, kind, type, flags) #name, -IRCALLDEF(IRCALLNAME) -#undef IRCALLNAME - NULL -}; - -static const char *const trace_errors[] = { -#define TREDEF(name, msg) msg, -#include "lj_traceerr.h" - NULL -}; - -static const char *lower(char *buf, const char *s) -{ - char *p = buf; - while (*s) { - *p++ = (*s >= 'A' && *s <= 'Z') ? *s+0x20 : *s; - s++; - } - *p = '\0'; - return buf; -} - -/* Emit C source code for bytecode-related definitions. */ -static void emit_bcdef(BuildCtx *ctx) -{ - int i; - fprintf(ctx->fp, "/* This is a generated file. DO NOT EDIT! */\n\n"); - fprintf(ctx->fp, "LJ_DATADEF const uint16_t lj_bc_ofs[] = {\n"); - for (i = 0; i < ctx->npc; i++) { - if (i != 0) - fprintf(ctx->fp, ",\n"); - fprintf(ctx->fp, "%d", ctx->bc_ofs[i]); - } -} - -/* Emit VM definitions as Lua code for debug modules. */ -static void emit_vmdef(BuildCtx *ctx) -{ - char buf[80]; - int i; - fprintf(ctx->fp, "-- This is a generated file. DO NOT EDIT!\n\n"); - fprintf(ctx->fp, "return {\n\n"); - - fprintf(ctx->fp, "bcnames = \""); - for (i = 0; bc_names[i]; i++) fprintf(ctx->fp, "%-6s", bc_names[i]); - fprintf(ctx->fp, "\",\n\n"); - - fprintf(ctx->fp, "irnames = \""); - for (i = 0; ir_names[i]; i++) fprintf(ctx->fp, "%-6s", ir_names[i]); - fprintf(ctx->fp, "\",\n\n"); - - fprintf(ctx->fp, "irfpm = { [0]="); - for (i = 0; irfpm_names[i]; i++) - fprintf(ctx->fp, "\"%s\", ", lower(buf, irfpm_names[i])); - fprintf(ctx->fp, "},\n\n"); - - fprintf(ctx->fp, "irfield = { [0]="); - for (i = 0; irfield_names[i]; i++) { - char *p; - lower(buf, irfield_names[i]); - p = strchr(buf, '_'); - if (p) *p = '.'; - fprintf(ctx->fp, "\"%s\", ", buf); - } - fprintf(ctx->fp, "},\n\n"); - - fprintf(ctx->fp, "ircall = {\n[0]="); - for (i = 0; ircall_names[i]; i++) - fprintf(ctx->fp, "\"%s\",\n", ircall_names[i]); - fprintf(ctx->fp, "},\n\n"); - - fprintf(ctx->fp, "traceerr = {\n[0]="); - for (i = 0; trace_errors[i]; i++) - fprintf(ctx->fp, "\"%s\",\n", trace_errors[i]); - fprintf(ctx->fp, "},\n\n"); -} - -/* -- Argument parsing ---------------------------------------------------- */ - -/* Build mode names. */ -static const char *const modenames[] = { -#define BUILDNAME(name) #name, -BUILDDEF(BUILDNAME) -#undef BUILDNAME - NULL -}; - -/* Print usage information and exit. */ -static void usage(void) -{ - int i; - fprintf(stderr, LUAJIT_VERSION " VM builder.\n"); - fprintf(stderr, LUAJIT_COPYRIGHT ", " LUAJIT_URL "\n"); - fprintf(stderr, "Target architecture: " LJ_ARCH_NAME "\n\n"); - fprintf(stderr, "Usage: buildvm -m mode [-o outfile] [infiles...]\n\n"); - fprintf(stderr, "Available modes:\n"); - for (i = 0; i < BUILD__MAX; i++) - fprintf(stderr, " %s\n", modenames[i]); - exit(1); -} - -/* Parse the output mode name. */ -static BuildMode parsemode(const char *mode) -{ - int i; - for (i = 0; modenames[i]; i++) - if (!strcmp(mode, modenames[i])) - return (BuildMode)i; - usage(); - return (BuildMode)-1; -} - -/* Parse arguments. */ -static void parseargs(BuildCtx *ctx, char **argv) -{ - const char *a; - int i; - ctx->mode = (BuildMode)-1; - ctx->outname = "-"; - for (i = 1; (a = argv[i]) != NULL; i++) { - if (a[0] != '-') - break; - switch (a[1]) { - case '-': - if (a[2]) goto err; - i++; - goto ok; - case '\0': - goto ok; - case 'm': - i++; - if (a[2] || argv[i] == NULL) goto err; - ctx->mode = parsemode(argv[i]); - break; - case 'o': - i++; - if (a[2] || argv[i] == NULL) goto err; - ctx->outname = argv[i]; - break; - default: err: - usage(); - break; - } - } -ok: - ctx->args = argv+i; - if (ctx->mode == (BuildMode)-1) goto err; -} - -int main(int argc, char **argv) -{ - BuildCtx ctx_; - BuildCtx *ctx = &ctx_; - int status, binmode; - - if (sizeof(void *) != 4*LJ_32+8*LJ_64) { - fprintf(stderr,"Error: pointer size mismatch in cross-build.\n"); - fprintf(stderr,"Try: make HOST_CC=\"gcc -m32\" CROSS=...\n\n"); - return 1; - } - - UNUSED(argc); - parseargs(ctx, argv); - - if ((status = build_code(ctx))) { - fprintf(stderr,"Error: DASM error %08x\n", status); - return 1; - } - - switch (ctx->mode) { - case BUILD_peobj: - case BUILD_raw: - binmode = 1; - break; - default: - binmode = 0; - break; - } - - if (ctx->outname[0] == '-' && ctx->outname[1] == '\0') { - ctx->fp = stdout; -#if defined(_WIN32) - if (binmode) - _setmode(_fileno(stdout), _O_BINARY); /* Yuck. */ -#endif - } else if (!(ctx->fp = fopen(ctx->outname, binmode ? "wb" : "w"))) { - fprintf(stderr, "Error: cannot open output file '%s': %s\n", - ctx->outname, strerror(errno)); - exit(1); - } - - switch (ctx->mode) { - case BUILD_elfasm: - case BUILD_coffasm: - case BUILD_machasm: - emit_asm(ctx); - emit_asm_debug(ctx); - break; - case BUILD_peobj: - emit_peobj(ctx); - break; - case BUILD_raw: - emit_raw(ctx); - break; - case BUILD_bcdef: - emit_bcdef(ctx); - emit_lib(ctx); - break; - case BUILD_vmdef: - emit_vmdef(ctx); - emit_lib(ctx); - fprintf(ctx->fp, "}\n\n"); - break; - case BUILD_ffdef: - case BUILD_libdef: - case BUILD_recdef: - emit_lib(ctx); - break; - case BUILD_folddef: - emit_fold(ctx); - break; - default: - break; - } - - fflush(ctx->fp); - if (ferror(ctx->fp)) { - fprintf(stderr, "Error: cannot write to output file: %s\n", - strerror(errno)); - exit(1); - } - fclose(ctx->fp); - - return 0; -} - diff --git a/lib/LuaJIT/src/host/buildvm.h b/lib/LuaJIT/src/host/buildvm.h deleted file mode 100644 index b90428d..0000000 --- a/lib/LuaJIT/src/host/buildvm.h +++ /dev/null @@ -1,105 +0,0 @@ -/* -** LuaJIT VM builder. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _BUILDVM_H -#define _BUILDVM_H - -#include -#include -#include -#include -#include - -#include "lj_def.h" -#include "lj_arch.h" - -/* Hardcoded limits. Increase as needed. */ -#define BUILD_MAX_RELOC 200 /* Max. number of relocations. */ -#define BUILD_MAX_FOLD 4096 /* Max. number of fold rules. */ - -/* Prefix for scanned library definitions. */ -#define LIBDEF_PREFIX "LJLIB_" - -/* Prefix for scanned fold definitions. */ -#define FOLDDEF_PREFIX "LJFOLD" - -/* Prefixes for generated labels. */ -#define LABEL_PREFIX "lj_" -#define LABEL_PREFIX_BC LABEL_PREFIX "BC_" -#define LABEL_PREFIX_FF LABEL_PREFIX "ff_" -#define LABEL_PREFIX_CF LABEL_PREFIX "cf_" -#define LABEL_PREFIX_FFH LABEL_PREFIX "ffh_" -#define LABEL_PREFIX_LIBCF LABEL_PREFIX "lib_cf_" -#define LABEL_PREFIX_LIBINIT LABEL_PREFIX "lib_init_" - -/* Forward declaration. */ -struct dasm_State; - -/* Build modes. */ -#define BUILDDEF(_) \ - _(elfasm) _(coffasm) _(machasm) _(peobj) _(raw) \ - _(bcdef) _(ffdef) _(libdef) _(recdef) _(vmdef) \ - _(folddef) - -typedef enum { -#define BUILDENUM(name) BUILD_##name, -BUILDDEF(BUILDENUM) -#undef BUILDENUM - BUILD__MAX -} BuildMode; - -/* Code relocation. */ -typedef struct BuildReloc { - int32_t ofs; - int sym; - int type; -} BuildReloc; - -typedef struct BuildSym { - const char *name; - int32_t ofs; -} BuildSym; - -/* Build context structure. */ -typedef struct BuildCtx { - /* DynASM state pointer. Should be first member. */ - struct dasm_State *D; - /* Parsed command line. */ - BuildMode mode; - FILE *fp; - const char *outname; - char **args; - /* Code and symbols generated by DynASM. */ - uint8_t *code; - size_t codesz; - int npc, nglob, nsym, nreloc, nrelocsym; - void **glob; - BuildSym *sym; - const char **relocsym; - int32_t *bc_ofs; - const char *beginsym; - /* Strings generated by DynASM. */ - const char *const *globnames; - const char *const *extnames; - const char *dasm_ident; - const char *dasm_arch; - /* Relocations. */ - BuildReloc reloc[BUILD_MAX_RELOC]; -} BuildCtx; - -extern void owrite(BuildCtx *ctx, const void *ptr, size_t sz); -extern void emit_asm(BuildCtx *ctx); -extern void emit_peobj(BuildCtx *ctx); -extern void emit_lib(BuildCtx *ctx); -extern void emit_fold(BuildCtx *ctx); - -extern const char *const bc_names[]; -extern const char *const ir_names[]; -extern const char *const irt_names[]; -extern const char *const irfpm_names[]; -extern const char *const irfield_names[]; -extern const char *const ircall_names[]; - -#endif diff --git a/lib/LuaJIT/src/host/buildvm_asm.c b/lib/LuaJIT/src/host/buildvm_asm.c deleted file mode 100644 index 43595b3..0000000 --- a/lib/LuaJIT/src/host/buildvm_asm.c +++ /dev/null @@ -1,359 +0,0 @@ -/* -** LuaJIT VM builder: Assembler source code emitter. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#include "buildvm.h" -#include "lj_bc.h" - -/* ------------------------------------------------------------------------ */ - -#if LJ_TARGET_X86ORX64 -/* Emit bytes piecewise as assembler text. */ -static void emit_asm_bytes(BuildCtx *ctx, uint8_t *p, int n) -{ - int i; - for (i = 0; i < n; i++) { - if ((i & 15) == 0) - fprintf(ctx->fp, "\t.byte %d", p[i]); - else - fprintf(ctx->fp, ",%d", p[i]); - if ((i & 15) == 15) putc('\n', ctx->fp); - } - if ((n & 15) != 0) putc('\n', ctx->fp); -} - -/* Emit relocation */ -static void emit_asm_reloc(BuildCtx *ctx, int type, const char *sym) -{ - switch (ctx->mode) { - case BUILD_elfasm: - if (type) - fprintf(ctx->fp, "\t.long %s-.-4\n", sym); - else - fprintf(ctx->fp, "\t.long %s\n", sym); - break; - case BUILD_coffasm: - fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", sym); - if (type) - fprintf(ctx->fp, "\t.long %s-.-4\n", sym); - else - fprintf(ctx->fp, "\t.long %s\n", sym); - break; - default: /* BUILD_machasm for relative relocations handled below. */ - fprintf(ctx->fp, "\t.long %s\n", sym); - break; - } -} - -static const char *const jccnames[] = { - "jo", "jno", "jb", "jnb", "jz", "jnz", "jbe", "ja", - "js", "jns", "jpe", "jpo", "jl", "jge", "jle", "jg" -}; - -/* Emit x86/x64 text relocations. */ -static void emit_asm_reloc_text(BuildCtx *ctx, uint8_t *cp, int n, - const char *sym) -{ - const char *opname = NULL; - if (--n < 0) goto err; - if (cp[n] == 0xe8) { - opname = "call"; - } else if (cp[n] == 0xe9) { - opname = "jmp"; - } else if (cp[n] >= 0x80 && cp[n] <= 0x8f && n > 0 && cp[n-1] == 0x0f) { - opname = jccnames[cp[n]-0x80]; - n--; - } else { -err: - fprintf(stderr, "Error: unsupported opcode for %s symbol relocation.\n", - sym); - exit(1); - } - emit_asm_bytes(ctx, cp, n); - if (strncmp(sym+(*sym == '_'), LABEL_PREFIX, sizeof(LABEL_PREFIX)-1)) { - /* Various fixups for external symbols outside of our binary. */ - if (ctx->mode == BUILD_elfasm) { - if (LJ_32) - fprintf(ctx->fp, "#if __PIC__\n\t%s lj_wrap_%s\n#else\n", opname, sym); - fprintf(ctx->fp, "\t%s %s@PLT\n", opname, sym); - if (LJ_32) - fprintf(ctx->fp, "#endif\n"); - return; - } else if (LJ_32 && ctx->mode == BUILD_machasm) { - fprintf(ctx->fp, "\t%s L%s$stub\n", opname, sym); - return; - } - } - fprintf(ctx->fp, "\t%s %s\n", opname, sym); -} -#else -/* Emit words piecewise as assembler text. */ -static void emit_asm_words(BuildCtx *ctx, uint8_t *p, int n) -{ - int i; - for (i = 0; i < n; i += 4) { - uint32_t ins = *(uint32_t *)(p+i); -#if LJ_TARGET_ARM64 && LJ_BE - ins = lj_bswap(ins); /* ARM64 instructions are always little-endian. */ -#endif - if ((i & 15) == 0) - fprintf(ctx->fp, "\t.long 0x%08x", ins); - else - fprintf(ctx->fp, ",0x%08x", ins); - if ((i & 15) == 12) putc('\n', ctx->fp); - } - if ((n & 15) != 0) putc('\n', ctx->fp); -} - -/* Emit relocation as part of an instruction. */ -static void emit_asm_wordreloc(BuildCtx *ctx, uint8_t *p, int n, - const char *sym) -{ - uint32_t ins; - emit_asm_words(ctx, p, n-4); - ins = *(uint32_t *)(p+n-4); -#if LJ_TARGET_ARM - if ((ins & 0xff000000u) == 0xfa000000u) { - fprintf(ctx->fp, "\tblx %s\n", sym); - } else if ((ins & 0x0e000000u) == 0x0a000000u) { - fprintf(ctx->fp, "\t%s%.2s %s\n", (ins & 0x01000000u) ? "bl" : "b", - &"eqnecsccmiplvsvchilsgeltgtle"[2*(ins >> 28)], sym); - } else { - fprintf(stderr, - "Error: unsupported opcode %08x for %s symbol relocation.\n", - ins, sym); - exit(1); - } -#elif LJ_TARGET_ARM64 - if ((ins >> 26) == 0x25u) { - fprintf(ctx->fp, "\tbl %s\n", sym); - } else { - fprintf(stderr, - "Error: unsupported opcode %08x for %s symbol relocation.\n", - ins, sym); - exit(1); - } -#elif LJ_TARGET_PPC -#if LJ_TARGET_PS3 -#define TOCPREFIX "." -#else -#define TOCPREFIX "" -#endif - if ((ins >> 26) == 16) { - fprintf(ctx->fp, "\t%s %d, %d, " TOCPREFIX "%s\n", - (ins & 1) ? "bcl" : "bc", (ins >> 21) & 31, (ins >> 16) & 31, sym); - } else if ((ins >> 26) == 18) { -#if LJ_ARCH_PPC64 - const char *suffix = strchr(sym, '@'); - if (suffix && suffix[1] == 'h') { - fprintf(ctx->fp, "\taddis 11, 2, %s\n", sym); - } else if (suffix && suffix[1] == 'l') { - fprintf(ctx->fp, "\tld 12, %s\n", sym); - } else -#endif - fprintf(ctx->fp, "\t%s " TOCPREFIX "%s\n", (ins & 1) ? "bl" : "b", sym); - } else { - fprintf(stderr, - "Error: unsupported opcode %08x for %s symbol relocation.\n", - ins, sym); - exit(1); - } -#elif LJ_TARGET_MIPS - fprintf(stderr, - "Error: unsupported opcode %08x for %s symbol relocation.\n", - ins, sym); - exit(1); -#else -#error "missing relocation support for this architecture" -#endif -} -#endif - -#if LJ_TARGET_ARM -#define ELFASM_PX "%%" -#else -#define ELFASM_PX "@" -#endif - -/* Emit an assembler label. */ -static void emit_asm_label(BuildCtx *ctx, const char *name, int size, int isfunc) -{ - switch (ctx->mode) { - case BUILD_elfasm: -#if LJ_TARGET_PS3 - if (!strncmp(name, "lj_vm_", 6) && - strcmp(name, ctx->beginsym) && - !strstr(name, "hook")) { - fprintf(ctx->fp, - "\n\t.globl %s\n" - "\t.section \".opd\",\"aw\"\n" - "%s:\n" - "\t.long .%s,.TOC.@tocbase32\n" - "\t.size %s,8\n" - "\t.previous\n" - "\t.globl .%s\n" - "\t.hidden .%s\n" - "\t.type .%s, " ELFASM_PX "function\n" - "\t.size .%s, %d\n" - ".%s:\n", - name, name, name, name, name, name, name, name, size, name); - break; - } -#endif - fprintf(ctx->fp, - "\n\t.globl %s\n" - "\t.hidden %s\n" - "\t.type %s, " ELFASM_PX "%s\n" - "\t.size %s, %d\n" - "%s:\n", - name, name, name, isfunc ? "function" : "object", name, size, name); - break; - case BUILD_coffasm: - fprintf(ctx->fp, "\n\t.globl %s\n", name); - if (isfunc) - fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", name); - fprintf(ctx->fp, "%s:\n", name); - break; - case BUILD_machasm: - fprintf(ctx->fp, - "\n\t.private_extern %s\n" - "\t.no_dead_strip %s\n" - "%s:\n", name, name, name); - break; - default: - break; - } -} - -/* Emit alignment. */ -static void emit_asm_align(BuildCtx *ctx, int bits) -{ - switch (ctx->mode) { - case BUILD_elfasm: - case BUILD_coffasm: - fprintf(ctx->fp, "\t.p2align %d\n", bits); - break; - case BUILD_machasm: - fprintf(ctx->fp, "\t.align %d\n", bits); - break; - default: - break; - } -} - -/* ------------------------------------------------------------------------ */ - -/* Emit assembler source code. */ -void emit_asm(BuildCtx *ctx) -{ - int i, rel; - - fprintf(ctx->fp, "\t.file \"buildvm_%s.dasc\"\n", ctx->dasm_arch); -#if LJ_ARCH_PPC64 - fprintf(ctx->fp, "\t.abiversion 2\n"); -#endif - fprintf(ctx->fp, "\t.text\n"); - emit_asm_align(ctx, 4); - -#if LJ_TARGET_PS3 - emit_asm_label(ctx, ctx->beginsym, ctx->codesz, 0); -#else - emit_asm_label(ctx, ctx->beginsym, 0, 0); -#endif - if (ctx->mode != BUILD_machasm) - fprintf(ctx->fp, ".Lbegin:\n"); - -#if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND - /* This should really be moved into buildvm_arm.dasc. */ -#if LJ_ARCH_HASFPU - fprintf(ctx->fp, - ".fnstart\n" - ".save {r5, r6, r7, r8, r9, r10, r11, lr}\n" - ".vsave {d8-d15}\n" - ".save {r4}\n" - ".pad #28\n"); -#else - fprintf(ctx->fp, - ".fnstart\n" - ".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n" - ".pad #28\n"); -#endif -#endif -#if LJ_TARGET_MIPS - fprintf(ctx->fp, ".set nomips16\n.abicalls\n.set noreorder\n.set nomacro\n"); -#endif - - for (i = rel = 0; i < ctx->nsym; i++) { - int32_t ofs = ctx->sym[i].ofs; - int32_t next = ctx->sym[i+1].ofs; -#if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND && LJ_HASFFI - if (!strcmp(ctx->sym[i].name, "lj_vm_ffi_call")) - fprintf(ctx->fp, - ".globl lj_err_unwind_arm\n" - ".personality lj_err_unwind_arm\n" - ".fnend\n" - ".fnstart\n" - ".save {r4, r5, r11, lr}\n" - ".setfp r11, sp\n"); -#endif - emit_asm_label(ctx, ctx->sym[i].name, next - ofs, 1); - while (rel < ctx->nreloc && ctx->reloc[rel].ofs <= next) { - BuildReloc *r = &ctx->reloc[rel]; - int n = r->ofs - ofs; -#if LJ_TARGET_X86ORX64 - if (r->type != 0 && - (ctx->mode == BUILD_elfasm || ctx->mode == BUILD_machasm)) { - emit_asm_reloc_text(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]); - } else { - emit_asm_bytes(ctx, ctx->code+ofs, n); - emit_asm_reloc(ctx, r->type, ctx->relocsym[r->sym]); - } - ofs += n+4; -#else - emit_asm_wordreloc(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]); - ofs += n; -#endif - rel++; - } -#if LJ_TARGET_X86ORX64 - emit_asm_bytes(ctx, ctx->code+ofs, next-ofs); -#else - emit_asm_words(ctx, ctx->code+ofs, next-ofs); -#endif - } - -#if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND - fprintf(ctx->fp, -#if !LJ_HASFFI - ".globl lj_err_unwind_arm\n" - ".personality lj_err_unwind_arm\n" -#endif - ".fnend\n"); -#endif - - fprintf(ctx->fp, "\n"); - switch (ctx->mode) { - case BUILD_elfasm: -#if !(LJ_TARGET_PS3 || LJ_TARGET_PSVITA) - fprintf(ctx->fp, "\t.section .note.GNU-stack,\"\"," ELFASM_PX "progbits\n"); -#endif -#if LJ_TARGET_PPC && !LJ_TARGET_PS3 && !LJ_ABI_SOFTFP - /* Hard-float ABI. */ - fprintf(ctx->fp, "\t.gnu_attribute 4, 1\n"); -#endif - /* fallthrough */ - case BUILD_coffasm: - fprintf(ctx->fp, "\t.ident \"%s\"\n", ctx->dasm_ident); - break; - case BUILD_machasm: - fprintf(ctx->fp, - "\t.cstring\n" - "\t.ascii \"%s\\0\"\n", ctx->dasm_ident); - break; - default: - break; - } - fprintf(ctx->fp, "\n"); -} - diff --git a/lib/LuaJIT/src/host/buildvm_fold.c b/lib/LuaJIT/src/host/buildvm_fold.c deleted file mode 100644 index d579f4d..0000000 --- a/lib/LuaJIT/src/host/buildvm_fold.c +++ /dev/null @@ -1,229 +0,0 @@ -/* -** LuaJIT VM builder: IR folding hash table generator. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#include "buildvm.h" -#include "lj_obj.h" -#include "lj_ir.h" - -/* Context for the folding hash table generator. */ -static int lineno; -static uint32_t funcidx; -static uint32_t foldkeys[BUILD_MAX_FOLD]; -static uint32_t nkeys; - -/* Try to fill the hash table with keys using the hash parameters. */ -static int tryhash(uint32_t *htab, uint32_t sz, uint32_t r, int dorol) -{ - uint32_t i; - if (dorol && ((r & 31) == 0 || (r>>5) == 0)) - return 0; /* Avoid zero rotates. */ - memset(htab, 0xff, (sz+1)*sizeof(uint32_t)); - for (i = 0; i < nkeys; i++) { - uint32_t key = foldkeys[i]; - uint32_t k = key & 0xffffff; - uint32_t h = (dorol ? lj_rol(lj_rol(k, r>>5) - k, r&31) : - (((k << (r>>5)) - k) << (r&31))) % sz; - if (htab[h] != 0xffffffff) { /* Collision on primary slot. */ - if (htab[h+1] != 0xffffffff) { /* Collision on secondary slot. */ - /* Try to move the colliding key, if possible. */ - if (h < sz-1 && htab[h+2] == 0xffffffff) { - uint32_t k2 = htab[h+1] & 0xffffff; - uint32_t h2 = (dorol ? lj_rol(lj_rol(k2, r>>5) - k2, r&31) : - (((k2 << (r>>5)) - k2) << (r&31))) % sz; - if (h2 != h+1) return 0; /* Cannot resolve collision. */ - htab[h+2] = htab[h+1]; /* Move colliding key to secondary slot. */ - } else { - return 0; /* Collision. */ - } - } - htab[h+1] = key; - } else { - htab[h] = key; - } - } - return 1; /* Success, all keys could be stored. */ -} - -/* Print the generated hash table. */ -static void printhash(BuildCtx *ctx, uint32_t *htab, uint32_t sz) -{ - uint32_t i; - fprintf(ctx->fp, "static const uint32_t fold_hash[%d] = {\n0x%08x", - sz+1, htab[0]); - for (i = 1; i < sz+1; i++) - fprintf(ctx->fp, ",\n0x%08x", htab[i]); - fprintf(ctx->fp, "\n};\n\n"); -} - -/* Exhaustive search for the shortest semi-perfect hash table. */ -static void makehash(BuildCtx *ctx) -{ - uint32_t htab[BUILD_MAX_FOLD*2+1]; - uint32_t sz, r; - /* Search for the smallest hash table with an odd size. */ - for (sz = (nkeys|1); sz < BUILD_MAX_FOLD*2; sz += 2) { - /* First try all shift hash combinations. */ - for (r = 0; r < 32*32; r++) { - if (tryhash(htab, sz, r, 0)) { - printhash(ctx, htab, sz); - fprintf(ctx->fp, - "#define fold_hashkey(k)\t(((((k)<<%u)-(k))<<%u)%%%u)\n\n", - r>>5, r&31, sz); - return; - } - } - /* Then try all rotate hash combinations. */ - for (r = 0; r < 32*32; r++) { - if (tryhash(htab, sz, r, 1)) { - printhash(ctx, htab, sz); - fprintf(ctx->fp, - "#define fold_hashkey(k)\t(lj_rol(lj_rol((k),%u)-(k),%u)%%%u)\n\n", - r>>5, r&31, sz); - return; - } - } - } - fprintf(stderr, "Error: search for perfect hash failed\n"); - exit(1); -} - -/* Parse one token of a fold rule. */ -static uint32_t nexttoken(char **pp, int allowlit, int allowany) -{ - char *p = *pp; - if (p) { - uint32_t i; - char *q = strchr(p, ' '); - if (q) *q++ = '\0'; - *pp = q; - if (allowlit && !strncmp(p, "IRFPM_", 6)) { - for (i = 0; irfpm_names[i]; i++) - if (!strcmp(irfpm_names[i], p+6)) - return i; - } else if (allowlit && !strncmp(p, "IRFL_", 5)) { - for (i = 0; irfield_names[i]; i++) - if (!strcmp(irfield_names[i], p+5)) - return i; - } else if (allowlit && !strncmp(p, "IRCALL_", 7)) { - for (i = 0; ircall_names[i]; i++) - if (!strcmp(ircall_names[i], p+7)) - return i; - } else if (allowlit && !strncmp(p, "IRCONV_", 7)) { - for (i = 0; irt_names[i]; i++) { - const char *r = strchr(p+7, '_'); - if (r && !strncmp(irt_names[i], p+7, r-(p+7))) { - uint32_t j; - for (j = 0; irt_names[j]; j++) - if (!strcmp(irt_names[j], r+1)) - return (i << 5) + j; - } - } - } else if (allowlit && *p >= '0' && *p <= '9') { - for (i = 0; *p >= '0' && *p <= '9'; p++) - i = i*10 + (*p - '0'); - if (*p == '\0') - return i; - } else if (allowany && !strcmp("any", p)) { - return allowany; - } else { - for (i = 0; ir_names[i]; i++) - if (!strcmp(ir_names[i], p)) - return i; - } - fprintf(stderr, "Error: bad fold definition token \"%s\" at line %d\n", p, lineno); - exit(1); - } - return 0; -} - -/* Parse a fold rule. */ -static void foldrule(char *p) -{ - uint32_t op = nexttoken(&p, 0, 0); - uint32_t left = nexttoken(&p, 0, 0x7f); - uint32_t right = nexttoken(&p, 1, 0x3ff); - uint32_t key = (funcidx << 24) | (op << 17) | (left << 10) | right; - uint32_t i; - if (nkeys >= BUILD_MAX_FOLD) { - fprintf(stderr, "Error: too many fold rules, increase BUILD_MAX_FOLD.\n"); - exit(1); - } - /* Simple insertion sort to detect duplicates. */ - for (i = nkeys; i > 0; i--) { - if ((foldkeys[i-1]&0xffffff) < (key & 0xffffff)) - break; - if ((foldkeys[i-1]&0xffffff) == (key & 0xffffff)) { - fprintf(stderr, "Error: duplicate fold definition at line %d\n", lineno); - exit(1); - } - foldkeys[i] = foldkeys[i-1]; - } - foldkeys[i] = key; - nkeys++; -} - -/* Emit C source code for IR folding hash table. */ -void emit_fold(BuildCtx *ctx) -{ - char buf[256]; /* We don't care about analyzing lines longer than that. */ - const char *fname = ctx->args[0]; - FILE *fp; - - if (fname == NULL) { - fprintf(stderr, "Error: missing input filename\n"); - exit(1); - } - - if (fname[0] == '-' && fname[1] == '\0') { - fp = stdin; - } else { - fp = fopen(fname, "r"); - if (!fp) { - fprintf(stderr, "Error: cannot open input file '%s': %s\n", - fname, strerror(errno)); - exit(1); - } - } - - fprintf(ctx->fp, "/* This is a generated file. DO NOT EDIT! */\n\n"); - fprintf(ctx->fp, "static const FoldFunc fold_func[] = {\n"); - - lineno = 0; - funcidx = 0; - nkeys = 0; - while (fgets(buf, sizeof(buf), fp) != NULL) { - lineno++; - /* The prefix must be at the start of a line, otherwise it's ignored. */ - if (!strncmp(buf, FOLDDEF_PREFIX, sizeof(FOLDDEF_PREFIX)-1)) { - char *p = buf+sizeof(FOLDDEF_PREFIX)-1; - char *q = strchr(p, ')'); - if (p[0] == '(' && q) { - p++; - *q = '\0'; - foldrule(p); - } else if ((p[0] == 'F' || p[0] == 'X') && p[1] == '(' && q) { - p += 2; - *q = '\0'; - if (funcidx) - fprintf(ctx->fp, ",\n"); - if (p[-2] == 'X') - fprintf(ctx->fp, " %s", p); - else - fprintf(ctx->fp, " fold_%s", p); - funcidx++; - } else { - buf[strlen(buf)-1] = '\0'; - fprintf(stderr, "Error: unknown fold definition tag %s%s at line %d\n", - FOLDDEF_PREFIX, p, lineno); - exit(1); - } - } - } - fclose(fp); - fprintf(ctx->fp, "\n};\n\n"); - - makehash(ctx); -} - diff --git a/lib/LuaJIT/src/host/buildvm_lib.c b/lib/LuaJIT/src/host/buildvm_lib.c deleted file mode 100644 index 2956fdb..0000000 --- a/lib/LuaJIT/src/host/buildvm_lib.c +++ /dev/null @@ -1,457 +0,0 @@ -/* -** LuaJIT VM builder: library definition compiler. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#include "buildvm.h" -#include "lj_obj.h" -#include "lj_bc.h" -#include "lj_lib.h" -#include "buildvm_libbc.h" - -/* Context for library definitions. */ -static uint8_t obuf[8192]; -static uint8_t *optr; -static char modname[80]; -static size_t modnamelen; -static char funcname[80]; -static int modstate, regfunc; -static int ffid, recffid, ffasmfunc; - -enum { - REGFUNC_OK, - REGFUNC_NOREG, - REGFUNC_NOREGUV -}; - -static void libdef_name(const char *p, int kind) -{ - size_t n = strlen(p); - if (kind != LIBINIT_STRING) { - if (n > modnamelen && p[modnamelen] == '_' && - !strncmp(p, modname, modnamelen)) { - p += modnamelen+1; - n -= modnamelen+1; - } - } - if (n > LIBINIT_MAXSTR) { - fprintf(stderr, "Error: string too long: '%s'\n", p); - exit(1); - } - if (optr+1+n+2 > obuf+sizeof(obuf)) { /* +2 for caller. */ - fprintf(stderr, "Error: output buffer overflow\n"); - exit(1); - } - *optr++ = (uint8_t)(n | kind); - memcpy(optr, p, n); - optr += n; -} - -static void libdef_endmodule(BuildCtx *ctx) -{ - if (modstate != 0) { - char line[80]; - const uint8_t *p; - int n; - if (modstate == 1) - fprintf(ctx->fp, " (lua_CFunction)0"); - fprintf(ctx->fp, "\n};\n"); - fprintf(ctx->fp, "static const uint8_t %s%s[] = {\n", - LABEL_PREFIX_LIBINIT, modname); - line[0] = '\0'; - for (n = 0, p = obuf; p < optr; p++) { - n += sprintf(line+n, "%d,", *p); - if (n >= 75) { - fprintf(ctx->fp, "%s\n", line); - n = 0; - line[0] = '\0'; - } - } - fprintf(ctx->fp, "%s%d\n};\n#endif\n\n", line, LIBINIT_END); - } -} - -static void libdef_module(BuildCtx *ctx, char *p, int arg) -{ - UNUSED(arg); - if (ctx->mode == BUILD_libdef) { - libdef_endmodule(ctx); - optr = obuf; - *optr++ = (uint8_t)ffid; - *optr++ = (uint8_t)ffasmfunc; - *optr++ = 0; /* Hash table size. */ - modstate = 1; - fprintf(ctx->fp, "#ifdef %sMODULE_%s\n", LIBDEF_PREFIX, p); - fprintf(ctx->fp, "#undef %sMODULE_%s\n", LIBDEF_PREFIX, p); - fprintf(ctx->fp, "static const lua_CFunction %s%s[] = {\n", - LABEL_PREFIX_LIBCF, p); - } - modnamelen = strlen(p); - if (modnamelen > sizeof(modname)-1) { - fprintf(stderr, "Error: module name too long: '%s'\n", p); - exit(1); - } - strcpy(modname, p); -} - -static int find_ffofs(BuildCtx *ctx, const char *name) -{ - int i; - for (i = 0; i < ctx->nglob; i++) { - const char *gl = ctx->globnames[i]; - if (gl[0] == 'f' && gl[1] == 'f' && gl[2] == '_' && !strcmp(gl+3, name)) { - return (int)((uint8_t *)ctx->glob[i] - ctx->code); - } - } - fprintf(stderr, "Error: undefined fast function %s%s\n", - LABEL_PREFIX_FF, name); - exit(1); -} - -static void libdef_func(BuildCtx *ctx, char *p, int arg) -{ - if (arg != LIBINIT_CF) - ffasmfunc++; - if (ctx->mode == BUILD_libdef) { - if (modstate == 0) { - fprintf(stderr, "Error: no module for function definition %s\n", p); - exit(1); - } - if (regfunc == REGFUNC_NOREG) { - if (optr+1 > obuf+sizeof(obuf)) { - fprintf(stderr, "Error: output buffer overflow\n"); - exit(1); - } - *optr++ = LIBINIT_FFID; - } else { - if (arg != LIBINIT_ASM_) { - if (modstate != 1) fprintf(ctx->fp, ",\n"); - modstate = 2; - fprintf(ctx->fp, " %s%s", arg ? LABEL_PREFIX_FFH : LABEL_PREFIX_CF, p); - } - if (regfunc != REGFUNC_NOREGUV) obuf[2]++; /* Bump hash table size. */ - libdef_name(regfunc == REGFUNC_NOREGUV ? "" : p, arg); - } - } else if (ctx->mode == BUILD_ffdef) { - fprintf(ctx->fp, "FFDEF(%s)\n", p); - } else if (ctx->mode == BUILD_recdef) { - if (strlen(p) > sizeof(funcname)-1) { - fprintf(stderr, "Error: function name too long: '%s'\n", p); - exit(1); - } - strcpy(funcname, p); - } else if (ctx->mode == BUILD_vmdef) { - int i; - for (i = 1; p[i] && modname[i-1]; i++) - if (p[i] == '_') p[i] = '.'; - fprintf(ctx->fp, "\"%s\",\n", p); - } else if (ctx->mode == BUILD_bcdef) { - if (arg != LIBINIT_CF) - fprintf(ctx->fp, ",\n%d", find_ffofs(ctx, p)); - } - ffid++; - regfunc = REGFUNC_OK; -} - -static uint8_t *libdef_uleb128(uint8_t *p, uint32_t *vv) -{ - uint32_t v = *p++; - if (v >= 0x80) { - int sh = 0; v &= 0x7f; - do { v |= ((*p & 0x7f) << (sh += 7)); } while (*p++ >= 0x80); - } - *vv = v; - return p; -} - -static void libdef_fixupbc(uint8_t *p) -{ - uint32_t i, sizebc; - p += 4; - p = libdef_uleb128(p, &sizebc); - p = libdef_uleb128(p, &sizebc); - p = libdef_uleb128(p, &sizebc); - for (i = 0; i < sizebc; i++, p += 4) { - uint8_t op = p[libbc_endian ? 3 : 0]; - uint8_t ra = p[libbc_endian ? 2 : 1]; - uint8_t rc = p[libbc_endian ? 1 : 2]; - uint8_t rb = p[libbc_endian ? 0 : 3]; - if (!LJ_DUALNUM && op == BC_ISTYPE && rc == ~LJ_TNUMX+1) { - op = BC_ISNUM; rc++; - } - p[LJ_ENDIAN_SELECT(0, 3)] = op; - p[LJ_ENDIAN_SELECT(1, 2)] = ra; - p[LJ_ENDIAN_SELECT(2, 1)] = rc; - p[LJ_ENDIAN_SELECT(3, 0)] = rb; - } -} - -static void libdef_lua(BuildCtx *ctx, char *p, int arg) -{ - UNUSED(arg); - if (ctx->mode == BUILD_libdef) { - int i; - for (i = 0; libbc_map[i].name != NULL; i++) { - if (!strcmp(libbc_map[i].name, p)) { - int ofs = libbc_map[i].ofs; - int len = libbc_map[i+1].ofs - ofs; - obuf[2]++; /* Bump hash table size. */ - *optr++ = LIBINIT_LUA; - libdef_name(p, 0); - memcpy(optr, libbc_code + ofs, len); - libdef_fixupbc(optr); - optr += len; - return; - } - } - fprintf(stderr, "Error: missing libbc definition for %s\n", p); - exit(1); - } -} - -static uint32_t find_rec(char *name) -{ - char *p = (char *)obuf; - uint32_t n; - for (n = 2; *p; n++) { - if (strcmp(p, name) == 0) - return n; - p += strlen(p)+1; - } - if (p+strlen(name)+1 >= (char *)obuf+sizeof(obuf)) { - fprintf(stderr, "Error: output buffer overflow\n"); - exit(1); - } - strcpy(p, name); - return n; -} - -static void libdef_rec(BuildCtx *ctx, char *p, int arg) -{ - UNUSED(arg); - if (ctx->mode == BUILD_recdef) { - char *q; - uint32_t n; - for (; recffid+1 < ffid; recffid++) - fprintf(ctx->fp, ",\n0"); - recffid = ffid; - if (*p == '.') p = funcname; - q = strchr(p, ' '); - if (q) *q++ = '\0'; - n = find_rec(p); - if (q) - fprintf(ctx->fp, ",\n0x%02x00+(%s)", n, q); - else - fprintf(ctx->fp, ",\n0x%02x00", n); - } -} - -static void memcpy_endian(void *dst, void *src, size_t n) -{ - union { uint8_t b; uint32_t u; } host_endian; - host_endian.u = 1; - if (host_endian.b == LJ_ENDIAN_SELECT(1, 0)) { - memcpy(dst, src, n); - } else { - size_t i; - for (i = 0; i < n; i++) - ((uint8_t *)dst)[i] = ((uint8_t *)src)[n-i-1]; - } -} - -static void libdef_push(BuildCtx *ctx, char *p, int arg) -{ - UNUSED(arg); - if (ctx->mode == BUILD_libdef) { - int len = (int)strlen(p); - if (*p == '"') { - if (len > 1 && p[len-1] == '"') { - p[len-1] = '\0'; - libdef_name(p+1, LIBINIT_STRING); - return; - } - } else if (*p >= '0' && *p <= '9') { - char *ep; - double d = strtod(p, &ep); - if (*ep == '\0') { - if (optr+1+sizeof(double) > obuf+sizeof(obuf)) { - fprintf(stderr, "Error: output buffer overflow\n"); - exit(1); - } - *optr++ = LIBINIT_NUMBER; - memcpy_endian(optr, &d, sizeof(double)); - optr += sizeof(double); - return; - } - } else if (!strcmp(p, "lastcl")) { - if (optr+1 > obuf+sizeof(obuf)) { - fprintf(stderr, "Error: output buffer overflow\n"); - exit(1); - } - *optr++ = LIBINIT_LASTCL; - return; - } else if (len > 4 && !strncmp(p, "top-", 4)) { - if (optr+2 > obuf+sizeof(obuf)) { - fprintf(stderr, "Error: output buffer overflow\n"); - exit(1); - } - *optr++ = LIBINIT_COPY; - *optr++ = (uint8_t)atoi(p+4); - return; - } - fprintf(stderr, "Error: bad value for %sPUSH(%s)\n", LIBDEF_PREFIX, p); - exit(1); - } -} - -static void libdef_set(BuildCtx *ctx, char *p, int arg) -{ - UNUSED(arg); - if (ctx->mode == BUILD_libdef) { - if (p[0] == '!' && p[1] == '\0') p[0] = '\0'; /* Set env. */ - libdef_name(p, LIBINIT_STRING); - *optr++ = LIBINIT_SET; - obuf[2]++; /* Bump hash table size. */ - } -} - -static void libdef_regfunc(BuildCtx *ctx, char *p, int arg) -{ - UNUSED(ctx); UNUSED(p); - regfunc = arg; -} - -typedef void (*LibDefFunc)(BuildCtx *ctx, char *p, int arg); - -typedef struct LibDefHandler { - const char *suffix; - const char *stop; - const LibDefFunc func; - const int arg; -} LibDefHandler; - -static const LibDefHandler libdef_handlers[] = { - { "MODULE_", " \t\r\n", libdef_module, 0 }, - { "CF(", ")", libdef_func, LIBINIT_CF }, - { "ASM(", ")", libdef_func, LIBINIT_ASM }, - { "ASM_(", ")", libdef_func, LIBINIT_ASM_ }, - { "LUA(", ")", libdef_lua, 0 }, - { "REC(", ")", libdef_rec, 0 }, - { "PUSH(", ")", libdef_push, 0 }, - { "SET(", ")", libdef_set, 0 }, - { "NOREGUV", NULL, libdef_regfunc, REGFUNC_NOREGUV }, - { "NOREG", NULL, libdef_regfunc, REGFUNC_NOREG }, - { NULL, NULL, (LibDefFunc)0, 0 } -}; - -/* Emit C source code for library function definitions. */ -void emit_lib(BuildCtx *ctx) -{ - const char *fname; - - if (ctx->mode == BUILD_ffdef || ctx->mode == BUILD_libdef || - ctx->mode == BUILD_recdef) - fprintf(ctx->fp, "/* This is a generated file. DO NOT EDIT! */\n\n"); - else if (ctx->mode == BUILD_vmdef) - fprintf(ctx->fp, "ffnames = {\n[0]=\"Lua\",\n\"C\",\n"); - if (ctx->mode == BUILD_recdef) - fprintf(ctx->fp, "static const uint16_t recff_idmap[] = {\n0,\n0x0100"); - recffid = ffid = FF_C+1; - ffasmfunc = 0; - - while ((fname = *ctx->args++)) { - char buf[256]; /* We don't care about analyzing lines longer than that. */ - FILE *fp; - if (fname[0] == '-' && fname[1] == '\0') { - fp = stdin; - } else { - fp = fopen(fname, "r"); - if (!fp) { - fprintf(stderr, "Error: cannot open input file '%s': %s\n", - fname, strerror(errno)); - exit(1); - } - } - modstate = 0; - regfunc = REGFUNC_OK; - while (fgets(buf, sizeof(buf), fp) != NULL) { - char *p; - /* Simplistic pre-processor. Only handles top-level #if/#endif. */ - if (buf[0] == '#' && buf[1] == 'i' && buf[2] == 'f') { - int ok = 1; - if (!strcmp(buf, "#if LJ_52\n")) - ok = LJ_52; - else if (!strcmp(buf, "#if LJ_HASJIT\n")) - ok = LJ_HASJIT; - else if (!strcmp(buf, "#if LJ_HASFFI\n")) - ok = LJ_HASFFI; - if (!ok) { - int lvl = 1; - while (fgets(buf, sizeof(buf), fp) != NULL) { - if (buf[0] == '#' && buf[1] == 'e' && buf[2] == 'n') { - if (--lvl == 0) break; - } else if (buf[0] == '#' && buf[1] == 'i' && buf[2] == 'f') { - lvl++; - } - } - continue; - } - } - for (p = buf; (p = strstr(p, LIBDEF_PREFIX)) != NULL; ) { - const LibDefHandler *ldh; - p += sizeof(LIBDEF_PREFIX)-1; - for (ldh = libdef_handlers; ldh->suffix != NULL; ldh++) { - size_t n, len = strlen(ldh->suffix); - if (!strncmp(p, ldh->suffix, len)) { - p += len; - n = ldh->stop ? strcspn(p, ldh->stop) : 0; - if (!p[n]) break; - p[n] = '\0'; - ldh->func(ctx, p, ldh->arg); - p += n+1; - break; - } - } - if (ldh->suffix == NULL) { - buf[strlen(buf)-1] = '\0'; - fprintf(stderr, "Error: unknown library definition tag %s%s\n", - LIBDEF_PREFIX, p); - exit(1); - } - } - } - fclose(fp); - if (ctx->mode == BUILD_libdef) { - libdef_endmodule(ctx); - } - } - - if (ctx->mode == BUILD_ffdef) { - fprintf(ctx->fp, "\n#undef FFDEF\n\n"); - fprintf(ctx->fp, - "#ifndef FF_NUM_ASMFUNC\n#define FF_NUM_ASMFUNC %d\n#endif\n\n", - ffasmfunc); - } else if (ctx->mode == BUILD_vmdef) { - fprintf(ctx->fp, "},\n\n"); - } else if (ctx->mode == BUILD_bcdef) { - int i; - fprintf(ctx->fp, "\n};\n\n"); - fprintf(ctx->fp, "LJ_DATADEF const uint16_t lj_bc_mode[] = {\n"); - fprintf(ctx->fp, "BCDEF(BCMODE)\n"); - for (i = ffasmfunc-1; i > 0; i--) - fprintf(ctx->fp, "BCMODE_FF,\n"); - fprintf(ctx->fp, "BCMODE_FF\n};\n\n"); - } else if (ctx->mode == BUILD_recdef) { - char *p = (char *)obuf; - fprintf(ctx->fp, "\n};\n\n"); - fprintf(ctx->fp, "static const RecordFunc recff_func[] = {\n" - "recff_nyi,\n" - "recff_c"); - while (*p) { - fprintf(ctx->fp, ",\nrecff_%s", p); - p += strlen(p)+1; - } - fprintf(ctx->fp, "\n};\n\n"); - } -} - diff --git a/lib/LuaJIT/src/host/buildvm_libbc.h b/lib/LuaJIT/src/host/buildvm_libbc.h deleted file mode 100644 index b2600bd..0000000 --- a/lib/LuaJIT/src/host/buildvm_libbc.h +++ /dev/null @@ -1,56 +0,0 @@ -/* This is a generated file. DO NOT EDIT! */ - -static const int libbc_endian = 0; - -static const uint8_t libbc_code[] = { -#if LJ_FR2 -0,1,2,0,0,1,2,24,1,0,0,76,1,2,0,241,135,158,166,3,220,203,178,130,4,0,1,2,0, -0,1,2,24,1,0,0,76,1,2,0,243,244,148,165,20,198,190,199,252,3,0,1,2,0,0,0,3, -16,0,5,0,21,1,0,0,76,1,2,0,0,2,10,0,0,0,15,16,0,12,0,16,1,9,0,41,2,1,0,21,3, -0,0,41,4,1,0,77,2,8,128,18,6,1,0,18,8,5,0,59,9,5,0,66,6,3,2,10,6,0,0,88,7,1, -128,76,6,2,0,79,2,248,127,75,0,1,0,0,2,11,0,0,0,16,16,0,12,0,16,1,9,0,43,2, -0,0,18,3,0,0,41,4,0,0,88,5,7,128,18,7,1,0,18,9,5,0,18,10,6,0,66,7,3,2,10,7, -0,0,88,8,1,128,76,7,2,0,70,5,3,3,82,5,247,127,75,0,1,0,0,1,2,0,0,0,3,16,0,12, -0,21,1,0,0,76,1,2,0,0,2,10,0,0,2,30,16,0,12,0,21,2,0,0,11,1,0,0,88,3,7,128, -8,2,0,0,88,3,23,128,59,3,2,0,43,4,0,0,64,4,2,0,76,3,2,0,88,3,18,128,16,1,14, -0,41,3,1,0,3,3,1,0,88,3,14,128,3,1,2,0,88,3,12,128,59,3,1,0,22,4,1,1,18,5,2, -0,41,6,1,0,77,4,4,128,23,8,1,7,59,9,7,0,64,9,8,0,79,4,252,127,43,4,0,0,64,4, -2,0,76,3,2,0,75,0,1,0,0,2,0,5,12,0,0,0,35,16,0,12,0,16,1,14,0,16,2,14,0,16, -3,14,0,11,4,0,0,88,5,1,128,18,4,0,0,16,4,12,0,3,1,2,0,88,5,24,128,33,5,1,3, -0,2,3,0,88,6,4,128,2,3,1,0,88,6,2,128,4,4,0,0,88,6,9,128,18,6,1,0,18,7,2,0, -41,8,1,0,77,6,4,128,32,10,5,9,59,11,9,0,64,11,10,4,79,6,252,127,88,6,8,128, -18,6,2,0,18,7,1,0,41,8,255,255,77,6,4,128,32,10,5,9,59,11,9,0,64,11,10,4,79, -6,252,127,76,4,2,0,0 -#else -0,1,2,0,0,1,2,24,1,0,0,76,1,2,0,241,135,158,166,3,220,203,178,130,4,0,1,2,0, -0,1,2,24,1,0,0,76,1,2,0,243,244,148,165,20,198,190,199,252,3,0,1,2,0,0,0,3, -16,0,5,0,21,1,0,0,76,1,2,0,0,2,9,0,0,0,15,16,0,12,0,16,1,9,0,41,2,1,0,21,3, -0,0,41,4,1,0,77,2,8,128,18,6,1,0,18,7,5,0,59,8,5,0,66,6,3,2,10,6,0,0,88,7,1, -128,76,6,2,0,79,2,248,127,75,0,1,0,0,2,10,0,0,0,16,16,0,12,0,16,1,9,0,43,2, -0,0,18,3,0,0,41,4,0,0,88,5,7,128,18,7,1,0,18,8,5,0,18,9,6,0,66,7,3,2,10,7,0, -0,88,8,1,128,76,7,2,0,70,5,3,3,82,5,247,127,75,0,1,0,0,1,2,0,0,0,3,16,0,12, -0,21,1,0,0,76,1,2,0,0,2,10,0,0,2,30,16,0,12,0,21,2,0,0,11,1,0,0,88,3,7,128, -8,2,0,0,88,3,23,128,59,3,2,0,43,4,0,0,64,4,2,0,76,3,2,0,88,3,18,128,16,1,14, -0,41,3,1,0,3,3,1,0,88,3,14,128,3,1,2,0,88,3,12,128,59,3,1,0,22,4,1,1,18,5,2, -0,41,6,1,0,77,4,4,128,23,8,1,7,59,9,7,0,64,9,8,0,79,4,252,127,43,4,0,0,64,4, -2,0,76,3,2,0,75,0,1,0,0,2,0,5,12,0,0,0,35,16,0,12,0,16,1,14,0,16,2,14,0,16, -3,14,0,11,4,0,0,88,5,1,128,18,4,0,0,16,4,12,0,3,1,2,0,88,5,24,128,33,5,1,3, -0,2,3,0,88,6,4,128,2,3,1,0,88,6,2,128,4,4,0,0,88,6,9,128,18,6,1,0,18,7,2,0, -41,8,1,0,77,6,4,128,32,10,5,9,59,11,9,0,64,11,10,4,79,6,252,127,88,6,8,128, -18,6,2,0,18,7,1,0,41,8,255,255,77,6,4,128,32,10,5,9,59,11,9,0,64,11,10,4,79, -6,252,127,76,4,2,0,0 -#endif -}; - -static const struct { const char *name; int ofs; } libbc_map[] = { -{"math_deg",0}, -{"math_rad",25}, -{"string_len",50}, -{"table_foreachi",69}, -{"table_foreach",136}, -{"table_getn",207}, -{"table_remove",226}, -{"table_move",355}, -{NULL,502} -}; - diff --git a/lib/LuaJIT/src/host/buildvm_peobj.c b/lib/LuaJIT/src/host/buildvm_peobj.c deleted file mode 100644 index 2eb2bb7..0000000 --- a/lib/LuaJIT/src/host/buildvm_peobj.c +++ /dev/null @@ -1,392 +0,0 @@ -/* -** LuaJIT VM builder: PE object emitter. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Only used for building on Windows, since we cannot assume the presence -** of a suitable assembler. The host and target byte order must match. -*/ - -#include "buildvm.h" -#include "lj_bc.h" - -#if LJ_TARGET_X86ORX64 || LJ_TARGET_PPC - -/* Context for PE object emitter. */ -static char *strtab; -static size_t strtabofs; - -/* -- PE object definitions ----------------------------------------------- */ - -/* PE header. */ -typedef struct PEheader { - uint16_t arch; - uint16_t nsects; - uint32_t time; - uint32_t symtabofs; - uint32_t nsyms; - uint16_t opthdrsz; - uint16_t flags; -} PEheader; - -/* PE section. */ -typedef struct PEsection { - char name[8]; - uint32_t vsize; - uint32_t vaddr; - uint32_t size; - uint32_t ofs; - uint32_t relocofs; - uint32_t lineofs; - uint16_t nreloc; - uint16_t nline; - uint32_t flags; -} PEsection; - -/* PE relocation. */ -typedef struct PEreloc { - uint32_t vaddr; - uint32_t symidx; - uint16_t type; -} PEreloc; - -/* Cannot use sizeof, because it pads up to the max. alignment. */ -#define PEOBJ_RELOC_SIZE (4+4+2) - -/* PE symbol table entry. */ -typedef struct PEsym { - union { - char name[8]; - uint32_t nameref[2]; - } n; - uint32_t value; - int16_t sect; - uint16_t type; - uint8_t scl; - uint8_t naux; -} PEsym; - -/* PE symbol table auxiliary entry for a section. */ -typedef struct PEsymaux { - uint32_t size; - uint16_t nreloc; - uint16_t nline; - uint32_t cksum; - uint16_t assoc; - uint8_t comdatsel; - uint8_t unused[3]; -} PEsymaux; - -/* Cannot use sizeof, because it pads up to the max. alignment. */ -#define PEOBJ_SYM_SIZE (8+4+2+2+1+1) - -/* PE object CPU specific defines. */ -#if LJ_TARGET_X86 -#define PEOBJ_ARCH_TARGET 0x014c -#define PEOBJ_RELOC_REL32 0x14 /* MS: REL32, GNU: DISP32. */ -#define PEOBJ_RELOC_DIR32 0x06 -#define PEOBJ_RELOC_OFS 0 -#define PEOBJ_TEXT_FLAGS 0x60500020 /* 60=r+x, 50=align16, 20=code. */ -#elif LJ_TARGET_X64 -#define PEOBJ_ARCH_TARGET 0x8664 -#define PEOBJ_RELOC_REL32 0x04 /* MS: REL32, GNU: DISP32. */ -#define PEOBJ_RELOC_DIR32 0x02 -#define PEOBJ_RELOC_ADDR32NB 0x03 -#define PEOBJ_RELOC_OFS 0 -#define PEOBJ_TEXT_FLAGS 0x60500020 /* 60=r+x, 50=align16, 20=code. */ -#elif LJ_TARGET_PPC -#define PEOBJ_ARCH_TARGET 0x01f2 -#define PEOBJ_RELOC_REL32 0x06 -#define PEOBJ_RELOC_DIR32 0x02 -#define PEOBJ_RELOC_OFS (-4) -#define PEOBJ_TEXT_FLAGS 0x60400020 /* 60=r+x, 40=align8, 20=code. */ -#endif - -/* Section numbers (0-based). */ -enum { - PEOBJ_SECT_ABS = -2, - PEOBJ_SECT_UNDEF = -1, - PEOBJ_SECT_TEXT, -#if LJ_TARGET_X64 - PEOBJ_SECT_PDATA, - PEOBJ_SECT_XDATA, -#elif LJ_TARGET_X86 - PEOBJ_SECT_SXDATA, -#endif - PEOBJ_SECT_RDATA_Z, - PEOBJ_NSECTIONS -}; - -/* Symbol types. */ -#define PEOBJ_TYPE_NULL 0 -#define PEOBJ_TYPE_FUNC 0x20 - -/* Symbol storage class. */ -#define PEOBJ_SCL_EXTERN 2 -#define PEOBJ_SCL_STATIC 3 - -/* -- PE object emitter --------------------------------------------------- */ - -/* Emit PE object symbol. */ -static void emit_peobj_sym(BuildCtx *ctx, const char *name, uint32_t value, - int sect, int type, int scl) -{ - PEsym sym; - size_t len = strlen(name); - if (!strtab) { /* Pass 1: only calculate string table length. */ - if (len > 8) strtabofs += len+1; - return; - } - if (len <= 8) { - memcpy(sym.n.name, name, len); - memset(sym.n.name+len, 0, 8-len); - } else { - sym.n.nameref[0] = 0; - sym.n.nameref[1] = (uint32_t)strtabofs; - memcpy(strtab + strtabofs, name, len); - strtab[strtabofs+len] = 0; - strtabofs += len+1; - } - sym.value = value; - sym.sect = (int16_t)(sect+1); /* 1-based section number. */ - sym.type = (uint16_t)type; - sym.scl = (uint8_t)scl; - sym.naux = 0; - owrite(ctx, &sym, PEOBJ_SYM_SIZE); -} - -/* Emit PE object section symbol. */ -static void emit_peobj_sym_sect(BuildCtx *ctx, PEsection *pesect, int sect) -{ - PEsym sym; - PEsymaux aux; - if (!strtab) return; /* Pass 1: no output. */ - memcpy(sym.n.name, pesect[sect].name, 8); - sym.value = 0; - sym.sect = (int16_t)(sect+1); /* 1-based section number. */ - sym.type = PEOBJ_TYPE_NULL; - sym.scl = PEOBJ_SCL_STATIC; - sym.naux = 1; - owrite(ctx, &sym, PEOBJ_SYM_SIZE); - memset(&aux, 0, sizeof(PEsymaux)); - aux.size = pesect[sect].size; - aux.nreloc = pesect[sect].nreloc; - owrite(ctx, &aux, PEOBJ_SYM_SIZE); -} - -/* Emit Windows PE object file. */ -void emit_peobj(BuildCtx *ctx) -{ - PEheader pehdr; - PEsection pesect[PEOBJ_NSECTIONS]; - uint32_t sofs; - int i, nrsym; - union { uint8_t b; uint32_t u; } host_endian; - - sofs = sizeof(PEheader) + PEOBJ_NSECTIONS*sizeof(PEsection); - - /* Fill in PE sections. */ - memset(&pesect, 0, PEOBJ_NSECTIONS*sizeof(PEsection)); - memcpy(pesect[PEOBJ_SECT_TEXT].name, ".text", sizeof(".text")-1); - pesect[PEOBJ_SECT_TEXT].ofs = sofs; - sofs += (pesect[PEOBJ_SECT_TEXT].size = (uint32_t)ctx->codesz); - pesect[PEOBJ_SECT_TEXT].relocofs = sofs; - sofs += (pesect[PEOBJ_SECT_TEXT].nreloc = (uint16_t)ctx->nreloc) * PEOBJ_RELOC_SIZE; - /* Flags: 60 = read+execute, 50 = align16, 20 = code. */ - pesect[PEOBJ_SECT_TEXT].flags = PEOBJ_TEXT_FLAGS; - -#if LJ_TARGET_X64 - memcpy(pesect[PEOBJ_SECT_PDATA].name, ".pdata", sizeof(".pdata")-1); - pesect[PEOBJ_SECT_PDATA].ofs = sofs; - sofs += (pesect[PEOBJ_SECT_PDATA].size = 6*4); - pesect[PEOBJ_SECT_PDATA].relocofs = sofs; - sofs += (pesect[PEOBJ_SECT_PDATA].nreloc = 6) * PEOBJ_RELOC_SIZE; - /* Flags: 40 = read, 30 = align4, 40 = initialized data. */ - pesect[PEOBJ_SECT_PDATA].flags = 0x40300040; - - memcpy(pesect[PEOBJ_SECT_XDATA].name, ".xdata", sizeof(".xdata")-1); - pesect[PEOBJ_SECT_XDATA].ofs = sofs; - sofs += (pesect[PEOBJ_SECT_XDATA].size = 8*2+4+6*2); /* See below. */ - pesect[PEOBJ_SECT_XDATA].relocofs = sofs; - sofs += (pesect[PEOBJ_SECT_XDATA].nreloc = 1) * PEOBJ_RELOC_SIZE; - /* Flags: 40 = read, 30 = align4, 40 = initialized data. */ - pesect[PEOBJ_SECT_XDATA].flags = 0x40300040; -#elif LJ_TARGET_X86 - memcpy(pesect[PEOBJ_SECT_SXDATA].name, ".sxdata", sizeof(".sxdata")-1); - pesect[PEOBJ_SECT_SXDATA].ofs = sofs; - sofs += (pesect[PEOBJ_SECT_SXDATA].size = 4); - pesect[PEOBJ_SECT_SXDATA].relocofs = sofs; - /* Flags: 40 = read, 30 = align4, 02 = lnk_info, 40 = initialized data. */ - pesect[PEOBJ_SECT_SXDATA].flags = 0x40300240; -#endif - - memcpy(pesect[PEOBJ_SECT_RDATA_Z].name, ".rdata$Z", sizeof(".rdata$Z")-1); - pesect[PEOBJ_SECT_RDATA_Z].ofs = sofs; - sofs += (pesect[PEOBJ_SECT_RDATA_Z].size = (uint32_t)strlen(ctx->dasm_ident)+1); - /* Flags: 40 = read, 30 = align4, 40 = initialized data. */ - pesect[PEOBJ_SECT_RDATA_Z].flags = 0x40300040; - - /* Fill in PE header. */ - pehdr.arch = PEOBJ_ARCH_TARGET; - pehdr.nsects = PEOBJ_NSECTIONS; - pehdr.time = 0; /* Timestamp is optional. */ - pehdr.symtabofs = sofs; - pehdr.opthdrsz = 0; - pehdr.flags = 0; - - /* Compute the size of the symbol table: - ** @feat.00 + nsections*2 - ** + asm_start + nsym - ** + nrsym - */ - nrsym = ctx->nrelocsym; - pehdr.nsyms = 1+PEOBJ_NSECTIONS*2 + 1+ctx->nsym + nrsym; -#if LJ_TARGET_X64 - pehdr.nsyms += 1; /* Symbol for lj_err_unwind_win. */ -#endif - - /* Write PE object header and all sections. */ - owrite(ctx, &pehdr, sizeof(PEheader)); - owrite(ctx, &pesect, sizeof(PEsection)*PEOBJ_NSECTIONS); - - /* Write .text section. */ - host_endian.u = 1; - if (host_endian.b != LJ_ENDIAN_SELECT(1, 0)) { -#if LJ_TARGET_PPC - uint32_t *p = (uint32_t *)ctx->code; - int n = (int)(ctx->codesz >> 2); - for (i = 0; i < n; i++, p++) - *p = lj_bswap(*p); /* Byteswap .text section. */ -#else - fprintf(stderr, "Error: different byte order for host and target\n"); - exit(1); -#endif - } - owrite(ctx, ctx->code, ctx->codesz); - for (i = 0; i < ctx->nreloc; i++) { - PEreloc reloc; - reloc.vaddr = (uint32_t)ctx->reloc[i].ofs + PEOBJ_RELOC_OFS; - reloc.symidx = 1+2+ctx->reloc[i].sym; /* Reloc syms are after .text sym. */ - reloc.type = ctx->reloc[i].type ? PEOBJ_RELOC_REL32 : PEOBJ_RELOC_DIR32; - owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); - } - -#if LJ_TARGET_X64 - { /* Write .pdata section. */ - uint32_t fcofs = (uint32_t)ctx->sym[ctx->nsym-1].ofs; - uint32_t pdata[3]; /* Start of .text, end of .text and .xdata. */ - PEreloc reloc; - pdata[0] = 0; pdata[1] = fcofs; pdata[2] = 0; - owrite(ctx, &pdata, sizeof(pdata)); - pdata[0] = fcofs; pdata[1] = (uint32_t)ctx->codesz; pdata[2] = 20; - owrite(ctx, &pdata, sizeof(pdata)); - reloc.vaddr = 0; reloc.symidx = 1+2+nrsym+2+2+1; - reloc.type = PEOBJ_RELOC_ADDR32NB; - owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); - reloc.vaddr = 4; reloc.symidx = 1+2+nrsym+2+2+1; - reloc.type = PEOBJ_RELOC_ADDR32NB; - owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); - reloc.vaddr = 8; reloc.symidx = 1+2+nrsym+2; - reloc.type = PEOBJ_RELOC_ADDR32NB; - owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); - reloc.vaddr = 12; reloc.symidx = 1+2+nrsym+2+2+1; - reloc.type = PEOBJ_RELOC_ADDR32NB; - owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); - reloc.vaddr = 16; reloc.symidx = 1+2+nrsym+2+2+1; - reloc.type = PEOBJ_RELOC_ADDR32NB; - owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); - reloc.vaddr = 20; reloc.symidx = 1+2+nrsym+2; - reloc.type = PEOBJ_RELOC_ADDR32NB; - owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); - } - { /* Write .xdata section. */ - uint16_t xdata[8+2+6]; - PEreloc reloc; - xdata[0] = 0x01|0x08|0x10; /* Ver. 1, uhandler/ehandler, prolog size 0. */ - xdata[1] = 0x0005; /* Number of unwind codes, no frame pointer. */ - xdata[2] = 0x4200; /* Stack offset 4*8+8 = aword*5. */ - xdata[3] = 0x3000; /* Push rbx. */ - xdata[4] = 0x6000; /* Push rsi. */ - xdata[5] = 0x7000; /* Push rdi. */ - xdata[6] = 0x5000; /* Push rbp. */ - xdata[7] = 0; /* Alignment. */ - xdata[8] = xdata[9] = 0; /* Relocated address of exception handler. */ - xdata[10] = 0x01; /* Ver. 1, no handler, prolog size 0. */ - xdata[11] = 0x1504; /* Number of unwind codes, fp = rbp, fpofs = 16. */ - xdata[12] = 0x0300; /* set_fpreg. */ - xdata[13] = 0x0200; /* stack offset 0*8+8 = aword*1. */ - xdata[14] = 0x3000; /* Push rbx. */ - xdata[15] = 0x5000; /* Push rbp. */ - owrite(ctx, &xdata, sizeof(xdata)); - reloc.vaddr = 2*8; reloc.symidx = 1+2+nrsym+2+2; - reloc.type = PEOBJ_RELOC_ADDR32NB; - owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); - } -#elif LJ_TARGET_X86 - /* Write .sxdata section. */ - for (i = 0; i < nrsym; i++) { - if (!strcmp(ctx->relocsym[i], "_lj_err_unwind_win")) { - uint32_t symidx = 1+2+i; - owrite(ctx, &symidx, 4); - break; - } - } - if (i == nrsym) { - fprintf(stderr, "Error: extern lj_err_unwind_win not used\n"); - exit(1); - } -#endif - - /* Write .rdata$Z section. */ - owrite(ctx, ctx->dasm_ident, strlen(ctx->dasm_ident)+1); - - /* Write symbol table. */ - strtab = NULL; /* 1st pass: collect string sizes. */ - for (;;) { - strtabofs = 4; - /* Mark as SafeSEH compliant. */ - emit_peobj_sym(ctx, "@feat.00", 1, - PEOBJ_SECT_ABS, PEOBJ_TYPE_NULL, PEOBJ_SCL_STATIC); - - emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_TEXT); - for (i = 0; i < nrsym; i++) - emit_peobj_sym(ctx, ctx->relocsym[i], 0, - PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN); - -#if LJ_TARGET_X64 - emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_PDATA); - emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_XDATA); - emit_peobj_sym(ctx, "lj_err_unwind_win", 0, - PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN); -#elif LJ_TARGET_X86 - emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_SXDATA); -#endif - - emit_peobj_sym(ctx, ctx->beginsym, 0, - PEOBJ_SECT_TEXT, PEOBJ_TYPE_NULL, PEOBJ_SCL_EXTERN); - for (i = 0; i < ctx->nsym; i++) - emit_peobj_sym(ctx, ctx->sym[i].name, (uint32_t)ctx->sym[i].ofs, - PEOBJ_SECT_TEXT, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN); - - emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_RDATA_Z); - - if (strtab) - break; - /* 2nd pass: alloc strtab, write syms and copy strings. */ - strtab = (char *)malloc(strtabofs); - *(uint32_t *)strtab = (uint32_t)strtabofs; - } - - /* Write string table. */ - owrite(ctx, strtab, strtabofs); -} - -#else - -void emit_peobj(BuildCtx *ctx) -{ - UNUSED(ctx); - fprintf(stderr, "Error: no PE object support for this target\n"); - exit(1); -} - -#endif diff --git a/lib/LuaJIT/src/host/genlibbc.lua b/lib/LuaJIT/src/host/genlibbc.lua deleted file mode 100644 index 6f5a05c..0000000 --- a/lib/LuaJIT/src/host/genlibbc.lua +++ /dev/null @@ -1,197 +0,0 @@ ----------------------------------------------------------------------------- --- Lua script to dump the bytecode of the library functions written in Lua. --- The resulting 'buildvm_libbc.h' is used for the build process of LuaJIT. ----------------------------------------------------------------------------- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- Released under the MIT license. See Copyright Notice in luajit.h ----------------------------------------------------------------------------- - -local ffi = require("ffi") -local bit = require("bit") -local vmdef = require("jit.vmdef") -local bcnames = vmdef.bcnames - -local format = string.format - -local isbe = (string.byte(string.dump(function() end), 5) % 2 == 1) - -local function usage(arg) - io.stderr:write("Usage: ", arg and arg[0] or "genlibbc", - " [-o buildvm_libbc.h] lib_*.c\n") - os.exit(1) -end - -local function parse_arg(arg) - local outfile = "-" - if not (arg and arg[1]) then - usage(arg) - end - if arg[1] == "-o" then - outfile = arg[2] - if not outfile then usage(arg) end - table.remove(arg, 1) - table.remove(arg, 1) - end - return outfile -end - -local function read_files(names) - local src = "" - for _,name in ipairs(names) do - local fp = assert(io.open(name)) - src = src .. fp:read("*a") - fp:close() - end - return src -end - -local function transform_lua(code) - local fixup = {} - local n = -30000 - code = string.gsub(code, "CHECK_(%w*)%((.-)%)", function(tp, var) - n = n + 1 - fixup[n] = { "CHECK", tp } - return format("%s=%d", var, n) - end) - code = string.gsub(code, "PAIRS%((.-)%)", function(var) - fixup.PAIRS = true - return format("nil, %s, 0", var) - end) - return "return "..code, fixup -end - -local function read_uleb128(p) - local v = p[0]; p = p + 1 - if v >= 128 then - local sh = 7; v = v - 128 - repeat - local r = p[0] - v = v + bit.lshift(bit.band(r, 127), sh) - sh = sh + 7 - p = p + 1 - until r < 128 - end - return p, v -end - --- ORDER LJ_T -local name2itype = { - str = 5, func = 9, tab = 12, int = 14, num = 15 -} - -local BC = {} -for i=0,#bcnames/6-1 do - BC[string.gsub(string.sub(bcnames, i*6+1, i*6+6), " ", "")] = i -end -local xop, xra = isbe and 3 or 0, isbe and 2 or 1 -local xrc, xrb = isbe and 1 or 2, isbe and 0 or 3 - -local function fixup_dump(dump, fixup) - local buf = ffi.new("uint8_t[?]", #dump+1, dump) - local p = buf+5 - local n, sizebc - p, n = read_uleb128(p) - local start = p - p = p + 4 - p = read_uleb128(p) - p = read_uleb128(p) - p, sizebc = read_uleb128(p) - local rawtab = {} - for i=0,sizebc-1 do - local op = p[xop] - if op == BC.KSHORT then - local rd = p[xrc] + 256*p[xrb] - rd = bit.arshift(bit.lshift(rd, 16), 16) - local f = fixup[rd] - if f then - if f[1] == "CHECK" then - local tp = f[2] - if tp == "tab" then rawtab[p[xra]] = true end - p[xop] = tp == "num" and BC.ISNUM or BC.ISTYPE - p[xrb] = 0 - p[xrc] = name2itype[tp] - else - error("unhandled fixup type: "..f[1]) - end - end - elseif op == BC.TGETV then - if rawtab[p[xrb]] then - p[xop] = BC.TGETR - end - elseif op == BC.TSETV then - if rawtab[p[xrb]] then - p[xop] = BC.TSETR - end - elseif op == BC.ITERC then - if fixup.PAIRS then - p[xop] = BC.ITERN - end - end - p = p + 4 - end - return ffi.string(start, n) -end - -local function find_defs(src) - local defs = {} - for name, code in string.gmatch(src, "LJLIB_LUA%(([^)]*)%)%s*/%*(.-)%*/") do - local env = {} - local tcode, fixup = transform_lua(code) - local func = assert(load(tcode, "", nil, env))() - defs[name] = fixup_dump(string.dump(func, true), fixup) - defs[#defs+1] = name - end - return defs -end - -local function gen_header(defs) - local t = {} - local function w(x) t[#t+1] = x end - w("/* This is a generated file. DO NOT EDIT! */\n\n") - w("static const int libbc_endian = ") w(isbe and 1 or 0) w(";\n\n") - local s = "" - for _,name in ipairs(defs) do - s = s .. defs[name] - end - w("static const uint8_t libbc_code[] = {\n") - local n = 0 - for i=1,#s do - local x = string.byte(s, i) - w(x); w(",") - n = n + (x < 10 and 2 or (x < 100 and 3 or 4)) - if n >= 75 then n = 0; w("\n") end - end - w("0\n};\n\n") - w("static const struct { const char *name; int ofs; } libbc_map[] = {\n") - local m = 0 - for _,name in ipairs(defs) do - w('{"'); w(name); w('",'); w(m) w('},\n') - m = m + #defs[name] - end - w("{NULL,"); w(m); w("}\n};\n\n") - return table.concat(t) -end - -local function write_file(name, data) - if name == "-" then - assert(io.write(data)) - assert(io.flush()) - else - local fp = io.open(name) - if fp then - local old = fp:read("*a") - fp:close() - if data == old then return end - end - fp = assert(io.open(name, "w")) - assert(fp:write(data)) - assert(fp:close()) - end -end - -local outfile = parse_arg(arg) -local src = read_files(arg) -local defs = find_defs(src) -local hdr = gen_header(defs) -write_file(outfile, hdr) - diff --git a/lib/LuaJIT/src/host/genminilua.lua b/lib/LuaJIT/src/host/genminilua.lua deleted file mode 100644 index 50feff0..0000000 --- a/lib/LuaJIT/src/host/genminilua.lua +++ /dev/null @@ -1,429 +0,0 @@ ----------------------------------------------------------------------------- --- Lua script to generate a customized, minified version of Lua. --- The resulting 'minilua' is used for the build process of LuaJIT. ----------------------------------------------------------------------------- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- Released under the MIT license. See Copyright Notice in luajit.h ----------------------------------------------------------------------------- - -local sub, match, gsub = string.sub, string.match, string.gsub - -local LUA_VERSION = "5.1.5" -local LUA_SOURCE - -local function usage() - io.stderr:write("Usage: ", arg and arg[0] or "genminilua", - " lua-", LUA_VERSION, "-source-dir\n") - os.exit(1) -end - -local function find_sources() - LUA_SOURCE = arg and arg[1] - if not LUA_SOURCE then usage() end - if sub(LUA_SOURCE, -1) ~= "/" then LUA_SOURCE = LUA_SOURCE.."/" end - local fp = io.open(LUA_SOURCE .. "lua.h") - if not fp then - LUA_SOURCE = LUA_SOURCE.."src/" - fp = io.open(LUA_SOURCE .. "lua.h") - if not fp then usage() end - end - local all = fp:read("*a") - fp:close() - if not match(all, 'LUA_RELEASE%s*"Lua '..LUA_VERSION..'"') then - io.stderr:write("Error: version mismatch\n") - usage() - end -end - -local LUA_FILES = { -"lmem.c", "lobject.c", "ltm.c", "lfunc.c", "ldo.c", "lstring.c", "ltable.c", -"lgc.c", "lstate.c", "ldebug.c", "lzio.c", "lopcodes.c", -"llex.c", "lcode.c", "lparser.c", "lvm.c", "lapi.c", "lauxlib.c", -"lbaselib.c", "ltablib.c", "liolib.c", "loslib.c", "lstrlib.c", "linit.c", -} - -local REMOVE_LIB = {} -gsub([[ -collectgarbage dofile gcinfo getfenv getmetatable load print rawequal rawset -select tostring xpcall -foreach foreachi getn maxn setn -popen tmpfile seek setvbuf __tostring -clock date difftime execute getenv rename setlocale time tmpname -dump gfind len reverse -LUA_LOADLIBNAME LUA_MATHLIBNAME LUA_DBLIBNAME -]], "%S+", function(name) - REMOVE_LIB[name] = true -end) - -local REMOVE_EXTINC = { [""] = true, [""] = true, } - -local CUSTOM_MAIN = [[ -typedef unsigned int UB; -static UB barg(lua_State *L,int idx){ -union{lua_Number n;U64 b;}bn; -bn.n=lua_tonumber(L,idx)+6755399441055744.0; -if (bn.n==0.0&&!lua_isnumber(L,idx))luaL_typerror(L,idx,"number"); -return(UB)bn.b; -} -#define BRET(b) lua_pushnumber(L,(lua_Number)(int)(b));return 1; -static int tobit(lua_State *L){ -BRET(barg(L,1))} -static int bnot(lua_State *L){ -BRET(~barg(L,1))} -static int band(lua_State *L){ -int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b&=barg(L,i);BRET(b)} -static int bor(lua_State *L){ -int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b|=barg(L,i);BRET(b)} -static int bxor(lua_State *L){ -int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b^=barg(L,i);BRET(b)} -static int lshift(lua_State *L){ -UB b=barg(L,1),n=barg(L,2)&31;BRET(b<>n)} -static int arshift(lua_State *L){ -UB b=barg(L,1),n=barg(L,2)&31;BRET((int)b>>n)} -static int rol(lua_State *L){ -UB b=barg(L,1),n=barg(L,2)&31;BRET((b<>(32-n)))} -static int ror(lua_State *L){ -UB b=barg(L,1),n=barg(L,2)&31;BRET((b>>n)|(b<<(32-n)))} -static int bswap(lua_State *L){ -UB b=barg(L,1);b=(b>>24)|((b>>8)&0xff00)|((b&0xff00)<<8)|(b<<24);BRET(b)} -static int tohex(lua_State *L){ -UB b=barg(L,1); -int n=lua_isnone(L,2)?8:(int)barg(L,2); -const char *hexdigits="0123456789abcdef"; -char buf[8]; -int i; -if(n<0){n=-n;hexdigits="0123456789ABCDEF";} -if(n>8)n=8; -for(i=(int)n;--i>=0;){buf[i]=hexdigits[b&15];b>>=4;} -lua_pushlstring(L,buf,(size_t)n); -return 1; -} -static const struct luaL_Reg bitlib[] = { -{"tobit",tobit}, -{"bnot",bnot}, -{"band",band}, -{"bor",bor}, -{"bxor",bxor}, -{"lshift",lshift}, -{"rshift",rshift}, -{"arshift",arshift}, -{"rol",rol}, -{"ror",ror}, -{"bswap",bswap}, -{"tohex",tohex}, -{NULL,NULL} -}; -int main(int argc, char **argv){ - lua_State *L = luaL_newstate(); - int i; - luaL_openlibs(L); - luaL_register(L, "bit", bitlib); - if (argc < 2) return sizeof(void *); - lua_createtable(L, 0, 1); - lua_pushstring(L, argv[1]); - lua_rawseti(L, -2, 0); - lua_setglobal(L, "arg"); - if (luaL_loadfile(L, argv[1])) - goto err; - for (i = 2; i < argc; i++) - lua_pushstring(L, argv[i]); - if (lua_pcall(L, argc - 2, 0, 0)) { - err: - fprintf(stderr, "Error: %s\n", lua_tostring(L, -1)); - return 1; - } - lua_close(L); - return 0; -} -]] - -local function read_sources() - local t = {} - for i, name in ipairs(LUA_FILES) do - local fp = assert(io.open(LUA_SOURCE..name, "r")) - t[i] = fp:read("*a") - assert(fp:close()) - end - t[#t+1] = CUSTOM_MAIN - return table.concat(t) -end - -local includes = {} - -local function merge_includes(src) - return gsub(src, '#include%s*"([^"]*)"%s*\n', function(name) - if includes[name] then return "" end - includes[name] = true - local fp = assert(io.open(LUA_SOURCE..name, "r")) - local inc = fp:read("*a") - assert(fp:close()) - inc = gsub(inc, "#ifndef%s+%w+_h\n#define%s+%w+_h\n", "") - inc = gsub(inc, "#endif%s*$", "") - return merge_includes(inc) - end) -end - -local function get_license(src) - return match(src, "/%*+\n%* Copyright %(.-%*/\n") -end - -local function fold_lines(src) - return gsub(src, "\\\n", " ") -end - -local strings = {} - -local function save_str(str) - local n = #strings+1 - strings[n] = str - return "\1"..n.."\2" -end - -local function save_strings(src) - src = gsub(src, '"[^"\n]*"', save_str) - return gsub(src, "'[^'\n]*'", save_str) -end - -local function restore_strings(src) - return gsub(src, "\1(%d+)\2", function(numstr) - return strings[tonumber(numstr)] - end) -end - -local function def_istrue(def) - return def == "INT_MAX > 2147483640L" or - def == "LUAI_BITSINT >= 32" or - def == "SIZE_Bx < LUAI_BITSINT-1" or - def == "cast" or - def == "defined(LUA_CORE)" or - def == "MINSTRTABSIZE" or - def == "LUA_MINBUFFER" or - def == "HARDSTACKTESTS" or - def == "UNUSED" -end - -local head, defs = {[[ -#ifdef _MSC_VER -typedef unsigned __int64 U64; -#else -typedef unsigned long long U64; -#endif -int _CRT_glob = 0; -]]}, {} - -local function preprocess(src) - local t = { match(src, "^(.-)#") } - local lvl, on, oldon = 0, true, {} - for pp, def, txt in string.gmatch(src, "#(%w+) *([^\n]*)\n([^#]*)") do - if pp == "if" or pp == "ifdef" or pp == "ifndef" then - lvl = lvl + 1 - oldon[lvl] = on - on = def_istrue(def) - elseif pp == "else" then - if oldon[lvl] then - if on == false then on = true else on = false end - end - elseif pp == "elif" then - if oldon[lvl] then - on = def_istrue(def) - end - elseif pp == "endif" then - on = oldon[lvl] - lvl = lvl - 1 - elseif on then - if pp == "include" then - if not head[def] and not REMOVE_EXTINC[def] then - head[def] = true - head[#head+1] = "#include "..def.."\n" - end - elseif pp == "define" then - local k, sp, v = match(def, "([%w_]+)(%s*)(.*)") - if k and not (sp == "" and sub(v, 1, 1) == "(") then - defs[k] = gsub(v, "%a[%w_]*", function(tok) - return defs[tok] or tok - end) - else - t[#t+1] = "#define "..def.."\n" - end - elseif pp ~= "undef" then - error("unexpected directive: "..pp.." "..def) - end - end - if on then t[#t+1] = txt end - end - return gsub(table.concat(t), "%a[%w_]*", function(tok) - return defs[tok] or tok - end) -end - -local function merge_header(src, license) - local hdr = string.format([[ -/* This is a heavily customized and minimized copy of Lua %s. */ -/* It's only used to build LuaJIT. It does NOT have all standard functions! */ -]], LUA_VERSION) - return hdr..license..table.concat(head)..src -end - -local function strip_unused1(src) - return gsub(src, '( {"?([%w_]+)"?,%s+%a[%w_]*},\n)', function(line, func) - return REMOVE_LIB[func] and "" or line - end) -end - -local function strip_unused2(src) - return gsub(src, "Symbolic Execution.-}=", "") -end - -local function strip_unused3(src) - src = gsub(src, "extern", "static") - src = gsub(src, "\nstatic([^\n]-)%(([^)]*)%)%(", "\nstatic%1 %2(") - src = gsub(src, "#define lua_assert[^\n]*\n", "") - src = gsub(src, "lua_assert%b();?", "") - src = gsub(src, "default:\n}", "default:;\n}") - src = gsub(src, "lua_lock%b();", "") - src = gsub(src, "lua_unlock%b();", "") - src = gsub(src, "luai_threadyield%b();", "") - src = gsub(src, "luai_userstateopen%b();", "{}") - src = gsub(src, "luai_userstate%w+%b();", "") - src = gsub(src, "%(%(c==.*luaY_parser%)", "luaY_parser") - src = gsub(src, "trydecpoint%(ls,seminfo%)", - "luaX_lexerror(ls,\"malformed number\",TK_NUMBER)") - src = gsub(src, "int c=luaZ_lookahead%b();", "") - src = gsub(src, "luaL_register%(L,[^,]*,co_funcs%);\nreturn 2;", - "return 1;") - src = gsub(src, "getfuncname%b():", "NULL:") - src = gsub(src, "getobjname%b():", "NULL:") - src = gsub(src, "if%([^\n]*hookmask[^\n]*%)\n[^\n]*\n", "") - src = gsub(src, "if%([^\n]*hookmask[^\n]*%)%b{}\n", "") - src = gsub(src, "if%([^\n]*hookmask[^\n]*&&\n[^\n]*%b{}\n", "") - src = gsub(src, "(twoto%b()%()", "%1(size_t)") - src = gsub(src, "i -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -typedef enum{ -TM_INDEX, -TM_NEWINDEX, -TM_GC, -TM_MODE, -TM_EQ, -TM_ADD, -TM_SUB, -TM_MUL, -TM_DIV, -TM_MOD, -TM_POW, -TM_UNM, -TM_LEN, -TM_LT, -TM_LE, -TM_CONCAT, -TM_CALL, -TM_N -}TMS; -enum OpMode{iABC,iABx,iAsBx}; -typedef enum{ -OP_MOVE, -OP_LOADK, -OP_LOADBOOL, -OP_LOADNIL, -OP_GETUPVAL, -OP_GETGLOBAL, -OP_GETTABLE, -OP_SETGLOBAL, -OP_SETUPVAL, -OP_SETTABLE, -OP_NEWTABLE, -OP_SELF, -OP_ADD, -OP_SUB, -OP_MUL, -OP_DIV, -OP_MOD, -OP_POW, -OP_UNM, -OP_NOT, -OP_LEN, -OP_CONCAT, -OP_JMP, -OP_EQ, -OP_LT, -OP_LE, -OP_TEST, -OP_TESTSET, -OP_CALL, -OP_TAILCALL, -OP_RETURN, -OP_FORLOOP, -OP_FORPREP, -OP_TFORLOOP, -OP_SETLIST, -OP_CLOSE, -OP_CLOSURE, -OP_VARARG -}OpCode; -enum OpArgMask{ -OpArgN, -OpArgU, -OpArgR, -OpArgK -}; -typedef enum{ -VVOID, -VNIL, -VTRUE, -VFALSE, -VK, -VKNUM, -VLOCAL, -VUPVAL, -VGLOBAL, -VINDEXED, -VJMP, -VRELOCABLE, -VNONRELOC, -VCALL, -VVARARG -}expkind; -enum RESERVED{ -TK_AND=257,TK_BREAK, -TK_DO,TK_ELSE,TK_ELSEIF,TK_END,TK_FALSE,TK_FOR,TK_FUNCTION, -TK_IF,TK_IN,TK_LOCAL,TK_NIL,TK_NOT,TK_OR,TK_REPEAT, -TK_RETURN,TK_THEN,TK_TRUE,TK_UNTIL,TK_WHILE, -TK_CONCAT,TK_DOTS,TK_EQ,TK_GE,TK_LE,TK_NE,TK_NUMBER, -TK_NAME,TK_STRING,TK_EOS -}; -typedef enum BinOpr{ -OPR_ADD,OPR_SUB,OPR_MUL,OPR_DIV,OPR_MOD,OPR_POW, -OPR_CONCAT, -OPR_NE,OPR_EQ, -OPR_LT,OPR_LE,OPR_GT,OPR_GE, -OPR_AND,OPR_OR, -OPR_NOBINOPR -}BinOpr; -typedef enum UnOpr{OPR_MINUS,OPR_NOT,OPR_LEN,OPR_NOUNOPR}UnOpr; -#define LUA_QL(x)"'"x"'" -#define luai_apicheck(L,o){(void)L;} -#define lua_number2str(s,n)sprintf((s),"%.14g",(n)) -#define lua_str2number(s,p)strtod((s),(p)) -#define luai_numadd(a,b)((a)+(b)) -#define luai_numsub(a,b)((a)-(b)) -#define luai_nummul(a,b)((a)*(b)) -#define luai_numdiv(a,b)((a)/(b)) -#define luai_nummod(a,b)((a)-floor((a)/(b))*(b)) -#define luai_numpow(a,b)(pow(a,b)) -#define luai_numunm(a)(-(a)) -#define luai_numeq(a,b)((a)==(b)) -#define luai_numlt(a,b)((a)<(b)) -#define luai_numle(a,b)((a)<=(b)) -#define luai_numisnan(a)(!luai_numeq((a),(a))) -#define lua_number2int(i,d)((i)=(int)(d)) -#define lua_number2integer(i,d)((i)=(lua_Integer)(d)) -#define LUAI_THROW(L,c)longjmp((c)->b,1) -#define LUAI_TRY(L,c,a)if(setjmp((c)->b)==0){a} -#define lua_pclose(L,file)((void)((void)L,file),0) -#define lua_upvalueindex(i)((-10002)-(i)) -typedef struct lua_State lua_State; -typedef int(*lua_CFunction)(lua_State*L); -typedef const char*(*lua_Reader)(lua_State*L,void*ud,size_t*sz); -typedef void*(*lua_Alloc)(void*ud,void*ptr,size_t osize,size_t nsize); -typedef double lua_Number; -typedef ptrdiff_t lua_Integer; -static void lua_settop(lua_State*L,int idx); -static int lua_type(lua_State*L,int idx); -static const char* lua_tolstring(lua_State*L,int idx,size_t*len); -static size_t lua_objlen(lua_State*L,int idx); -static void lua_pushlstring(lua_State*L,const char*s,size_t l); -static void lua_pushcclosure(lua_State*L,lua_CFunction fn,int n); -static void lua_createtable(lua_State*L,int narr,int nrec); -static void lua_setfield(lua_State*L,int idx,const char*k); -#define lua_pop(L,n)lua_settop(L,-(n)-1) -#define lua_newtable(L)lua_createtable(L,0,0) -#define lua_pushcfunction(L,f)lua_pushcclosure(L,(f),0) -#define lua_strlen(L,i)lua_objlen(L,(i)) -#define lua_isfunction(L,n)(lua_type(L,(n))==6) -#define lua_istable(L,n)(lua_type(L,(n))==5) -#define lua_isnil(L,n)(lua_type(L,(n))==0) -#define lua_isboolean(L,n)(lua_type(L,(n))==1) -#define lua_isnone(L,n)(lua_type(L,(n))==(-1)) -#define lua_isnoneornil(L,n)(lua_type(L,(n))<=0) -#define lua_pushliteral(L,s)lua_pushlstring(L,""s,(sizeof(s)/sizeof(char))-1) -#define lua_setglobal(L,s)lua_setfield(L,(-10002),(s)) -#define lua_tostring(L,i)lua_tolstring(L,(i),NULL) -typedef struct lua_Debug lua_Debug; -typedef void(*lua_Hook)(lua_State*L,lua_Debug*ar); -struct lua_Debug{ -int event; -const char*name; -const char*namewhat; -const char*what; -const char*source; -int currentline; -int nups; -int linedefined; -int lastlinedefined; -char short_src[60]; -int i_ci; -}; -typedef unsigned int lu_int32; -typedef size_t lu_mem; -typedef ptrdiff_t l_mem; -typedef unsigned char lu_byte; -#define IntPoint(p)((unsigned int)(lu_mem)(p)) -typedef union{double u;void*s;long l;}L_Umaxalign; -typedef double l_uacNumber; -#define check_exp(c,e)(e) -#define UNUSED(x)((void)(x)) -#define cast(t,exp)((t)(exp)) -#define cast_byte(i)cast(lu_byte,(i)) -#define cast_num(i)cast(lua_Number,(i)) -#define cast_int(i)cast(int,(i)) -typedef lu_int32 Instruction; -#define condhardstacktests(x)((void)0) -typedef union GCObject GCObject; -typedef struct GCheader{ -GCObject*next;lu_byte tt;lu_byte marked; -}GCheader; -typedef union{ -GCObject*gc; -void*p; -lua_Number n; -int b; -}Value; -typedef struct lua_TValue{ -Value value;int tt; -}TValue; -#define ttisnil(o)(ttype(o)==0) -#define ttisnumber(o)(ttype(o)==3) -#define ttisstring(o)(ttype(o)==4) -#define ttistable(o)(ttype(o)==5) -#define ttisfunction(o)(ttype(o)==6) -#define ttisboolean(o)(ttype(o)==1) -#define ttisuserdata(o)(ttype(o)==7) -#define ttisthread(o)(ttype(o)==8) -#define ttislightuserdata(o)(ttype(o)==2) -#define ttype(o)((o)->tt) -#define gcvalue(o)check_exp(iscollectable(o),(o)->value.gc) -#define pvalue(o)check_exp(ttislightuserdata(o),(o)->value.p) -#define nvalue(o)check_exp(ttisnumber(o),(o)->value.n) -#define rawtsvalue(o)check_exp(ttisstring(o),&(o)->value.gc->ts) -#define tsvalue(o)(&rawtsvalue(o)->tsv) -#define rawuvalue(o)check_exp(ttisuserdata(o),&(o)->value.gc->u) -#define uvalue(o)(&rawuvalue(o)->uv) -#define clvalue(o)check_exp(ttisfunction(o),&(o)->value.gc->cl) -#define hvalue(o)check_exp(ttistable(o),&(o)->value.gc->h) -#define bvalue(o)check_exp(ttisboolean(o),(o)->value.b) -#define thvalue(o)check_exp(ttisthread(o),&(o)->value.gc->th) -#define l_isfalse(o)(ttisnil(o)||(ttisboolean(o)&&bvalue(o)==0)) -#define checkconsistency(obj) -#define checkliveness(g,obj) -#define setnilvalue(obj)((obj)->tt=0) -#define setnvalue(obj,x){TValue*i_o=(obj);i_o->value.n=(x);i_o->tt=3;} -#define setbvalue(obj,x){TValue*i_o=(obj);i_o->value.b=(x);i_o->tt=1;} -#define setsvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=4;checkliveness(G(L),i_o);} -#define setuvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=7;checkliveness(G(L),i_o);} -#define setthvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=8;checkliveness(G(L),i_o);} -#define setclvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=6;checkliveness(G(L),i_o);} -#define sethvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=5;checkliveness(G(L),i_o);} -#define setptvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=(8+1);checkliveness(G(L),i_o);} -#define setobj(L,obj1,obj2){const TValue*o2=(obj2);TValue*o1=(obj1);o1->value=o2->value;o1->tt=o2->tt;checkliveness(G(L),o1);} -#define setttype(obj,tt)(ttype(obj)=(tt)) -#define iscollectable(o)(ttype(o)>=4) -typedef TValue*StkId; -typedef union TString{ -L_Umaxalign dummy; -struct{ -GCObject*next;lu_byte tt;lu_byte marked; -lu_byte reserved; -unsigned int hash; -size_t len; -}tsv; -}TString; -#define getstr(ts)cast(const char*,(ts)+1) -#define svalue(o)getstr(rawtsvalue(o)) -typedef union Udata{ -L_Umaxalign dummy; -struct{ -GCObject*next;lu_byte tt;lu_byte marked; -struct Table*metatable; -struct Table*env; -size_t len; -}uv; -}Udata; -typedef struct Proto{ -GCObject*next;lu_byte tt;lu_byte marked; -TValue*k; -Instruction*code; -struct Proto**p; -int*lineinfo; -struct LocVar*locvars; -TString**upvalues; -TString*source; -int sizeupvalues; -int sizek; -int sizecode; -int sizelineinfo; -int sizep; -int sizelocvars; -int linedefined; -int lastlinedefined; -GCObject*gclist; -lu_byte nups; -lu_byte numparams; -lu_byte is_vararg; -lu_byte maxstacksize; -}Proto; -typedef struct LocVar{ -TString*varname; -int startpc; -int endpc; -}LocVar; -typedef struct UpVal{ -GCObject*next;lu_byte tt;lu_byte marked; -TValue*v; -union{ -TValue value; -struct{ -struct UpVal*prev; -struct UpVal*next; -}l; -}u; -}UpVal; -typedef struct CClosure{ -GCObject*next;lu_byte tt;lu_byte marked;lu_byte isC;lu_byte nupvalues;GCObject*gclist;struct Table*env; -lua_CFunction f; -TValue upvalue[1]; -}CClosure; -typedef struct LClosure{ -GCObject*next;lu_byte tt;lu_byte marked;lu_byte isC;lu_byte nupvalues;GCObject*gclist;struct Table*env; -struct Proto*p; -UpVal*upvals[1]; -}LClosure; -typedef union Closure{ -CClosure c; -LClosure l; -}Closure; -#define iscfunction(o)(ttype(o)==6&&clvalue(o)->c.isC) -typedef union TKey{ -struct{ -Value value;int tt; -struct Node*next; -}nk; -TValue tvk; -}TKey; -typedef struct Node{ -TValue i_val; -TKey i_key; -}Node; -typedef struct Table{ -GCObject*next;lu_byte tt;lu_byte marked; -lu_byte flags; -lu_byte lsizenode; -struct Table*metatable; -TValue*array; -Node*node; -Node*lastfree; -GCObject*gclist; -int sizearray; -}Table; -#define lmod(s,size)(check_exp((size&(size-1))==0,(cast(int,(s)&((size)-1))))) -#define twoto(x)((size_t)1<<(x)) -#define sizenode(t)(twoto((t)->lsizenode)) -static const TValue luaO_nilobject_; -#define ceillog2(x)(luaO_log2((x)-1)+1) -static int luaO_log2(unsigned int x); -#define gfasttm(g,et,e)((et)==NULL?NULL:((et)->flags&(1u<<(e)))?NULL:luaT_gettm(et,e,(g)->tmname[e])) -#define fasttm(l,et,e)gfasttm(G(l),et,e) -static const TValue*luaT_gettm(Table*events,TMS event,TString*ename); -#define luaM_reallocv(L,b,on,n,e)((cast(size_t,(n)+1)<=((size_t)(~(size_t)0)-2)/(e))?luaM_realloc_(L,(b),(on)*(e),(n)*(e)):luaM_toobig(L)) -#define luaM_freemem(L,b,s)luaM_realloc_(L,(b),(s),0) -#define luaM_free(L,b)luaM_realloc_(L,(b),sizeof(*(b)),0) -#define luaM_freearray(L,b,n,t)luaM_reallocv(L,(b),n,0,sizeof(t)) -#define luaM_malloc(L,t)luaM_realloc_(L,NULL,0,(t)) -#define luaM_new(L,t)cast(t*,luaM_malloc(L,sizeof(t))) -#define luaM_newvector(L,n,t)cast(t*,luaM_reallocv(L,NULL,0,n,sizeof(t))) -#define luaM_growvector(L,v,nelems,size,t,limit,e)if((nelems)+1>(size))((v)=cast(t*,luaM_growaux_(L,v,&(size),sizeof(t),limit,e))) -#define luaM_reallocvector(L,v,oldn,n,t)((v)=cast(t*,luaM_reallocv(L,v,oldn,n,sizeof(t)))) -static void*luaM_realloc_(lua_State*L,void*block,size_t oldsize, -size_t size); -static void*luaM_toobig(lua_State*L); -static void*luaM_growaux_(lua_State*L,void*block,int*size, -size_t size_elem,int limit, -const char*errormsg); -typedef struct Zio ZIO; -#define char2int(c)cast(int,cast(unsigned char,(c))) -#define zgetc(z)(((z)->n--)>0?char2int(*(z)->p++):luaZ_fill(z)) -typedef struct Mbuffer{ -char*buffer; -size_t n; -size_t buffsize; -}Mbuffer; -#define luaZ_initbuffer(L,buff)((buff)->buffer=NULL,(buff)->buffsize=0) -#define luaZ_buffer(buff)((buff)->buffer) -#define luaZ_sizebuffer(buff)((buff)->buffsize) -#define luaZ_bufflen(buff)((buff)->n) -#define luaZ_resetbuffer(buff)((buff)->n=0) -#define luaZ_resizebuffer(L,buff,size)(luaM_reallocvector(L,(buff)->buffer,(buff)->buffsize,size,char),(buff)->buffsize=size) -#define luaZ_freebuffer(L,buff)luaZ_resizebuffer(L,buff,0) -struct Zio{ -size_t n; -const char*p; -lua_Reader reader; -void*data; -lua_State*L; -}; -static int luaZ_fill(ZIO*z); -struct lua_longjmp; -#define gt(L)(&L->l_gt) -#define registry(L)(&G(L)->l_registry) -typedef struct stringtable{ -GCObject**hash; -lu_int32 nuse; -int size; -}stringtable; -typedef struct CallInfo{ -StkId base; -StkId func; -StkId top; -const Instruction*savedpc; -int nresults; -int tailcalls; -}CallInfo; -#define curr_func(L)(clvalue(L->ci->func)) -#define ci_func(ci)(clvalue((ci)->func)) -#define f_isLua(ci)(!ci_func(ci)->c.isC) -#define isLua(ci)(ttisfunction((ci)->func)&&f_isLua(ci)) -typedef struct global_State{ -stringtable strt; -lua_Alloc frealloc; -void*ud; -lu_byte currentwhite; -lu_byte gcstate; -int sweepstrgc; -GCObject*rootgc; -GCObject**sweepgc; -GCObject*gray; -GCObject*grayagain; -GCObject*weak; -GCObject*tmudata; -Mbuffer buff; -lu_mem GCthreshold; -lu_mem totalbytes; -lu_mem estimate; -lu_mem gcdept; -int gcpause; -int gcstepmul; -lua_CFunction panic; -TValue l_registry; -struct lua_State*mainthread; -UpVal uvhead; -struct Table*mt[(8+1)]; -TString*tmname[TM_N]; -}global_State; -struct lua_State{ -GCObject*next;lu_byte tt;lu_byte marked; -lu_byte status; -StkId top; -StkId base; -global_State*l_G; -CallInfo*ci; -const Instruction*savedpc; -StkId stack_last; -StkId stack; -CallInfo*end_ci; -CallInfo*base_ci; -int stacksize; -int size_ci; -unsigned short nCcalls; -unsigned short baseCcalls; -lu_byte hookmask; -lu_byte allowhook; -int basehookcount; -int hookcount; -lua_Hook hook; -TValue l_gt; -TValue env; -GCObject*openupval; -GCObject*gclist; -struct lua_longjmp*errorJmp; -ptrdiff_t errfunc; -}; -#define G(L)(L->l_G) -union GCObject{ -GCheader gch; -union TString ts; -union Udata u; -union Closure cl; -struct Table h; -struct Proto p; -struct UpVal uv; -struct lua_State th; -}; -#define rawgco2ts(o)check_exp((o)->gch.tt==4,&((o)->ts)) -#define gco2ts(o)(&rawgco2ts(o)->tsv) -#define rawgco2u(o)check_exp((o)->gch.tt==7,&((o)->u)) -#define gco2u(o)(&rawgco2u(o)->uv) -#define gco2cl(o)check_exp((o)->gch.tt==6,&((o)->cl)) -#define gco2h(o)check_exp((o)->gch.tt==5,&((o)->h)) -#define gco2p(o)check_exp((o)->gch.tt==(8+1),&((o)->p)) -#define gco2uv(o)check_exp((o)->gch.tt==(8+2),&((o)->uv)) -#define ngcotouv(o)check_exp((o)==NULL||(o)->gch.tt==(8+2),&((o)->uv)) -#define gco2th(o)check_exp((o)->gch.tt==8,&((o)->th)) -#define obj2gco(v)(cast(GCObject*,(v))) -static void luaE_freethread(lua_State*L,lua_State*L1); -#define pcRel(pc,p)(cast(int,(pc)-(p)->code)-1) -#define getline_(f,pc)(((f)->lineinfo)?(f)->lineinfo[pc]:0) -#define resethookcount(L)(L->hookcount=L->basehookcount) -static void luaG_typeerror(lua_State*L,const TValue*o, -const char*opname); -static void luaG_runerror(lua_State*L,const char*fmt,...); -#define luaD_checkstack(L,n)if((char*)L->stack_last-(char*)L->top<=(n)*(int)sizeof(TValue))luaD_growstack(L,n);else condhardstacktests(luaD_reallocstack(L,L->stacksize-5-1)); -#define incr_top(L){luaD_checkstack(L,1);L->top++;} -#define savestack(L,p)((char*)(p)-(char*)L->stack) -#define restorestack(L,n)((TValue*)((char*)L->stack+(n))) -#define saveci(L,p)((char*)(p)-(char*)L->base_ci) -#define restoreci(L,n)((CallInfo*)((char*)L->base_ci+(n))) -typedef void(*Pfunc)(lua_State*L,void*ud); -static int luaD_poscall(lua_State*L,StkId firstResult); -static void luaD_reallocCI(lua_State*L,int newsize); -static void luaD_reallocstack(lua_State*L,int newsize); -static void luaD_growstack(lua_State*L,int n); -static void luaD_throw(lua_State*L,int errcode); -static void*luaM_growaux_(lua_State*L,void*block,int*size,size_t size_elems, -int limit,const char*errormsg){ -void*newblock; -int newsize; -if(*size>=limit/2){ -if(*size>=limit) -luaG_runerror(L,errormsg); -newsize=limit; -} -else{ -newsize=(*size)*2; -if(newsize<4) -newsize=4; -} -newblock=luaM_reallocv(L,block,*size,newsize,size_elems); -*size=newsize; -return newblock; -} -static void*luaM_toobig(lua_State*L){ -luaG_runerror(L,"memory allocation error: block too big"); -return NULL; -} -static void*luaM_realloc_(lua_State*L,void*block,size_t osize,size_t nsize){ -global_State*g=G(L); -block=(*g->frealloc)(g->ud,block,osize,nsize); -if(block==NULL&&nsize>0) -luaD_throw(L,4); -g->totalbytes=(g->totalbytes-osize)+nsize; -return block; -} -#define resetbits(x,m)((x)&=cast(lu_byte,~(m))) -#define setbits(x,m)((x)|=(m)) -#define testbits(x,m)((x)&(m)) -#define bitmask(b)(1<<(b)) -#define bit2mask(b1,b2)(bitmask(b1)|bitmask(b2)) -#define l_setbit(x,b)setbits(x,bitmask(b)) -#define resetbit(x,b)resetbits(x,bitmask(b)) -#define testbit(x,b)testbits(x,bitmask(b)) -#define set2bits(x,b1,b2)setbits(x,(bit2mask(b1,b2))) -#define reset2bits(x,b1,b2)resetbits(x,(bit2mask(b1,b2))) -#define test2bits(x,b1,b2)testbits(x,(bit2mask(b1,b2))) -#define iswhite(x)test2bits((x)->gch.marked,0,1) -#define isblack(x)testbit((x)->gch.marked,2) -#define isgray(x)(!isblack(x)&&!iswhite(x)) -#define otherwhite(g)(g->currentwhite^bit2mask(0,1)) -#define isdead(g,v)((v)->gch.marked&otherwhite(g)&bit2mask(0,1)) -#define changewhite(x)((x)->gch.marked^=bit2mask(0,1)) -#define gray2black(x)l_setbit((x)->gch.marked,2) -#define valiswhite(x)(iscollectable(x)&&iswhite(gcvalue(x))) -#define luaC_white(g)cast(lu_byte,(g)->currentwhite&bit2mask(0,1)) -#define luaC_checkGC(L){condhardstacktests(luaD_reallocstack(L,L->stacksize-5-1));if(G(L)->totalbytes>=G(L)->GCthreshold)luaC_step(L);} -#define luaC_barrier(L,p,v){if(valiswhite(v)&&isblack(obj2gco(p)))luaC_barrierf(L,obj2gco(p),gcvalue(v));} -#define luaC_barriert(L,t,v){if(valiswhite(v)&&isblack(obj2gco(t)))luaC_barrierback(L,t);} -#define luaC_objbarrier(L,p,o){if(iswhite(obj2gco(o))&&isblack(obj2gco(p)))luaC_barrierf(L,obj2gco(p),obj2gco(o));} -#define luaC_objbarriert(L,t,o){if(iswhite(obj2gco(o))&&isblack(obj2gco(t)))luaC_barrierback(L,t);} -static void luaC_step(lua_State*L); -static void luaC_link(lua_State*L,GCObject*o,lu_byte tt); -static void luaC_linkupval(lua_State*L,UpVal*uv); -static void luaC_barrierf(lua_State*L,GCObject*o,GCObject*v); -static void luaC_barrierback(lua_State*L,Table*t); -#define sizestring(s)(sizeof(union TString)+((s)->len+1)*sizeof(char)) -#define sizeudata(u)(sizeof(union Udata)+(u)->len) -#define luaS_new(L,s)(luaS_newlstr(L,s,strlen(s))) -#define luaS_newliteral(L,s)(luaS_newlstr(L,""s,(sizeof(s)/sizeof(char))-1)) -#define luaS_fix(s)l_setbit((s)->tsv.marked,5) -static TString*luaS_newlstr(lua_State*L,const char*str,size_t l); -#define tostring(L,o)((ttype(o)==4)||(luaV_tostring(L,o))) -#define tonumber(o,n)(ttype(o)==3||(((o)=luaV_tonumber(o,n))!=NULL)) -#define equalobj(L,o1,o2)(ttype(o1)==ttype(o2)&&luaV_equalval(L,o1,o2)) -static int luaV_equalval(lua_State*L,const TValue*t1,const TValue*t2); -static const TValue*luaV_tonumber(const TValue*obj,TValue*n); -static int luaV_tostring(lua_State*L,StkId obj); -static void luaV_execute(lua_State*L,int nexeccalls); -static void luaV_concat(lua_State*L,int total,int last); -static const TValue luaO_nilobject_={{NULL},0}; -static int luaO_int2fb(unsigned int x){ -int e=0; -while(x>=16){ -x=(x+1)>>1; -e++; -} -if(x<8)return x; -else return((e+1)<<3)|(cast_int(x)-8); -} -static int luaO_fb2int(int x){ -int e=(x>>3)&31; -if(e==0)return x; -else return((x&7)+8)<<(e-1); -} -static int luaO_log2(unsigned int x){ -static const lu_byte log_2[256]={ -0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, -7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, -7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, -8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, -8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, -8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, -8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 -}; -int l=-1; -while(x>=256){l+=8;x>>=8;} -return l+log_2[x]; -} -static int luaO_rawequalObj(const TValue*t1,const TValue*t2){ -if(ttype(t1)!=ttype(t2))return 0; -else switch(ttype(t1)){ -case 0: -return 1; -case 3: -return luai_numeq(nvalue(t1),nvalue(t2)); -case 1: -return bvalue(t1)==bvalue(t2); -case 2: -return pvalue(t1)==pvalue(t2); -default: -return gcvalue(t1)==gcvalue(t2); -} -} -static int luaO_str2d(const char*s,lua_Number*result){ -char*endptr; -*result=lua_str2number(s,&endptr); -if(endptr==s)return 0; -if(*endptr=='x'||*endptr=='X') -*result=cast_num(strtoul(s,&endptr,16)); -if(*endptr=='\0')return 1; -while(isspace(cast(unsigned char,*endptr)))endptr++; -if(*endptr!='\0')return 0; -return 1; -} -static void pushstr(lua_State*L,const char*str){ -setsvalue(L,L->top,luaS_new(L,str)); -incr_top(L); -} -static const char*luaO_pushvfstring(lua_State*L,const char*fmt,va_list argp){ -int n=1; -pushstr(L,""); -for(;;){ -const char*e=strchr(fmt,'%'); -if(e==NULL)break; -setsvalue(L,L->top,luaS_newlstr(L,fmt,e-fmt)); -incr_top(L); -switch(*(e+1)){ -case's':{ -const char*s=va_arg(argp,char*); -if(s==NULL)s="(null)"; -pushstr(L,s); -break; -} -case'c':{ -char buff[2]; -buff[0]=cast(char,va_arg(argp,int)); -buff[1]='\0'; -pushstr(L,buff); -break; -} -case'd':{ -setnvalue(L->top,cast_num(va_arg(argp,int))); -incr_top(L); -break; -} -case'f':{ -setnvalue(L->top,cast_num(va_arg(argp,l_uacNumber))); -incr_top(L); -break; -} -case'p':{ -char buff[4*sizeof(void*)+8]; -sprintf(buff,"%p",va_arg(argp,void*)); -pushstr(L,buff); -break; -} -case'%':{ -pushstr(L,"%"); -break; -} -default:{ -char buff[3]; -buff[0]='%'; -buff[1]=*(e+1); -buff[2]='\0'; -pushstr(L,buff); -break; -} -} -n+=2; -fmt=e+2; -} -pushstr(L,fmt); -luaV_concat(L,n+1,cast_int(L->top-L->base)-1); -L->top-=n; -return svalue(L->top-1); -} -static const char*luaO_pushfstring(lua_State*L,const char*fmt,...){ -const char*msg; -va_list argp; -va_start(argp,fmt); -msg=luaO_pushvfstring(L,fmt,argp); -va_end(argp); -return msg; -} -static void luaO_chunkid(char*out,const char*source,size_t bufflen){ -if(*source=='='){ -strncpy(out,source+1,bufflen); -out[bufflen-1]='\0'; -} -else{ -if(*source=='@'){ -size_t l; -source++; -bufflen-=sizeof(" '...' "); -l=strlen(source); -strcpy(out,""); -if(l>bufflen){ -source+=(l-bufflen); -strcat(out,"..."); -} -strcat(out,source); -} -else{ -size_t len=strcspn(source,"\n\r"); -bufflen-=sizeof(" [string \"...\"] "); -if(len>bufflen)len=bufflen; -strcpy(out,"[string \""); -if(source[len]!='\0'){ -strncat(out,source,len); -strcat(out,"..."); -} -else -strcat(out,source); -strcat(out,"\"]"); -} -} -} -#define gnode(t,i)(&(t)->node[i]) -#define gkey(n)(&(n)->i_key.nk) -#define gval(n)(&(n)->i_val) -#define gnext(n)((n)->i_key.nk.next) -#define key2tval(n)(&(n)->i_key.tvk) -static TValue*luaH_setnum(lua_State*L,Table*t,int key); -static const TValue*luaH_getstr(Table*t,TString*key); -static TValue*luaH_set(lua_State*L,Table*t,const TValue*key); -static const char*const luaT_typenames[]={ -"nil","boolean","userdata","number", -"string","table","function","userdata","thread", -"proto","upval" -}; -static void luaT_init(lua_State*L){ -static const char*const luaT_eventname[]={ -"__index","__newindex", -"__gc","__mode","__eq", -"__add","__sub","__mul","__div","__mod", -"__pow","__unm","__len","__lt","__le", -"__concat","__call" -}; -int i; -for(i=0;itmname[i]=luaS_new(L,luaT_eventname[i]); -luaS_fix(G(L)->tmname[i]); -} -} -static const TValue*luaT_gettm(Table*events,TMS event,TString*ename){ -const TValue*tm=luaH_getstr(events,ename); -if(ttisnil(tm)){ -events->flags|=cast_byte(1u<metatable; -break; -case 7: -mt=uvalue(o)->metatable; -break; -default: -mt=G(L)->mt[ttype(o)]; -} -return(mt?luaH_getstr(mt,G(L)->tmname[event]):(&luaO_nilobject_)); -} -#define sizeCclosure(n)(cast(int,sizeof(CClosure))+cast(int,sizeof(TValue)*((n)-1))) -#define sizeLclosure(n)(cast(int,sizeof(LClosure))+cast(int,sizeof(TValue*)*((n)-1))) -static Closure*luaF_newCclosure(lua_State*L,int nelems,Table*e){ -Closure*c=cast(Closure*,luaM_malloc(L,sizeCclosure(nelems))); -luaC_link(L,obj2gco(c),6); -c->c.isC=1; -c->c.env=e; -c->c.nupvalues=cast_byte(nelems); -return c; -} -static Closure*luaF_newLclosure(lua_State*L,int nelems,Table*e){ -Closure*c=cast(Closure*,luaM_malloc(L,sizeLclosure(nelems))); -luaC_link(L,obj2gco(c),6); -c->l.isC=0; -c->l.env=e; -c->l.nupvalues=cast_byte(nelems); -while(nelems--)c->l.upvals[nelems]=NULL; -return c; -} -static UpVal*luaF_newupval(lua_State*L){ -UpVal*uv=luaM_new(L,UpVal); -luaC_link(L,obj2gco(uv),(8+2)); -uv->v=&uv->u.value; -setnilvalue(uv->v); -return uv; -} -static UpVal*luaF_findupval(lua_State*L,StkId level){ -global_State*g=G(L); -GCObject**pp=&L->openupval; -UpVal*p; -UpVal*uv; -while(*pp!=NULL&&(p=ngcotouv(*pp))->v>=level){ -if(p->v==level){ -if(isdead(g,obj2gco(p))) -changewhite(obj2gco(p)); -return p; -} -pp=&p->next; -} -uv=luaM_new(L,UpVal); -uv->tt=(8+2); -uv->marked=luaC_white(g); -uv->v=level; -uv->next=*pp; -*pp=obj2gco(uv); -uv->u.l.prev=&g->uvhead; -uv->u.l.next=g->uvhead.u.l.next; -uv->u.l.next->u.l.prev=uv; -g->uvhead.u.l.next=uv; -return uv; -} -static void unlinkupval(UpVal*uv){ -uv->u.l.next->u.l.prev=uv->u.l.prev; -uv->u.l.prev->u.l.next=uv->u.l.next; -} -static void luaF_freeupval(lua_State*L,UpVal*uv){ -if(uv->v!=&uv->u.value) -unlinkupval(uv); -luaM_free(L,uv); -} -static void luaF_close(lua_State*L,StkId level){ -UpVal*uv; -global_State*g=G(L); -while(L->openupval!=NULL&&(uv=ngcotouv(L->openupval))->v>=level){ -GCObject*o=obj2gco(uv); -L->openupval=uv->next; -if(isdead(g,o)) -luaF_freeupval(L,uv); -else{ -unlinkupval(uv); -setobj(L,&uv->u.value,uv->v); -uv->v=&uv->u.value; -luaC_linkupval(L,uv); -} -} -} -static Proto*luaF_newproto(lua_State*L){ -Proto*f=luaM_new(L,Proto); -luaC_link(L,obj2gco(f),(8+1)); -f->k=NULL; -f->sizek=0; -f->p=NULL; -f->sizep=0; -f->code=NULL; -f->sizecode=0; -f->sizelineinfo=0; -f->sizeupvalues=0; -f->nups=0; -f->upvalues=NULL; -f->numparams=0; -f->is_vararg=0; -f->maxstacksize=0; -f->lineinfo=NULL; -f->sizelocvars=0; -f->locvars=NULL; -f->linedefined=0; -f->lastlinedefined=0; -f->source=NULL; -return f; -} -static void luaF_freeproto(lua_State*L,Proto*f){ -luaM_freearray(L,f->code,f->sizecode,Instruction); -luaM_freearray(L,f->p,f->sizep,Proto*); -luaM_freearray(L,f->k,f->sizek,TValue); -luaM_freearray(L,f->lineinfo,f->sizelineinfo,int); -luaM_freearray(L,f->locvars,f->sizelocvars,struct LocVar); -luaM_freearray(L,f->upvalues,f->sizeupvalues,TString*); -luaM_free(L,f); -} -static void luaF_freeclosure(lua_State*L,Closure*c){ -int size=(c->c.isC)?sizeCclosure(c->c.nupvalues): -sizeLclosure(c->l.nupvalues); -luaM_freemem(L,c,size); -} -#define MASK1(n,p)((~((~(Instruction)0)<>0)&MASK1(6,0))) -#define SET_OPCODE(i,o)((i)=(((i)&MASK0(6,0))|((cast(Instruction,o)<<0)&MASK1(6,0)))) -#define GETARG_A(i)(cast(int,((i)>>(0+6))&MASK1(8,0))) -#define SETARG_A(i,u)((i)=(((i)&MASK0(8,(0+6)))|((cast(Instruction,u)<<(0+6))&MASK1(8,(0+6))))) -#define GETARG_B(i)(cast(int,((i)>>(((0+6)+8)+9))&MASK1(9,0))) -#define SETARG_B(i,b)((i)=(((i)&MASK0(9,(((0+6)+8)+9)))|((cast(Instruction,b)<<(((0+6)+8)+9))&MASK1(9,(((0+6)+8)+9))))) -#define GETARG_C(i)(cast(int,((i)>>((0+6)+8))&MASK1(9,0))) -#define SETARG_C(i,b)((i)=(((i)&MASK0(9,((0+6)+8)))|((cast(Instruction,b)<<((0+6)+8))&MASK1(9,((0+6)+8))))) -#define GETARG_Bx(i)(cast(int,((i)>>((0+6)+8))&MASK1((9+9),0))) -#define SETARG_Bx(i,b)((i)=(((i)&MASK0((9+9),((0+6)+8)))|((cast(Instruction,b)<<((0+6)+8))&MASK1((9+9),((0+6)+8))))) -#define GETARG_sBx(i)(GETARG_Bx(i)-(((1<<(9+9))-1)>>1)) -#define SETARG_sBx(i,b)SETARG_Bx((i),cast(unsigned int,(b)+(((1<<(9+9))-1)>>1))) -#define CREATE_ABC(o,a,b,c)((cast(Instruction,o)<<0)|(cast(Instruction,a)<<(0+6))|(cast(Instruction,b)<<(((0+6)+8)+9))|(cast(Instruction,c)<<((0+6)+8))) -#define CREATE_ABx(o,a,bc)((cast(Instruction,o)<<0)|(cast(Instruction,a)<<(0+6))|(cast(Instruction,bc)<<((0+6)+8))) -#define ISK(x)((x)&(1<<(9-1))) -#define INDEXK(r)((int)(r)&~(1<<(9-1))) -#define RKASK(x)((x)|(1<<(9-1))) -static const lu_byte luaP_opmodes[(cast(int,OP_VARARG)+1)]; -#define getBMode(m)(cast(enum OpArgMask,(luaP_opmodes[m]>>4)&3)) -#define getCMode(m)(cast(enum OpArgMask,(luaP_opmodes[m]>>2)&3)) -#define testTMode(m)(luaP_opmodes[m]&(1<<7)) -typedef struct expdesc{ -expkind k; -union{ -struct{int info,aux;}s; -lua_Number nval; -}u; -int t; -int f; -}expdesc; -typedef struct upvaldesc{ -lu_byte k; -lu_byte info; -}upvaldesc; -struct BlockCnt; -typedef struct FuncState{ -Proto*f; -Table*h; -struct FuncState*prev; -struct LexState*ls; -struct lua_State*L; -struct BlockCnt*bl; -int pc; -int lasttarget; -int jpc; -int freereg; -int nk; -int np; -short nlocvars; -lu_byte nactvar; -upvaldesc upvalues[60]; -unsigned short actvar[200]; -}FuncState; -static Proto*luaY_parser(lua_State*L,ZIO*z,Mbuffer*buff, -const char*name); -struct lua_longjmp{ -struct lua_longjmp*previous; -jmp_buf b; -volatile int status; -}; -static void luaD_seterrorobj(lua_State*L,int errcode,StkId oldtop){ -switch(errcode){ -case 4:{ -setsvalue(L,oldtop,luaS_newliteral(L,"not enough memory")); -break; -} -case 5:{ -setsvalue(L,oldtop,luaS_newliteral(L,"error in error handling")); -break; -} -case 3: -case 2:{ -setobj(L,oldtop,L->top-1); -break; -} -} -L->top=oldtop+1; -} -static void restore_stack_limit(lua_State*L){ -if(L->size_ci>20000){ -int inuse=cast_int(L->ci-L->base_ci); -if(inuse+1<20000) -luaD_reallocCI(L,20000); -} -} -static void resetstack(lua_State*L,int status){ -L->ci=L->base_ci; -L->base=L->ci->base; -luaF_close(L,L->base); -luaD_seterrorobj(L,status,L->base); -L->nCcalls=L->baseCcalls; -L->allowhook=1; -restore_stack_limit(L); -L->errfunc=0; -L->errorJmp=NULL; -} -static void luaD_throw(lua_State*L,int errcode){ -if(L->errorJmp){ -L->errorJmp->status=errcode; -LUAI_THROW(L,L->errorJmp); -} -else{ -L->status=cast_byte(errcode); -if(G(L)->panic){ -resetstack(L,errcode); -G(L)->panic(L); -} -exit(EXIT_FAILURE); -} -} -static int luaD_rawrunprotected(lua_State*L,Pfunc f,void*ud){ -struct lua_longjmp lj; -lj.status=0; -lj.previous=L->errorJmp; -L->errorJmp=&lj; -LUAI_TRY(L,&lj, -(*f)(L,ud); -); -L->errorJmp=lj.previous; -return lj.status; -} -static void correctstack(lua_State*L,TValue*oldstack){ -CallInfo*ci; -GCObject*up; -L->top=(L->top-oldstack)+L->stack; -for(up=L->openupval;up!=NULL;up=up->gch.next) -gco2uv(up)->v=(gco2uv(up)->v-oldstack)+L->stack; -for(ci=L->base_ci;ci<=L->ci;ci++){ -ci->top=(ci->top-oldstack)+L->stack; -ci->base=(ci->base-oldstack)+L->stack; -ci->func=(ci->func-oldstack)+L->stack; -} -L->base=(L->base-oldstack)+L->stack; -} -static void luaD_reallocstack(lua_State*L,int newsize){ -TValue*oldstack=L->stack; -int realsize=newsize+1+5; -luaM_reallocvector(L,L->stack,L->stacksize,realsize,TValue); -L->stacksize=realsize; -L->stack_last=L->stack+newsize; -correctstack(L,oldstack); -} -static void luaD_reallocCI(lua_State*L,int newsize){ -CallInfo*oldci=L->base_ci; -luaM_reallocvector(L,L->base_ci,L->size_ci,newsize,CallInfo); -L->size_ci=newsize; -L->ci=(L->ci-oldci)+L->base_ci; -L->end_ci=L->base_ci+L->size_ci-1; -} -static void luaD_growstack(lua_State*L,int n){ -if(n<=L->stacksize) -luaD_reallocstack(L,2*L->stacksize); -else -luaD_reallocstack(L,L->stacksize+n); -} -static CallInfo*growCI(lua_State*L){ -if(L->size_ci>20000) -luaD_throw(L,5); -else{ -luaD_reallocCI(L,2*L->size_ci); -if(L->size_ci>20000) -luaG_runerror(L,"stack overflow"); -} -return++L->ci; -} -static StkId adjust_varargs(lua_State*L,Proto*p,int actual){ -int i; -int nfixargs=p->numparams; -Table*htab=NULL; -StkId base,fixed; -for(;actualtop++); -fixed=L->top-actual; -base=L->top; -for(i=0;itop++,fixed+i); -setnilvalue(fixed+i); -} -if(htab){ -sethvalue(L,L->top++,htab); -} -return base; -} -static StkId tryfuncTM(lua_State*L,StkId func){ -const TValue*tm=luaT_gettmbyobj(L,func,TM_CALL); -StkId p; -ptrdiff_t funcr=savestack(L,func); -if(!ttisfunction(tm)) -luaG_typeerror(L,func,"call"); -for(p=L->top;p>func;p--)setobj(L,p,p-1); -incr_top(L); -func=restorestack(L,funcr); -setobj(L,func,tm); -return func; -} -#define inc_ci(L)((L->ci==L->end_ci)?growCI(L):(condhardstacktests(luaD_reallocCI(L,L->size_ci)),++L->ci)) -static int luaD_precall(lua_State*L,StkId func,int nresults){ -LClosure*cl; -ptrdiff_t funcr; -if(!ttisfunction(func)) -func=tryfuncTM(L,func); -funcr=savestack(L,func); -cl=&clvalue(func)->l; -L->ci->savedpc=L->savedpc; -if(!cl->isC){ -CallInfo*ci; -StkId st,base; -Proto*p=cl->p; -luaD_checkstack(L,p->maxstacksize); -func=restorestack(L,funcr); -if(!p->is_vararg){ -base=func+1; -if(L->top>base+p->numparams) -L->top=base+p->numparams; -} -else{ -int nargs=cast_int(L->top-func)-1; -base=adjust_varargs(L,p,nargs); -func=restorestack(L,funcr); -} -ci=inc_ci(L); -ci->func=func; -L->base=ci->base=base; -ci->top=L->base+p->maxstacksize; -L->savedpc=p->code; -ci->tailcalls=0; -ci->nresults=nresults; -for(st=L->top;sttop;st++) -setnilvalue(st); -L->top=ci->top; -return 0; -} -else{ -CallInfo*ci; -int n; -luaD_checkstack(L,20); -ci=inc_ci(L); -ci->func=restorestack(L,funcr); -L->base=ci->base=ci->func+1; -ci->top=L->top+20; -ci->nresults=nresults; -n=(*curr_func(L)->c.f)(L); -if(n<0) -return 2; -else{ -luaD_poscall(L,L->top-n); -return 1; -} -} -} -static int luaD_poscall(lua_State*L,StkId firstResult){ -StkId res; -int wanted,i; -CallInfo*ci; -ci=L->ci--; -res=ci->func; -wanted=ci->nresults; -L->base=(ci-1)->base; -L->savedpc=(ci-1)->savedpc; -for(i=wanted;i!=0&&firstResulttop;i--) -setobj(L,res++,firstResult++); -while(i-->0) -setnilvalue(res++); -L->top=res; -return(wanted-(-1)); -} -static void luaD_call(lua_State*L,StkId func,int nResults){ -if(++L->nCcalls>=200){ -if(L->nCcalls==200) -luaG_runerror(L,"C stack overflow"); -else if(L->nCcalls>=(200+(200>>3))) -luaD_throw(L,5); -} -if(luaD_precall(L,func,nResults)==0) -luaV_execute(L,1); -L->nCcalls--; -luaC_checkGC(L); -} -static int luaD_pcall(lua_State*L,Pfunc func,void*u, -ptrdiff_t old_top,ptrdiff_t ef){ -int status; -unsigned short oldnCcalls=L->nCcalls; -ptrdiff_t old_ci=saveci(L,L->ci); -lu_byte old_allowhooks=L->allowhook; -ptrdiff_t old_errfunc=L->errfunc; -L->errfunc=ef; -status=luaD_rawrunprotected(L,func,u); -if(status!=0){ -StkId oldtop=restorestack(L,old_top); -luaF_close(L,oldtop); -luaD_seterrorobj(L,status,oldtop); -L->nCcalls=oldnCcalls; -L->ci=restoreci(L,old_ci); -L->base=L->ci->base; -L->savedpc=L->ci->savedpc; -L->allowhook=old_allowhooks; -restore_stack_limit(L); -} -L->errfunc=old_errfunc; -return status; -} -struct SParser{ -ZIO*z; -Mbuffer buff; -const char*name; -}; -static void f_parser(lua_State*L,void*ud){ -int i; -Proto*tf; -Closure*cl; -struct SParser*p=cast(struct SParser*,ud); -luaC_checkGC(L); -tf=luaY_parser(L,p->z, -&p->buff,p->name); -cl=luaF_newLclosure(L,tf->nups,hvalue(gt(L))); -cl->l.p=tf; -for(i=0;inups;i++) -cl->l.upvals[i]=luaF_newupval(L); -setclvalue(L,L->top,cl); -incr_top(L); -} -static int luaD_protectedparser(lua_State*L,ZIO*z,const char*name){ -struct SParser p; -int status; -p.z=z;p.name=name; -luaZ_initbuffer(L,&p.buff); -status=luaD_pcall(L,f_parser,&p,savestack(L,L->top),L->errfunc); -luaZ_freebuffer(L,&p.buff); -return status; -} -static void luaS_resize(lua_State*L,int newsize){ -GCObject**newhash; -stringtable*tb; -int i; -if(G(L)->gcstate==2) -return; -newhash=luaM_newvector(L,newsize,GCObject*); -tb=&G(L)->strt; -for(i=0;isize;i++){ -GCObject*p=tb->hash[i]; -while(p){ -GCObject*next=p->gch.next; -unsigned int h=gco2ts(p)->hash; -int h1=lmod(h,newsize); -p->gch.next=newhash[h1]; -newhash[h1]=p; -p=next; -} -} -luaM_freearray(L,tb->hash,tb->size,TString*); -tb->size=newsize; -tb->hash=newhash; -} -static TString*newlstr(lua_State*L,const char*str,size_t l, -unsigned int h){ -TString*ts; -stringtable*tb; -if(l+1>(((size_t)(~(size_t)0)-2)-sizeof(TString))/sizeof(char)) -luaM_toobig(L); -ts=cast(TString*,luaM_malloc(L,(l+1)*sizeof(char)+sizeof(TString))); -ts->tsv.len=l; -ts->tsv.hash=h; -ts->tsv.marked=luaC_white(G(L)); -ts->tsv.tt=4; -ts->tsv.reserved=0; -memcpy(ts+1,str,l*sizeof(char)); -((char*)(ts+1))[l]='\0'; -tb=&G(L)->strt; -h=lmod(h,tb->size); -ts->tsv.next=tb->hash[h]; -tb->hash[h]=obj2gco(ts); -tb->nuse++; -if(tb->nuse>cast(lu_int32,tb->size)&&tb->size<=(INT_MAX-2)/2) -luaS_resize(L,tb->size*2); -return ts; -} -static TString*luaS_newlstr(lua_State*L,const char*str,size_t l){ -GCObject*o; -unsigned int h=cast(unsigned int,l); -size_t step=(l>>5)+1; -size_t l1; -for(l1=l;l1>=step;l1-=step) -h=h^((h<<5)+(h>>2)+cast(unsigned char,str[l1-1])); -for(o=G(L)->strt.hash[lmod(h,G(L)->strt.size)]; -o!=NULL; -o=o->gch.next){ -TString*ts=rawgco2ts(o); -if(ts->tsv.len==l&&(memcmp(str,getstr(ts),l)==0)){ -if(isdead(G(L),o))changewhite(o); -return ts; -} -} -return newlstr(L,str,l,h); -} -static Udata*luaS_newudata(lua_State*L,size_t s,Table*e){ -Udata*u; -if(s>((size_t)(~(size_t)0)-2)-sizeof(Udata)) -luaM_toobig(L); -u=cast(Udata*,luaM_malloc(L,s+sizeof(Udata))); -u->uv.marked=luaC_white(G(L)); -u->uv.tt=7; -u->uv.len=s; -u->uv.metatable=NULL; -u->uv.env=e; -u->uv.next=G(L)->mainthread->next; -G(L)->mainthread->next=obj2gco(u); -return u; -} -#define hashpow2(t,n)(gnode(t,lmod((n),sizenode(t)))) -#define hashstr(t,str)hashpow2(t,(str)->tsv.hash) -#define hashboolean(t,p)hashpow2(t,p) -#define hashmod(t,n)(gnode(t,((n)%((sizenode(t)-1)|1)))) -#define hashpointer(t,p)hashmod(t,IntPoint(p)) -static const Node dummynode_={ -{{NULL},0}, -{{{NULL},0,NULL}} -}; -static Node*hashnum(const Table*t,lua_Number n){ -unsigned int a[cast_int(sizeof(lua_Number)/sizeof(int))]; -int i; -if(luai_numeq(n,0)) -return gnode(t,0); -memcpy(a,&n,sizeof(a)); -for(i=1;isizearray) -return i-1; -else{ -Node*n=mainposition(t,key); -do{ -if(luaO_rawequalObj(key2tval(n),key)|| -(ttype(gkey(n))==(8+3)&&iscollectable(key)&& -gcvalue(gkey(n))==gcvalue(key))){ -i=cast_int(n-gnode(t,0)); -return i+t->sizearray; -} -else n=gnext(n); -}while(n); -luaG_runerror(L,"invalid key to "LUA_QL("next")); -return 0; -} -} -static int luaH_next(lua_State*L,Table*t,StkId key){ -int i=findindex(L,t,key); -for(i++;isizearray;i++){ -if(!ttisnil(&t->array[i])){ -setnvalue(key,cast_num(i+1)); -setobj(L,key+1,&t->array[i]); -return 1; -} -} -for(i-=t->sizearray;i<(int)sizenode(t);i++){ -if(!ttisnil(gval(gnode(t,i)))){ -setobj(L,key,key2tval(gnode(t,i))); -setobj(L,key+1,gval(gnode(t,i))); -return 1; -} -} -return 0; -} -static int computesizes(int nums[],int*narray){ -int i; -int twotoi; -int a=0; -int na=0; -int n=0; -for(i=0,twotoi=1;twotoi/2<*narray;i++,twotoi*=2){ -if(nums[i]>0){ -a+=nums[i]; -if(a>twotoi/2){ -n=twotoi; -na=a; -} -} -if(a==*narray)break; -} -*narray=n; -return na; -} -static int countint(const TValue*key,int*nums){ -int k=arrayindex(key); -if(0t->sizearray){ -lim=t->sizearray; -if(i>lim) -break; -} -for(;i<=lim;i++){ -if(!ttisnil(&t->array[i-1])) -lc++; -} -nums[lg]+=lc; -ause+=lc; -} -return ause; -} -static int numusehash(const Table*t,int*nums,int*pnasize){ -int totaluse=0; -int ause=0; -int i=sizenode(t); -while(i--){ -Node*n=&t->node[i]; -if(!ttisnil(gval(n))){ -ause+=countint(key2tval(n),nums); -totaluse++; -} -} -*pnasize+=ause; -return totaluse; -} -static void setarrayvector(lua_State*L,Table*t,int size){ -int i; -luaM_reallocvector(L,t->array,t->sizearray,size,TValue); -for(i=t->sizearray;iarray[i]); -t->sizearray=size; -} -static void setnodevector(lua_State*L,Table*t,int size){ -int lsize; -if(size==0){ -t->node=cast(Node*,(&dummynode_)); -lsize=0; -} -else{ -int i; -lsize=ceillog2(size); -if(lsize>(32-2)) -luaG_runerror(L,"table overflow"); -size=twoto(lsize); -t->node=luaM_newvector(L,size,Node); -for(i=0;ilsizenode=cast_byte(lsize); -t->lastfree=gnode(t,size); -} -static void resize(lua_State*L,Table*t,int nasize,int nhsize){ -int i; -int oldasize=t->sizearray; -int oldhsize=t->lsizenode; -Node*nold=t->node; -if(nasize>oldasize) -setarrayvector(L,t,nasize); -setnodevector(L,t,nhsize); -if(nasizesizearray=nasize; -for(i=nasize;iarray[i])) -setobj(L,luaH_setnum(L,t,i+1),&t->array[i]); -} -luaM_reallocvector(L,t->array,oldasize,nasize,TValue); -} -for(i=twoto(oldhsize)-1;i>=0;i--){ -Node*old=nold+i; -if(!ttisnil(gval(old))) -setobj(L,luaH_set(L,t,key2tval(old)),gval(old)); -} -if(nold!=(&dummynode_)) -luaM_freearray(L,nold,twoto(oldhsize),Node); -} -static void luaH_resizearray(lua_State*L,Table*t,int nasize){ -int nsize=(t->node==(&dummynode_))?0:sizenode(t); -resize(L,t,nasize,nsize); -} -static void rehash(lua_State*L,Table*t,const TValue*ek){ -int nasize,na; -int nums[(32-2)+1]; -int i; -int totaluse; -for(i=0;i<=(32-2);i++)nums[i]=0; -nasize=numusearray(t,nums); -totaluse=nasize; -totaluse+=numusehash(t,nums,&nasize); -nasize+=countint(ek,nums); -totaluse++; -na=computesizes(nums,&nasize); -resize(L,t,nasize,totaluse-na); -} -static Table*luaH_new(lua_State*L,int narray,int nhash){ -Table*t=luaM_new(L,Table); -luaC_link(L,obj2gco(t),5); -t->metatable=NULL; -t->flags=cast_byte(~0); -t->array=NULL; -t->sizearray=0; -t->lsizenode=0; -t->node=cast(Node*,(&dummynode_)); -setarrayvector(L,t,narray); -setnodevector(L,t,nhash); -return t; -} -static void luaH_free(lua_State*L,Table*t){ -if(t->node!=(&dummynode_)) -luaM_freearray(L,t->node,sizenode(t),Node); -luaM_freearray(L,t->array,t->sizearray,TValue); -luaM_free(L,t); -} -static Node*getfreepos(Table*t){ -while(t->lastfree-->t->node){ -if(ttisnil(gkey(t->lastfree))) -return t->lastfree; -} -return NULL; -} -static TValue*newkey(lua_State*L,Table*t,const TValue*key){ -Node*mp=mainposition(t,key); -if(!ttisnil(gval(mp))||mp==(&dummynode_)){ -Node*othern; -Node*n=getfreepos(t); -if(n==NULL){ -rehash(L,t,key); -return luaH_set(L,t,key); -} -othern=mainposition(t,key2tval(mp)); -if(othern!=mp){ -while(gnext(othern)!=mp)othern=gnext(othern); -gnext(othern)=n; -*n=*mp; -gnext(mp)=NULL; -setnilvalue(gval(mp)); -} -else{ -gnext(n)=gnext(mp); -gnext(mp)=n; -mp=n; -} -} -gkey(mp)->value=key->value;gkey(mp)->tt=key->tt; -luaC_barriert(L,t,key); -return gval(mp); -} -static const TValue*luaH_getnum(Table*t,int key){ -if(cast(unsigned int,key)-1sizearray)) -return&t->array[key-1]; -else{ -lua_Number nk=cast_num(key); -Node*n=hashnum(t,nk); -do{ -if(ttisnumber(gkey(n))&&luai_numeq(nvalue(gkey(n)),nk)) -return gval(n); -else n=gnext(n); -}while(n); -return(&luaO_nilobject_); -} -} -static const TValue*luaH_getstr(Table*t,TString*key){ -Node*n=hashstr(t,key); -do{ -if(ttisstring(gkey(n))&&rawtsvalue(gkey(n))==key) -return gval(n); -else n=gnext(n); -}while(n); -return(&luaO_nilobject_); -} -static const TValue*luaH_get(Table*t,const TValue*key){ -switch(ttype(key)){ -case 0:return(&luaO_nilobject_); -case 4:return luaH_getstr(t,rawtsvalue(key)); -case 3:{ -int k; -lua_Number n=nvalue(key); -lua_number2int(k,n); -if(luai_numeq(cast_num(k),nvalue(key))) -return luaH_getnum(t,k); -} -default:{ -Node*n=mainposition(t,key); -do{ -if(luaO_rawequalObj(key2tval(n),key)) -return gval(n); -else n=gnext(n); -}while(n); -return(&luaO_nilobject_); -} -} -} -static TValue*luaH_set(lua_State*L,Table*t,const TValue*key){ -const TValue*p=luaH_get(t,key); -t->flags=0; -if(p!=(&luaO_nilobject_)) -return cast(TValue*,p); -else{ -if(ttisnil(key))luaG_runerror(L,"table index is nil"); -else if(ttisnumber(key)&&luai_numisnan(nvalue(key))) -luaG_runerror(L,"table index is NaN"); -return newkey(L,t,key); -} -} -static TValue*luaH_setnum(lua_State*L,Table*t,int key){ -const TValue*p=luaH_getnum(t,key); -if(p!=(&luaO_nilobject_)) -return cast(TValue*,p); -else{ -TValue k; -setnvalue(&k,cast_num(key)); -return newkey(L,t,&k); -} -} -static TValue*luaH_setstr(lua_State*L,Table*t,TString*key){ -const TValue*p=luaH_getstr(t,key); -if(p!=(&luaO_nilobject_)) -return cast(TValue*,p); -else{ -TValue k; -setsvalue(L,&k,key); -return newkey(L,t,&k); -} -} -static int unbound_search(Table*t,unsigned int j){ -unsigned int i=j; -j++; -while(!ttisnil(luaH_getnum(t,j))){ -i=j; -j*=2; -if(j>cast(unsigned int,(INT_MAX-2))){ -i=1; -while(!ttisnil(luaH_getnum(t,i)))i++; -return i-1; -} -} -while(j-i>1){ -unsigned int m=(i+j)/2; -if(ttisnil(luaH_getnum(t,m)))j=m; -else i=m; -} -return i; -} -static int luaH_getn(Table*t){ -unsigned int j=t->sizearray; -if(j>0&&ttisnil(&t->array[j-1])){ -unsigned int i=0; -while(j-i>1){ -unsigned int m=(i+j)/2; -if(ttisnil(&t->array[m-1]))j=m; -else i=m; -} -return i; -} -else if(t->node==(&dummynode_)) -return j; -else return unbound_search(t,j); -} -#define makewhite(g,x)((x)->gch.marked=cast_byte(((x)->gch.marked&cast_byte(~(bitmask(2)|bit2mask(0,1))))|luaC_white(g))) -#define white2gray(x)reset2bits((x)->gch.marked,0,1) -#define black2gray(x)resetbit((x)->gch.marked,2) -#define stringmark(s)reset2bits((s)->tsv.marked,0,1) -#define isfinalized(u)testbit((u)->marked,3) -#define markfinalized(u)l_setbit((u)->marked,3) -#define markvalue(g,o){checkconsistency(o);if(iscollectable(o)&&iswhite(gcvalue(o)))reallymarkobject(g,gcvalue(o));} -#define markobject(g,t){if(iswhite(obj2gco(t)))reallymarkobject(g,obj2gco(t));} -#define setthreshold(g)(g->GCthreshold=(g->estimate/100)*g->gcpause) -static void removeentry(Node*n){ -if(iscollectable(gkey(n))) -setttype(gkey(n),(8+3)); -} -static void reallymarkobject(global_State*g,GCObject*o){ -white2gray(o); -switch(o->gch.tt){ -case 4:{ -return; -} -case 7:{ -Table*mt=gco2u(o)->metatable; -gray2black(o); -if(mt)markobject(g,mt); -markobject(g,gco2u(o)->env); -return; -} -case(8+2):{ -UpVal*uv=gco2uv(o); -markvalue(g,uv->v); -if(uv->v==&uv->u.value) -gray2black(o); -return; -} -case 6:{ -gco2cl(o)->c.gclist=g->gray; -g->gray=o; -break; -} -case 5:{ -gco2h(o)->gclist=g->gray; -g->gray=o; -break; -} -case 8:{ -gco2th(o)->gclist=g->gray; -g->gray=o; -break; -} -case(8+1):{ -gco2p(o)->gclist=g->gray; -g->gray=o; -break; -} -default:; -} -} -static void marktmu(global_State*g){ -GCObject*u=g->tmudata; -if(u){ -do{ -u=u->gch.next; -makewhite(g,u); -reallymarkobject(g,u); -}while(u!=g->tmudata); -} -} -static size_t luaC_separateudata(lua_State*L,int all){ -global_State*g=G(L); -size_t deadmem=0; -GCObject**p=&g->mainthread->next; -GCObject*curr; -while((curr=*p)!=NULL){ -if(!(iswhite(curr)||all)||isfinalized(gco2u(curr))) -p=&curr->gch.next; -else if(fasttm(L,gco2u(curr)->metatable,TM_GC)==NULL){ -markfinalized(gco2u(curr)); -p=&curr->gch.next; -} -else{ -deadmem+=sizeudata(gco2u(curr)); -markfinalized(gco2u(curr)); -*p=curr->gch.next; -if(g->tmudata==NULL) -g->tmudata=curr->gch.next=curr; -else{ -curr->gch.next=g->tmudata->gch.next; -g->tmudata->gch.next=curr; -g->tmudata=curr; -} -} -} -return deadmem; -} -static int traversetable(global_State*g,Table*h){ -int i; -int weakkey=0; -int weakvalue=0; -const TValue*mode; -if(h->metatable) -markobject(g,h->metatable); -mode=gfasttm(g,h->metatable,TM_MODE); -if(mode&&ttisstring(mode)){ -weakkey=(strchr(svalue(mode),'k')!=NULL); -weakvalue=(strchr(svalue(mode),'v')!=NULL); -if(weakkey||weakvalue){ -h->marked&=~(bitmask(3)|bitmask(4)); -h->marked|=cast_byte((weakkey<<3)| -(weakvalue<<4)); -h->gclist=g->weak; -g->weak=obj2gco(h); -} -} -if(weakkey&&weakvalue)return 1; -if(!weakvalue){ -i=h->sizearray; -while(i--) -markvalue(g,&h->array[i]); -} -i=sizenode(h); -while(i--){ -Node*n=gnode(h,i); -if(ttisnil(gval(n))) -removeentry(n); -else{ -if(!weakkey)markvalue(g,gkey(n)); -if(!weakvalue)markvalue(g,gval(n)); -} -} -return weakkey||weakvalue; -} -static void traverseproto(global_State*g,Proto*f){ -int i; -if(f->source)stringmark(f->source); -for(i=0;isizek;i++) -markvalue(g,&f->k[i]); -for(i=0;isizeupvalues;i++){ -if(f->upvalues[i]) -stringmark(f->upvalues[i]); -} -for(i=0;isizep;i++){ -if(f->p[i]) -markobject(g,f->p[i]); -} -for(i=0;isizelocvars;i++){ -if(f->locvars[i].varname) -stringmark(f->locvars[i].varname); -} -} -static void traverseclosure(global_State*g,Closure*cl){ -markobject(g,cl->c.env); -if(cl->c.isC){ -int i; -for(i=0;ic.nupvalues;i++) -markvalue(g,&cl->c.upvalue[i]); -} -else{ -int i; -markobject(g,cl->l.p); -for(i=0;il.nupvalues;i++) -markobject(g,cl->l.upvals[i]); -} -} -static void checkstacksizes(lua_State*L,StkId max){ -int ci_used=cast_int(L->ci-L->base_ci); -int s_used=cast_int(max-L->stack); -if(L->size_ci>20000) -return; -if(4*ci_usedsize_ci&&2*8size_ci) -luaD_reallocCI(L,L->size_ci/2); -condhardstacktests(luaD_reallocCI(L,ci_used+1)); -if(4*s_usedstacksize&& -2*((2*20)+5)stacksize) -luaD_reallocstack(L,L->stacksize/2); -condhardstacktests(luaD_reallocstack(L,s_used)); -} -static void traversestack(global_State*g,lua_State*l){ -StkId o,lim; -CallInfo*ci; -markvalue(g,gt(l)); -lim=l->top; -for(ci=l->base_ci;ci<=l->ci;ci++){ -if(limtop)lim=ci->top; -} -for(o=l->stack;otop;o++) -markvalue(g,o); -for(;o<=lim;o++) -setnilvalue(o); -checkstacksizes(l,lim); -} -static l_mem propagatemark(global_State*g){ -GCObject*o=g->gray; -gray2black(o); -switch(o->gch.tt){ -case 5:{ -Table*h=gco2h(o); -g->gray=h->gclist; -if(traversetable(g,h)) -black2gray(o); -return sizeof(Table)+sizeof(TValue)*h->sizearray+ -sizeof(Node)*sizenode(h); -} -case 6:{ -Closure*cl=gco2cl(o); -g->gray=cl->c.gclist; -traverseclosure(g,cl); -return(cl->c.isC)?sizeCclosure(cl->c.nupvalues): -sizeLclosure(cl->l.nupvalues); -} -case 8:{ -lua_State*th=gco2th(o); -g->gray=th->gclist; -th->gclist=g->grayagain; -g->grayagain=o; -black2gray(o); -traversestack(g,th); -return sizeof(lua_State)+sizeof(TValue)*th->stacksize+ -sizeof(CallInfo)*th->size_ci; -} -case(8+1):{ -Proto*p=gco2p(o); -g->gray=p->gclist; -traverseproto(g,p); -return sizeof(Proto)+sizeof(Instruction)*p->sizecode+ -sizeof(Proto*)*p->sizep+ -sizeof(TValue)*p->sizek+ -sizeof(int)*p->sizelineinfo+ -sizeof(LocVar)*p->sizelocvars+ -sizeof(TString*)*p->sizeupvalues; -} -default:return 0; -} -} -static size_t propagateall(global_State*g){ -size_t m=0; -while(g->gray)m+=propagatemark(g); -return m; -} -static int iscleared(const TValue*o,int iskey){ -if(!iscollectable(o))return 0; -if(ttisstring(o)){ -stringmark(rawtsvalue(o)); -return 0; -} -return iswhite(gcvalue(o))|| -(ttisuserdata(o)&&(!iskey&&isfinalized(uvalue(o)))); -} -static void cleartable(GCObject*l){ -while(l){ -Table*h=gco2h(l); -int i=h->sizearray; -if(testbit(h->marked,4)){ -while(i--){ -TValue*o=&h->array[i]; -if(iscleared(o,0)) -setnilvalue(o); -} -} -i=sizenode(h); -while(i--){ -Node*n=gnode(h,i); -if(!ttisnil(gval(n))&& -(iscleared(key2tval(n),1)||iscleared(gval(n),0))){ -setnilvalue(gval(n)); -removeentry(n); -} -} -l=h->gclist; -} -} -static void freeobj(lua_State*L,GCObject*o){ -switch(o->gch.tt){ -case(8+1):luaF_freeproto(L,gco2p(o));break; -case 6:luaF_freeclosure(L,gco2cl(o));break; -case(8+2):luaF_freeupval(L,gco2uv(o));break; -case 5:luaH_free(L,gco2h(o));break; -case 8:{ -luaE_freethread(L,gco2th(o)); -break; -} -case 4:{ -G(L)->strt.nuse--; -luaM_freemem(L,o,sizestring(gco2ts(o))); -break; -} -case 7:{ -luaM_freemem(L,o,sizeudata(gco2u(o))); -break; -} -default:; -} -} -#define sweepwholelist(L,p)sweeplist(L,p,((lu_mem)(~(lu_mem)0)-2)) -static GCObject**sweeplist(lua_State*L,GCObject**p,lu_mem count){ -GCObject*curr; -global_State*g=G(L); -int deadmask=otherwhite(g); -while((curr=*p)!=NULL&&count-->0){ -if(curr->gch.tt==8) -sweepwholelist(L,&gco2th(curr)->openupval); -if((curr->gch.marked^bit2mask(0,1))&deadmask){ -makewhite(g,curr); -p=&curr->gch.next; -} -else{ -*p=curr->gch.next; -if(curr==g->rootgc) -g->rootgc=curr->gch.next; -freeobj(L,curr); -} -} -return p; -} -static void checkSizes(lua_State*L){ -global_State*g=G(L); -if(g->strt.nusestrt.size/4)&& -g->strt.size>32*2) -luaS_resize(L,g->strt.size/2); -if(luaZ_sizebuffer(&g->buff)>32*2){ -size_t newsize=luaZ_sizebuffer(&g->buff)/2; -luaZ_resizebuffer(L,&g->buff,newsize); -} -} -static void GCTM(lua_State*L){ -global_State*g=G(L); -GCObject*o=g->tmudata->gch.next; -Udata*udata=rawgco2u(o); -const TValue*tm; -if(o==g->tmudata) -g->tmudata=NULL; -else -g->tmudata->gch.next=udata->uv.next; -udata->uv.next=g->mainthread->next; -g->mainthread->next=o; -makewhite(g,o); -tm=fasttm(L,udata->uv.metatable,TM_GC); -if(tm!=NULL){ -lu_byte oldah=L->allowhook; -lu_mem oldt=g->GCthreshold; -L->allowhook=0; -g->GCthreshold=2*g->totalbytes; -setobj(L,L->top,tm); -setuvalue(L,L->top+1,udata); -L->top+=2; -luaD_call(L,L->top-2,0); -L->allowhook=oldah; -g->GCthreshold=oldt; -} -} -static void luaC_callGCTM(lua_State*L){ -while(G(L)->tmudata) -GCTM(L); -} -static void luaC_freeall(lua_State*L){ -global_State*g=G(L); -int i; -g->currentwhite=bit2mask(0,1)|bitmask(6); -sweepwholelist(L,&g->rootgc); -for(i=0;istrt.size;i++) -sweepwholelist(L,&g->strt.hash[i]); -} -static void markmt(global_State*g){ -int i; -for(i=0;i<(8+1);i++) -if(g->mt[i])markobject(g,g->mt[i]); -} -static void markroot(lua_State*L){ -global_State*g=G(L); -g->gray=NULL; -g->grayagain=NULL; -g->weak=NULL; -markobject(g,g->mainthread); -markvalue(g,gt(g->mainthread)); -markvalue(g,registry(L)); -markmt(g); -g->gcstate=1; -} -static void remarkupvals(global_State*g){ -UpVal*uv; -for(uv=g->uvhead.u.l.next;uv!=&g->uvhead;uv=uv->u.l.next){ -if(isgray(obj2gco(uv))) -markvalue(g,uv->v); -} -} -static void atomic(lua_State*L){ -global_State*g=G(L); -size_t udsize; -remarkupvals(g); -propagateall(g); -g->gray=g->weak; -g->weak=NULL; -markobject(g,L); -markmt(g); -propagateall(g); -g->gray=g->grayagain; -g->grayagain=NULL; -propagateall(g); -udsize=luaC_separateudata(L,0); -marktmu(g); -udsize+=propagateall(g); -cleartable(g->weak); -g->currentwhite=cast_byte(otherwhite(g)); -g->sweepstrgc=0; -g->sweepgc=&g->rootgc; -g->gcstate=2; -g->estimate=g->totalbytes-udsize; -} -static l_mem singlestep(lua_State*L){ -global_State*g=G(L); -switch(g->gcstate){ -case 0:{ -markroot(L); -return 0; -} -case 1:{ -if(g->gray) -return propagatemark(g); -else{ -atomic(L); -return 0; -} -} -case 2:{ -lu_mem old=g->totalbytes; -sweepwholelist(L,&g->strt.hash[g->sweepstrgc++]); -if(g->sweepstrgc>=g->strt.size) -g->gcstate=3; -g->estimate-=old-g->totalbytes; -return 10; -} -case 3:{ -lu_mem old=g->totalbytes; -g->sweepgc=sweeplist(L,g->sweepgc,40); -if(*g->sweepgc==NULL){ -checkSizes(L); -g->gcstate=4; -} -g->estimate-=old-g->totalbytes; -return 40*10; -} -case 4:{ -if(g->tmudata){ -GCTM(L); -if(g->estimate>100) -g->estimate-=100; -return 100; -} -else{ -g->gcstate=0; -g->gcdept=0; -return 0; -} -} -default:return 0; -} -} -static void luaC_step(lua_State*L){ -global_State*g=G(L); -l_mem lim=(1024u/100)*g->gcstepmul; -if(lim==0) -lim=(((lu_mem)(~(lu_mem)0)-2)-1)/2; -g->gcdept+=g->totalbytes-g->GCthreshold; -do{ -lim-=singlestep(L); -if(g->gcstate==0) -break; -}while(lim>0); -if(g->gcstate!=0){ -if(g->gcdept<1024u) -g->GCthreshold=g->totalbytes+1024u; -else{ -g->gcdept-=1024u; -g->GCthreshold=g->totalbytes; -} -} -else{ -setthreshold(g); -} -} -static void luaC_barrierf(lua_State*L,GCObject*o,GCObject*v){ -global_State*g=G(L); -if(g->gcstate==1) -reallymarkobject(g,v); -else -makewhite(g,o); -} -static void luaC_barrierback(lua_State*L,Table*t){ -global_State*g=G(L); -GCObject*o=obj2gco(t); -black2gray(o); -t->gclist=g->grayagain; -g->grayagain=o; -} -static void luaC_link(lua_State*L,GCObject*o,lu_byte tt){ -global_State*g=G(L); -o->gch.next=g->rootgc; -g->rootgc=o; -o->gch.marked=luaC_white(g); -o->gch.tt=tt; -} -static void luaC_linkupval(lua_State*L,UpVal*uv){ -global_State*g=G(L); -GCObject*o=obj2gco(uv); -o->gch.next=g->rootgc; -g->rootgc=o; -if(isgray(o)){ -if(g->gcstate==1){ -gray2black(o); -luaC_barrier(L,uv,uv->v); -} -else{ -makewhite(g,o); -} -} -} -typedef union{ -lua_Number r; -TString*ts; -}SemInfo; -typedef struct Token{ -int token; -SemInfo seminfo; -}Token; -typedef struct LexState{ -int current; -int linenumber; -int lastline; -Token t; -Token lookahead; -struct FuncState*fs; -struct lua_State*L; -ZIO*z; -Mbuffer*buff; -TString*source; -char decpoint; -}LexState; -static void luaX_init(lua_State*L); -static void luaX_lexerror(LexState*ls,const char*msg,int token); -#define state_size(x)(sizeof(x)+0) -#define fromstate(l)(cast(lu_byte*,(l))-0) -#define tostate(l)(cast(lua_State*,cast(lu_byte*,l)+0)) -typedef struct LG{ -lua_State l; -global_State g; -}LG; -static void stack_init(lua_State*L1,lua_State*L){ -L1->base_ci=luaM_newvector(L,8,CallInfo); -L1->ci=L1->base_ci; -L1->size_ci=8; -L1->end_ci=L1->base_ci+L1->size_ci-1; -L1->stack=luaM_newvector(L,(2*20)+5,TValue); -L1->stacksize=(2*20)+5; -L1->top=L1->stack; -L1->stack_last=L1->stack+(L1->stacksize-5)-1; -L1->ci->func=L1->top; -setnilvalue(L1->top++); -L1->base=L1->ci->base=L1->top; -L1->ci->top=L1->top+20; -} -static void freestack(lua_State*L,lua_State*L1){ -luaM_freearray(L,L1->base_ci,L1->size_ci,CallInfo); -luaM_freearray(L,L1->stack,L1->stacksize,TValue); -} -static void f_luaopen(lua_State*L,void*ud){ -global_State*g=G(L); -UNUSED(ud); -stack_init(L,L); -sethvalue(L,gt(L),luaH_new(L,0,2)); -sethvalue(L,registry(L),luaH_new(L,0,2)); -luaS_resize(L,32); -luaT_init(L); -luaX_init(L); -luaS_fix(luaS_newliteral(L,"not enough memory")); -g->GCthreshold=4*g->totalbytes; -} -static void preinit_state(lua_State*L,global_State*g){ -G(L)=g; -L->stack=NULL; -L->stacksize=0; -L->errorJmp=NULL; -L->hook=NULL; -L->hookmask=0; -L->basehookcount=0; -L->allowhook=1; -resethookcount(L); -L->openupval=NULL; -L->size_ci=0; -L->nCcalls=L->baseCcalls=0; -L->status=0; -L->base_ci=L->ci=NULL; -L->savedpc=NULL; -L->errfunc=0; -setnilvalue(gt(L)); -} -static void close_state(lua_State*L){ -global_State*g=G(L); -luaF_close(L,L->stack); -luaC_freeall(L); -luaM_freearray(L,G(L)->strt.hash,G(L)->strt.size,TString*); -luaZ_freebuffer(L,&g->buff); -freestack(L,L); -(*g->frealloc)(g->ud,fromstate(L),state_size(LG),0); -} -static void luaE_freethread(lua_State*L,lua_State*L1){ -luaF_close(L1,L1->stack); -freestack(L,L1); -luaM_freemem(L,fromstate(L1),state_size(lua_State)); -} -static lua_State*lua_newstate(lua_Alloc f,void*ud){ -int i; -lua_State*L; -global_State*g; -void*l=(*f)(ud,NULL,0,state_size(LG)); -if(l==NULL)return NULL; -L=tostate(l); -g=&((LG*)L)->g; -L->next=NULL; -L->tt=8; -g->currentwhite=bit2mask(0,5); -L->marked=luaC_white(g); -set2bits(L->marked,5,6); -preinit_state(L,g); -g->frealloc=f; -g->ud=ud; -g->mainthread=L; -g->uvhead.u.l.prev=&g->uvhead; -g->uvhead.u.l.next=&g->uvhead; -g->GCthreshold=0; -g->strt.size=0; -g->strt.nuse=0; -g->strt.hash=NULL; -setnilvalue(registry(L)); -luaZ_initbuffer(L,&g->buff); -g->panic=NULL; -g->gcstate=0; -g->rootgc=obj2gco(L); -g->sweepstrgc=0; -g->sweepgc=&g->rootgc; -g->gray=NULL; -g->grayagain=NULL; -g->weak=NULL; -g->tmudata=NULL; -g->totalbytes=sizeof(LG); -g->gcpause=200; -g->gcstepmul=200; -g->gcdept=0; -for(i=0;i<(8+1);i++)g->mt[i]=NULL; -if(luaD_rawrunprotected(L,f_luaopen,NULL)!=0){ -close_state(L); -L=NULL; -} -else -{} -return L; -} -static void callallgcTM(lua_State*L,void*ud){ -UNUSED(ud); -luaC_callGCTM(L); -} -static void lua_close(lua_State*L){ -L=G(L)->mainthread; -luaF_close(L,L->stack); -luaC_separateudata(L,1); -L->errfunc=0; -do{ -L->ci=L->base_ci; -L->base=L->top=L->ci->base; -L->nCcalls=L->baseCcalls=0; -}while(luaD_rawrunprotected(L,callallgcTM,NULL)!=0); -close_state(L); -} -#define getcode(fs,e)((fs)->f->code[(e)->u.s.info]) -#define luaK_codeAsBx(fs,o,A,sBx)luaK_codeABx(fs,o,A,(sBx)+(((1<<(9+9))-1)>>1)) -#define luaK_setmultret(fs,e)luaK_setreturns(fs,e,(-1)) -static int luaK_codeABx(FuncState*fs,OpCode o,int A,unsigned int Bx); -static int luaK_codeABC(FuncState*fs,OpCode o,int A,int B,int C); -static void luaK_setreturns(FuncState*fs,expdesc*e,int nresults); -static void luaK_patchtohere(FuncState*fs,int list); -static void luaK_concat(FuncState*fs,int*l1,int l2); -static int currentpc(lua_State*L,CallInfo*ci){ -if(!isLua(ci))return-1; -if(ci==L->ci) -ci->savedpc=L->savedpc; -return pcRel(ci->savedpc,ci_func(ci)->l.p); -} -static int currentline(lua_State*L,CallInfo*ci){ -int pc=currentpc(L,ci); -if(pc<0) -return-1; -else -return getline_(ci_func(ci)->l.p,pc); -} -static int lua_getstack(lua_State*L,int level,lua_Debug*ar){ -int status; -CallInfo*ci; -for(ci=L->ci;level>0&&ci>L->base_ci;ci--){ -level--; -if(f_isLua(ci)) -level-=ci->tailcalls; -} -if(level==0&&ci>L->base_ci){ -status=1; -ar->i_ci=cast_int(ci-L->base_ci); -} -else if(level<0){ -status=1; -ar->i_ci=0; -} -else status=0; -return status; -} -static Proto*getluaproto(CallInfo*ci){ -return(isLua(ci)?ci_func(ci)->l.p:NULL); -} -static void funcinfo(lua_Debug*ar,Closure*cl){ -if(cl->c.isC){ -ar->source="=[C]"; -ar->linedefined=-1; -ar->lastlinedefined=-1; -ar->what="C"; -} -else{ -ar->source=getstr(cl->l.p->source); -ar->linedefined=cl->l.p->linedefined; -ar->lastlinedefined=cl->l.p->lastlinedefined; -ar->what=(ar->linedefined==0)?"main":"Lua"; -} -luaO_chunkid(ar->short_src,ar->source,60); -} -static void info_tailcall(lua_Debug*ar){ -ar->name=ar->namewhat=""; -ar->what="tail"; -ar->lastlinedefined=ar->linedefined=ar->currentline=-1; -ar->source="=(tail call)"; -luaO_chunkid(ar->short_src,ar->source,60); -ar->nups=0; -} -static void collectvalidlines(lua_State*L,Closure*f){ -if(f==NULL||f->c.isC){ -setnilvalue(L->top); -} -else{ -Table*t=luaH_new(L,0,0); -int*lineinfo=f->l.p->lineinfo; -int i; -for(i=0;il.p->sizelineinfo;i++) -setbvalue(luaH_setnum(L,t,lineinfo[i]),1); -sethvalue(L,L->top,t); -} -incr_top(L); -} -static int auxgetinfo(lua_State*L,const char*what,lua_Debug*ar, -Closure*f,CallInfo*ci){ -int status=1; -if(f==NULL){ -info_tailcall(ar); -return status; -} -for(;*what;what++){ -switch(*what){ -case'S':{ -funcinfo(ar,f); -break; -} -case'l':{ -ar->currentline=(ci)?currentline(L,ci):-1; -break; -} -case'u':{ -ar->nups=f->c.nupvalues; -break; -} -case'n':{ -ar->namewhat=(ci)?NULL:NULL; -if(ar->namewhat==NULL){ -ar->namewhat=""; -ar->name=NULL; -} -break; -} -case'L': -case'f': -break; -default:status=0; -} -} -return status; -} -static int lua_getinfo(lua_State*L,const char*what,lua_Debug*ar){ -int status; -Closure*f=NULL; -CallInfo*ci=NULL; -if(*what=='>'){ -StkId func=L->top-1; -luai_apicheck(L,ttisfunction(func)); -what++; -f=clvalue(func); -L->top--; -} -else if(ar->i_ci!=0){ -ci=L->base_ci+ar->i_ci; -f=clvalue(ci->func); -} -status=auxgetinfo(L,what,ar,f,ci); -if(strchr(what,'f')){ -if(f==NULL)setnilvalue(L->top); -else setclvalue(L,L->top,f); -incr_top(L); -} -if(strchr(what,'L')) -collectvalidlines(L,f); -return status; -} -static int isinstack(CallInfo*ci,const TValue*o){ -StkId p; -for(p=ci->base;ptop;p++) -if(o==p)return 1; -return 0; -} -static void luaG_typeerror(lua_State*L,const TValue*o,const char*op){ -const char*name=NULL; -const char*t=luaT_typenames[ttype(o)]; -const char*kind=(isinstack(L->ci,o))? -NULL: -NULL; -if(kind) -luaG_runerror(L,"attempt to %s %s "LUA_QL("%s")" (a %s value)", -op,kind,name,t); -else -luaG_runerror(L,"attempt to %s a %s value",op,t); -} -static void luaG_concaterror(lua_State*L,StkId p1,StkId p2){ -if(ttisstring(p1)||ttisnumber(p1))p1=p2; -luaG_typeerror(L,p1,"concatenate"); -} -static void luaG_aritherror(lua_State*L,const TValue*p1,const TValue*p2){ -TValue temp; -if(luaV_tonumber(p1,&temp)==NULL) -p2=p1; -luaG_typeerror(L,p2,"perform arithmetic on"); -} -static int luaG_ordererror(lua_State*L,const TValue*p1,const TValue*p2){ -const char*t1=luaT_typenames[ttype(p1)]; -const char*t2=luaT_typenames[ttype(p2)]; -if(t1[2]==t2[2]) -luaG_runerror(L,"attempt to compare two %s values",t1); -else -luaG_runerror(L,"attempt to compare %s with %s",t1,t2); -return 0; -} -static void addinfo(lua_State*L,const char*msg){ -CallInfo*ci=L->ci; -if(isLua(ci)){ -char buff[60]; -int line=currentline(L,ci); -luaO_chunkid(buff,getstr(getluaproto(ci)->source),60); -luaO_pushfstring(L,"%s:%d: %s",buff,line,msg); -} -} -static void luaG_errormsg(lua_State*L){ -if(L->errfunc!=0){ -StkId errfunc=restorestack(L,L->errfunc); -if(!ttisfunction(errfunc))luaD_throw(L,5); -setobj(L,L->top,L->top-1); -setobj(L,L->top-1,errfunc); -incr_top(L); -luaD_call(L,L->top-2,1); -} -luaD_throw(L,2); -} -static void luaG_runerror(lua_State*L,const char*fmt,...){ -va_list argp; -va_start(argp,fmt); -addinfo(L,luaO_pushvfstring(L,fmt,argp)); -va_end(argp); -luaG_errormsg(L); -} -static int luaZ_fill(ZIO*z){ -size_t size; -lua_State*L=z->L; -const char*buff; -buff=z->reader(L,z->data,&size); -if(buff==NULL||size==0)return(-1); -z->n=size-1; -z->p=buff; -return char2int(*(z->p++)); -} -static void luaZ_init(lua_State*L,ZIO*z,lua_Reader reader,void*data){ -z->L=L; -z->reader=reader; -z->data=data; -z->n=0; -z->p=NULL; -} -static char*luaZ_openspace(lua_State*L,Mbuffer*buff,size_t n){ -if(n>buff->buffsize){ -if(n<32)n=32; -luaZ_resizebuffer(L,buff,n); -} -return buff->buffer; -} -#define opmode(t,a,b,c,m)(((t)<<7)|((a)<<6)|((b)<<4)|((c)<<2)|(m)) -static const lu_byte luaP_opmodes[(cast(int,OP_VARARG)+1)]={ -opmode(0,1,OpArgR,OpArgN,iABC) -,opmode(0,1,OpArgK,OpArgN,iABx) -,opmode(0,1,OpArgU,OpArgU,iABC) -,opmode(0,1,OpArgR,OpArgN,iABC) -,opmode(0,1,OpArgU,OpArgN,iABC) -,opmode(0,1,OpArgK,OpArgN,iABx) -,opmode(0,1,OpArgR,OpArgK,iABC) -,opmode(0,0,OpArgK,OpArgN,iABx) -,opmode(0,0,OpArgU,OpArgN,iABC) -,opmode(0,0,OpArgK,OpArgK,iABC) -,opmode(0,1,OpArgU,OpArgU,iABC) -,opmode(0,1,OpArgR,OpArgK,iABC) -,opmode(0,1,OpArgK,OpArgK,iABC) -,opmode(0,1,OpArgK,OpArgK,iABC) -,opmode(0,1,OpArgK,OpArgK,iABC) -,opmode(0,1,OpArgK,OpArgK,iABC) -,opmode(0,1,OpArgK,OpArgK,iABC) -,opmode(0,1,OpArgK,OpArgK,iABC) -,opmode(0,1,OpArgR,OpArgN,iABC) -,opmode(0,1,OpArgR,OpArgN,iABC) -,opmode(0,1,OpArgR,OpArgN,iABC) -,opmode(0,1,OpArgR,OpArgR,iABC) -,opmode(0,0,OpArgR,OpArgN,iAsBx) -,opmode(1,0,OpArgK,OpArgK,iABC) -,opmode(1,0,OpArgK,OpArgK,iABC) -,opmode(1,0,OpArgK,OpArgK,iABC) -,opmode(1,1,OpArgR,OpArgU,iABC) -,opmode(1,1,OpArgR,OpArgU,iABC) -,opmode(0,1,OpArgU,OpArgU,iABC) -,opmode(0,1,OpArgU,OpArgU,iABC) -,opmode(0,0,OpArgU,OpArgN,iABC) -,opmode(0,1,OpArgR,OpArgN,iAsBx) -,opmode(0,1,OpArgR,OpArgN,iAsBx) -,opmode(1,0,OpArgN,OpArgU,iABC) -,opmode(0,0,OpArgU,OpArgU,iABC) -,opmode(0,0,OpArgN,OpArgN,iABC) -,opmode(0,1,OpArgU,OpArgN,iABx) -,opmode(0,1,OpArgU,OpArgN,iABC) -}; -#define next(ls)(ls->current=zgetc(ls->z)) -#define currIsNewline(ls)(ls->current=='\n'||ls->current=='\r') -static const char*const luaX_tokens[]={ -"and","break","do","else","elseif", -"end","false","for","function","if", -"in","local","nil","not","or","repeat", -"return","then","true","until","while", -"..","...","==",">=","<=","~=", -"","","","", -NULL -}; -#define save_and_next(ls)(save(ls,ls->current),next(ls)) -static void save(LexState*ls,int c){ -Mbuffer*b=ls->buff; -if(b->n+1>b->buffsize){ -size_t newsize; -if(b->buffsize>=((size_t)(~(size_t)0)-2)/2) -luaX_lexerror(ls,"lexical element too long",0); -newsize=b->buffsize*2; -luaZ_resizebuffer(ls->L,b,newsize); -} -b->buffer[b->n++]=cast(char,c); -} -static void luaX_init(lua_State*L){ -int i; -for(i=0;i<(cast(int,TK_WHILE-257+1));i++){ -TString*ts=luaS_new(L,luaX_tokens[i]); -luaS_fix(ts); -ts->tsv.reserved=cast_byte(i+1); -} -} -static const char*luaX_token2str(LexState*ls,int token){ -if(token<257){ -return(iscntrl(token))?luaO_pushfstring(ls->L,"char(%d)",token): -luaO_pushfstring(ls->L,"%c",token); -} -else -return luaX_tokens[token-257]; -} -static const char*txtToken(LexState*ls,int token){ -switch(token){ -case TK_NAME: -case TK_STRING: -case TK_NUMBER: -save(ls,'\0'); -return luaZ_buffer(ls->buff); -default: -return luaX_token2str(ls,token); -} -} -static void luaX_lexerror(LexState*ls,const char*msg,int token){ -char buff[80]; -luaO_chunkid(buff,getstr(ls->source),80); -msg=luaO_pushfstring(ls->L,"%s:%d: %s",buff,ls->linenumber,msg); -if(token) -luaO_pushfstring(ls->L,"%s near "LUA_QL("%s"),msg,txtToken(ls,token)); -luaD_throw(ls->L,3); -} -static void luaX_syntaxerror(LexState*ls,const char*msg){ -luaX_lexerror(ls,msg,ls->t.token); -} -static TString*luaX_newstring(LexState*ls,const char*str,size_t l){ -lua_State*L=ls->L; -TString*ts=luaS_newlstr(L,str,l); -TValue*o=luaH_setstr(L,ls->fs->h,ts); -if(ttisnil(o)){ -setbvalue(o,1); -luaC_checkGC(L); -} -return ts; -} -static void inclinenumber(LexState*ls){ -int old=ls->current; -next(ls); -if(currIsNewline(ls)&&ls->current!=old) -next(ls); -if(++ls->linenumber>=(INT_MAX-2)) -luaX_syntaxerror(ls,"chunk has too many lines"); -} -static void luaX_setinput(lua_State*L,LexState*ls,ZIO*z,TString*source){ -ls->decpoint='.'; -ls->L=L; -ls->lookahead.token=TK_EOS; -ls->z=z; -ls->fs=NULL; -ls->linenumber=1; -ls->lastline=1; -ls->source=source; -luaZ_resizebuffer(ls->L,ls->buff,32); -next(ls); -} -static int check_next(LexState*ls,const char*set){ -if(!strchr(set,ls->current)) -return 0; -save_and_next(ls); -return 1; -} -static void buffreplace(LexState*ls,char from,char to){ -size_t n=luaZ_bufflen(ls->buff); -char*p=luaZ_buffer(ls->buff); -while(n--) -if(p[n]==from)p[n]=to; -} -static void read_numeral(LexState*ls,SemInfo*seminfo){ -do{ -save_and_next(ls); -}while(isdigit(ls->current)||ls->current=='.'); -if(check_next(ls,"Ee")) -check_next(ls,"+-"); -while(isalnum(ls->current)||ls->current=='_') -save_and_next(ls); -save(ls,'\0'); -buffreplace(ls,'.',ls->decpoint); -if(!luaO_str2d(luaZ_buffer(ls->buff),&seminfo->r)) -luaX_lexerror(ls,"malformed number",TK_NUMBER); -} -static int skip_sep(LexState*ls){ -int count=0; -int s=ls->current; -save_and_next(ls); -while(ls->current=='='){ -save_and_next(ls); -count++; -} -return(ls->current==s)?count:(-count)-1; -} -static void read_long_string(LexState*ls,SemInfo*seminfo,int sep){ -int cont=0; -(void)(cont); -save_and_next(ls); -if(currIsNewline(ls)) -inclinenumber(ls); -for(;;){ -switch(ls->current){ -case(-1): -luaX_lexerror(ls,(seminfo)?"unfinished long string": -"unfinished long comment",TK_EOS); -break; -case']':{ -if(skip_sep(ls)==sep){ -save_and_next(ls); -goto endloop; -} -break; -} -case'\n': -case'\r':{ -save(ls,'\n'); -inclinenumber(ls); -if(!seminfo)luaZ_resetbuffer(ls->buff); -break; -} -default:{ -if(seminfo)save_and_next(ls); -else next(ls); -} -} -}endloop: -if(seminfo) -seminfo->ts=luaX_newstring(ls,luaZ_buffer(ls->buff)+(2+sep), -luaZ_bufflen(ls->buff)-2*(2+sep)); -} -static void read_string(LexState*ls,int del,SemInfo*seminfo){ -save_and_next(ls); -while(ls->current!=del){ -switch(ls->current){ -case(-1): -luaX_lexerror(ls,"unfinished string",TK_EOS); -continue; -case'\n': -case'\r': -luaX_lexerror(ls,"unfinished string",TK_STRING); -continue; -case'\\':{ -int c; -next(ls); -switch(ls->current){ -case'a':c='\a';break; -case'b':c='\b';break; -case'f':c='\f';break; -case'n':c='\n';break; -case'r':c='\r';break; -case't':c='\t';break; -case'v':c='\v';break; -case'\n': -case'\r':save(ls,'\n');inclinenumber(ls);continue; -case(-1):continue; -default:{ -if(!isdigit(ls->current)) -save_and_next(ls); -else{ -int i=0; -c=0; -do{ -c=10*c+(ls->current-'0'); -next(ls); -}while(++i<3&&isdigit(ls->current)); -if(c>UCHAR_MAX) -luaX_lexerror(ls,"escape sequence too large",TK_STRING); -save(ls,c); -} -continue; -} -} -save(ls,c); -next(ls); -continue; -} -default: -save_and_next(ls); -} -} -save_and_next(ls); -seminfo->ts=luaX_newstring(ls,luaZ_buffer(ls->buff)+1, -luaZ_bufflen(ls->buff)-2); -} -static int llex(LexState*ls,SemInfo*seminfo){ -luaZ_resetbuffer(ls->buff); -for(;;){ -switch(ls->current){ -case'\n': -case'\r':{ -inclinenumber(ls); -continue; -} -case'-':{ -next(ls); -if(ls->current!='-')return'-'; -next(ls); -if(ls->current=='['){ -int sep=skip_sep(ls); -luaZ_resetbuffer(ls->buff); -if(sep>=0){ -read_long_string(ls,NULL,sep); -luaZ_resetbuffer(ls->buff); -continue; -} -} -while(!currIsNewline(ls)&&ls->current!=(-1)) -next(ls); -continue; -} -case'[':{ -int sep=skip_sep(ls); -if(sep>=0){ -read_long_string(ls,seminfo,sep); -return TK_STRING; -} -else if(sep==-1)return'['; -else luaX_lexerror(ls,"invalid long string delimiter",TK_STRING); -} -case'=':{ -next(ls); -if(ls->current!='=')return'='; -else{next(ls);return TK_EQ;} -} -case'<':{ -next(ls); -if(ls->current!='=')return'<'; -else{next(ls);return TK_LE;} -} -case'>':{ -next(ls); -if(ls->current!='=')return'>'; -else{next(ls);return TK_GE;} -} -case'~':{ -next(ls); -if(ls->current!='=')return'~'; -else{next(ls);return TK_NE;} -} -case'"': -case'\'':{ -read_string(ls,ls->current,seminfo); -return TK_STRING; -} -case'.':{ -save_and_next(ls); -if(check_next(ls,".")){ -if(check_next(ls,".")) -return TK_DOTS; -else return TK_CONCAT; -} -else if(!isdigit(ls->current))return'.'; -else{ -read_numeral(ls,seminfo); -return TK_NUMBER; -} -} -case(-1):{ -return TK_EOS; -} -default:{ -if(isspace(ls->current)){ -next(ls); -continue; -} -else if(isdigit(ls->current)){ -read_numeral(ls,seminfo); -return TK_NUMBER; -} -else if(isalpha(ls->current)||ls->current=='_'){ -TString*ts; -do{ -save_and_next(ls); -}while(isalnum(ls->current)||ls->current=='_'); -ts=luaX_newstring(ls,luaZ_buffer(ls->buff), -luaZ_bufflen(ls->buff)); -if(ts->tsv.reserved>0) -return ts->tsv.reserved-1+257; -else{ -seminfo->ts=ts; -return TK_NAME; -} -} -else{ -int c=ls->current; -next(ls); -return c; -} -} -} -} -} -static void luaX_next(LexState*ls){ -ls->lastline=ls->linenumber; -if(ls->lookahead.token!=TK_EOS){ -ls->t=ls->lookahead; -ls->lookahead.token=TK_EOS; -} -else -ls->t.token=llex(ls,&ls->t.seminfo); -} -static void luaX_lookahead(LexState*ls){ -ls->lookahead.token=llex(ls,&ls->lookahead.seminfo); -} -#define hasjumps(e)((e)->t!=(e)->f) -static int isnumeral(expdesc*e){ -return(e->k==VKNUM&&e->t==(-1)&&e->f==(-1)); -} -static void luaK_nil(FuncState*fs,int from,int n){ -Instruction*previous; -if(fs->pc>fs->lasttarget){ -if(fs->pc==0){ -if(from>=fs->nactvar) -return; -} -else{ -previous=&fs->f->code[fs->pc-1]; -if(GET_OPCODE(*previous)==OP_LOADNIL){ -int pfrom=GETARG_A(*previous); -int pto=GETARG_B(*previous); -if(pfrom<=from&&from<=pto+1){ -if(from+n-1>pto) -SETARG_B(*previous,from+n-1); -return; -} -} -} -} -luaK_codeABC(fs,OP_LOADNIL,from,from+n-1,0); -} -static int luaK_jump(FuncState*fs){ -int jpc=fs->jpc; -int j; -fs->jpc=(-1); -j=luaK_codeAsBx(fs,OP_JMP,0,(-1)); -luaK_concat(fs,&j,jpc); -return j; -} -static void luaK_ret(FuncState*fs,int first,int nret){ -luaK_codeABC(fs,OP_RETURN,first,nret+1,0); -} -static int condjump(FuncState*fs,OpCode op,int A,int B,int C){ -luaK_codeABC(fs,op,A,B,C); -return luaK_jump(fs); -} -static void fixjump(FuncState*fs,int pc,int dest){ -Instruction*jmp=&fs->f->code[pc]; -int offset=dest-(pc+1); -if(abs(offset)>(((1<<(9+9))-1)>>1)) -luaX_syntaxerror(fs->ls,"control structure too long"); -SETARG_sBx(*jmp,offset); -} -static int luaK_getlabel(FuncState*fs){ -fs->lasttarget=fs->pc; -return fs->pc; -} -static int getjump(FuncState*fs,int pc){ -int offset=GETARG_sBx(fs->f->code[pc]); -if(offset==(-1)) -return(-1); -else -return(pc+1)+offset; -} -static Instruction*getjumpcontrol(FuncState*fs,int pc){ -Instruction*pi=&fs->f->code[pc]; -if(pc>=1&&testTMode(GET_OPCODE(*(pi-1)))) -return pi-1; -else -return pi; -} -static int need_value(FuncState*fs,int list){ -for(;list!=(-1);list=getjump(fs,list)){ -Instruction i=*getjumpcontrol(fs,list); -if(GET_OPCODE(i)!=OP_TESTSET)return 1; -} -return 0; -} -static int patchtestreg(FuncState*fs,int node,int reg){ -Instruction*i=getjumpcontrol(fs,node); -if(GET_OPCODE(*i)!=OP_TESTSET) -return 0; -if(reg!=((1<<8)-1)&®!=GETARG_B(*i)) -SETARG_A(*i,reg); -else -*i=CREATE_ABC(OP_TEST,GETARG_B(*i),0,GETARG_C(*i)); -return 1; -} -static void removevalues(FuncState*fs,int list){ -for(;list!=(-1);list=getjump(fs,list)) -patchtestreg(fs,list,((1<<8)-1)); -} -static void patchlistaux(FuncState*fs,int list,int vtarget,int reg, -int dtarget){ -while(list!=(-1)){ -int next=getjump(fs,list); -if(patchtestreg(fs,list,reg)) -fixjump(fs,list,vtarget); -else -fixjump(fs,list,dtarget); -list=next; -} -} -static void dischargejpc(FuncState*fs){ -patchlistaux(fs,fs->jpc,fs->pc,((1<<8)-1),fs->pc); -fs->jpc=(-1); -} -static void luaK_patchlist(FuncState*fs,int list,int target){ -if(target==fs->pc) -luaK_patchtohere(fs,list); -else{ -patchlistaux(fs,list,target,((1<<8)-1),target); -} -} -static void luaK_patchtohere(FuncState*fs,int list){ -luaK_getlabel(fs); -luaK_concat(fs,&fs->jpc,list); -} -static void luaK_concat(FuncState*fs,int*l1,int l2){ -if(l2==(-1))return; -else if(*l1==(-1)) -*l1=l2; -else{ -int list=*l1; -int next; -while((next=getjump(fs,list))!=(-1)) -list=next; -fixjump(fs,list,l2); -} -} -static void luaK_checkstack(FuncState*fs,int n){ -int newstack=fs->freereg+n; -if(newstack>fs->f->maxstacksize){ -if(newstack>=250) -luaX_syntaxerror(fs->ls,"function or expression too complex"); -fs->f->maxstacksize=cast_byte(newstack); -} -} -static void luaK_reserveregs(FuncState*fs,int n){ -luaK_checkstack(fs,n); -fs->freereg+=n; -} -static void freereg(FuncState*fs,int reg){ -if(!ISK(reg)&®>=fs->nactvar){ -fs->freereg--; -} -} -static void freeexp(FuncState*fs,expdesc*e){ -if(e->k==VNONRELOC) -freereg(fs,e->u.s.info); -} -static int addk(FuncState*fs,TValue*k,TValue*v){ -lua_State*L=fs->L; -TValue*idx=luaH_set(L,fs->h,k); -Proto*f=fs->f; -int oldsize=f->sizek; -if(ttisnumber(idx)){ -return cast_int(nvalue(idx)); -} -else{ -setnvalue(idx,cast_num(fs->nk)); -luaM_growvector(L,f->k,fs->nk,f->sizek,TValue, -((1<<(9+9))-1),"constant table overflow"); -while(oldsizesizek)setnilvalue(&f->k[oldsize++]); -setobj(L,&f->k[fs->nk],v); -luaC_barrier(L,f,v); -return fs->nk++; -} -} -static int luaK_stringK(FuncState*fs,TString*s){ -TValue o; -setsvalue(fs->L,&o,s); -return addk(fs,&o,&o); -} -static int luaK_numberK(FuncState*fs,lua_Number r){ -TValue o; -setnvalue(&o,r); -return addk(fs,&o,&o); -} -static int boolK(FuncState*fs,int b){ -TValue o; -setbvalue(&o,b); -return addk(fs,&o,&o); -} -static int nilK(FuncState*fs){ -TValue k,v; -setnilvalue(&v); -sethvalue(fs->L,&k,fs->h); -return addk(fs,&k,&v); -} -static void luaK_setreturns(FuncState*fs,expdesc*e,int nresults){ -if(e->k==VCALL){ -SETARG_C(getcode(fs,e),nresults+1); -} -else if(e->k==VVARARG){ -SETARG_B(getcode(fs,e),nresults+1); -SETARG_A(getcode(fs,e),fs->freereg); -luaK_reserveregs(fs,1); -} -} -static void luaK_setoneret(FuncState*fs,expdesc*e){ -if(e->k==VCALL){ -e->k=VNONRELOC; -e->u.s.info=GETARG_A(getcode(fs,e)); -} -else if(e->k==VVARARG){ -SETARG_B(getcode(fs,e),2); -e->k=VRELOCABLE; -} -} -static void luaK_dischargevars(FuncState*fs,expdesc*e){ -switch(e->k){ -case VLOCAL:{ -e->k=VNONRELOC; -break; -} -case VUPVAL:{ -e->u.s.info=luaK_codeABC(fs,OP_GETUPVAL,0,e->u.s.info,0); -e->k=VRELOCABLE; -break; -} -case VGLOBAL:{ -e->u.s.info=luaK_codeABx(fs,OP_GETGLOBAL,0,e->u.s.info); -e->k=VRELOCABLE; -break; -} -case VINDEXED:{ -freereg(fs,e->u.s.aux); -freereg(fs,e->u.s.info); -e->u.s.info=luaK_codeABC(fs,OP_GETTABLE,0,e->u.s.info,e->u.s.aux); -e->k=VRELOCABLE; -break; -} -case VVARARG: -case VCALL:{ -luaK_setoneret(fs,e); -break; -} -default:break; -} -} -static int code_label(FuncState*fs,int A,int b,int jump){ -luaK_getlabel(fs); -return luaK_codeABC(fs,OP_LOADBOOL,A,b,jump); -} -static void discharge2reg(FuncState*fs,expdesc*e,int reg){ -luaK_dischargevars(fs,e); -switch(e->k){ -case VNIL:{ -luaK_nil(fs,reg,1); -break; -} -case VFALSE:case VTRUE:{ -luaK_codeABC(fs,OP_LOADBOOL,reg,e->k==VTRUE,0); -break; -} -case VK:{ -luaK_codeABx(fs,OP_LOADK,reg,e->u.s.info); -break; -} -case VKNUM:{ -luaK_codeABx(fs,OP_LOADK,reg,luaK_numberK(fs,e->u.nval)); -break; -} -case VRELOCABLE:{ -Instruction*pc=&getcode(fs,e); -SETARG_A(*pc,reg); -break; -} -case VNONRELOC:{ -if(reg!=e->u.s.info) -luaK_codeABC(fs,OP_MOVE,reg,e->u.s.info,0); -break; -} -default:{ -return; -} -} -e->u.s.info=reg; -e->k=VNONRELOC; -} -static void discharge2anyreg(FuncState*fs,expdesc*e){ -if(e->k!=VNONRELOC){ -luaK_reserveregs(fs,1); -discharge2reg(fs,e,fs->freereg-1); -} -} -static void exp2reg(FuncState*fs,expdesc*e,int reg){ -discharge2reg(fs,e,reg); -if(e->k==VJMP) -luaK_concat(fs,&e->t,e->u.s.info); -if(hasjumps(e)){ -int final; -int p_f=(-1); -int p_t=(-1); -if(need_value(fs,e->t)||need_value(fs,e->f)){ -int fj=(e->k==VJMP)?(-1):luaK_jump(fs); -p_f=code_label(fs,reg,0,1); -p_t=code_label(fs,reg,1,0); -luaK_patchtohere(fs,fj); -} -final=luaK_getlabel(fs); -patchlistaux(fs,e->f,final,reg,p_f); -patchlistaux(fs,e->t,final,reg,p_t); -} -e->f=e->t=(-1); -e->u.s.info=reg; -e->k=VNONRELOC; -} -static void luaK_exp2nextreg(FuncState*fs,expdesc*e){ -luaK_dischargevars(fs,e); -freeexp(fs,e); -luaK_reserveregs(fs,1); -exp2reg(fs,e,fs->freereg-1); -} -static int luaK_exp2anyreg(FuncState*fs,expdesc*e){ -luaK_dischargevars(fs,e); -if(e->k==VNONRELOC){ -if(!hasjumps(e))return e->u.s.info; -if(e->u.s.info>=fs->nactvar){ -exp2reg(fs,e,e->u.s.info); -return e->u.s.info; -} -} -luaK_exp2nextreg(fs,e); -return e->u.s.info; -} -static void luaK_exp2val(FuncState*fs,expdesc*e){ -if(hasjumps(e)) -luaK_exp2anyreg(fs,e); -else -luaK_dischargevars(fs,e); -} -static int luaK_exp2RK(FuncState*fs,expdesc*e){ -luaK_exp2val(fs,e); -switch(e->k){ -case VKNUM: -case VTRUE: -case VFALSE: -case VNIL:{ -if(fs->nk<=((1<<(9-1))-1)){ -e->u.s.info=(e->k==VNIL)?nilK(fs): -(e->k==VKNUM)?luaK_numberK(fs,e->u.nval): -boolK(fs,(e->k==VTRUE)); -e->k=VK; -return RKASK(e->u.s.info); -} -else break; -} -case VK:{ -if(e->u.s.info<=((1<<(9-1))-1)) -return RKASK(e->u.s.info); -else break; -} -default:break; -} -return luaK_exp2anyreg(fs,e); -} -static void luaK_storevar(FuncState*fs,expdesc*var,expdesc*ex){ -switch(var->k){ -case VLOCAL:{ -freeexp(fs,ex); -exp2reg(fs,ex,var->u.s.info); -return; -} -case VUPVAL:{ -int e=luaK_exp2anyreg(fs,ex); -luaK_codeABC(fs,OP_SETUPVAL,e,var->u.s.info,0); -break; -} -case VGLOBAL:{ -int e=luaK_exp2anyreg(fs,ex); -luaK_codeABx(fs,OP_SETGLOBAL,e,var->u.s.info); -break; -} -case VINDEXED:{ -int e=luaK_exp2RK(fs,ex); -luaK_codeABC(fs,OP_SETTABLE,var->u.s.info,var->u.s.aux,e); -break; -} -default:{ -break; -} -} -freeexp(fs,ex); -} -static void luaK_self(FuncState*fs,expdesc*e,expdesc*key){ -int func; -luaK_exp2anyreg(fs,e); -freeexp(fs,e); -func=fs->freereg; -luaK_reserveregs(fs,2); -luaK_codeABC(fs,OP_SELF,func,e->u.s.info,luaK_exp2RK(fs,key)); -freeexp(fs,key); -e->u.s.info=func; -e->k=VNONRELOC; -} -static void invertjump(FuncState*fs,expdesc*e){ -Instruction*pc=getjumpcontrol(fs,e->u.s.info); -SETARG_A(*pc,!(GETARG_A(*pc))); -} -static int jumponcond(FuncState*fs,expdesc*e,int cond){ -if(e->k==VRELOCABLE){ -Instruction ie=getcode(fs,e); -if(GET_OPCODE(ie)==OP_NOT){ -fs->pc--; -return condjump(fs,OP_TEST,GETARG_B(ie),0,!cond); -} -} -discharge2anyreg(fs,e); -freeexp(fs,e); -return condjump(fs,OP_TESTSET,((1<<8)-1),e->u.s.info,cond); -} -static void luaK_goiftrue(FuncState*fs,expdesc*e){ -int pc; -luaK_dischargevars(fs,e); -switch(e->k){ -case VK:case VKNUM:case VTRUE:{ -pc=(-1); -break; -} -case VJMP:{ -invertjump(fs,e); -pc=e->u.s.info; -break; -} -default:{ -pc=jumponcond(fs,e,0); -break; -} -} -luaK_concat(fs,&e->f,pc); -luaK_patchtohere(fs,e->t); -e->t=(-1); -} -static void luaK_goiffalse(FuncState*fs,expdesc*e){ -int pc; -luaK_dischargevars(fs,e); -switch(e->k){ -case VNIL:case VFALSE:{ -pc=(-1); -break; -} -case VJMP:{ -pc=e->u.s.info; -break; -} -default:{ -pc=jumponcond(fs,e,1); -break; -} -} -luaK_concat(fs,&e->t,pc); -luaK_patchtohere(fs,e->f); -e->f=(-1); -} -static void codenot(FuncState*fs,expdesc*e){ -luaK_dischargevars(fs,e); -switch(e->k){ -case VNIL:case VFALSE:{ -e->k=VTRUE; -break; -} -case VK:case VKNUM:case VTRUE:{ -e->k=VFALSE; -break; -} -case VJMP:{ -invertjump(fs,e); -break; -} -case VRELOCABLE: -case VNONRELOC:{ -discharge2anyreg(fs,e); -freeexp(fs,e); -e->u.s.info=luaK_codeABC(fs,OP_NOT,0,e->u.s.info,0); -e->k=VRELOCABLE; -break; -} -default:{ -break; -} -} -{int temp=e->f;e->f=e->t;e->t=temp;} -removevalues(fs,e->f); -removevalues(fs,e->t); -} -static void luaK_indexed(FuncState*fs,expdesc*t,expdesc*k){ -t->u.s.aux=luaK_exp2RK(fs,k); -t->k=VINDEXED; -} -static int constfolding(OpCode op,expdesc*e1,expdesc*e2){ -lua_Number v1,v2,r; -if(!isnumeral(e1)||!isnumeral(e2))return 0; -v1=e1->u.nval; -v2=e2->u.nval; -switch(op){ -case OP_ADD:r=luai_numadd(v1,v2);break; -case OP_SUB:r=luai_numsub(v1,v2);break; -case OP_MUL:r=luai_nummul(v1,v2);break; -case OP_DIV: -if(v2==0)return 0; -r=luai_numdiv(v1,v2);break; -case OP_MOD: -if(v2==0)return 0; -r=luai_nummod(v1,v2);break; -case OP_POW:r=luai_numpow(v1,v2);break; -case OP_UNM:r=luai_numunm(v1);break; -case OP_LEN:return 0; -default:r=0;break; -} -if(luai_numisnan(r))return 0; -e1->u.nval=r; -return 1; -} -static void codearith(FuncState*fs,OpCode op,expdesc*e1,expdesc*e2){ -if(constfolding(op,e1,e2)) -return; -else{ -int o2=(op!=OP_UNM&&op!=OP_LEN)?luaK_exp2RK(fs,e2):0; -int o1=luaK_exp2RK(fs,e1); -if(o1>o2){ -freeexp(fs,e1); -freeexp(fs,e2); -} -else{ -freeexp(fs,e2); -freeexp(fs,e1); -} -e1->u.s.info=luaK_codeABC(fs,op,0,o1,o2); -e1->k=VRELOCABLE; -} -} -static void codecomp(FuncState*fs,OpCode op,int cond,expdesc*e1, -expdesc*e2){ -int o1=luaK_exp2RK(fs,e1); -int o2=luaK_exp2RK(fs,e2); -freeexp(fs,e2); -freeexp(fs,e1); -if(cond==0&&op!=OP_EQ){ -int temp; -temp=o1;o1=o2;o2=temp; -cond=1; -} -e1->u.s.info=condjump(fs,op,cond,o1,o2); -e1->k=VJMP; -} -static void luaK_prefix(FuncState*fs,UnOpr op,expdesc*e){ -expdesc e2; -e2.t=e2.f=(-1);e2.k=VKNUM;e2.u.nval=0; -switch(op){ -case OPR_MINUS:{ -if(!isnumeral(e)) -luaK_exp2anyreg(fs,e); -codearith(fs,OP_UNM,e,&e2); -break; -} -case OPR_NOT:codenot(fs,e);break; -case OPR_LEN:{ -luaK_exp2anyreg(fs,e); -codearith(fs,OP_LEN,e,&e2); -break; -} -default:; -} -} -static void luaK_infix(FuncState*fs,BinOpr op,expdesc*v){ -switch(op){ -case OPR_AND:{ -luaK_goiftrue(fs,v); -break; -} -case OPR_OR:{ -luaK_goiffalse(fs,v); -break; -} -case OPR_CONCAT:{ -luaK_exp2nextreg(fs,v); -break; -} -case OPR_ADD:case OPR_SUB:case OPR_MUL:case OPR_DIV: -case OPR_MOD:case OPR_POW:{ -if(!isnumeral(v))luaK_exp2RK(fs,v); -break; -} -default:{ -luaK_exp2RK(fs,v); -break; -} -} -} -static void luaK_posfix(FuncState*fs,BinOpr op,expdesc*e1,expdesc*e2){ -switch(op){ -case OPR_AND:{ -luaK_dischargevars(fs,e2); -luaK_concat(fs,&e2->f,e1->f); -*e1=*e2; -break; -} -case OPR_OR:{ -luaK_dischargevars(fs,e2); -luaK_concat(fs,&e2->t,e1->t); -*e1=*e2; -break; -} -case OPR_CONCAT:{ -luaK_exp2val(fs,e2); -if(e2->k==VRELOCABLE&&GET_OPCODE(getcode(fs,e2))==OP_CONCAT){ -freeexp(fs,e1); -SETARG_B(getcode(fs,e2),e1->u.s.info); -e1->k=VRELOCABLE;e1->u.s.info=e2->u.s.info; -} -else{ -luaK_exp2nextreg(fs,e2); -codearith(fs,OP_CONCAT,e1,e2); -} -break; -} -case OPR_ADD:codearith(fs,OP_ADD,e1,e2);break; -case OPR_SUB:codearith(fs,OP_SUB,e1,e2);break; -case OPR_MUL:codearith(fs,OP_MUL,e1,e2);break; -case OPR_DIV:codearith(fs,OP_DIV,e1,e2);break; -case OPR_MOD:codearith(fs,OP_MOD,e1,e2);break; -case OPR_POW:codearith(fs,OP_POW,e1,e2);break; -case OPR_EQ:codecomp(fs,OP_EQ,1,e1,e2);break; -case OPR_NE:codecomp(fs,OP_EQ,0,e1,e2);break; -case OPR_LT:codecomp(fs,OP_LT,1,e1,e2);break; -case OPR_LE:codecomp(fs,OP_LE,1,e1,e2);break; -case OPR_GT:codecomp(fs,OP_LT,0,e1,e2);break; -case OPR_GE:codecomp(fs,OP_LE,0,e1,e2);break; -default:; -} -} -static void luaK_fixline(FuncState*fs,int line){ -fs->f->lineinfo[fs->pc-1]=line; -} -static int luaK_code(FuncState*fs,Instruction i,int line){ -Proto*f=fs->f; -dischargejpc(fs); -luaM_growvector(fs->L,f->code,fs->pc,f->sizecode,Instruction, -(INT_MAX-2),"code size overflow"); -f->code[fs->pc]=i; -luaM_growvector(fs->L,f->lineinfo,fs->pc,f->sizelineinfo,int, -(INT_MAX-2),"code size overflow"); -f->lineinfo[fs->pc]=line; -return fs->pc++; -} -static int luaK_codeABC(FuncState*fs,OpCode o,int a,int b,int c){ -return luaK_code(fs,CREATE_ABC(o,a,b,c),fs->ls->lastline); -} -static int luaK_codeABx(FuncState*fs,OpCode o,int a,unsigned int bc){ -return luaK_code(fs,CREATE_ABx(o,a,bc),fs->ls->lastline); -} -static void luaK_setlist(FuncState*fs,int base,int nelems,int tostore){ -int c=(nelems-1)/50+1; -int b=(tostore==(-1))?0:tostore; -if(c<=((1<<9)-1)) -luaK_codeABC(fs,OP_SETLIST,base,b,c); -else{ -luaK_codeABC(fs,OP_SETLIST,base,b,0); -luaK_code(fs,cast(Instruction,c),fs->ls->lastline); -} -fs->freereg=base+1; -} -#define hasmultret(k)((k)==VCALL||(k)==VVARARG) -#define getlocvar(fs,i)((fs)->f->locvars[(fs)->actvar[i]]) -#define luaY_checklimit(fs,v,l,m)if((v)>(l))errorlimit(fs,l,m) -typedef struct BlockCnt{ -struct BlockCnt*previous; -int breaklist; -lu_byte nactvar; -lu_byte upval; -lu_byte isbreakable; -}BlockCnt; -static void chunk(LexState*ls); -static void expr(LexState*ls,expdesc*v); -static void anchor_token(LexState*ls){ -if(ls->t.token==TK_NAME||ls->t.token==TK_STRING){ -TString*ts=ls->t.seminfo.ts; -luaX_newstring(ls,getstr(ts),ts->tsv.len); -} -} -static void error_expected(LexState*ls,int token){ -luaX_syntaxerror(ls, -luaO_pushfstring(ls->L,LUA_QL("%s")" expected",luaX_token2str(ls,token))); -} -static void errorlimit(FuncState*fs,int limit,const char*what){ -const char*msg=(fs->f->linedefined==0)? -luaO_pushfstring(fs->L,"main function has more than %d %s",limit,what): -luaO_pushfstring(fs->L,"function at line %d has more than %d %s", -fs->f->linedefined,limit,what); -luaX_lexerror(fs->ls,msg,0); -} -static int testnext(LexState*ls,int c){ -if(ls->t.token==c){ -luaX_next(ls); -return 1; -} -else return 0; -} -static void check(LexState*ls,int c){ -if(ls->t.token!=c) -error_expected(ls,c); -} -static void checknext(LexState*ls,int c){ -check(ls,c); -luaX_next(ls); -} -#define check_condition(ls,c,msg){if(!(c))luaX_syntaxerror(ls,msg);} -static void check_match(LexState*ls,int what,int who,int where){ -if(!testnext(ls,what)){ -if(where==ls->linenumber) -error_expected(ls,what); -else{ -luaX_syntaxerror(ls,luaO_pushfstring(ls->L, -LUA_QL("%s")" expected (to close "LUA_QL("%s")" at line %d)", -luaX_token2str(ls,what),luaX_token2str(ls,who),where)); -} -} -} -static TString*str_checkname(LexState*ls){ -TString*ts; -check(ls,TK_NAME); -ts=ls->t.seminfo.ts; -luaX_next(ls); -return ts; -} -static void init_exp(expdesc*e,expkind k,int i){ -e->f=e->t=(-1); -e->k=k; -e->u.s.info=i; -} -static void codestring(LexState*ls,expdesc*e,TString*s){ -init_exp(e,VK,luaK_stringK(ls->fs,s)); -} -static void checkname(LexState*ls,expdesc*e){ -codestring(ls,e,str_checkname(ls)); -} -static int registerlocalvar(LexState*ls,TString*varname){ -FuncState*fs=ls->fs; -Proto*f=fs->f; -int oldsize=f->sizelocvars; -luaM_growvector(ls->L,f->locvars,fs->nlocvars,f->sizelocvars, -LocVar,SHRT_MAX,"too many local variables"); -while(oldsizesizelocvars)f->locvars[oldsize++].varname=NULL; -f->locvars[fs->nlocvars].varname=varname; -luaC_objbarrier(ls->L,f,varname); -return fs->nlocvars++; -} -#define new_localvarliteral(ls,v,n)new_localvar(ls,luaX_newstring(ls,""v,(sizeof(v)/sizeof(char))-1),n) -static void new_localvar(LexState*ls,TString*name,int n){ -FuncState*fs=ls->fs; -luaY_checklimit(fs,fs->nactvar+n+1,200,"local variables"); -fs->actvar[fs->nactvar+n]=cast(unsigned short,registerlocalvar(ls,name)); -} -static void adjustlocalvars(LexState*ls,int nvars){ -FuncState*fs=ls->fs; -fs->nactvar=cast_byte(fs->nactvar+nvars); -for(;nvars;nvars--){ -getlocvar(fs,fs->nactvar-nvars).startpc=fs->pc; -} -} -static void removevars(LexState*ls,int tolevel){ -FuncState*fs=ls->fs; -while(fs->nactvar>tolevel) -getlocvar(fs,--fs->nactvar).endpc=fs->pc; -} -static int indexupvalue(FuncState*fs,TString*name,expdesc*v){ -int i; -Proto*f=fs->f; -int oldsize=f->sizeupvalues; -for(i=0;inups;i++){ -if(fs->upvalues[i].k==v->k&&fs->upvalues[i].info==v->u.s.info){ -return i; -} -} -luaY_checklimit(fs,f->nups+1,60,"upvalues"); -luaM_growvector(fs->L,f->upvalues,f->nups,f->sizeupvalues, -TString*,(INT_MAX-2),""); -while(oldsizesizeupvalues)f->upvalues[oldsize++]=NULL; -f->upvalues[f->nups]=name; -luaC_objbarrier(fs->L,f,name); -fs->upvalues[f->nups].k=cast_byte(v->k); -fs->upvalues[f->nups].info=cast_byte(v->u.s.info); -return f->nups++; -} -static int searchvar(FuncState*fs,TString*n){ -int i; -for(i=fs->nactvar-1;i>=0;i--){ -if(n==getlocvar(fs,i).varname) -return i; -} -return-1; -} -static void markupval(FuncState*fs,int level){ -BlockCnt*bl=fs->bl; -while(bl&&bl->nactvar>level)bl=bl->previous; -if(bl)bl->upval=1; -} -static int singlevaraux(FuncState*fs,TString*n,expdesc*var,int base){ -if(fs==NULL){ -init_exp(var,VGLOBAL,((1<<8)-1)); -return VGLOBAL; -} -else{ -int v=searchvar(fs,n); -if(v>=0){ -init_exp(var,VLOCAL,v); -if(!base) -markupval(fs,v); -return VLOCAL; -} -else{ -if(singlevaraux(fs->prev,n,var,0)==VGLOBAL) -return VGLOBAL; -var->u.s.info=indexupvalue(fs,n,var); -var->k=VUPVAL; -return VUPVAL; -} -} -} -static void singlevar(LexState*ls,expdesc*var){ -TString*varname=str_checkname(ls); -FuncState*fs=ls->fs; -if(singlevaraux(fs,varname,var,1)==VGLOBAL) -var->u.s.info=luaK_stringK(fs,varname); -} -static void adjust_assign(LexState*ls,int nvars,int nexps,expdesc*e){ -FuncState*fs=ls->fs; -int extra=nvars-nexps; -if(hasmultret(e->k)){ -extra++; -if(extra<0)extra=0; -luaK_setreturns(fs,e,extra); -if(extra>1)luaK_reserveregs(fs,extra-1); -} -else{ -if(e->k!=VVOID)luaK_exp2nextreg(fs,e); -if(extra>0){ -int reg=fs->freereg; -luaK_reserveregs(fs,extra); -luaK_nil(fs,reg,extra); -} -} -} -static void enterlevel(LexState*ls){ -if(++ls->L->nCcalls>200) -luaX_lexerror(ls,"chunk has too many syntax levels",0); -} -#define leavelevel(ls)((ls)->L->nCcalls--) -static void enterblock(FuncState*fs,BlockCnt*bl,lu_byte isbreakable){ -bl->breaklist=(-1); -bl->isbreakable=isbreakable; -bl->nactvar=fs->nactvar; -bl->upval=0; -bl->previous=fs->bl; -fs->bl=bl; -} -static void leaveblock(FuncState*fs){ -BlockCnt*bl=fs->bl; -fs->bl=bl->previous; -removevars(fs->ls,bl->nactvar); -if(bl->upval) -luaK_codeABC(fs,OP_CLOSE,bl->nactvar,0,0); -fs->freereg=fs->nactvar; -luaK_patchtohere(fs,bl->breaklist); -} -static void pushclosure(LexState*ls,FuncState*func,expdesc*v){ -FuncState*fs=ls->fs; -Proto*f=fs->f; -int oldsize=f->sizep; -int i; -luaM_growvector(ls->L,f->p,fs->np,f->sizep,Proto*, -((1<<(9+9))-1),"constant table overflow"); -while(oldsizesizep)f->p[oldsize++]=NULL; -f->p[fs->np++]=func->f; -luaC_objbarrier(ls->L,f,func->f); -init_exp(v,VRELOCABLE,luaK_codeABx(fs,OP_CLOSURE,0,fs->np-1)); -for(i=0;if->nups;i++){ -OpCode o=(func->upvalues[i].k==VLOCAL)?OP_MOVE:OP_GETUPVAL; -luaK_codeABC(fs,o,0,func->upvalues[i].info,0); -} -} -static void open_func(LexState*ls,FuncState*fs){ -lua_State*L=ls->L; -Proto*f=luaF_newproto(L); -fs->f=f; -fs->prev=ls->fs; -fs->ls=ls; -fs->L=L; -ls->fs=fs; -fs->pc=0; -fs->lasttarget=-1; -fs->jpc=(-1); -fs->freereg=0; -fs->nk=0; -fs->np=0; -fs->nlocvars=0; -fs->nactvar=0; -fs->bl=NULL; -f->source=ls->source; -f->maxstacksize=2; -fs->h=luaH_new(L,0,0); -sethvalue(L,L->top,fs->h); -incr_top(L); -setptvalue(L,L->top,f); -incr_top(L); -} -static void close_func(LexState*ls){ -lua_State*L=ls->L; -FuncState*fs=ls->fs; -Proto*f=fs->f; -removevars(ls,0); -luaK_ret(fs,0,0); -luaM_reallocvector(L,f->code,f->sizecode,fs->pc,Instruction); -f->sizecode=fs->pc; -luaM_reallocvector(L,f->lineinfo,f->sizelineinfo,fs->pc,int); -f->sizelineinfo=fs->pc; -luaM_reallocvector(L,f->k,f->sizek,fs->nk,TValue); -f->sizek=fs->nk; -luaM_reallocvector(L,f->p,f->sizep,fs->np,Proto*); -f->sizep=fs->np; -luaM_reallocvector(L,f->locvars,f->sizelocvars,fs->nlocvars,LocVar); -f->sizelocvars=fs->nlocvars; -luaM_reallocvector(L,f->upvalues,f->sizeupvalues,f->nups,TString*); -f->sizeupvalues=f->nups; -ls->fs=fs->prev; -if(fs)anchor_token(ls); -L->top-=2; -} -static Proto*luaY_parser(lua_State*L,ZIO*z,Mbuffer*buff,const char*name){ -struct LexState lexstate; -struct FuncState funcstate; -lexstate.buff=buff; -luaX_setinput(L,&lexstate,z,luaS_new(L,name)); -open_func(&lexstate,&funcstate); -funcstate.f->is_vararg=2; -luaX_next(&lexstate); -chunk(&lexstate); -check(&lexstate,TK_EOS); -close_func(&lexstate); -return funcstate.f; -} -static void field(LexState*ls,expdesc*v){ -FuncState*fs=ls->fs; -expdesc key; -luaK_exp2anyreg(fs,v); -luaX_next(ls); -checkname(ls,&key); -luaK_indexed(fs,v,&key); -} -static void yindex(LexState*ls,expdesc*v){ -luaX_next(ls); -expr(ls,v); -luaK_exp2val(ls->fs,v); -checknext(ls,']'); -} -struct ConsControl{ -expdesc v; -expdesc*t; -int nh; -int na; -int tostore; -}; -static void recfield(LexState*ls,struct ConsControl*cc){ -FuncState*fs=ls->fs; -int reg=ls->fs->freereg; -expdesc key,val; -int rkkey; -if(ls->t.token==TK_NAME){ -luaY_checklimit(fs,cc->nh,(INT_MAX-2),"items in a constructor"); -checkname(ls,&key); -} -else -yindex(ls,&key); -cc->nh++; -checknext(ls,'='); -rkkey=luaK_exp2RK(fs,&key); -expr(ls,&val); -luaK_codeABC(fs,OP_SETTABLE,cc->t->u.s.info,rkkey,luaK_exp2RK(fs,&val)); -fs->freereg=reg; -} -static void closelistfield(FuncState*fs,struct ConsControl*cc){ -if(cc->v.k==VVOID)return; -luaK_exp2nextreg(fs,&cc->v); -cc->v.k=VVOID; -if(cc->tostore==50){ -luaK_setlist(fs,cc->t->u.s.info,cc->na,cc->tostore); -cc->tostore=0; -} -} -static void lastlistfield(FuncState*fs,struct ConsControl*cc){ -if(cc->tostore==0)return; -if(hasmultret(cc->v.k)){ -luaK_setmultret(fs,&cc->v); -luaK_setlist(fs,cc->t->u.s.info,cc->na,(-1)); -cc->na--; -} -else{ -if(cc->v.k!=VVOID) -luaK_exp2nextreg(fs,&cc->v); -luaK_setlist(fs,cc->t->u.s.info,cc->na,cc->tostore); -} -} -static void listfield(LexState*ls,struct ConsControl*cc){ -expr(ls,&cc->v); -luaY_checklimit(ls->fs,cc->na,(INT_MAX-2),"items in a constructor"); -cc->na++; -cc->tostore++; -} -static void constructor(LexState*ls,expdesc*t){ -FuncState*fs=ls->fs; -int line=ls->linenumber; -int pc=luaK_codeABC(fs,OP_NEWTABLE,0,0,0); -struct ConsControl cc; -cc.na=cc.nh=cc.tostore=0; -cc.t=t; -init_exp(t,VRELOCABLE,pc); -init_exp(&cc.v,VVOID,0); -luaK_exp2nextreg(ls->fs,t); -checknext(ls,'{'); -do{ -if(ls->t.token=='}')break; -closelistfield(fs,&cc); -switch(ls->t.token){ -case TK_NAME:{ -luaX_lookahead(ls); -if(ls->lookahead.token!='=') -listfield(ls,&cc); -else -recfield(ls,&cc); -break; -} -case'[':{ -recfield(ls,&cc); -break; -} -default:{ -listfield(ls,&cc); -break; -} -} -}while(testnext(ls,',')||testnext(ls,';')); -check_match(ls,'}','{',line); -lastlistfield(fs,&cc); -SETARG_B(fs->f->code[pc],luaO_int2fb(cc.na)); -SETARG_C(fs->f->code[pc],luaO_int2fb(cc.nh)); -} -static void parlist(LexState*ls){ -FuncState*fs=ls->fs; -Proto*f=fs->f; -int nparams=0; -f->is_vararg=0; -if(ls->t.token!=')'){ -do{ -switch(ls->t.token){ -case TK_NAME:{ -new_localvar(ls,str_checkname(ls),nparams++); -break; -} -case TK_DOTS:{ -luaX_next(ls); -f->is_vararg|=2; -break; -} -default:luaX_syntaxerror(ls," or "LUA_QL("...")" expected"); -} -}while(!f->is_vararg&&testnext(ls,',')); -} -adjustlocalvars(ls,nparams); -f->numparams=cast_byte(fs->nactvar-(f->is_vararg&1)); -luaK_reserveregs(fs,fs->nactvar); -} -static void body(LexState*ls,expdesc*e,int needself,int line){ -FuncState new_fs; -open_func(ls,&new_fs); -new_fs.f->linedefined=line; -checknext(ls,'('); -if(needself){ -new_localvarliteral(ls,"self",0); -adjustlocalvars(ls,1); -} -parlist(ls); -checknext(ls,')'); -chunk(ls); -new_fs.f->lastlinedefined=ls->linenumber; -check_match(ls,TK_END,TK_FUNCTION,line); -close_func(ls); -pushclosure(ls,&new_fs,e); -} -static int explist1(LexState*ls,expdesc*v){ -int n=1; -expr(ls,v); -while(testnext(ls,',')){ -luaK_exp2nextreg(ls->fs,v); -expr(ls,v); -n++; -} -return n; -} -static void funcargs(LexState*ls,expdesc*f){ -FuncState*fs=ls->fs; -expdesc args; -int base,nparams; -int line=ls->linenumber; -switch(ls->t.token){ -case'(':{ -if(line!=ls->lastline) -luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)"); -luaX_next(ls); -if(ls->t.token==')') -args.k=VVOID; -else{ -explist1(ls,&args); -luaK_setmultret(fs,&args); -} -check_match(ls,')','(',line); -break; -} -case'{':{ -constructor(ls,&args); -break; -} -case TK_STRING:{ -codestring(ls,&args,ls->t.seminfo.ts); -luaX_next(ls); -break; -} -default:{ -luaX_syntaxerror(ls,"function arguments expected"); -return; -} -} -base=f->u.s.info; -if(hasmultret(args.k)) -nparams=(-1); -else{ -if(args.k!=VVOID) -luaK_exp2nextreg(fs,&args); -nparams=fs->freereg-(base+1); -} -init_exp(f,VCALL,luaK_codeABC(fs,OP_CALL,base,nparams+1,2)); -luaK_fixline(fs,line); -fs->freereg=base+1; -} -static void prefixexp(LexState*ls,expdesc*v){ -switch(ls->t.token){ -case'(':{ -int line=ls->linenumber; -luaX_next(ls); -expr(ls,v); -check_match(ls,')','(',line); -luaK_dischargevars(ls->fs,v); -return; -} -case TK_NAME:{ -singlevar(ls,v); -return; -} -default:{ -luaX_syntaxerror(ls,"unexpected symbol"); -return; -} -} -} -static void primaryexp(LexState*ls,expdesc*v){ -FuncState*fs=ls->fs; -prefixexp(ls,v); -for(;;){ -switch(ls->t.token){ -case'.':{ -field(ls,v); -break; -} -case'[':{ -expdesc key; -luaK_exp2anyreg(fs,v); -yindex(ls,&key); -luaK_indexed(fs,v,&key); -break; -} -case':':{ -expdesc key; -luaX_next(ls); -checkname(ls,&key); -luaK_self(fs,v,&key); -funcargs(ls,v); -break; -} -case'(':case TK_STRING:case'{':{ -luaK_exp2nextreg(fs,v); -funcargs(ls,v); -break; -} -default:return; -} -} -} -static void simpleexp(LexState*ls,expdesc*v){ -switch(ls->t.token){ -case TK_NUMBER:{ -init_exp(v,VKNUM,0); -v->u.nval=ls->t.seminfo.r; -break; -} -case TK_STRING:{ -codestring(ls,v,ls->t.seminfo.ts); -break; -} -case TK_NIL:{ -init_exp(v,VNIL,0); -break; -} -case TK_TRUE:{ -init_exp(v,VTRUE,0); -break; -} -case TK_FALSE:{ -init_exp(v,VFALSE,0); -break; -} -case TK_DOTS:{ -FuncState*fs=ls->fs; -check_condition(ls,fs->f->is_vararg, -"cannot use "LUA_QL("...")" outside a vararg function"); -fs->f->is_vararg&=~4; -init_exp(v,VVARARG,luaK_codeABC(fs,OP_VARARG,0,1,0)); -break; -} -case'{':{ -constructor(ls,v); -return; -} -case TK_FUNCTION:{ -luaX_next(ls); -body(ls,v,0,ls->linenumber); -return; -} -default:{ -primaryexp(ls,v); -return; -} -} -luaX_next(ls); -} -static UnOpr getunopr(int op){ -switch(op){ -case TK_NOT:return OPR_NOT; -case'-':return OPR_MINUS; -case'#':return OPR_LEN; -default:return OPR_NOUNOPR; -} -} -static BinOpr getbinopr(int op){ -switch(op){ -case'+':return OPR_ADD; -case'-':return OPR_SUB; -case'*':return OPR_MUL; -case'/':return OPR_DIV; -case'%':return OPR_MOD; -case'^':return OPR_POW; -case TK_CONCAT:return OPR_CONCAT; -case TK_NE:return OPR_NE; -case TK_EQ:return OPR_EQ; -case'<':return OPR_LT; -case TK_LE:return OPR_LE; -case'>':return OPR_GT; -case TK_GE:return OPR_GE; -case TK_AND:return OPR_AND; -case TK_OR:return OPR_OR; -default:return OPR_NOBINOPR; -} -} -static const struct{ -lu_byte left; -lu_byte right; -}priority[]={ -{6,6},{6,6},{7,7},{7,7},{7,7}, -{10,9},{5,4}, -{3,3},{3,3}, -{3,3},{3,3},{3,3},{3,3}, -{2,2},{1,1} -}; -static BinOpr subexpr(LexState*ls,expdesc*v,unsigned int limit){ -BinOpr op; -UnOpr uop; -enterlevel(ls); -uop=getunopr(ls->t.token); -if(uop!=OPR_NOUNOPR){ -luaX_next(ls); -subexpr(ls,v,8); -luaK_prefix(ls->fs,uop,v); -} -else simpleexp(ls,v); -op=getbinopr(ls->t.token); -while(op!=OPR_NOBINOPR&&priority[op].left>limit){ -expdesc v2; -BinOpr nextop; -luaX_next(ls); -luaK_infix(ls->fs,op,v); -nextop=subexpr(ls,&v2,priority[op].right); -luaK_posfix(ls->fs,op,v,&v2); -op=nextop; -} -leavelevel(ls); -return op; -} -static void expr(LexState*ls,expdesc*v){ -subexpr(ls,v,0); -} -static int block_follow(int token){ -switch(token){ -case TK_ELSE:case TK_ELSEIF:case TK_END: -case TK_UNTIL:case TK_EOS: -return 1; -default:return 0; -} -} -static void block(LexState*ls){ -FuncState*fs=ls->fs; -BlockCnt bl; -enterblock(fs,&bl,0); -chunk(ls); -leaveblock(fs); -} -struct LHS_assign{ -struct LHS_assign*prev; -expdesc v; -}; -static void check_conflict(LexState*ls,struct LHS_assign*lh,expdesc*v){ -FuncState*fs=ls->fs; -int extra=fs->freereg; -int conflict=0; -for(;lh;lh=lh->prev){ -if(lh->v.k==VINDEXED){ -if(lh->v.u.s.info==v->u.s.info){ -conflict=1; -lh->v.u.s.info=extra; -} -if(lh->v.u.s.aux==v->u.s.info){ -conflict=1; -lh->v.u.s.aux=extra; -} -} -} -if(conflict){ -luaK_codeABC(fs,OP_MOVE,fs->freereg,v->u.s.info,0); -luaK_reserveregs(fs,1); -} -} -static void assignment(LexState*ls,struct LHS_assign*lh,int nvars){ -expdesc e; -check_condition(ls,VLOCAL<=lh->v.k&&lh->v.k<=VINDEXED, -"syntax error"); -if(testnext(ls,',')){ -struct LHS_assign nv; -nv.prev=lh; -primaryexp(ls,&nv.v); -if(nv.v.k==VLOCAL) -check_conflict(ls,lh,&nv.v); -luaY_checklimit(ls->fs,nvars,200-ls->L->nCcalls, -"variables in assignment"); -assignment(ls,&nv,nvars+1); -} -else{ -int nexps; -checknext(ls,'='); -nexps=explist1(ls,&e); -if(nexps!=nvars){ -adjust_assign(ls,nvars,nexps,&e); -if(nexps>nvars) -ls->fs->freereg-=nexps-nvars; -} -else{ -luaK_setoneret(ls->fs,&e); -luaK_storevar(ls->fs,&lh->v,&e); -return; -} -} -init_exp(&e,VNONRELOC,ls->fs->freereg-1); -luaK_storevar(ls->fs,&lh->v,&e); -} -static int cond(LexState*ls){ -expdesc v; -expr(ls,&v); -if(v.k==VNIL)v.k=VFALSE; -luaK_goiftrue(ls->fs,&v); -return v.f; -} -static void breakstat(LexState*ls){ -FuncState*fs=ls->fs; -BlockCnt*bl=fs->bl; -int upval=0; -while(bl&&!bl->isbreakable){ -upval|=bl->upval; -bl=bl->previous; -} -if(!bl) -luaX_syntaxerror(ls,"no loop to break"); -if(upval) -luaK_codeABC(fs,OP_CLOSE,bl->nactvar,0,0); -luaK_concat(fs,&bl->breaklist,luaK_jump(fs)); -} -static void whilestat(LexState*ls,int line){ -FuncState*fs=ls->fs; -int whileinit; -int condexit; -BlockCnt bl; -luaX_next(ls); -whileinit=luaK_getlabel(fs); -condexit=cond(ls); -enterblock(fs,&bl,1); -checknext(ls,TK_DO); -block(ls); -luaK_patchlist(fs,luaK_jump(fs),whileinit); -check_match(ls,TK_END,TK_WHILE,line); -leaveblock(fs); -luaK_patchtohere(fs,condexit); -} -static void repeatstat(LexState*ls,int line){ -int condexit; -FuncState*fs=ls->fs; -int repeat_init=luaK_getlabel(fs); -BlockCnt bl1,bl2; -enterblock(fs,&bl1,1); -enterblock(fs,&bl2,0); -luaX_next(ls); -chunk(ls); -check_match(ls,TK_UNTIL,TK_REPEAT,line); -condexit=cond(ls); -if(!bl2.upval){ -leaveblock(fs); -luaK_patchlist(ls->fs,condexit,repeat_init); -} -else{ -breakstat(ls); -luaK_patchtohere(ls->fs,condexit); -leaveblock(fs); -luaK_patchlist(ls->fs,luaK_jump(fs),repeat_init); -} -leaveblock(fs); -} -static int exp1(LexState*ls){ -expdesc e; -int k; -expr(ls,&e); -k=e.k; -luaK_exp2nextreg(ls->fs,&e); -return k; -} -static void forbody(LexState*ls,int base,int line,int nvars,int isnum){ -BlockCnt bl; -FuncState*fs=ls->fs; -int prep,endfor; -adjustlocalvars(ls,3); -checknext(ls,TK_DO); -prep=isnum?luaK_codeAsBx(fs,OP_FORPREP,base,(-1)):luaK_jump(fs); -enterblock(fs,&bl,0); -adjustlocalvars(ls,nvars); -luaK_reserveregs(fs,nvars); -block(ls); -leaveblock(fs); -luaK_patchtohere(fs,prep); -endfor=(isnum)?luaK_codeAsBx(fs,OP_FORLOOP,base,(-1)): -luaK_codeABC(fs,OP_TFORLOOP,base,0,nvars); -luaK_fixline(fs,line); -luaK_patchlist(fs,(isnum?endfor:luaK_jump(fs)),prep+1); -} -static void fornum(LexState*ls,TString*varname,int line){ -FuncState*fs=ls->fs; -int base=fs->freereg; -new_localvarliteral(ls,"(for index)",0); -new_localvarliteral(ls,"(for limit)",1); -new_localvarliteral(ls,"(for step)",2); -new_localvar(ls,varname,3); -checknext(ls,'='); -exp1(ls); -checknext(ls,','); -exp1(ls); -if(testnext(ls,',')) -exp1(ls); -else{ -luaK_codeABx(fs,OP_LOADK,fs->freereg,luaK_numberK(fs,1)); -luaK_reserveregs(fs,1); -} -forbody(ls,base,line,1,1); -} -static void forlist(LexState*ls,TString*indexname){ -FuncState*fs=ls->fs; -expdesc e; -int nvars=0; -int line; -int base=fs->freereg; -new_localvarliteral(ls,"(for generator)",nvars++); -new_localvarliteral(ls,"(for state)",nvars++); -new_localvarliteral(ls,"(for control)",nvars++); -new_localvar(ls,indexname,nvars++); -while(testnext(ls,',')) -new_localvar(ls,str_checkname(ls),nvars++); -checknext(ls,TK_IN); -line=ls->linenumber; -adjust_assign(ls,3,explist1(ls,&e),&e); -luaK_checkstack(fs,3); -forbody(ls,base,line,nvars-3,0); -} -static void forstat(LexState*ls,int line){ -FuncState*fs=ls->fs; -TString*varname; -BlockCnt bl; -enterblock(fs,&bl,1); -luaX_next(ls); -varname=str_checkname(ls); -switch(ls->t.token){ -case'=':fornum(ls,varname,line);break; -case',':case TK_IN:forlist(ls,varname);break; -default:luaX_syntaxerror(ls,LUA_QL("=")" or "LUA_QL("in")" expected"); -} -check_match(ls,TK_END,TK_FOR,line); -leaveblock(fs); -} -static int test_then_block(LexState*ls){ -int condexit; -luaX_next(ls); -condexit=cond(ls); -checknext(ls,TK_THEN); -block(ls); -return condexit; -} -static void ifstat(LexState*ls,int line){ -FuncState*fs=ls->fs; -int flist; -int escapelist=(-1); -flist=test_then_block(ls); -while(ls->t.token==TK_ELSEIF){ -luaK_concat(fs,&escapelist,luaK_jump(fs)); -luaK_patchtohere(fs,flist); -flist=test_then_block(ls); -} -if(ls->t.token==TK_ELSE){ -luaK_concat(fs,&escapelist,luaK_jump(fs)); -luaK_patchtohere(fs,flist); -luaX_next(ls); -block(ls); -} -else -luaK_concat(fs,&escapelist,flist); -luaK_patchtohere(fs,escapelist); -check_match(ls,TK_END,TK_IF,line); -} -static void localfunc(LexState*ls){ -expdesc v,b; -FuncState*fs=ls->fs; -new_localvar(ls,str_checkname(ls),0); -init_exp(&v,VLOCAL,fs->freereg); -luaK_reserveregs(fs,1); -adjustlocalvars(ls,1); -body(ls,&b,0,ls->linenumber); -luaK_storevar(fs,&v,&b); -getlocvar(fs,fs->nactvar-1).startpc=fs->pc; -} -static void localstat(LexState*ls){ -int nvars=0; -int nexps; -expdesc e; -do{ -new_localvar(ls,str_checkname(ls),nvars++); -}while(testnext(ls,',')); -if(testnext(ls,'=')) -nexps=explist1(ls,&e); -else{ -e.k=VVOID; -nexps=0; -} -adjust_assign(ls,nvars,nexps,&e); -adjustlocalvars(ls,nvars); -} -static int funcname(LexState*ls,expdesc*v){ -int needself=0; -singlevar(ls,v); -while(ls->t.token=='.') -field(ls,v); -if(ls->t.token==':'){ -needself=1; -field(ls,v); -} -return needself; -} -static void funcstat(LexState*ls,int line){ -int needself; -expdesc v,b; -luaX_next(ls); -needself=funcname(ls,&v); -body(ls,&b,needself,line); -luaK_storevar(ls->fs,&v,&b); -luaK_fixline(ls->fs,line); -} -static void exprstat(LexState*ls){ -FuncState*fs=ls->fs; -struct LHS_assign v; -primaryexp(ls,&v.v); -if(v.v.k==VCALL) -SETARG_C(getcode(fs,&v.v),1); -else{ -v.prev=NULL; -assignment(ls,&v,1); -} -} -static void retstat(LexState*ls){ -FuncState*fs=ls->fs; -expdesc e; -int first,nret; -luaX_next(ls); -if(block_follow(ls->t.token)||ls->t.token==';') -first=nret=0; -else{ -nret=explist1(ls,&e); -if(hasmultret(e.k)){ -luaK_setmultret(fs,&e); -if(e.k==VCALL&&nret==1){ -SET_OPCODE(getcode(fs,&e),OP_TAILCALL); -} -first=fs->nactvar; -nret=(-1); -} -else{ -if(nret==1) -first=luaK_exp2anyreg(fs,&e); -else{ -luaK_exp2nextreg(fs,&e); -first=fs->nactvar; -} -} -} -luaK_ret(fs,first,nret); -} -static int statement(LexState*ls){ -int line=ls->linenumber; -switch(ls->t.token){ -case TK_IF:{ -ifstat(ls,line); -return 0; -} -case TK_WHILE:{ -whilestat(ls,line); -return 0; -} -case TK_DO:{ -luaX_next(ls); -block(ls); -check_match(ls,TK_END,TK_DO,line); -return 0; -} -case TK_FOR:{ -forstat(ls,line); -return 0; -} -case TK_REPEAT:{ -repeatstat(ls,line); -return 0; -} -case TK_FUNCTION:{ -funcstat(ls,line); -return 0; -} -case TK_LOCAL:{ -luaX_next(ls); -if(testnext(ls,TK_FUNCTION)) -localfunc(ls); -else -localstat(ls); -return 0; -} -case TK_RETURN:{ -retstat(ls); -return 1; -} -case TK_BREAK:{ -luaX_next(ls); -breakstat(ls); -return 1; -} -default:{ -exprstat(ls); -return 0; -} -} -} -static void chunk(LexState*ls){ -int islast=0; -enterlevel(ls); -while(!islast&&!block_follow(ls->t.token)){ -islast=statement(ls); -testnext(ls,';'); -ls->fs->freereg=ls->fs->nactvar; -} -leavelevel(ls); -} -static const TValue*luaV_tonumber(const TValue*obj,TValue*n){ -lua_Number num; -if(ttisnumber(obj))return obj; -if(ttisstring(obj)&&luaO_str2d(svalue(obj),&num)){ -setnvalue(n,num); -return n; -} -else -return NULL; -} -static int luaV_tostring(lua_State*L,StkId obj){ -if(!ttisnumber(obj)) -return 0; -else{ -char s[32]; -lua_Number n=nvalue(obj); -lua_number2str(s,n); -setsvalue(L,obj,luaS_new(L,s)); -return 1; -} -} -static void callTMres(lua_State*L,StkId res,const TValue*f, -const TValue*p1,const TValue*p2){ -ptrdiff_t result=savestack(L,res); -setobj(L,L->top,f); -setobj(L,L->top+1,p1); -setobj(L,L->top+2,p2); -luaD_checkstack(L,3); -L->top+=3; -luaD_call(L,L->top-3,1); -res=restorestack(L,result); -L->top--; -setobj(L,res,L->top); -} -static void callTM(lua_State*L,const TValue*f,const TValue*p1, -const TValue*p2,const TValue*p3){ -setobj(L,L->top,f); -setobj(L,L->top+1,p1); -setobj(L,L->top+2,p2); -setobj(L,L->top+3,p3); -luaD_checkstack(L,4); -L->top+=4; -luaD_call(L,L->top-4,0); -} -static void luaV_gettable(lua_State*L,const TValue*t,TValue*key,StkId val){ -int loop; -for(loop=0;loop<100;loop++){ -const TValue*tm; -if(ttistable(t)){ -Table*h=hvalue(t); -const TValue*res=luaH_get(h,key); -if(!ttisnil(res)|| -(tm=fasttm(L,h->metatable,TM_INDEX))==NULL){ -setobj(L,val,res); -return; -} -} -else if(ttisnil(tm=luaT_gettmbyobj(L,t,TM_INDEX))) -luaG_typeerror(L,t,"index"); -if(ttisfunction(tm)){ -callTMres(L,val,tm,t,key); -return; -} -t=tm; -} -luaG_runerror(L,"loop in gettable"); -} -static void luaV_settable(lua_State*L,const TValue*t,TValue*key,StkId val){ -int loop; -TValue temp; -for(loop=0;loop<100;loop++){ -const TValue*tm; -if(ttistable(t)){ -Table*h=hvalue(t); -TValue*oldval=luaH_set(L,h,key); -if(!ttisnil(oldval)|| -(tm=fasttm(L,h->metatable,TM_NEWINDEX))==NULL){ -setobj(L,oldval,val); -h->flags=0; -luaC_barriert(L,h,val); -return; -} -} -else if(ttisnil(tm=luaT_gettmbyobj(L,t,TM_NEWINDEX))) -luaG_typeerror(L,t,"index"); -if(ttisfunction(tm)){ -callTM(L,tm,t,key,val); -return; -} -setobj(L,&temp,tm); -t=&temp; -} -luaG_runerror(L,"loop in settable"); -} -static int call_binTM(lua_State*L,const TValue*p1,const TValue*p2, -StkId res,TMS event){ -const TValue*tm=luaT_gettmbyobj(L,p1,event); -if(ttisnil(tm)) -tm=luaT_gettmbyobj(L,p2,event); -if(ttisnil(tm))return 0; -callTMres(L,res,tm,p1,p2); -return 1; -} -static const TValue*get_compTM(lua_State*L,Table*mt1,Table*mt2, -TMS event){ -const TValue*tm1=fasttm(L,mt1,event); -const TValue*tm2; -if(tm1==NULL)return NULL; -if(mt1==mt2)return tm1; -tm2=fasttm(L,mt2,event); -if(tm2==NULL)return NULL; -if(luaO_rawequalObj(tm1,tm2)) -return tm1; -return NULL; -} -static int call_orderTM(lua_State*L,const TValue*p1,const TValue*p2, -TMS event){ -const TValue*tm1=luaT_gettmbyobj(L,p1,event); -const TValue*tm2; -if(ttisnil(tm1))return-1; -tm2=luaT_gettmbyobj(L,p2,event); -if(!luaO_rawequalObj(tm1,tm2)) -return-1; -callTMres(L,L->top,tm1,p1,p2); -return!l_isfalse(L->top); -} -static int l_strcmp(const TString*ls,const TString*rs){ -const char*l=getstr(ls); -size_t ll=ls->tsv.len; -const char*r=getstr(rs); -size_t lr=rs->tsv.len; -for(;;){ -int temp=strcoll(l,r); -if(temp!=0)return temp; -else{ -size_t len=strlen(l); -if(len==lr) -return(len==ll)?0:1; -else if(len==ll) -return-1; -len++; -l+=len;ll-=len;r+=len;lr-=len; -} -} -} -static int luaV_lessthan(lua_State*L,const TValue*l,const TValue*r){ -int res; -if(ttype(l)!=ttype(r)) -return luaG_ordererror(L,l,r); -else if(ttisnumber(l)) -return luai_numlt(nvalue(l),nvalue(r)); -else if(ttisstring(l)) -return l_strcmp(rawtsvalue(l),rawtsvalue(r))<0; -else if((res=call_orderTM(L,l,r,TM_LT))!=-1) -return res; -return luaG_ordererror(L,l,r); -} -static int lessequal(lua_State*L,const TValue*l,const TValue*r){ -int res; -if(ttype(l)!=ttype(r)) -return luaG_ordererror(L,l,r); -else if(ttisnumber(l)) -return luai_numle(nvalue(l),nvalue(r)); -else if(ttisstring(l)) -return l_strcmp(rawtsvalue(l),rawtsvalue(r))<=0; -else if((res=call_orderTM(L,l,r,TM_LE))!=-1) -return res; -else if((res=call_orderTM(L,r,l,TM_LT))!=-1) -return!res; -return luaG_ordererror(L,l,r); -} -static int luaV_equalval(lua_State*L,const TValue*t1,const TValue*t2){ -const TValue*tm; -switch(ttype(t1)){ -case 0:return 1; -case 3:return luai_numeq(nvalue(t1),nvalue(t2)); -case 1:return bvalue(t1)==bvalue(t2); -case 2:return pvalue(t1)==pvalue(t2); -case 7:{ -if(uvalue(t1)==uvalue(t2))return 1; -tm=get_compTM(L,uvalue(t1)->metatable,uvalue(t2)->metatable, -TM_EQ); -break; -} -case 5:{ -if(hvalue(t1)==hvalue(t2))return 1; -tm=get_compTM(L,hvalue(t1)->metatable,hvalue(t2)->metatable,TM_EQ); -break; -} -default:return gcvalue(t1)==gcvalue(t2); -} -if(tm==NULL)return 0; -callTMres(L,L->top,tm,t1,t2); -return!l_isfalse(L->top); -} -static void luaV_concat(lua_State*L,int total,int last){ -do{ -StkId top=L->base+last+1; -int n=2; -if(!(ttisstring(top-2)||ttisnumber(top-2))||!tostring(L,top-1)){ -if(!call_binTM(L,top-2,top-1,top-2,TM_CONCAT)) -luaG_concaterror(L,top-2,top-1); -}else if(tsvalue(top-1)->len==0) -(void)tostring(L,top-2); -else{ -size_t tl=tsvalue(top-1)->len; -char*buffer; -int i; -for(n=1;nlen; -if(l>=((size_t)(~(size_t)0)-2)-tl)luaG_runerror(L,"string length overflow"); -tl+=l; -} -buffer=luaZ_openspace(L,&G(L)->buff,tl); -tl=0; -for(i=n;i>0;i--){ -size_t l=tsvalue(top-i)->len; -memcpy(buffer+tl,svalue(top-i),l); -tl+=l; -} -setsvalue(L,top-n,luaS_newlstr(L,buffer,tl)); -} -total-=n-1; -last-=n-1; -}while(total>1); -} -static void Arith(lua_State*L,StkId ra,const TValue*rb, -const TValue*rc,TMS op){ -TValue tempb,tempc; -const TValue*b,*c; -if((b=luaV_tonumber(rb,&tempb))!=NULL&& -(c=luaV_tonumber(rc,&tempc))!=NULL){ -lua_Number nb=nvalue(b),nc=nvalue(c); -switch(op){ -case TM_ADD:setnvalue(ra,luai_numadd(nb,nc));break; -case TM_SUB:setnvalue(ra,luai_numsub(nb,nc));break; -case TM_MUL:setnvalue(ra,luai_nummul(nb,nc));break; -case TM_DIV:setnvalue(ra,luai_numdiv(nb,nc));break; -case TM_MOD:setnvalue(ra,luai_nummod(nb,nc));break; -case TM_POW:setnvalue(ra,luai_numpow(nb,nc));break; -case TM_UNM:setnvalue(ra,luai_numunm(nb));break; -default:break; -} -} -else if(!call_binTM(L,rb,rc,ra,op)) -luaG_aritherror(L,rb,rc); -} -#define runtime_check(L,c){if(!(c))break;} -#define RA(i)(base+GETARG_A(i)) -#define RB(i)check_exp(getBMode(GET_OPCODE(i))==OpArgR,base+GETARG_B(i)) -#define RKB(i)check_exp(getBMode(GET_OPCODE(i))==OpArgK,ISK(GETARG_B(i))?k+INDEXK(GETARG_B(i)):base+GETARG_B(i)) -#define RKC(i)check_exp(getCMode(GET_OPCODE(i))==OpArgK,ISK(GETARG_C(i))?k+INDEXK(GETARG_C(i)):base+GETARG_C(i)) -#define KBx(i)check_exp(getBMode(GET_OPCODE(i))==OpArgK,k+GETARG_Bx(i)) -#define dojump(L,pc,i){(pc)+=(i);} -#define Protect(x){L->savedpc=pc;{x;};base=L->base;} -#define arith_op(op,tm){TValue*rb=RKB(i);TValue*rc=RKC(i);if(ttisnumber(rb)&&ttisnumber(rc)){lua_Number nb=nvalue(rb),nc=nvalue(rc);setnvalue(ra,op(nb,nc));}else Protect(Arith(L,ra,rb,rc,tm));} -static void luaV_execute(lua_State*L,int nexeccalls){ -LClosure*cl; -StkId base; -TValue*k; -const Instruction*pc; -reentry: -pc=L->savedpc; -cl=&clvalue(L->ci->func)->l; -base=L->base; -k=cl->p->k; -for(;;){ -const Instruction i=*pc++; -StkId ra; -ra=RA(i); -switch(GET_OPCODE(i)){ -case OP_MOVE:{ -setobj(L,ra,RB(i)); -continue; -} -case OP_LOADK:{ -setobj(L,ra,KBx(i)); -continue; -} -case OP_LOADBOOL:{ -setbvalue(ra,GETARG_B(i)); -if(GETARG_C(i))pc++; -continue; -} -case OP_LOADNIL:{ -TValue*rb=RB(i); -do{ -setnilvalue(rb--); -}while(rb>=ra); -continue; -} -case OP_GETUPVAL:{ -int b=GETARG_B(i); -setobj(L,ra,cl->upvals[b]->v); -continue; -} -case OP_GETGLOBAL:{ -TValue g; -TValue*rb=KBx(i); -sethvalue(L,&g,cl->env); -Protect(luaV_gettable(L,&g,rb,ra)); -continue; -} -case OP_GETTABLE:{ -Protect(luaV_gettable(L,RB(i),RKC(i),ra)); -continue; -} -case OP_SETGLOBAL:{ -TValue g; -sethvalue(L,&g,cl->env); -Protect(luaV_settable(L,&g,KBx(i),ra)); -continue; -} -case OP_SETUPVAL:{ -UpVal*uv=cl->upvals[GETARG_B(i)]; -setobj(L,uv->v,ra); -luaC_barrier(L,uv,ra); -continue; -} -case OP_SETTABLE:{ -Protect(luaV_settable(L,ra,RKB(i),RKC(i))); -continue; -} -case OP_NEWTABLE:{ -int b=GETARG_B(i); -int c=GETARG_C(i); -sethvalue(L,ra,luaH_new(L,luaO_fb2int(b),luaO_fb2int(c))); -Protect(luaC_checkGC(L)); -continue; -} -case OP_SELF:{ -StkId rb=RB(i); -setobj(L,ra+1,rb); -Protect(luaV_gettable(L,rb,RKC(i),ra)); -continue; -} -case OP_ADD:{ -arith_op(luai_numadd,TM_ADD); -continue; -} -case OP_SUB:{ -arith_op(luai_numsub,TM_SUB); -continue; -} -case OP_MUL:{ -arith_op(luai_nummul,TM_MUL); -continue; -} -case OP_DIV:{ -arith_op(luai_numdiv,TM_DIV); -continue; -} -case OP_MOD:{ -arith_op(luai_nummod,TM_MOD); -continue; -} -case OP_POW:{ -arith_op(luai_numpow,TM_POW); -continue; -} -case OP_UNM:{ -TValue*rb=RB(i); -if(ttisnumber(rb)){ -lua_Number nb=nvalue(rb); -setnvalue(ra,luai_numunm(nb)); -} -else{ -Protect(Arith(L,ra,rb,rb,TM_UNM)); -} -continue; -} -case OP_NOT:{ -int res=l_isfalse(RB(i)); -setbvalue(ra,res); -continue; -} -case OP_LEN:{ -const TValue*rb=RB(i); -switch(ttype(rb)){ -case 5:{ -setnvalue(ra,cast_num(luaH_getn(hvalue(rb)))); -break; -} -case 4:{ -setnvalue(ra,cast_num(tsvalue(rb)->len)); -break; -} -default:{ -Protect( -if(!call_binTM(L,rb,(&luaO_nilobject_),ra,TM_LEN)) -luaG_typeerror(L,rb,"get length of"); -) -} -} -continue; -} -case OP_CONCAT:{ -int b=GETARG_B(i); -int c=GETARG_C(i); -Protect(luaV_concat(L,c-b+1,c);luaC_checkGC(L)); -setobj(L,RA(i),base+b); -continue; -} -case OP_JMP:{ -dojump(L,pc,GETARG_sBx(i)); -continue; -} -case OP_EQ:{ -TValue*rb=RKB(i); -TValue*rc=RKC(i); -Protect( -if(equalobj(L,rb,rc)==GETARG_A(i)) -dojump(L,pc,GETARG_sBx(*pc)); -) -pc++; -continue; -} -case OP_LT:{ -Protect( -if(luaV_lessthan(L,RKB(i),RKC(i))==GETARG_A(i)) -dojump(L,pc,GETARG_sBx(*pc)); -) -pc++; -continue; -} -case OP_LE:{ -Protect( -if(lessequal(L,RKB(i),RKC(i))==GETARG_A(i)) -dojump(L,pc,GETARG_sBx(*pc)); -) -pc++; -continue; -} -case OP_TEST:{ -if(l_isfalse(ra)!=GETARG_C(i)) -dojump(L,pc,GETARG_sBx(*pc)); -pc++; -continue; -} -case OP_TESTSET:{ -TValue*rb=RB(i); -if(l_isfalse(rb)!=GETARG_C(i)){ -setobj(L,ra,rb); -dojump(L,pc,GETARG_sBx(*pc)); -} -pc++; -continue; -} -case OP_CALL:{ -int b=GETARG_B(i); -int nresults=GETARG_C(i)-1; -if(b!=0)L->top=ra+b; -L->savedpc=pc; -switch(luaD_precall(L,ra,nresults)){ -case 0:{ -nexeccalls++; -goto reentry; -} -case 1:{ -if(nresults>=0)L->top=L->ci->top; -base=L->base; -continue; -} -default:{ -return; -} -} -} -case OP_TAILCALL:{ -int b=GETARG_B(i); -if(b!=0)L->top=ra+b; -L->savedpc=pc; -switch(luaD_precall(L,ra,(-1))){ -case 0:{ -CallInfo*ci=L->ci-1; -int aux; -StkId func=ci->func; -StkId pfunc=(ci+1)->func; -if(L->openupval)luaF_close(L,ci->base); -L->base=ci->base=ci->func+((ci+1)->base-pfunc); -for(aux=0;pfunc+auxtop;aux++) -setobj(L,func+aux,pfunc+aux); -ci->top=L->top=func+aux; -ci->savedpc=L->savedpc; -ci->tailcalls++; -L->ci--; -goto reentry; -} -case 1:{ -base=L->base; -continue; -} -default:{ -return; -} -} -} -case OP_RETURN:{ -int b=GETARG_B(i); -if(b!=0)L->top=ra+b-1; -if(L->openupval)luaF_close(L,base); -L->savedpc=pc; -b=luaD_poscall(L,ra); -if(--nexeccalls==0) -return; -else{ -if(b)L->top=L->ci->top; -goto reentry; -} -} -case OP_FORLOOP:{ -lua_Number step=nvalue(ra+2); -lua_Number idx=luai_numadd(nvalue(ra),step); -lua_Number limit=nvalue(ra+1); -if(luai_numlt(0,step)?luai_numle(idx,limit) -:luai_numle(limit,idx)){ -dojump(L,pc,GETARG_sBx(i)); -setnvalue(ra,idx); -setnvalue(ra+3,idx); -} -continue; -} -case OP_FORPREP:{ -const TValue*init=ra; -const TValue*plimit=ra+1; -const TValue*pstep=ra+2; -L->savedpc=pc; -if(!tonumber(init,ra)) -luaG_runerror(L,LUA_QL("for")" initial value must be a number"); -else if(!tonumber(plimit,ra+1)) -luaG_runerror(L,LUA_QL("for")" limit must be a number"); -else if(!tonumber(pstep,ra+2)) -luaG_runerror(L,LUA_QL("for")" step must be a number"); -setnvalue(ra,luai_numsub(nvalue(ra),nvalue(pstep))); -dojump(L,pc,GETARG_sBx(i)); -continue; -} -case OP_TFORLOOP:{ -StkId cb=ra+3; -setobj(L,cb+2,ra+2); -setobj(L,cb+1,ra+1); -setobj(L,cb,ra); -L->top=cb+3; -Protect(luaD_call(L,cb,GETARG_C(i))); -L->top=L->ci->top; -cb=RA(i)+3; -if(!ttisnil(cb)){ -setobj(L,cb-1,cb); -dojump(L,pc,GETARG_sBx(*pc)); -} -pc++; -continue; -} -case OP_SETLIST:{ -int n=GETARG_B(i); -int c=GETARG_C(i); -int last; -Table*h; -if(n==0){ -n=cast_int(L->top-ra)-1; -L->top=L->ci->top; -} -if(c==0)c=cast_int(*pc++); -runtime_check(L,ttistable(ra)); -h=hvalue(ra); -last=((c-1)*50)+n; -if(last>h->sizearray) -luaH_resizearray(L,h,last); -for(;n>0;n--){ -TValue*val=ra+n; -setobj(L,luaH_setnum(L,h,last--),val); -luaC_barriert(L,h,val); -} -continue; -} -case OP_CLOSE:{ -luaF_close(L,ra); -continue; -} -case OP_CLOSURE:{ -Proto*p; -Closure*ncl; -int nup,j; -p=cl->p->p[GETARG_Bx(i)]; -nup=p->nups; -ncl=luaF_newLclosure(L,nup,cl->env); -ncl->l.p=p; -for(j=0;jl.upvals[j]=cl->upvals[GETARG_B(*pc)]; -else{ -ncl->l.upvals[j]=luaF_findupval(L,base+GETARG_B(*pc)); -} -} -setclvalue(L,ra,ncl); -Protect(luaC_checkGC(L)); -continue; -} -case OP_VARARG:{ -int b=GETARG_B(i)-1; -int j; -CallInfo*ci=L->ci; -int n=cast_int(ci->base-ci->func)-cl->p->numparams-1; -if(b==(-1)){ -Protect(luaD_checkstack(L,n)); -ra=RA(i); -b=n; -L->top=ra+n; -} -for(j=0;jbase-n+j); -} -else{ -setnilvalue(ra+j); -} -} -continue; -} -} -} -} -#define api_checknelems(L,n)luai_apicheck(L,(n)<=(L->top-L->base)) -#define api_checkvalidindex(L,i)luai_apicheck(L,(i)!=(&luaO_nilobject_)) -#define api_incr_top(L){luai_apicheck(L,L->topci->top);L->top++;} -static TValue*index2adr(lua_State*L,int idx){ -if(idx>0){ -TValue*o=L->base+(idx-1); -luai_apicheck(L,idx<=L->ci->top-L->base); -if(o>=L->top)return cast(TValue*,(&luaO_nilobject_)); -else return o; -} -else if(idx>(-10000)){ -luai_apicheck(L,idx!=0&&-idx<=L->top-L->base); -return L->top+idx; -} -else switch(idx){ -case(-10000):return registry(L); -case(-10001):{ -Closure*func=curr_func(L); -sethvalue(L,&L->env,func->c.env); -return&L->env; -} -case(-10002):return gt(L); -default:{ -Closure*func=curr_func(L); -idx=(-10002)-idx; -return(idx<=func->c.nupvalues) -?&func->c.upvalue[idx-1] -:cast(TValue*,(&luaO_nilobject_)); -} -} -} -static Table*getcurrenv(lua_State*L){ -if(L->ci==L->base_ci) -return hvalue(gt(L)); -else{ -Closure*func=curr_func(L); -return func->c.env; -} -} -static int lua_checkstack(lua_State*L,int size){ -int res=1; -if(size>8000||(L->top-L->base+size)>8000) -res=0; -else if(size>0){ -luaD_checkstack(L,size); -if(L->ci->toptop+size) -L->ci->top=L->top+size; -} -return res; -} -static lua_CFunction lua_atpanic(lua_State*L,lua_CFunction panicf){ -lua_CFunction old; -old=G(L)->panic; -G(L)->panic=panicf; -return old; -} -static int lua_gettop(lua_State*L){ -return cast_int(L->top-L->base); -} -static void lua_settop(lua_State*L,int idx){ -if(idx>=0){ -luai_apicheck(L,idx<=L->stack_last-L->base); -while(L->topbase+idx) -setnilvalue(L->top++); -L->top=L->base+idx; -} -else{ -luai_apicheck(L,-(idx+1)<=(L->top-L->base)); -L->top+=idx+1; -} -} -static void lua_remove(lua_State*L,int idx){ -StkId p; -p=index2adr(L,idx); -api_checkvalidindex(L,p); -while(++ptop)setobj(L,p-1,p); -L->top--; -} -static void lua_insert(lua_State*L,int idx){ -StkId p; -StkId q; -p=index2adr(L,idx); -api_checkvalidindex(L,p); -for(q=L->top;q>p;q--)setobj(L,q,q-1); -setobj(L,p,L->top); -} -static void lua_replace(lua_State*L,int idx){ -StkId o; -if(idx==(-10001)&&L->ci==L->base_ci) -luaG_runerror(L,"no calling environment"); -api_checknelems(L,1); -o=index2adr(L,idx); -api_checkvalidindex(L,o); -if(idx==(-10001)){ -Closure*func=curr_func(L); -luai_apicheck(L,ttistable(L->top-1)); -func->c.env=hvalue(L->top-1); -luaC_barrier(L,func,L->top-1); -} -else{ -setobj(L,o,L->top-1); -if(idx<(-10002)) -luaC_barrier(L,curr_func(L),L->top-1); -} -L->top--; -} -static void lua_pushvalue(lua_State*L,int idx){ -setobj(L,L->top,index2adr(L,idx)); -api_incr_top(L); -} -static int lua_type(lua_State*L,int idx){ -StkId o=index2adr(L,idx); -return(o==(&luaO_nilobject_))?(-1):ttype(o); -} -static const char*lua_typename(lua_State*L,int t){ -UNUSED(L); -return(t==(-1))?"no value":luaT_typenames[t]; -} -static int lua_iscfunction(lua_State*L,int idx){ -StkId o=index2adr(L,idx); -return iscfunction(o); -} -static int lua_isnumber(lua_State*L,int idx){ -TValue n; -const TValue*o=index2adr(L,idx); -return tonumber(o,&n); -} -static int lua_isstring(lua_State*L,int idx){ -int t=lua_type(L,idx); -return(t==4||t==3); -} -static int lua_rawequal(lua_State*L,int index1,int index2){ -StkId o1=index2adr(L,index1); -StkId o2=index2adr(L,index2); -return(o1==(&luaO_nilobject_)||o2==(&luaO_nilobject_))?0 -:luaO_rawequalObj(o1,o2); -} -static int lua_lessthan(lua_State*L,int index1,int index2){ -StkId o1,o2; -int i; -o1=index2adr(L,index1); -o2=index2adr(L,index2); -i=(o1==(&luaO_nilobject_)||o2==(&luaO_nilobject_))?0 -:luaV_lessthan(L,o1,o2); -return i; -} -static lua_Number lua_tonumber(lua_State*L,int idx){ -TValue n; -const TValue*o=index2adr(L,idx); -if(tonumber(o,&n)) -return nvalue(o); -else -return 0; -} -static lua_Integer lua_tointeger(lua_State*L,int idx){ -TValue n; -const TValue*o=index2adr(L,idx); -if(tonumber(o,&n)){ -lua_Integer res; -lua_Number num=nvalue(o); -lua_number2integer(res,num); -return res; -} -else -return 0; -} -static int lua_toboolean(lua_State*L,int idx){ -const TValue*o=index2adr(L,idx); -return!l_isfalse(o); -} -static const char*lua_tolstring(lua_State*L,int idx,size_t*len){ -StkId o=index2adr(L,idx); -if(!ttisstring(o)){ -if(!luaV_tostring(L,o)){ -if(len!=NULL)*len=0; -return NULL; -} -luaC_checkGC(L); -o=index2adr(L,idx); -} -if(len!=NULL)*len=tsvalue(o)->len; -return svalue(o); -} -static size_t lua_objlen(lua_State*L,int idx){ -StkId o=index2adr(L,idx); -switch(ttype(o)){ -case 4:return tsvalue(o)->len; -case 7:return uvalue(o)->len; -case 5:return luaH_getn(hvalue(o)); -case 3:{ -size_t l; -l=(luaV_tostring(L,o)?tsvalue(o)->len:0); -return l; -} -default:return 0; -} -} -static lua_CFunction lua_tocfunction(lua_State*L,int idx){ -StkId o=index2adr(L,idx); -return(!iscfunction(o))?NULL:clvalue(o)->c.f; -} -static void*lua_touserdata(lua_State*L,int idx){ -StkId o=index2adr(L,idx); -switch(ttype(o)){ -case 7:return(rawuvalue(o)+1); -case 2:return pvalue(o); -default:return NULL; -} -} -static void lua_pushnil(lua_State*L){ -setnilvalue(L->top); -api_incr_top(L); -} -static void lua_pushnumber(lua_State*L,lua_Number n){ -setnvalue(L->top,n); -api_incr_top(L); -} -static void lua_pushinteger(lua_State*L,lua_Integer n){ -setnvalue(L->top,cast_num(n)); -api_incr_top(L); -} -static void lua_pushlstring(lua_State*L,const char*s,size_t len){ -luaC_checkGC(L); -setsvalue(L,L->top,luaS_newlstr(L,s,len)); -api_incr_top(L); -} -static void lua_pushstring(lua_State*L,const char*s){ -if(s==NULL) -lua_pushnil(L); -else -lua_pushlstring(L,s,strlen(s)); -} -static const char*lua_pushvfstring(lua_State*L,const char*fmt, -va_list argp){ -const char*ret; -luaC_checkGC(L); -ret=luaO_pushvfstring(L,fmt,argp); -return ret; -} -static const char*lua_pushfstring(lua_State*L,const char*fmt,...){ -const char*ret; -va_list argp; -luaC_checkGC(L); -va_start(argp,fmt); -ret=luaO_pushvfstring(L,fmt,argp); -va_end(argp); -return ret; -} -static void lua_pushcclosure(lua_State*L,lua_CFunction fn,int n){ -Closure*cl; -luaC_checkGC(L); -api_checknelems(L,n); -cl=luaF_newCclosure(L,n,getcurrenv(L)); -cl->c.f=fn; -L->top-=n; -while(n--) -setobj(L,&cl->c.upvalue[n],L->top+n); -setclvalue(L,L->top,cl); -api_incr_top(L); -} -static void lua_pushboolean(lua_State*L,int b){ -setbvalue(L->top,(b!=0)); -api_incr_top(L); -} -static int lua_pushthread(lua_State*L){ -setthvalue(L,L->top,L); -api_incr_top(L); -return(G(L)->mainthread==L); -} -static void lua_gettable(lua_State*L,int idx){ -StkId t; -t=index2adr(L,idx); -api_checkvalidindex(L,t); -luaV_gettable(L,t,L->top-1,L->top-1); -} -static void lua_getfield(lua_State*L,int idx,const char*k){ -StkId t; -TValue key; -t=index2adr(L,idx); -api_checkvalidindex(L,t); -setsvalue(L,&key,luaS_new(L,k)); -luaV_gettable(L,t,&key,L->top); -api_incr_top(L); -} -static void lua_rawget(lua_State*L,int idx){ -StkId t; -t=index2adr(L,idx); -luai_apicheck(L,ttistable(t)); -setobj(L,L->top-1,luaH_get(hvalue(t),L->top-1)); -} -static void lua_rawgeti(lua_State*L,int idx,int n){ -StkId o; -o=index2adr(L,idx); -luai_apicheck(L,ttistable(o)); -setobj(L,L->top,luaH_getnum(hvalue(o),n)); -api_incr_top(L); -} -static void lua_createtable(lua_State*L,int narray,int nrec){ -luaC_checkGC(L); -sethvalue(L,L->top,luaH_new(L,narray,nrec)); -api_incr_top(L); -} -static int lua_getmetatable(lua_State*L,int objindex){ -const TValue*obj; -Table*mt=NULL; -int res; -obj=index2adr(L,objindex); -switch(ttype(obj)){ -case 5: -mt=hvalue(obj)->metatable; -break; -case 7: -mt=uvalue(obj)->metatable; -break; -default: -mt=G(L)->mt[ttype(obj)]; -break; -} -if(mt==NULL) -res=0; -else{ -sethvalue(L,L->top,mt); -api_incr_top(L); -res=1; -} -return res; -} -static void lua_getfenv(lua_State*L,int idx){ -StkId o; -o=index2adr(L,idx); -api_checkvalidindex(L,o); -switch(ttype(o)){ -case 6: -sethvalue(L,L->top,clvalue(o)->c.env); -break; -case 7: -sethvalue(L,L->top,uvalue(o)->env); -break; -case 8: -setobj(L,L->top,gt(thvalue(o))); -break; -default: -setnilvalue(L->top); -break; -} -api_incr_top(L); -} -static void lua_settable(lua_State*L,int idx){ -StkId t; -api_checknelems(L,2); -t=index2adr(L,idx); -api_checkvalidindex(L,t); -luaV_settable(L,t,L->top-2,L->top-1); -L->top-=2; -} -static void lua_setfield(lua_State*L,int idx,const char*k){ -StkId t; -TValue key; -api_checknelems(L,1); -t=index2adr(L,idx); -api_checkvalidindex(L,t); -setsvalue(L,&key,luaS_new(L,k)); -luaV_settable(L,t,&key,L->top-1); -L->top--; -} -static void lua_rawset(lua_State*L,int idx){ -StkId t; -api_checknelems(L,2); -t=index2adr(L,idx); -luai_apicheck(L,ttistable(t)); -setobj(L,luaH_set(L,hvalue(t),L->top-2),L->top-1); -luaC_barriert(L,hvalue(t),L->top-1); -L->top-=2; -} -static void lua_rawseti(lua_State*L,int idx,int n){ -StkId o; -api_checknelems(L,1); -o=index2adr(L,idx); -luai_apicheck(L,ttistable(o)); -setobj(L,luaH_setnum(L,hvalue(o),n),L->top-1); -luaC_barriert(L,hvalue(o),L->top-1); -L->top--; -} -static int lua_setmetatable(lua_State*L,int objindex){ -TValue*obj; -Table*mt; -api_checknelems(L,1); -obj=index2adr(L,objindex); -api_checkvalidindex(L,obj); -if(ttisnil(L->top-1)) -mt=NULL; -else{ -luai_apicheck(L,ttistable(L->top-1)); -mt=hvalue(L->top-1); -} -switch(ttype(obj)){ -case 5:{ -hvalue(obj)->metatable=mt; -if(mt) -luaC_objbarriert(L,hvalue(obj),mt); -break; -} -case 7:{ -uvalue(obj)->metatable=mt; -if(mt) -luaC_objbarrier(L,rawuvalue(obj),mt); -break; -} -default:{ -G(L)->mt[ttype(obj)]=mt; -break; -} -} -L->top--; -return 1; -} -static int lua_setfenv(lua_State*L,int idx){ -StkId o; -int res=1; -api_checknelems(L,1); -o=index2adr(L,idx); -api_checkvalidindex(L,o); -luai_apicheck(L,ttistable(L->top-1)); -switch(ttype(o)){ -case 6: -clvalue(o)->c.env=hvalue(L->top-1); -break; -case 7: -uvalue(o)->env=hvalue(L->top-1); -break; -case 8: -sethvalue(L,gt(thvalue(o)),hvalue(L->top-1)); -break; -default: -res=0; -break; -} -if(res)luaC_objbarrier(L,gcvalue(o),hvalue(L->top-1)); -L->top--; -return res; -} -#define adjustresults(L,nres){if(nres==(-1)&&L->top>=L->ci->top)L->ci->top=L->top;} -#define checkresults(L,na,nr)luai_apicheck(L,(nr)==(-1)||(L->ci->top-L->top>=(nr)-(na))) -static void lua_call(lua_State*L,int nargs,int nresults){ -StkId func; -api_checknelems(L,nargs+1); -checkresults(L,nargs,nresults); -func=L->top-(nargs+1); -luaD_call(L,func,nresults); -adjustresults(L,nresults); -} -struct CallS{ -StkId func; -int nresults; -}; -static void f_call(lua_State*L,void*ud){ -struct CallS*c=cast(struct CallS*,ud); -luaD_call(L,c->func,c->nresults); -} -static int lua_pcall(lua_State*L,int nargs,int nresults,int errfunc){ -struct CallS c; -int status; -ptrdiff_t func; -api_checknelems(L,nargs+1); -checkresults(L,nargs,nresults); -if(errfunc==0) -func=0; -else{ -StkId o=index2adr(L,errfunc); -api_checkvalidindex(L,o); -func=savestack(L,o); -} -c.func=L->top-(nargs+1); -c.nresults=nresults; -status=luaD_pcall(L,f_call,&c,savestack(L,c.func),func); -adjustresults(L,nresults); -return status; -} -static int lua_load(lua_State*L,lua_Reader reader,void*data, -const char*chunkname){ -ZIO z; -int status; -if(!chunkname)chunkname="?"; -luaZ_init(L,&z,reader,data); -status=luaD_protectedparser(L,&z,chunkname); -return status; -} -static int lua_error(lua_State*L){ -api_checknelems(L,1); -luaG_errormsg(L); -return 0; -} -static int lua_next(lua_State*L,int idx){ -StkId t; -int more; -t=index2adr(L,idx); -luai_apicheck(L,ttistable(t)); -more=luaH_next(L,hvalue(t),L->top-1); -if(more){ -api_incr_top(L); -} -else -L->top-=1; -return more; -} -static void lua_concat(lua_State*L,int n){ -api_checknelems(L,n); -if(n>=2){ -luaC_checkGC(L); -luaV_concat(L,n,cast_int(L->top-L->base)-1); -L->top-=(n-1); -} -else if(n==0){ -setsvalue(L,L->top,luaS_newlstr(L,"",0)); -api_incr_top(L); -} -} -static void*lua_newuserdata(lua_State*L,size_t size){ -Udata*u; -luaC_checkGC(L); -u=luaS_newudata(L,size,getcurrenv(L)); -setuvalue(L,L->top,u); -api_incr_top(L); -return u+1; -} -#define luaL_getn(L,i)((int)lua_objlen(L,i)) -#define luaL_setn(L,i,j)((void)0) -typedef struct luaL_Reg{ -const char*name; -lua_CFunction func; -}luaL_Reg; -static void luaI_openlib(lua_State*L,const char*libname, -const luaL_Reg*l,int nup); -static int luaL_argerror(lua_State*L,int numarg,const char*extramsg); -static const char* luaL_checklstring(lua_State*L,int numArg, -size_t*l); -static const char* luaL_optlstring(lua_State*L,int numArg, -const char*def,size_t*l); -static lua_Integer luaL_checkinteger(lua_State*L,int numArg); -static lua_Integer luaL_optinteger(lua_State*L,int nArg, -lua_Integer def); -static int luaL_error(lua_State*L,const char*fmt,...); -static const char* luaL_findtable(lua_State*L,int idx, -const char*fname,int szhint); -#define luaL_argcheck(L,cond,numarg,extramsg)((void)((cond)||luaL_argerror(L,(numarg),(extramsg)))) -#define luaL_checkstring(L,n)(luaL_checklstring(L,(n),NULL)) -#define luaL_optstring(L,n,d)(luaL_optlstring(L,(n),(d),NULL)) -#define luaL_checkint(L,n)((int)luaL_checkinteger(L,(n))) -#define luaL_optint(L,n,d)((int)luaL_optinteger(L,(n),(d))) -#define luaL_typename(L,i)lua_typename(L,lua_type(L,(i))) -#define luaL_getmetatable(L,n)(lua_getfield(L,(-10000),(n))) -#define luaL_opt(L,f,n,d)(lua_isnoneornil(L,(n))?(d):f(L,(n))) -typedef struct luaL_Buffer{ -char*p; -int lvl; -lua_State*L; -char buffer[BUFSIZ]; -}luaL_Buffer; -#define luaL_addchar(B,c)((void)((B)->p<((B)->buffer+BUFSIZ)||luaL_prepbuffer(B)),(*(B)->p++=(char)(c))) -#define luaL_addsize(B,n)((B)->p+=(n)) -static char* luaL_prepbuffer(luaL_Buffer*B); -static int luaL_argerror(lua_State*L,int narg,const char*extramsg){ -lua_Debug ar; -if(!lua_getstack(L,0,&ar)) -return luaL_error(L,"bad argument #%d (%s)",narg,extramsg); -lua_getinfo(L,"n",&ar); -if(strcmp(ar.namewhat,"method")==0){ -narg--; -if(narg==0) -return luaL_error(L,"calling "LUA_QL("%s")" on bad self (%s)", -ar.name,extramsg); -} -if(ar.name==NULL) -ar.name="?"; -return luaL_error(L,"bad argument #%d to "LUA_QL("%s")" (%s)", -narg,ar.name,extramsg); -} -static int luaL_typerror(lua_State*L,int narg,const char*tname){ -const char*msg=lua_pushfstring(L,"%s expected, got %s", -tname,luaL_typename(L,narg)); -return luaL_argerror(L,narg,msg); -} -static void tag_error(lua_State*L,int narg,int tag){ -luaL_typerror(L,narg,lua_typename(L,tag)); -} -static void luaL_where(lua_State*L,int level){ -lua_Debug ar; -if(lua_getstack(L,level,&ar)){ -lua_getinfo(L,"Sl",&ar); -if(ar.currentline>0){ -lua_pushfstring(L,"%s:%d: ",ar.short_src,ar.currentline); -return; -} -} -lua_pushliteral(L,""); -} -static int luaL_error(lua_State*L,const char*fmt,...){ -va_list argp; -va_start(argp,fmt); -luaL_where(L,1); -lua_pushvfstring(L,fmt,argp); -va_end(argp); -lua_concat(L,2); -return lua_error(L); -} -static int luaL_newmetatable(lua_State*L,const char*tname){ -lua_getfield(L,(-10000),tname); -if(!lua_isnil(L,-1)) -return 0; -lua_pop(L,1); -lua_newtable(L); -lua_pushvalue(L,-1); -lua_setfield(L,(-10000),tname); -return 1; -} -static void*luaL_checkudata(lua_State*L,int ud,const char*tname){ -void*p=lua_touserdata(L,ud); -if(p!=NULL){ -if(lua_getmetatable(L,ud)){ -lua_getfield(L,(-10000),tname); -if(lua_rawequal(L,-1,-2)){ -lua_pop(L,2); -return p; -} -} -} -luaL_typerror(L,ud,tname); -return NULL; -} -static void luaL_checkstack(lua_State*L,int space,const char*mes){ -if(!lua_checkstack(L,space)) -luaL_error(L,"stack overflow (%s)",mes); -} -static void luaL_checktype(lua_State*L,int narg,int t){ -if(lua_type(L,narg)!=t) -tag_error(L,narg,t); -} -static void luaL_checkany(lua_State*L,int narg){ -if(lua_type(L,narg)==(-1)) -luaL_argerror(L,narg,"value expected"); -} -static const char*luaL_checklstring(lua_State*L,int narg,size_t*len){ -const char*s=lua_tolstring(L,narg,len); -if(!s)tag_error(L,narg,4); -return s; -} -static const char*luaL_optlstring(lua_State*L,int narg, -const char*def,size_t*len){ -if(lua_isnoneornil(L,narg)){ -if(len) -*len=(def?strlen(def):0); -return def; -} -else return luaL_checklstring(L,narg,len); -} -static lua_Number luaL_checknumber(lua_State*L,int narg){ -lua_Number d=lua_tonumber(L,narg); -if(d==0&&!lua_isnumber(L,narg)) -tag_error(L,narg,3); -return d; -} -static lua_Integer luaL_checkinteger(lua_State*L,int narg){ -lua_Integer d=lua_tointeger(L,narg); -if(d==0&&!lua_isnumber(L,narg)) -tag_error(L,narg,3); -return d; -} -static lua_Integer luaL_optinteger(lua_State*L,int narg, -lua_Integer def){ -return luaL_opt(L,luaL_checkinteger,narg,def); -} -static int luaL_getmetafield(lua_State*L,int obj,const char*event){ -if(!lua_getmetatable(L,obj)) -return 0; -lua_pushstring(L,event); -lua_rawget(L,-2); -if(lua_isnil(L,-1)){ -lua_pop(L,2); -return 0; -} -else{ -lua_remove(L,-2); -return 1; -} -} -static void luaL_register(lua_State*L,const char*libname, -const luaL_Reg*l){ -luaI_openlib(L,libname,l,0); -} -static int libsize(const luaL_Reg*l){ -int size=0; -for(;l->name;l++)size++; -return size; -} -static void luaI_openlib(lua_State*L,const char*libname, -const luaL_Reg*l,int nup){ -if(libname){ -int size=libsize(l); -luaL_findtable(L,(-10000),"_LOADED",1); -lua_getfield(L,-1,libname); -if(!lua_istable(L,-1)){ -lua_pop(L,1); -if(luaL_findtable(L,(-10002),libname,size)!=NULL) -luaL_error(L,"name conflict for module "LUA_QL("%s"),libname); -lua_pushvalue(L,-1); -lua_setfield(L,-3,libname); -} -lua_remove(L,-2); -lua_insert(L,-(nup+1)); -} -for(;l->name;l++){ -int i; -for(i=0;ifunc,nup); -lua_setfield(L,-(nup+2),l->name); -} -lua_pop(L,nup); -} -static const char*luaL_findtable(lua_State*L,int idx, -const char*fname,int szhint){ -const char*e; -lua_pushvalue(L,idx); -do{ -e=strchr(fname,'.'); -if(e==NULL)e=fname+strlen(fname); -lua_pushlstring(L,fname,e-fname); -lua_rawget(L,-2); -if(lua_isnil(L,-1)){ -lua_pop(L,1); -lua_createtable(L,0,(*e=='.'?1:szhint)); -lua_pushlstring(L,fname,e-fname); -lua_pushvalue(L,-2); -lua_settable(L,-4); -} -else if(!lua_istable(L,-1)){ -lua_pop(L,2); -return fname; -} -lua_remove(L,-2); -fname=e+1; -}while(*e=='.'); -return NULL; -} -#define bufflen(B)((B)->p-(B)->buffer) -#define bufffree(B)((size_t)(BUFSIZ-bufflen(B))) -static int emptybuffer(luaL_Buffer*B){ -size_t l=bufflen(B); -if(l==0)return 0; -else{ -lua_pushlstring(B->L,B->buffer,l); -B->p=B->buffer; -B->lvl++; -return 1; -} -} -static void adjuststack(luaL_Buffer*B){ -if(B->lvl>1){ -lua_State*L=B->L; -int toget=1; -size_t toplen=lua_strlen(L,-1); -do{ -size_t l=lua_strlen(L,-(toget+1)); -if(B->lvl-toget+1>=(20/2)||toplen>l){ -toplen+=l; -toget++; -} -else break; -}while(togetlvl); -lua_concat(L,toget); -B->lvl=B->lvl-toget+1; -} -} -static char*luaL_prepbuffer(luaL_Buffer*B){ -if(emptybuffer(B)) -adjuststack(B); -return B->buffer; -} -static void luaL_addlstring(luaL_Buffer*B,const char*s,size_t l){ -while(l--) -luaL_addchar(B,*s++); -} -static void luaL_pushresult(luaL_Buffer*B){ -emptybuffer(B); -lua_concat(B->L,B->lvl); -B->lvl=1; -} -static void luaL_addvalue(luaL_Buffer*B){ -lua_State*L=B->L; -size_t vl; -const char*s=lua_tolstring(L,-1,&vl); -if(vl<=bufffree(B)){ -memcpy(B->p,s,vl); -B->p+=vl; -lua_pop(L,1); -} -else{ -if(emptybuffer(B)) -lua_insert(L,-2); -B->lvl++; -adjuststack(B); -} -} -static void luaL_buffinit(lua_State*L,luaL_Buffer*B){ -B->L=L; -B->p=B->buffer; -B->lvl=0; -} -typedef struct LoadF{ -int extraline; -FILE*f; -char buff[BUFSIZ]; -}LoadF; -static const char*getF(lua_State*L,void*ud,size_t*size){ -LoadF*lf=(LoadF*)ud; -(void)L; -if(lf->extraline){ -lf->extraline=0; -*size=1; -return"\n"; -} -if(feof(lf->f))return NULL; -*size=fread(lf->buff,1,sizeof(lf->buff),lf->f); -return(*size>0)?lf->buff:NULL; -} -static int errfile(lua_State*L,const char*what,int fnameindex){ -const char*serr=strerror(errno); -const char*filename=lua_tostring(L,fnameindex)+1; -lua_pushfstring(L,"cannot %s %s: %s",what,filename,serr); -lua_remove(L,fnameindex); -return(5+1); -} -static int luaL_loadfile(lua_State*L,const char*filename){ -LoadF lf; -int status,readstatus; -int c; -int fnameindex=lua_gettop(L)+1; -lf.extraline=0; -if(filename==NULL){ -lua_pushliteral(L,"=stdin"); -lf.f=stdin; -} -else{ -lua_pushfstring(L,"@%s",filename); -lf.f=fopen(filename,"r"); -if(lf.f==NULL)return errfile(L,"open",fnameindex); -} -c=getc(lf.f); -if(c=='#'){ -lf.extraline=1; -while((c=getc(lf.f))!=EOF&&c!='\n'); -if(c=='\n')c=getc(lf.f); -} -if(c=="\033Lua"[0]&&filename){ -lf.f=freopen(filename,"rb",lf.f); -if(lf.f==NULL)return errfile(L,"reopen",fnameindex); -while((c=getc(lf.f))!=EOF&&c!="\033Lua"[0]); -lf.extraline=0; -} -ungetc(c,lf.f); -status=lua_load(L,getF,&lf,lua_tostring(L,-1)); -readstatus=ferror(lf.f); -if(filename)fclose(lf.f); -if(readstatus){ -lua_settop(L,fnameindex); -return errfile(L,"read",fnameindex); -} -lua_remove(L,fnameindex); -return status; -} -typedef struct LoadS{ -const char*s; -size_t size; -}LoadS; -static const char*getS(lua_State*L,void*ud,size_t*size){ -LoadS*ls=(LoadS*)ud; -(void)L; -if(ls->size==0)return NULL; -*size=ls->size; -ls->size=0; -return ls->s; -} -static int luaL_loadbuffer(lua_State*L,const char*buff,size_t size, -const char*name){ -LoadS ls; -ls.s=buff; -ls.size=size; -return lua_load(L,getS,&ls,name); -} -static void*l_alloc(void*ud,void*ptr,size_t osize,size_t nsize){ -(void)ud; -(void)osize; -if(nsize==0){ -free(ptr); -return NULL; -} -else -return realloc(ptr,nsize); -} -static int panic(lua_State*L){ -(void)L; -fprintf(stderr,"PANIC: unprotected error in call to Lua API (%s)\n", -lua_tostring(L,-1)); -return 0; -} -static lua_State*luaL_newstate(void){ -lua_State*L=lua_newstate(l_alloc,NULL); -if(L)lua_atpanic(L,&panic); -return L; -} -static int luaB_tonumber(lua_State*L){ -int base=luaL_optint(L,2,10); -if(base==10){ -luaL_checkany(L,1); -if(lua_isnumber(L,1)){ -lua_pushnumber(L,lua_tonumber(L,1)); -return 1; -} -} -else{ -const char*s1=luaL_checkstring(L,1); -char*s2; -unsigned long n; -luaL_argcheck(L,2<=base&&base<=36,2,"base out of range"); -n=strtoul(s1,&s2,base); -if(s1!=s2){ -while(isspace((unsigned char)(*s2)))s2++; -if(*s2=='\0'){ -lua_pushnumber(L,(lua_Number)n); -return 1; -} -} -} -lua_pushnil(L); -return 1; -} -static int luaB_error(lua_State*L){ -int level=luaL_optint(L,2,1); -lua_settop(L,1); -if(lua_isstring(L,1)&&level>0){ -luaL_where(L,level); -lua_pushvalue(L,1); -lua_concat(L,2); -} -return lua_error(L); -} -static int luaB_setmetatable(lua_State*L){ -int t=lua_type(L,2); -luaL_checktype(L,1,5); -luaL_argcheck(L,t==0||t==5,2, -"nil or table expected"); -if(luaL_getmetafield(L,1,"__metatable")) -luaL_error(L,"cannot change a protected metatable"); -lua_settop(L,2); -lua_setmetatable(L,1); -return 1; -} -static void getfunc(lua_State*L,int opt){ -if(lua_isfunction(L,1))lua_pushvalue(L,1); -else{ -lua_Debug ar; -int level=opt?luaL_optint(L,1,1):luaL_checkint(L,1); -luaL_argcheck(L,level>=0,1,"level must be non-negative"); -if(lua_getstack(L,level,&ar)==0) -luaL_argerror(L,1,"invalid level"); -lua_getinfo(L,"f",&ar); -if(lua_isnil(L,-1)) -luaL_error(L,"no function environment for tail call at level %d", -level); -} -} -static int luaB_setfenv(lua_State*L){ -luaL_checktype(L,2,5); -getfunc(L,0); -lua_pushvalue(L,2); -if(lua_isnumber(L,1)&&lua_tonumber(L,1)==0){ -lua_pushthread(L); -lua_insert(L,-2); -lua_setfenv(L,-2); -return 0; -} -else if(lua_iscfunction(L,-2)||lua_setfenv(L,-2)==0) -luaL_error(L, -LUA_QL("setfenv")" cannot change environment of given object"); -return 1; -} -static int luaB_rawget(lua_State*L){ -luaL_checktype(L,1,5); -luaL_checkany(L,2); -lua_settop(L,2); -lua_rawget(L,1); -return 1; -} -static int luaB_type(lua_State*L){ -luaL_checkany(L,1); -lua_pushstring(L,luaL_typename(L,1)); -return 1; -} -static int luaB_next(lua_State*L){ -luaL_checktype(L,1,5); -lua_settop(L,2); -if(lua_next(L,1)) -return 2; -else{ -lua_pushnil(L); -return 1; -} -} -static int luaB_pairs(lua_State*L){ -luaL_checktype(L,1,5); -lua_pushvalue(L,lua_upvalueindex(1)); -lua_pushvalue(L,1); -lua_pushnil(L); -return 3; -} -static int ipairsaux(lua_State*L){ -int i=luaL_checkint(L,2); -luaL_checktype(L,1,5); -i++; -lua_pushinteger(L,i); -lua_rawgeti(L,1,i); -return(lua_isnil(L,-1))?0:2; -} -static int luaB_ipairs(lua_State*L){ -luaL_checktype(L,1,5); -lua_pushvalue(L,lua_upvalueindex(1)); -lua_pushvalue(L,1); -lua_pushinteger(L,0); -return 3; -} -static int load_aux(lua_State*L,int status){ -if(status==0) -return 1; -else{ -lua_pushnil(L); -lua_insert(L,-2); -return 2; -} -} -static int luaB_loadstring(lua_State*L){ -size_t l; -const char*s=luaL_checklstring(L,1,&l); -const char*chunkname=luaL_optstring(L,2,s); -return load_aux(L,luaL_loadbuffer(L,s,l,chunkname)); -} -static int luaB_loadfile(lua_State*L){ -const char*fname=luaL_optstring(L,1,NULL); -return load_aux(L,luaL_loadfile(L,fname)); -} -static int luaB_assert(lua_State*L){ -luaL_checkany(L,1); -if(!lua_toboolean(L,1)) -return luaL_error(L,"%s",luaL_optstring(L,2,"assertion failed!")); -return lua_gettop(L); -} -static int luaB_unpack(lua_State*L){ -int i,e,n; -luaL_checktype(L,1,5); -i=luaL_optint(L,2,1); -e=luaL_opt(L,luaL_checkint,3,luaL_getn(L,1)); -if(i>e)return 0; -n=e-i+1; -if(n<=0||!lua_checkstack(L,n)) -return luaL_error(L,"too many results to unpack"); -lua_rawgeti(L,1,i); -while(i++e)e=pos; -for(i=e;i>pos;i--){ -lua_rawgeti(L,1,i-1); -lua_rawseti(L,1,i); -} -break; -} -default:{ -return luaL_error(L,"wrong number of arguments to "LUA_QL("insert")); -} -} -luaL_setn(L,1,e); -lua_rawseti(L,1,pos); -return 0; -} -static int tremove(lua_State*L){ -int e=aux_getn(L,1); -int pos=luaL_optint(L,2,e); -if(!(1<=pos&&pos<=e)) -return 0; -luaL_setn(L,1,e-1); -lua_rawgeti(L,1,pos); -for(;posu)luaL_error(L,"invalid order function for sorting"); -lua_pop(L,1); -} -while(lua_rawgeti(L,1,--j),sort_comp(L,-3,-1)){ -if(j0); -} -l=strlen(p); -if(l==0||p[l-1]!='\n') -luaL_addsize(&b,l); -else{ -luaL_addsize(&b,l-1); -luaL_pushresult(&b); -return 1; -} -} -} -static int read_chars(lua_State*L,FILE*f,size_t n){ -size_t rlen; -size_t nr; -luaL_Buffer b; -luaL_buffinit(L,&b); -rlen=BUFSIZ; -do{ -char*p=luaL_prepbuffer(&b); -if(rlen>n)rlen=n; -nr=fread(p,sizeof(char),rlen,f); -luaL_addsize(&b,nr); -n-=nr; -}while(n>0&&nr==rlen); -luaL_pushresult(&b); -return(n==0||lua_objlen(L,-1)>0); -} -static int g_read(lua_State*L,FILE*f,int first){ -int nargs=lua_gettop(L)-1; -int success; -int n; -clearerr(f); -if(nargs==0){ -success=read_line(L,f); -n=first+1; -} -else{ -luaL_checkstack(L,nargs+20,"too many arguments"); -success=1; -for(n=first;nargs--&&success;n++){ -if(lua_type(L,n)==3){ -size_t l=(size_t)lua_tointeger(L,n); -success=(l==0)?test_eof(L,f):read_chars(L,f,l); -} -else{ -const char*p=lua_tostring(L,n); -luaL_argcheck(L,p&&p[0]=='*',n,"invalid option"); -switch(p[1]){ -case'n': -success=read_number(L,f); -break; -case'l': -success=read_line(L,f); -break; -case'a': -read_chars(L,f,~((size_t)0)); -success=1; -break; -default: -return luaL_argerror(L,n,"invalid format"); -} -} -} -} -if(ferror(f)) -return pushresult(L,0,NULL); -if(!success){ -lua_pop(L,1); -lua_pushnil(L); -} -return n-first; -} -static int io_read(lua_State*L){ -return g_read(L,getiofile(L,1),1); -} -static int f_read(lua_State*L){ -return g_read(L,tofile(L),2); -} -static int io_readline(lua_State*L){ -FILE*f=*(FILE**)lua_touserdata(L,lua_upvalueindex(1)); -int sucess; -if(f==NULL) -luaL_error(L,"file is already closed"); -sucess=read_line(L,f); -if(ferror(f)) -return luaL_error(L,"%s",strerror(errno)); -if(sucess)return 1; -else{ -if(lua_toboolean(L,lua_upvalueindex(2))){ -lua_settop(L,0); -lua_pushvalue(L,lua_upvalueindex(1)); -aux_close(L); -} -return 0; -} -} -static int g_write(lua_State*L,FILE*f,int arg){ -int nargs=lua_gettop(L)-1; -int status=1; -for(;nargs--;arg++){ -if(lua_type(L,arg)==3){ -status=status&& -fprintf(f,"%.14g",lua_tonumber(L,arg))>0; -} -else{ -size_t l; -const char*s=luaL_checklstring(L,arg,&l); -status=status&&(fwrite(s,sizeof(char),l,f)==l); -} -} -return pushresult(L,status,NULL); -} -static int io_write(lua_State*L){ -return g_write(L,getiofile(L,2),1); -} -static int f_write(lua_State*L){ -return g_write(L,tofile(L),2); -} -static int io_flush(lua_State*L){ -return pushresult(L,fflush(getiofile(L,2))==0,NULL); -} -static int f_flush(lua_State*L){ -return pushresult(L,fflush(tofile(L))==0,NULL); -} -static const luaL_Reg iolib[]={ -{"close",io_close}, -{"flush",io_flush}, -{"input",io_input}, -{"lines",io_lines}, -{"open",io_open}, -{"output",io_output}, -{"read",io_read}, -{"type",io_type}, -{"write",io_write}, -{NULL,NULL} -}; -static const luaL_Reg flib[]={ -{"close",io_close}, -{"flush",f_flush}, -{"lines",f_lines}, -{"read",f_read}, -{"write",f_write}, -{"__gc",io_gc}, -{NULL,NULL} -}; -static void createmeta(lua_State*L){ -luaL_newmetatable(L,"FILE*"); -lua_pushvalue(L,-1); -lua_setfield(L,-2,"__index"); -luaL_register(L,NULL,flib); -} -static void createstdfile(lua_State*L,FILE*f,int k,const char*fname){ -*newfile(L)=f; -if(k>0){ -lua_pushvalue(L,-1); -lua_rawseti(L,(-10001),k); -} -lua_pushvalue(L,-2); -lua_setfenv(L,-2); -lua_setfield(L,-3,fname); -} -static void newfenv(lua_State*L,lua_CFunction cls){ -lua_createtable(L,0,1); -lua_pushcfunction(L,cls); -lua_setfield(L,-2,"__close"); -} -static int luaopen_io(lua_State*L){ -createmeta(L); -newfenv(L,io_fclose); -lua_replace(L,(-10001)); -luaL_register(L,"io",iolib); -newfenv(L,io_noclose); -createstdfile(L,stdin,1,"stdin"); -createstdfile(L,stdout,2,"stdout"); -createstdfile(L,stderr,0,"stderr"); -lua_pop(L,1); -lua_getfield(L,-1,"popen"); -newfenv(L,io_pclose); -lua_setfenv(L,-2); -lua_pop(L,1); -return 1; -} -static int os_pushresult(lua_State*L,int i,const char*filename){ -int en=errno; -if(i){ -lua_pushboolean(L,1); -return 1; -} -else{ -lua_pushnil(L); -lua_pushfstring(L,"%s: %s",filename,strerror(en)); -lua_pushinteger(L,en); -return 3; -} -} -static int os_remove(lua_State*L){ -const char*filename=luaL_checkstring(L,1); -return os_pushresult(L,remove(filename)==0,filename); -} -static int os_exit(lua_State*L){ -exit(luaL_optint(L,1,EXIT_SUCCESS)); -} -static const luaL_Reg syslib[]={ -{"exit",os_exit}, -{"remove",os_remove}, -{NULL,NULL} -}; -static int luaopen_os(lua_State*L){ -luaL_register(L,"os",syslib); -return 1; -} -#define uchar(c)((unsigned char)(c)) -static ptrdiff_t posrelat(ptrdiff_t pos,size_t len){ -if(pos<0)pos+=(ptrdiff_t)len+1; -return(pos>=0)?pos:0; -} -static int str_sub(lua_State*L){ -size_t l; -const char*s=luaL_checklstring(L,1,&l); -ptrdiff_t start=posrelat(luaL_checkinteger(L,2),l); -ptrdiff_t end=posrelat(luaL_optinteger(L,3,-1),l); -if(start<1)start=1; -if(end>(ptrdiff_t)l)end=(ptrdiff_t)l; -if(start<=end) -lua_pushlstring(L,s+start-1,end-start+1); -else lua_pushliteral(L,""); -return 1; -} -static int str_lower(lua_State*L){ -size_t l; -size_t i; -luaL_Buffer b; -const char*s=luaL_checklstring(L,1,&l); -luaL_buffinit(L,&b); -for(i=0;i0) -luaL_addlstring(&b,s,l); -luaL_pushresult(&b); -return 1; -} -static int str_byte(lua_State*L){ -size_t l; -const char*s=luaL_checklstring(L,1,&l); -ptrdiff_t posi=posrelat(luaL_optinteger(L,2,1),l); -ptrdiff_t pose=posrelat(luaL_optinteger(L,3,posi),l); -int n,i; -if(posi<=0)posi=1; -if((size_t)pose>l)pose=l; -if(posi>pose)return 0; -n=(int)(pose-posi+1); -if(posi+n<=pose) -luaL_error(L,"string slice too long"); -luaL_checkstack(L,n,"string slice too long"); -for(i=0;i=ms->level||ms->capture[l].len==(-1)) -return luaL_error(ms->L,"invalid capture index"); -return l; -} -static int capture_to_close(MatchState*ms){ -int level=ms->level; -for(level--;level>=0;level--) -if(ms->capture[level].len==(-1))return level; -return luaL_error(ms->L,"invalid pattern capture"); -} -static const char*classend(MatchState*ms,const char*p){ -switch(*p++){ -case'%':{ -if(*p=='\0') -luaL_error(ms->L,"malformed pattern (ends with "LUA_QL("%%")")"); -return p+1; -} -case'[':{ -if(*p=='^')p++; -do{ -if(*p=='\0') -luaL_error(ms->L,"malformed pattern (missing "LUA_QL("]")")"); -if(*(p++)=='%'&&*p!='\0') -p++; -}while(*p!=']'); -return p+1; -} -default:{ -return p; -} -} -} -static int match_class(int c,int cl){ -int res; -switch(tolower(cl)){ -case'a':res=isalpha(c);break; -case'c':res=iscntrl(c);break; -case'd':res=isdigit(c);break; -case'l':res=islower(c);break; -case'p':res=ispunct(c);break; -case's':res=isspace(c);break; -case'u':res=isupper(c);break; -case'w':res=isalnum(c);break; -case'x':res=isxdigit(c);break; -case'z':res=(c==0);break; -default:return(cl==c); -} -return(islower(cl)?res:!res); -} -static int matchbracketclass(int c,const char*p,const char*ec){ -int sig=1; -if(*(p+1)=='^'){ -sig=0; -p++; -} -while(++pL,"unbalanced pattern"); -if(*s!=*p)return NULL; -else{ -int b=*p; -int e=*(p+1); -int cont=1; -while(++ssrc_end){ -if(*s==e){ -if(--cont==0)return s+1; -} -else if(*s==b)cont++; -} -} -return NULL; -} -static const char*max_expand(MatchState*ms,const char*s, -const char*p,const char*ep){ -ptrdiff_t i=0; -while((s+i)src_end&&singlematch(uchar(*(s+i)),p,ep)) -i++; -while(i>=0){ -const char*res=match(ms,(s+i),ep+1); -if(res)return res; -i--; -} -return NULL; -} -static const char*min_expand(MatchState*ms,const char*s, -const char*p,const char*ep){ -for(;;){ -const char*res=match(ms,s,ep+1); -if(res!=NULL) -return res; -else if(ssrc_end&&singlematch(uchar(*s),p,ep)) -s++; -else return NULL; -} -} -static const char*start_capture(MatchState*ms,const char*s, -const char*p,int what){ -const char*res; -int level=ms->level; -if(level>=32)luaL_error(ms->L,"too many captures"); -ms->capture[level].init=s; -ms->capture[level].len=what; -ms->level=level+1; -if((res=match(ms,s,p))==NULL) -ms->level--; -return res; -} -static const char*end_capture(MatchState*ms,const char*s, -const char*p){ -int l=capture_to_close(ms); -const char*res; -ms->capture[l].len=s-ms->capture[l].init; -if((res=match(ms,s,p))==NULL) -ms->capture[l].len=(-1); -return res; -} -static const char*match_capture(MatchState*ms,const char*s,int l){ -size_t len; -l=check_capture(ms,l); -len=ms->capture[l].len; -if((size_t)(ms->src_end-s)>=len&& -memcmp(ms->capture[l].init,s,len)==0) -return s+len; -else return NULL; -} -static const char*match(MatchState*ms,const char*s,const char*p){ -init: -switch(*p){ -case'(':{ -if(*(p+1)==')') -return start_capture(ms,s,p+2,(-2)); -else -return start_capture(ms,s,p+1,(-1)); -} -case')':{ -return end_capture(ms,s,p+1); -} -case'%':{ -switch(*(p+1)){ -case'b':{ -s=matchbalance(ms,s,p+2); -if(s==NULL)return NULL; -p+=4;goto init; -} -case'f':{ -const char*ep;char previous; -p+=2; -if(*p!='[') -luaL_error(ms->L,"missing "LUA_QL("[")" after " -LUA_QL("%%f")" in pattern"); -ep=classend(ms,p); -previous=(s==ms->src_init)?'\0':*(s-1); -if(matchbracketclass(uchar(previous),p,ep-1)|| -!matchbracketclass(uchar(*s),p,ep-1))return NULL; -p=ep;goto init; -} -default:{ -if(isdigit(uchar(*(p+1)))){ -s=match_capture(ms,s,uchar(*(p+1))); -if(s==NULL)return NULL; -p+=2;goto init; -} -goto dflt; -} -} -} -case'\0':{ -return s; -} -case'$':{ -if(*(p+1)=='\0') -return(s==ms->src_end)?s:NULL; -else goto dflt; -} -default:dflt:{ -const char*ep=classend(ms,p); -int m=ssrc_end&&singlematch(uchar(*s),p,ep); -switch(*ep){ -case'?':{ -const char*res; -if(m&&((res=match(ms,s+1,ep+1))!=NULL)) -return res; -p=ep+1;goto init; -} -case'*':{ -return max_expand(ms,s,p,ep); -} -case'+':{ -return(m?max_expand(ms,s+1,p,ep):NULL); -} -case'-':{ -return min_expand(ms,s,p,ep); -} -default:{ -if(!m)return NULL; -s++;p=ep;goto init; -} -} -} -} -} -static const char*lmemfind(const char*s1,size_t l1, -const char*s2,size_t l2){ -if(l2==0)return s1; -else if(l2>l1)return NULL; -else{ -const char*init; -l2--; -l1=l1-l2; -while(l1>0&&(init=(const char*)memchr(s1,*s2,l1))!=NULL){ -init++; -if(memcmp(init,s2+1,l2)==0) -return init-1; -else{ -l1-=init-s1; -s1=init; -} -} -return NULL; -} -} -static void push_onecapture(MatchState*ms,int i,const char*s, -const char*e){ -if(i>=ms->level){ -if(i==0) -lua_pushlstring(ms->L,s,e-s); -else -luaL_error(ms->L,"invalid capture index"); -} -else{ -ptrdiff_t l=ms->capture[i].len; -if(l==(-1))luaL_error(ms->L,"unfinished capture"); -if(l==(-2)) -lua_pushinteger(ms->L,ms->capture[i].init-ms->src_init+1); -else -lua_pushlstring(ms->L,ms->capture[i].init,l); -} -} -static int push_captures(MatchState*ms,const char*s,const char*e){ -int i; -int nlevels=(ms->level==0&&s)?1:ms->level; -luaL_checkstack(ms->L,nlevels,"too many captures"); -for(i=0;il1)init=(ptrdiff_t)l1; -if(find&&(lua_toboolean(L,4)|| -strpbrk(p,"^$*+?.([%-")==NULL)){ -const char*s2=lmemfind(s+init,l1-init,p,l2); -if(s2){ -lua_pushinteger(L,s2-s+1); -lua_pushinteger(L,s2-s+l2); -return 2; -} -} -else{ -MatchState ms; -int anchor=(*p=='^')?(p++,1):0; -const char*s1=s+init; -ms.L=L; -ms.src_init=s; -ms.src_end=s+l1; -do{ -const char*res; -ms.level=0; -if((res=match(&ms,s1,p))!=NULL){ -if(find){ -lua_pushinteger(L,s1-s+1); -lua_pushinteger(L,res-s); -return push_captures(&ms,NULL,0)+2; -} -else -return push_captures(&ms,s1,res); -} -}while(s1++L,3,&l); -for(i=0;iL; -switch(lua_type(L,3)){ -case 3: -case 4:{ -add_s(ms,b,s,e); -return; -} -case 6:{ -int n; -lua_pushvalue(L,3); -n=push_captures(ms,s,e); -lua_call(L,n,1); -break; -} -case 5:{ -push_onecapture(ms,0,s,e); -lua_gettable(L,3); -break; -} -} -if(!lua_toboolean(L,-1)){ -lua_pop(L,1); -lua_pushlstring(L,s,e-s); -} -else if(!lua_isstring(L,-1)) -luaL_error(L,"invalid replacement value (a %s)",luaL_typename(L,-1)); -luaL_addvalue(b); -} -static int str_gsub(lua_State*L){ -size_t srcl; -const char*src=luaL_checklstring(L,1,&srcl); -const char*p=luaL_checkstring(L,2); -int tr=lua_type(L,3); -int max_s=luaL_optint(L,4,srcl+1); -int anchor=(*p=='^')?(p++,1):0; -int n=0; -MatchState ms; -luaL_Buffer b; -luaL_argcheck(L,tr==3||tr==4|| -tr==6||tr==5,3, -"string/function/table expected"); -luaL_buffinit(L,&b); -ms.L=L; -ms.src_init=src; -ms.src_end=src+srcl; -while(nsrc) -src=e; -else if(src=sizeof("-+ #0")) -luaL_error(L,"invalid format (repeated flags)"); -if(isdigit(uchar(*p)))p++; -if(isdigit(uchar(*p)))p++; -if(*p=='.'){ -p++; -if(isdigit(uchar(*p)))p++; -if(isdigit(uchar(*p)))p++; -} -if(isdigit(uchar(*p))) -luaL_error(L,"invalid format (width or precision too long)"); -*(form++)='%'; -strncpy(form,strfrmt,p-strfrmt+1); -form+=p-strfrmt+1; -*form='\0'; -return p; -} -static void addintlen(char*form){ -size_t l=strlen(form); -char spec=form[l-1]; -strcpy(form+l-1,"l"); -form[l+sizeof("l")-2]=spec; -form[l+sizeof("l")-1]='\0'; -} -static int str_format(lua_State*L){ -int top=lua_gettop(L); -int arg=1; -size_t sfl; -const char*strfrmt=luaL_checklstring(L,arg,&sfl); -const char*strfrmt_end=strfrmt+sfl; -luaL_Buffer b; -luaL_buffinit(L,&b); -while(strfrmttop) -luaL_argerror(L,arg,"no value"); -strfrmt=scanformat(L,strfrmt,form); -switch(*strfrmt++){ -case'c':{ -sprintf(buff,form,(int)luaL_checknumber(L,arg)); -break; -} -case'd':case'i':{ -addintlen(form); -sprintf(buff,form,(long)luaL_checknumber(L,arg)); -break; -} -case'o':case'u':case'x':case'X':{ -addintlen(form); -sprintf(buff,form,(unsigned long)luaL_checknumber(L,arg)); -break; -} -case'e':case'E':case'f': -case'g':case'G':{ -sprintf(buff,form,(double)luaL_checknumber(L,arg)); -break; -} -case'q':{ -addquoted(L,&b,arg); -continue; -} -case's':{ -size_t l; -const char*s=luaL_checklstring(L,arg,&l); -if(!strchr(form,'.')&&l>=100){ -lua_pushvalue(L,arg); -luaL_addvalue(&b); -continue; -} -else{ -sprintf(buff,form,s); -break; -} -} -default:{ -return luaL_error(L,"invalid option "LUA_QL("%%%c")" to " -LUA_QL("format"),*(strfrmt-1)); -} -} -luaL_addlstring(&b,buff,strlen(buff)); -} -} -luaL_pushresult(&b); -return 1; -} -static const luaL_Reg strlib[]={ -{"byte",str_byte}, -{"char",str_char}, -{"find",str_find}, -{"format",str_format}, -{"gmatch",gmatch}, -{"gsub",str_gsub}, -{"lower",str_lower}, -{"match",str_match}, -{"rep",str_rep}, -{"sub",str_sub}, -{"upper",str_upper}, -{NULL,NULL} -}; -static void createmetatable(lua_State*L){ -lua_createtable(L,0,1); -lua_pushliteral(L,""); -lua_pushvalue(L,-2); -lua_setmetatable(L,-2); -lua_pop(L,1); -lua_pushvalue(L,-2); -lua_setfield(L,-2,"__index"); -lua_pop(L,1); -} -static int luaopen_string(lua_State*L){ -luaL_register(L,"string",strlib); -createmetatable(L); -return 1; -} -static const luaL_Reg lualibs[]={ -{"",luaopen_base}, -{"table",luaopen_table}, -{"io",luaopen_io}, -{"os",luaopen_os}, -{"string",luaopen_string}, -{NULL,NULL} -}; -static void luaL_openlibs(lua_State*L){ -const luaL_Reg*lib=lualibs; -for(;lib->func;lib++){ -lua_pushcfunction(L,lib->func); -lua_pushstring(L,lib->name); -lua_call(L,1,0); -} -} -typedef unsigned int UB; -static UB barg(lua_State*L,int idx){ -union{lua_Number n;U64 b;}bn; -bn.n=lua_tonumber(L,idx)+6755399441055744.0; -if(bn.n==0.0&&!lua_isnumber(L,idx))luaL_typerror(L,idx,"number"); -return(UB)bn.b; -} -#define BRET(b)lua_pushnumber(L,(lua_Number)(int)(b));return 1; -static int tobit(lua_State*L){ -BRET(barg(L,1))} -static int bnot(lua_State*L){ -BRET(~barg(L,1))} -static int band(lua_State*L){ -int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b&=barg(L,i);BRET(b)} -static int bor(lua_State*L){ -int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b|=barg(L,i);BRET(b)} -static int bxor(lua_State*L){ -int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b^=barg(L,i);BRET(b)} -static int lshift(lua_State*L){ -UB b=barg(L,1),n=barg(L,2)&31;BRET(b<>n)} -static int arshift(lua_State*L){ -UB b=barg(L,1),n=barg(L,2)&31;BRET((int)b>>n)} -static int rol(lua_State*L){ -UB b=barg(L,1),n=barg(L,2)&31;BRET((b<>(32-n)))} -static int ror(lua_State*L){ -UB b=barg(L,1),n=barg(L,2)&31;BRET((b>>n)|(b<<(32-n)))} -static int bswap(lua_State*L){ -UB b=barg(L,1);b=(b>>24)|((b>>8)&0xff00)|((b&0xff00)<<8)|(b<<24);BRET(b)} -static int tohex(lua_State*L){ -UB b=barg(L,1); -int n=lua_isnone(L,2)?8:(int)barg(L,2); -const char*hexdigits="0123456789abcdef"; -char buf[8]; -int i; -if(n<0){n=-n;hexdigits="0123456789ABCDEF";} -if(n>8)n=8; -for(i=(int)n;--i>=0;){buf[i]=hexdigits[b&15];b>>=4;} -lua_pushlstring(L,buf,(size_t)n); -return 1; -} -static const struct luaL_Reg bitlib[]={ -{"tobit",tobit}, -{"bnot",bnot}, -{"band",band}, -{"bor",bor}, -{"bxor",bxor}, -{"lshift",lshift}, -{"rshift",rshift}, -{"arshift",arshift}, -{"rol",rol}, -{"ror",ror}, -{"bswap",bswap}, -{"tohex",tohex}, -{NULL,NULL} -}; -int main(int argc,char**argv){ -lua_State*L=luaL_newstate(); -int i; -luaL_openlibs(L); -luaL_register(L,"bit",bitlib); -if(argc<2)return sizeof(void*); -lua_createtable(L,0,1); -lua_pushstring(L,argv[1]); -lua_rawseti(L,-2,0); -lua_setglobal(L,"arg"); -if(luaL_loadfile(L,argv[1])) -goto err; -for(i=2;i -- BYTECODE -- [...] --- print(bc.line(foo, 2)) --> 0002 KSTR 1 1 ; "hello" --- --- local out = { --- -- Do something with each line: --- write = function(t, ...) io.write(...) end, --- close = function(t) end, --- flush = function(t) end, --- } --- bc.dump(foo, out) --- ------------------------------------------------------------------------------- - --- Cache some library functions and objects. -local jit = require("jit") -assert(jit.version_num == 20100, "LuaJIT core/library version mismatch") -local jutil = require("jit.util") -local vmdef = require("jit.vmdef") -local bit = require("bit") -local sub, gsub, format = string.sub, string.gsub, string.format -local byte, band, shr = string.byte, bit.band, bit.rshift -local funcinfo, funcbc, funck = jutil.funcinfo, jutil.funcbc, jutil.funck -local funcuvname = jutil.funcuvname -local bcnames = vmdef.bcnames -local stdout, stderr = io.stdout, io.stderr - ------------------------------------------------------------------------------- - -local function ctlsub(c) - if c == "\n" then return "\\n" - elseif c == "\r" then return "\\r" - elseif c == "\t" then return "\\t" - else return format("\\%03d", byte(c)) - end -end - --- Return one bytecode line. -local function bcline(func, pc, prefix) - local ins, m = funcbc(func, pc) - if not ins then return end - local ma, mb, mc = band(m, 7), band(m, 15*8), band(m, 15*128) - local a = band(shr(ins, 8), 0xff) - local oidx = 6*band(ins, 0xff) - local op = sub(bcnames, oidx+1, oidx+6) - local s = format("%04d %s %-6s %3s ", - pc, prefix or " ", op, ma == 0 and "" or a) - local d = shr(ins, 16) - if mc == 13*128 then -- BCMjump - return format("%s=> %04d\n", s, pc+d-0x7fff) - end - if mb ~= 0 then - d = band(d, 0xff) - elseif mc == 0 then - return s.."\n" - end - local kc - if mc == 10*128 then -- BCMstr - kc = funck(func, -d-1) - kc = format(#kc > 40 and '"%.40s"~' or '"%s"', gsub(kc, "%c", ctlsub)) - elseif mc == 9*128 then -- BCMnum - kc = funck(func, d) - if op == "TSETM " then kc = kc - 2^52 end - elseif mc == 12*128 then -- BCMfunc - local fi = funcinfo(funck(func, -d-1)) - if fi.ffid then - kc = vmdef.ffnames[fi.ffid] - else - kc = fi.loc - end - elseif mc == 5*128 then -- BCMuv - kc = funcuvname(func, d) - end - if ma == 5 then -- BCMuv - local ka = funcuvname(func, a) - if kc then kc = ka.." ; "..kc else kc = ka end - end - if mb ~= 0 then - local b = shr(ins, 24) - if kc then return format("%s%3d %3d ; %s\n", s, b, d, kc) end - return format("%s%3d %3d\n", s, b, d) - end - if kc then return format("%s%3d ; %s\n", s, d, kc) end - if mc == 7*128 and d > 32767 then d = d - 65536 end -- BCMlits - return format("%s%3d\n", s, d) -end - --- Collect branch targets of a function. -local function bctargets(func) - local target = {} - for pc=1,1000000000 do - local ins, m = funcbc(func, pc) - if not ins then break end - if band(m, 15*128) == 13*128 then target[pc+shr(ins, 16)-0x7fff] = true end - end - return target -end - --- Dump bytecode instructions of a function. -local function bcdump(func, out, all) - if not out then out = stdout end - local fi = funcinfo(func) - if all and fi.children then - for n=-1,-1000000000,-1 do - local k = funck(func, n) - if not k then break end - if type(k) == "proto" then bcdump(k, out, true) end - end - end - out:write(format("-- BYTECODE -- %s-%d\n", fi.loc, fi.lastlinedefined)) - local target = bctargets(func) - for pc=1,1000000000 do - local s = bcline(func, pc, target[pc] and "=>") - if not s then break end - out:write(s) - end - out:write("\n") - out:flush() -end - ------------------------------------------------------------------------------- - --- Active flag and output file handle. -local active, out - --- List handler. -local function h_list(func) - return bcdump(func, out) -end - --- Detach list handler. -local function bclistoff() - if active then - active = false - jit.attach(h_list) - if out and out ~= stdout and out ~= stderr then out:close() end - out = nil - end -end - --- Open the output file and attach list handler. -local function bcliston(outfile) - if active then bclistoff() end - if not outfile then outfile = os.getenv("LUAJIT_LISTFILE") end - if outfile then - out = outfile == "-" and stdout or assert(io.open(outfile, "w")) - else - out = stderr - end - jit.attach(h_list, "bc") - active = true -end - --- Public module functions. -return { - line = bcline, - dump = bcdump, - targets = bctargets, - on = bcliston, - off = bclistoff, - start = bcliston -- For -j command line option. -} - diff --git a/lib/LuaJIT/src/jit/bcsave.lua b/lib/LuaJIT/src/jit/bcsave.lua deleted file mode 100644 index 2553d97..0000000 --- a/lib/LuaJIT/src/jit/bcsave.lua +++ /dev/null @@ -1,661 +0,0 @@ ----------------------------------------------------------------------------- --- LuaJIT module to save/list bytecode. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- Released under the MIT license. See Copyright Notice in luajit.h ----------------------------------------------------------------------------- --- --- This module saves or lists the bytecode for an input file. --- It's run by the -b command line option. --- ------------------------------------------------------------------------------- - -local jit = require("jit") -assert(jit.version_num == 20100, "LuaJIT core/library version mismatch") -local bit = require("bit") - --- Symbol name prefix for LuaJIT bytecode. -local LJBC_PREFIX = "luaJIT_BC_" - ------------------------------------------------------------------------------- - -local function usage() - io.stderr:write[[ -Save LuaJIT bytecode: luajit -b[options] input output - -l Only list bytecode. - -s Strip debug info (default). - -g Keep debug info. - -n name Set module name (default: auto-detect from input name). - -t type Set output file type (default: auto-detect from output name). - -a arch Override architecture for object files (default: native). - -o os Override OS for object files (default: native). - -e chunk Use chunk string as input. - -- Stop handling options. - - Use stdin as input and/or stdout as output. - -File types: c h obj o raw (default) -]] - os.exit(1) -end - -local function check(ok, ...) - if ok then return ok, ... end - io.stderr:write("luajit: ", ...) - io.stderr:write("\n") - os.exit(1) -end - -local function readfile(input) - if type(input) == "function" then return input end - if input == "-" then input = nil end - return check(loadfile(input)) -end - -local function savefile(name, mode) - if name == "-" then return io.stdout end - return check(io.open(name, mode)) -end - ------------------------------------------------------------------------------- - -local map_type = { - raw = "raw", c = "c", h = "h", o = "obj", obj = "obj", -} - -local map_arch = { - x86 = true, x64 = true, arm = true, arm64 = true, arm64be = true, - ppc = true, mips = true, mipsel = true, -} - -local map_os = { - linux = true, windows = true, osx = true, freebsd = true, netbsd = true, - openbsd = true, dragonfly = true, solaris = true, -} - -local function checkarg(str, map, err) - str = string.lower(str) - local s = check(map[str], "unknown ", err) - return s == true and str or s -end - -local function detecttype(str) - local ext = string.match(string.lower(str), "%.(%a+)$") - return map_type[ext] or "raw" -end - -local function checkmodname(str) - check(string.match(str, "^[%w_.%-]+$"), "bad module name") - return string.gsub(str, "[%.%-]", "_") -end - -local function detectmodname(str) - if type(str) == "string" then - local tail = string.match(str, "[^/\\]+$") - if tail then str = tail end - local head = string.match(str, "^(.*)%.[^.]*$") - if head then str = head end - str = string.match(str, "^[%w_.%-]+") - else - str = nil - end - check(str, "cannot derive module name, use -n name") - return string.gsub(str, "[%.%-]", "_") -end - ------------------------------------------------------------------------------- - -local function bcsave_tail(fp, output, s) - local ok, err = fp:write(s) - if ok and output ~= "-" then ok, err = fp:close() end - check(ok, "cannot write ", output, ": ", err) -end - -local function bcsave_raw(output, s) - local fp = savefile(output, "wb") - bcsave_tail(fp, output, s) -end - -local function bcsave_c(ctx, output, s) - local fp = savefile(output, "w") - if ctx.type == "c" then - fp:write(string.format([[ -#ifdef _cplusplus -extern "C" -#endif -#ifdef _WIN32 -__declspec(dllexport) -#endif -const unsigned char %s%s[] = { -]], LJBC_PREFIX, ctx.modname)) - else - fp:write(string.format([[ -#define %s%s_SIZE %d -static const unsigned char %s%s[] = { -]], LJBC_PREFIX, ctx.modname, #s, LJBC_PREFIX, ctx.modname)) - end - local t, n, m = {}, 0, 0 - for i=1,#s do - local b = tostring(string.byte(s, i)) - m = m + #b + 1 - if m > 78 then - fp:write(table.concat(t, ",", 1, n), ",\n") - n, m = 0, #b + 1 - end - n = n + 1 - t[n] = b - end - bcsave_tail(fp, output, table.concat(t, ",", 1, n).."\n};\n") -end - -local function bcsave_elfobj(ctx, output, s, ffi) - ffi.cdef[[ -typedef struct { - uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7]; - uint16_t type, machine; - uint32_t version; - uint32_t entry, phofs, shofs; - uint32_t flags; - uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx; -} ELF32header; -typedef struct { - uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7]; - uint16_t type, machine; - uint32_t version; - uint64_t entry, phofs, shofs; - uint32_t flags; - uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx; -} ELF64header; -typedef struct { - uint32_t name, type, flags, addr, ofs, size, link, info, align, entsize; -} ELF32sectheader; -typedef struct { - uint32_t name, type; - uint64_t flags, addr, ofs, size; - uint32_t link, info; - uint64_t align, entsize; -} ELF64sectheader; -typedef struct { - uint32_t name, value, size; - uint8_t info, other; - uint16_t sectidx; -} ELF32symbol; -typedef struct { - uint32_t name; - uint8_t info, other; - uint16_t sectidx; - uint64_t value, size; -} ELF64symbol; -typedef struct { - ELF32header hdr; - ELF32sectheader sect[6]; - ELF32symbol sym[2]; - uint8_t space[4096]; -} ELF32obj; -typedef struct { - ELF64header hdr; - ELF64sectheader sect[6]; - ELF64symbol sym[2]; - uint8_t space[4096]; -} ELF64obj; -]] - local symname = LJBC_PREFIX..ctx.modname - local is64, isbe = false, false - if ctx.arch == "x64" or ctx.arch == "arm64" or ctx.arch == "arm64be" then - is64 = true - elseif ctx.arch == "ppc" or ctx.arch == "mips" then - isbe = true - end - - -- Handle different host/target endianess. - local function f32(x) return x end - local f16, fofs = f32, f32 - if ffi.abi("be") ~= isbe then - f32 = bit.bswap - function f16(x) return bit.rshift(bit.bswap(x), 16) end - if is64 then - local two32 = ffi.cast("int64_t", 2^32) - function fofs(x) return bit.bswap(x)*two32 end - else - fofs = f32 - end - end - - -- Create ELF object and fill in header. - local o = ffi.new(is64 and "ELF64obj" or "ELF32obj") - local hdr = o.hdr - if ctx.os == "bsd" or ctx.os == "other" then -- Determine native hdr.eosabi. - local bf = assert(io.open("/bin/ls", "rb")) - local bs = bf:read(9) - bf:close() - ffi.copy(o, bs, 9) - check(hdr.emagic[0] == 127, "no support for writing native object files") - else - hdr.emagic = "\127ELF" - hdr.eosabi = ({ freebsd=9, netbsd=2, openbsd=12, solaris=6 })[ctx.os] or 0 - end - hdr.eclass = is64 and 2 or 1 - hdr.eendian = isbe and 2 or 1 - hdr.eversion = 1 - hdr.type = f16(1) - hdr.machine = f16(({ x86=3, x64=62, arm=40, arm64=183, arm64be=183, ppc=20, mips=8, mipsel=8 })[ctx.arch]) - if ctx.arch == "mips" or ctx.arch == "mipsel" then - hdr.flags = f32(0x50001006) - end - hdr.version = f32(1) - hdr.shofs = fofs(ffi.offsetof(o, "sect")) - hdr.ehsize = f16(ffi.sizeof(hdr)) - hdr.shentsize = f16(ffi.sizeof(o.sect[0])) - hdr.shnum = f16(6) - hdr.shstridx = f16(2) - - -- Fill in sections and symbols. - local sofs, ofs = ffi.offsetof(o, "space"), 1 - for i,name in ipairs{ - ".symtab", ".shstrtab", ".strtab", ".rodata", ".note.GNU-stack", - } do - local sect = o.sect[i] - sect.align = fofs(1) - sect.name = f32(ofs) - ffi.copy(o.space+ofs, name) - ofs = ofs + #name+1 - end - o.sect[1].type = f32(2) -- .symtab - o.sect[1].link = f32(3) - o.sect[1].info = f32(1) - o.sect[1].align = fofs(8) - o.sect[1].ofs = fofs(ffi.offsetof(o, "sym")) - o.sect[1].entsize = fofs(ffi.sizeof(o.sym[0])) - o.sect[1].size = fofs(ffi.sizeof(o.sym)) - o.sym[1].name = f32(1) - o.sym[1].sectidx = f16(4) - o.sym[1].size = fofs(#s) - o.sym[1].info = 17 - o.sect[2].type = f32(3) -- .shstrtab - o.sect[2].ofs = fofs(sofs) - o.sect[2].size = fofs(ofs) - o.sect[3].type = f32(3) -- .strtab - o.sect[3].ofs = fofs(sofs + ofs) - o.sect[3].size = fofs(#symname+2) - ffi.copy(o.space+ofs+1, symname) - ofs = ofs + #symname + 2 - o.sect[4].type = f32(1) -- .rodata - o.sect[4].flags = fofs(2) - o.sect[4].ofs = fofs(sofs + ofs) - o.sect[4].size = fofs(#s) - o.sect[5].type = f32(1) -- .note.GNU-stack - o.sect[5].ofs = fofs(sofs + ofs + #s) - - -- Write ELF object file. - local fp = savefile(output, "wb") - fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs)) - bcsave_tail(fp, output, s) -end - -local function bcsave_peobj(ctx, output, s, ffi) - ffi.cdef[[ -typedef struct { - uint16_t arch, nsects; - uint32_t time, symtabofs, nsyms; - uint16_t opthdrsz, flags; -} PEheader; -typedef struct { - char name[8]; - uint32_t vsize, vaddr, size, ofs, relocofs, lineofs; - uint16_t nreloc, nline; - uint32_t flags; -} PEsection; -typedef struct __attribute((packed)) { - union { - char name[8]; - uint32_t nameref[2]; - }; - uint32_t value; - int16_t sect; - uint16_t type; - uint8_t scl, naux; -} PEsym; -typedef struct __attribute((packed)) { - uint32_t size; - uint16_t nreloc, nline; - uint32_t cksum; - uint16_t assoc; - uint8_t comdatsel, unused[3]; -} PEsymaux; -typedef struct { - PEheader hdr; - PEsection sect[2]; - // Must be an even number of symbol structs. - PEsym sym0; - PEsymaux sym0aux; - PEsym sym1; - PEsymaux sym1aux; - PEsym sym2; - PEsym sym3; - uint32_t strtabsize; - uint8_t space[4096]; -} PEobj; -]] - local symname = LJBC_PREFIX..ctx.modname - local is64 = false - if ctx.arch == "x86" then - symname = "_"..symname - elseif ctx.arch == "x64" then - is64 = true - end - local symexport = " /EXPORT:"..symname..",DATA " - - -- The file format is always little-endian. Swap if the host is big-endian. - local function f32(x) return x end - local f16 = f32 - if ffi.abi("be") then - f32 = bit.bswap - function f16(x) return bit.rshift(bit.bswap(x), 16) end - end - - -- Create PE object and fill in header. - local o = ffi.new("PEobj") - local hdr = o.hdr - hdr.arch = f16(({ x86=0x14c, x64=0x8664, arm=0x1c0, ppc=0x1f2, mips=0x366, mipsel=0x366 })[ctx.arch]) - hdr.nsects = f16(2) - hdr.symtabofs = f32(ffi.offsetof(o, "sym0")) - hdr.nsyms = f32(6) - - -- Fill in sections and symbols. - o.sect[0].name = ".drectve" - o.sect[0].size = f32(#symexport) - o.sect[0].flags = f32(0x00100a00) - o.sym0.sect = f16(1) - o.sym0.scl = 3 - o.sym0.name = ".drectve" - o.sym0.naux = 1 - o.sym0aux.size = f32(#symexport) - o.sect[1].name = ".rdata" - o.sect[1].size = f32(#s) - o.sect[1].flags = f32(0x40300040) - o.sym1.sect = f16(2) - o.sym1.scl = 3 - o.sym1.name = ".rdata" - o.sym1.naux = 1 - o.sym1aux.size = f32(#s) - o.sym2.sect = f16(2) - o.sym2.scl = 2 - o.sym2.nameref[1] = f32(4) - o.sym3.sect = f16(-1) - o.sym3.scl = 2 - o.sym3.value = f32(1) - o.sym3.name = "@feat.00" -- Mark as SafeSEH compliant. - ffi.copy(o.space, symname) - local ofs = #symname + 1 - o.strtabsize = f32(ofs + 4) - o.sect[0].ofs = f32(ffi.offsetof(o, "space") + ofs) - ffi.copy(o.space + ofs, symexport) - ofs = ofs + #symexport - o.sect[1].ofs = f32(ffi.offsetof(o, "space") + ofs) - - -- Write PE object file. - local fp = savefile(output, "wb") - fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs)) - bcsave_tail(fp, output, s) -end - -local function bcsave_machobj(ctx, output, s, ffi) - ffi.cdef[[ -typedef struct -{ - uint32_t magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags; -} mach_header; -typedef struct -{ - mach_header; uint32_t reserved; -} mach_header_64; -typedef struct { - uint32_t cmd, cmdsize; - char segname[16]; - uint32_t vmaddr, vmsize, fileoff, filesize; - uint32_t maxprot, initprot, nsects, flags; -} mach_segment_command; -typedef struct { - uint32_t cmd, cmdsize; - char segname[16]; - uint64_t vmaddr, vmsize, fileoff, filesize; - uint32_t maxprot, initprot, nsects, flags; -} mach_segment_command_64; -typedef struct { - char sectname[16], segname[16]; - uint32_t addr, size; - uint32_t offset, align, reloff, nreloc, flags; - uint32_t reserved1, reserved2; -} mach_section; -typedef struct { - char sectname[16], segname[16]; - uint64_t addr, size; - uint32_t offset, align, reloff, nreloc, flags; - uint32_t reserved1, reserved2, reserved3; -} mach_section_64; -typedef struct { - uint32_t cmd, cmdsize, symoff, nsyms, stroff, strsize; -} mach_symtab_command; -typedef struct { - int32_t strx; - uint8_t type, sect; - int16_t desc; - uint32_t value; -} mach_nlist; -typedef struct { - uint32_t strx; - uint8_t type, sect; - uint16_t desc; - uint64_t value; -} mach_nlist_64; -typedef struct -{ - uint32_t magic, nfat_arch; -} mach_fat_header; -typedef struct -{ - uint32_t cputype, cpusubtype, offset, size, align; -} mach_fat_arch; -typedef struct { - struct { - mach_header hdr; - mach_segment_command seg; - mach_section sec; - mach_symtab_command sym; - } arch[1]; - mach_nlist sym_entry; - uint8_t space[4096]; -} mach_obj; -typedef struct { - struct { - mach_header_64 hdr; - mach_segment_command_64 seg; - mach_section_64 sec; - mach_symtab_command sym; - } arch[1]; - mach_nlist_64 sym_entry; - uint8_t space[4096]; -} mach_obj_64; -typedef struct { - mach_fat_header fat; - mach_fat_arch fat_arch[2]; - struct { - mach_header hdr; - mach_segment_command seg; - mach_section sec; - mach_symtab_command sym; - } arch[2]; - mach_nlist sym_entry; - uint8_t space[4096]; -} mach_fat_obj; -]] - local symname = '_'..LJBC_PREFIX..ctx.modname - local isfat, is64, align, mobj = false, false, 4, "mach_obj" - if ctx.arch == "x64" then - is64, align, mobj = true, 8, "mach_obj_64" - elseif ctx.arch == "arm" then - isfat, mobj = true, "mach_fat_obj" - elseif ctx.arch == "arm64" then - is64, align, isfat, mobj = true, 8, true, "mach_fat_obj" - else - check(ctx.arch == "x86", "unsupported architecture for OSX") - end - local function aligned(v, a) return bit.band(v+a-1, -a) end - local be32 = bit.bswap -- Mach-O FAT is BE, supported archs are LE. - - -- Create Mach-O object and fill in header. - local o = ffi.new(mobj) - local mach_size = aligned(ffi.offsetof(o, "space")+#symname+2, align) - local cputype = ({ x86={7}, x64={0x01000007}, arm={7,12}, arm64={0x01000007,0x0100000c} })[ctx.arch] - local cpusubtype = ({ x86={3}, x64={3}, arm={3,9}, arm64={3,0} })[ctx.arch] - if isfat then - o.fat.magic = be32(0xcafebabe) - o.fat.nfat_arch = be32(#cpusubtype) - end - - -- Fill in sections and symbols. - for i=0,#cpusubtype-1 do - local ofs = 0 - if isfat then - local a = o.fat_arch[i] - a.cputype = be32(cputype[i+1]) - a.cpusubtype = be32(cpusubtype[i+1]) - -- Subsequent slices overlap each other to share data. - ofs = ffi.offsetof(o, "arch") + i*ffi.sizeof(o.arch[0]) - a.offset = be32(ofs) - a.size = be32(mach_size-ofs+#s) - end - local a = o.arch[i] - a.hdr.magic = is64 and 0xfeedfacf or 0xfeedface - a.hdr.cputype = cputype[i+1] - a.hdr.cpusubtype = cpusubtype[i+1] - a.hdr.filetype = 1 - a.hdr.ncmds = 2 - a.hdr.sizeofcmds = ffi.sizeof(a.seg)+ffi.sizeof(a.sec)+ffi.sizeof(a.sym) - a.seg.cmd = is64 and 0x19 or 0x1 - a.seg.cmdsize = ffi.sizeof(a.seg)+ffi.sizeof(a.sec) - a.seg.vmsize = #s - a.seg.fileoff = mach_size-ofs - a.seg.filesize = #s - a.seg.maxprot = 1 - a.seg.initprot = 1 - a.seg.nsects = 1 - ffi.copy(a.sec.sectname, "__data") - ffi.copy(a.sec.segname, "__DATA") - a.sec.size = #s - a.sec.offset = mach_size-ofs - a.sym.cmd = 2 - a.sym.cmdsize = ffi.sizeof(a.sym) - a.sym.symoff = ffi.offsetof(o, "sym_entry")-ofs - a.sym.nsyms = 1 - a.sym.stroff = ffi.offsetof(o, "sym_entry")+ffi.sizeof(o.sym_entry)-ofs - a.sym.strsize = aligned(#symname+2, align) - end - o.sym_entry.type = 0xf - o.sym_entry.sect = 1 - o.sym_entry.strx = 1 - ffi.copy(o.space+1, symname) - - -- Write Macho-O object file. - local fp = savefile(output, "wb") - fp:write(ffi.string(o, mach_size)) - bcsave_tail(fp, output, s) -end - -local function bcsave_obj(ctx, output, s) - local ok, ffi = pcall(require, "ffi") - check(ok, "FFI library required to write this file type") - if ctx.os == "windows" then - return bcsave_peobj(ctx, output, s, ffi) - elseif ctx.os == "osx" then - return bcsave_machobj(ctx, output, s, ffi) - else - return bcsave_elfobj(ctx, output, s, ffi) - end -end - ------------------------------------------------------------------------------- - -local function bclist(input, output) - local f = readfile(input) - require("jit.bc").dump(f, savefile(output, "w"), true) -end - -local function bcsave(ctx, input, output) - local f = readfile(input) - local s = string.dump(f, ctx.strip) - local t = ctx.type - if not t then - t = detecttype(output) - ctx.type = t - end - if t == "raw" then - bcsave_raw(output, s) - else - if not ctx.modname then ctx.modname = detectmodname(input) end - if t == "obj" then - bcsave_obj(ctx, output, s) - else - bcsave_c(ctx, output, s) - end - end -end - -local function docmd(...) - local arg = {...} - local n = 1 - local list = false - local ctx = { - strip = true, arch = jit.arch, os = string.lower(jit.os), - type = false, modname = false, - } - while n <= #arg do - local a = arg[n] - if type(a) == "string" and string.sub(a, 1, 1) == "-" and a ~= "-" then - table.remove(arg, n) - if a == "--" then break end - for m=2,#a do - local opt = string.sub(a, m, m) - if opt == "l" then - list = true - elseif opt == "s" then - ctx.strip = true - elseif opt == "g" then - ctx.strip = false - else - if arg[n] == nil or m ~= #a then usage() end - if opt == "e" then - if n ~= 1 then usage() end - arg[1] = check(loadstring(arg[1])) - elseif opt == "n" then - ctx.modname = checkmodname(table.remove(arg, n)) - elseif opt == "t" then - ctx.type = checkarg(table.remove(arg, n), map_type, "file type") - elseif opt == "a" then - ctx.arch = checkarg(table.remove(arg, n), map_arch, "architecture") - elseif opt == "o" then - ctx.os = checkarg(table.remove(arg, n), map_os, "OS name") - else - usage() - end - end - end - else - n = n + 1 - end - end - if list then - if #arg == 0 or #arg > 2 then usage() end - bclist(arg[1], arg[2] or "-") - else - if #arg ~= 2 then usage() end - bcsave(ctx, arg[1], arg[2]) - end -end - ------------------------------------------------------------------------------- - --- Public module functions. -return { - start = docmd -- Process -b command line option. -} - diff --git a/lib/LuaJIT/src/jit/dis_arm.lua b/lib/LuaJIT/src/jit/dis_arm.lua deleted file mode 100644 index c2dd776..0000000 --- a/lib/LuaJIT/src/jit/dis_arm.lua +++ /dev/null @@ -1,689 +0,0 @@ ----------------------------------------------------------------------------- --- LuaJIT ARM disassembler module. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- Released under the MIT license. See Copyright Notice in luajit.h ----------------------------------------------------------------------------- --- This is a helper module used by the LuaJIT machine code dumper module. --- --- It disassembles most user-mode ARMv7 instructions --- NYI: Advanced SIMD and VFP instructions. ------------------------------------------------------------------------------- - -local type = type -local sub, byte, format = string.sub, string.byte, string.format -local match, gmatch = string.match, string.gmatch -local concat = table.concat -local bit = require("bit") -local band, bor, ror, tohex = bit.band, bit.bor, bit.ror, bit.tohex -local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift - ------------------------------------------------------------------------------- --- Opcode maps ------------------------------------------------------------------------------- - -local map_loadc = { - shift = 8, mask = 15, - [10] = { - shift = 20, mask = 1, - [0] = { - shift = 23, mask = 3, - [0] = "vmovFmDN", "vstmFNdr", - _ = { - shift = 21, mask = 1, - [0] = "vstrFdl", - { shift = 16, mask = 15, [13] = "vpushFdr", _ = "vstmdbFNdr", } - }, - }, - { - shift = 23, mask = 3, - [0] = "vmovFDNm", - { shift = 16, mask = 15, [13] = "vpopFdr", _ = "vldmFNdr", }, - _ = { - shift = 21, mask = 1, - [0] = "vldrFdl", "vldmdbFNdr", - }, - }, - }, - [11] = { - shift = 20, mask = 1, - [0] = { - shift = 23, mask = 3, - [0] = "vmovGmDN", "vstmGNdr", - _ = { - shift = 21, mask = 1, - [0] = "vstrGdl", - { shift = 16, mask = 15, [13] = "vpushGdr", _ = "vstmdbGNdr", } - }, - }, - { - shift = 23, mask = 3, - [0] = "vmovGDNm", - { shift = 16, mask = 15, [13] = "vpopGdr", _ = "vldmGNdr", }, - _ = { - shift = 21, mask = 1, - [0] = "vldrGdl", "vldmdbGNdr", - }, - }, - }, - _ = { - shift = 0, mask = 0 -- NYI ldc, mcrr, mrrc. - }, -} - -local map_vfps = { - shift = 6, mask = 0x2c001, - [0] = "vmlaF.dnm", "vmlsF.dnm", - [0x04000] = "vnmlsF.dnm", [0x04001] = "vnmlaF.dnm", - [0x08000] = "vmulF.dnm", [0x08001] = "vnmulF.dnm", - [0x0c000] = "vaddF.dnm", [0x0c001] = "vsubF.dnm", - [0x20000] = "vdivF.dnm", - [0x24000] = "vfnmsF.dnm", [0x24001] = "vfnmaF.dnm", - [0x28000] = "vfmaF.dnm", [0x28001] = "vfmsF.dnm", - [0x2c000] = "vmovF.dY", - [0x2c001] = { - shift = 7, mask = 0x1e01, - [0] = "vmovF.dm", "vabsF.dm", - [0x0200] = "vnegF.dm", [0x0201] = "vsqrtF.dm", - [0x0800] = "vcmpF.dm", [0x0801] = "vcmpeF.dm", - [0x0a00] = "vcmpzF.d", [0x0a01] = "vcmpzeF.d", - [0x0e01] = "vcvtG.dF.m", - [0x1000] = "vcvt.f32.u32Fdm", [0x1001] = "vcvt.f32.s32Fdm", - [0x1800] = "vcvtr.u32F.dm", [0x1801] = "vcvt.u32F.dm", - [0x1a00] = "vcvtr.s32F.dm", [0x1a01] = "vcvt.s32F.dm", - }, -} - -local map_vfpd = { - shift = 6, mask = 0x2c001, - [0] = "vmlaG.dnm", "vmlsG.dnm", - [0x04000] = "vnmlsG.dnm", [0x04001] = "vnmlaG.dnm", - [0x08000] = "vmulG.dnm", [0x08001] = "vnmulG.dnm", - [0x0c000] = "vaddG.dnm", [0x0c001] = "vsubG.dnm", - [0x20000] = "vdivG.dnm", - [0x24000] = "vfnmsG.dnm", [0x24001] = "vfnmaG.dnm", - [0x28000] = "vfmaG.dnm", [0x28001] = "vfmsG.dnm", - [0x2c000] = "vmovG.dY", - [0x2c001] = { - shift = 7, mask = 0x1e01, - [0] = "vmovG.dm", "vabsG.dm", - [0x0200] = "vnegG.dm", [0x0201] = "vsqrtG.dm", - [0x0800] = "vcmpG.dm", [0x0801] = "vcmpeG.dm", - [0x0a00] = "vcmpzG.d", [0x0a01] = "vcmpzeG.d", - [0x0e01] = "vcvtF.dG.m", - [0x1000] = "vcvt.f64.u32GdFm", [0x1001] = "vcvt.f64.s32GdFm", - [0x1800] = "vcvtr.u32FdG.m", [0x1801] = "vcvt.u32FdG.m", - [0x1a00] = "vcvtr.s32FdG.m", [0x1a01] = "vcvt.s32FdG.m", - }, -} - -local map_datac = { - shift = 24, mask = 1, - [0] = { - shift = 4, mask = 1, - [0] = { - shift = 8, mask = 15, - [10] = map_vfps, - [11] = map_vfpd, - -- NYI cdp, mcr, mrc. - }, - { - shift = 8, mask = 15, - [10] = { - shift = 20, mask = 15, - [0] = "vmovFnD", "vmovFDn", - [14] = "vmsrD", - [15] = { shift = 12, mask = 15, [15] = "vmrs", _ = "vmrsD", }, - }, - }, - }, - "svcT", -} - -local map_loadcu = { - shift = 0, mask = 0, -- NYI unconditional CP load/store. -} - -local map_datacu = { - shift = 0, mask = 0, -- NYI unconditional CP data. -} - -local map_simddata = { - shift = 0, mask = 0, -- NYI SIMD data. -} - -local map_simdload = { - shift = 0, mask = 0, -- NYI SIMD load/store, preload. -} - -local map_preload = { - shift = 0, mask = 0, -- NYI preload. -} - -local map_media = { - shift = 20, mask = 31, - [0] = false, - { --01 - shift = 5, mask = 7, - [0] = "sadd16DNM", "sasxDNM", "ssaxDNM", "ssub16DNM", - "sadd8DNM", false, false, "ssub8DNM", - }, - { --02 - shift = 5, mask = 7, - [0] = "qadd16DNM", "qasxDNM", "qsaxDNM", "qsub16DNM", - "qadd8DNM", false, false, "qsub8DNM", - }, - { --03 - shift = 5, mask = 7, - [0] = "shadd16DNM", "shasxDNM", "shsaxDNM", "shsub16DNM", - "shadd8DNM", false, false, "shsub8DNM", - }, - false, - { --05 - shift = 5, mask = 7, - [0] = "uadd16DNM", "uasxDNM", "usaxDNM", "usub16DNM", - "uadd8DNM", false, false, "usub8DNM", - }, - { --06 - shift = 5, mask = 7, - [0] = "uqadd16DNM", "uqasxDNM", "uqsaxDNM", "uqsub16DNM", - "uqadd8DNM", false, false, "uqsub8DNM", - }, - { --07 - shift = 5, mask = 7, - [0] = "uhadd16DNM", "uhasxDNM", "uhsaxDNM", "uhsub16DNM", - "uhadd8DNM", false, false, "uhsub8DNM", - }, - { --08 - shift = 5, mask = 7, - [0] = "pkhbtDNMU", false, "pkhtbDNMU", - { shift = 16, mask = 15, [15] = "sxtb16DMU", _ = "sxtab16DNMU", }, - "pkhbtDNMU", "selDNM", "pkhtbDNMU", - }, - false, - { --0a - shift = 5, mask = 7, - [0] = "ssatDxMu", "ssat16DxM", "ssatDxMu", - { shift = 16, mask = 15, [15] = "sxtbDMU", _ = "sxtabDNMU", }, - "ssatDxMu", false, "ssatDxMu", - }, - { --0b - shift = 5, mask = 7, - [0] = "ssatDxMu", "revDM", "ssatDxMu", - { shift = 16, mask = 15, [15] = "sxthDMU", _ = "sxtahDNMU", }, - "ssatDxMu", "rev16DM", "ssatDxMu", - }, - { --0c - shift = 5, mask = 7, - [3] = { shift = 16, mask = 15, [15] = "uxtb16DMU", _ = "uxtab16DNMU", }, - }, - false, - { --0e - shift = 5, mask = 7, - [0] = "usatDwMu", "usat16DwM", "usatDwMu", - { shift = 16, mask = 15, [15] = "uxtbDMU", _ = "uxtabDNMU", }, - "usatDwMu", false, "usatDwMu", - }, - { --0f - shift = 5, mask = 7, - [0] = "usatDwMu", "rbitDM", "usatDwMu", - { shift = 16, mask = 15, [15] = "uxthDMU", _ = "uxtahDNMU", }, - "usatDwMu", "revshDM", "usatDwMu", - }, - { --10 - shift = 12, mask = 15, - [15] = { - shift = 5, mask = 7, - "smuadNMS", "smuadxNMS", "smusdNMS", "smusdxNMS", - }, - _ = { - shift = 5, mask = 7, - [0] = "smladNMSD", "smladxNMSD", "smlsdNMSD", "smlsdxNMSD", - }, - }, - false, false, false, - { --14 - shift = 5, mask = 7, - [0] = "smlaldDNMS", "smlaldxDNMS", "smlsldDNMS", "smlsldxDNMS", - }, - { --15 - shift = 5, mask = 7, - [0] = { shift = 12, mask = 15, [15] = "smmulNMS", _ = "smmlaNMSD", }, - { shift = 12, mask = 15, [15] = "smmulrNMS", _ = "smmlarNMSD", }, - false, false, false, false, - "smmlsNMSD", "smmlsrNMSD", - }, - false, false, - { --18 - shift = 5, mask = 7, - [0] = { shift = 12, mask = 15, [15] = "usad8NMS", _ = "usada8NMSD", }, - }, - false, - { --1a - shift = 5, mask = 3, [2] = "sbfxDMvw", - }, - { --1b - shift = 5, mask = 3, [2] = "sbfxDMvw", - }, - { --1c - shift = 5, mask = 3, - [0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", }, - }, - { --1d - shift = 5, mask = 3, - [0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", }, - }, - { --1e - shift = 5, mask = 3, [2] = "ubfxDMvw", - }, - { --1f - shift = 5, mask = 3, [2] = "ubfxDMvw", - }, -} - -local map_load = { - shift = 21, mask = 9, - { - shift = 20, mask = 5, - [0] = "strtDL", "ldrtDL", [4] = "strbtDL", [5] = "ldrbtDL", - }, - _ = { - shift = 20, mask = 5, - [0] = "strDL", "ldrDL", [4] = "strbDL", [5] = "ldrbDL", - } -} - -local map_load1 = { - shift = 4, mask = 1, - [0] = map_load, map_media, -} - -local map_loadm = { - shift = 20, mask = 1, - [0] = { - shift = 23, mask = 3, - [0] = "stmdaNR", "stmNR", - { shift = 16, mask = 63, [45] = "pushR", _ = "stmdbNR", }, "stmibNR", - }, - { - shift = 23, mask = 3, - [0] = "ldmdaNR", { shift = 16, mask = 63, [61] = "popR", _ = "ldmNR", }, - "ldmdbNR", "ldmibNR", - }, -} - -local map_data = { - shift = 21, mask = 15, - [0] = "andDNPs", "eorDNPs", "subDNPs", "rsbDNPs", - "addDNPs", "adcDNPs", "sbcDNPs", "rscDNPs", - "tstNP", "teqNP", "cmpNP", "cmnNP", - "orrDNPs", "movDPs", "bicDNPs", "mvnDPs", -} - -local map_mul = { - shift = 21, mask = 7, - [0] = "mulNMSs", "mlaNMSDs", "umaalDNMS", "mlsDNMS", - "umullDNMSs", "umlalDNMSs", "smullDNMSs", "smlalDNMSs", -} - -local map_sync = { - shift = 20, mask = 15, -- NYI: brackets around N. R(D+1) for ldrexd/strexd. - [0] = "swpDMN", false, false, false, - "swpbDMN", false, false, false, - "strexDMN", "ldrexDN", "strexdDN", "ldrexdDN", - "strexbDMN", "ldrexbDN", "strexhDN", "ldrexhDN", -} - -local map_mulh = { - shift = 21, mask = 3, - [0] = { shift = 5, mask = 3, - [0] = "smlabbNMSD", "smlatbNMSD", "smlabtNMSD", "smlattNMSD", }, - { shift = 5, mask = 3, - [0] = "smlawbNMSD", "smulwbNMS", "smlawtNMSD", "smulwtNMS", }, - { shift = 5, mask = 3, - [0] = "smlalbbDNMS", "smlaltbDNMS", "smlalbtDNMS", "smlalttDNMS", }, - { shift = 5, mask = 3, - [0] = "smulbbNMS", "smultbNMS", "smulbtNMS", "smulttNMS", }, -} - -local map_misc = { - shift = 4, mask = 7, - -- NYI: decode PSR bits of msr. - [0] = { shift = 21, mask = 1, [0] = "mrsD", "msrM", }, - { shift = 21, mask = 3, "bxM", false, "clzDM", }, - { shift = 21, mask = 3, "bxjM", }, - { shift = 21, mask = 3, "blxM", }, - false, - { shift = 21, mask = 3, [0] = "qaddDMN", "qsubDMN", "qdaddDMN", "qdsubDMN", }, - false, - { shift = 21, mask = 3, "bkptK", }, -} - -local map_datar = { - shift = 4, mask = 9, - [9] = { - shift = 5, mask = 3, - [0] = { shift = 24, mask = 1, [0] = map_mul, map_sync, }, - { shift = 20, mask = 1, [0] = "strhDL", "ldrhDL", }, - { shift = 20, mask = 1, [0] = "ldrdDL", "ldrsbDL", }, - { shift = 20, mask = 1, [0] = "strdDL", "ldrshDL", }, - }, - _ = { - shift = 20, mask = 25, - [16] = { shift = 7, mask = 1, [0] = map_misc, map_mulh, }, - _ = { - shift = 0, mask = 0xffffffff, - [bor(0xe1a00000)] = "nop", - _ = map_data, - } - }, -} - -local map_datai = { - shift = 20, mask = 31, -- NYI: decode PSR bits of msr. Decode imm12. - [16] = "movwDW", [20] = "movtDW", - [18] = { shift = 0, mask = 0xf00ff, [0] = "nopv6", _ = "msrNW", }, - [22] = "msrNW", - _ = map_data, -} - -local map_branch = { - shift = 24, mask = 1, - [0] = "bB", "blB" -} - -local map_condins = { - [0] = map_datar, map_datai, map_load, map_load1, - map_loadm, map_branch, map_loadc, map_datac -} - --- NYI: setend. -local map_uncondins = { - [0] = false, map_simddata, map_simdload, map_preload, - false, "blxB", map_loadcu, map_datacu, -} - ------------------------------------------------------------------------------- - -local map_gpr = { - [0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", -} - -local map_cond = { - [0] = "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc", - "hi", "ls", "ge", "lt", "gt", "le", "al", -} - -local map_shift = { [0] = "lsl", "lsr", "asr", "ror", } - ------------------------------------------------------------------------------- - --- Output a nicely formatted line with an opcode and operands. -local function putop(ctx, text, operands) - local pos = ctx.pos - local extra = "" - if ctx.rel then - local sym = ctx.symtab[ctx.rel] - if sym then - extra = "\t->"..sym - elseif band(ctx.op, 0x0e000000) ~= 0x0a000000 then - extra = "\t; 0x"..tohex(ctx.rel) - end - end - if ctx.hexdump > 0 then - ctx.out(format("%08x %s %-5s %s%s\n", - ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra)) - else - ctx.out(format("%08x %-5s %s%s\n", - ctx.addr+pos, text, concat(operands, ", "), extra)) - end - ctx.pos = pos + 4 -end - --- Fallback for unknown opcodes. -local function unknown(ctx) - return putop(ctx, ".long", { "0x"..tohex(ctx.op) }) -end - --- Format operand 2 of load/store opcodes. -local function fmtload(ctx, op, pos) - local base = map_gpr[band(rshift(op, 16), 15)] - local x, ofs - local ext = (band(op, 0x04000000) == 0) - if not ext and band(op, 0x02000000) == 0 then - ofs = band(op, 4095) - if band(op, 0x00800000) == 0 then ofs = -ofs end - if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end - ofs = "#"..ofs - elseif ext and band(op, 0x00400000) ~= 0 then - ofs = band(op, 15) + band(rshift(op, 4), 0xf0) - if band(op, 0x00800000) == 0 then ofs = -ofs end - if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end - ofs = "#"..ofs - else - ofs = map_gpr[band(op, 15)] - if ext or band(op, 0xfe0) == 0 then - elseif band(op, 0xfe0) == 0x60 then - ofs = format("%s, rrx", ofs) - else - local sh = band(rshift(op, 7), 31) - if sh == 0 then sh = 32 end - ofs = format("%s, %s #%d", ofs, map_shift[band(rshift(op, 5), 3)], sh) - end - if band(op, 0x00800000) == 0 then ofs = "-"..ofs end - end - if ofs == "#0" then - x = format("[%s]", base) - elseif band(op, 0x01000000) == 0 then - x = format("[%s], %s", base, ofs) - else - x = format("[%s, %s]", base, ofs) - end - if band(op, 0x01200000) == 0x01200000 then x = x.."!" end - return x -end - --- Format operand 2 of vector load/store opcodes. -local function fmtvload(ctx, op, pos) - local base = map_gpr[band(rshift(op, 16), 15)] - local ofs = band(op, 255)*4 - if band(op, 0x00800000) == 0 then ofs = -ofs end - if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end - if ofs == 0 then - return format("[%s]", base) - else - return format("[%s, #%d]", base, ofs) - end -end - -local function fmtvr(op, vr, sh0, sh1) - if vr == "s" then - return format("s%d", 2*band(rshift(op, sh0), 15)+band(rshift(op, sh1), 1)) - else - return format("d%d", band(rshift(op, sh0), 15)+band(rshift(op, sh1-4), 16)) - end -end - --- Disassemble a single instruction. -local function disass_ins(ctx) - local pos = ctx.pos - local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) - local op = bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0) - local operands = {} - local suffix = "" - local last, name, pat - local vr - ctx.op = op - ctx.rel = nil - - local cond = rshift(op, 28) - local opat - if cond == 15 then - opat = map_uncondins[band(rshift(op, 25), 7)] - else - if cond ~= 14 then suffix = map_cond[cond] end - opat = map_condins[band(rshift(op, 25), 7)] - end - while type(opat) ~= "string" do - if not opat then return unknown(ctx) end - opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._ - end - name, pat = match(opat, "^([a-z0-9]*)(.*)") - if sub(pat, 1, 1) == "." then - local s2, p2 = match(pat, "^([a-z0-9.]*)(.*)") - suffix = suffix..s2 - pat = p2 - end - - for p in gmatch(pat, ".") do - local x = nil - if p == "D" then - x = map_gpr[band(rshift(op, 12), 15)] - elseif p == "N" then - x = map_gpr[band(rshift(op, 16), 15)] - elseif p == "S" then - x = map_gpr[band(rshift(op, 8), 15)] - elseif p == "M" then - x = map_gpr[band(op, 15)] - elseif p == "d" then - x = fmtvr(op, vr, 12, 22) - elseif p == "n" then - x = fmtvr(op, vr, 16, 7) - elseif p == "m" then - x = fmtvr(op, vr, 0, 5) - elseif p == "P" then - if band(op, 0x02000000) ~= 0 then - x = ror(band(op, 255), 2*band(rshift(op, 8), 15)) - else - x = map_gpr[band(op, 15)] - if band(op, 0xff0) ~= 0 then - operands[#operands+1] = x - local s = map_shift[band(rshift(op, 5), 3)] - local r = nil - if band(op, 0xf90) == 0 then - if s == "ror" then s = "rrx" else r = "#32" end - elseif band(op, 0x10) == 0 then - r = "#"..band(rshift(op, 7), 31) - else - r = map_gpr[band(rshift(op, 8), 15)] - end - if name == "mov" then name = s; x = r - elseif r then x = format("%s %s", s, r) - else x = s end - end - end - elseif p == "L" then - x = fmtload(ctx, op, pos) - elseif p == "l" then - x = fmtvload(ctx, op, pos) - elseif p == "B" then - local addr = ctx.addr + pos + 8 + arshift(lshift(op, 8), 6) - if cond == 15 then addr = addr + band(rshift(op, 23), 2) end - ctx.rel = addr - x = "0x"..tohex(addr) - elseif p == "F" then - vr = "s" - elseif p == "G" then - vr = "d" - elseif p == "." then - suffix = suffix..(vr == "s" and ".f32" or ".f64") - elseif p == "R" then - if band(op, 0x00200000) ~= 0 and #operands == 1 then - operands[1] = operands[1].."!" - end - local t = {} - for i=0,15 do - if band(rshift(op, i), 1) == 1 then t[#t+1] = map_gpr[i] end - end - x = "{"..concat(t, ", ").."}" - elseif p == "r" then - if band(op, 0x00200000) ~= 0 and #operands == 2 then - operands[1] = operands[1].."!" - end - local s = tonumber(sub(last, 2)) - local n = band(op, 255) - if vr == "d" then n = rshift(n, 1) end - operands[#operands] = format("{%s-%s%d}", last, vr, s+n-1) - elseif p == "W" then - x = band(op, 0x0fff) + band(rshift(op, 4), 0xf000) - elseif p == "T" then - x = "#0x"..tohex(band(op, 0x00ffffff), 6) - elseif p == "U" then - x = band(rshift(op, 7), 31) - if x == 0 then x = nil end - elseif p == "u" then - x = band(rshift(op, 7), 31) - if band(op, 0x40) == 0 then - if x == 0 then x = nil else x = "lsl #"..x end - else - if x == 0 then x = "asr #32" else x = "asr #"..x end - end - elseif p == "v" then - x = band(rshift(op, 7), 31) - elseif p == "w" then - x = band(rshift(op, 16), 31) - elseif p == "x" then - x = band(rshift(op, 16), 31) + 1 - elseif p == "X" then - x = band(rshift(op, 16), 31) - last + 1 - elseif p == "Y" then - x = band(rshift(op, 12), 0xf0) + band(op, 0x0f) - elseif p == "K" then - x = "#0x"..tohex(band(rshift(op, 4), 0x0000fff0) + band(op, 15), 4) - elseif p == "s" then - if band(op, 0x00100000) ~= 0 then suffix = "s"..suffix end - else - assert(false) - end - if x then - last = x - if type(x) == "number" then x = "#"..x end - operands[#operands+1] = x - end - end - - return putop(ctx, name..suffix, operands) -end - ------------------------------------------------------------------------------- - --- Disassemble a block of code. -local function disass_block(ctx, ofs, len) - if not ofs then ofs = 0 end - local stop = len and ofs+len or #ctx.code - ctx.pos = ofs - ctx.rel = nil - while ctx.pos < stop do disass_ins(ctx) end -end - --- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). -local function create(code, addr, out) - local ctx = {} - ctx.code = code - ctx.addr = addr or 0 - ctx.out = out or io.write - ctx.symtab = {} - ctx.disass = disass_block - ctx.hexdump = 8 - return ctx -end - --- Simple API: disassemble code (a string) at address and output via out. -local function disass(code, addr, out) - create(code, addr, out):disass() -end - --- Return register name for RID. -local function regname(r) - if r < 16 then return map_gpr[r] end - return "d"..(r-16) -end - --- Public module functions. -return { - create = create, - disass = disass, - regname = regname -} - diff --git a/lib/LuaJIT/src/jit/dis_arm64.lua b/lib/LuaJIT/src/jit/dis_arm64.lua deleted file mode 100644 index a717332..0000000 --- a/lib/LuaJIT/src/jit/dis_arm64.lua +++ /dev/null @@ -1,1216 +0,0 @@ ----------------------------------------------------------------------------- --- LuaJIT ARM64 disassembler module. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- Released under the MIT license. See Copyright Notice in luajit.h --- --- Contributed by Djordje Kovacevic and Stefan Pejic from RT-RK.com. --- Sponsored by Cisco Systems, Inc. ----------------------------------------------------------------------------- --- This is a helper module used by the LuaJIT machine code dumper module. --- --- It disassembles most user-mode AArch64 instructions. --- NYI: Advanced SIMD and VFP instructions. ------------------------------------------------------------------------------- - -local type = type -local sub, byte, format = string.sub, string.byte, string.format -local match, gmatch, gsub = string.match, string.gmatch, string.gsub -local concat = table.concat -local bit = require("bit") -local band, bor, bxor, tohex = bit.band, bit.bor, bit.bxor, bit.tohex -local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift -local ror = bit.ror - ------------------------------------------------------------------------------- --- Opcode maps ------------------------------------------------------------------------------- - -local map_adr = { -- PC-relative addressing. - shift = 31, mask = 1, - [0] = "adrDBx", "adrpDBx" -} - -local map_addsubi = { -- Add/subtract immediate. - shift = 29, mask = 3, - [0] = "add|movDNIg", "adds|cmnD0NIg", "subDNIg", "subs|cmpD0NIg", -} - -local map_logi = { -- Logical immediate. - shift = 31, mask = 1, - [0] = { - shift = 22, mask = 1, - [0] = { - shift = 29, mask = 3, - [0] = "andDNig", "orr|movDN0ig", "eorDNig", "ands|tstD0Nig" - }, - false -- unallocated - }, - { - shift = 29, mask = 3, - [0] = "andDNig", "orr|movDN0ig", "eorDNig", "ands|tstD0Nig" - } -} - -local map_movwi = { -- Move wide immediate. - shift = 31, mask = 1, - [0] = { - shift = 22, mask = 1, - [0] = { - shift = 29, mask = 3, - [0] = "movnDWRg", false, "movz|movDYRg", "movkDWRg" - }, false -- unallocated - }, - { - shift = 29, mask = 3, - [0] = "movnDWRg", false, "movz|movDYRg", "movkDWRg" - }, -} - -local map_bitf = { -- Bitfield. - shift = 31, mask = 1, - [0] = { - shift = 22, mask = 1, - [0] = { - shift = 29, mask = 3, - [0] = "sbfm|sbfiz|sbfx|asr|sxtw|sxth|sxtbDN12w", - "bfm|bfi|bfxilDN13w", - "ubfm|ubfiz|ubfx|lsr|lsl|uxth|uxtbDN12w" - } - }, - { - shift = 22, mask = 1, - { - shift = 29, mask = 3, - [0] = "sbfm|sbfiz|sbfx|asr|sxtw|sxth|sxtbDN12x", - "bfm|bfi|bfxilDN13x", - "ubfm|ubfiz|ubfx|lsr|lsl|uxth|uxtbDN12x" - } - } -} - -local map_datai = { -- Data processing - immediate. - shift = 23, mask = 7, - [0] = map_adr, map_adr, map_addsubi, false, - map_logi, map_movwi, map_bitf, - { - shift = 15, mask = 0x1c0c1, - [0] = "extr|rorDNM4w", [0x10080] = "extr|rorDNM4x", - [0x10081] = "extr|rorDNM4x" - } -} - -local map_logsr = { -- Logical, shifted register. - shift = 31, mask = 1, - [0] = { - shift = 15, mask = 1, - [0] = { - shift = 29, mask = 3, - [0] = { - shift = 21, mask = 7, - [0] = "andDNMSg", "bicDNMSg", "andDNMSg", "bicDNMSg", - "andDNMSg", "bicDNMSg", "andDNMg", "bicDNMg" - }, - { - shift = 21, mask = 7, - [0] ="orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0MSg", "orn|mvnDN0MSg", - "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0Mg", "orn|mvnDN0Mg" - }, - { - shift = 21, mask = 7, - [0] = "eorDNMSg", "eonDNMSg", "eorDNMSg", "eonDNMSg", - "eorDNMSg", "eonDNMSg", "eorDNMg", "eonDNMg" - }, - { - shift = 21, mask = 7, - [0] = "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMSg", "bicsDNMSg", - "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMg", "bicsDNMg" - } - }, - false -- unallocated - }, - { - shift = 29, mask = 3, - [0] = { - shift = 21, mask = 7, - [0] = "andDNMSg", "bicDNMSg", "andDNMSg", "bicDNMSg", - "andDNMSg", "bicDNMSg", "andDNMg", "bicDNMg" - }, - { - shift = 21, mask = 7, - [0] = "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0MSg", "orn|mvnDN0MSg", - "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0Mg", "orn|mvnDN0Mg" - }, - { - shift = 21, mask = 7, - [0] = "eorDNMSg", "eonDNMSg", "eorDNMSg", "eonDNMSg", - "eorDNMSg", "eonDNMSg", "eorDNMg", "eonDNMg" - }, - { - shift = 21, mask = 7, - [0] = "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMSg", "bicsDNMSg", - "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMg", "bicsDNMg" - } - } -} - -local map_assh = { - shift = 31, mask = 1, - [0] = { - shift = 15, mask = 1, - [0] = { - shift = 29, mask = 3, - [0] = { - shift = 22, mask = 3, - [0] = "addDNMSg", "addDNMSg", "addDNMSg", "addDNMg" - }, - { - shift = 22, mask = 3, - [0] = "adds|cmnD0NMSg", "adds|cmnD0NMSg", - "adds|cmnD0NMSg", "adds|cmnD0NMg" - }, - { - shift = 22, mask = 3, - [0] = "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0Mg" - }, - { - shift = 22, mask = 3, - [0] = "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0MzSg", - "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0Mzg" - }, - }, - false -- unallocated - }, - { - shift = 29, mask = 3, - [0] = { - shift = 22, mask = 3, - [0] = "addDNMSg", "addDNMSg", "addDNMSg", "addDNMg" - }, - { - shift = 22, mask = 3, - [0] = "adds|cmnD0NMSg", "adds|cmnD0NMSg", "adds|cmnD0NMSg", - "adds|cmnD0NMg" - }, - { - shift = 22, mask = 3, - [0] = "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0Mg" - }, - { - shift = 22, mask = 3, - [0] = "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0MzSg", - "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0Mzg" - } - } -} - -local map_addsubsh = { -- Add/subtract, shifted register. - shift = 22, mask = 3, - [0] = map_assh, map_assh, map_assh -} - -local map_addsubex = { -- Add/subtract, extended register. - shift = 22, mask = 3, - [0] = { - shift = 29, mask = 3, - [0] = "addDNMXg", "adds|cmnD0NMXg", "subDNMXg", "subs|cmpD0NMzXg", - } -} - -local map_addsubc = { -- Add/subtract, with carry. - shift = 10, mask = 63, - [0] = { - shift = 29, mask = 3, - [0] = "adcDNMg", "adcsDNMg", "sbc|ngcDN0Mg", "sbcs|ngcsDN0Mg", - } -} - -local map_ccomp = { - shift = 4, mask = 1, - [0] = { - shift = 10, mask = 3, - [0] = { -- Conditional compare register. - shift = 29, mask = 3, - "ccmnNMVCg", false, "ccmpNMVCg", - }, - [2] = { -- Conditional compare immediate. - shift = 29, mask = 3, - "ccmnN5VCg", false, "ccmpN5VCg", - } - } -} - -local map_csel = { -- Conditional select. - shift = 11, mask = 1, - [0] = { - shift = 10, mask = 1, - [0] = { - shift = 29, mask = 3, - [0] = "cselDNMzCg", false, "csinv|cinv|csetmDNMcg", false, - }, - { - shift = 29, mask = 3, - [0] = "csinc|cinc|csetDNMcg", false, "csneg|cnegDNMcg", false, - } - } -} - -local map_data1s = { -- Data processing, 1 source. - shift = 29, mask = 1, - [0] = { - shift = 31, mask = 1, - [0] = { - shift = 10, mask = 0x7ff, - [0] = "rbitDNg", "rev16DNg", "revDNw", false, "clzDNg", "clsDNg" - }, - { - shift = 10, mask = 0x7ff, - [0] = "rbitDNg", "rev16DNg", "rev32DNx", "revDNx", "clzDNg", "clsDNg" - } - } -} - -local map_data2s = { -- Data processing, 2 sources. - shift = 29, mask = 1, - [0] = { - shift = 10, mask = 63, - false, "udivDNMg", "sdivDNMg", false, false, false, false, "lslDNMg", - "lsrDNMg", "asrDNMg", "rorDNMg" - } -} - -local map_data3s = { -- Data processing, 3 sources. - shift = 29, mask = 7, - [0] = { - shift = 21, mask = 7, - [0] = { - shift = 15, mask = 1, - [0] = "madd|mulDNMA0g", "msub|mnegDNMA0g" - } - }, false, false, false, - { - shift = 15, mask = 1, - [0] = { - shift = 21, mask = 7, - [0] = "madd|mulDNMA0g", "smaddl|smullDxNMwA0x", "smulhDNMx", false, - false, "umaddl|umullDxNMwA0x", "umulhDNMx" - }, - { - shift = 21, mask = 7, - [0] = "msub|mnegDNMA0g", "smsubl|smneglDxNMwA0x", false, false, - false, "umsubl|umneglDxNMwA0x" - } - } -} - -local map_datar = { -- Data processing, register. - shift = 28, mask = 1, - [0] = { - shift = 24, mask = 1, - [0] = map_logsr, - { - shift = 21, mask = 1, - [0] = map_addsubsh, map_addsubex - } - }, - { - shift = 21, mask = 15, - [0] = map_addsubc, false, map_ccomp, false, map_csel, false, - { - shift = 30, mask = 1, - [0] = map_data2s, map_data1s - }, - false, map_data3s, map_data3s, map_data3s, map_data3s, map_data3s, - map_data3s, map_data3s, map_data3s - } -} - -local map_lrl = { -- Load register, literal. - shift = 26, mask = 1, - [0] = { - shift = 30, mask = 3, - [0] = "ldrDwB", "ldrDxB", "ldrswDxB" - }, - { - shift = 30, mask = 3, - [0] = "ldrDsB", "ldrDdB" - } -} - -local map_lsriind = { -- Load/store register, immediate pre/post-indexed. - shift = 30, mask = 3, - [0] = { - shift = 26, mask = 1, - [0] = { - shift = 22, mask = 3, - [0] = "strbDwzL", "ldrbDwzL", "ldrsbDxzL", "ldrsbDwzL" - } - }, - { - shift = 26, mask = 1, - [0] = { - shift = 22, mask = 3, - [0] = "strhDwzL", "ldrhDwzL", "ldrshDxzL", "ldrshDwzL" - } - }, - { - shift = 26, mask = 1, - [0] = { - shift = 22, mask = 3, - [0] = "strDwzL", "ldrDwzL", "ldrswDxzL" - }, - { - shift = 22, mask = 3, - [0] = "strDszL", "ldrDszL" - } - }, - { - shift = 26, mask = 1, - [0] = { - shift = 22, mask = 3, - [0] = "strDxzL", "ldrDxzL" - }, - { - shift = 22, mask = 3, - [0] = "strDdzL", "ldrDdzL" - } - } -} - -local map_lsriro = { - shift = 21, mask = 1, - [0] = { -- Load/store register immediate. - shift = 10, mask = 3, - [0] = { -- Unscaled immediate. - shift = 26, mask = 1, - [0] = { - shift = 30, mask = 3, - [0] = { - shift = 22, mask = 3, - [0] = "sturbDwK", "ldurbDwK" - }, - { - shift = 22, mask = 3, - [0] = "sturhDwK", "ldurhDwK" - }, - { - shift = 22, mask = 3, - [0] = "sturDwK", "ldurDwK" - }, - { - shift = 22, mask = 3, - [0] = "sturDxK", "ldurDxK" - } - } - }, map_lsriind, false, map_lsriind - }, - { -- Load/store register, register offset. - shift = 10, mask = 3, - [2] = { - shift = 26, mask = 1, - [0] = { - shift = 30, mask = 3, - [0] = { - shift = 22, mask = 3, - [0] = "strbDwO", "ldrbDwO", "ldrsbDxO", "ldrsbDwO" - }, - { - shift = 22, mask = 3, - [0] = "strhDwO", "ldrhDwO", "ldrshDxO", "ldrshDwO" - }, - { - shift = 22, mask = 3, - [0] = "strDwO", "ldrDwO", "ldrswDxO" - }, - { - shift = 22, mask = 3, - [0] = "strDxO", "ldrDxO" - } - }, - { - shift = 30, mask = 3, - [2] = { - shift = 22, mask = 3, - [0] = "strDsO", "ldrDsO" - }, - [3] = { - shift = 22, mask = 3, - [0] = "strDdO", "ldrDdO" - } - } - } - } -} - -local map_lsp = { -- Load/store register pair, offset. - shift = 22, mask = 1, - [0] = { - shift = 30, mask = 3, - [0] = { - shift = 26, mask = 1, - [0] = "stpDzAzwP", "stpDzAzsP", - }, - { - shift = 26, mask = 1, - "stpDzAzdP" - }, - { - shift = 26, mask = 1, - [0] = "stpDzAzxP" - } - }, - { - shift = 30, mask = 3, - [0] = { - shift = 26, mask = 1, - [0] = "ldpDzAzwP", "ldpDzAzsP", - }, - { - shift = 26, mask = 1, - [0] = "ldpswDAxP", "ldpDzAzdP" - }, - { - shift = 26, mask = 1, - [0] = "ldpDzAzxP" - } - } -} - -local map_ls = { -- Loads and stores. - shift = 24, mask = 0x31, - [0x10] = map_lrl, [0x30] = map_lsriro, - [0x20] = { - shift = 23, mask = 3, - map_lsp, map_lsp, map_lsp - }, - [0x21] = { - shift = 23, mask = 3, - map_lsp, map_lsp, map_lsp - }, - [0x31] = { - shift = 26, mask = 1, - [0] = { - shift = 30, mask = 3, - [0] = { - shift = 22, mask = 3, - [0] = "strbDwzU", "ldrbDwzU" - }, - { - shift = 22, mask = 3, - [0] = "strhDwzU", "ldrhDwzU" - }, - { - shift = 22, mask = 3, - [0] = "strDwzU", "ldrDwzU" - }, - { - shift = 22, mask = 3, - [0] = "strDxzU", "ldrDxzU" - } - }, - { - shift = 30, mask = 3, - [2] = { - shift = 22, mask = 3, - [0] = "strDszU", "ldrDszU" - }, - [3] = { - shift = 22, mask = 3, - [0] = "strDdzU", "ldrDdzU" - } - } - }, -} - -local map_datafp = { -- Data processing, SIMD and FP. - shift = 28, mask = 7, - { -- 001 - shift = 24, mask = 1, - [0] = { - shift = 21, mask = 1, - { - shift = 10, mask = 3, - [0] = { - shift = 12, mask = 1, - [0] = { - shift = 13, mask = 1, - [0] = { - shift = 14, mask = 1, - [0] = { - shift = 15, mask = 1, - [0] = { -- FP/int conversion. - shift = 31, mask = 1, - [0] = { - shift = 16, mask = 0xff, - [0x20] = "fcvtnsDwNs", [0x21] = "fcvtnuDwNs", - [0x22] = "scvtfDsNw", [0x23] = "ucvtfDsNw", - [0x24] = "fcvtasDwNs", [0x25] = "fcvtauDwNs", - [0x26] = "fmovDwNs", [0x27] = "fmovDsNw", - [0x28] = "fcvtpsDwNs", [0x29] = "fcvtpuDwNs", - [0x30] = "fcvtmsDwNs", [0x31] = "fcvtmuDwNs", - [0x38] = "fcvtzsDwNs", [0x39] = "fcvtzuDwNs", - [0x60] = "fcvtnsDwNd", [0x61] = "fcvtnuDwNd", - [0x62] = "scvtfDdNw", [0x63] = "ucvtfDdNw", - [0x64] = "fcvtasDwNd", [0x65] = "fcvtauDwNd", - [0x68] = "fcvtpsDwNd", [0x69] = "fcvtpuDwNd", - [0x70] = "fcvtmsDwNd", [0x71] = "fcvtmuDwNd", - [0x78] = "fcvtzsDwNd", [0x79] = "fcvtzuDwNd" - }, - { - shift = 16, mask = 0xff, - [0x20] = "fcvtnsDxNs", [0x21] = "fcvtnuDxNs", - [0x22] = "scvtfDsNx", [0x23] = "ucvtfDsNx", - [0x24] = "fcvtasDxNs", [0x25] = "fcvtauDxNs", - [0x28] = "fcvtpsDxNs", [0x29] = "fcvtpuDxNs", - [0x30] = "fcvtmsDxNs", [0x31] = "fcvtmuDxNs", - [0x38] = "fcvtzsDxNs", [0x39] = "fcvtzuDxNs", - [0x60] = "fcvtnsDxNd", [0x61] = "fcvtnuDxNd", - [0x62] = "scvtfDdNx", [0x63] = "ucvtfDdNx", - [0x64] = "fcvtasDxNd", [0x65] = "fcvtauDxNd", - [0x66] = "fmovDxNd", [0x67] = "fmovDdNx", - [0x68] = "fcvtpsDxNd", [0x69] = "fcvtpuDxNd", - [0x70] = "fcvtmsDxNd", [0x71] = "fcvtmuDxNd", - [0x78] = "fcvtzsDxNd", [0x79] = "fcvtzuDxNd" - } - } - }, - { -- FP data-processing, 1 source. - shift = 31, mask = 1, - [0] = { - shift = 22, mask = 3, - [0] = { - shift = 15, mask = 63, - [0] = "fmovDNf", "fabsDNf", "fnegDNf", - "fsqrtDNf", false, "fcvtDdNs", false, false, - "frintnDNf", "frintpDNf", "frintmDNf", "frintzDNf", - "frintaDNf", false, "frintxDNf", "frintiDNf", - }, - { - shift = 15, mask = 63, - [0] = "fmovDNf", "fabsDNf", "fnegDNf", - "fsqrtDNf", "fcvtDsNd", false, false, false, - "frintnDNf", "frintpDNf", "frintmDNf", "frintzDNf", - "frintaDNf", false, "frintxDNf", "frintiDNf", - } - } - } - }, - { -- FP compare. - shift = 31, mask = 1, - [0] = { - shift = 14, mask = 3, - [0] = { - shift = 23, mask = 1, - [0] = { - shift = 0, mask = 31, - [0] = "fcmpNMf", [8] = "fcmpNZf", - [16] = "fcmpeNMf", [24] = "fcmpeNZf", - } - } - } - } - }, - { -- FP immediate. - shift = 31, mask = 1, - [0] = { - shift = 5, mask = 31, - [0] = { - shift = 23, mask = 1, - [0] = "fmovDFf" - } - } - } - }, - { -- FP conditional compare. - shift = 31, mask = 1, - [0] = { - shift = 23, mask = 1, - [0] = { - shift = 4, mask = 1, - [0] = "fccmpNMVCf", "fccmpeNMVCf" - } - } - }, - { -- FP data-processing, 2 sources. - shift = 31, mask = 1, - [0] = { - shift = 23, mask = 1, - [0] = { - shift = 12, mask = 15, - [0] = "fmulDNMf", "fdivDNMf", "faddDNMf", "fsubDNMf", - "fmaxDNMf", "fminDNMf", "fmaxnmDNMf", "fminnmDNMf", - "fnmulDNMf" - } - } - }, - { -- FP conditional select. - shift = 31, mask = 1, - [0] = { - shift = 23, mask = 1, - [0] = "fcselDNMCf" - } - } - } - }, - { -- FP data-processing, 3 sources. - shift = 31, mask = 1, - [0] = { - shift = 15, mask = 1, - [0] = { - shift = 21, mask = 5, - [0] = "fmaddDNMAf", "fnmaddDNMAf" - }, - { - shift = 21, mask = 5, - [0] = "fmsubDNMAf", "fnmsubDNMAf" - } - } - } - } -} - -local map_br = { -- Branches, exception generating and system instructions. - shift = 29, mask = 7, - [0] = "bB", - { -- Compare & branch, immediate. - shift = 24, mask = 3, - [0] = "cbzDBg", "cbnzDBg", "tbzDTBw", "tbnzDTBw" - }, - { -- Conditional branch, immediate. - shift = 24, mask = 3, - [0] = { - shift = 4, mask = 1, - [0] = { - shift = 0, mask = 15, - [0] = "beqB", "bneB", "bhsB", "bloB", "bmiB", "bplB", "bvsB", "bvcB", - "bhiB", "blsB", "bgeB", "bltB", "bgtB", "bleB", "balB" - } - } - }, false, "blB", - { -- Compare & branch, immediate. - shift = 24, mask = 3, - [0] = "cbzDBg", "cbnzDBg", "tbzDTBx", "tbnzDTBx" - }, - { - shift = 24, mask = 3, - [0] = { -- Exception generation. - shift = 0, mask = 0xe0001f, - [0x200000] = "brkW" - }, - { -- System instructions. - shift = 0, mask = 0x3fffff, - [0x03201f] = "nop" - }, - { -- Unconditional branch, register. - shift = 0, mask = 0xfffc1f, - [0x1f0000] = "brNx", [0x3f0000] = "blrNx", - [0x5f0000] = "retNx" - }, - } -} - -local map_init = { - shift = 25, mask = 15, - [0] = false, false, false, false, map_ls, map_datar, map_ls, map_datafp, - map_datai, map_datai, map_br, map_br, map_ls, map_datar, map_ls, map_datafp -} - ------------------------------------------------------------------------------- - -local map_regs = { x = {}, w = {}, d = {}, s = {} } - -for i=0,30 do - map_regs.x[i] = "x"..i - map_regs.w[i] = "w"..i - map_regs.d[i] = "d"..i - map_regs.s[i] = "s"..i -end -map_regs.x[31] = "sp" -map_regs.w[31] = "wsp" -map_regs.d[31] = "d31" -map_regs.s[31] = "s31" - -local map_cond = { - [0] = "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", - "hi", "ls", "ge", "lt", "gt", "le", "al", -} - -local map_shift = { [0] = "lsl", "lsr", "asr", } - -local map_extend = { - [0] = "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx", -} - ------------------------------------------------------------------------------- - --- Output a nicely formatted line with an opcode and operands. -local function putop(ctx, text, operands) - local pos = ctx.pos - local extra = "" - if ctx.rel then - local sym = ctx.symtab[ctx.rel] - if sym then - extra = "\t->"..sym - end - end - if ctx.hexdump > 0 then - ctx.out(format("%08x %s %-5s %s%s\n", - ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra)) - else - ctx.out(format("%08x %-5s %s%s\n", - ctx.addr+pos, text, concat(operands, ", "), extra)) - end - ctx.pos = pos + 4 -end - --- Fallback for unknown opcodes. -local function unknown(ctx) - return putop(ctx, ".long", { "0x"..tohex(ctx.op) }) -end - -local function match_reg(p, pat, regnum) - return map_regs[match(pat, p.."%w-([xwds])")][regnum] -end - -local function fmt_hex32(x) - if x < 0 then - return tohex(x) - else - return format("%x", x) - end -end - -local imm13_rep = { 0x55555555, 0x11111111, 0x01010101, 0x00010001, 0x00000001 } - -local function decode_imm13(op) - local imms = band(rshift(op, 10), 63) - local immr = band(rshift(op, 16), 63) - if band(op, 0x00400000) == 0 then - local len = 5 - if imms >= 56 then - if imms >= 60 then len = 1 else len = 2 end - elseif imms >= 48 then len = 3 elseif imms >= 32 then len = 4 end - local l = lshift(1, len)-1 - local s = band(imms, l) - local r = band(immr, l) - local imm = ror(rshift(-1, 31-s), r) - if len ~= 5 then imm = band(imm, lshift(1, l)-1) + rshift(imm, 31-l) end - imm = imm * imm13_rep[len] - local ix = fmt_hex32(imm) - if rshift(op, 31) ~= 0 then - return ix..tohex(imm) - else - return ix - end - else - local lo, hi = -1, 0 - if imms < 32 then lo = rshift(-1, 31-imms) else hi = rshift(-1, 63-imms) end - if immr ~= 0 then - lo, hi = ror(lo, immr), ror(hi, immr) - local x = immr == 32 and 0 or band(bxor(lo, hi), lshift(-1, 32-immr)) - lo, hi = bxor(lo, x), bxor(hi, x) - if immr >= 32 then lo, hi = hi, lo end - end - if hi ~= 0 then - return fmt_hex32(hi)..tohex(lo) - else - return fmt_hex32(lo) - end - end -end - -local function parse_immpc(op, name) - if name == "b" or name == "bl" then - return arshift(lshift(op, 6), 4) - elseif name == "adr" or name == "adrp" then - local immlo = band(rshift(op, 29), 3) - local immhi = lshift(arshift(lshift(op, 8), 13), 2) - return bor(immhi, immlo) - elseif name == "tbz" or name == "tbnz" then - return lshift(arshift(lshift(op, 13), 18), 2) - else - return lshift(arshift(lshift(op, 8), 13), 2) - end -end - -local function parse_fpimm8(op) - local sign = band(op, 0x100000) == 0 and 1 or -1 - local exp = bxor(rshift(arshift(lshift(op, 12), 5), 24), 0x80) - 131 - local frac = 16+band(rshift(op, 13), 15) - return sign * frac * 2^exp -end - -local function prefer_bfx(sf, uns, imms, immr) - if imms < immr or imms == 31 or imms == 63 then - return false - end - if immr == 0 then - if sf == 0 and (imms == 7 or imms == 15) then - return false - end - if sf ~= 0 and uns == 0 and (imms == 7 or imms == 15 or imms == 31) then - return false - end - end - return true -end - --- Disassemble a single instruction. -local function disass_ins(ctx) - local pos = ctx.pos - local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) - local op = bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0) - local operands = {} - local suffix = "" - local last, name, pat - local map_reg - ctx.op = op - ctx.rel = nil - last = nil - local opat - opat = map_init[band(rshift(op, 25), 15)] - while type(opat) ~= "string" do - if not opat then return unknown(ctx) end - opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._ - end - name, pat = match(opat, "^([a-z0-9]*)(.*)") - local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)") - if altname then pat = pat2 end - if sub(pat, 1, 1) == "." then - local s2, p2 = match(pat, "^([a-z0-9.]*)(.*)") - suffix = suffix..s2 - pat = p2 - end - - local rt = match(pat, "[gf]") - if rt then - if rt == "g" then - map_reg = band(op, 0x80000000) ~= 0 and map_regs.x or map_regs.w - else - map_reg = band(op, 0x400000) ~= 0 and map_regs.d or map_regs.s - end - end - - local second0, immr - - for p in gmatch(pat, ".") do - local x = nil - if p == "D" then - local regnum = band(op, 31) - x = rt and map_reg[regnum] or match_reg(p, pat, regnum) - elseif p == "N" then - local regnum = band(rshift(op, 5), 31) - x = rt and map_reg[regnum] or match_reg(p, pat, regnum) - elseif p == "M" then - local regnum = band(rshift(op, 16), 31) - x = rt and map_reg[regnum] or match_reg(p, pat, regnum) - elseif p == "A" then - local regnum = band(rshift(op, 10), 31) - x = rt and map_reg[regnum] or match_reg(p, pat, regnum) - elseif p == "B" then - local addr = ctx.addr + pos + parse_immpc(op, name) - ctx.rel = addr - x = "0x"..tohex(addr) - elseif p == "T" then - x = bor(band(rshift(op, 26), 32), band(rshift(op, 19), 31)) - elseif p == "V" then - x = band(op, 15) - elseif p == "C" then - x = map_cond[band(rshift(op, 12), 15)] - elseif p == "c" then - local rn = band(rshift(op, 5), 31) - local rm = band(rshift(op, 16), 31) - local cond = band(rshift(op, 12), 15) - local invc = bxor(cond, 1) - x = map_cond[cond] - if altname and cond ~= 14 and cond ~= 15 then - local a1, a2 = match(altname, "([^|]*)|(.*)") - if rn == rm then - local n = #operands - operands[n] = nil - x = map_cond[invc] - if rn ~= 31 then - if a1 then name = a1 else name = altname end - else - operands[n-1] = nil - name = a2 - end - end - end - elseif p == "W" then - x = band(rshift(op, 5), 0xffff) - elseif p == "Y" then - x = band(rshift(op, 5), 0xffff) - local hw = band(rshift(op, 21), 3) - if altname and (hw == 0 or x ~= 0) then - name = altname - end - elseif p == "L" then - local rn = map_regs.x[band(rshift(op, 5), 31)] - local imm9 = arshift(lshift(op, 11), 23) - if band(op, 0x800) ~= 0 then - x = "["..rn..", #"..imm9.."]!" - else - x = "["..rn.."], #"..imm9 - end - elseif p == "U" then - local rn = map_regs.x[band(rshift(op, 5), 31)] - local sz = band(rshift(op, 30), 3) - local imm12 = lshift(arshift(lshift(op, 10), 20), sz) - if imm12 ~= 0 then - x = "["..rn..", #"..imm12.."]" - else - x = "["..rn.."]" - end - elseif p == "K" then - local rn = map_regs.x[band(rshift(op, 5), 31)] - local imm9 = arshift(lshift(op, 11), 23) - if imm9 ~= 0 then - x = "["..rn..", #"..imm9.."]" - else - x = "["..rn.."]" - end - elseif p == "O" then - local rn, rm = map_regs.x[band(rshift(op, 5), 31)] - local m = band(rshift(op, 13), 1) - if m == 0 then - rm = map_regs.w[band(rshift(op, 16), 31)] - else - rm = map_regs.x[band(rshift(op, 16), 31)] - end - x = "["..rn..", "..rm - local opt = band(rshift(op, 13), 7) - local s = band(rshift(op, 12), 1) - local sz = band(rshift(op, 30), 3) - -- extension to be applied - if opt == 3 then - if s == 0 then x = x.."]" - else x = x..", lsl #"..sz.."]" end - elseif opt == 2 or opt == 6 or opt == 7 then - if s == 0 then x = x..", "..map_extend[opt].."]" - else x = x..", "..map_extend[opt].." #"..sz.."]" end - else - x = x.."]" - end - elseif p == "P" then - local opcv, sh = rshift(op, 26), 2 - if opcv >= 0x2a then sh = 4 elseif opcv >= 0x1b then sh = 3 end - local imm7 = lshift(arshift(lshift(op, 10), 25), sh) - local rn = map_regs.x[band(rshift(op, 5), 31)] - local ind = band(rshift(op, 23), 3) - if ind == 1 then - x = "["..rn.."], #"..imm7 - elseif ind == 2 then - if imm7 == 0 then - x = "["..rn.."]" - else - x = "["..rn..", #"..imm7.."]" - end - elseif ind == 3 then - x = "["..rn..", #"..imm7.."]!" - end - elseif p == "I" then - local shf = band(rshift(op, 22), 3) - local imm12 = band(rshift(op, 10), 0x0fff) - local rn, rd = band(rshift(op, 5), 31), band(op, 31) - if altname == "mov" and shf == 0 and imm12 == 0 and (rn == 31 or rd == 31) then - name = altname - x = nil - elseif shf == 0 then - x = imm12 - elseif shf == 1 then - x = imm12..", lsl #12" - end - elseif p == "i" then - x = "#0x"..decode_imm13(op) - elseif p == "1" then - immr = band(rshift(op, 16), 63) - x = immr - elseif p == "2" then - x = band(rshift(op, 10), 63) - if altname then - local a1, a2, a3, a4, a5, a6 = - match(altname, "([^|]*)|([^|]*)|([^|]*)|([^|]*)|([^|]*)|(.*)") - local sf = band(rshift(op, 26), 32) - local uns = band(rshift(op, 30), 1) - if prefer_bfx(sf, uns, x, immr) then - name = a2 - x = x - immr + 1 - elseif immr == 0 and x == 7 then - local n = #operands - operands[n] = nil - if sf ~= 0 then - operands[n-1] = gsub(operands[n-1], "x", "w") - end - last = operands[n-1] - name = a6 - x = nil - elseif immr == 0 and x == 15 then - local n = #operands - operands[n] = nil - if sf ~= 0 then - operands[n-1] = gsub(operands[n-1], "x", "w") - end - last = operands[n-1] - name = a5 - x = nil - elseif x == 31 or x == 63 then - if x == 31 and immr == 0 and name == "sbfm" then - name = a4 - local n = #operands - operands[n] = nil - if sf ~= 0 then - operands[n-1] = gsub(operands[n-1], "x", "w") - end - last = operands[n-1] - else - name = a3 - end - x = nil - elseif band(x, 31) ~= 31 and immr == x+1 and name == "ubfm" then - name = a4 - last = "#"..(sf+32 - immr) - operands[#operands] = last - x = nil - elseif x < immr then - name = a1 - last = "#"..(sf+32 - immr) - operands[#operands] = last - x = x + 1 - end - end - elseif p == "3" then - x = band(rshift(op, 10), 63) - if altname then - local a1, a2 = match(altname, "([^|]*)|(.*)") - if x < immr then - name = a1 - local sf = band(rshift(op, 26), 32) - last = "#"..(sf+32 - immr) - operands[#operands] = last - x = x + 1 - elseif x >= immr then - name = a2 - x = x - immr + 1 - end - end - elseif p == "4" then - x = band(rshift(op, 10), 63) - local rn = band(rshift(op, 5), 31) - local rm = band(rshift(op, 16), 31) - if altname and rn == rm then - local n = #operands - operands[n] = nil - last = operands[n-1] - name = altname - end - elseif p == "5" then - x = band(rshift(op, 16), 31) - elseif p == "S" then - x = band(rshift(op, 10), 63) - if x == 0 then x = nil - else x = map_shift[band(rshift(op, 22), 3)].." #"..x end - elseif p == "X" then - local opt = band(rshift(op, 13), 7) - -- Width specifier . - if opt ~= 3 and opt ~= 7 then - last = map_regs.w[band(rshift(op, 16), 31)] - operands[#operands] = last - end - x = band(rshift(op, 10), 7) - -- Extension. - if opt == 2 + band(rshift(op, 31), 1) and - band(rshift(op, second0 and 5 or 0), 31) == 31 then - if x == 0 then x = nil - else x = "lsl #"..x end - else - if x == 0 then x = map_extend[band(rshift(op, 13), 7)] - else x = map_extend[band(rshift(op, 13), 7)].." #"..x end - end - elseif p == "R" then - x = band(rshift(op,21), 3) - if x == 0 then x = nil - else x = "lsl #"..x*16 end - elseif p == "z" then - local n = #operands - if operands[n] == "sp" then operands[n] = "xzr" - elseif operands[n] == "wsp" then operands[n] = "wzr" - end - elseif p == "Z" then - x = 0 - elseif p == "F" then - x = parse_fpimm8(op) - elseif p == "g" or p == "f" or p == "x" or p == "w" or - p == "d" or p == "s" then - -- These are handled in D/N/M/A. - elseif p == "0" then - if last == "sp" or last == "wsp" then - local n = #operands - operands[n] = nil - last = operands[n-1] - if altname then - local a1, a2 = match(altname, "([^|]*)|(.*)") - if not a1 then - name = altname - elseif second0 then - name, altname = a2, a1 - else - name, altname = a1, a2 - end - end - end - second0 = true - else - assert(false) - end - if x then - last = x - if type(x) == "number" then x = "#"..x end - operands[#operands+1] = x - end - end - - return putop(ctx, name..suffix, operands) -end - ------------------------------------------------------------------------------- - --- Disassemble a block of code. -local function disass_block(ctx, ofs, len) - if not ofs then ofs = 0 end - local stop = len and ofs+len or #ctx.code - ctx.pos = ofs - ctx.rel = nil - while ctx.pos < stop do disass_ins(ctx) end -end - --- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). -local function create(code, addr, out) - local ctx = {} - ctx.code = code - ctx.addr = addr or 0 - ctx.out = out or io.write - ctx.symtab = {} - ctx.disass = disass_block - ctx.hexdump = 8 - return ctx -end - --- Simple API: disassemble code (a string) at address and output via out. -local function disass(code, addr, out) - create(code, addr, out):disass() -end - --- Return register name for RID. -local function regname(r) - if r < 32 then return map_regs.x[r] end - return map_regs.d[r-32] -end - --- Public module functions. -return { - create = create, - disass = disass, - regname = regname -} - diff --git a/lib/LuaJIT/src/jit/dis_arm64be.lua b/lib/LuaJIT/src/jit/dis_arm64be.lua deleted file mode 100644 index 7eb389e..0000000 --- a/lib/LuaJIT/src/jit/dis_arm64be.lua +++ /dev/null @@ -1,12 +0,0 @@ ----------------------------------------------------------------------------- --- LuaJIT ARM64BE disassembler wrapper module. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- Released under the MIT license. See Copyright Notice in luajit.h ----------------------------------------------------------------------------- --- ARM64 instructions are always little-endian. So just forward to the --- common ARM64 disassembler module. All the interesting stuff is there. ------------------------------------------------------------------------------- - -return require((string.match(..., ".*%.") or "").."dis_arm64") - diff --git a/lib/LuaJIT/src/jit/dis_mips.lua b/lib/LuaJIT/src/jit/dis_mips.lua deleted file mode 100644 index a12b8e6..0000000 --- a/lib/LuaJIT/src/jit/dis_mips.lua +++ /dev/null @@ -1,443 +0,0 @@ ----------------------------------------------------------------------------- --- LuaJIT MIPS disassembler module. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- Released under the MIT/X license. See Copyright Notice in luajit.h ----------------------------------------------------------------------------- --- This is a helper module used by the LuaJIT machine code dumper module. --- --- It disassembles all standard MIPS32R1/R2 instructions. --- Default mode is big-endian, but see: dis_mipsel.lua ------------------------------------------------------------------------------- - -local type = type -local byte, format = string.byte, string.format -local match, gmatch = string.match, string.gmatch -local concat = table.concat -local bit = require("bit") -local band, bor, tohex = bit.band, bit.bor, bit.tohex -local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift - ------------------------------------------------------------------------------- --- Primary and extended opcode maps ------------------------------------------------------------------------------- - -local map_movci = { shift = 16, mask = 1, [0] = "movfDSC", "movtDSC", } -local map_srl = { shift = 21, mask = 1, [0] = "srlDTA", "rotrDTA", } -local map_srlv = { shift = 6, mask = 1, [0] = "srlvDTS", "rotrvDTS", } - -local map_special = { - shift = 0, mask = 63, - [0] = { shift = 0, mask = -1, [0] = "nop", _ = "sllDTA" }, - map_movci, map_srl, "sraDTA", - "sllvDTS", false, map_srlv, "sravDTS", - "jrS", "jalrD1S", "movzDST", "movnDST", - "syscallY", "breakY", false, "sync", - "mfhiD", "mthiS", "mfloD", "mtloS", - "dsllvDST", false, "dsrlvDST", "dsravDST", - "multST", "multuST", "divST", "divuST", - "dmultST", "dmultuST", "ddivST", "ddivuST", - "addDST", "addu|moveDST0", "subDST", "subu|neguDS0T", - "andDST", "or|moveDST0", "xorDST", "nor|notDST0", - false, false, "sltDST", "sltuDST", - "daddDST", "dadduDST", "dsubDST", "dsubuDST", - "tgeSTZ", "tgeuSTZ", "tltSTZ", "tltuSTZ", - "teqSTZ", false, "tneSTZ", false, - "dsllDTA", false, "dsrlDTA", "dsraDTA", - "dsll32DTA", false, "dsrl32DTA", "dsra32DTA", -} - -local map_special2 = { - shift = 0, mask = 63, - [0] = "maddST", "madduST", "mulDST", false, - "msubST", "msubuST", - [32] = "clzDS", [33] = "cloDS", - [63] = "sdbbpY", -} - -local map_bshfl = { - shift = 6, mask = 31, - [2] = "wsbhDT", - [16] = "sebDT", - [24] = "sehDT", -} - -local map_dbshfl = { - shift = 6, mask = 31, - [2] = "dsbhDT", - [5] = "dshdDT", -} - -local map_special3 = { - shift = 0, mask = 63, - [0] = "extTSAK", [1] = "dextmTSAP", [3] = "dextTSAK", - [4] = "insTSAL", [6] = "dinsuTSEQ", [7] = "dinsTSAL", - [32] = map_bshfl, [36] = map_dbshfl, [59] = "rdhwrTD", -} - -local map_regimm = { - shift = 16, mask = 31, - [0] = "bltzSB", "bgezSB", "bltzlSB", "bgezlSB", - false, false, false, false, - "tgeiSI", "tgeiuSI", "tltiSI", "tltiuSI", - "teqiSI", false, "tneiSI", false, - "bltzalSB", "bgezalSB", "bltzallSB", "bgezallSB", - false, false, false, false, - false, false, false, false, - false, false, false, "synciSO", -} - -local map_cop0 = { - shift = 25, mask = 1, - [0] = { - shift = 21, mask = 15, - [0] = "mfc0TDW", [4] = "mtc0TDW", - [10] = "rdpgprDT", - [11] = { shift = 5, mask = 1, [0] = "diT0", "eiT0", }, - [14] = "wrpgprDT", - }, { - shift = 0, mask = 63, - [1] = "tlbr", [2] = "tlbwi", [6] = "tlbwr", [8] = "tlbp", - [24] = "eret", [31] = "deret", - [32] = "wait", - }, -} - -local map_cop1s = { - shift = 0, mask = 63, - [0] = "add.sFGH", "sub.sFGH", "mul.sFGH", "div.sFGH", - "sqrt.sFG", "abs.sFG", "mov.sFG", "neg.sFG", - "round.l.sFG", "trunc.l.sFG", "ceil.l.sFG", "floor.l.sFG", - "round.w.sFG", "trunc.w.sFG", "ceil.w.sFG", "floor.w.sFG", - false, - { shift = 16, mask = 1, [0] = "movf.sFGC", "movt.sFGC" }, - "movz.sFGT", "movn.sFGT", - false, "recip.sFG", "rsqrt.sFG", false, - false, false, false, false, - false, false, false, false, - false, "cvt.d.sFG", false, false, - "cvt.w.sFG", "cvt.l.sFG", "cvt.ps.sFGH", false, - false, false, false, false, - false, false, false, false, - "c.f.sVGH", "c.un.sVGH", "c.eq.sVGH", "c.ueq.sVGH", - "c.olt.sVGH", "c.ult.sVGH", "c.ole.sVGH", "c.ule.sVGH", - "c.sf.sVGH", "c.ngle.sVGH", "c.seq.sVGH", "c.ngl.sVGH", - "c.lt.sVGH", "c.nge.sVGH", "c.le.sVGH", "c.ngt.sVGH", -} - -local map_cop1d = { - shift = 0, mask = 63, - [0] = "add.dFGH", "sub.dFGH", "mul.dFGH", "div.dFGH", - "sqrt.dFG", "abs.dFG", "mov.dFG", "neg.dFG", - "round.l.dFG", "trunc.l.dFG", "ceil.l.dFG", "floor.l.dFG", - "round.w.dFG", "trunc.w.dFG", "ceil.w.dFG", "floor.w.dFG", - false, - { shift = 16, mask = 1, [0] = "movf.dFGC", "movt.dFGC" }, - "movz.dFGT", "movn.dFGT", - false, "recip.dFG", "rsqrt.dFG", false, - false, false, false, false, - false, false, false, false, - "cvt.s.dFG", false, false, false, - "cvt.w.dFG", "cvt.l.dFG", false, false, - false, false, false, false, - false, false, false, false, - "c.f.dVGH", "c.un.dVGH", "c.eq.dVGH", "c.ueq.dVGH", - "c.olt.dVGH", "c.ult.dVGH", "c.ole.dVGH", "c.ule.dVGH", - "c.df.dVGH", "c.ngle.dVGH", "c.deq.dVGH", "c.ngl.dVGH", - "c.lt.dVGH", "c.nge.dVGH", "c.le.dVGH", "c.ngt.dVGH", -} - -local map_cop1ps = { - shift = 0, mask = 63, - [0] = "add.psFGH", "sub.psFGH", "mul.psFGH", false, - false, "abs.psFG", "mov.psFG", "neg.psFG", - false, false, false, false, - false, false, false, false, - false, - { shift = 16, mask = 1, [0] = "movf.psFGC", "movt.psFGC" }, - "movz.psFGT", "movn.psFGT", - false, false, false, false, - false, false, false, false, - false, false, false, false, - "cvt.s.puFG", false, false, false, - false, false, false, false, - "cvt.s.plFG", false, false, false, - "pll.psFGH", "plu.psFGH", "pul.psFGH", "puu.psFGH", - "c.f.psVGH", "c.un.psVGH", "c.eq.psVGH", "c.ueq.psVGH", - "c.olt.psVGH", "c.ult.psVGH", "c.ole.psVGH", "c.ule.psVGH", - "c.psf.psVGH", "c.ngle.psVGH", "c.pseq.psVGH", "c.ngl.psVGH", - "c.lt.psVGH", "c.nge.psVGH", "c.le.psVGH", "c.ngt.psVGH", -} - -local map_cop1w = { - shift = 0, mask = 63, - [32] = "cvt.s.wFG", [33] = "cvt.d.wFG", -} - -local map_cop1l = { - shift = 0, mask = 63, - [32] = "cvt.s.lFG", [33] = "cvt.d.lFG", -} - -local map_cop1bc = { - shift = 16, mask = 3, - [0] = "bc1fCB", "bc1tCB", "bc1flCB", "bc1tlCB", -} - -local map_cop1 = { - shift = 21, mask = 31, - [0] = "mfc1TG", "dmfc1TG", "cfc1TG", "mfhc1TG", - "mtc1TG", "dmtc1TG", "ctc1TG", "mthc1TG", - map_cop1bc, false, false, false, - false, false, false, false, - map_cop1s, map_cop1d, false, false, - map_cop1w, map_cop1l, map_cop1ps, -} - -local map_cop1x = { - shift = 0, mask = 63, - [0] = "lwxc1FSX", "ldxc1FSX", false, false, - false, "luxc1FSX", false, false, - "swxc1FSX", "sdxc1FSX", false, false, - false, "suxc1FSX", false, "prefxMSX", - false, false, false, false, - false, false, false, false, - false, false, false, false, - false, false, "alnv.psFGHS", false, - "madd.sFRGH", "madd.dFRGH", false, false, - false, false, "madd.psFRGH", false, - "msub.sFRGH", "msub.dFRGH", false, false, - false, false, "msub.psFRGH", false, - "nmadd.sFRGH", "nmadd.dFRGH", false, false, - false, false, "nmadd.psFRGH", false, - "nmsub.sFRGH", "nmsub.dFRGH", false, false, - false, false, "nmsub.psFRGH", false, -} - -local map_pri = { - [0] = map_special, map_regimm, "jJ", "jalJ", - "beq|beqz|bST00B", "bne|bnezST0B", "blezSB", "bgtzSB", - "addiTSI", "addiu|liTS0I", "sltiTSI", "sltiuTSI", - "andiTSU", "ori|liTS0U", "xoriTSU", "luiTU", - map_cop0, map_cop1, false, map_cop1x, - "beql|beqzlST0B", "bnel|bnezlST0B", "blezlSB", "bgtzlSB", - "daddiTSI", "daddiuTSI", false, false, - map_special2, "jalxJ", false, map_special3, - "lbTSO", "lhTSO", "lwlTSO", "lwTSO", - "lbuTSO", "lhuTSO", "lwrTSO", false, - "sbTSO", "shTSO", "swlTSO", "swTSO", - false, false, "swrTSO", "cacheNSO", - "llTSO", "lwc1HSO", "lwc2TSO", "prefNSO", - false, "ldc1HSO", "ldc2TSO", "ldTSO", - "scTSO", "swc1HSO", "swc2TSO", false, - false, "sdc1HSO", "sdc2TSO", "sdTSO", -} - ------------------------------------------------------------------------------- - -local map_gpr = { - [0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", - "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", - "r24", "r25", "r26", "r27", "r28", "sp", "r30", "ra", -} - ------------------------------------------------------------------------------- - --- Output a nicely formatted line with an opcode and operands. -local function putop(ctx, text, operands) - local pos = ctx.pos - local extra = "" - if ctx.rel then - local sym = ctx.symtab[ctx.rel] - if sym then extra = "\t->"..sym end - end - if ctx.hexdump > 0 then - ctx.out(format("%08x %s %-7s %s%s\n", - ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra)) - else - ctx.out(format("%08x %-7s %s%s\n", - ctx.addr+pos, text, concat(operands, ", "), extra)) - end - ctx.pos = pos + 4 -end - --- Fallback for unknown opcodes. -local function unknown(ctx) - return putop(ctx, ".long", { "0x"..tohex(ctx.op) }) -end - -local function get_be(ctx) - local pos = ctx.pos - local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) - return bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3) -end - -local function get_le(ctx) - local pos = ctx.pos - local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) - return bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0) -end - --- Disassemble a single instruction. -local function disass_ins(ctx) - local op = ctx:get() - local operands = {} - local last = nil - ctx.op = op - ctx.rel = nil - - local opat = map_pri[rshift(op, 26)] - while type(opat) ~= "string" do - if not opat then return unknown(ctx) end - opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._ - end - local name, pat = match(opat, "^([a-z0-9_.]*)(.*)") - local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)") - if altname then pat = pat2 end - - for p in gmatch(pat, ".") do - local x = nil - if p == "S" then - x = map_gpr[band(rshift(op, 21), 31)] - elseif p == "T" then - x = map_gpr[band(rshift(op, 16), 31)] - elseif p == "D" then - x = map_gpr[band(rshift(op, 11), 31)] - elseif p == "F" then - x = "f"..band(rshift(op, 6), 31) - elseif p == "G" then - x = "f"..band(rshift(op, 11), 31) - elseif p == "H" then - x = "f"..band(rshift(op, 16), 31) - elseif p == "R" then - x = "f"..band(rshift(op, 21), 31) - elseif p == "A" then - x = band(rshift(op, 6), 31) - elseif p == "E" then - x = band(rshift(op, 6), 31) + 32 - elseif p == "M" then - x = band(rshift(op, 11), 31) - elseif p == "N" then - x = band(rshift(op, 16), 31) - elseif p == "C" then - x = band(rshift(op, 18), 7) - if x == 0 then x = nil end - elseif p == "K" then - x = band(rshift(op, 11), 31) + 1 - elseif p == "P" then - x = band(rshift(op, 11), 31) + 33 - elseif p == "L" then - x = band(rshift(op, 11), 31) - last + 1 - elseif p == "Q" then - x = band(rshift(op, 11), 31) - last + 33 - elseif p == "I" then - x = arshift(lshift(op, 16), 16) - elseif p == "U" then - x = band(op, 0xffff) - elseif p == "O" then - local disp = arshift(lshift(op, 16), 16) - operands[#operands] = format("%d(%s)", disp, last) - elseif p == "X" then - local index = map_gpr[band(rshift(op, 16), 31)] - operands[#operands] = format("%s(%s)", index, last) - elseif p == "B" then - x = ctx.addr + ctx.pos + arshift(lshift(op, 16), 16)*4 + 4 - ctx.rel = x - x = format("0x%08x", x) - elseif p == "J" then - local a = ctx.addr + ctx.pos - x = a - band(a, 0x0fffffff) + band(op, 0x03ffffff)*4 - ctx.rel = x - x = format("0x%08x", x) - elseif p == "V" then - x = band(rshift(op, 8), 7) - if x == 0 then x = nil end - elseif p == "W" then - x = band(op, 7) - if x == 0 then x = nil end - elseif p == "Y" then - x = band(rshift(op, 6), 0x000fffff) - if x == 0 then x = nil end - elseif p == "Z" then - x = band(rshift(op, 6), 1023) - if x == 0 then x = nil end - elseif p == "0" then - if last == "r0" or last == 0 then - local n = #operands - operands[n] = nil - last = operands[n-1] - if altname then - local a1, a2 = match(altname, "([^|]*)|(.*)") - if a1 then name, altname = a1, a2 - else name = altname end - end - end - elseif p == "1" then - if last == "ra" then - operands[#operands] = nil - end - else - assert(false) - end - if x then operands[#operands+1] = x; last = x end - end - - return putop(ctx, name, operands) -end - ------------------------------------------------------------------------------- - --- Disassemble a block of code. -local function disass_block(ctx, ofs, len) - if not ofs then ofs = 0 end - local stop = len and ofs+len or #ctx.code - stop = stop - stop % 4 - ctx.pos = ofs - ofs % 4 - ctx.rel = nil - while ctx.pos < stop do disass_ins(ctx) end -end - --- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). -local function create(code, addr, out) - local ctx = {} - ctx.code = code - ctx.addr = addr or 0 - ctx.out = out or io.write - ctx.symtab = {} - ctx.disass = disass_block - ctx.hexdump = 8 - ctx.get = get_be - return ctx -end - -local function create_el(code, addr, out) - local ctx = create(code, addr, out) - ctx.get = get_le - return ctx -end - --- Simple API: disassemble code (a string) at address and output via out. -local function disass(code, addr, out) - create(code, addr, out):disass() -end - -local function disass_el(code, addr, out) - create_el(code, addr, out):disass() -end - --- Return register name for RID. -local function regname(r) - if r < 32 then return map_gpr[r] end - return "f"..(r-32) -end - --- Public module functions. -return { - create = create, - create_el = create_el, - disass = disass, - disass_el = disass_el, - regname = regname -} - diff --git a/lib/LuaJIT/src/jit/dis_mips64.lua b/lib/LuaJIT/src/jit/dis_mips64.lua deleted file mode 100644 index c437492..0000000 --- a/lib/LuaJIT/src/jit/dis_mips64.lua +++ /dev/null @@ -1,17 +0,0 @@ ----------------------------------------------------------------------------- --- LuaJIT MIPS64 disassembler wrapper module. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- Released under the MIT license. See Copyright Notice in luajit.h ----------------------------------------------------------------------------- --- This module just exports the big-endian functions from the --- MIPS disassembler module. All the interesting stuff is there. ------------------------------------------------------------------------------- - -local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips") -return { - create = dis_mips.create, - disass = dis_mips.disass, - regname = dis_mips.regname -} - diff --git a/lib/LuaJIT/src/jit/dis_mips64el.lua b/lib/LuaJIT/src/jit/dis_mips64el.lua deleted file mode 100644 index 2b1470a..0000000 --- a/lib/LuaJIT/src/jit/dis_mips64el.lua +++ /dev/null @@ -1,17 +0,0 @@ ----------------------------------------------------------------------------- --- LuaJIT MIPS64EL disassembler wrapper module. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- Released under the MIT license. See Copyright Notice in luajit.h ----------------------------------------------------------------------------- --- This module just exports the little-endian functions from the --- MIPS disassembler module. All the interesting stuff is there. ------------------------------------------------------------------------------- - -local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips") -return { - create = dis_mips.create_el, - disass = dis_mips.disass_el, - regname = dis_mips.regname -} - diff --git a/lib/LuaJIT/src/jit/dis_mipsel.lua b/lib/LuaJIT/src/jit/dis_mipsel.lua deleted file mode 100644 index f69b11f..0000000 --- a/lib/LuaJIT/src/jit/dis_mipsel.lua +++ /dev/null @@ -1,17 +0,0 @@ ----------------------------------------------------------------------------- --- LuaJIT MIPSEL disassembler wrapper module. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- Released under the MIT license. See Copyright Notice in luajit.h ----------------------------------------------------------------------------- --- This module just exports the little-endian functions from the --- MIPS disassembler module. All the interesting stuff is there. ------------------------------------------------------------------------------- - -local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips") -return { - create = dis_mips.create_el, - disass = dis_mips.disass_el, - regname = dis_mips.regname -} - diff --git a/lib/LuaJIT/src/jit/dis_ppc.lua b/lib/LuaJIT/src/jit/dis_ppc.lua deleted file mode 100644 index 2aeb1b2..0000000 --- a/lib/LuaJIT/src/jit/dis_ppc.lua +++ /dev/null @@ -1,591 +0,0 @@ ----------------------------------------------------------------------------- --- LuaJIT PPC disassembler module. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- Released under the MIT/X license. See Copyright Notice in luajit.h ----------------------------------------------------------------------------- --- This is a helper module used by the LuaJIT machine code dumper module. --- --- It disassembles all common, non-privileged 32/64 bit PowerPC instructions --- plus the e500 SPE instructions and some Cell/Xenon extensions. --- --- NYI: VMX, VMX128 ------------------------------------------------------------------------------- - -local type = type -local byte, format = string.byte, string.format -local match, gmatch, gsub = string.match, string.gmatch, string.gsub -local concat = table.concat -local bit = require("bit") -local band, bor, tohex = bit.band, bit.bor, bit.tohex -local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift - ------------------------------------------------------------------------------- --- Primary and extended opcode maps ------------------------------------------------------------------------------- - -local map_crops = { - shift = 1, mask = 1023, - [0] = "mcrfXX", - [33] = "crnor|crnotCCC=", [129] = "crandcCCC", - [193] = "crxor|crclrCCC%", [225] = "crnandCCC", - [257] = "crandCCC", [289] = "creqv|crsetCCC%", - [417] = "crorcCCC", [449] = "cror|crmoveCCC=", - [16] = "b_lrKB", [528] = "b_ctrKB", - [150] = "isync", -} - -local map_rlwinm = setmetatable({ - shift = 0, mask = -1, -}, -{ __index = function(t, x) - local rot = band(rshift(x, 11), 31) - local mb = band(rshift(x, 6), 31) - local me = band(rshift(x, 1), 31) - if mb == 0 and me == 31-rot then - return "slwiRR~A." - elseif me == 31 and mb == 32-rot then - return "srwiRR~-A." - else - return "rlwinmRR~AAA." - end - end -}) - -local map_rld = { - shift = 2, mask = 7, - [0] = "rldiclRR~HM.", "rldicrRR~HM.", "rldicRR~HM.", "rldimiRR~HM.", - { - shift = 1, mask = 1, - [0] = "rldclRR~RM.", "rldcrRR~RM.", - }, -} - -local map_ext = setmetatable({ - shift = 1, mask = 1023, - - [0] = "cmp_YLRR", [32] = "cmpl_YLRR", - [4] = "twARR", [68] = "tdARR", - - [8] = "subfcRRR.", [40] = "subfRRR.", - [104] = "negRR.", [136] = "subfeRRR.", - [200] = "subfzeRR.", [232] = "subfmeRR.", - [520] = "subfcoRRR.", [552] = "subfoRRR.", - [616] = "negoRR.", [648] = "subfeoRRR.", - [712] = "subfzeoRR.", [744] = "subfmeoRR.", - - [9] = "mulhduRRR.", [73] = "mulhdRRR.", [233] = "mulldRRR.", - [457] = "divduRRR.", [489] = "divdRRR.", - [745] = "mulldoRRR.", - [969] = "divduoRRR.", [1001] = "divdoRRR.", - - [10] = "addcRRR.", [138] = "addeRRR.", - [202] = "addzeRR.", [234] = "addmeRR.", [266] = "addRRR.", - [522] = "addcoRRR.", [650] = "addeoRRR.", - [714] = "addzeoRR.", [746] = "addmeoRR.", [778] = "addoRRR.", - - [11] = "mulhwuRRR.", [75] = "mulhwRRR.", [235] = "mullwRRR.", - [459] = "divwuRRR.", [491] = "divwRRR.", - [747] = "mullwoRRR.", - [971] = "divwouRRR.", [1003] = "divwoRRR.", - - [15] = "iselltRRR", [47] = "iselgtRRR", [79] = "iseleqRRR", - - [144] = { shift = 20, mask = 1, [0] = "mtcrfRZ~", "mtocrfRZ~", }, - [19] = { shift = 20, mask = 1, [0] = "mfcrR", "mfocrfRZ", }, - [371] = { shift = 11, mask = 1023, [392] = "mftbR", [424] = "mftbuR", }, - [339] = { - shift = 11, mask = 1023, - [32] = "mferR", [256] = "mflrR", [288] = "mfctrR", [16] = "mfspefscrR", - }, - [467] = { - shift = 11, mask = 1023, - [32] = "mtxerR", [256] = "mtlrR", [288] = "mtctrR", [16] = "mtspefscrR", - }, - - [20] = "lwarxRR0R", [84] = "ldarxRR0R", - - [21] = "ldxRR0R", [53] = "lduxRRR", - [149] = "stdxRR0R", [181] = "stduxRRR", - [341] = "lwaxRR0R", [373] = "lwauxRRR", - - [23] = "lwzxRR0R", [55] = "lwzuxRRR", - [87] = "lbzxRR0R", [119] = "lbzuxRRR", - [151] = "stwxRR0R", [183] = "stwuxRRR", - [215] = "stbxRR0R", [247] = "stbuxRRR", - [279] = "lhzxRR0R", [311] = "lhzuxRRR", - [343] = "lhaxRR0R", [375] = "lhauxRRR", - [407] = "sthxRR0R", [439] = "sthuxRRR", - - [54] = "dcbst-R0R", [86] = "dcbf-R0R", - [150] = "stwcxRR0R.", [214] = "stdcxRR0R.", - [246] = "dcbtst-R0R", [278] = "dcbt-R0R", - [310] = "eciwxRR0R", [438] = "ecowxRR0R", - [470] = "dcbi-RR", - - [598] = { - shift = 21, mask = 3, - [0] = "sync", "lwsync", "ptesync", - }, - [758] = "dcba-RR", - [854] = "eieio", [982] = "icbi-R0R", [1014] = "dcbz-R0R", - - [26] = "cntlzwRR~", [58] = "cntlzdRR~", - [122] = "popcntbRR~", - [154] = "prtywRR~", [186] = "prtydRR~", - - [28] = "andRR~R.", [60] = "andcRR~R.", [124] = "nor|notRR~R=.", - [284] = "eqvRR~R.", [316] = "xorRR~R.", - [412] = "orcRR~R.", [444] = "or|mrRR~R=.", [476] = "nandRR~R.", - [508] = "cmpbRR~R", - - [512] = "mcrxrX", - - [532] = "ldbrxRR0R", [660] = "stdbrxRR0R", - - [533] = "lswxRR0R", [597] = "lswiRR0A", - [661] = "stswxRR0R", [725] = "stswiRR0A", - - [534] = "lwbrxRR0R", [662] = "stwbrxRR0R", - [790] = "lhbrxRR0R", [918] = "sthbrxRR0R", - - [535] = "lfsxFR0R", [567] = "lfsuxFRR", - [599] = "lfdxFR0R", [631] = "lfduxFRR", - [663] = "stfsxFR0R", [695] = "stfsuxFRR", - [727] = "stfdxFR0R", [759] = "stfduxFR0R", - [855] = "lfiwaxFR0R", - [983] = "stfiwxFR0R", - - [24] = "slwRR~R.", - - [27] = "sldRR~R.", [536] = "srwRR~R.", - [792] = "srawRR~R.", [824] = "srawiRR~A.", - - [794] = "sradRR~R.", [826] = "sradiRR~H.", [827] = "sradiRR~H.", - [922] = "extshRR~.", [954] = "extsbRR~.", [986] = "extswRR~.", - - [539] = "srdRR~R.", -}, -{ __index = function(t, x) - if band(x, 31) == 15 then return "iselRRRC" end - end -}) - -local map_ld = { - shift = 0, mask = 3, - [0] = "ldRRE", "lduRRE", "lwaRRE", -} - -local map_std = { - shift = 0, mask = 3, - [0] = "stdRRE", "stduRRE", -} - -local map_fps = { - shift = 5, mask = 1, - { - shift = 1, mask = 15, - [0] = false, false, "fdivsFFF.", false, - "fsubsFFF.", "faddsFFF.", "fsqrtsF-F.", false, - "fresF-F.", "fmulsFF-F.", "frsqrtesF-F.", false, - "fmsubsFFFF~.", "fmaddsFFFF~.", "fnmsubsFFFF~.", "fnmaddsFFFF~.", - } -} - -local map_fpd = { - shift = 5, mask = 1, - [0] = { - shift = 1, mask = 1023, - [0] = "fcmpuXFF", [32] = "fcmpoXFF", [64] = "mcrfsXX", - [38] = "mtfsb1A.", [70] = "mtfsb0A.", [134] = "mtfsfiA>>-A>", - [8] = "fcpsgnFFF.", [40] = "fnegF-F.", [72] = "fmrF-F.", - [136] = "fnabsF-F.", [264] = "fabsF-F.", - [12] = "frspF-F.", - [14] = "fctiwF-F.", [15] = "fctiwzF-F.", - [583] = "mffsF.", [711] = "mtfsfZF.", - [392] = "frinF-F.", [424] = "frizF-F.", - [456] = "fripF-F.", [488] = "frimF-F.", - [814] = "fctidF-F.", [815] = "fctidzF-F.", [846] = "fcfidF-F.", - }, - { - shift = 1, mask = 15, - [0] = false, false, "fdivFFF.", false, - "fsubFFF.", "faddFFF.", "fsqrtF-F.", "fselFFFF~.", - "freF-F.", "fmulFF-F.", "frsqrteF-F.", false, - "fmsubFFFF~.", "fmaddFFFF~.", "fnmsubFFFF~.", "fnmaddFFFF~.", - } -} - -local map_spe = { - shift = 0, mask = 2047, - - [512] = "evaddwRRR", [514] = "evaddiwRAR~", - [516] = "evsubwRRR~", [518] = "evsubiwRAR~", - [520] = "evabsRR", [521] = "evnegRR", - [522] = "evextsbRR", [523] = "evextshRR", [524] = "evrndwRR", - [525] = "evcntlzwRR", [526] = "evcntlswRR", - - [527] = "brincRRR", - - [529] = "evandRRR", [530] = "evandcRRR", [534] = "evxorRRR", - [535] = "evor|evmrRRR=", [536] = "evnor|evnotRRR=", - [537] = "eveqvRRR", [539] = "evorcRRR", [542] = "evnandRRR", - - [544] = "evsrwuRRR", [545] = "evsrwsRRR", - [546] = "evsrwiuRRA", [547] = "evsrwisRRA", - [548] = "evslwRRR", [550] = "evslwiRRA", - [552] = "evrlwRRR", [553] = "evsplatiRS", - [554] = "evrlwiRRA", [555] = "evsplatfiRS", - [556] = "evmergehiRRR", [557] = "evmergeloRRR", - [558] = "evmergehiloRRR", [559] = "evmergelohiRRR", - - [560] = "evcmpgtuYRR", [561] = "evcmpgtsYRR", - [562] = "evcmpltuYRR", [563] = "evcmpltsYRR", - [564] = "evcmpeqYRR", - - [632] = "evselRRR", [633] = "evselRRRW", - [634] = "evselRRRW", [635] = "evselRRRW", - [636] = "evselRRRW", [637] = "evselRRRW", - [638] = "evselRRRW", [639] = "evselRRRW", - - [640] = "evfsaddRRR", [641] = "evfssubRRR", - [644] = "evfsabsRR", [645] = "evfsnabsRR", [646] = "evfsnegRR", - [648] = "evfsmulRRR", [649] = "evfsdivRRR", - [652] = "evfscmpgtYRR", [653] = "evfscmpltYRR", [654] = "evfscmpeqYRR", - [656] = "evfscfuiR-R", [657] = "evfscfsiR-R", - [658] = "evfscfufR-R", [659] = "evfscfsfR-R", - [660] = "evfsctuiR-R", [661] = "evfsctsiR-R", - [662] = "evfsctufR-R", [663] = "evfsctsfR-R", - [664] = "evfsctuizR-R", [666] = "evfsctsizR-R", - [668] = "evfststgtYRR", [669] = "evfststltYRR", [670] = "evfststeqYRR", - - [704] = "efsaddRRR", [705] = "efssubRRR", - [708] = "efsabsRR", [709] = "efsnabsRR", [710] = "efsnegRR", - [712] = "efsmulRRR", [713] = "efsdivRRR", - [716] = "efscmpgtYRR", [717] = "efscmpltYRR", [718] = "efscmpeqYRR", - [719] = "efscfdR-R", - [720] = "efscfuiR-R", [721] = "efscfsiR-R", - [722] = "efscfufR-R", [723] = "efscfsfR-R", - [724] = "efsctuiR-R", [725] = "efsctsiR-R", - [726] = "efsctufR-R", [727] = "efsctsfR-R", - [728] = "efsctuizR-R", [730] = "efsctsizR-R", - [732] = "efststgtYRR", [733] = "efststltYRR", [734] = "efststeqYRR", - - [736] = "efdaddRRR", [737] = "efdsubRRR", - [738] = "efdcfuidR-R", [739] = "efdcfsidR-R", - [740] = "efdabsRR", [741] = "efdnabsRR", [742] = "efdnegRR", - [744] = "efdmulRRR", [745] = "efddivRRR", - [746] = "efdctuidzR-R", [747] = "efdctsidzR-R", - [748] = "efdcmpgtYRR", [749] = "efdcmpltYRR", [750] = "efdcmpeqYRR", - [751] = "efdcfsR-R", - [752] = "efdcfuiR-R", [753] = "efdcfsiR-R", - [754] = "efdcfufR-R", [755] = "efdcfsfR-R", - [756] = "efdctuiR-R", [757] = "efdctsiR-R", - [758] = "efdctufR-R", [759] = "efdctsfR-R", - [760] = "efdctuizR-R", [762] = "efdctsizR-R", - [764] = "efdtstgtYRR", [765] = "efdtstltYRR", [766] = "efdtsteqYRR", - - [768] = "evlddxRR0R", [769] = "evlddRR8", - [770] = "evldwxRR0R", [771] = "evldwRR8", - [772] = "evldhxRR0R", [773] = "evldhRR8", - [776] = "evlhhesplatxRR0R", [777] = "evlhhesplatRR2", - [780] = "evlhhousplatxRR0R", [781] = "evlhhousplatRR2", - [782] = "evlhhossplatxRR0R", [783] = "evlhhossplatRR2", - [784] = "evlwhexRR0R", [785] = "evlwheRR4", - [788] = "evlwhouxRR0R", [789] = "evlwhouRR4", - [790] = "evlwhosxRR0R", [791] = "evlwhosRR4", - [792] = "evlwwsplatxRR0R", [793] = "evlwwsplatRR4", - [796] = "evlwhsplatxRR0R", [797] = "evlwhsplatRR4", - - [800] = "evstddxRR0R", [801] = "evstddRR8", - [802] = "evstdwxRR0R", [803] = "evstdwRR8", - [804] = "evstdhxRR0R", [805] = "evstdhRR8", - [816] = "evstwhexRR0R", [817] = "evstwheRR4", - [820] = "evstwhoxRR0R", [821] = "evstwhoRR4", - [824] = "evstwwexRR0R", [825] = "evstwweRR4", - [828] = "evstwwoxRR0R", [829] = "evstwwoRR4", - - [1027] = "evmhessfRRR", [1031] = "evmhossfRRR", [1032] = "evmheumiRRR", - [1033] = "evmhesmiRRR", [1035] = "evmhesmfRRR", [1036] = "evmhoumiRRR", - [1037] = "evmhosmiRRR", [1039] = "evmhosmfRRR", [1059] = "evmhessfaRRR", - [1063] = "evmhossfaRRR", [1064] = "evmheumiaRRR", [1065] = "evmhesmiaRRR", - [1067] = "evmhesmfaRRR", [1068] = "evmhoumiaRRR", [1069] = "evmhosmiaRRR", - [1071] = "evmhosmfaRRR", [1095] = "evmwhssfRRR", [1096] = "evmwlumiRRR", - [1100] = "evmwhumiRRR", [1101] = "evmwhsmiRRR", [1103] = "evmwhsmfRRR", - [1107] = "evmwssfRRR", [1112] = "evmwumiRRR", [1113] = "evmwsmiRRR", - [1115] = "evmwsmfRRR", [1127] = "evmwhssfaRRR", [1128] = "evmwlumiaRRR", - [1132] = "evmwhumiaRRR", [1133] = "evmwhsmiaRRR", [1135] = "evmwhsmfaRRR", - [1139] = "evmwssfaRRR", [1144] = "evmwumiaRRR", [1145] = "evmwsmiaRRR", - [1147] = "evmwsmfaRRR", - - [1216] = "evaddusiaawRR", [1217] = "evaddssiaawRR", - [1218] = "evsubfusiaawRR", [1219] = "evsubfssiaawRR", - [1220] = "evmraRR", - [1222] = "evdivwsRRR", [1223] = "evdivwuRRR", - [1224] = "evaddumiaawRR", [1225] = "evaddsmiaawRR", - [1226] = "evsubfumiaawRR", [1227] = "evsubfsmiaawRR", - - [1280] = "evmheusiaawRRR", [1281] = "evmhessiaawRRR", - [1283] = "evmhessfaawRRR", [1284] = "evmhousiaawRRR", - [1285] = "evmhossiaawRRR", [1287] = "evmhossfaawRRR", - [1288] = "evmheumiaawRRR", [1289] = "evmhesmiaawRRR", - [1291] = "evmhesmfaawRRR", [1292] = "evmhoumiaawRRR", - [1293] = "evmhosmiaawRRR", [1295] = "evmhosmfaawRRR", - [1320] = "evmhegumiaaRRR", [1321] = "evmhegsmiaaRRR", - [1323] = "evmhegsmfaaRRR", [1324] = "evmhogumiaaRRR", - [1325] = "evmhogsmiaaRRR", [1327] = "evmhogsmfaaRRR", - [1344] = "evmwlusiaawRRR", [1345] = "evmwlssiaawRRR", - [1352] = "evmwlumiaawRRR", [1353] = "evmwlsmiaawRRR", - [1363] = "evmwssfaaRRR", [1368] = "evmwumiaaRRR", - [1369] = "evmwsmiaaRRR", [1371] = "evmwsmfaaRRR", - [1408] = "evmheusianwRRR", [1409] = "evmhessianwRRR", - [1411] = "evmhessfanwRRR", [1412] = "evmhousianwRRR", - [1413] = "evmhossianwRRR", [1415] = "evmhossfanwRRR", - [1416] = "evmheumianwRRR", [1417] = "evmhesmianwRRR", - [1419] = "evmhesmfanwRRR", [1420] = "evmhoumianwRRR", - [1421] = "evmhosmianwRRR", [1423] = "evmhosmfanwRRR", - [1448] = "evmhegumianRRR", [1449] = "evmhegsmianRRR", - [1451] = "evmhegsmfanRRR", [1452] = "evmhogumianRRR", - [1453] = "evmhogsmianRRR", [1455] = "evmhogsmfanRRR", - [1472] = "evmwlusianwRRR", [1473] = "evmwlssianwRRR", - [1480] = "evmwlumianwRRR", [1481] = "evmwlsmianwRRR", - [1491] = "evmwssfanRRR", [1496] = "evmwumianRRR", - [1497] = "evmwsmianRRR", [1499] = "evmwsmfanRRR", -} - -local map_pri = { - [0] = false, false, "tdiARI", "twiARI", - map_spe, false, false, "mulliRRI", - "subficRRI", false, "cmpl_iYLRU", "cmp_iYLRI", - "addicRRI", "addic.RRI", "addi|liRR0I", "addis|lisRR0I", - "b_KBJ", "sc", "bKJ", map_crops, - "rlwimiRR~AAA.", map_rlwinm, false, "rlwnmRR~RAA.", - "oriNRR~U", "orisRR~U", "xoriRR~U", "xorisRR~U", - "andi.RR~U", "andis.RR~U", map_rld, map_ext, - "lwzRRD", "lwzuRRD", "lbzRRD", "lbzuRRD", - "stwRRD", "stwuRRD", "stbRRD", "stbuRRD", - "lhzRRD", "lhzuRRD", "lhaRRD", "lhauRRD", - "sthRRD", "sthuRRD", "lmwRRD", "stmwRRD", - "lfsFRD", "lfsuFRD", "lfdFRD", "lfduFRD", - "stfsFRD", "stfsuFRD", "stfdFRD", "stfduFRD", - false, false, map_ld, map_fps, - false, false, map_std, map_fpd, -} - ------------------------------------------------------------------------------- - -local map_gpr = { - [0] = "r0", "sp", "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", - "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", - "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", -} - -local map_cond = { [0] = "lt", "gt", "eq", "so", "ge", "le", "ne", "ns", } - --- Format a condition bit. -local function condfmt(cond) - if cond <= 3 then - return map_cond[band(cond, 3)] - else - return format("4*cr%d+%s", rshift(cond, 2), map_cond[band(cond, 3)]) - end -end - ------------------------------------------------------------------------------- - --- Output a nicely formatted line with an opcode and operands. -local function putop(ctx, text, operands) - local pos = ctx.pos - local extra = "" - if ctx.rel then - local sym = ctx.symtab[ctx.rel] - if sym then extra = "\t->"..sym end - end - if ctx.hexdump > 0 then - ctx.out(format("%08x %s %-7s %s%s\n", - ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra)) - else - ctx.out(format("%08x %-7s %s%s\n", - ctx.addr+pos, text, concat(operands, ", "), extra)) - end - ctx.pos = pos + 4 -end - --- Fallback for unknown opcodes. -local function unknown(ctx) - return putop(ctx, ".long", { "0x"..tohex(ctx.op) }) -end - --- Disassemble a single instruction. -local function disass_ins(ctx) - local pos = ctx.pos - local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) - local op = bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3) - local operands = {} - local last = nil - local rs = 21 - ctx.op = op - ctx.rel = nil - - local opat = map_pri[rshift(b0, 2)] - while type(opat) ~= "string" do - if not opat then return unknown(ctx) end - opat = opat[band(rshift(op, opat.shift), opat.mask)] - end - local name, pat = match(opat, "^([a-z0-9_.]*)(.*)") - local altname, pat2 = match(pat, "|([a-z0-9_.]*)(.*)") - if altname then pat = pat2 end - - for p in gmatch(pat, ".") do - local x = nil - if p == "R" then - x = map_gpr[band(rshift(op, rs), 31)] - rs = rs - 5 - elseif p == "F" then - x = "f"..band(rshift(op, rs), 31) - rs = rs - 5 - elseif p == "A" then - x = band(rshift(op, rs), 31) - rs = rs - 5 - elseif p == "S" then - x = arshift(lshift(op, 27-rs), 27) - rs = rs - 5 - elseif p == "I" then - x = arshift(lshift(op, 16), 16) - elseif p == "U" then - x = band(op, 0xffff) - elseif p == "D" or p == "E" then - local disp = arshift(lshift(op, 16), 16) - if p == "E" then disp = band(disp, -4) end - if last == "r0" then last = "0" end - operands[#operands] = format("%d(%s)", disp, last) - elseif p >= "2" and p <= "8" then - local disp = band(rshift(op, rs), 31) * p - if last == "r0" then last = "0" end - operands[#operands] = format("%d(%s)", disp, last) - elseif p == "H" then - x = band(rshift(op, rs), 31) + lshift(band(op, 2), 4) - rs = rs - 5 - elseif p == "M" then - x = band(rshift(op, rs), 31) + band(op, 0x20) - elseif p == "C" then - x = condfmt(band(rshift(op, rs), 31)) - rs = rs - 5 - elseif p == "B" then - local bo = rshift(op, 21) - local cond = band(rshift(op, 16), 31) - local cn = "" - rs = rs - 10 - if band(bo, 4) == 0 then - cn = band(bo, 2) == 0 and "dnz" or "dz" - if band(bo, 0x10) == 0 then - cn = cn..(band(bo, 8) == 0 and "f" or "t") - end - if band(bo, 0x10) == 0 then x = condfmt(cond) end - name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+") - elseif band(bo, 0x10) == 0 then - cn = map_cond[band(cond, 3) + (band(bo, 8) == 0 and 4 or 0)] - if cond > 3 then x = "cr"..rshift(cond, 2) end - name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+") - end - name = gsub(name, "_", cn) - elseif p == "J" then - x = arshift(lshift(op, 27-rs), 29-rs)*4 - if band(op, 2) == 0 then x = ctx.addr + pos + x end - ctx.rel = x - x = "0x"..tohex(x) - elseif p == "K" then - if band(op, 1) ~= 0 then name = name.."l" end - if band(op, 2) ~= 0 then name = name.."a" end - elseif p == "X" or p == "Y" then - x = band(rshift(op, rs+2), 7) - if x == 0 and p == "Y" then x = nil else x = "cr"..x end - rs = rs - 5 - elseif p == "W" then - x = "cr"..band(op, 7) - elseif p == "Z" then - x = band(rshift(op, rs-4), 255) - rs = rs - 10 - elseif p == ">" then - operands[#operands] = rshift(operands[#operands], 1) - elseif p == "0" then - if last == "r0" then - operands[#operands] = nil - if altname then name = altname end - end - elseif p == "L" then - name = gsub(name, "_", band(op, 0x00200000) ~= 0 and "d" or "w") - elseif p == "." then - if band(op, 1) == 1 then name = name.."." end - elseif p == "N" then - if op == 0x60000000 then name = "nop"; break end - elseif p == "~" then - local n = #operands - operands[n-1], operands[n] = operands[n], operands[n-1] - elseif p == "=" then - local n = #operands - if last == operands[n-1] then - operands[n] = nil - name = altname - end - elseif p == "%" then - local n = #operands - if last == operands[n-1] and last == operands[n-2] then - operands[n] = nil - operands[n-1] = nil - name = altname - end - elseif p == "-" then - rs = rs - 5 - else - assert(false) - end - if x then operands[#operands+1] = x; last = x end - end - - return putop(ctx, name, operands) -end - ------------------------------------------------------------------------------- - --- Disassemble a block of code. -local function disass_block(ctx, ofs, len) - if not ofs then ofs = 0 end - local stop = len and ofs+len or #ctx.code - stop = stop - stop % 4 - ctx.pos = ofs - ofs % 4 - ctx.rel = nil - while ctx.pos < stop do disass_ins(ctx) end -end - --- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). -local function create(code, addr, out) - local ctx = {} - ctx.code = code - ctx.addr = addr or 0 - ctx.out = out or io.write - ctx.symtab = {} - ctx.disass = disass_block - ctx.hexdump = 8 - return ctx -end - --- Simple API: disassemble code (a string) at address and output via out. -local function disass(code, addr, out) - create(code, addr, out):disass() -end - --- Return register name for RID. -local function regname(r) - if r < 32 then return map_gpr[r] end - return "f"..(r-32) -end - --- Public module functions. -return { - create = create, - disass = disass, - regname = regname -} - diff --git a/lib/LuaJIT/src/jit/dis_x64.lua b/lib/LuaJIT/src/jit/dis_x64.lua deleted file mode 100644 index d5714ee..0000000 --- a/lib/LuaJIT/src/jit/dis_x64.lua +++ /dev/null @@ -1,17 +0,0 @@ ----------------------------------------------------------------------------- --- LuaJIT x64 disassembler wrapper module. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- Released under the MIT license. See Copyright Notice in luajit.h ----------------------------------------------------------------------------- --- This module just exports the 64 bit functions from the combined --- x86/x64 disassembler module. All the interesting stuff is there. ------------------------------------------------------------------------------- - -local dis_x86 = require((string.match(..., ".*%.") or "").."dis_x86") -return { - create = dis_x86.create64, - disass = dis_x86.disass64, - regname = dis_x86.regname64 -} - diff --git a/lib/LuaJIT/src/jit/dis_x86.lua b/lib/LuaJIT/src/jit/dis_x86.lua deleted file mode 100644 index 3a68c93..0000000 --- a/lib/LuaJIT/src/jit/dis_x86.lua +++ /dev/null @@ -1,953 +0,0 @@ ----------------------------------------------------------------------------- --- LuaJIT x86/x64 disassembler module. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- Released under the MIT license. See Copyright Notice in luajit.h ----------------------------------------------------------------------------- --- This is a helper module used by the LuaJIT machine code dumper module. --- --- Sending small code snippets to an external disassembler and mixing the --- output with our own stuff was too fragile. So I had to bite the bullet --- and write yet another x86 disassembler. Oh well ... --- --- The output format is very similar to what ndisasm generates. But it has --- been developed independently by looking at the opcode tables from the --- Intel and AMD manuals. The supported instruction set is quite extensive --- and reflects what a current generation Intel or AMD CPU implements in --- 32 bit and 64 bit mode. Yes, this includes MMX, SSE, SSE2, SSE3, SSSE3, --- SSE4.1, SSE4.2, SSE4a, AVX, AVX2 and even privileged and hypervisor --- (VMX/SVM) instructions. --- --- Notes: --- * The (useless) a16 prefix, 3DNow and pre-586 opcodes are unsupported. --- * No attempt at optimization has been made -- it's fast enough for my needs. ------------------------------------------------------------------------------- - -local type = type -local sub, byte, format = string.sub, string.byte, string.format -local match, gmatch, gsub = string.match, string.gmatch, string.gsub -local lower, rep = string.lower, string.rep -local bit = require("bit") -local tohex = bit.tohex - --- Map for 1st opcode byte in 32 bit mode. Ugly? Well ... read on. -local map_opc1_32 = { ---0x -[0]="addBmr","addVmr","addBrm","addVrm","addBai","addVai","push es","pop es", -"orBmr","orVmr","orBrm","orVrm","orBai","orVai","push cs","opc2*", ---1x -"adcBmr","adcVmr","adcBrm","adcVrm","adcBai","adcVai","push ss","pop ss", -"sbbBmr","sbbVmr","sbbBrm","sbbVrm","sbbBai","sbbVai","push ds","pop ds", ---2x -"andBmr","andVmr","andBrm","andVrm","andBai","andVai","es:seg","daa", -"subBmr","subVmr","subBrm","subVrm","subBai","subVai","cs:seg","das", ---3x -"xorBmr","xorVmr","xorBrm","xorVrm","xorBai","xorVai","ss:seg","aaa", -"cmpBmr","cmpVmr","cmpBrm","cmpVrm","cmpBai","cmpVai","ds:seg","aas", ---4x -"incVR","incVR","incVR","incVR","incVR","incVR","incVR","incVR", -"decVR","decVR","decVR","decVR","decVR","decVR","decVR","decVR", ---5x -"pushUR","pushUR","pushUR","pushUR","pushUR","pushUR","pushUR","pushUR", -"popUR","popUR","popUR","popUR","popUR","popUR","popUR","popUR", ---6x -"sz*pushaw,pusha","sz*popaw,popa","boundVrm","arplWmr", -"fs:seg","gs:seg","o16:","a16", -"pushUi","imulVrmi","pushBs","imulVrms", -"insb","insVS","outsb","outsVS", ---7x -"joBj","jnoBj","jbBj","jnbBj","jzBj","jnzBj","jbeBj","jaBj", -"jsBj","jnsBj","jpeBj","jpoBj","jlBj","jgeBj","jleBj","jgBj", ---8x -"arith!Bmi","arith!Vmi","arith!Bmi","arith!Vms", -"testBmr","testVmr","xchgBrm","xchgVrm", -"movBmr","movVmr","movBrm","movVrm", -"movVmg","leaVrm","movWgm","popUm", ---9x -"nop*xchgVaR|pause|xchgWaR|repne nop","xchgVaR","xchgVaR","xchgVaR", -"xchgVaR","xchgVaR","xchgVaR","xchgVaR", -"sz*cbw,cwde,cdqe","sz*cwd,cdq,cqo","call farViw","wait", -"sz*pushfw,pushf","sz*popfw,popf","sahf","lahf", ---Ax -"movBao","movVao","movBoa","movVoa", -"movsb","movsVS","cmpsb","cmpsVS", -"testBai","testVai","stosb","stosVS", -"lodsb","lodsVS","scasb","scasVS", ---Bx -"movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi", -"movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI", ---Cx -"shift!Bmu","shift!Vmu","retBw","ret","vex*3$lesVrm","vex*2$ldsVrm","movBmi","movVmi", -"enterBwu","leave","retfBw","retf","int3","intBu","into","iretVS", ---Dx -"shift!Bm1","shift!Vm1","shift!Bmc","shift!Vmc","aamBu","aadBu","salc","xlatb", -"fp*0","fp*1","fp*2","fp*3","fp*4","fp*5","fp*6","fp*7", ---Ex -"loopneBj","loopeBj","loopBj","sz*jcxzBj,jecxzBj,jrcxzBj", -"inBau","inVau","outBua","outVua", -"callVj","jmpVj","jmp farViw","jmpBj","inBad","inVad","outBda","outVda", ---Fx -"lock:","int1","repne:rep","rep:","hlt","cmc","testb!Bm","testv!Vm", -"clc","stc","cli","sti","cld","std","incb!Bm","incd!Vm", -} -assert(#map_opc1_32 == 255) - --- Map for 1st opcode byte in 64 bit mode (overrides only). -local map_opc1_64 = setmetatable({ - [0x06]=false, [0x07]=false, [0x0e]=false, - [0x16]=false, [0x17]=false, [0x1e]=false, [0x1f]=false, - [0x27]=false, [0x2f]=false, [0x37]=false, [0x3f]=false, - [0x60]=false, [0x61]=false, [0x62]=false, [0x63]="movsxdVrDmt", [0x67]="a32:", - [0x40]="rex*", [0x41]="rex*b", [0x42]="rex*x", [0x43]="rex*xb", - [0x44]="rex*r", [0x45]="rex*rb", [0x46]="rex*rx", [0x47]="rex*rxb", - [0x48]="rex*w", [0x49]="rex*wb", [0x4a]="rex*wx", [0x4b]="rex*wxb", - [0x4c]="rex*wr", [0x4d]="rex*wrb", [0x4e]="rex*wrx", [0x4f]="rex*wrxb", - [0x82]=false, [0x9a]=false, [0xc4]="vex*3", [0xc5]="vex*2", [0xce]=false, - [0xd4]=false, [0xd5]=false, [0xd6]=false, [0xea]=false, -}, { __index = map_opc1_32 }) - --- Map for 2nd opcode byte (0F xx). True CISC hell. Hey, I told you. --- Prefix dependent MMX/SSE opcodes: (none)|rep|o16|repne, -|F3|66|F2 -local map_opc2 = { ---0x -[0]="sldt!Dmp","sgdt!Ump","larVrm","lslVrm",nil,"syscall","clts","sysret", -"invd","wbinvd",nil,"ud1",nil,"$prefetch!Bm","femms","3dnowMrmu", ---1x -"movupsXrm|movssXrvm|movupdXrm|movsdXrvm", -"movupsXmr|movssXmvr|movupdXmr|movsdXmvr", -"movhlpsXrm$movlpsXrm|movsldupXrm|movlpdXrm|movddupXrm", -"movlpsXmr||movlpdXmr", -"unpcklpsXrvm||unpcklpdXrvm", -"unpckhpsXrvm||unpckhpdXrvm", -"movlhpsXrm$movhpsXrm|movshdupXrm|movhpdXrm", -"movhpsXmr||movhpdXmr", -"$prefetcht!Bm","hintnopVm","hintnopVm","hintnopVm", -"hintnopVm","hintnopVm","hintnopVm","hintnopVm", ---2x -"movUmx$","movUmy$","movUxm$","movUym$","movUmz$",nil,"movUzm$",nil, -"movapsXrm||movapdXrm", -"movapsXmr||movapdXmr", -"cvtpi2psXrMm|cvtsi2ssXrvVmt|cvtpi2pdXrMm|cvtsi2sdXrvVmt", -"movntpsXmr|movntssXmr|movntpdXmr|movntsdXmr", -"cvttps2piMrXm|cvttss2siVrXm|cvttpd2piMrXm|cvttsd2siVrXm", -"cvtps2piMrXm|cvtss2siVrXm|cvtpd2piMrXm|cvtsd2siVrXm", -"ucomissXrm||ucomisdXrm", -"comissXrm||comisdXrm", ---3x -"wrmsr","rdtsc","rdmsr","rdpmc","sysenter","sysexit",nil,"getsec", -"opc3*38",nil,"opc3*3a",nil,nil,nil,nil,nil, ---4x -"cmovoVrm","cmovnoVrm","cmovbVrm","cmovnbVrm", -"cmovzVrm","cmovnzVrm","cmovbeVrm","cmovaVrm", -"cmovsVrm","cmovnsVrm","cmovpeVrm","cmovpoVrm", -"cmovlVrm","cmovgeVrm","cmovleVrm","cmovgVrm", ---5x -"movmskpsVrXm$||movmskpdVrXm$","sqrtpsXrm|sqrtssXrm|sqrtpdXrm|sqrtsdXrm", -"rsqrtpsXrm|rsqrtssXrvm","rcppsXrm|rcpssXrvm", -"andpsXrvm||andpdXrvm","andnpsXrvm||andnpdXrvm", -"orpsXrvm||orpdXrvm","xorpsXrvm||xorpdXrvm", -"addpsXrvm|addssXrvm|addpdXrvm|addsdXrvm","mulpsXrvm|mulssXrvm|mulpdXrvm|mulsdXrvm", -"cvtps2pdXrm|cvtss2sdXrvm|cvtpd2psXrm|cvtsd2ssXrvm", -"cvtdq2psXrm|cvttps2dqXrm|cvtps2dqXrm", -"subpsXrvm|subssXrvm|subpdXrvm|subsdXrvm","minpsXrvm|minssXrvm|minpdXrvm|minsdXrvm", -"divpsXrvm|divssXrvm|divpdXrvm|divsdXrvm","maxpsXrvm|maxssXrvm|maxpdXrvm|maxsdXrvm", ---6x -"punpcklbwPrvm","punpcklwdPrvm","punpckldqPrvm","packsswbPrvm", -"pcmpgtbPrvm","pcmpgtwPrvm","pcmpgtdPrvm","packuswbPrvm", -"punpckhbwPrvm","punpckhwdPrvm","punpckhdqPrvm","packssdwPrvm", -"||punpcklqdqXrvm","||punpckhqdqXrvm", -"movPrVSm","movqMrm|movdquXrm|movdqaXrm", ---7x -"pshufwMrmu|pshufhwXrmu|pshufdXrmu|pshuflwXrmu","pshiftw!Pvmu", -"pshiftd!Pvmu","pshiftq!Mvmu||pshiftdq!Xvmu", -"pcmpeqbPrvm","pcmpeqwPrvm","pcmpeqdPrvm","emms*|", -"vmreadUmr||extrqXmuu$|insertqXrmuu$","vmwriteUrm||extrqXrm$|insertqXrm$", -nil,nil, -"||haddpdXrvm|haddpsXrvm","||hsubpdXrvm|hsubpsXrvm", -"movVSmMr|movqXrm|movVSmXr","movqMmr|movdquXmr|movdqaXmr", ---8x -"joVj","jnoVj","jbVj","jnbVj","jzVj","jnzVj","jbeVj","jaVj", -"jsVj","jnsVj","jpeVj","jpoVj","jlVj","jgeVj","jleVj","jgVj", ---9x -"setoBm","setnoBm","setbBm","setnbBm","setzBm","setnzBm","setbeBm","setaBm", -"setsBm","setnsBm","setpeBm","setpoBm","setlBm","setgeBm","setleBm","setgBm", ---Ax -"push fs","pop fs","cpuid","btVmr","shldVmru","shldVmrc",nil,nil, -"push gs","pop gs","rsm","btsVmr","shrdVmru","shrdVmrc","fxsave!Dmp","imulVrm", ---Bx -"cmpxchgBmr","cmpxchgVmr","$lssVrm","btrVmr", -"$lfsVrm","$lgsVrm","movzxVrBmt","movzxVrWmt", -"|popcntVrm","ud2Dp","bt!Vmu","btcVmr", -"bsfVrm","bsrVrm|lzcntVrm|bsrWrm","movsxVrBmt","movsxVrWmt", ---Cx -"xaddBmr","xaddVmr", -"cmppsXrvmu|cmpssXrvmu|cmppdXrvmu|cmpsdXrvmu","$movntiVmr|", -"pinsrwPrvWmu","pextrwDrPmu", -"shufpsXrvmu||shufpdXrvmu","$cmpxchg!Qmp", -"bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR", ---Dx -"||addsubpdXrvm|addsubpsXrvm","psrlwPrvm","psrldPrvm","psrlqPrvm", -"paddqPrvm","pmullwPrvm", -"|movq2dqXrMm|movqXmr|movdq2qMrXm$","pmovmskbVrMm||pmovmskbVrXm", -"psubusbPrvm","psubuswPrvm","pminubPrvm","pandPrvm", -"paddusbPrvm","padduswPrvm","pmaxubPrvm","pandnPrvm", ---Ex -"pavgbPrvm","psrawPrvm","psradPrvm","pavgwPrvm", -"pmulhuwPrvm","pmulhwPrvm", -"|cvtdq2pdXrm|cvttpd2dqXrm|cvtpd2dqXrm","$movntqMmr||$movntdqXmr", -"psubsbPrvm","psubswPrvm","pminswPrvm","porPrvm", -"paddsbPrvm","paddswPrvm","pmaxswPrvm","pxorPrvm", ---Fx -"|||lddquXrm","psllwPrvm","pslldPrvm","psllqPrvm", -"pmuludqPrvm","pmaddwdPrvm","psadbwPrvm","maskmovqMrm||maskmovdquXrm$", -"psubbPrvm","psubwPrvm","psubdPrvm","psubqPrvm", -"paddbPrvm","paddwPrvm","padddPrvm","ud", -} -assert(map_opc2[255] == "ud") - --- Map for three-byte opcodes. Can't wait for their next invention. -local map_opc3 = { -["38"] = { -- [66] 0f 38 xx ---0x -[0]="pshufbPrvm","phaddwPrvm","phadddPrvm","phaddswPrvm", -"pmaddubswPrvm","phsubwPrvm","phsubdPrvm","phsubswPrvm", -"psignbPrvm","psignwPrvm","psigndPrvm","pmulhrswPrvm", -"||permilpsXrvm","||permilpdXrvm",nil,nil, ---1x -"||pblendvbXrma",nil,nil,nil, -"||blendvpsXrma","||blendvpdXrma","||permpsXrvm","||ptestXrm", -"||broadcastssXrm","||broadcastsdXrm","||broadcastf128XrlXm",nil, -"pabsbPrm","pabswPrm","pabsdPrm",nil, ---2x -"||pmovsxbwXrm","||pmovsxbdXrm","||pmovsxbqXrm","||pmovsxwdXrm", -"||pmovsxwqXrm","||pmovsxdqXrm",nil,nil, -"||pmuldqXrvm","||pcmpeqqXrvm","||$movntdqaXrm","||packusdwXrvm", -"||maskmovpsXrvm","||maskmovpdXrvm","||maskmovpsXmvr","||maskmovpdXmvr", ---3x -"||pmovzxbwXrm","||pmovzxbdXrm","||pmovzxbqXrm","||pmovzxwdXrm", -"||pmovzxwqXrm","||pmovzxdqXrm","||permdXrvm","||pcmpgtqXrvm", -"||pminsbXrvm","||pminsdXrvm","||pminuwXrvm","||pminudXrvm", -"||pmaxsbXrvm","||pmaxsdXrvm","||pmaxuwXrvm","||pmaxudXrvm", ---4x -"||pmulddXrvm","||phminposuwXrm",nil,nil, -nil,"||psrlvVSXrvm","||psravdXrvm","||psllvVSXrvm", ---5x -[0x58] = "||pbroadcastdXrlXm",[0x59] = "||pbroadcastqXrlXm", -[0x5a] = "||broadcasti128XrlXm", ---7x -[0x78] = "||pbroadcastbXrlXm",[0x79] = "||pbroadcastwXrlXm", ---8x -[0x8c] = "||pmaskmovXrvVSm", -[0x8e] = "||pmaskmovVSmXvr", ---9x -[0x96] = "||fmaddsub132pHXrvm",[0x97] = "||fmsubadd132pHXrvm", -[0x98] = "||fmadd132pHXrvm",[0x99] = "||fmadd132sHXrvm", -[0x9a] = "||fmsub132pHXrvm",[0x9b] = "||fmsub132sHXrvm", -[0x9c] = "||fnmadd132pHXrvm",[0x9d] = "||fnmadd132sHXrvm", -[0x9e] = "||fnmsub132pHXrvm",[0x9f] = "||fnmsub132sHXrvm", ---Ax -[0xa6] = "||fmaddsub213pHXrvm",[0xa7] = "||fmsubadd213pHXrvm", -[0xa8] = "||fmadd213pHXrvm",[0xa9] = "||fmadd213sHXrvm", -[0xaa] = "||fmsub213pHXrvm",[0xab] = "||fmsub213sHXrvm", -[0xac] = "||fnmadd213pHXrvm",[0xad] = "||fnmadd213sHXrvm", -[0xae] = "||fnmsub213pHXrvm",[0xaf] = "||fnmsub213sHXrvm", ---Bx -[0xb6] = "||fmaddsub231pHXrvm",[0xb7] = "||fmsubadd231pHXrvm", -[0xb8] = "||fmadd231pHXrvm",[0xb9] = "||fmadd231sHXrvm", -[0xba] = "||fmsub231pHXrvm",[0xbb] = "||fmsub231sHXrvm", -[0xbc] = "||fnmadd231pHXrvm",[0xbd] = "||fnmadd231sHXrvm", -[0xbe] = "||fnmsub231pHXrvm",[0xbf] = "||fnmsub231sHXrvm", ---Dx -[0xdc] = "||aesencXrvm", [0xdd] = "||aesenclastXrvm", -[0xde] = "||aesdecXrvm", [0xdf] = "||aesdeclastXrvm", ---Fx -[0xf0] = "|||crc32TrBmt",[0xf1] = "|||crc32TrVmt", -[0xf7] = "| sarxVrmv| shlxVrmv| shrxVrmv", -}, - -["3a"] = { -- [66] 0f 3a xx ---0x -[0x00]="||permqXrmu","||permpdXrmu","||pblenddXrvmu",nil, -"||permilpsXrmu","||permilpdXrmu","||perm2f128Xrvmu",nil, -"||roundpsXrmu","||roundpdXrmu","||roundssXrvmu","||roundsdXrvmu", -"||blendpsXrvmu","||blendpdXrvmu","||pblendwXrvmu","palignrPrvmu", ---1x -nil,nil,nil,nil, -"||pextrbVmXru","||pextrwVmXru","||pextrVmSXru","||extractpsVmXru", -"||insertf128XrvlXmu","||extractf128XlXmYru",nil,nil, -nil,nil,nil,nil, ---2x -"||pinsrbXrvVmu","||insertpsXrvmu","||pinsrXrvVmuS",nil, ---3x -[0x38] = "||inserti128Xrvmu",[0x39] = "||extracti128XlXmYru", ---4x -[0x40] = "||dppsXrvmu", -[0x41] = "||dppdXrvmu", -[0x42] = "||mpsadbwXrvmu", -[0x44] = "||pclmulqdqXrvmu", -[0x46] = "||perm2i128Xrvmu", -[0x4a] = "||blendvpsXrvmb",[0x4b] = "||blendvpdXrvmb", -[0x4c] = "||pblendvbXrvmb", ---6x -[0x60] = "||pcmpestrmXrmu",[0x61] = "||pcmpestriXrmu", -[0x62] = "||pcmpistrmXrmu",[0x63] = "||pcmpistriXrmu", -[0xdf] = "||aeskeygenassistXrmu", ---Fx -[0xf0] = "||| rorxVrmu", -}, -} - --- Map for VMX/SVM opcodes 0F 01 C0-FF (sgdt group with register operands). -local map_opcvm = { -[0xc1]="vmcall",[0xc2]="vmlaunch",[0xc3]="vmresume",[0xc4]="vmxoff", -[0xc8]="monitor",[0xc9]="mwait", -[0xd8]="vmrun",[0xd9]="vmmcall",[0xda]="vmload",[0xdb]="vmsave", -[0xdc]="stgi",[0xdd]="clgi",[0xde]="skinit",[0xdf]="invlpga", -[0xf8]="swapgs",[0xf9]="rdtscp", -} - --- Map for FP opcodes. And you thought stack machines are simple? -local map_opcfp = { --- D8-DF 00-BF: opcodes with a memory operand. --- D8 -[0]="faddFm","fmulFm","fcomFm","fcompFm","fsubFm","fsubrFm","fdivFm","fdivrFm", -"fldFm",nil,"fstFm","fstpFm","fldenvVm","fldcwWm","fnstenvVm","fnstcwWm", --- DA -"fiaddDm","fimulDm","ficomDm","ficompDm", -"fisubDm","fisubrDm","fidivDm","fidivrDm", --- DB -"fildDm","fisttpDm","fistDm","fistpDm",nil,"fld twordFmp",nil,"fstp twordFmp", --- DC -"faddGm","fmulGm","fcomGm","fcompGm","fsubGm","fsubrGm","fdivGm","fdivrGm", --- DD -"fldGm","fisttpQm","fstGm","fstpGm","frstorDmp",nil,"fnsaveDmp","fnstswWm", --- DE -"fiaddWm","fimulWm","ficomWm","ficompWm", -"fisubWm","fisubrWm","fidivWm","fidivrWm", --- DF -"fildWm","fisttpWm","fistWm","fistpWm", -"fbld twordFmp","fildQm","fbstp twordFmp","fistpQm", --- xx C0-FF: opcodes with a pseudo-register operand. --- D8 -"faddFf","fmulFf","fcomFf","fcompFf","fsubFf","fsubrFf","fdivFf","fdivrFf", --- D9 -"fldFf","fxchFf",{"fnop"},nil, -{"fchs","fabs",nil,nil,"ftst","fxam"}, -{"fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz"}, -{"f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp"}, -{"fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos"}, --- DA -"fcmovbFf","fcmoveFf","fcmovbeFf","fcmovuFf",nil,{nil,"fucompp"},nil,nil, --- DB -"fcmovnbFf","fcmovneFf","fcmovnbeFf","fcmovnuFf", -{nil,nil,"fnclex","fninit"},"fucomiFf","fcomiFf",nil, --- DC -"fadd toFf","fmul toFf",nil,nil, -"fsub toFf","fsubr toFf","fdivr toFf","fdiv toFf", --- DD -"ffreeFf",nil,"fstFf","fstpFf","fucomFf","fucompFf",nil,nil, --- DE -"faddpFf","fmulpFf",nil,{nil,"fcompp"}, -"fsubrpFf","fsubpFf","fdivrpFf","fdivpFf", --- DF -nil,nil,nil,nil,{"fnstsw ax"},"fucomipFf","fcomipFf",nil, -} -assert(map_opcfp[126] == "fcomipFf") - --- Map for opcode groups. The subkey is sp from the ModRM byte. -local map_opcgroup = { - arith = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" }, - shift = { "rol", "ror", "rcl", "rcr", "shl", "shr", "sal", "sar" }, - testb = { "testBmi", "testBmi", "not", "neg", "mul", "imul", "div", "idiv" }, - testv = { "testVmi", "testVmi", "not", "neg", "mul", "imul", "div", "idiv" }, - incb = { "inc", "dec" }, - incd = { "inc", "dec", "callUmp", "$call farDmp", - "jmpUmp", "$jmp farDmp", "pushUm" }, - sldt = { "sldt", "str", "lldt", "ltr", "verr", "verw" }, - sgdt = { "vm*$sgdt", "vm*$sidt", "$lgdt", "vm*$lidt", - "smsw", nil, "lmsw", "vm*$invlpg" }, - bt = { nil, nil, nil, nil, "bt", "bts", "btr", "btc" }, - cmpxchg = { nil, "sz*,cmpxchg8bQmp,cmpxchg16bXmp", nil, nil, - nil, nil, "vmptrld|vmxon|vmclear", "vmptrst" }, - pshiftw = { nil, nil, "psrlw", nil, "psraw", nil, "psllw" }, - pshiftd = { nil, nil, "psrld", nil, "psrad", nil, "pslld" }, - pshiftq = { nil, nil, "psrlq", nil, nil, nil, "psllq" }, - pshiftdq = { nil, nil, "psrlq", "psrldq", nil, nil, "psllq", "pslldq" }, - fxsave = { "$fxsave", "$fxrstor", "$ldmxcsr", "$stmxcsr", - nil, "lfenceDp$", "mfenceDp$", "sfenceDp$clflush" }, - prefetch = { "prefetch", "prefetchw" }, - prefetcht = { "prefetchnta", "prefetcht0", "prefetcht1", "prefetcht2" }, -} - ------------------------------------------------------------------------------- - --- Maps for register names. -local map_regs = { - B = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", - "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" }, - B64 = { "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", - "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" }, - W = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", - "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" }, - D = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", - "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" }, - Q = { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" }, - M = { "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", - "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" }, -- No x64 ext! - X = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", - "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" }, - Y = { "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", - "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15" }, -} -local map_segregs = { "es", "cs", "ss", "ds", "fs", "gs", "segr6", "segr7" } - --- Maps for size names. -local map_sz2n = { - B = 1, W = 2, D = 4, Q = 8, M = 8, X = 16, Y = 32, -} -local map_sz2prefix = { - B = "byte", W = "word", D = "dword", - Q = "qword", - M = "qword", X = "xword", Y = "yword", - F = "dword", G = "qword", -- No need for sizes/register names for these two. -} - ------------------------------------------------------------------------------- - --- Output a nicely formatted line with an opcode and operands. -local function putop(ctx, text, operands) - local code, pos, hex = ctx.code, ctx.pos, "" - local hmax = ctx.hexdump - if hmax > 0 then - for i=ctx.start,pos-1 do - hex = hex..format("%02X", byte(code, i, i)) - end - if #hex > hmax then hex = sub(hex, 1, hmax)..". " - else hex = hex..rep(" ", hmax-#hex+2) end - end - if operands then text = text.." "..operands end - if ctx.o16 then text = "o16 "..text; ctx.o16 = false end - if ctx.a32 then text = "a32 "..text; ctx.a32 = false end - if ctx.rep then text = ctx.rep.." "..text; ctx.rep = false end - if ctx.rex then - local t = (ctx.rexw and "w" or "")..(ctx.rexr and "r" or "").. - (ctx.rexx and "x" or "")..(ctx.rexb and "b" or "").. - (ctx.vexl and "l" or "") - if ctx.vexv and ctx.vexv ~= 0 then t = t.."v"..ctx.vexv end - if t ~= "" then text = ctx.rex.."."..t.." "..gsub(text, "^ ", "") - elseif ctx.rex == "vex" then text = gsub("v"..text, "^v ", "") end - ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false - ctx.rex = false; ctx.vexl = false; ctx.vexv = false - end - if ctx.seg then - local text2, n = gsub(text, "%[", "["..ctx.seg..":") - if n == 0 then text = ctx.seg.." "..text else text = text2 end - ctx.seg = false - end - if ctx.lock then text = "lock "..text; ctx.lock = false end - local imm = ctx.imm - if imm then - local sym = ctx.symtab[imm] - if sym then text = text.."\t->"..sym end - end - ctx.out(format("%08x %s%s\n", ctx.addr+ctx.start, hex, text)) - ctx.mrm = false - ctx.vexv = false - ctx.start = pos - ctx.imm = nil -end - --- Clear all prefix flags. -local function clearprefixes(ctx) - ctx.o16 = false; ctx.seg = false; ctx.lock = false; ctx.rep = false - ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false - ctx.rex = false; ctx.a32 = false; ctx.vexl = false -end - --- Fallback for incomplete opcodes at the end. -local function incomplete(ctx) - ctx.pos = ctx.stop+1 - clearprefixes(ctx) - return putop(ctx, "(incomplete)") -end - --- Fallback for unknown opcodes. -local function unknown(ctx) - clearprefixes(ctx) - return putop(ctx, "(unknown)") -end - --- Return an immediate of the specified size. -local function getimm(ctx, pos, n) - if pos+n-1 > ctx.stop then return incomplete(ctx) end - local code = ctx.code - if n == 1 then - local b1 = byte(code, pos, pos) - return b1 - elseif n == 2 then - local b1, b2 = byte(code, pos, pos+1) - return b1+b2*256 - else - local b1, b2, b3, b4 = byte(code, pos, pos+3) - local imm = b1+b2*256+b3*65536+b4*16777216 - ctx.imm = imm - return imm - end -end - --- Process pattern string and generate the operands. -local function putpat(ctx, name, pat) - local operands, regs, sz, mode, sp, rm, sc, rx, sdisp - local code, pos, stop, vexl = ctx.code, ctx.pos, ctx.stop, ctx.vexl - - -- Chars used: 1DFGHIMPQRSTUVWXYabcdfgijlmoprstuvwxyz - for p in gmatch(pat, ".") do - local x = nil - if p == "V" or p == "U" then - if ctx.rexw then sz = "Q"; ctx.rexw = false - elseif ctx.o16 then sz = "W"; ctx.o16 = false - elseif p == "U" and ctx.x64 then sz = "Q" - else sz = "D" end - regs = map_regs[sz] - elseif p == "T" then - if ctx.rexw then sz = "Q"; ctx.rexw = false else sz = "D" end - regs = map_regs[sz] - elseif p == "B" then - sz = "B" - regs = ctx.rex and map_regs.B64 or map_regs.B - elseif match(p, "[WDQMXYFG]") then - sz = p - if sz == "X" and vexl then sz = "Y"; ctx.vexl = false end - regs = map_regs[sz] - elseif p == "P" then - sz = ctx.o16 and "X" or "M"; ctx.o16 = false - if sz == "X" and vexl then sz = "Y"; ctx.vexl = false end - regs = map_regs[sz] - elseif p == "H" then - name = name..(ctx.rexw and "d" or "s") - ctx.rexw = false - elseif p == "S" then - name = name..lower(sz) - elseif p == "s" then - local imm = getimm(ctx, pos, 1); if not imm then return end - x = imm <= 127 and format("+0x%02x", imm) - or format("-0x%02x", 256-imm) - pos = pos+1 - elseif p == "u" then - local imm = getimm(ctx, pos, 1); if not imm then return end - x = format("0x%02x", imm) - pos = pos+1 - elseif p == "b" then - local imm = getimm(ctx, pos, 1); if not imm then return end - x = regs[imm/16+1] - pos = pos+1 - elseif p == "w" then - local imm = getimm(ctx, pos, 2); if not imm then return end - x = format("0x%x", imm) - pos = pos+2 - elseif p == "o" then -- [offset] - if ctx.x64 then - local imm1 = getimm(ctx, pos, 4); if not imm1 then return end - local imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end - x = format("[0x%08x%08x]", imm2, imm1) - pos = pos+8 - else - local imm = getimm(ctx, pos, 4); if not imm then return end - x = format("[0x%08x]", imm) - pos = pos+4 - end - elseif p == "i" or p == "I" then - local n = map_sz2n[sz] - if n == 8 and ctx.x64 and p == "I" then - local imm1 = getimm(ctx, pos, 4); if not imm1 then return end - local imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end - x = format("0x%08x%08x", imm2, imm1) - else - if n == 8 then n = 4 end - local imm = getimm(ctx, pos, n); if not imm then return end - if sz == "Q" and (imm < 0 or imm > 0x7fffffff) then - imm = (0xffffffff+1)-imm - x = format(imm > 65535 and "-0x%08x" or "-0x%x", imm) - else - x = format(imm > 65535 and "0x%08x" or "0x%x", imm) - end - end - pos = pos+n - elseif p == "j" then - local n = map_sz2n[sz] - if n == 8 then n = 4 end - local imm = getimm(ctx, pos, n); if not imm then return end - if sz == "B" and imm > 127 then imm = imm-256 - elseif imm > 2147483647 then imm = imm-4294967296 end - pos = pos+n - imm = imm + pos + ctx.addr - if imm > 4294967295 and not ctx.x64 then imm = imm-4294967296 end - ctx.imm = imm - if sz == "W" then - x = format("word 0x%04x", imm%65536) - elseif ctx.x64 then - local lo = imm % 0x1000000 - x = format("0x%02x%06x", (imm-lo) / 0x1000000, lo) - else - x = "0x"..tohex(imm) - end - elseif p == "R" then - local r = byte(code, pos-1, pos-1)%8 - if ctx.rexb then r = r + 8; ctx.rexb = false end - x = regs[r+1] - elseif p == "a" then x = regs[1] - elseif p == "c" then x = "cl" - elseif p == "d" then x = "dx" - elseif p == "1" then x = "1" - else - if not mode then - mode = ctx.mrm - if not mode then - if pos > stop then return incomplete(ctx) end - mode = byte(code, pos, pos) - pos = pos+1 - end - rm = mode%8; mode = (mode-rm)/8 - sp = mode%8; mode = (mode-sp)/8 - sdisp = "" - if mode < 3 then - if rm == 4 then - if pos > stop then return incomplete(ctx) end - sc = byte(code, pos, pos) - pos = pos+1 - rm = sc%8; sc = (sc-rm)/8 - rx = sc%8; sc = (sc-rx)/8 - if ctx.rexx then rx = rx + 8; ctx.rexx = false end - if rx == 4 then rx = nil end - end - if mode > 0 or rm == 5 then - local dsz = mode - if dsz ~= 1 then dsz = 4 end - local disp = getimm(ctx, pos, dsz); if not disp then return end - if mode == 0 then rm = nil end - if rm or rx or (not sc and ctx.x64 and not ctx.a32) then - if dsz == 1 and disp > 127 then - sdisp = format("-0x%x", 256-disp) - elseif disp >= 0 and disp <= 0x7fffffff then - sdisp = format("+0x%x", disp) - else - sdisp = format("-0x%x", (0xffffffff+1)-disp) - end - else - sdisp = format(ctx.x64 and not ctx.a32 and - not (disp >= 0 and disp <= 0x7fffffff) - and "0xffffffff%08x" or "0x%08x", disp) - end - pos = pos+dsz - end - end - if rm and ctx.rexb then rm = rm + 8; ctx.rexb = false end - if ctx.rexr then sp = sp + 8; ctx.rexr = false end - end - if p == "m" then - if mode == 3 then x = regs[rm+1] - else - local aregs = ctx.a32 and map_regs.D or ctx.aregs - local srm, srx = "", "" - if rm then srm = aregs[rm+1] - elseif not sc and ctx.x64 and not ctx.a32 then srm = "rip" end - ctx.a32 = false - if rx then - if rm then srm = srm.."+" end - srx = aregs[rx+1] - if sc > 0 then srx = srx.."*"..(2^sc) end - end - x = format("[%s%s%s]", srm, srx, sdisp) - end - if mode < 3 and - (not match(pat, "[aRrgp]") or match(pat, "t")) then -- Yuck. - x = map_sz2prefix[sz].." "..x - end - elseif p == "r" then x = regs[sp+1] - elseif p == "g" then x = map_segregs[sp+1] - elseif p == "p" then -- Suppress prefix. - elseif p == "f" then x = "st"..rm - elseif p == "x" then - if sp == 0 and ctx.lock and not ctx.x64 then - x = "CR8"; ctx.lock = false - else - x = "CR"..sp - end - elseif p == "v" then - if ctx.vexv then - x = regs[ctx.vexv+1]; ctx.vexv = false - end - elseif p == "y" then x = "DR"..sp - elseif p == "z" then x = "TR"..sp - elseif p == "l" then vexl = false - elseif p == "t" then - else - error("bad pattern `"..pat.."'") - end - end - if x then operands = operands and operands..", "..x or x end - end - ctx.pos = pos - return putop(ctx, name, operands) -end - --- Forward declaration. -local map_act - --- Fetch and cache MRM byte. -local function getmrm(ctx) - local mrm = ctx.mrm - if not mrm then - local pos = ctx.pos - if pos > ctx.stop then return nil end - mrm = byte(ctx.code, pos, pos) - ctx.pos = pos+1 - ctx.mrm = mrm - end - return mrm -end - --- Dispatch to handler depending on pattern. -local function dispatch(ctx, opat, patgrp) - if not opat then return unknown(ctx) end - if match(opat, "%|") then -- MMX/SSE variants depending on prefix. - local p - if ctx.rep then - p = ctx.rep=="rep" and "%|([^%|]*)" or "%|[^%|]*%|[^%|]*%|([^%|]*)" - ctx.rep = false - elseif ctx.o16 then p = "%|[^%|]*%|([^%|]*)"; ctx.o16 = false - else p = "^[^%|]*" end - opat = match(opat, p) - if not opat then return unknown(ctx) end --- ctx.rep = false; ctx.o16 = false - --XXX fails for 66 f2 0f 38 f1 06 crc32 eax,WORD PTR [esi] - --XXX remove in branches? - end - if match(opat, "%$") then -- reg$mem variants. - local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end - opat = match(opat, mrm >= 192 and "^[^%$]*" or "%$(.*)") - if opat == "" then return unknown(ctx) end - end - if opat == "" then return unknown(ctx) end - local name, pat = match(opat, "^([a-z0-9 ]*)(.*)") - if pat == "" and patgrp then pat = patgrp end - return map_act[sub(pat, 1, 1)](ctx, name, pat) -end - --- Get a pattern from an opcode map and dispatch to handler. -local function dispatchmap(ctx, opcmap) - local pos = ctx.pos - local opat = opcmap[byte(ctx.code, pos, pos)] - pos = pos + 1 - ctx.pos = pos - return dispatch(ctx, opat) -end - --- Map for action codes. The key is the first char after the name. -map_act = { - -- Simple opcodes without operands. - [""] = function(ctx, name, pat) - return putop(ctx, name) - end, - - -- Operand size chars fall right through. - B = putpat, W = putpat, D = putpat, Q = putpat, - V = putpat, U = putpat, T = putpat, - M = putpat, X = putpat, P = putpat, - F = putpat, G = putpat, Y = putpat, - H = putpat, - - -- Collect prefixes. - [":"] = function(ctx, name, pat) - ctx[pat == ":" and name or sub(pat, 2)] = name - if ctx.pos - ctx.start > 5 then return unknown(ctx) end -- Limit #prefixes. - end, - - -- Chain to special handler specified by name. - ["*"] = function(ctx, name, pat) - return map_act[name](ctx, name, sub(pat, 2)) - end, - - -- Use named subtable for opcode group. - ["!"] = function(ctx, name, pat) - local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end - return dispatch(ctx, map_opcgroup[name][((mrm-(mrm%8))/8)%8+1], sub(pat, 2)) - end, - - -- o16,o32[,o64] variants. - sz = function(ctx, name, pat) - if ctx.o16 then ctx.o16 = false - else - pat = match(pat, ",(.*)") - if ctx.rexw then - local p = match(pat, ",(.*)") - if p then pat = p; ctx.rexw = false end - end - end - pat = match(pat, "^[^,]*") - return dispatch(ctx, pat) - end, - - -- Two-byte opcode dispatch. - opc2 = function(ctx, name, pat) - return dispatchmap(ctx, map_opc2) - end, - - -- Three-byte opcode dispatch. - opc3 = function(ctx, name, pat) - return dispatchmap(ctx, map_opc3[pat]) - end, - - -- VMX/SVM dispatch. - vm = function(ctx, name, pat) - return dispatch(ctx, map_opcvm[ctx.mrm]) - end, - - -- Floating point opcode dispatch. - fp = function(ctx, name, pat) - local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end - local rm = mrm%8 - local idx = pat*8 + ((mrm-rm)/8)%8 - if mrm >= 192 then idx = idx + 64 end - local opat = map_opcfp[idx] - if type(opat) == "table" then opat = opat[rm+1] end - return dispatch(ctx, opat) - end, - - -- REX prefix. - rex = function(ctx, name, pat) - if ctx.rex then return unknown(ctx) end -- Only 1 REX or VEX prefix allowed. - for p in gmatch(pat, ".") do ctx["rex"..p] = true end - ctx.rex = "rex" - end, - - -- VEX prefix. - vex = function(ctx, name, pat) - if ctx.rex then return unknown(ctx) end -- Only 1 REX or VEX prefix allowed. - ctx.rex = "vex" - local pos = ctx.pos - if ctx.mrm then - ctx.mrm = nil - pos = pos-1 - end - local b = byte(ctx.code, pos, pos) - if not b then return incomplete(ctx) end - pos = pos+1 - if b < 128 then ctx.rexr = true end - local m = 1 - if pat == "3" then - m = b%32; b = (b-m)/32 - local nb = b%2; b = (b-nb)/2 - if nb == 0 then ctx.rexb = true end - local nx = b%2 - if nx == 0 then ctx.rexx = true end - b = byte(ctx.code, pos, pos) - if not b then return incomplete(ctx) end - pos = pos+1 - if b >= 128 then ctx.rexw = true end - end - ctx.pos = pos - local map - if m == 1 then map = map_opc2 - elseif m == 2 then map = map_opc3["38"] - elseif m == 3 then map = map_opc3["3a"] - else return unknown(ctx) end - local p = b%4; b = (b-p)/4 - if p == 1 then ctx.o16 = "o16" - elseif p == 2 then ctx.rep = "rep" - elseif p == 3 then ctx.rep = "repne" end - local l = b%2; b = (b-l)/2 - if l ~= 0 then ctx.vexl = true end - ctx.vexv = (-1-b)%16 - return dispatchmap(ctx, map) - end, - - -- Special case for nop with REX prefix. - nop = function(ctx, name, pat) - return dispatch(ctx, ctx.rex and pat or "nop") - end, - - -- Special case for 0F 77. - emms = function(ctx, name, pat) - if ctx.rex ~= "vex" then - return putop(ctx, "emms") - elseif ctx.vexl then - ctx.vexl = false - return putop(ctx, "zeroall") - else - return putop(ctx, "zeroupper") - end - end, -} - ------------------------------------------------------------------------------- - --- Disassemble a block of code. -local function disass_block(ctx, ofs, len) - if not ofs then ofs = 0 end - local stop = len and ofs+len or #ctx.code - ofs = ofs + 1 - ctx.start = ofs - ctx.pos = ofs - ctx.stop = stop - ctx.imm = nil - ctx.mrm = false - clearprefixes(ctx) - while ctx.pos <= stop do dispatchmap(ctx, ctx.map1) end - if ctx.pos ~= ctx.start then incomplete(ctx) end -end - --- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). -local function create(code, addr, out) - local ctx = {} - ctx.code = code - ctx.addr = (addr or 0) - 1 - ctx.out = out or io.write - ctx.symtab = {} - ctx.disass = disass_block - ctx.hexdump = 16 - ctx.x64 = false - ctx.map1 = map_opc1_32 - ctx.aregs = map_regs.D - return ctx -end - -local function create64(code, addr, out) - local ctx = create(code, addr, out) - ctx.x64 = true - ctx.map1 = map_opc1_64 - ctx.aregs = map_regs.Q - return ctx -end - --- Simple API: disassemble code (a string) at address and output via out. -local function disass(code, addr, out) - create(code, addr, out):disass() -end - -local function disass64(code, addr, out) - create64(code, addr, out):disass() -end - --- Return register name for RID. -local function regname(r) - if r < 8 then return map_regs.D[r+1] end - return map_regs.X[r-7] -end - -local function regname64(r) - if r < 16 then return map_regs.Q[r+1] end - return map_regs.X[r-15] -end - --- Public module functions. -return { - create = create, - create64 = create64, - disass = disass, - disass64 = disass64, - regname = regname, - regname64 = regname64 -} - diff --git a/lib/LuaJIT/src/jit/dump.lua b/lib/LuaJIT/src/jit/dump.lua deleted file mode 100644 index 2bea652..0000000 --- a/lib/LuaJIT/src/jit/dump.lua +++ /dev/null @@ -1,712 +0,0 @@ ----------------------------------------------------------------------------- --- LuaJIT compiler dump module. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- Released under the MIT license. See Copyright Notice in luajit.h ----------------------------------------------------------------------------- --- --- This module can be used to debug the JIT compiler itself. It dumps the --- code representations and structures used in various compiler stages. --- --- Example usage: --- --- luajit -jdump -e "local x=0; for i=1,1e6 do x=x+i end; print(x)" --- luajit -jdump=im -e "for i=1,1000 do for j=1,1000 do end end" | less -R --- luajit -jdump=is myapp.lua | less -R --- luajit -jdump=-b myapp.lua --- luajit -jdump=+aH,myapp.html myapp.lua --- luajit -jdump=ixT,myapp.dump myapp.lua --- --- The first argument specifies the dump mode. The second argument gives --- the output file name. Default output is to stdout, unless the environment --- variable LUAJIT_DUMPFILE is set. The file is overwritten every time the --- module is started. --- --- Different features can be turned on or off with the dump mode. If the --- mode starts with a '+', the following features are added to the default --- set of features; a '-' removes them. Otherwise the features are replaced. --- --- The following dump features are available (* marks the default): --- --- * t Print a line for each started, ended or aborted trace (see also -jv). --- * b Dump the traced bytecode. --- * i Dump the IR (intermediate representation). --- r Augment the IR with register/stack slots. --- s Dump the snapshot map. --- * m Dump the generated machine code. --- x Print each taken trace exit. --- X Print each taken trace exit and the contents of all registers. --- a Print the IR of aborted traces, too. --- --- The output format can be set with the following characters: --- --- T Plain text output. --- A ANSI-colored text output --- H Colorized HTML + CSS output. --- --- The default output format is plain text. It's set to ANSI-colored text --- if the COLORTERM variable is set. Note: this is independent of any output --- redirection, which is actually considered a feature. --- --- You probably want to use less -R to enjoy viewing ANSI-colored text from --- a pipe or a file. Add this to your ~/.bashrc: export LESS="-R" --- ------------------------------------------------------------------------------- - --- Cache some library functions and objects. -local jit = require("jit") -assert(jit.version_num == 20100, "LuaJIT core/library version mismatch") -local jutil = require("jit.util") -local vmdef = require("jit.vmdef") -local funcinfo, funcbc = jutil.funcinfo, jutil.funcbc -local traceinfo, traceir, tracek = jutil.traceinfo, jutil.traceir, jutil.tracek -local tracemc, tracesnap = jutil.tracemc, jutil.tracesnap -local traceexitstub, ircalladdr = jutil.traceexitstub, jutil.ircalladdr -local bit = require("bit") -local band, shr, tohex = bit.band, bit.rshift, bit.tohex -local sub, gsub, format = string.sub, string.gsub, string.format -local byte, rep = string.byte, string.rep -local type, tostring = type, tostring -local stdout, stderr = io.stdout, io.stderr - --- Load other modules on-demand. -local bcline, disass - --- Active flag, output file handle and dump mode. -local active, out, dumpmode - ------------------------------------------------------------------------------- - -local symtabmt = { __index = false } -local symtab = {} -local nexitsym = 0 - --- Fill nested symbol table with per-trace exit stub addresses. -local function fillsymtab_tr(tr, nexit) - local t = {} - symtabmt.__index = t - if jit.arch:sub(1, 4) == "mips" then - t[traceexitstub(tr, 0)] = "exit" - return - end - for i=0,nexit-1 do - local addr = traceexitstub(tr, i) - if addr < 0 then addr = addr + 2^32 end - t[addr] = tostring(i) - end - local addr = traceexitstub(tr, nexit) - if addr then t[addr] = "stack_check" end -end - --- Fill symbol table with trace exit stub addresses. -local function fillsymtab(tr, nexit) - local t = symtab - if nexitsym == 0 then - local ircall = vmdef.ircall - for i=0,#ircall do - local addr = ircalladdr(i) - if addr ~= 0 then - if addr < 0 then addr = addr + 2^32 end - t[addr] = ircall[i] - end - end - end - if nexitsym == 1000000 then -- Per-trace exit stubs. - fillsymtab_tr(tr, nexit) - elseif nexit > nexitsym then -- Shared exit stubs. - for i=nexitsym,nexit-1 do - local addr = traceexitstub(i) - if addr == nil then -- Fall back to per-trace exit stubs. - fillsymtab_tr(tr, nexit) - setmetatable(symtab, symtabmt) - nexit = 1000000 - break - end - if addr < 0 then addr = addr + 2^32 end - t[addr] = tostring(i) - end - nexitsym = nexit - end - return t -end - -local function dumpwrite(s) - out:write(s) -end - --- Disassemble machine code. -local function dump_mcode(tr) - local info = traceinfo(tr) - if not info then return end - local mcode, addr, loop = tracemc(tr) - if not mcode then return end - if not disass then disass = require("jit.dis_"..jit.arch) end - if addr < 0 then addr = addr + 2^32 end - out:write("---- TRACE ", tr, " mcode ", #mcode, "\n") - local ctx = disass.create(mcode, addr, dumpwrite) - ctx.hexdump = 0 - ctx.symtab = fillsymtab(tr, info.nexit) - if loop ~= 0 then - symtab[addr+loop] = "LOOP" - ctx:disass(0, loop) - out:write("->LOOP:\n") - ctx:disass(loop, #mcode-loop) - symtab[addr+loop] = nil - else - ctx:disass(0, #mcode) - end -end - ------------------------------------------------------------------------------- - -local irtype_text = { - [0] = "nil", - "fal", - "tru", - "lud", - "str", - "p32", - "thr", - "pro", - "fun", - "p64", - "cdt", - "tab", - "udt", - "flt", - "num", - "i8 ", - "u8 ", - "i16", - "u16", - "int", - "u32", - "i64", - "u64", - "sfp", -} - -local colortype_ansi = { - [0] = "%s", - "%s", - "%s", - "\027[36m%s\027[m", - "\027[32m%s\027[m", - "%s", - "\027[1m%s\027[m", - "%s", - "\027[1m%s\027[m", - "%s", - "\027[33m%s\027[m", - "\027[31m%s\027[m", - "\027[36m%s\027[m", - "\027[34m%s\027[m", - "\027[34m%s\027[m", - "\027[35m%s\027[m", - "\027[35m%s\027[m", - "\027[35m%s\027[m", - "\027[35m%s\027[m", - "\027[35m%s\027[m", - "\027[35m%s\027[m", - "\027[35m%s\027[m", - "\027[35m%s\027[m", - "\027[35m%s\027[m", -} - -local function colorize_text(s) - return s -end - -local function colorize_ansi(s, t) - return format(colortype_ansi[t], s) -end - -local irtype_ansi = setmetatable({}, - { __index = function(tab, t) - local s = colorize_ansi(irtype_text[t], t); tab[t] = s; return s; end }) - -local html_escape = { ["<"] = "<", [">"] = ">", ["&"] = "&", } - -local function colorize_html(s, t) - s = gsub(s, "[<>&]", html_escape) - return format('%s', irtype_text[t], s) -end - -local irtype_html = setmetatable({}, - { __index = function(tab, t) - local s = colorize_html(irtype_text[t], t); tab[t] = s; return s; end }) - -local header_html = [[ - -]] - -local colorize, irtype - --- Lookup tables to convert some literals into names. -local litname = { - ["SLOAD "] = setmetatable({}, { __index = function(t, mode) - local s = "" - if band(mode, 1) ~= 0 then s = s.."P" end - if band(mode, 2) ~= 0 then s = s.."F" end - if band(mode, 4) ~= 0 then s = s.."T" end - if band(mode, 8) ~= 0 then s = s.."C" end - if band(mode, 16) ~= 0 then s = s.."R" end - if band(mode, 32) ~= 0 then s = s.."I" end - t[mode] = s - return s - end}), - ["XLOAD "] = { [0] = "", "R", "V", "RV", "U", "RU", "VU", "RVU", }, - ["CONV "] = setmetatable({}, { __index = function(t, mode) - local s = irtype[band(mode, 31)] - s = irtype[band(shr(mode, 5), 31)].."."..s - if band(mode, 0x800) ~= 0 then s = s.." sext" end - local c = shr(mode, 14) - if c == 2 then s = s.." index" elseif c == 3 then s = s.." check" end - t[mode] = s - return s - end}), - ["FLOAD "] = vmdef.irfield, - ["FREF "] = vmdef.irfield, - ["FPMATH"] = vmdef.irfpm, - ["BUFHDR"] = { [0] = "RESET", "APPEND" }, - ["TOSTR "] = { [0] = "INT", "NUM", "CHAR" }, -} - -local function ctlsub(c) - if c == "\n" then return "\\n" - elseif c == "\r" then return "\\r" - elseif c == "\t" then return "\\t" - else return format("\\%03d", byte(c)) - end -end - -local function fmtfunc(func, pc) - local fi = funcinfo(func, pc) - if fi.loc then - return fi.loc - elseif fi.ffid then - return vmdef.ffnames[fi.ffid] - elseif fi.addr then - return format("C:%x", fi.addr) - else - return "(?)" - end -end - -local function formatk(tr, idx, sn) - local k, t, slot = tracek(tr, idx) - local tn = type(k) - local s - if tn == "number" then - if band(sn or 0, 0x30000) ~= 0 then - s = band(sn, 0x20000) ~= 0 and "contpc" or "ftsz" - elseif k == 2^52+2^51 then - s = "bias" - else - s = format(0 < k and k < 0x1p-1026 and "%+a" or "%+.14g", k) - end - elseif tn == "string" then - s = format(#k > 20 and '"%.20s"~' or '"%s"', gsub(k, "%c", ctlsub)) - elseif tn == "function" then - s = fmtfunc(k) - elseif tn == "table" then - s = format("{%p}", k) - elseif tn == "userdata" then - if t == 12 then - s = format("userdata:%p", k) - else - s = format("[%p]", k) - if s == "[NULL]" then s = "NULL" end - end - elseif t == 21 then -- int64_t - s = sub(tostring(k), 1, -3) - if sub(s, 1, 1) ~= "-" then s = "+"..s end - elseif sn == 0x1057fff then -- SNAP(1, SNAP_FRAME | SNAP_NORESTORE, REF_NIL) - return "----" -- Special case for LJ_FR2 slot 1. - else - s = tostring(k) -- For primitives. - end - s = colorize(format("%-4s", s), t) - if slot then - s = format("%s @%d", s, slot) - end - return s -end - -local function printsnap(tr, snap) - local n = 2 - for s=0,snap[1]-1 do - local sn = snap[n] - if shr(sn, 24) == s then - n = n + 1 - local ref = band(sn, 0xffff) - 0x8000 -- REF_BIAS - if ref < 0 then - out:write(formatk(tr, ref, sn)) - elseif band(sn, 0x80000) ~= 0 then -- SNAP_SOFTFPNUM - out:write(colorize(format("%04d/%04d", ref, ref+1), 14)) - else - local m, ot, op1, op2 = traceir(tr, ref) - out:write(colorize(format("%04d", ref), band(ot, 31))) - end - out:write(band(sn, 0x10000) == 0 and " " or "|") -- SNAP_FRAME - else - out:write("---- ") - end - end - out:write("]\n") -end - --- Dump snapshots (not interleaved with IR). -local function dump_snap(tr) - out:write("---- TRACE ", tr, " snapshots\n") - for i=0,1000000000 do - local snap = tracesnap(tr, i) - if not snap then break end - out:write(format("#%-3d %04d [ ", i, snap[0])) - printsnap(tr, snap) - end -end - --- Return a register name or stack slot for a rid/sp location. -local function ridsp_name(ridsp, ins) - if not disass then disass = require("jit.dis_"..jit.arch) end - local rid, slot = band(ridsp, 0xff), shr(ridsp, 8) - if rid == 253 or rid == 254 then - return (slot == 0 or slot == 255) and " {sink" or format(" {%04d", ins-slot) - end - if ridsp > 255 then return format("[%x]", slot*4) end - if rid < 128 then return disass.regname(rid) end - return "" -end - --- Dump CALL* function ref and return optional ctype. -local function dumpcallfunc(tr, ins) - local ctype - if ins > 0 then - local m, ot, op1, op2 = traceir(tr, ins) - if band(ot, 31) == 0 then -- nil type means CARG(func, ctype). - ins = op1 - ctype = formatk(tr, op2) - end - end - if ins < 0 then - out:write(format("[0x%x](", tonumber((tracek(tr, ins))))) - else - out:write(format("%04d (", ins)) - end - return ctype -end - --- Recursively gather CALL* args and dump them. -local function dumpcallargs(tr, ins) - if ins < 0 then - out:write(formatk(tr, ins)) - else - local m, ot, op1, op2 = traceir(tr, ins) - local oidx = 6*shr(ot, 8) - local op = sub(vmdef.irnames, oidx+1, oidx+6) - if op == "CARG " then - dumpcallargs(tr, op1) - if op2 < 0 then - out:write(" ", formatk(tr, op2)) - else - out:write(" ", format("%04d", op2)) - end - else - out:write(format("%04d", ins)) - end - end -end - --- Dump IR and interleaved snapshots. -local function dump_ir(tr, dumpsnap, dumpreg) - local info = traceinfo(tr) - if not info then return end - local nins = info.nins - out:write("---- TRACE ", tr, " IR\n") - local irnames = vmdef.irnames - local snapref = 65536 - local snap, snapno - if dumpsnap then - snap = tracesnap(tr, 0) - snapref = snap[0] - snapno = 0 - end - for ins=1,nins do - if ins >= snapref then - if dumpreg then - out:write(format(".... SNAP #%-3d [ ", snapno)) - else - out:write(format(".... SNAP #%-3d [ ", snapno)) - end - printsnap(tr, snap) - snapno = snapno + 1 - snap = tracesnap(tr, snapno) - snapref = snap and snap[0] or 65536 - end - local m, ot, op1, op2, ridsp = traceir(tr, ins) - local oidx, t = 6*shr(ot, 8), band(ot, 31) - local op = sub(irnames, oidx+1, oidx+6) - if op == "LOOP " then - if dumpreg then - out:write(format("%04d ------------ LOOP ------------\n", ins)) - else - out:write(format("%04d ------ LOOP ------------\n", ins)) - end - elseif op ~= "NOP " and op ~= "CARG " and - (dumpreg or op ~= "RENAME") then - local rid = band(ridsp, 255) - if dumpreg then - out:write(format("%04d %-6s", ins, ridsp_name(ridsp, ins))) - else - out:write(format("%04d ", ins)) - end - out:write(format("%s%s %s %s ", - (rid == 254 or rid == 253) and "}" or - (band(ot, 128) == 0 and " " or ">"), - band(ot, 64) == 0 and " " or "+", - irtype[t], op)) - local m1, m2 = band(m, 3), band(m, 3*4) - if sub(op, 1, 4) == "CALL" then - local ctype - if m2 == 1*4 then -- op2 == IRMlit - out:write(format("%-10s (", vmdef.ircall[op2])) - else - ctype = dumpcallfunc(tr, op2) - end - if op1 ~= -1 then dumpcallargs(tr, op1) end - out:write(")") - if ctype then out:write(" ctype ", ctype) end - elseif op == "CNEW " and op2 == -1 then - out:write(formatk(tr, op1)) - elseif m1 ~= 3 then -- op1 != IRMnone - if op1 < 0 then - out:write(formatk(tr, op1)) - else - out:write(format(m1 == 0 and "%04d" or "#%-3d", op1)) - end - if m2 ~= 3*4 then -- op2 != IRMnone - if m2 == 1*4 then -- op2 == IRMlit - local litn = litname[op] - if litn and litn[op2] then - out:write(" ", litn[op2]) - elseif op == "UREFO " or op == "UREFC " then - out:write(format(" #%-3d", shr(op2, 8))) - else - out:write(format(" #%-3d", op2)) - end - elseif op2 < 0 then - out:write(" ", formatk(tr, op2)) - else - out:write(format(" %04d", op2)) - end - end - end - out:write("\n") - end - end - if snap then - if dumpreg then - out:write(format(".... SNAP #%-3d [ ", snapno)) - else - out:write(format(".... SNAP #%-3d [ ", snapno)) - end - printsnap(tr, snap) - end -end - ------------------------------------------------------------------------------- - -local recprefix = "" -local recdepth = 0 - --- Format trace error message. -local function fmterr(err, info) - if type(err) == "number" then - if type(info) == "function" then info = fmtfunc(info) end - err = format(vmdef.traceerr[err], info) - end - return err -end - --- Dump trace states. -local function dump_trace(what, tr, func, pc, otr, oex) - if what == "stop" or (what == "abort" and dumpmode.a) then - if dumpmode.i then dump_ir(tr, dumpmode.s, dumpmode.r and what == "stop") - elseif dumpmode.s then dump_snap(tr) end - if dumpmode.m then dump_mcode(tr) end - end - if what == "start" then - if dumpmode.H then out:write('
\n') end
-    out:write("---- TRACE ", tr, " ", what)
-    if otr then out:write(" ", otr, "/", oex == -1 and "stitch" or oex) end
-    out:write(" ", fmtfunc(func, pc), "\n")
-  elseif what == "stop" or what == "abort" then
-    out:write("---- TRACE ", tr, " ", what)
-    if what == "abort" then
-      out:write(" ", fmtfunc(func, pc), " -- ", fmterr(otr, oex), "\n")
-    else
-      local info = traceinfo(tr)
-      local link, ltype = info.link, info.linktype
-      if link == tr or link == 0 then
-	out:write(" -> ", ltype, "\n")
-      elseif ltype == "root" then
-	out:write(" -> ", link, "\n")
-      else
-	out:write(" -> ", link, " ", ltype, "\n")
-      end
-    end
-    if dumpmode.H then out:write("
\n\n") else out:write("\n") end - else - if what == "flush" then symtab, nexitsym = {}, 0 end - out:write("---- TRACE ", what, "\n\n") - end - out:flush() -end - --- Dump recorded bytecode. -local function dump_record(tr, func, pc, depth, callee) - if depth ~= recdepth then - recdepth = depth - recprefix = rep(" .", depth) - end - local line - if pc >= 0 then - line = bcline(func, pc, recprefix) - if dumpmode.H then line = gsub(line, "[<>&]", html_escape) end - else - line = "0000 "..recprefix.." FUNCC \n" - callee = func - end - if pc <= 0 then - out:write(sub(line, 1, -2), " ; ", fmtfunc(func), "\n") - else - out:write(line) - end - if pc >= 0 and band(funcbc(func, pc), 0xff) < 16 then -- ORDER BC - out:write(bcline(func, pc+1, recprefix)) -- Write JMP for cond. - end -end - ------------------------------------------------------------------------------- - --- Dump taken trace exits. -local function dump_texit(tr, ex, ngpr, nfpr, ...) - out:write("---- TRACE ", tr, " exit ", ex, "\n") - if dumpmode.X then - local regs = {...} - if jit.arch == "x64" then - for i=1,ngpr do - out:write(format(" %016x", regs[i])) - if i % 4 == 0 then out:write("\n") end - end - else - for i=1,ngpr do - out:write(" ", tohex(regs[i])) - if i % 8 == 0 then out:write("\n") end - end - end - if jit.arch == "mips" or jit.arch == "mipsel" then - for i=1,nfpr,2 do - out:write(format(" %+17.14g", regs[ngpr+i])) - if i % 8 == 7 then out:write("\n") end - end - else - for i=1,nfpr do - out:write(format(" %+17.14g", regs[ngpr+i])) - if i % 4 == 0 then out:write("\n") end - end - end - end -end - ------------------------------------------------------------------------------- - --- Detach dump handlers. -local function dumpoff() - if active then - active = false - jit.attach(dump_texit) - jit.attach(dump_record) - jit.attach(dump_trace) - if out and out ~= stdout and out ~= stderr then out:close() end - out = nil - end -end - --- Open the output file and attach dump handlers. -local function dumpon(opt, outfile) - if active then dumpoff() end - - local term = os.getenv("TERM") - local colormode = (term and term:match("color") or os.getenv("COLORTERM")) and "A" or "T" - if opt then - opt = gsub(opt, "[TAH]", function(mode) colormode = mode; return ""; end) - end - - local m = { t=true, b=true, i=true, m=true, } - if opt and opt ~= "" then - local o = sub(opt, 1, 1) - if o ~= "+" and o ~= "-" then m = {} end - for i=1,#opt do m[sub(opt, i, i)] = (o ~= "-") end - end - dumpmode = m - - if m.t or m.b or m.i or m.s or m.m then - jit.attach(dump_trace, "trace") - end - if m.b then - jit.attach(dump_record, "record") - if not bcline then bcline = require("jit.bc").line end - end - if m.x or m.X then - jit.attach(dump_texit, "texit") - end - - if not outfile then outfile = os.getenv("LUAJIT_DUMPFILE") end - if outfile then - out = outfile == "-" and stdout or assert(io.open(outfile, "w")) - else - out = stdout - end - - m[colormode] = true - if colormode == "A" then - colorize = colorize_ansi - irtype = irtype_ansi - elseif colormode == "H" then - colorize = colorize_html - irtype = irtype_html - out:write(header_html) - else - colorize = colorize_text - irtype = irtype_text - end - - active = true -end - --- Public module functions. -return { - on = dumpon, - off = dumpoff, - start = dumpon -- For -j command line option. -} - diff --git a/lib/LuaJIT/src/jit/p.lua b/lib/LuaJIT/src/jit/p.lua deleted file mode 100644 index 7be1058..0000000 --- a/lib/LuaJIT/src/jit/p.lua +++ /dev/null @@ -1,311 +0,0 @@ ----------------------------------------------------------------------------- --- LuaJIT profiler. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- Released under the MIT license. See Copyright Notice in luajit.h ----------------------------------------------------------------------------- --- --- This module is a simple command line interface to the built-in --- low-overhead profiler of LuaJIT. --- --- The lower-level API of the profiler is accessible via the "jit.profile" --- module or the luaJIT_profile_* C API. --- --- Example usage: --- --- luajit -jp myapp.lua --- luajit -jp=s myapp.lua --- luajit -jp=-s myapp.lua --- luajit -jp=vl myapp.lua --- luajit -jp=G,profile.txt myapp.lua --- --- The following dump features are available: --- --- f Stack dump: function name, otherwise module:line. Default mode. --- F Stack dump: ditto, but always prepend module. --- l Stack dump: module:line. --- stack dump depth (callee < caller). Default: 1. --- - Inverse stack dump depth (caller > callee). --- s Split stack dump after first stack level. Implies abs(depth) >= 2. --- p Show full path for module names. --- v Show VM states. Can be combined with stack dumps, e.g. vf or fv. --- z Show zones. Can be combined with stack dumps, e.g. zf or fz. --- r Show raw sample counts. Default: show percentages. --- a Annotate excerpts from source code files. --- A Annotate complete source code files. --- G Produce raw output suitable for graphical tools (e.g. flame graphs). --- m Minimum sample percentage to be shown. Default: 3. --- i Sampling interval in milliseconds. Default: 10. --- ----------------------------------------------------------------------------- - --- Cache some library functions and objects. -local jit = require("jit") -assert(jit.version_num == 20100, "LuaJIT core/library version mismatch") -local profile = require("jit.profile") -local vmdef = require("jit.vmdef") -local math = math -local pairs, ipairs, tonumber, floor = pairs, ipairs, tonumber, math.floor -local sort, format = table.sort, string.format -local stdout = io.stdout -local zone -- Load jit.zone module on demand. - --- Output file handle. -local out - ------------------------------------------------------------------------------- - -local prof_ud -local prof_states, prof_split, prof_min, prof_raw, prof_fmt, prof_depth -local prof_ann, prof_count1, prof_count2, prof_samples - -local map_vmmode = { - N = "Compiled", - I = "Interpreted", - C = "C code", - G = "Garbage Collector", - J = "JIT Compiler", -} - --- Profiler callback. -local function prof_cb(th, samples, vmmode) - prof_samples = prof_samples + samples - local key_stack, key_stack2, key_state - -- Collect keys for sample. - if prof_states then - if prof_states == "v" then - key_state = map_vmmode[vmmode] or vmmode - else - key_state = zone:get() or "(none)" - end - end - if prof_fmt then - key_stack = profile.dumpstack(th, prof_fmt, prof_depth) - key_stack = key_stack:gsub("%[builtin#(%d+)%]", function(x) - return vmdef.ffnames[tonumber(x)] - end) - if prof_split == 2 then - local k1, k2 = key_stack:match("(.-) [<>] (.*)") - if k2 then key_stack, key_stack2 = k1, k2 end - elseif prof_split == 3 then - key_stack2 = profile.dumpstack(th, "l", 1) - end - end - -- Order keys. - local k1, k2 - if prof_split == 1 then - if key_state then - k1 = key_state - if key_stack then k2 = key_stack end - end - elseif key_stack then - k1 = key_stack - if key_stack2 then k2 = key_stack2 elseif key_state then k2 = key_state end - end - -- Coalesce samples in one or two levels. - if k1 then - local t1 = prof_count1 - t1[k1] = (t1[k1] or 0) + samples - if k2 then - local t2 = prof_count2 - local t3 = t2[k1] - if not t3 then t3 = {}; t2[k1] = t3 end - t3[k2] = (t3[k2] or 0) + samples - end - end -end - ------------------------------------------------------------------------------- - --- Show top N list. -local function prof_top(count1, count2, samples, indent) - local t, n = {}, 0 - for k in pairs(count1) do - n = n + 1 - t[n] = k - end - sort(t, function(a, b) return count1[a] > count1[b] end) - for i=1,n do - local k = t[i] - local v = count1[k] - local pct = floor(v*100/samples + 0.5) - if pct < prof_min then break end - if not prof_raw then - out:write(format("%s%2d%% %s\n", indent, pct, k)) - elseif prof_raw == "r" then - out:write(format("%s%5d %s\n", indent, v, k)) - else - out:write(format("%s %d\n", k, v)) - end - if count2 then - local r = count2[k] - if r then - prof_top(r, nil, v, (prof_split == 3 or prof_split == 1) and " -- " or - (prof_depth < 0 and " -> " or " <- ")) - end - end - end -end - --- Annotate source code -local function prof_annotate(count1, samples) - local files = {} - local ms = 0 - for k, v in pairs(count1) do - local pct = floor(v*100/samples + 0.5) - ms = math.max(ms, v) - if pct >= prof_min then - local file, line = k:match("^(.*):(%d+)$") - if not file then file = k; line = 0 end - local fl = files[file] - if not fl then fl = {}; files[file] = fl; files[#files+1] = file end - line = tonumber(line) - fl[line] = prof_raw and v or pct - end - end - sort(files) - local fmtv, fmtn = " %3d%% | %s\n", " | %s\n" - if prof_raw then - local n = math.max(5, math.ceil(math.log10(ms))) - fmtv = "%"..n.."d | %s\n" - fmtn = (" "):rep(n).." | %s\n" - end - local ann = prof_ann - for _, file in ipairs(files) do - local f0 = file:byte() - if f0 == 40 or f0 == 91 then - out:write(format("\n====== %s ======\n[Cannot annotate non-file]\n", file)) - break - end - local fp, err = io.open(file) - if not fp then - out:write(format("====== ERROR: %s: %s\n", file, err)) - break - end - out:write(format("\n====== %s ======\n", file)) - local fl = files[file] - local n, show = 1, false - if ann ~= 0 then - for i=1,ann do - if fl[i] then show = true; out:write("@@ 1 @@\n"); break end - end - end - for line in fp:lines() do - if line:byte() == 27 then - out:write("[Cannot annotate bytecode file]\n") - break - end - local v = fl[n] - if ann ~= 0 then - local v2 = fl[n+ann] - if show then - if v2 then show = n+ann elseif v then show = n - elseif show+ann < n then show = false end - elseif v2 then - show = n+ann - out:write(format("@@ %d @@\n", n)) - end - if not show then goto next end - end - if v then - out:write(format(fmtv, v, line)) - else - out:write(format(fmtn, line)) - end - ::next:: - n = n + 1 - end - fp:close() - end -end - ------------------------------------------------------------------------------- - --- Finish profiling and dump result. -local function prof_finish() - if prof_ud then - profile.stop() - local samples = prof_samples - if samples == 0 then - if prof_raw ~= true then out:write("[No samples collected]\n") end - return - end - if prof_ann then - prof_annotate(prof_count1, samples) - else - prof_top(prof_count1, prof_count2, samples, "") - end - prof_count1 = nil - prof_count2 = nil - prof_ud = nil - end -end - --- Start profiling. -local function prof_start(mode) - local interval = "" - mode = mode:gsub("i%d*", function(s) interval = s; return "" end) - prof_min = 3 - mode = mode:gsub("m(%d+)", function(s) prof_min = tonumber(s); return "" end) - prof_depth = 1 - mode = mode:gsub("%-?%d+", function(s) prof_depth = tonumber(s); return "" end) - local m = {} - for c in mode:gmatch(".") do m[c] = c end - prof_states = m.z or m.v - if prof_states == "z" then zone = require("jit.zone") end - local scope = m.l or m.f or m.F or (prof_states and "" or "f") - local flags = (m.p or "") - prof_raw = m.r - if m.s then - prof_split = 2 - if prof_depth == -1 or m["-"] then prof_depth = -2 - elseif prof_depth == 1 then prof_depth = 2 end - elseif mode:find("[fF].*l") then - scope = "l" - prof_split = 3 - else - prof_split = (scope == "" or mode:find("[zv].*[lfF]")) and 1 or 0 - end - prof_ann = m.A and 0 or (m.a and 3) - if prof_ann then - scope = "l" - prof_fmt = "pl" - prof_split = 0 - prof_depth = 1 - elseif m.G and scope ~= "" then - prof_fmt = flags..scope.."Z;" - prof_depth = -100 - prof_raw = true - prof_min = 0 - elseif scope == "" then - prof_fmt = false - else - local sc = prof_split == 3 and m.f or m.F or scope - prof_fmt = flags..sc..(prof_depth >= 0 and "Z < " or "Z > ") - end - prof_count1 = {} - prof_count2 = {} - prof_samples = 0 - profile.start(scope:lower()..interval, prof_cb) - prof_ud = newproxy(true) - getmetatable(prof_ud).__gc = prof_finish -end - ------------------------------------------------------------------------------- - -local function start(mode, outfile) - if not outfile then outfile = os.getenv("LUAJIT_PROFILEFILE") end - if outfile then - out = outfile == "-" and stdout or assert(io.open(outfile, "w")) - else - out = stdout - end - prof_start(mode or "f") -end - --- Public module functions. -return { - start = start, -- For -j command line option. - stop = prof_finish -} - diff --git a/lib/LuaJIT/src/jit/v.lua b/lib/LuaJIT/src/jit/v.lua deleted file mode 100644 index 934de98..0000000 --- a/lib/LuaJIT/src/jit/v.lua +++ /dev/null @@ -1,170 +0,0 @@ ----------------------------------------------------------------------------- --- Verbose mode of the LuaJIT compiler. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- Released under the MIT license. See Copyright Notice in luajit.h ----------------------------------------------------------------------------- --- --- This module shows verbose information about the progress of the --- JIT compiler. It prints one line for each generated trace. This module --- is useful to see which code has been compiled or where the compiler --- punts and falls back to the interpreter. --- --- Example usage: --- --- luajit -jv -e "for i=1,1000 do for j=1,1000 do end end" --- luajit -jv=myapp.out myapp.lua --- --- Default output is to stderr. To redirect the output to a file, pass a --- filename as an argument (use '-' for stdout) or set the environment --- variable LUAJIT_VERBOSEFILE. The file is overwritten every time the --- module is started. --- --- The output from the first example should look like this: --- --- [TRACE 1 (command line):1 loop] --- [TRACE 2 (1/3) (command line):1 -> 1] --- --- The first number in each line is the internal trace number. Next are --- the file name ('(command line)') and the line number (':1') where the --- trace has started. Side traces also show the parent trace number and --- the exit number where they are attached to in parentheses ('(1/3)'). --- An arrow at the end shows where the trace links to ('-> 1'), unless --- it loops to itself. --- --- In this case the inner loop gets hot and is traced first, generating --- a root trace. Then the last exit from the 1st trace gets hot, too, --- and triggers generation of the 2nd trace. The side trace follows the --- path along the outer loop and *around* the inner loop, back to its --- start, and then links to the 1st trace. Yes, this may seem unusual, --- if you know how traditional compilers work. Trace compilers are full --- of surprises like this -- have fun! :-) --- --- Aborted traces are shown like this: --- --- [TRACE --- foo.lua:44 -- leaving loop in root trace at foo:lua:50] --- --- Don't worry -- trace aborts are quite common, even in programs which --- can be fully compiled. The compiler may retry several times until it --- finds a suitable trace. --- --- Of course this doesn't work with features that are not-yet-implemented --- (NYI error messages). The VM simply falls back to the interpreter. This --- may not matter at all if the particular trace is not very high up in --- the CPU usage profile. Oh, and the interpreter is quite fast, too. --- --- Also check out the -jdump module, which prints all the gory details. --- ------------------------------------------------------------------------------- - --- Cache some library functions and objects. -local jit = require("jit") -assert(jit.version_num == 20100, "LuaJIT core/library version mismatch") -local jutil = require("jit.util") -local vmdef = require("jit.vmdef") -local funcinfo, traceinfo = jutil.funcinfo, jutil.traceinfo -local type, format = type, string.format -local stdout, stderr = io.stdout, io.stderr - --- Active flag and output file handle. -local active, out - ------------------------------------------------------------------------------- - -local startloc, startex - -local function fmtfunc(func, pc) - local fi = funcinfo(func, pc) - if fi.loc then - return fi.loc - elseif fi.ffid then - return vmdef.ffnames[fi.ffid] - elseif fi.addr then - return format("C:%x", fi.addr) - else - return "(?)" - end -end - --- Format trace error message. -local function fmterr(err, info) - if type(err) == "number" then - if type(info) == "function" then info = fmtfunc(info) end - err = format(vmdef.traceerr[err], info) - end - return err -end - --- Dump trace states. -local function dump_trace(what, tr, func, pc, otr, oex) - if what == "start" then - startloc = fmtfunc(func, pc) - startex = otr and "("..otr.."/"..(oex == -1 and "stitch" or oex)..") " or "" - else - if what == "abort" then - local loc = fmtfunc(func, pc) - if loc ~= startloc then - out:write(format("[TRACE --- %s%s -- %s at %s]\n", - startex, startloc, fmterr(otr, oex), loc)) - else - out:write(format("[TRACE --- %s%s -- %s]\n", - startex, startloc, fmterr(otr, oex))) - end - elseif what == "stop" then - local info = traceinfo(tr) - local link, ltype = info.link, info.linktype - if ltype == "interpreter" then - out:write(format("[TRACE %3s %s%s -- fallback to interpreter]\n", - tr, startex, startloc)) - elseif ltype == "stitch" then - out:write(format("[TRACE %3s %s%s %s %s]\n", - tr, startex, startloc, ltype, fmtfunc(func, pc))) - elseif link == tr or link == 0 then - out:write(format("[TRACE %3s %s%s %s]\n", - tr, startex, startloc, ltype)) - elseif ltype == "root" then - out:write(format("[TRACE %3s %s%s -> %d]\n", - tr, startex, startloc, link)) - else - out:write(format("[TRACE %3s %s%s -> %d %s]\n", - tr, startex, startloc, link, ltype)) - end - else - out:write(format("[TRACE %s]\n", what)) - end - out:flush() - end -end - ------------------------------------------------------------------------------- - --- Detach dump handlers. -local function dumpoff() - if active then - active = false - jit.attach(dump_trace) - if out and out ~= stdout and out ~= stderr then out:close() end - out = nil - end -end - --- Open the output file and attach dump handlers. -local function dumpon(outfile) - if active then dumpoff() end - if not outfile then outfile = os.getenv("LUAJIT_VERBOSEFILE") end - if outfile then - out = outfile == "-" and stdout or assert(io.open(outfile, "w")) - else - out = stderr - end - jit.attach(dump_trace, "trace") - active = true -end - --- Public module functions. -return { - on = dumpon, - off = dumpoff, - start = dumpon -- For -j command line option. -} - diff --git a/lib/LuaJIT/src/jit/zone.lua b/lib/LuaJIT/src/jit/zone.lua deleted file mode 100644 index fa702c4..0000000 --- a/lib/LuaJIT/src/jit/zone.lua +++ /dev/null @@ -1,45 +0,0 @@ ----------------------------------------------------------------------------- --- LuaJIT profiler zones. --- --- Copyright (C) 2005-2017 Mike Pall. All rights reserved. --- Released under the MIT license. See Copyright Notice in luajit.h ----------------------------------------------------------------------------- --- --- This module implements a simple hierarchical zone model. --- --- Example usage: --- --- local zone = require("jit.zone") --- zone("AI") --- ... --- zone("A*") --- ... --- print(zone:get()) --> "A*" --- ... --- zone() --- ... --- print(zone:get()) --> "AI" --- ... --- zone() --- ----------------------------------------------------------------------------- - -local remove = table.remove - -return setmetatable({ - flush = function(t) - for i=#t,1,-1 do t[i] = nil end - end, - get = function(t) - return t[#t] - end -}, { - __call = function(t, zone) - if zone then - t[#t+1] = zone - else - return (assert(remove(t), "empty zone stack")) - end - end -}) - diff --git a/lib/LuaJIT/src/lauxlib.h b/lib/LuaJIT/src/lauxlib.h deleted file mode 100644 index a44f027..0000000 --- a/lib/LuaJIT/src/lauxlib.h +++ /dev/null @@ -1,161 +0,0 @@ -/* -** $Id: lauxlib.h,v 1.88.1.1 2007/12/27 13:02:25 roberto Exp $ -** Auxiliary functions for building Lua libraries -** See Copyright Notice in lua.h -*/ - - -#ifndef lauxlib_h -#define lauxlib_h - - -#include -#include - -#include "lua.h" - - -/* extra error code for `luaL_load' */ -#define LUA_ERRFILE (LUA_ERRERR+1) - -typedef struct luaL_Reg { - const char *name; - lua_CFunction func; -} luaL_Reg; - -LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname, - const luaL_Reg *l, int nup); -LUALIB_API void (luaL_register) (lua_State *L, const char *libname, - const luaL_Reg *l); -LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); -LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); -LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname); -LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg); -LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg, - size_t *l); -LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg, - const char *def, size_t *l); -LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg); -LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def); - -LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg); -LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg, - lua_Integer def); - -LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); -LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t); -LUALIB_API void (luaL_checkany) (lua_State *L, int narg); - -LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); -LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); - -LUALIB_API void (luaL_where) (lua_State *L, int lvl); -LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); - -LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def, - const char *const lst[]); - -/* pre-defined references */ -#define LUA_NOREF (-2) -#define LUA_REFNIL (-1) - -LUALIB_API int (luaL_ref) (lua_State *L, int t); -LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); - -LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename); -LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, - const char *name); -LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); - -LUALIB_API lua_State *(luaL_newstate) (void); - - -LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, - const char *r); - -LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, - const char *fname, int szhint); - -/* From Lua 5.2. */ -LUALIB_API int luaL_fileresult(lua_State *L, int stat, const char *fname); -LUALIB_API int luaL_execresult(lua_State *L, int stat); -LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename, - const char *mode); -LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, - const char *name, const char *mode); -LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, - int level); -LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); -LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname, - int sizehint); -LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname); -LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname); - - -/* -** =============================================================== -** some useful macros -** =============================================================== -*/ - -#define luaL_argcheck(L, cond,numarg,extramsg) \ - ((void)((cond) || luaL_argerror(L, (numarg), (extramsg)))) -#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) -#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) -#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) -#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) -#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) -#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) - -#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) - -#define luaL_dofile(L, fn) \ - (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) - -#define luaL_dostring(L, s) \ - (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) - -#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) - -#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) - -/* From Lua 5.2. */ -#define luaL_newlibtable(L, l) \ - lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1) -#define luaL_newlib(L, l) (luaL_newlibtable(L, l), luaL_setfuncs(L, l, 0)) - -/* -** {====================================================== -** Generic Buffer manipulation -** ======================================================= -*/ - - - -typedef struct luaL_Buffer { - char *p; /* current position in buffer */ - int lvl; /* number of strings in the stack (level) */ - lua_State *L; - char buffer[LUAL_BUFFERSIZE]; -} luaL_Buffer; - -#define luaL_addchar(B,c) \ - ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \ - (*(B)->p++ = (char)(c))) - -/* compatibility only */ -#define luaL_putchar(B,c) luaL_addchar(B,c) - -#define luaL_addsize(B,n) ((B)->p += (n)) - -LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); -LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B); -LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); -LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); -LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); -LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); - - -/* }====================================================== */ - -#endif diff --git a/lib/LuaJIT/src/lib_aux.c b/lib/LuaJIT/src/lib_aux.c deleted file mode 100644 index 2682a38..0000000 --- a/lib/LuaJIT/src/lib_aux.c +++ /dev/null @@ -1,374 +0,0 @@ -/* -** Auxiliary library for the Lua/C API. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Major parts taken verbatim or adapted from the Lua interpreter. -** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h -*/ - -#include -#include -#include - -#define lib_aux_c -#define LUA_LIB - -#include "lua.h" -#include "lauxlib.h" - -#include "lj_obj.h" -#include "lj_err.h" -#include "lj_state.h" -#include "lj_trace.h" -#include "lj_lib.h" - -#if LJ_TARGET_POSIX -#include -#endif - -/* -- I/O error handling -------------------------------------------------- */ - -LUALIB_API int luaL_fileresult(lua_State *L, int stat, const char *fname) -{ - if (stat) { - setboolV(L->top++, 1); - return 1; - } else { - int en = errno; /* Lua API calls may change this value. */ - setnilV(L->top++); - if (fname) - lua_pushfstring(L, "%s: %s", fname, strerror(en)); - else - lua_pushfstring(L, "%s", strerror(en)); - setintV(L->top++, en); - lj_trace_abort(G(L)); - return 3; - } -} - -LUALIB_API int luaL_execresult(lua_State *L, int stat) -{ - if (stat != -1) { -#if LJ_TARGET_POSIX - if (WIFSIGNALED(stat)) { - stat = WTERMSIG(stat); - setnilV(L->top++); - lua_pushliteral(L, "signal"); - } else { - if (WIFEXITED(stat)) - stat = WEXITSTATUS(stat); - if (stat == 0) - setboolV(L->top++, 1); - else - setnilV(L->top++); - lua_pushliteral(L, "exit"); - } -#else - if (stat == 0) - setboolV(L->top++, 1); - else - setnilV(L->top++); - lua_pushliteral(L, "exit"); -#endif - setintV(L->top++, stat); - return 3; - } - return luaL_fileresult(L, 0, NULL); -} - -/* -- Module registration ------------------------------------------------- */ - -LUALIB_API const char *luaL_findtable(lua_State *L, int idx, - const char *fname, int szhint) -{ - const char *e; - lua_pushvalue(L, idx); - do { - e = strchr(fname, '.'); - if (e == NULL) e = fname + strlen(fname); - lua_pushlstring(L, fname, (size_t)(e - fname)); - lua_rawget(L, -2); - if (lua_isnil(L, -1)) { /* no such field? */ - lua_pop(L, 1); /* remove this nil */ - lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ - lua_pushlstring(L, fname, (size_t)(e - fname)); - lua_pushvalue(L, -2); - lua_settable(L, -4); /* set new table into field */ - } else if (!lua_istable(L, -1)) { /* field has a non-table value? */ - lua_pop(L, 2); /* remove table and value */ - return fname; /* return problematic part of the name */ - } - lua_remove(L, -2); /* remove previous table */ - fname = e + 1; - } while (*e == '.'); - return NULL; -} - -static int libsize(const luaL_Reg *l) -{ - int size = 0; - for (; l && l->name; l++) size++; - return size; -} - -LUALIB_API void luaL_pushmodule(lua_State *L, const char *modname, int sizehint) -{ - luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 16); - lua_getfield(L, -1, modname); - if (!lua_istable(L, -1)) { - lua_pop(L, 1); - if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, sizehint) != NULL) - lj_err_callerv(L, LJ_ERR_BADMODN, modname); - lua_pushvalue(L, -1); - lua_setfield(L, -3, modname); /* _LOADED[modname] = new table. */ - } - lua_remove(L, -2); /* Remove _LOADED table. */ -} - -LUALIB_API void luaL_openlib(lua_State *L, const char *libname, - const luaL_Reg *l, int nup) -{ - lj_lib_checkfpu(L); - if (libname) { - luaL_pushmodule(L, libname, libsize(l)); - lua_insert(L, -(nup + 1)); /* Move module table below upvalues. */ - } - if (l) - luaL_setfuncs(L, l, nup); - else - lua_pop(L, nup); /* Remove upvalues. */ -} - -LUALIB_API void luaL_register(lua_State *L, const char *libname, - const luaL_Reg *l) -{ - luaL_openlib(L, libname, l, 0); -} - -LUALIB_API void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup) -{ - luaL_checkstack(L, nup, "too many upvalues"); - for (; l->name; l++) { - int i; - for (i = 0; i < nup; i++) /* Copy upvalues to the top. */ - lua_pushvalue(L, -nup); - lua_pushcclosure(L, l->func, nup); - lua_setfield(L, -(nup + 2), l->name); - } - lua_pop(L, nup); /* Remove upvalues. */ -} - -LUALIB_API const char *luaL_gsub(lua_State *L, const char *s, - const char *p, const char *r) -{ - const char *wild; - size_t l = strlen(p); - luaL_Buffer b; - luaL_buffinit(L, &b); - while ((wild = strstr(s, p)) != NULL) { - luaL_addlstring(&b, s, (size_t)(wild - s)); /* push prefix */ - luaL_addstring(&b, r); /* push replacement in place of pattern */ - s = wild + l; /* continue after `p' */ - } - luaL_addstring(&b, s); /* push last suffix */ - luaL_pushresult(&b); - return lua_tostring(L, -1); -} - -/* -- Buffer handling ----------------------------------------------------- */ - -#define bufflen(B) ((size_t)((B)->p - (B)->buffer)) -#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B))) - -static int emptybuffer(luaL_Buffer *B) -{ - size_t l = bufflen(B); - if (l == 0) - return 0; /* put nothing on stack */ - lua_pushlstring(B->L, B->buffer, l); - B->p = B->buffer; - B->lvl++; - return 1; -} - -static void adjuststack(luaL_Buffer *B) -{ - if (B->lvl > 1) { - lua_State *L = B->L; - int toget = 1; /* number of levels to concat */ - size_t toplen = lua_strlen(L, -1); - do { - size_t l = lua_strlen(L, -(toget+1)); - if (!(B->lvl - toget + 1 >= LUA_MINSTACK/2 || toplen > l)) - break; - toplen += l; - toget++; - } while (toget < B->lvl); - lua_concat(L, toget); - B->lvl = B->lvl - toget + 1; - } -} - -LUALIB_API char *luaL_prepbuffer(luaL_Buffer *B) -{ - if (emptybuffer(B)) - adjuststack(B); - return B->buffer; -} - -LUALIB_API void luaL_addlstring(luaL_Buffer *B, const char *s, size_t l) -{ - if (l <= bufffree(B)) { - memcpy(B->p, s, l); - B->p += l; - } else { - emptybuffer(B); - lua_pushlstring(B->L, s, l); - B->lvl++; - adjuststack(B); - } -} - -LUALIB_API void luaL_addstring(luaL_Buffer *B, const char *s) -{ - luaL_addlstring(B, s, strlen(s)); -} - -LUALIB_API void luaL_pushresult(luaL_Buffer *B) -{ - emptybuffer(B); - lua_concat(B->L, B->lvl); - B->lvl = 1; -} - -LUALIB_API void luaL_addvalue(luaL_Buffer *B) -{ - lua_State *L = B->L; - size_t vl; - const char *s = lua_tolstring(L, -1, &vl); - if (vl <= bufffree(B)) { /* fit into buffer? */ - memcpy(B->p, s, vl); /* put it there */ - B->p += vl; - lua_pop(L, 1); /* remove from stack */ - } else { - if (emptybuffer(B)) - lua_insert(L, -2); /* put buffer before new value */ - B->lvl++; /* add new value into B stack */ - adjuststack(B); - } -} - -LUALIB_API void luaL_buffinit(lua_State *L, luaL_Buffer *B) -{ - B->L = L; - B->p = B->buffer; - B->lvl = 0; -} - -/* -- Reference management ------------------------------------------------ */ - -#define FREELIST_REF 0 - -/* Convert a stack index to an absolute index. */ -#define abs_index(L, i) \ - ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : lua_gettop(L) + (i) + 1) - -LUALIB_API int luaL_ref(lua_State *L, int t) -{ - int ref; - t = abs_index(L, t); - if (lua_isnil(L, -1)) { - lua_pop(L, 1); /* remove from stack */ - return LUA_REFNIL; /* `nil' has a unique fixed reference */ - } - lua_rawgeti(L, t, FREELIST_REF); /* get first free element */ - ref = (int)lua_tointeger(L, -1); /* ref = t[FREELIST_REF] */ - lua_pop(L, 1); /* remove it from stack */ - if (ref != 0) { /* any free element? */ - lua_rawgeti(L, t, ref); /* remove it from list */ - lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */ - } else { /* no free elements */ - ref = (int)lua_objlen(L, t); - ref++; /* create new reference */ - } - lua_rawseti(L, t, ref); - return ref; -} - -LUALIB_API void luaL_unref(lua_State *L, int t, int ref) -{ - if (ref >= 0) { - t = abs_index(L, t); - lua_rawgeti(L, t, FREELIST_REF); - lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */ - lua_pushinteger(L, ref); - lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */ - } -} - -/* -- Default allocator and panic function -------------------------------- */ - -static int panic(lua_State *L) -{ - const char *s = lua_tostring(L, -1); - fputs("PANIC: unprotected error in call to Lua API (", stderr); - fputs(s ? s : "?", stderr); - fputc(')', stderr); fputc('\n', stderr); - fflush(stderr); - return 0; -} - -#ifdef LUAJIT_USE_SYSMALLOC - -#if LJ_64 && !LJ_GC64 && !defined(LUAJIT_USE_VALGRIND) -#error "Must use builtin allocator for 64 bit target" -#endif - -static void *mem_alloc(void *ud, void *ptr, size_t osize, size_t nsize) -{ - (void)ud; - (void)osize; - if (nsize == 0) { - free(ptr); - return NULL; - } else { - return realloc(ptr, nsize); - } -} - -LUALIB_API lua_State *luaL_newstate(void) -{ - lua_State *L = lua_newstate(mem_alloc, NULL); - if (L) G(L)->panic = panic; - return L; -} - -#else - -#include "lj_alloc.h" - -LUALIB_API lua_State *luaL_newstate(void) -{ - lua_State *L; - void *ud = lj_alloc_create(); - if (ud == NULL) return NULL; -#if LJ_64 && !LJ_GC64 - L = lj_state_newstate(lj_alloc_f, ud); -#else - L = lua_newstate(lj_alloc_f, ud); -#endif - if (L) G(L)->panic = panic; - return L; -} - -#if LJ_64 && !LJ_GC64 -LUA_API lua_State *lua_newstate(lua_Alloc f, void *ud) -{ - UNUSED(f); UNUSED(ud); - fputs("Must use luaL_newstate() for 64 bit target\n", stderr); - return NULL; -} -#endif - -#endif - diff --git a/lib/LuaJIT/src/lib_base.c b/lib/LuaJIT/src/lib_base.c deleted file mode 100644 index 1cd8305..0000000 --- a/lib/LuaJIT/src/lib_base.c +++ /dev/null @@ -1,679 +0,0 @@ -/* -** Base and coroutine library. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Major portions taken verbatim or adapted from the Lua interpreter. -** Copyright (C) 1994-2011 Lua.org, PUC-Rio. See Copyright Notice in lua.h -*/ - -#include - -#define lib_base_c -#define LUA_LIB - -#include "lua.h" -#include "lauxlib.h" -#include "lualib.h" - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_debug.h" -#include "lj_str.h" -#include "lj_tab.h" -#include "lj_meta.h" -#include "lj_state.h" -#include "lj_frame.h" -#if LJ_HASFFI -#include "lj_ctype.h" -#include "lj_cconv.h" -#endif -#include "lj_bc.h" -#include "lj_ff.h" -#include "lj_dispatch.h" -#include "lj_char.h" -#include "lj_strscan.h" -#include "lj_strfmt.h" -#include "lj_lib.h" - -/* -- Base library: checks ------------------------------------------------ */ - -#define LJLIB_MODULE_base - -LJLIB_ASM(assert) LJLIB_REC(.) -{ - lj_lib_checkany(L, 1); - if (L->top == L->base+1) - lj_err_caller(L, LJ_ERR_ASSERT); - else if (tvisstr(L->base+1) || tvisnumber(L->base+1)) - lj_err_callermsg(L, strdata(lj_lib_checkstr(L, 2))); - else - lj_err_run(L); - return FFH_UNREACHABLE; -} - -/* ORDER LJ_T */ -LJLIB_PUSH("nil") -LJLIB_PUSH("boolean") -LJLIB_PUSH(top-1) /* boolean */ -LJLIB_PUSH("userdata") -LJLIB_PUSH("string") -LJLIB_PUSH("upval") -LJLIB_PUSH("thread") -LJLIB_PUSH("proto") -LJLIB_PUSH("function") -LJLIB_PUSH("trace") -LJLIB_PUSH("cdata") -LJLIB_PUSH("table") -LJLIB_PUSH(top-9) /* userdata */ -LJLIB_PUSH("number") -LJLIB_ASM_(type) LJLIB_REC(.) -/* Recycle the lj_lib_checkany(L, 1) from assert. */ - -/* -- Base library: iterators --------------------------------------------- */ - -/* This solves a circular dependency problem -- change FF_next_N as needed. */ -LJ_STATIC_ASSERT((int)FF_next == FF_next_N); - -LJLIB_ASM(next) -{ - lj_lib_checktab(L, 1); - return FFH_UNREACHABLE; -} - -#if LJ_52 || LJ_HASFFI -static int ffh_pairs(lua_State *L, MMS mm) -{ - TValue *o = lj_lib_checkany(L, 1); - cTValue *mo = lj_meta_lookup(L, o, mm); - if ((LJ_52 || tviscdata(o)) && !tvisnil(mo)) { - L->top = o+1; /* Only keep one argument. */ - copyTV(L, L->base-1-LJ_FR2, mo); /* Replace callable. */ - return FFH_TAILCALL; - } else { - if (!tvistab(o)) lj_err_argt(L, 1, LUA_TTABLE); - if (LJ_FR2) { copyTV(L, o-1, o); o--; } - setfuncV(L, o-1, funcV(lj_lib_upvalue(L, 1))); - if (mm == MM_pairs) setnilV(o+1); else setintV(o+1, 0); - return FFH_RES(3); - } -} -#else -#define ffh_pairs(L, mm) (lj_lib_checktab(L, 1), FFH_UNREACHABLE) -#endif - -LJLIB_PUSH(lastcl) -LJLIB_ASM(pairs) LJLIB_REC(xpairs 0) -{ - return ffh_pairs(L, MM_pairs); -} - -LJLIB_NOREGUV LJLIB_ASM(ipairs_aux) LJLIB_REC(.) -{ - lj_lib_checktab(L, 1); - lj_lib_checkint(L, 2); - return FFH_UNREACHABLE; -} - -LJLIB_PUSH(lastcl) -LJLIB_ASM(ipairs) LJLIB_REC(xpairs 1) -{ - return ffh_pairs(L, MM_ipairs); -} - -/* -- Base library: getters and setters ----------------------------------- */ - -LJLIB_ASM_(getmetatable) LJLIB_REC(.) -/* Recycle the lj_lib_checkany(L, 1) from assert. */ - -LJLIB_ASM(setmetatable) LJLIB_REC(.) -{ - GCtab *t = lj_lib_checktab(L, 1); - GCtab *mt = lj_lib_checktabornil(L, 2); - if (!tvisnil(lj_meta_lookup(L, L->base, MM_metatable))) - lj_err_caller(L, LJ_ERR_PROTMT); - setgcref(t->metatable, obj2gco(mt)); - if (mt) { lj_gc_objbarriert(L, t, mt); } - settabV(L, L->base-1-LJ_FR2, t); - return FFH_RES(1); -} - -LJLIB_CF(getfenv) LJLIB_REC(.) -{ - GCfunc *fn; - cTValue *o = L->base; - if (!(o < L->top && tvisfunc(o))) { - int level = lj_lib_optint(L, 1, 1); - o = lj_debug_frame(L, level, &level); - if (o == NULL) - lj_err_arg(L, 1, LJ_ERR_INVLVL); - if (LJ_FR2) o--; - } - fn = &gcval(o)->fn; - settabV(L, L->top++, isluafunc(fn) ? tabref(fn->l.env) : tabref(L->env)); - return 1; -} - -LJLIB_CF(setfenv) -{ - GCfunc *fn; - GCtab *t = lj_lib_checktab(L, 2); - cTValue *o = L->base; - if (!(o < L->top && tvisfunc(o))) { - int level = lj_lib_checkint(L, 1); - if (level == 0) { - /* NOBARRIER: A thread (i.e. L) is never black. */ - setgcref(L->env, obj2gco(t)); - return 0; - } - o = lj_debug_frame(L, level, &level); - if (o == NULL) - lj_err_arg(L, 1, LJ_ERR_INVLVL); - if (LJ_FR2) o--; - } - fn = &gcval(o)->fn; - if (!isluafunc(fn)) - lj_err_caller(L, LJ_ERR_SETFENV); - setgcref(fn->l.env, obj2gco(t)); - lj_gc_objbarrier(L, obj2gco(fn), t); - setfuncV(L, L->top++, fn); - return 1; -} - -LJLIB_ASM(rawget) LJLIB_REC(.) -{ - lj_lib_checktab(L, 1); - lj_lib_checkany(L, 2); - return FFH_UNREACHABLE; -} - -LJLIB_CF(rawset) LJLIB_REC(.) -{ - lj_lib_checktab(L, 1); - lj_lib_checkany(L, 2); - L->top = 1+lj_lib_checkany(L, 3); - lua_rawset(L, 1); - return 1; -} - -LJLIB_CF(rawequal) LJLIB_REC(.) -{ - cTValue *o1 = lj_lib_checkany(L, 1); - cTValue *o2 = lj_lib_checkany(L, 2); - setboolV(L->top-1, lj_obj_equal(o1, o2)); - return 1; -} - -#if LJ_52 -LJLIB_CF(rawlen) LJLIB_REC(.) -{ - cTValue *o = L->base; - int32_t len; - if (L->top > o && tvisstr(o)) - len = (int32_t)strV(o)->len; - else - len = (int32_t)lj_tab_len(lj_lib_checktab(L, 1)); - setintV(L->top-1, len); - return 1; -} -#endif - -LJLIB_CF(unpack) -{ - GCtab *t = lj_lib_checktab(L, 1); - int32_t n, i = lj_lib_optint(L, 2, 1); - int32_t e = (L->base+3-1 < L->top && !tvisnil(L->base+3-1)) ? - lj_lib_checkint(L, 3) : (int32_t)lj_tab_len(t); - if (i > e) return 0; - n = e - i + 1; - if (n <= 0 || !lua_checkstack(L, n)) - lj_err_caller(L, LJ_ERR_UNPACK); - do { - cTValue *tv = lj_tab_getint(t, i); - if (tv) { - copyTV(L, L->top++, tv); - } else { - setnilV(L->top++); - } - } while (i++ < e); - return n; -} - -LJLIB_CF(select) LJLIB_REC(.) -{ - int32_t n = (int32_t)(L->top - L->base); - if (n >= 1 && tvisstr(L->base) && *strVdata(L->base) == '#') { - setintV(L->top-1, n-1); - return 1; - } else { - int32_t i = lj_lib_checkint(L, 1); - if (i < 0) i = n + i; else if (i > n) i = n; - if (i < 1) - lj_err_arg(L, 1, LJ_ERR_IDXRNG); - return n - i; - } -} - -/* -- Base library: conversions ------------------------------------------- */ - -LJLIB_ASM(tonumber) LJLIB_REC(.) -{ - int32_t base = lj_lib_optint(L, 2, 10); - if (base == 10) { - TValue *o = lj_lib_checkany(L, 1); - if (lj_strscan_numberobj(o)) { - copyTV(L, L->base-1-LJ_FR2, o); - return FFH_RES(1); - } -#if LJ_HASFFI - if (tviscdata(o)) { - CTState *cts = ctype_cts(L); - CType *ct = lj_ctype_rawref(cts, cdataV(o)->ctypeid); - if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct); - if (ctype_isnum(ct->info) || ctype_iscomplex(ct->info)) { - if (LJ_DUALNUM && ctype_isinteger_or_bool(ct->info) && - ct->size <= 4 && !(ct->size == 4 && (ct->info & CTF_UNSIGNED))) { - int32_t i; - lj_cconv_ct_tv(cts, ctype_get(cts, CTID_INT32), (uint8_t *)&i, o, 0); - setintV(L->base-1-LJ_FR2, i); - return FFH_RES(1); - } - lj_cconv_ct_tv(cts, ctype_get(cts, CTID_DOUBLE), - (uint8_t *)&(L->base-1-LJ_FR2)->n, o, 0); - return FFH_RES(1); - } - } -#endif - } else { - const char *p = strdata(lj_lib_checkstr(L, 1)); - char *ep; - unsigned int neg = 0; - unsigned long ul; - if (base < 2 || base > 36) - lj_err_arg(L, 2, LJ_ERR_BASERNG); - while (lj_char_isspace((unsigned char)(*p))) p++; - if (*p == '-') { p++; neg = 1; } else if (*p == '+') { p++; } - if (lj_char_isalnum((unsigned char)(*p))) { - ul = strtoul(p, &ep, base); - if (p != ep) { - while (lj_char_isspace((unsigned char)(*ep))) ep++; - if (*ep == '\0') { - if (LJ_DUALNUM && LJ_LIKELY(ul < 0x80000000u+neg)) { - if (neg) ul = -ul; - setintV(L->base-1-LJ_FR2, (int32_t)ul); - } else { - lua_Number n = (lua_Number)ul; - if (neg) n = -n; - setnumV(L->base-1-LJ_FR2, n); - } - return FFH_RES(1); - } - } - } - } - setnilV(L->base-1-LJ_FR2); - return FFH_RES(1); -} - -LJLIB_ASM(tostring) LJLIB_REC(.) -{ - TValue *o = lj_lib_checkany(L, 1); - cTValue *mo; - L->top = o+1; /* Only keep one argument. */ - if (!tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) { - copyTV(L, L->base-1-LJ_FR2, mo); /* Replace callable. */ - return FFH_TAILCALL; - } - lj_gc_check(L); - setstrV(L, L->base-1-LJ_FR2, lj_strfmt_obj(L, L->base)); - return FFH_RES(1); -} - -/* -- Base library: throw and catch errors -------------------------------- */ - -LJLIB_CF(error) -{ - int32_t level = lj_lib_optint(L, 2, 1); - lua_settop(L, 1); - if (lua_isstring(L, 1) && level > 0) { - luaL_where(L, level); - lua_pushvalue(L, 1); - lua_concat(L, 2); - } - return lua_error(L); -} - -LJLIB_ASM(pcall) LJLIB_REC(.) -{ - lj_lib_checkany(L, 1); - lj_lib_checkfunc(L, 2); /* For xpcall only. */ - return FFH_UNREACHABLE; -} -LJLIB_ASM_(xpcall) LJLIB_REC(.) - -/* -- Base library: load Lua code ----------------------------------------- */ - -static int load_aux(lua_State *L, int status, int envarg) -{ - if (status == LUA_OK) { - if (tvistab(L->base+envarg-1)) { - GCfunc *fn = funcV(L->top-1); - GCtab *t = tabV(L->base+envarg-1); - setgcref(fn->c.env, obj2gco(t)); - lj_gc_objbarrier(L, fn, t); - } - return 1; - } else { - setnilV(L->top-2); - return 2; - } -} - -LJLIB_CF(loadfile) -{ - GCstr *fname = lj_lib_optstr(L, 1); - GCstr *mode = lj_lib_optstr(L, 2); - int status; - lua_settop(L, 3); /* Ensure env arg exists. */ - status = luaL_loadfilex(L, fname ? strdata(fname) : NULL, - mode ? strdata(mode) : NULL); - return load_aux(L, status, 3); -} - -static const char *reader_func(lua_State *L, void *ud, size_t *size) -{ - UNUSED(ud); - luaL_checkstack(L, 2, "too many nested functions"); - copyTV(L, L->top++, L->base); - lua_call(L, 0, 1); /* Call user-supplied function. */ - L->top--; - if (tvisnil(L->top)) { - *size = 0; - return NULL; - } else if (tvisstr(L->top) || tvisnumber(L->top)) { - copyTV(L, L->base+4, L->top); /* Anchor string in reserved stack slot. */ - return lua_tolstring(L, 5, size); - } else { - lj_err_caller(L, LJ_ERR_RDRSTR); - return NULL; - } -} - -LJLIB_CF(load) -{ - GCstr *name = lj_lib_optstr(L, 2); - GCstr *mode = lj_lib_optstr(L, 3); - int status; - if (L->base < L->top && (tvisstr(L->base) || tvisnumber(L->base))) { - GCstr *s = lj_lib_checkstr(L, 1); - lua_settop(L, 4); /* Ensure env arg exists. */ - status = luaL_loadbufferx(L, strdata(s), s->len, strdata(name ? name : s), - mode ? strdata(mode) : NULL); - } else { - lj_lib_checkfunc(L, 1); - lua_settop(L, 5); /* Reserve a slot for the string from the reader. */ - status = lua_loadx(L, reader_func, NULL, name ? strdata(name) : "=(load)", - mode ? strdata(mode) : NULL); - } - return load_aux(L, status, 4); -} - -LJLIB_CF(loadstring) -{ - return lj_cf_load(L); -} - -LJLIB_CF(dofile) -{ - GCstr *fname = lj_lib_optstr(L, 1); - setnilV(L->top); - L->top = L->base+1; - if (luaL_loadfile(L, fname ? strdata(fname) : NULL) != LUA_OK) - lua_error(L); - lua_call(L, 0, LUA_MULTRET); - return (int)(L->top - L->base) - 1; -} - -/* -- Base library: GC control -------------------------------------------- */ - -LJLIB_CF(gcinfo) -{ - setintV(L->top++, (int32_t)(G(L)->gc.total >> 10)); - return 1; -} - -LJLIB_CF(collectgarbage) -{ - int opt = lj_lib_checkopt(L, 1, LUA_GCCOLLECT, /* ORDER LUA_GC* */ - "\4stop\7restart\7collect\5count\1\377\4step\10setpause\12setstepmul\1\377\11isrunning"); - int32_t data = lj_lib_optint(L, 2, 0); - if (opt == LUA_GCCOUNT) { - setnumV(L->top, (lua_Number)G(L)->gc.total/1024.0); - } else { - int res = lua_gc(L, opt, data); - if (opt == LUA_GCSTEP || opt == LUA_GCISRUNNING) - setboolV(L->top, res); - else - setintV(L->top, res); - } - L->top++; - return 1; -} - -/* -- Base library: miscellaneous functions ------------------------------- */ - -LJLIB_PUSH(top-2) /* Upvalue holds weak table. */ -LJLIB_CF(newproxy) -{ - lua_settop(L, 1); - lua_newuserdata(L, 0); - if (lua_toboolean(L, 1) == 0) { /* newproxy(): without metatable. */ - return 1; - } else if (lua_isboolean(L, 1)) { /* newproxy(true): with metatable. */ - lua_newtable(L); - lua_pushvalue(L, -1); - lua_pushboolean(L, 1); - lua_rawset(L, lua_upvalueindex(1)); /* Remember mt in weak table. */ - } else { /* newproxy(proxy): inherit metatable. */ - int validproxy = 0; - if (lua_getmetatable(L, 1)) { - lua_rawget(L, lua_upvalueindex(1)); - validproxy = lua_toboolean(L, -1); - lua_pop(L, 1); - } - if (!validproxy) - lj_err_arg(L, 1, LJ_ERR_NOPROXY); - lua_getmetatable(L, 1); - } - lua_setmetatable(L, 2); - return 1; -} - -LJLIB_PUSH("tostring") -LJLIB_CF(print) -{ - ptrdiff_t i, nargs = L->top - L->base; - cTValue *tv = lj_tab_getstr(tabref(L->env), strV(lj_lib_upvalue(L, 1))); - int shortcut; - if (tv && !tvisnil(tv)) { - copyTV(L, L->top++, tv); - } else { - setstrV(L, L->top++, strV(lj_lib_upvalue(L, 1))); - lua_gettable(L, LUA_GLOBALSINDEX); - tv = L->top-1; - } - shortcut = (tvisfunc(tv) && funcV(tv)->c.ffid == FF_tostring); - for (i = 0; i < nargs; i++) { - cTValue *o = &L->base[i]; - const char *str; - size_t size; - MSize len; - if (shortcut && (str = lj_strfmt_wstrnum(L, o, &len)) != NULL) { - size = len; - } else { - copyTV(L, L->top+1, o); - copyTV(L, L->top, L->top-1); - L->top += 2; - lua_call(L, 1, 1); - str = lua_tolstring(L, -1, &size); - if (!str) - lj_err_caller(L, LJ_ERR_PRTOSTR); - L->top--; - } - if (i) - putchar('\t'); - fwrite(str, 1, size, stdout); - } - putchar('\n'); - return 0; -} - -LJLIB_PUSH(top-3) -LJLIB_SET(_VERSION) - -#include "lj_libdef.h" - -/* -- Coroutine library --------------------------------------------------- */ - -#define LJLIB_MODULE_coroutine - -LJLIB_CF(coroutine_status) -{ - const char *s; - lua_State *co; - if (!(L->top > L->base && tvisthread(L->base))) - lj_err_arg(L, 1, LJ_ERR_NOCORO); - co = threadV(L->base); - if (co == L) s = "running"; - else if (co->status == LUA_YIELD) s = "suspended"; - else if (co->status != LUA_OK) s = "dead"; - else if (co->base > tvref(co->stack)+1+LJ_FR2) s = "normal"; - else if (co->top == co->base) s = "dead"; - else s = "suspended"; - lua_pushstring(L, s); - return 1; -} - -LJLIB_CF(coroutine_running) -{ -#if LJ_52 - int ismain = lua_pushthread(L); - setboolV(L->top++, ismain); - return 2; -#else - if (lua_pushthread(L)) - setnilV(L->top++); - return 1; -#endif -} - -LJLIB_CF(coroutine_isyieldable) -{ - setboolV(L->top++, cframe_canyield(L->cframe)); - return 1; -} - -LJLIB_CF(coroutine_create) -{ - lua_State *L1; - if (!(L->base < L->top && tvisfunc(L->base))) - lj_err_argt(L, 1, LUA_TFUNCTION); - L1 = lua_newthread(L); - setfuncV(L, L1->top++, funcV(L->base)); - return 1; -} - -LJLIB_ASM(coroutine_yield) -{ - lj_err_caller(L, LJ_ERR_CYIELD); - return FFH_UNREACHABLE; -} - -static int ffh_resume(lua_State *L, lua_State *co, int wrap) -{ - if (co->cframe != NULL || co->status > LUA_YIELD || - (co->status == LUA_OK && co->top == co->base)) { - ErrMsg em = co->cframe ? LJ_ERR_CORUN : LJ_ERR_CODEAD; - if (wrap) lj_err_caller(L, em); - setboolV(L->base-1-LJ_FR2, 0); - setstrV(L, L->base-LJ_FR2, lj_err_str(L, em)); - return FFH_RES(2); - } - lj_state_growstack(co, (MSize)(L->top - L->base)); - return FFH_RETRY; -} - -LJLIB_ASM(coroutine_resume) -{ - if (!(L->top > L->base && tvisthread(L->base))) - lj_err_arg(L, 1, LJ_ERR_NOCORO); - return ffh_resume(L, threadV(L->base), 0); -} - -LJLIB_NOREG LJLIB_ASM(coroutine_wrap_aux) -{ - return ffh_resume(L, threadV(lj_lib_upvalue(L, 1)), 1); -} - -/* Inline declarations. */ -LJ_ASMF void lj_ff_coroutine_wrap_aux(void); -#if !(LJ_TARGET_MIPS && defined(ljamalg_c)) -LJ_FUNCA_NORET void LJ_FASTCALL lj_ffh_coroutine_wrap_err(lua_State *L, - lua_State *co); -#endif - -/* Error handler, called from assembler VM. */ -void LJ_FASTCALL lj_ffh_coroutine_wrap_err(lua_State *L, lua_State *co) -{ - co->top--; copyTV(L, L->top, co->top); L->top++; - if (tvisstr(L->top-1)) - lj_err_callermsg(L, strVdata(L->top-1)); - else - lj_err_run(L); -} - -/* Forward declaration. */ -static void setpc_wrap_aux(lua_State *L, GCfunc *fn); - -LJLIB_CF(coroutine_wrap) -{ - GCfunc *fn; - lj_cf_coroutine_create(L); - fn = lj_lib_pushcc(L, lj_ffh_coroutine_wrap_aux, FF_coroutine_wrap_aux, 1); - setpc_wrap_aux(L, fn); - return 1; -} - -#include "lj_libdef.h" - -/* Fix the PC of wrap_aux. Really ugly workaround. */ -static void setpc_wrap_aux(lua_State *L, GCfunc *fn) -{ - setmref(fn->c.pc, &L2GG(L)->bcff[lj_lib_init_coroutine[1]+2]); -} - -/* ------------------------------------------------------------------------ */ - -static void newproxy_weaktable(lua_State *L) -{ - /* NOBARRIER: The table is new (marked white). */ - GCtab *t = lj_tab_new(L, 0, 1); - settabV(L, L->top++, t); - setgcref(t->metatable, obj2gco(t)); - setstrV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "__mode")), - lj_str_newlit(L, "kv")); - t->nomm = (uint8_t)(~(1u<env); - settabV(L, lj_tab_setstr(L, env, lj_str_newlit(L, "_G")), env); - lua_pushliteral(L, LUA_VERSION); /* top-3. */ - newproxy_weaktable(L); /* top-2. */ - LJ_LIB_REG(L, "_G", base); - LJ_LIB_REG(L, LUA_COLIBNAME, coroutine); - return 2; -} - diff --git a/lib/LuaJIT/src/lib_bit.c b/lib/LuaJIT/src/lib_bit.c deleted file mode 100644 index c979a44..0000000 --- a/lib/LuaJIT/src/lib_bit.c +++ /dev/null @@ -1,180 +0,0 @@ -/* -** Bit manipulation library. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lib_bit_c -#define LUA_LIB - -#include "lua.h" -#include "lauxlib.h" -#include "lualib.h" - -#include "lj_obj.h" -#include "lj_err.h" -#include "lj_buf.h" -#include "lj_strscan.h" -#include "lj_strfmt.h" -#if LJ_HASFFI -#include "lj_ctype.h" -#include "lj_cdata.h" -#include "lj_cconv.h" -#include "lj_carith.h" -#endif -#include "lj_ff.h" -#include "lj_lib.h" - -/* ------------------------------------------------------------------------ */ - -#define LJLIB_MODULE_bit - -#if LJ_HASFFI -static int bit_result64(lua_State *L, CTypeID id, uint64_t x) -{ - GCcdata *cd = lj_cdata_new_(L, id, 8); - *(uint64_t *)cdataptr(cd) = x; - setcdataV(L, L->base-1-LJ_FR2, cd); - return FFH_RES(1); -} -#else -static int32_t bit_checkbit(lua_State *L, int narg) -{ - TValue *o = L->base + narg-1; - if (!(o < L->top && lj_strscan_numberobj(o))) - lj_err_argt(L, narg, LUA_TNUMBER); - if (LJ_LIKELY(tvisint(o))) { - return intV(o); - } else { - int32_t i = lj_num2bit(numV(o)); - if (LJ_DUALNUM) setintV(o, i); - return i; - } -} -#endif - -LJLIB_ASM(bit_tobit) LJLIB_REC(bit_tobit) -{ -#if LJ_HASFFI - CTypeID id = 0; - setintV(L->base-1-LJ_FR2, (int32_t)lj_carith_check64(L, 1, &id)); - return FFH_RES(1); -#else - lj_lib_checknumber(L, 1); - return FFH_RETRY; -#endif -} - -LJLIB_ASM(bit_bnot) LJLIB_REC(bit_unary IR_BNOT) -{ -#if LJ_HASFFI - CTypeID id = 0; - uint64_t x = lj_carith_check64(L, 1, &id); - return id ? bit_result64(L, id, ~x) : FFH_RETRY; -#else - lj_lib_checknumber(L, 1); - return FFH_RETRY; -#endif -} - -LJLIB_ASM(bit_bswap) LJLIB_REC(bit_unary IR_BSWAP) -{ -#if LJ_HASFFI - CTypeID id = 0; - uint64_t x = lj_carith_check64(L, 1, &id); - return id ? bit_result64(L, id, lj_bswap64(x)) : FFH_RETRY; -#else - lj_lib_checknumber(L, 1); - return FFH_RETRY; -#endif -} - -LJLIB_ASM(bit_lshift) LJLIB_REC(bit_shift IR_BSHL) -{ -#if LJ_HASFFI - CTypeID id = 0, id2 = 0; - uint64_t x = lj_carith_check64(L, 1, &id); - int32_t sh = (int32_t)lj_carith_check64(L, 2, &id2); - if (id) { - x = lj_carith_shift64(x, sh, curr_func(L)->c.ffid - (int)FF_bit_lshift); - return bit_result64(L, id, x); - } - if (id2) setintV(L->base+1, sh); - return FFH_RETRY; -#else - lj_lib_checknumber(L, 1); - bit_checkbit(L, 2); - return FFH_RETRY; -#endif -} -LJLIB_ASM_(bit_rshift) LJLIB_REC(bit_shift IR_BSHR) -LJLIB_ASM_(bit_arshift) LJLIB_REC(bit_shift IR_BSAR) -LJLIB_ASM_(bit_rol) LJLIB_REC(bit_shift IR_BROL) -LJLIB_ASM_(bit_ror) LJLIB_REC(bit_shift IR_BROR) - -LJLIB_ASM(bit_band) LJLIB_REC(bit_nary IR_BAND) -{ -#if LJ_HASFFI - CTypeID id = 0; - TValue *o = L->base, *top = L->top; - int i = 0; - do { lj_carith_check64(L, ++i, &id); } while (++o < top); - if (id) { - CTState *cts = ctype_cts(L); - CType *ct = ctype_get(cts, id); - int op = curr_func(L)->c.ffid - (int)FF_bit_bor; - uint64_t x, y = op >= 0 ? 0 : ~(uint64_t)0; - o = L->base; - do { - lj_cconv_ct_tv(cts, ct, (uint8_t *)&x, o, 0); - if (op < 0) y &= x; else if (op == 0) y |= x; else y ^= x; - } while (++o < top); - return bit_result64(L, id, y); - } - return FFH_RETRY; -#else - int i = 0; - do { lj_lib_checknumber(L, ++i); } while (L->base+i < L->top); - return FFH_RETRY; -#endif -} -LJLIB_ASM_(bit_bor) LJLIB_REC(bit_nary IR_BOR) -LJLIB_ASM_(bit_bxor) LJLIB_REC(bit_nary IR_BXOR) - -/* ------------------------------------------------------------------------ */ - -LJLIB_CF(bit_tohex) LJLIB_REC(.) -{ -#if LJ_HASFFI - CTypeID id = 0, id2 = 0; - uint64_t b = lj_carith_check64(L, 1, &id); - int32_t n = L->base+1>=L->top ? (id ? 16 : 8) : - (int32_t)lj_carith_check64(L, 2, &id2); -#else - uint32_t b = (uint32_t)bit_checkbit(L, 1); - int32_t n = L->base+1>=L->top ? 8 : bit_checkbit(L, 2); -#endif - SBuf *sb = lj_buf_tmp_(L); - SFormat sf = (STRFMT_UINT|STRFMT_T_HEX); - if (n < 0) { n = -n; sf |= STRFMT_F_UPPER; } - sf |= ((SFormat)((n+1)&255) << STRFMT_SH_PREC); -#if LJ_HASFFI - if (n < 16) b &= ((uint64_t)1 << 4*n)-1; -#else - if (n < 8) b &= (1u << 4*n)-1; -#endif - sb = lj_strfmt_putfxint(sb, sf, b); - setstrV(L, L->top-1, lj_buf_str(L, sb)); - lj_gc_check(L); - return 1; -} - -/* ------------------------------------------------------------------------ */ - -#include "lj_libdef.h" - -LUALIB_API int luaopen_bit(lua_State *L) -{ - LJ_LIB_REG(L, LUA_BITLIBNAME, bit); - return 1; -} - diff --git a/lib/LuaJIT/src/lib_debug.c b/lib/LuaJIT/src/lib_debug.c deleted file mode 100644 index f112b5b..0000000 --- a/lib/LuaJIT/src/lib_debug.c +++ /dev/null @@ -1,405 +0,0 @@ -/* -** Debug library. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Major portions taken verbatim or adapted from the Lua interpreter. -** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h -*/ - -#define lib_debug_c -#define LUA_LIB - -#include "lua.h" -#include "lauxlib.h" -#include "lualib.h" - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_debug.h" -#include "lj_lib.h" - -/* ------------------------------------------------------------------------ */ - -#define LJLIB_MODULE_debug - -LJLIB_CF(debug_getregistry) -{ - copyTV(L, L->top++, registry(L)); - return 1; -} - -LJLIB_CF(debug_getmetatable) LJLIB_REC(.) -{ - lj_lib_checkany(L, 1); - if (!lua_getmetatable(L, 1)) { - setnilV(L->top-1); - } - return 1; -} - -LJLIB_CF(debug_setmetatable) -{ - lj_lib_checktabornil(L, 2); - L->top = L->base+2; - lua_setmetatable(L, 1); -#if !LJ_52 - setboolV(L->top-1, 1); -#endif - return 1; -} - -LJLIB_CF(debug_getfenv) -{ - lj_lib_checkany(L, 1); - lua_getfenv(L, 1); - return 1; -} - -LJLIB_CF(debug_setfenv) -{ - lj_lib_checktab(L, 2); - L->top = L->base+2; - if (!lua_setfenv(L, 1)) - lj_err_caller(L, LJ_ERR_SETFENV); - return 1; -} - -/* ------------------------------------------------------------------------ */ - -static void settabss(lua_State *L, const char *i, const char *v) -{ - lua_pushstring(L, v); - lua_setfield(L, -2, i); -} - -static void settabsi(lua_State *L, const char *i, int v) -{ - lua_pushinteger(L, v); - lua_setfield(L, -2, i); -} - -static void settabsb(lua_State *L, const char *i, int v) -{ - lua_pushboolean(L, v); - lua_setfield(L, -2, i); -} - -static lua_State *getthread(lua_State *L, int *arg) -{ - if (L->base < L->top && tvisthread(L->base)) { - *arg = 1; - return threadV(L->base); - } else { - *arg = 0; - return L; - } -} - -static void treatstackoption(lua_State *L, lua_State *L1, const char *fname) -{ - if (L == L1) { - lua_pushvalue(L, -2); - lua_remove(L, -3); - } - else - lua_xmove(L1, L, 1); - lua_setfield(L, -2, fname); -} - -LJLIB_CF(debug_getinfo) -{ - lj_Debug ar; - int arg, opt_f = 0, opt_L = 0; - lua_State *L1 = getthread(L, &arg); - const char *options = luaL_optstring(L, arg+2, "flnSu"); - if (lua_isnumber(L, arg+1)) { - if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), (lua_Debug *)&ar)) { - setnilV(L->top-1); - return 1; - } - } else if (L->base+arg < L->top && tvisfunc(L->base+arg)) { - options = lua_pushfstring(L, ">%s", options); - setfuncV(L1, L1->top++, funcV(L->base+arg)); - } else { - lj_err_arg(L, arg+1, LJ_ERR_NOFUNCL); - } - if (!lj_debug_getinfo(L1, options, &ar, 1)) - lj_err_arg(L, arg+2, LJ_ERR_INVOPT); - lua_createtable(L, 0, 16); /* Create result table. */ - for (; *options; options++) { - switch (*options) { - case 'S': - settabss(L, "source", ar.source); - settabss(L, "short_src", ar.short_src); - settabsi(L, "linedefined", ar.linedefined); - settabsi(L, "lastlinedefined", ar.lastlinedefined); - settabss(L, "what", ar.what); - break; - case 'l': - settabsi(L, "currentline", ar.currentline); - break; - case 'u': - settabsi(L, "nups", ar.nups); - settabsi(L, "nparams", ar.nparams); - settabsb(L, "isvararg", ar.isvararg); - break; - case 'n': - settabss(L, "name", ar.name); - settabss(L, "namewhat", ar.namewhat); - break; - case 'f': opt_f = 1; break; - case 'L': opt_L = 1; break; - default: break; - } - } - if (opt_L) treatstackoption(L, L1, "activelines"); - if (opt_f) treatstackoption(L, L1, "func"); - return 1; /* Return result table. */ -} - -LJLIB_CF(debug_getlocal) -{ - int arg; - lua_State *L1 = getthread(L, &arg); - lua_Debug ar; - const char *name; - int slot = lj_lib_checkint(L, arg+2); - if (tvisfunc(L->base+arg)) { - L->top = L->base+arg+1; - lua_pushstring(L, lua_getlocal(L, NULL, slot)); - return 1; - } - if (!lua_getstack(L1, lj_lib_checkint(L, arg+1), &ar)) - lj_err_arg(L, arg+1, LJ_ERR_LVLRNG); - name = lua_getlocal(L1, &ar, slot); - if (name) { - lua_xmove(L1, L, 1); - lua_pushstring(L, name); - lua_pushvalue(L, -2); - return 2; - } else { - setnilV(L->top-1); - return 1; - } -} - -LJLIB_CF(debug_setlocal) -{ - int arg; - lua_State *L1 = getthread(L, &arg); - lua_Debug ar; - TValue *tv; - if (!lua_getstack(L1, lj_lib_checkint(L, arg+1), &ar)) - lj_err_arg(L, arg+1, LJ_ERR_LVLRNG); - tv = lj_lib_checkany(L, arg+3); - copyTV(L1, L1->top++, tv); - lua_pushstring(L, lua_setlocal(L1, &ar, lj_lib_checkint(L, arg+2))); - return 1; -} - -static int debug_getupvalue(lua_State *L, int get) -{ - int32_t n = lj_lib_checkint(L, 2); - const char *name; - lj_lib_checkfunc(L, 1); - name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); - if (name) { - lua_pushstring(L, name); - if (!get) return 1; - copyTV(L, L->top, L->top-2); - L->top++; - return 2; - } - return 0; -} - -LJLIB_CF(debug_getupvalue) -{ - return debug_getupvalue(L, 1); -} - -LJLIB_CF(debug_setupvalue) -{ - lj_lib_checkany(L, 3); - return debug_getupvalue(L, 0); -} - -LJLIB_CF(debug_upvalueid) -{ - GCfunc *fn = lj_lib_checkfunc(L, 1); - int32_t n = lj_lib_checkint(L, 2) - 1; - if ((uint32_t)n >= fn->l.nupvalues) - lj_err_arg(L, 2, LJ_ERR_IDXRNG); - setlightudV(L->top-1, isluafunc(fn) ? (void *)gcref(fn->l.uvptr[n]) : - (void *)&fn->c.upvalue[n]); - return 1; -} - -LJLIB_CF(debug_upvaluejoin) -{ - GCfunc *fn[2]; - GCRef *p[2]; - int i; - for (i = 0; i < 2; i++) { - int32_t n; - fn[i] = lj_lib_checkfunc(L, 2*i+1); - if (!isluafunc(fn[i])) - lj_err_arg(L, 2*i+1, LJ_ERR_NOLFUNC); - n = lj_lib_checkint(L, 2*i+2) - 1; - if ((uint32_t)n >= fn[i]->l.nupvalues) - lj_err_arg(L, 2*i+2, LJ_ERR_IDXRNG); - p[i] = &fn[i]->l.uvptr[n]; - } - setgcrefr(*p[0], *p[1]); - lj_gc_objbarrier(L, fn[0], gcref(*p[1])); - return 0; -} - -#if LJ_52 -LJLIB_CF(debug_getuservalue) -{ - TValue *o = L->base; - if (o < L->top && tvisudata(o)) - settabV(L, o, tabref(udataV(o)->env)); - else - setnilV(o); - L->top = o+1; - return 1; -} - -LJLIB_CF(debug_setuservalue) -{ - TValue *o = L->base; - if (!(o < L->top && tvisudata(o))) - lj_err_argt(L, 1, LUA_TUSERDATA); - if (!(o+1 < L->top && tvistab(o+1))) - lj_err_argt(L, 2, LUA_TTABLE); - L->top = o+2; - lua_setfenv(L, 1); - return 1; -} -#endif - -/* ------------------------------------------------------------------------ */ - -#define KEY_HOOK ((void *)0x3004) - -static void hookf(lua_State *L, lua_Debug *ar) -{ - static const char *const hooknames[] = - {"call", "return", "line", "count", "tail return"}; - lua_pushlightuserdata(L, KEY_HOOK); - lua_rawget(L, LUA_REGISTRYINDEX); - if (lua_isfunction(L, -1)) { - lua_pushstring(L, hooknames[(int)ar->event]); - if (ar->currentline >= 0) - lua_pushinteger(L, ar->currentline); - else lua_pushnil(L); - lua_call(L, 2, 0); - } -} - -static int makemask(const char *smask, int count) -{ - int mask = 0; - if (strchr(smask, 'c')) mask |= LUA_MASKCALL; - if (strchr(smask, 'r')) mask |= LUA_MASKRET; - if (strchr(smask, 'l')) mask |= LUA_MASKLINE; - if (count > 0) mask |= LUA_MASKCOUNT; - return mask; -} - -static char *unmakemask(int mask, char *smask) -{ - int i = 0; - if (mask & LUA_MASKCALL) smask[i++] = 'c'; - if (mask & LUA_MASKRET) smask[i++] = 'r'; - if (mask & LUA_MASKLINE) smask[i++] = 'l'; - smask[i] = '\0'; - return smask; -} - -LJLIB_CF(debug_sethook) -{ - int arg, mask, count; - lua_Hook func; - (void)getthread(L, &arg); - if (lua_isnoneornil(L, arg+1)) { - lua_settop(L, arg+1); - func = NULL; mask = 0; count = 0; /* turn off hooks */ - } else { - const char *smask = luaL_checkstring(L, arg+2); - luaL_checktype(L, arg+1, LUA_TFUNCTION); - count = luaL_optint(L, arg+3, 0); - func = hookf; mask = makemask(smask, count); - } - lua_pushlightuserdata(L, KEY_HOOK); - lua_pushvalue(L, arg+1); - lua_rawset(L, LUA_REGISTRYINDEX); - lua_sethook(L, func, mask, count); - return 0; -} - -LJLIB_CF(debug_gethook) -{ - char buff[5]; - int mask = lua_gethookmask(L); - lua_Hook hook = lua_gethook(L); - if (hook != NULL && hook != hookf) { /* external hook? */ - lua_pushliteral(L, "external hook"); - } else { - lua_pushlightuserdata(L, KEY_HOOK); - lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */ - } - lua_pushstring(L, unmakemask(mask, buff)); - lua_pushinteger(L, lua_gethookcount(L)); - return 3; -} - -/* ------------------------------------------------------------------------ */ - -LJLIB_CF(debug_debug) -{ - for (;;) { - char buffer[250]; - fputs("lua_debug> ", stderr); - if (fgets(buffer, sizeof(buffer), stdin) == 0 || - strcmp(buffer, "cont\n") == 0) - return 0; - if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || - lua_pcall(L, 0, 0, 0)) { - fputs(lua_tostring(L, -1), stderr); - fputs("\n", stderr); - } - lua_settop(L, 0); /* remove eventual returns */ - } -} - -/* ------------------------------------------------------------------------ */ - -#define LEVELS1 12 /* size of the first part of the stack */ -#define LEVELS2 10 /* size of the second part of the stack */ - -LJLIB_CF(debug_traceback) -{ - int arg; - lua_State *L1 = getthread(L, &arg); - const char *msg = lua_tostring(L, arg+1); - if (msg == NULL && L->top > L->base+arg) - L->top = L->base+arg+1; - else - luaL_traceback(L, L1, msg, lj_lib_optint(L, arg+2, (L == L1))); - return 1; -} - -/* ------------------------------------------------------------------------ */ - -#include "lj_libdef.h" - -LUALIB_API int luaopen_debug(lua_State *L) -{ - LJ_LIB_REG(L, LUA_DBLIBNAME, debug); - return 1; -} - diff --git a/lib/LuaJIT/src/lib_ffi.c b/lib/LuaJIT/src/lib_ffi.c deleted file mode 100644 index 8032411..0000000 --- a/lib/LuaJIT/src/lib_ffi.c +++ /dev/null @@ -1,872 +0,0 @@ -/* -** FFI library. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lib_ffi_c -#define LUA_LIB - -#include - -#include "lua.h" -#include "lauxlib.h" -#include "lualib.h" - -#include "lj_obj.h" - -#if LJ_HASFFI - -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_str.h" -#include "lj_tab.h" -#include "lj_meta.h" -#include "lj_ctype.h" -#include "lj_cparse.h" -#include "lj_cdata.h" -#include "lj_cconv.h" -#include "lj_carith.h" -#include "lj_ccall.h" -#include "lj_ccallback.h" -#include "lj_clib.h" -#include "lj_strfmt.h" -#include "lj_ff.h" -#include "lj_lib.h" - -/* -- C type checks ------------------------------------------------------- */ - -/* Check first argument for a C type and returns its ID. */ -static CTypeID ffi_checkctype(lua_State *L, CTState *cts, TValue *param) -{ - TValue *o = L->base; - if (!(o < L->top)) { - err_argtype: - lj_err_argtype(L, 1, "C type"); - } - if (tvisstr(o)) { /* Parse an abstract C type declaration. */ - GCstr *s = strV(o); - CPState cp; - int errcode; - cp.L = L; - cp.cts = cts; - cp.srcname = strdata(s); - cp.p = strdata(s); - cp.param = param; - cp.mode = CPARSE_MODE_ABSTRACT|CPARSE_MODE_NOIMPLICIT; - errcode = lj_cparse(&cp); - if (errcode) lj_err_throw(L, errcode); /* Propagate errors. */ - return cp.val.id; - } else { - GCcdata *cd; - if (!tviscdata(o)) goto err_argtype; - if (param && param < L->top) lj_err_arg(L, 1, LJ_ERR_FFI_NUMPARAM); - cd = cdataV(o); - return cd->ctypeid == CTID_CTYPEID ? *(CTypeID *)cdataptr(cd) : cd->ctypeid; - } -} - -/* Check argument for C data and return it. */ -static GCcdata *ffi_checkcdata(lua_State *L, int narg) -{ - TValue *o = L->base + narg-1; - if (!(o < L->top && tviscdata(o))) - lj_err_argt(L, narg, LUA_TCDATA); - return cdataV(o); -} - -/* Convert argument to C pointer. */ -static void *ffi_checkptr(lua_State *L, int narg, CTypeID id) -{ - CTState *cts = ctype_cts(L); - TValue *o = L->base + narg-1; - void *p; - if (o >= L->top) - lj_err_arg(L, narg, LJ_ERR_NOVAL); - lj_cconv_ct_tv(cts, ctype_get(cts, id), (uint8_t *)&p, o, CCF_ARG(narg)); - return p; -} - -/* Convert argument to int32_t. */ -static int32_t ffi_checkint(lua_State *L, int narg) -{ - CTState *cts = ctype_cts(L); - TValue *o = L->base + narg-1; - int32_t i; - if (o >= L->top) - lj_err_arg(L, narg, LJ_ERR_NOVAL); - lj_cconv_ct_tv(cts, ctype_get(cts, CTID_INT32), (uint8_t *)&i, o, - CCF_ARG(narg)); - return i; -} - -/* -- C type metamethods -------------------------------------------------- */ - -#define LJLIB_MODULE_ffi_meta - -/* Handle ctype __index/__newindex metamethods. */ -static int ffi_index_meta(lua_State *L, CTState *cts, CType *ct, MMS mm) -{ - CTypeID id = ctype_typeid(cts, ct); - cTValue *tv = lj_ctype_meta(cts, id, mm); - TValue *base = L->base; - if (!tv) { - const char *s; - err_index: - s = strdata(lj_ctype_repr(L, id, NULL)); - if (tvisstr(L->base+1)) { - lj_err_callerv(L, LJ_ERR_FFI_BADMEMBER, s, strVdata(L->base+1)); - } else { - const char *key = tviscdata(L->base+1) ? - strdata(lj_ctype_repr(L, cdataV(L->base+1)->ctypeid, NULL)) : - lj_typename(L->base+1); - lj_err_callerv(L, LJ_ERR_FFI_BADIDXW, s, key); - } - } - if (!tvisfunc(tv)) { - if (mm == MM_index) { - cTValue *o = lj_meta_tget(L, tv, base+1); - if (o) { - if (tvisnil(o)) goto err_index; - copyTV(L, L->top-1, o); - return 1; - } - } else { - TValue *o = lj_meta_tset(L, tv, base+1); - if (o) { - copyTV(L, o, base+2); - return 0; - } - } - copyTV(L, base, L->top); - tv = L->top-1-LJ_FR2; - } - return lj_meta_tailcall(L, tv); -} - -LJLIB_CF(ffi_meta___index) LJLIB_REC(cdata_index 0) -{ - CTState *cts = ctype_cts(L); - CTInfo qual = 0; - CType *ct; - uint8_t *p; - TValue *o = L->base; - if (!(o+1 < L->top && tviscdata(o))) /* Also checks for presence of key. */ - lj_err_argt(L, 1, LUA_TCDATA); - ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual); - if ((qual & 1)) - return ffi_index_meta(L, cts, ct, MM_index); - if (lj_cdata_get(cts, ct, L->top-1, p)) - lj_gc_check(L); - return 1; -} - -LJLIB_CF(ffi_meta___newindex) LJLIB_REC(cdata_index 1) -{ - CTState *cts = ctype_cts(L); - CTInfo qual = 0; - CType *ct; - uint8_t *p; - TValue *o = L->base; - if (!(o+2 < L->top && tviscdata(o))) /* Also checks for key and value. */ - lj_err_argt(L, 1, LUA_TCDATA); - ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual); - if ((qual & 1)) { - if ((qual & CTF_CONST)) - lj_err_caller(L, LJ_ERR_FFI_WRCONST); - return ffi_index_meta(L, cts, ct, MM_newindex); - } - lj_cdata_set(cts, ct, p, o+2, qual); - return 0; -} - -/* Common handler for cdata arithmetic. */ -static int ffi_arith(lua_State *L) -{ - MMS mm = (MMS)(curr_func(L)->c.ffid - (int)FF_ffi_meta___eq + (int)MM_eq); - return lj_carith_op(L, mm); -} - -/* The following functions must be in contiguous ORDER MM. */ -LJLIB_CF(ffi_meta___eq) LJLIB_REC(cdata_arith MM_eq) -{ - return ffi_arith(L); -} - -LJLIB_CF(ffi_meta___len) LJLIB_REC(cdata_arith MM_len) -{ - return lj_carith_len(L); -} - -LJLIB_CF(ffi_meta___lt) LJLIB_REC(cdata_arith MM_lt) -{ - return ffi_arith(L); -} - -LJLIB_CF(ffi_meta___le) LJLIB_REC(cdata_arith MM_le) -{ - return ffi_arith(L); -} - -LJLIB_CF(ffi_meta___concat) LJLIB_REC(cdata_arith MM_concat) -{ - return ffi_arith(L); -} - -/* Forward declaration. */ -static int lj_cf_ffi_new(lua_State *L); - -LJLIB_CF(ffi_meta___call) LJLIB_REC(cdata_call) -{ - CTState *cts = ctype_cts(L); - GCcdata *cd = ffi_checkcdata(L, 1); - CTypeID id = cd->ctypeid; - CType *ct; - cTValue *tv; - MMS mm = MM_call; - if (cd->ctypeid == CTID_CTYPEID) { - id = *(CTypeID *)cdataptr(cd); - mm = MM_new; - } else { - int ret = lj_ccall_func(L, cd); - if (ret >= 0) - return ret; - } - /* Handle ctype __call/__new metamethod. */ - ct = ctype_raw(cts, id); - if (ctype_isptr(ct->info)) id = ctype_cid(ct->info); - tv = lj_ctype_meta(cts, id, mm); - if (tv) - return lj_meta_tailcall(L, tv); - else if (mm == MM_call) - lj_err_callerv(L, LJ_ERR_FFI_BADCALL, strdata(lj_ctype_repr(L, id, NULL))); - return lj_cf_ffi_new(L); -} - -LJLIB_CF(ffi_meta___add) LJLIB_REC(cdata_arith MM_add) -{ - return ffi_arith(L); -} - -LJLIB_CF(ffi_meta___sub) LJLIB_REC(cdata_arith MM_sub) -{ - return ffi_arith(L); -} - -LJLIB_CF(ffi_meta___mul) LJLIB_REC(cdata_arith MM_mul) -{ - return ffi_arith(L); -} - -LJLIB_CF(ffi_meta___div) LJLIB_REC(cdata_arith MM_div) -{ - return ffi_arith(L); -} - -LJLIB_CF(ffi_meta___mod) LJLIB_REC(cdata_arith MM_mod) -{ - return ffi_arith(L); -} - -LJLIB_CF(ffi_meta___pow) LJLIB_REC(cdata_arith MM_pow) -{ - return ffi_arith(L); -} - -LJLIB_CF(ffi_meta___unm) LJLIB_REC(cdata_arith MM_unm) -{ - return ffi_arith(L); -} -/* End of contiguous ORDER MM. */ - -LJLIB_CF(ffi_meta___tostring) -{ - GCcdata *cd = ffi_checkcdata(L, 1); - const char *msg = "cdata<%s>: %p"; - CTypeID id = cd->ctypeid; - void *p = cdataptr(cd); - if (id == CTID_CTYPEID) { - msg = "ctype<%s>"; - id = *(CTypeID *)p; - } else { - CTState *cts = ctype_cts(L); - CType *ct = ctype_raw(cts, id); - if (ctype_isref(ct->info)) { - p = *(void **)p; - ct = ctype_rawchild(cts, ct); - } - if (ctype_iscomplex(ct->info)) { - setstrV(L, L->top-1, lj_ctype_repr_complex(L, cdataptr(cd), ct->size)); - goto checkgc; - } else if (ct->size == 8 && ctype_isinteger(ct->info)) { - setstrV(L, L->top-1, lj_ctype_repr_int64(L, *(uint64_t *)cdataptr(cd), - (ct->info & CTF_UNSIGNED))); - goto checkgc; - } else if (ctype_isfunc(ct->info)) { - p = *(void **)p; - } else if (ctype_isenum(ct->info)) { - msg = "cdata<%s>: %d"; - p = (void *)(uintptr_t)*(uint32_t **)p; - } else { - if (ctype_isptr(ct->info)) { - p = cdata_getptr(p, ct->size); - ct = ctype_rawchild(cts, ct); - } - if (ctype_isstruct(ct->info) || ctype_isvector(ct->info)) { - /* Handle ctype __tostring metamethod. */ - cTValue *tv = lj_ctype_meta(cts, ctype_typeid(cts, ct), MM_tostring); - if (tv) - return lj_meta_tailcall(L, tv); - } - } - } - lj_strfmt_pushf(L, msg, strdata(lj_ctype_repr(L, id, NULL)), p); -checkgc: - lj_gc_check(L); - return 1; -} - -static int ffi_pairs(lua_State *L, MMS mm) -{ - CTState *cts = ctype_cts(L); - CTypeID id = ffi_checkcdata(L, 1)->ctypeid; - CType *ct = ctype_raw(cts, id); - cTValue *tv; - if (ctype_isptr(ct->info)) id = ctype_cid(ct->info); - tv = lj_ctype_meta(cts, id, mm); - if (!tv) - lj_err_callerv(L, LJ_ERR_FFI_BADMM, strdata(lj_ctype_repr(L, id, NULL)), - strdata(mmname_str(G(L), mm))); - return lj_meta_tailcall(L, tv); -} - -LJLIB_CF(ffi_meta___pairs) -{ - return ffi_pairs(L, MM_pairs); -} - -LJLIB_CF(ffi_meta___ipairs) -{ - return ffi_pairs(L, MM_ipairs); -} - -LJLIB_PUSH("ffi") LJLIB_SET(__metatable) - -#include "lj_libdef.h" - -/* -- C library metamethods ----------------------------------------------- */ - -#define LJLIB_MODULE_ffi_clib - -/* Index C library by a name. */ -static TValue *ffi_clib_index(lua_State *L) -{ - TValue *o = L->base; - CLibrary *cl; - if (!(o < L->top && tvisudata(o) && udataV(o)->udtype == UDTYPE_FFI_CLIB)) - lj_err_argt(L, 1, LUA_TUSERDATA); - cl = (CLibrary *)uddata(udataV(o)); - if (!(o+1 < L->top && tvisstr(o+1))) - lj_err_argt(L, 2, LUA_TSTRING); - return lj_clib_index(L, cl, strV(o+1)); -} - -LJLIB_CF(ffi_clib___index) LJLIB_REC(clib_index 1) -{ - TValue *tv = ffi_clib_index(L); - if (tviscdata(tv)) { - CTState *cts = ctype_cts(L); - GCcdata *cd = cdataV(tv); - CType *s = ctype_get(cts, cd->ctypeid); - if (ctype_isextern(s->info)) { - CTypeID sid = ctype_cid(s->info); - void *sp = *(void **)cdataptr(cd); - CType *ct = ctype_raw(cts, sid); - if (lj_cconv_tv_ct(cts, ct, sid, L->top-1, sp)) - lj_gc_check(L); - return 1; - } - } - copyTV(L, L->top-1, tv); - return 1; -} - -LJLIB_CF(ffi_clib___newindex) LJLIB_REC(clib_index 0) -{ - TValue *tv = ffi_clib_index(L); - TValue *o = L->base+2; - if (o < L->top && tviscdata(tv)) { - CTState *cts = ctype_cts(L); - GCcdata *cd = cdataV(tv); - CType *d = ctype_get(cts, cd->ctypeid); - if (ctype_isextern(d->info)) { - CTInfo qual = 0; - for (;;) { /* Skip attributes and collect qualifiers. */ - d = ctype_child(cts, d); - if (!ctype_isattrib(d->info)) break; - if (ctype_attrib(d->info) == CTA_QUAL) qual |= d->size; - } - if (!((d->info|qual) & CTF_CONST)) { - lj_cconv_ct_tv(cts, d, *(void **)cdataptr(cd), o, 0); - return 0; - } - } - } - lj_err_caller(L, LJ_ERR_FFI_WRCONST); - return 0; /* unreachable */ -} - -LJLIB_CF(ffi_clib___gc) -{ - TValue *o = L->base; - if (o < L->top && tvisudata(o) && udataV(o)->udtype == UDTYPE_FFI_CLIB) - lj_clib_unload((CLibrary *)uddata(udataV(o))); - return 0; -} - -#include "lj_libdef.h" - -/* -- Callback function metamethods --------------------------------------- */ - -#define LJLIB_MODULE_ffi_callback - -static int ffi_callback_set(lua_State *L, GCfunc *fn) -{ - GCcdata *cd = ffi_checkcdata(L, 1); - CTState *cts = ctype_cts(L); - CType *ct = ctype_raw(cts, cd->ctypeid); - if (ctype_isptr(ct->info) && (LJ_32 || ct->size == 8)) { - MSize slot = lj_ccallback_ptr2slot(cts, *(void **)cdataptr(cd)); - if (slot < cts->cb.sizeid && cts->cb.cbid[slot] != 0) { - GCtab *t = cts->miscmap; - TValue *tv = lj_tab_setint(L, t, (int32_t)slot); - if (fn) { - setfuncV(L, tv, fn); - lj_gc_anybarriert(L, t); - } else { - setnilV(tv); - cts->cb.cbid[slot] = 0; - cts->cb.topid = slot < cts->cb.topid ? slot : cts->cb.topid; - } - return 0; - } - } - lj_err_caller(L, LJ_ERR_FFI_BADCBACK); - return 0; -} - -LJLIB_CF(ffi_callback_free) -{ - return ffi_callback_set(L, NULL); -} - -LJLIB_CF(ffi_callback_set) -{ - GCfunc *fn = lj_lib_checkfunc(L, 2); - return ffi_callback_set(L, fn); -} - -LJLIB_PUSH(top-1) LJLIB_SET(__index) - -#include "lj_libdef.h" - -/* -- FFI library functions ----------------------------------------------- */ - -#define LJLIB_MODULE_ffi - -LJLIB_CF(ffi_cdef) -{ - GCstr *s = lj_lib_checkstr(L, 1); - CPState cp; - int errcode; - cp.L = L; - cp.cts = ctype_cts(L); - cp.srcname = strdata(s); - cp.p = strdata(s); - cp.param = L->base+1; - cp.mode = CPARSE_MODE_MULTI|CPARSE_MODE_DIRECT; - errcode = lj_cparse(&cp); - if (errcode) lj_err_throw(L, errcode); /* Propagate errors. */ - lj_gc_check(L); - return 0; -} - -LJLIB_CF(ffi_new) LJLIB_REC(.) -{ - CTState *cts = ctype_cts(L); - CTypeID id = ffi_checkctype(L, cts, NULL); - CType *ct = ctype_raw(cts, id); - CTSize sz; - CTInfo info = lj_ctype_info(cts, id, &sz); - TValue *o = L->base+1; - GCcdata *cd; - if ((info & CTF_VLA)) { - o++; - sz = lj_ctype_vlsize(cts, ct, (CTSize)ffi_checkint(L, 2)); - } - if (sz == CTSIZE_INVALID) - lj_err_arg(L, 1, LJ_ERR_FFI_INVSIZE); - cd = lj_cdata_newx(cts, id, sz, info); - setcdataV(L, o-1, cd); /* Anchor the uninitialized cdata. */ - lj_cconv_ct_init(cts, ct, sz, cdataptr(cd), - o, (MSize)(L->top - o)); /* Initialize cdata. */ - if (ctype_isstruct(ct->info)) { - /* Handle ctype __gc metamethod. Use the fast lookup here. */ - cTValue *tv = lj_tab_getinth(cts->miscmap, -(int32_t)id); - if (tv && tvistab(tv) && (tv = lj_meta_fast(L, tabV(tv), MM_gc))) { - GCtab *t = cts->finalizer; - if (gcref(t->metatable)) { - /* Add to finalizer table, if still enabled. */ - copyTV(L, lj_tab_set(L, t, o-1), tv); - lj_gc_anybarriert(L, t); - cd->marked |= LJ_GC_CDATA_FIN; - } - } - } - L->top = o; /* Only return the cdata itself. */ - lj_gc_check(L); - return 1; -} - -LJLIB_CF(ffi_cast) LJLIB_REC(ffi_new) -{ - CTState *cts = ctype_cts(L); - CTypeID id = ffi_checkctype(L, cts, NULL); - CType *d = ctype_raw(cts, id); - TValue *o = lj_lib_checkany(L, 2); - L->top = o+1; /* Make sure this is the last item on the stack. */ - if (!(ctype_isnum(d->info) || ctype_isptr(d->info) || ctype_isenum(d->info))) - lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE); - if (!(tviscdata(o) && cdataV(o)->ctypeid == id)) { - GCcdata *cd = lj_cdata_new(cts, id, d->size); - lj_cconv_ct_tv(cts, d, cdataptr(cd), o, CCF_CAST); - setcdataV(L, o, cd); - lj_gc_check(L); - } - return 1; -} - -LJLIB_CF(ffi_typeof) LJLIB_REC(.) -{ - CTState *cts = ctype_cts(L); - CTypeID id = ffi_checkctype(L, cts, L->base+1); - GCcdata *cd = lj_cdata_new(cts, CTID_CTYPEID, 4); - *(CTypeID *)cdataptr(cd) = id; - setcdataV(L, L->top-1, cd); - lj_gc_check(L); - return 1; -} - -/* Internal and unsupported API. */ -LJLIB_CF(ffi_typeinfo) -{ - CTState *cts = ctype_cts(L); - CTypeID id = (CTypeID)ffi_checkint(L, 1); - if (id > 0 && id < cts->top) { - CType *ct = ctype_get(cts, id); - GCtab *t; - lua_createtable(L, 0, 4); /* Increment hash size if fields are added. */ - t = tabV(L->top-1); - setintV(lj_tab_setstr(L, t, lj_str_newlit(L, "info")), (int32_t)ct->info); - if (ct->size != CTSIZE_INVALID) - setintV(lj_tab_setstr(L, t, lj_str_newlit(L, "size")), (int32_t)ct->size); - if (ct->sib) - setintV(lj_tab_setstr(L, t, lj_str_newlit(L, "sib")), (int32_t)ct->sib); - if (gcref(ct->name)) { - GCstr *s = gco2str(gcref(ct->name)); - setstrV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "name")), s); - } - lj_gc_check(L); - return 1; - } - return 0; -} - -LJLIB_CF(ffi_istype) LJLIB_REC(.) -{ - CTState *cts = ctype_cts(L); - CTypeID id1 = ffi_checkctype(L, cts, NULL); - TValue *o = lj_lib_checkany(L, 2); - int b = 0; - if (tviscdata(o)) { - GCcdata *cd = cdataV(o); - CTypeID id2 = cd->ctypeid == CTID_CTYPEID ? *(CTypeID *)cdataptr(cd) : - cd->ctypeid; - CType *ct1 = lj_ctype_rawref(cts, id1); - CType *ct2 = lj_ctype_rawref(cts, id2); - if (ct1 == ct2) { - b = 1; - } else if (ctype_type(ct1->info) == ctype_type(ct2->info) && - ct1->size == ct2->size) { - if (ctype_ispointer(ct1->info)) - b = lj_cconv_compatptr(cts, ct1, ct2, CCF_IGNQUAL); - else if (ctype_isnum(ct1->info) || ctype_isvoid(ct1->info)) - b = (((ct1->info ^ ct2->info) & ~(CTF_QUAL|CTF_LONG)) == 0); - } else if (ctype_isstruct(ct1->info) && ctype_isptr(ct2->info) && - ct1 == ctype_rawchild(cts, ct2)) { - b = 1; - } - } - setboolV(L->top-1, b); - setboolV(&G(L)->tmptv2, b); /* Remember for trace recorder. */ - return 1; -} - -LJLIB_CF(ffi_sizeof) LJLIB_REC(ffi_xof FF_ffi_sizeof) -{ - CTState *cts = ctype_cts(L); - CTypeID id = ffi_checkctype(L, cts, NULL); - CTSize sz; - if (LJ_UNLIKELY(tviscdata(L->base) && cdataisv(cdataV(L->base)))) { - sz = cdatavlen(cdataV(L->base)); - } else { - CType *ct = lj_ctype_rawref(cts, id); - if (ctype_isvltype(ct->info)) - sz = lj_ctype_vlsize(cts, ct, (CTSize)ffi_checkint(L, 2)); - else - sz = ctype_hassize(ct->info) ? ct->size : CTSIZE_INVALID; - if (LJ_UNLIKELY(sz == CTSIZE_INVALID)) { - setnilV(L->top-1); - return 1; - } - } - setintV(L->top-1, (int32_t)sz); - return 1; -} - -LJLIB_CF(ffi_alignof) LJLIB_REC(ffi_xof FF_ffi_alignof) -{ - CTState *cts = ctype_cts(L); - CTypeID id = ffi_checkctype(L, cts, NULL); - CTSize sz = 0; - CTInfo info = lj_ctype_info(cts, id, &sz); - setintV(L->top-1, 1 << ctype_align(info)); - return 1; -} - -LJLIB_CF(ffi_offsetof) LJLIB_REC(ffi_xof FF_ffi_offsetof) -{ - CTState *cts = ctype_cts(L); - CTypeID id = ffi_checkctype(L, cts, NULL); - GCstr *name = lj_lib_checkstr(L, 2); - CType *ct = lj_ctype_rawref(cts, id); - CTSize ofs; - if (ctype_isstruct(ct->info) && ct->size != CTSIZE_INVALID) { - CType *fct = lj_ctype_getfield(cts, ct, name, &ofs); - if (fct) { - setintV(L->top-1, ofs); - if (ctype_isfield(fct->info)) { - return 1; - } else if (ctype_isbitfield(fct->info)) { - setintV(L->top++, ctype_bitpos(fct->info)); - setintV(L->top++, ctype_bitbsz(fct->info)); - return 3; - } - } - } - return 0; -} - -LJLIB_CF(ffi_errno) LJLIB_REC(.) -{ - int err = errno; - if (L->top > L->base) - errno = ffi_checkint(L, 1); - setintV(L->top++, err); - return 1; -} - -LJLIB_CF(ffi_string) LJLIB_REC(.) -{ - CTState *cts = ctype_cts(L); - TValue *o = lj_lib_checkany(L, 1); - const char *p; - size_t len; - if (o+1 < L->top && !tvisnil(o+1)) { - len = (size_t)ffi_checkint(L, 2); - lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p, o, - CCF_ARG(1)); - } else { - lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CCHAR), (uint8_t *)&p, o, - CCF_ARG(1)); - len = strlen(p); - } - L->top = o+1; /* Make sure this is the last item on the stack. */ - setstrV(L, o, lj_str_new(L, p, len)); - lj_gc_check(L); - return 1; -} - -LJLIB_CF(ffi_copy) LJLIB_REC(.) -{ - void *dp = ffi_checkptr(L, 1, CTID_P_VOID); - void *sp = ffi_checkptr(L, 2, CTID_P_CVOID); - TValue *o = L->base+1; - CTSize len; - if (tvisstr(o) && o+1 >= L->top) - len = strV(o)->len+1; /* Copy Lua string including trailing '\0'. */ - else - len = (CTSize)ffi_checkint(L, 3); - memcpy(dp, sp, len); - return 0; -} - -LJLIB_CF(ffi_fill) LJLIB_REC(.) -{ - void *dp = ffi_checkptr(L, 1, CTID_P_VOID); - CTSize len = (CTSize)ffi_checkint(L, 2); - int32_t fill = 0; - if (L->base+2 < L->top && !tvisnil(L->base+2)) fill = ffi_checkint(L, 3); - memset(dp, fill, len); - return 0; -} - -#define H_(le, be) LJ_ENDIAN_SELECT(0x##le, 0x##be) - -/* Test ABI string. */ -LJLIB_CF(ffi_abi) LJLIB_REC(.) -{ - GCstr *s = lj_lib_checkstr(L, 1); - int b = 0; - switch (s->hash) { -#if LJ_64 - case H_(849858eb,ad35fd06): b = 1; break; /* 64bit */ -#else - case H_(662d3c79,d0e22477): b = 1; break; /* 32bit */ -#endif -#if LJ_ARCH_HASFPU - case H_(e33ee463,e33ee463): b = 1; break; /* fpu */ -#endif -#if LJ_ABI_SOFTFP - case H_(61211a23,c2e8c81c): b = 1; break; /* softfp */ -#else - case H_(539417a8,8ce0812f): b = 1; break; /* hardfp */ -#endif -#if LJ_ABI_EABI - case H_(2182df8f,f2ed1152): b = 1; break; /* eabi */ -#endif -#if LJ_ABI_WIN - case H_(4ab624a8,4ab624a8): b = 1; break; /* win */ -#endif -#if LJ_TARGET_UWP - case H_(a40f0bcb,a40f0bcb): b = 1; break; /* uwp */ -#endif - case H_(3af93066,1f001464): b = 1; break; /* le/be */ -#if LJ_GC64 - case H_(9e89d2c9,13c83c92): b = 1; break; /* gc64 */ -#endif - default: - break; - } - setboolV(L->top-1, b); - setboolV(&G(L)->tmptv2, b); /* Remember for trace recorder. */ - return 1; -} - -#undef H_ - -LJLIB_PUSH(top-8) LJLIB_SET(!) /* Store reference to miscmap table. */ - -LJLIB_CF(ffi_metatype) -{ - CTState *cts = ctype_cts(L); - CTypeID id = ffi_checkctype(L, cts, NULL); - GCtab *mt = lj_lib_checktab(L, 2); - GCtab *t = cts->miscmap; - CType *ct = ctype_get(cts, id); /* Only allow raw types. */ - TValue *tv; - GCcdata *cd; - if (!(ctype_isstruct(ct->info) || ctype_iscomplex(ct->info) || - ctype_isvector(ct->info))) - lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE); - tv = lj_tab_setinth(L, t, -(int32_t)id); - if (!tvisnil(tv)) - lj_err_caller(L, LJ_ERR_PROTMT); - settabV(L, tv, mt); - lj_gc_anybarriert(L, t); - cd = lj_cdata_new(cts, CTID_CTYPEID, 4); - *(CTypeID *)cdataptr(cd) = id; - setcdataV(L, L->top-1, cd); - lj_gc_check(L); - return 1; -} - -LJLIB_PUSH(top-7) LJLIB_SET(!) /* Store reference to finalizer table. */ - -LJLIB_CF(ffi_gc) LJLIB_REC(.) -{ - GCcdata *cd = ffi_checkcdata(L, 1); - TValue *fin = lj_lib_checkany(L, 2); - CTState *cts = ctype_cts(L); - CType *ct = ctype_raw(cts, cd->ctypeid); - if (!(ctype_isptr(ct->info) || ctype_isstruct(ct->info) || - ctype_isrefarray(ct->info))) - lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE); - lj_cdata_setfin(L, cd, gcval(fin), itype(fin)); - L->top = L->base+1; /* Pass through the cdata object. */ - return 1; -} - -LJLIB_PUSH(top-5) LJLIB_SET(!) /* Store clib metatable in func environment. */ - -LJLIB_CF(ffi_load) -{ - GCstr *name = lj_lib_checkstr(L, 1); - int global = (L->base+1 < L->top && tvistruecond(L->base+1)); - lj_clib_load(L, tabref(curr_func(L)->c.env), name, global); - return 1; -} - -LJLIB_PUSH(top-4) LJLIB_SET(C) -LJLIB_PUSH(top-3) LJLIB_SET(os) -LJLIB_PUSH(top-2) LJLIB_SET(arch) - -#include "lj_libdef.h" - -/* ------------------------------------------------------------------------ */ - -/* Create special weak-keyed finalizer table. */ -static GCtab *ffi_finalizer(lua_State *L) -{ - /* NOBARRIER: The table is new (marked white). */ - GCtab *t = lj_tab_new(L, 0, 1); - settabV(L, L->top++, t); - setgcref(t->metatable, obj2gco(t)); - setstrV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "__mode")), - lj_str_newlit(L, "k")); - t->nomm = (uint8_t)(~(1u<top-1); - lj_gc_anybarriert(L, t); - } -} - -LUALIB_API int luaopen_ffi(lua_State *L) -{ - CTState *cts = lj_ctype_init(L); - settabV(L, L->top++, (cts->miscmap = lj_tab_new(L, 0, 1))); - cts->finalizer = ffi_finalizer(L); - LJ_LIB_REG(L, NULL, ffi_meta); - /* NOBARRIER: basemt is a GC root. */ - setgcref(basemt_it(G(L), LJ_TCDATA), obj2gco(tabV(L->top-1))); - LJ_LIB_REG(L, NULL, ffi_clib); - LJ_LIB_REG(L, NULL, ffi_callback); - /* NOBARRIER: the key is new and lj_tab_newkey() handles the barrier. */ - settabV(L, lj_tab_setstr(L, cts->miscmap, &cts->g->strempty), tabV(L->top-1)); - L->top--; - lj_clib_default(L, tabV(L->top-1)); /* Create ffi.C default namespace. */ - lua_pushliteral(L, LJ_OS_NAME); - lua_pushliteral(L, LJ_ARCH_NAME); - LJ_LIB_REG(L, NULL, ffi); /* Note: no global "ffi" created! */ - ffi_register_module(L); - return 1; -} - -#endif diff --git a/lib/LuaJIT/src/lib_init.c b/lib/LuaJIT/src/lib_init.c deleted file mode 100644 index 2ed370e..0000000 --- a/lib/LuaJIT/src/lib_init.c +++ /dev/null @@ -1,55 +0,0 @@ -/* -** Library initialization. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Major parts taken verbatim from the Lua interpreter. -** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h -*/ - -#define lib_init_c -#define LUA_LIB - -#include "lua.h" -#include "lauxlib.h" -#include "lualib.h" - -#include "lj_arch.h" - -static const luaL_Reg lj_lib_load[] = { - { "", luaopen_base }, - { LUA_LOADLIBNAME, luaopen_package }, - { LUA_TABLIBNAME, luaopen_table }, - { LUA_IOLIBNAME, luaopen_io }, - { LUA_OSLIBNAME, luaopen_os }, - { LUA_STRLIBNAME, luaopen_string }, - { LUA_MATHLIBNAME, luaopen_math }, - { LUA_DBLIBNAME, luaopen_debug }, - { LUA_BITLIBNAME, luaopen_bit }, - { LUA_JITLIBNAME, luaopen_jit }, - { NULL, NULL } -}; - -static const luaL_Reg lj_lib_preload[] = { -#if LJ_HASFFI - { LUA_FFILIBNAME, luaopen_ffi }, -#endif - { NULL, NULL } -}; - -LUALIB_API void luaL_openlibs(lua_State *L) -{ - const luaL_Reg *lib; - for (lib = lj_lib_load; lib->func; lib++) { - lua_pushcfunction(L, lib->func); - lua_pushstring(L, lib->name); - lua_call(L, 1, 0); - } - luaL_findtable(L, LUA_REGISTRYINDEX, "_PRELOAD", - sizeof(lj_lib_preload)/sizeof(lj_lib_preload[0])-1); - for (lib = lj_lib_preload; lib->func; lib++) { - lua_pushcfunction(L, lib->func); - lua_setfield(L, -2, lib->name); - } - lua_pop(L, 1); -} - diff --git a/lib/LuaJIT/src/lib_io.c b/lib/LuaJIT/src/lib_io.c deleted file mode 100644 index 73fd932..0000000 --- a/lib/LuaJIT/src/lib_io.c +++ /dev/null @@ -1,539 +0,0 @@ -/* -** I/O library. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Major portions taken verbatim or adapted from the Lua interpreter. -** Copyright (C) 1994-2011 Lua.org, PUC-Rio. See Copyright Notice in lua.h -*/ - -#include -#include - -#define lib_io_c -#define LUA_LIB - -#include "lua.h" -#include "lauxlib.h" -#include "lualib.h" - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_buf.h" -#include "lj_str.h" -#include "lj_state.h" -#include "lj_strfmt.h" -#include "lj_ff.h" -#include "lj_lib.h" - -/* Userdata payload for I/O file. */ -typedef struct IOFileUD { - FILE *fp; /* File handle. */ - uint32_t type; /* File type. */ -} IOFileUD; - -#define IOFILE_TYPE_FILE 0 /* Regular file. */ -#define IOFILE_TYPE_PIPE 1 /* Pipe. */ -#define IOFILE_TYPE_STDF 2 /* Standard file handle. */ -#define IOFILE_TYPE_MASK 3 - -#define IOFILE_FLAG_CLOSE 4 /* Close after io.lines() iterator. */ - -#define IOSTDF_UD(L, id) (&gcref(G(L)->gcroot[(id)])->ud) -#define IOSTDF_IOF(L, id) ((IOFileUD *)uddata(IOSTDF_UD(L, (id)))) - -/* -- Open/close helpers -------------------------------------------------- */ - -static IOFileUD *io_tofilep(lua_State *L) -{ - if (!(L->base < L->top && tvisudata(L->base) && - udataV(L->base)->udtype == UDTYPE_IO_FILE)) - lj_err_argtype(L, 1, "FILE*"); - return (IOFileUD *)uddata(udataV(L->base)); -} - -static IOFileUD *io_tofile(lua_State *L) -{ - IOFileUD *iof = io_tofilep(L); - if (iof->fp == NULL) - lj_err_caller(L, LJ_ERR_IOCLFL); - return iof; -} - -static FILE *io_stdfile(lua_State *L, ptrdiff_t id) -{ - IOFileUD *iof = IOSTDF_IOF(L, id); - if (iof->fp == NULL) - lj_err_caller(L, LJ_ERR_IOSTDCL); - return iof->fp; -} - -static IOFileUD *io_file_new(lua_State *L) -{ - IOFileUD *iof = (IOFileUD *)lua_newuserdata(L, sizeof(IOFileUD)); - GCudata *ud = udataV(L->top-1); - ud->udtype = UDTYPE_IO_FILE; - /* NOBARRIER: The GCudata is new (marked white). */ - setgcrefr(ud->metatable, curr_func(L)->c.env); - iof->fp = NULL; - iof->type = IOFILE_TYPE_FILE; - return iof; -} - -static IOFileUD *io_file_open(lua_State *L, const char *mode) -{ - const char *fname = strdata(lj_lib_checkstr(L, 1)); - IOFileUD *iof = io_file_new(L); - iof->fp = fopen(fname, mode); - if (iof->fp == NULL) - luaL_argerror(L, 1, lj_strfmt_pushf(L, "%s: %s", fname, strerror(errno))); - return iof; -} - -static int io_file_close(lua_State *L, IOFileUD *iof) -{ - int ok; - if ((iof->type & IOFILE_TYPE_MASK) == IOFILE_TYPE_FILE) { - ok = (fclose(iof->fp) == 0); - } else if ((iof->type & IOFILE_TYPE_MASK) == IOFILE_TYPE_PIPE) { - int stat = -1; -#if LJ_TARGET_POSIX - stat = pclose(iof->fp); -#elif LJ_TARGET_WINDOWS && !LJ_TARGET_XBOXONE && !LJ_TARGET_UWP - stat = _pclose(iof->fp); -#else - lua_assert(0); - return 0; -#endif -#if LJ_52 - iof->fp = NULL; - return luaL_execresult(L, stat); -#else - ok = (stat != -1); -#endif - } else { - lua_assert((iof->type & IOFILE_TYPE_MASK) == IOFILE_TYPE_STDF); - setnilV(L->top++); - lua_pushliteral(L, "cannot close standard file"); - return 2; - } - iof->fp = NULL; - return luaL_fileresult(L, ok, NULL); -} - -/* -- Read/write helpers -------------------------------------------------- */ - -static int io_file_readnum(lua_State *L, FILE *fp) -{ - lua_Number d; - if (fscanf(fp, LUA_NUMBER_SCAN, &d) == 1) { - if (LJ_DUALNUM) { - int32_t i = lj_num2int(d); - if (d == (lua_Number)i && !tvismzero((cTValue *)&d)) { - setintV(L->top++, i); - return 1; - } - } - setnumV(L->top++, d); - return 1; - } else { - setnilV(L->top++); - return 0; - } -} - -static int io_file_readline(lua_State *L, FILE *fp, MSize chop) -{ - MSize m = LUAL_BUFFERSIZE, n = 0, ok = 0; - char *buf; - for (;;) { - buf = lj_buf_tmp(L, m); - if (fgets(buf+n, m-n, fp) == NULL) break; - n += (MSize)strlen(buf+n); - ok |= n; - if (n && buf[n-1] == '\n') { n -= chop; break; } - if (n >= m - 64) m += m; - } - setstrV(L, L->top++, lj_str_new(L, buf, (size_t)n)); - lj_gc_check(L); - return (int)ok; -} - -static void io_file_readall(lua_State *L, FILE *fp) -{ - MSize m, n; - for (m = LUAL_BUFFERSIZE, n = 0; ; m += m) { - char *buf = lj_buf_tmp(L, m); - n += (MSize)fread(buf+n, 1, m-n, fp); - if (n != m) { - setstrV(L, L->top++, lj_str_new(L, buf, (size_t)n)); - lj_gc_check(L); - return; - } - } -} - -static int io_file_readlen(lua_State *L, FILE *fp, MSize m) -{ - if (m) { - char *buf = lj_buf_tmp(L, m); - MSize n = (MSize)fread(buf, 1, m, fp); - setstrV(L, L->top++, lj_str_new(L, buf, (size_t)n)); - lj_gc_check(L); - return (n > 0 || m == 0); - } else { - int c = getc(fp); - ungetc(c, fp); - setstrV(L, L->top++, &G(L)->strempty); - return (c != EOF); - } -} - -static int io_file_read(lua_State *L, FILE *fp, int start) -{ - int ok, n, nargs = (int)(L->top - L->base) - start; - clearerr(fp); - if (nargs == 0) { - ok = io_file_readline(L, fp, 1); - n = start+1; /* Return 1 result. */ - } else { - /* The results plus the buffers go on top of the args. */ - luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); - ok = 1; - for (n = start; nargs-- && ok; n++) { - if (tvisstr(L->base+n)) { - const char *p = strVdata(L->base+n); - if (p[0] == '*') p++; - if (p[0] == 'n') - ok = io_file_readnum(L, fp); - else if ((p[0] & ~0x20) == 'L') - ok = io_file_readline(L, fp, (p[0] == 'l')); - else if (p[0] == 'a') - io_file_readall(L, fp); - else - lj_err_arg(L, n+1, LJ_ERR_INVFMT); - } else if (tvisnumber(L->base+n)) { - ok = io_file_readlen(L, fp, (MSize)lj_lib_checkint(L, n+1)); - } else { - lj_err_arg(L, n+1, LJ_ERR_INVOPT); - } - } - } - if (ferror(fp)) - return luaL_fileresult(L, 0, NULL); - if (!ok) - setnilV(L->top-1); /* Replace last result with nil. */ - return n - start; -} - -static int io_file_write(lua_State *L, FILE *fp, int start) -{ - cTValue *tv; - int status = 1; - for (tv = L->base+start; tv < L->top; tv++) { - MSize len; - const char *p = lj_strfmt_wstrnum(L, tv, &len); - if (!p) - lj_err_argt(L, (int)(tv - L->base) + 1, LUA_TSTRING); - status = status && (fwrite(p, 1, len, fp) == len); - } - if (LJ_52 && status) { - L->top = L->base+1; - if (start == 0) - setudataV(L, L->base, IOSTDF_UD(L, GCROOT_IO_OUTPUT)); - return 1; - } - return luaL_fileresult(L, status, NULL); -} - -static int io_file_iter(lua_State *L) -{ - GCfunc *fn = curr_func(L); - IOFileUD *iof = uddata(udataV(&fn->c.upvalue[0])); - int n = fn->c.nupvalues - 1; - if (iof->fp == NULL) - lj_err_caller(L, LJ_ERR_IOCLFL); - L->top = L->base; - if (n) { /* Copy upvalues with options to stack. */ - if (n > LUAI_MAXCSTACK) - lj_err_caller(L, LJ_ERR_STKOV); - lj_state_checkstack(L, (MSize)n); - memcpy(L->top, &fn->c.upvalue[1], n*sizeof(TValue)); - L->top += n; - } - n = io_file_read(L, iof->fp, 0); - if (ferror(iof->fp)) - lj_err_callermsg(L, strVdata(L->top-2)); - if (tvisnil(L->base) && (iof->type & IOFILE_FLAG_CLOSE)) { - io_file_close(L, iof); /* Return values are ignored. */ - return 0; - } - return n; -} - -static int io_file_lines(lua_State *L) -{ - int n = (int)(L->top - L->base); - if (n > LJ_MAX_UPVAL) - lj_err_caller(L, LJ_ERR_UNPACK); - lua_pushcclosure(L, io_file_iter, n); - return 1; -} - -/* -- I/O file methods ---------------------------------------------------- */ - -#define LJLIB_MODULE_io_method - -LJLIB_CF(io_method_close) -{ - IOFileUD *iof = L->base < L->top ? io_tofile(L) : - IOSTDF_IOF(L, GCROOT_IO_OUTPUT); - return io_file_close(L, iof); -} - -LJLIB_CF(io_method_read) -{ - return io_file_read(L, io_tofile(L)->fp, 1); -} - -LJLIB_CF(io_method_write) LJLIB_REC(io_write 0) -{ - return io_file_write(L, io_tofile(L)->fp, 1); -} - -LJLIB_CF(io_method_flush) LJLIB_REC(io_flush 0) -{ - return luaL_fileresult(L, fflush(io_tofile(L)->fp) == 0, NULL); -} - -LJLIB_CF(io_method_seek) -{ - FILE *fp = io_tofile(L)->fp; - int opt = lj_lib_checkopt(L, 2, 1, "\3set\3cur\3end"); - int64_t ofs = 0; - cTValue *o; - int res; - if (opt == 0) opt = SEEK_SET; - else if (opt == 1) opt = SEEK_CUR; - else if (opt == 2) opt = SEEK_END; - o = L->base+2; - if (o < L->top) { - if (tvisint(o)) - ofs = (int64_t)intV(o); - else if (tvisnum(o)) - ofs = (int64_t)numV(o); - else if (!tvisnil(o)) - lj_err_argt(L, 3, LUA_TNUMBER); - } -#if LJ_TARGET_POSIX - res = fseeko(fp, ofs, opt); -#elif _MSC_VER >= 1400 - res = _fseeki64(fp, ofs, opt); -#elif defined(__MINGW32__) - res = fseeko64(fp, ofs, opt); -#else - res = fseek(fp, (long)ofs, opt); -#endif - if (res) - return luaL_fileresult(L, 0, NULL); -#if LJ_TARGET_POSIX - ofs = ftello(fp); -#elif _MSC_VER >= 1400 - ofs = _ftelli64(fp); -#elif defined(__MINGW32__) - ofs = ftello64(fp); -#else - ofs = (int64_t)ftell(fp); -#endif - setint64V(L->top-1, ofs); - return 1; -} - -LJLIB_CF(io_method_setvbuf) -{ - FILE *fp = io_tofile(L)->fp; - int opt = lj_lib_checkopt(L, 2, -1, "\4full\4line\2no"); - size_t sz = (size_t)lj_lib_optint(L, 3, LUAL_BUFFERSIZE); - if (opt == 0) opt = _IOFBF; - else if (opt == 1) opt = _IOLBF; - else if (opt == 2) opt = _IONBF; - return luaL_fileresult(L, setvbuf(fp, NULL, opt, sz) == 0, NULL); -} - -LJLIB_CF(io_method_lines) -{ - io_tofile(L); - return io_file_lines(L); -} - -LJLIB_CF(io_method___gc) -{ - IOFileUD *iof = io_tofilep(L); - if (iof->fp != NULL && (iof->type & IOFILE_TYPE_MASK) != IOFILE_TYPE_STDF) - io_file_close(L, iof); - return 0; -} - -LJLIB_CF(io_method___tostring) -{ - IOFileUD *iof = io_tofilep(L); - if (iof->fp != NULL) - lua_pushfstring(L, "file (%p)", iof->fp); - else - lua_pushliteral(L, "file (closed)"); - return 1; -} - -LJLIB_PUSH(top-1) LJLIB_SET(__index) - -#include "lj_libdef.h" - -/* -- I/O library functions ----------------------------------------------- */ - -#define LJLIB_MODULE_io - -LJLIB_PUSH(top-2) LJLIB_SET(!) /* Set environment. */ - -LJLIB_CF(io_open) -{ - const char *fname = strdata(lj_lib_checkstr(L, 1)); - GCstr *s = lj_lib_optstr(L, 2); - const char *mode = s ? strdata(s) : "r"; - IOFileUD *iof = io_file_new(L); - iof->fp = fopen(fname, mode); - return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, fname); -} - -LJLIB_CF(io_popen) -{ -#if LJ_TARGET_POSIX || (LJ_TARGET_WINDOWS && !LJ_TARGET_XBOXONE && !LJ_TARGET_UWP) - const char *fname = strdata(lj_lib_checkstr(L, 1)); - GCstr *s = lj_lib_optstr(L, 2); - const char *mode = s ? strdata(s) : "r"; - IOFileUD *iof = io_file_new(L); - iof->type = IOFILE_TYPE_PIPE; -#if LJ_TARGET_POSIX - fflush(NULL); - iof->fp = popen(fname, mode); -#else - iof->fp = _popen(fname, mode); -#endif - return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, fname); -#else - return luaL_error(L, LUA_QL("popen") " not supported"); -#endif -} - -LJLIB_CF(io_tmpfile) -{ - IOFileUD *iof = io_file_new(L); -#if LJ_TARGET_PS3 || LJ_TARGET_PS4 || LJ_TARGET_PSVITA - iof->fp = NULL; errno = ENOSYS; -#else - iof->fp = tmpfile(); -#endif - return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, NULL); -} - -LJLIB_CF(io_close) -{ - return lj_cf_io_method_close(L); -} - -LJLIB_CF(io_read) -{ - return io_file_read(L, io_stdfile(L, GCROOT_IO_INPUT), 0); -} - -LJLIB_CF(io_write) LJLIB_REC(io_write GCROOT_IO_OUTPUT) -{ - return io_file_write(L, io_stdfile(L, GCROOT_IO_OUTPUT), 0); -} - -LJLIB_CF(io_flush) LJLIB_REC(io_flush GCROOT_IO_OUTPUT) -{ - return luaL_fileresult(L, fflush(io_stdfile(L, GCROOT_IO_OUTPUT)) == 0, NULL); -} - -static int io_std_getset(lua_State *L, ptrdiff_t id, const char *mode) -{ - if (L->base < L->top && !tvisnil(L->base)) { - if (tvisudata(L->base)) { - io_tofile(L); - L->top = L->base+1; - } else { - io_file_open(L, mode); - } - /* NOBARRIER: The standard I/O handles are GC roots. */ - setgcref(G(L)->gcroot[id], gcV(L->top-1)); - } else { - setudataV(L, L->top++, IOSTDF_UD(L, id)); - } - return 1; -} - -LJLIB_CF(io_input) -{ - return io_std_getset(L, GCROOT_IO_INPUT, "r"); -} - -LJLIB_CF(io_output) -{ - return io_std_getset(L, GCROOT_IO_OUTPUT, "w"); -} - -LJLIB_CF(io_lines) -{ - if (L->base == L->top) setnilV(L->top++); - if (!tvisnil(L->base)) { /* io.lines(fname) */ - IOFileUD *iof = io_file_open(L, "r"); - iof->type = IOFILE_TYPE_FILE|IOFILE_FLAG_CLOSE; - L->top--; - setudataV(L, L->base, udataV(L->top)); - } else { /* io.lines() iterates over stdin. */ - setudataV(L, L->base, IOSTDF_UD(L, GCROOT_IO_INPUT)); - } - return io_file_lines(L); -} - -LJLIB_CF(io_type) -{ - cTValue *o = lj_lib_checkany(L, 1); - if (!(tvisudata(o) && udataV(o)->udtype == UDTYPE_IO_FILE)) - setnilV(L->top++); - else if (((IOFileUD *)uddata(udataV(o)))->fp != NULL) - lua_pushliteral(L, "file"); - else - lua_pushliteral(L, "closed file"); - return 1; -} - -#include "lj_libdef.h" - -/* ------------------------------------------------------------------------ */ - -static GCobj *io_std_new(lua_State *L, FILE *fp, const char *name) -{ - IOFileUD *iof = (IOFileUD *)lua_newuserdata(L, sizeof(IOFileUD)); - GCudata *ud = udataV(L->top-1); - ud->udtype = UDTYPE_IO_FILE; - /* NOBARRIER: The GCudata is new (marked white). */ - setgcref(ud->metatable, gcV(L->top-3)); - iof->fp = fp; - iof->type = IOFILE_TYPE_STDF; - lua_setfield(L, -2, name); - return obj2gco(ud); -} - -LUALIB_API int luaopen_io(lua_State *L) -{ - LJ_LIB_REG(L, NULL, io_method); - copyTV(L, L->top, L->top-1); L->top++; - lua_setfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); - LJ_LIB_REG(L, LUA_IOLIBNAME, io); - setgcref(G(L)->gcroot[GCROOT_IO_INPUT], io_std_new(L, stdin, "stdin")); - setgcref(G(L)->gcroot[GCROOT_IO_OUTPUT], io_std_new(L, stdout, "stdout")); - io_std_new(L, stderr, "stderr"); - return 1; -} - diff --git a/lib/LuaJIT/src/lib_jit.c b/lib/LuaJIT/src/lib_jit.c deleted file mode 100644 index 22ca0a1..0000000 --- a/lib/LuaJIT/src/lib_jit.c +++ /dev/null @@ -1,777 +0,0 @@ -/* -** JIT library. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lib_jit_c -#define LUA_LIB - -#include "lua.h" -#include "lauxlib.h" -#include "lualib.h" - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_debug.h" -#include "lj_str.h" -#include "lj_tab.h" -#include "lj_state.h" -#include "lj_bc.h" -#if LJ_HASFFI -#include "lj_ctype.h" -#endif -#if LJ_HASJIT -#include "lj_ir.h" -#include "lj_jit.h" -#include "lj_ircall.h" -#include "lj_iropt.h" -#include "lj_target.h" -#endif -#include "lj_trace.h" -#include "lj_dispatch.h" -#include "lj_vm.h" -#include "lj_vmevent.h" -#include "lj_lib.h" - -#include "luajit.h" - -/* -- jit.* functions ----------------------------------------------------- */ - -#define LJLIB_MODULE_jit - -static int setjitmode(lua_State *L, int mode) -{ - int idx = 0; - if (L->base == L->top || tvisnil(L->base)) { /* jit.on/off/flush([nil]) */ - mode |= LUAJIT_MODE_ENGINE; - } else { - /* jit.on/off/flush(func|proto, nil|true|false) */ - if (tvisfunc(L->base) || tvisproto(L->base)) - idx = 1; - else if (!tvistrue(L->base)) /* jit.on/off/flush(true, nil|true|false) */ - goto err; - if (L->base+1 < L->top && tvisbool(L->base+1)) - mode |= boolV(L->base+1) ? LUAJIT_MODE_ALLFUNC : LUAJIT_MODE_ALLSUBFUNC; - else - mode |= LUAJIT_MODE_FUNC; - } - if (luaJIT_setmode(L, idx, mode) != 1) { - if ((mode & LUAJIT_MODE_MASK) == LUAJIT_MODE_ENGINE) - lj_err_caller(L, LJ_ERR_NOJIT); - err: - lj_err_argt(L, 1, LUA_TFUNCTION); - } - return 0; -} - -LJLIB_CF(jit_on) -{ - return setjitmode(L, LUAJIT_MODE_ON); -} - -LJLIB_CF(jit_off) -{ - return setjitmode(L, LUAJIT_MODE_OFF); -} - -LJLIB_CF(jit_flush) -{ -#if LJ_HASJIT - if (L->base < L->top && tvisnumber(L->base)) { - int traceno = lj_lib_checkint(L, 1); - luaJIT_setmode(L, traceno, LUAJIT_MODE_FLUSH|LUAJIT_MODE_TRACE); - return 0; - } -#endif - return setjitmode(L, LUAJIT_MODE_FLUSH); -} - -#if LJ_HASJIT -/* Push a string for every flag bit that is set. */ -static void flagbits_to_strings(lua_State *L, uint32_t flags, uint32_t base, - const char *str) -{ - for (; *str; base <<= 1, str += 1+*str) - if (flags & base) - setstrV(L, L->top++, lj_str_new(L, str+1, *(uint8_t *)str)); -} -#endif - -LJLIB_CF(jit_status) -{ -#if LJ_HASJIT - jit_State *J = L2J(L); - L->top = L->base; - setboolV(L->top++, (J->flags & JIT_F_ON) ? 1 : 0); - flagbits_to_strings(L, J->flags, JIT_F_CPU_FIRST, JIT_F_CPUSTRING); - flagbits_to_strings(L, J->flags, JIT_F_OPT_FIRST, JIT_F_OPTSTRING); - return (int)(L->top - L->base); -#else - setboolV(L->top++, 0); - return 1; -#endif -} - -LJLIB_CF(jit_attach) -{ -#ifdef LUAJIT_DISABLE_VMEVENT - luaL_error(L, "vmevent API disabled"); -#else - GCfunc *fn = lj_lib_checkfunc(L, 1); - GCstr *s = lj_lib_optstr(L, 2); - luaL_findtable(L, LUA_REGISTRYINDEX, LJ_VMEVENTS_REGKEY, LJ_VMEVENTS_HSIZE); - if (s) { /* Attach to given event. */ - const uint8_t *p = (const uint8_t *)strdata(s); - uint32_t h = s->len; - while (*p) h = h ^ (lj_rol(h, 6) + *p++); - lua_pushvalue(L, 1); - lua_rawseti(L, -2, VMEVENT_HASHIDX(h)); - G(L)->vmevmask = VMEVENT_NOCACHE; /* Invalidate cache. */ - } else { /* Detach if no event given. */ - setnilV(L->top++); - while (lua_next(L, -2)) { - L->top--; - if (tvisfunc(L->top) && funcV(L->top) == fn) { - setnilV(lj_tab_set(L, tabV(L->top-2), L->top-1)); - } - } - } -#endif - return 0; -} - -LJLIB_PUSH(top-5) LJLIB_SET(os) -LJLIB_PUSH(top-4) LJLIB_SET(arch) -LJLIB_PUSH(top-3) LJLIB_SET(version_num) -LJLIB_PUSH(top-2) LJLIB_SET(version) - -#include "lj_libdef.h" - -/* -- jit.util.* functions ------------------------------------------------ */ - -#define LJLIB_MODULE_jit_util - -/* -- Reflection API for Lua functions ------------------------------------ */ - -/* Return prototype of first argument (Lua function or prototype object) */ -static GCproto *check_Lproto(lua_State *L, int nolua) -{ - TValue *o = L->base; - if (L->top > o) { - if (tvisproto(o)) { - return protoV(o); - } else if (tvisfunc(o)) { - if (isluafunc(funcV(o))) - return funcproto(funcV(o)); - else if (nolua) - return NULL; - } - } - lj_err_argt(L, 1, LUA_TFUNCTION); - return NULL; /* unreachable */ -} - -static void setintfield(lua_State *L, GCtab *t, const char *name, int32_t val) -{ - setintV(lj_tab_setstr(L, t, lj_str_newz(L, name)), val); -} - -/* local info = jit.util.funcinfo(func [,pc]) */ -LJLIB_CF(jit_util_funcinfo) -{ - GCproto *pt = check_Lproto(L, 1); - if (pt) { - BCPos pc = (BCPos)lj_lib_optint(L, 2, 0); - GCtab *t; - lua_createtable(L, 0, 16); /* Increment hash size if fields are added. */ - t = tabV(L->top-1); - setintfield(L, t, "linedefined", pt->firstline); - setintfield(L, t, "lastlinedefined", pt->firstline + pt->numline); - setintfield(L, t, "stackslots", pt->framesize); - setintfield(L, t, "params", pt->numparams); - setintfield(L, t, "bytecodes", (int32_t)pt->sizebc); - setintfield(L, t, "gcconsts", (int32_t)pt->sizekgc); - setintfield(L, t, "nconsts", (int32_t)pt->sizekn); - setintfield(L, t, "upvalues", (int32_t)pt->sizeuv); - if (pc < pt->sizebc) - setintfield(L, t, "currentline", lj_debug_line(pt, pc)); - lua_pushboolean(L, (pt->flags & PROTO_VARARG)); - lua_setfield(L, -2, "isvararg"); - lua_pushboolean(L, (pt->flags & PROTO_CHILD)); - lua_setfield(L, -2, "children"); - setstrV(L, L->top++, proto_chunkname(pt)); - lua_setfield(L, -2, "source"); - lj_debug_pushloc(L, pt, pc); - lua_setfield(L, -2, "loc"); - setprotoV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "proto")), pt); - } else { - GCfunc *fn = funcV(L->base); - GCtab *t; - lua_createtable(L, 0, 4); /* Increment hash size if fields are added. */ - t = tabV(L->top-1); - if (!iscfunc(fn)) - setintfield(L, t, "ffid", fn->c.ffid); - setintptrV(lj_tab_setstr(L, t, lj_str_newlit(L, "addr")), - (intptr_t)(void *)fn->c.f); - setintfield(L, t, "upvalues", fn->c.nupvalues); - } - return 1; -} - -/* local ins, m = jit.util.funcbc(func, pc) */ -LJLIB_CF(jit_util_funcbc) -{ - GCproto *pt = check_Lproto(L, 0); - BCPos pc = (BCPos)lj_lib_checkint(L, 2); - if (pc < pt->sizebc) { - BCIns ins = proto_bc(pt)[pc]; - BCOp op = bc_op(ins); - lua_assert(op < BC__MAX); - setintV(L->top, ins); - setintV(L->top+1, lj_bc_mode[op]); - L->top += 2; - return 2; - } - return 0; -} - -/* local k = jit.util.funck(func, idx) */ -LJLIB_CF(jit_util_funck) -{ - GCproto *pt = check_Lproto(L, 0); - ptrdiff_t idx = (ptrdiff_t)lj_lib_checkint(L, 2); - if (idx >= 0) { - if (idx < (ptrdiff_t)pt->sizekn) { - copyTV(L, L->top-1, proto_knumtv(pt, idx)); - return 1; - } - } else { - if (~idx < (ptrdiff_t)pt->sizekgc) { - GCobj *gc = proto_kgc(pt, idx); - setgcV(L, L->top-1, gc, ~gc->gch.gct); - return 1; - } - } - return 0; -} - -/* local name = jit.util.funcuvname(func, idx) */ -LJLIB_CF(jit_util_funcuvname) -{ - GCproto *pt = check_Lproto(L, 0); - uint32_t idx = (uint32_t)lj_lib_checkint(L, 2); - if (idx < pt->sizeuv) { - setstrV(L, L->top-1, lj_str_newz(L, lj_debug_uvname(pt, idx))); - return 1; - } - return 0; -} - -/* -- Reflection API for traces ------------------------------------------- */ - -#if LJ_HASJIT - -/* Check trace argument. Must not throw for non-existent trace numbers. */ -static GCtrace *jit_checktrace(lua_State *L) -{ - TraceNo tr = (TraceNo)lj_lib_checkint(L, 1); - jit_State *J = L2J(L); - if (tr > 0 && tr < J->sizetrace) - return traceref(J, tr); - return NULL; -} - -/* Names of link types. ORDER LJ_TRLINK */ -static const char *const jit_trlinkname[] = { - "none", "root", "loop", "tail-recursion", "up-recursion", "down-recursion", - "interpreter", "return", "stitch" -}; - -/* local info = jit.util.traceinfo(tr) */ -LJLIB_CF(jit_util_traceinfo) -{ - GCtrace *T = jit_checktrace(L); - if (T) { - GCtab *t; - lua_createtable(L, 0, 8); /* Increment hash size if fields are added. */ - t = tabV(L->top-1); - setintfield(L, t, "nins", (int32_t)T->nins - REF_BIAS - 1); - setintfield(L, t, "nk", REF_BIAS - (int32_t)T->nk); - setintfield(L, t, "link", T->link); - setintfield(L, t, "nexit", T->nsnap); - setstrV(L, L->top++, lj_str_newz(L, jit_trlinkname[T->linktype])); - lua_setfield(L, -2, "linktype"); - /* There are many more fields. Add them only when needed. */ - return 1; - } - return 0; -} - -/* local m, ot, op1, op2, prev = jit.util.traceir(tr, idx) */ -LJLIB_CF(jit_util_traceir) -{ - GCtrace *T = jit_checktrace(L); - IRRef ref = (IRRef)lj_lib_checkint(L, 2) + REF_BIAS; - if (T && ref >= REF_BIAS && ref < T->nins) { - IRIns *ir = &T->ir[ref]; - int32_t m = lj_ir_mode[ir->o]; - setintV(L->top-2, m); - setintV(L->top-1, ir->ot); - setintV(L->top++, (int32_t)ir->op1 - (irm_op1(m)==IRMref ? REF_BIAS : 0)); - setintV(L->top++, (int32_t)ir->op2 - (irm_op2(m)==IRMref ? REF_BIAS : 0)); - setintV(L->top++, ir->prev); - return 5; - } - return 0; -} - -/* local k, t [, slot] = jit.util.tracek(tr, idx) */ -LJLIB_CF(jit_util_tracek) -{ - GCtrace *T = jit_checktrace(L); - IRRef ref = (IRRef)lj_lib_checkint(L, 2) + REF_BIAS; - if (T && ref >= T->nk && ref < REF_BIAS) { - IRIns *ir = &T->ir[ref]; - int32_t slot = -1; - if (ir->o == IR_KSLOT) { - slot = ir->op2; - ir = &T->ir[ir->op1]; - } -#if LJ_HASFFI - if (ir->o == IR_KINT64 && !ctype_ctsG(G(L))) { - ptrdiff_t oldtop = savestack(L, L->top); - luaopen_ffi(L); /* Load FFI library on-demand. */ - L->top = restorestack(L, oldtop); - } -#endif - lj_ir_kvalue(L, L->top-2, ir); - setintV(L->top-1, (int32_t)irt_type(ir->t)); - if (slot == -1) - return 2; - setintV(L->top++, slot); - return 3; - } - return 0; -} - -/* local snap = jit.util.tracesnap(tr, sn) */ -LJLIB_CF(jit_util_tracesnap) -{ - GCtrace *T = jit_checktrace(L); - SnapNo sn = (SnapNo)lj_lib_checkint(L, 2); - if (T && sn < T->nsnap) { - SnapShot *snap = &T->snap[sn]; - SnapEntry *map = &T->snapmap[snap->mapofs]; - MSize n, nent = snap->nent; - GCtab *t; - lua_createtable(L, nent+2, 0); - t = tabV(L->top-1); - setintV(lj_tab_setint(L, t, 0), (int32_t)snap->ref - REF_BIAS); - setintV(lj_tab_setint(L, t, 1), (int32_t)snap->nslots); - for (n = 0; n < nent; n++) - setintV(lj_tab_setint(L, t, (int32_t)(n+2)), (int32_t)map[n]); - setintV(lj_tab_setint(L, t, (int32_t)(nent+2)), (int32_t)SNAP(255, 0, 0)); - return 1; - } - return 0; -} - -/* local mcode, addr, loop = jit.util.tracemc(tr) */ -LJLIB_CF(jit_util_tracemc) -{ - GCtrace *T = jit_checktrace(L); - if (T && T->mcode != NULL) { - setstrV(L, L->top-1, lj_str_new(L, (const char *)T->mcode, T->szmcode)); - setintptrV(L->top++, (intptr_t)(void *)T->mcode); - setintV(L->top++, T->mcloop); - return 3; - } - return 0; -} - -/* local addr = jit.util.traceexitstub([tr,] exitno) */ -LJLIB_CF(jit_util_traceexitstub) -{ -#ifdef EXITSTUBS_PER_GROUP - ExitNo exitno = (ExitNo)lj_lib_checkint(L, 1); - jit_State *J = L2J(L); - if (exitno < EXITSTUBS_PER_GROUP*LJ_MAX_EXITSTUBGR) { - setintptrV(L->top-1, (intptr_t)(void *)exitstub_addr(J, exitno)); - return 1; - } -#else - if (L->top > L->base+1) { /* Don't throw for one-argument variant. */ - GCtrace *T = jit_checktrace(L); - ExitNo exitno = (ExitNo)lj_lib_checkint(L, 2); - ExitNo maxexit = T->root ? T->nsnap+1 : T->nsnap; - if (T && T->mcode != NULL && exitno < maxexit) { - setintptrV(L->top-1, (intptr_t)(void *)exitstub_trace_addr(T, exitno)); - return 1; - } - } -#endif - return 0; -} - -/* local addr = jit.util.ircalladdr(idx) */ -LJLIB_CF(jit_util_ircalladdr) -{ - uint32_t idx = (uint32_t)lj_lib_checkint(L, 1); - if (idx < IRCALL__MAX) { - setintptrV(L->top-1, (intptr_t)(void *)lj_ir_callinfo[idx].func); - return 1; - } - return 0; -} - -#endif - -#include "lj_libdef.h" - -static int luaopen_jit_util(lua_State *L) -{ - LJ_LIB_REG(L, NULL, jit_util); - return 1; -} - -/* -- jit.opt module ------------------------------------------------------ */ - -#if LJ_HASJIT - -#define LJLIB_MODULE_jit_opt - -/* Parse optimization level. */ -static int jitopt_level(jit_State *J, const char *str) -{ - if (str[0] >= '0' && str[0] <= '9' && str[1] == '\0') { - uint32_t flags; - if (str[0] == '0') flags = JIT_F_OPT_0; - else if (str[0] == '1') flags = JIT_F_OPT_1; - else if (str[0] == '2') flags = JIT_F_OPT_2; - else flags = JIT_F_OPT_3; - J->flags = (J->flags & ~JIT_F_OPT_MASK) | flags; - return 1; /* Ok. */ - } - return 0; /* No match. */ -} - -/* Parse optimization flag. */ -static int jitopt_flag(jit_State *J, const char *str) -{ - const char *lst = JIT_F_OPTSTRING; - uint32_t opt; - int set = 1; - if (str[0] == '+') { - str++; - } else if (str[0] == '-') { - str++; - set = 0; - } else if (str[0] == 'n' && str[1] == 'o') { - str += str[2] == '-' ? 3 : 2; - set = 0; - } - for (opt = JIT_F_OPT_FIRST; ; opt <<= 1) { - size_t len = *(const uint8_t *)lst; - if (len == 0) - break; - if (strncmp(str, lst+1, len) == 0 && str[len] == '\0') { - if (set) J->flags |= opt; else J->flags &= ~opt; - return 1; /* Ok. */ - } - lst += 1+len; - } - return 0; /* No match. */ -} - -/* Parse optimization parameter. */ -static int jitopt_param(jit_State *J, const char *str) -{ - const char *lst = JIT_P_STRING; - int i; - for (i = 0; i < JIT_P__MAX; i++) { - size_t len = *(const uint8_t *)lst; - lua_assert(len != 0); - if (strncmp(str, lst+1, len) == 0 && str[len] == '=') { - int32_t n = 0; - const char *p = &str[len+1]; - while (*p >= '0' && *p <= '9') - n = n*10 + (*p++ - '0'); - if (*p) return 0; /* Malformed number. */ - J->param[i] = n; - if (i == JIT_P_hotloop) - lj_dispatch_init_hotcount(J2G(J)); - return 1; /* Ok. */ - } - lst += 1+len; - } - return 0; /* No match. */ -} - -/* jit.opt.start(flags...) */ -LJLIB_CF(jit_opt_start) -{ - jit_State *J = L2J(L); - int nargs = (int)(L->top - L->base); - if (nargs == 0) { - J->flags = (J->flags & ~JIT_F_OPT_MASK) | JIT_F_OPT_DEFAULT; - } else { - int i; - for (i = 1; i <= nargs; i++) { - const char *str = strdata(lj_lib_checkstr(L, i)); - if (!jitopt_level(J, str) && - !jitopt_flag(J, str) && - !jitopt_param(J, str)) - lj_err_callerv(L, LJ_ERR_JITOPT, str); - } - } - return 0; -} - -#include "lj_libdef.h" - -#endif - -/* -- jit.profile module -------------------------------------------------- */ - -#if LJ_HASPROFILE - -#define LJLIB_MODULE_jit_profile - -/* Not loaded by default, use: local profile = require("jit.profile") */ - -static const char KEY_PROFILE_THREAD = 't'; -static const char KEY_PROFILE_FUNC = 'f'; - -static void jit_profile_callback(lua_State *L2, lua_State *L, int samples, - int vmstate) -{ - TValue key; - cTValue *tv; - setlightudV(&key, (void *)&KEY_PROFILE_FUNC); - tv = lj_tab_get(L, tabV(registry(L)), &key); - if (tvisfunc(tv)) { - char vmst = (char)vmstate; - int status; - setfuncV(L2, L2->top++, funcV(tv)); - setthreadV(L2, L2->top++, L); - setintV(L2->top++, samples); - setstrV(L2, L2->top++, lj_str_new(L2, &vmst, 1)); - status = lua_pcall(L2, 3, 0, 0); /* callback(thread, samples, vmstate) */ - if (status) { - if (G(L2)->panic) G(L2)->panic(L2); - exit(EXIT_FAILURE); - } - lj_trace_abort(G(L2)); - } -} - -/* profile.start(mode, cb) */ -LJLIB_CF(jit_profile_start) -{ - GCtab *registry = tabV(registry(L)); - GCstr *mode = lj_lib_optstr(L, 1); - GCfunc *func = lj_lib_checkfunc(L, 2); - lua_State *L2 = lua_newthread(L); /* Thread that runs profiler callback. */ - TValue key; - /* Anchor thread and function in registry. */ - setlightudV(&key, (void *)&KEY_PROFILE_THREAD); - setthreadV(L, lj_tab_set(L, registry, &key), L2); - setlightudV(&key, (void *)&KEY_PROFILE_FUNC); - setfuncV(L, lj_tab_set(L, registry, &key), func); - lj_gc_anybarriert(L, registry); - luaJIT_profile_start(L, mode ? strdata(mode) : "", - (luaJIT_profile_callback)jit_profile_callback, L2); - return 0; -} - -/* profile.stop() */ -LJLIB_CF(jit_profile_stop) -{ - GCtab *registry; - TValue key; - luaJIT_profile_stop(L); - registry = tabV(registry(L)); - setlightudV(&key, (void *)&KEY_PROFILE_THREAD); - setnilV(lj_tab_set(L, registry, &key)); - setlightudV(&key, (void *)&KEY_PROFILE_FUNC); - setnilV(lj_tab_set(L, registry, &key)); - lj_gc_anybarriert(L, registry); - return 0; -} - -/* dump = profile.dumpstack([thread,] fmt, depth) */ -LJLIB_CF(jit_profile_dumpstack) -{ - lua_State *L2 = L; - int arg = 0; - size_t len; - int depth; - GCstr *fmt; - const char *p; - if (L->top > L->base && tvisthread(L->base)) { - L2 = threadV(L->base); - arg = 1; - } - fmt = lj_lib_checkstr(L, arg+1); - depth = lj_lib_checkint(L, arg+2); - p = luaJIT_profile_dumpstack(L2, strdata(fmt), depth, &len); - lua_pushlstring(L, p, len); - return 1; -} - -#include "lj_libdef.h" - -static int luaopen_jit_profile(lua_State *L) -{ - LJ_LIB_REG(L, NULL, jit_profile); - return 1; -} - -#endif - -/* -- JIT compiler initialization ----------------------------------------- */ - -#if LJ_HASJIT -/* Default values for JIT parameters. */ -static const int32_t jit_param_default[JIT_P__MAX+1] = { -#define JIT_PARAMINIT(len, name, value) (value), -JIT_PARAMDEF(JIT_PARAMINIT) -#undef JIT_PARAMINIT - 0 -}; -#endif - -#if LJ_TARGET_ARM && LJ_TARGET_LINUX -#include -#endif - -/* Arch-dependent CPU detection. */ -static uint32_t jit_cpudetect(lua_State *L) -{ - uint32_t flags = 0; -#if LJ_TARGET_X86ORX64 - uint32_t vendor[4]; - uint32_t features[4]; - if (lj_vm_cpuid(0, vendor) && lj_vm_cpuid(1, features)) { -#if !LJ_HASJIT -#define JIT_F_SSE2 2 -#endif - flags |= ((features[3] >> 26)&1) * JIT_F_SSE2; -#if LJ_HASJIT - flags |= ((features[2] >> 0)&1) * JIT_F_SSE3; - flags |= ((features[2] >> 19)&1) * JIT_F_SSE4_1; - if (vendor[2] == 0x6c65746e) { /* Intel. */ - if ((features[0] & 0x0fff0ff0) == 0x000106c0) /* Atom. */ - flags |= JIT_F_LEA_AGU; - } else if (vendor[2] == 0x444d4163) { /* AMD. */ - uint32_t fam = (features[0] & 0x0ff00f00); - if (fam >= 0x00000f00) /* K8, K10. */ - flags |= JIT_F_PREFER_IMUL; - } - if (vendor[0] >= 7) { - uint32_t xfeatures[4]; - lj_vm_cpuid(7, xfeatures); - flags |= ((xfeatures[1] >> 8)&1) * JIT_F_BMI2; - } -#endif - } - /* Check for required instruction set support on x86 (unnecessary on x64). */ -#if LJ_TARGET_X86 - if (!(flags & JIT_F_SSE2)) - luaL_error(L, "CPU with SSE2 required"); -#endif -#elif LJ_TARGET_ARM -#if LJ_HASJIT - int ver = LJ_ARCH_VERSION; /* Compile-time ARM CPU detection. */ -#if LJ_TARGET_LINUX - if (ver < 70) { /* Runtime ARM CPU detection. */ - struct utsname ut; - uname(&ut); - if (strncmp(ut.machine, "armv", 4) == 0) { - if (ut.machine[4] >= '7') - ver = 70; - else if (ut.machine[4] == '6') - ver = 60; - } - } -#endif - flags |= ver >= 70 ? JIT_F_ARMV7 : - ver >= 61 ? JIT_F_ARMV6T2_ : - ver >= 60 ? JIT_F_ARMV6_ : 0; - flags |= LJ_ARCH_HASFPU == 0 ? 0 : ver >= 70 ? JIT_F_VFPV3 : JIT_F_VFPV2; -#endif -#elif LJ_TARGET_ARM64 - /* No optional CPU features to detect (for now). */ -#elif LJ_TARGET_PPC -#if LJ_HASJIT -#if LJ_ARCH_SQRT - flags |= JIT_F_SQRT; -#endif -#if LJ_ARCH_ROUND - flags |= JIT_F_ROUND; -#endif -#endif -#elif LJ_TARGET_MIPS -#if LJ_HASJIT - /* Compile-time MIPS CPU detection. */ -#if LJ_ARCH_VERSION >= 20 - flags |= JIT_F_MIPSXXR2; -#endif - /* Runtime MIPS CPU detection. */ -#if defined(__GNUC__) - if (!(flags & JIT_F_MIPSXXR2)) { - int x; -#ifdef __mips16 - x = 0; /* Runtime detection is difficult. Ensure optimal -march flags. */ -#else - /* On MIPS32R1 rotr is treated as srl. rotr r2,r2,1 -> srl r2,r2,1. */ - __asm__("li $2, 1\n\t.long 0x00221042\n\tmove %0, $2" : "=r"(x) : : "$2"); -#endif - if (x) flags |= JIT_F_MIPSXXR2; /* Either 0x80000000 (R2) or 0 (R1). */ - } -#endif -#endif -#else -#error "Missing CPU detection for this architecture" -#endif - UNUSED(L); - return flags; -} - -/* Initialize JIT compiler. */ -static void jit_init(lua_State *L) -{ - uint32_t flags = jit_cpudetect(L); -#if LJ_HASJIT - jit_State *J = L2J(L); - J->flags = flags | JIT_F_ON | JIT_F_OPT_DEFAULT; - memcpy(J->param, jit_param_default, sizeof(J->param)); - lj_dispatch_update(G(L)); -#else - UNUSED(flags); -#endif -} - -LUALIB_API int luaopen_jit(lua_State *L) -{ - jit_init(L); - lua_pushliteral(L, LJ_OS_NAME); - lua_pushliteral(L, LJ_ARCH_NAME); - lua_pushinteger(L, LUAJIT_VERSION_NUM); - lua_pushliteral(L, LUAJIT_VERSION); - LJ_LIB_REG(L, LUA_JITLIBNAME, jit); -#if LJ_HASPROFILE - lj_lib_prereg(L, LUA_JITLIBNAME ".profile", luaopen_jit_profile, - tabref(L->env)); -#endif -#ifndef LUAJIT_DISABLE_JITUTIL - lj_lib_prereg(L, LUA_JITLIBNAME ".util", luaopen_jit_util, tabref(L->env)); -#endif -#if LJ_HASJIT - LJ_LIB_REG(L, "jit.opt", jit_opt); -#endif - L->top -= 2; - return 1; -} - diff --git a/lib/LuaJIT/src/lib_math.c b/lib/LuaJIT/src/lib_math.c deleted file mode 100644 index ef9dda2..0000000 --- a/lib/LuaJIT/src/lib_math.c +++ /dev/null @@ -1,226 +0,0 @@ -/* -** Math library. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#include - -#define lib_math_c -#define LUA_LIB - -#include "lua.h" -#include "lauxlib.h" -#include "lualib.h" - -#include "lj_obj.h" -#include "lj_lib.h" -#include "lj_vm.h" - -/* ------------------------------------------------------------------------ */ - -#define LJLIB_MODULE_math - -LJLIB_ASM(math_abs) LJLIB_REC(.) -{ - lj_lib_checknumber(L, 1); - return FFH_RETRY; -} -LJLIB_ASM_(math_floor) LJLIB_REC(math_round IRFPM_FLOOR) -LJLIB_ASM_(math_ceil) LJLIB_REC(math_round IRFPM_CEIL) - -LJLIB_ASM(math_sqrt) LJLIB_REC(math_unary IRFPM_SQRT) -{ - lj_lib_checknum(L, 1); - return FFH_RETRY; -} -LJLIB_ASM_(math_log10) LJLIB_REC(math_unary IRFPM_LOG10) -LJLIB_ASM_(math_exp) LJLIB_REC(math_unary IRFPM_EXP) -LJLIB_ASM_(math_sin) LJLIB_REC(math_unary IRFPM_SIN) -LJLIB_ASM_(math_cos) LJLIB_REC(math_unary IRFPM_COS) -LJLIB_ASM_(math_tan) LJLIB_REC(math_unary IRFPM_TAN) -LJLIB_ASM_(math_asin) LJLIB_REC(math_atrig FF_math_asin) -LJLIB_ASM_(math_acos) LJLIB_REC(math_atrig FF_math_acos) -LJLIB_ASM_(math_atan) LJLIB_REC(math_atrig FF_math_atan) -LJLIB_ASM_(math_sinh) LJLIB_REC(math_htrig IRCALL_sinh) -LJLIB_ASM_(math_cosh) LJLIB_REC(math_htrig IRCALL_cosh) -LJLIB_ASM_(math_tanh) LJLIB_REC(math_htrig IRCALL_tanh) -LJLIB_ASM_(math_frexp) -LJLIB_ASM_(math_modf) LJLIB_REC(.) - -LJLIB_ASM(math_log) LJLIB_REC(math_log) -{ - double x = lj_lib_checknum(L, 1); - if (L->base+1 < L->top) { - double y = lj_lib_checknum(L, 2); -#ifdef LUAJIT_NO_LOG2 - x = log(x); y = 1.0 / log(y); -#else - x = lj_vm_log2(x); y = 1.0 / lj_vm_log2(y); -#endif - setnumV(L->base-1-LJ_FR2, x*y); /* Do NOT join the expression to x / y. */ - return FFH_RES(1); - } - return FFH_RETRY; -} - -LJLIB_LUA(math_deg) /* function(x) return x * 57.29577951308232 end */ -LJLIB_LUA(math_rad) /* function(x) return x * 0.017453292519943295 end */ - -LJLIB_ASM(math_atan2) LJLIB_REC(.) -{ - lj_lib_checknum(L, 1); - lj_lib_checknum(L, 2); - return FFH_RETRY; -} -LJLIB_ASM_(math_pow) LJLIB_REC(.) -LJLIB_ASM_(math_fmod) - -LJLIB_ASM(math_ldexp) LJLIB_REC(.) -{ - lj_lib_checknum(L, 1); -#if LJ_DUALNUM && !LJ_TARGET_X86ORX64 - lj_lib_checkint(L, 2); -#else - lj_lib_checknum(L, 2); -#endif - return FFH_RETRY; -} - -LJLIB_ASM(math_min) LJLIB_REC(math_minmax IR_MIN) -{ - int i = 0; - do { lj_lib_checknumber(L, ++i); } while (L->base+i < L->top); - return FFH_RETRY; -} -LJLIB_ASM_(math_max) LJLIB_REC(math_minmax IR_MAX) - -LJLIB_PUSH(3.14159265358979323846) LJLIB_SET(pi) -LJLIB_PUSH(1e310) LJLIB_SET(huge) - -/* ------------------------------------------------------------------------ */ - -/* This implements a Tausworthe PRNG with period 2^223. Based on: -** Tables of maximally-equidistributed combined LFSR generators, -** Pierre L'Ecuyer, 1991, table 3, 1st entry. -** Full-period ME-CF generator with L=64, J=4, k=223, N1=49. -*/ - -/* PRNG state. */ -struct RandomState { - uint64_t gen[4]; /* State of the 4 LFSR generators. */ - int valid; /* State is valid. */ -}; - -/* Union needed for bit-pattern conversion between uint64_t and double. */ -typedef union { uint64_t u64; double d; } U64double; - -/* Update generator i and compute a running xor of all states. */ -#define TW223_GEN(i, k, q, s) \ - z = rs->gen[i]; \ - z = (((z<> (k-s)) ^ ((z&((uint64_t)(int64_t)-1 << (64-k)))<gen[i] = z; - -/* PRNG step function. Returns a double in the range 1.0 <= d < 2.0. */ -LJ_NOINLINE uint64_t LJ_FASTCALL lj_math_random_step(RandomState *rs) -{ - uint64_t z, r = 0; - TW223_GEN(0, 63, 31, 18) - TW223_GEN(1, 58, 19, 28) - TW223_GEN(2, 55, 24, 7) - TW223_GEN(3, 47, 21, 8) - return (r & U64x(000fffff,ffffffff)) | U64x(3ff00000,00000000); -} - -/* PRNG initialization function. */ -static void random_init(RandomState *rs, double d) -{ - uint32_t r = 0x11090601; /* 64-k[i] as four 8 bit constants. */ - int i; - for (i = 0; i < 4; i++) { - U64double u; - uint32_t m = 1u << (r&255); - r >>= 8; - u.d = d = d * 3.14159265358979323846 + 2.7182818284590452354; - if (u.u64 < m) u.u64 += m; /* Ensure k[i] MSB of gen[i] are non-zero. */ - rs->gen[i] = u.u64; - } - rs->valid = 1; - for (i = 0; i < 10; i++) - lj_math_random_step(rs); -} - -/* PRNG extract function. */ -LJLIB_PUSH(top-2) /* Upvalue holds userdata with RandomState. */ -LJLIB_CF(math_random) LJLIB_REC(.) -{ - int n = (int)(L->top - L->base); - RandomState *rs = (RandomState *)(uddata(udataV(lj_lib_upvalue(L, 1)))); - U64double u; - double d; - if (LJ_UNLIKELY(!rs->valid)) random_init(rs, 0.0); - u.u64 = lj_math_random_step(rs); - d = u.d - 1.0; - if (n > 0) { -#if LJ_DUALNUM - int isint = 1; - double r1; - lj_lib_checknumber(L, 1); - if (tvisint(L->base)) { - r1 = (lua_Number)intV(L->base); - } else { - isint = 0; - r1 = numV(L->base); - } -#else - double r1 = lj_lib_checknum(L, 1); -#endif - if (n == 1) { - d = lj_vm_floor(d*r1) + 1.0; /* d is an int in range [1, r1] */ - } else { -#if LJ_DUALNUM - double r2; - lj_lib_checknumber(L, 2); - if (tvisint(L->base+1)) { - r2 = (lua_Number)intV(L->base+1); - } else { - isint = 0; - r2 = numV(L->base+1); - } -#else - double r2 = lj_lib_checknum(L, 2); -#endif - d = lj_vm_floor(d*(r2-r1+1.0)) + r1; /* d is an int in range [r1, r2] */ - } -#if LJ_DUALNUM - if (isint) { - setintV(L->top-1, lj_num2int(d)); - return 1; - } -#endif - } /* else: d is a double in range [0, 1] */ - setnumV(L->top++, d); - return 1; -} - -/* PRNG seed function. */ -LJLIB_PUSH(top-2) /* Upvalue holds userdata with RandomState. */ -LJLIB_CF(math_randomseed) -{ - RandomState *rs = (RandomState *)(uddata(udataV(lj_lib_upvalue(L, 1)))); - random_init(rs, lj_lib_checknum(L, 1)); - return 0; -} - -/* ------------------------------------------------------------------------ */ - -#include "lj_libdef.h" - -LUALIB_API int luaopen_math(lua_State *L) -{ - RandomState *rs; - rs = (RandomState *)lua_newuserdata(L, sizeof(RandomState)); - rs->valid = 0; /* Use lazy initialization to save some time on startup. */ - LJ_LIB_REG(L, LUA_MATHLIBNAME, math); - return 1; -} - diff --git a/lib/LuaJIT/src/lib_os.c b/lib/LuaJIT/src/lib_os.c deleted file mode 100644 index ffbc3fd..0000000 --- a/lib/LuaJIT/src/lib_os.c +++ /dev/null @@ -1,292 +0,0 @@ -/* -** OS library. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Major portions taken verbatim or adapted from the Lua interpreter. -** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h -*/ - -#include -#include - -#define lib_os_c -#define LUA_LIB - -#include "lua.h" -#include "lauxlib.h" -#include "lualib.h" - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_buf.h" -#include "lj_str.h" -#include "lj_lib.h" - -#if LJ_TARGET_POSIX -#include -#else -#include -#endif - -#if !LJ_TARGET_PSVITA -#include -#endif - -/* ------------------------------------------------------------------------ */ - -#define LJLIB_MODULE_os - -LJLIB_CF(os_execute) -{ -#if LJ_NO_SYSTEM -#if LJ_52 - errno = ENOSYS; - return luaL_fileresult(L, 0, NULL); -#else - lua_pushinteger(L, -1); - return 1; -#endif -#else - const char *cmd = luaL_optstring(L, 1, NULL); - int stat = system(cmd); -#if LJ_52 - if (cmd) - return luaL_execresult(L, stat); - setboolV(L->top++, 1); -#else - setintV(L->top++, stat); -#endif - return 1; -#endif -} - -LJLIB_CF(os_remove) -{ - const char *filename = luaL_checkstring(L, 1); - return luaL_fileresult(L, remove(filename) == 0, filename); -} - -LJLIB_CF(os_rename) -{ - const char *fromname = luaL_checkstring(L, 1); - const char *toname = luaL_checkstring(L, 2); - return luaL_fileresult(L, rename(fromname, toname) == 0, fromname); -} - -LJLIB_CF(os_tmpname) -{ -#if LJ_TARGET_PS3 || LJ_TARGET_PS4 || LJ_TARGET_PSVITA - lj_err_caller(L, LJ_ERR_OSUNIQF); - return 0; -#else -#if LJ_TARGET_POSIX - char buf[15+1]; - int fp; - strcpy(buf, "/tmp/lua_XXXXXX"); - fp = mkstemp(buf); - if (fp != -1) - close(fp); - else - lj_err_caller(L, LJ_ERR_OSUNIQF); -#else - char buf[L_tmpnam]; - if (tmpnam(buf) == NULL) - lj_err_caller(L, LJ_ERR_OSUNIQF); -#endif - lua_pushstring(L, buf); - return 1; -#endif -} - -LJLIB_CF(os_getenv) -{ -#if LJ_TARGET_CONSOLE - lua_pushnil(L); -#else - lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ -#endif - return 1; -} - -LJLIB_CF(os_exit) -{ - int status; - if (L->base < L->top && tvisbool(L->base)) - status = boolV(L->base) ? EXIT_SUCCESS : EXIT_FAILURE; - else - status = lj_lib_optint(L, 1, EXIT_SUCCESS); - if (L->base+1 < L->top && tvistruecond(L->base+1)) - lua_close(L); - exit(status); - return 0; /* Unreachable. */ -} - -LJLIB_CF(os_clock) -{ - setnumV(L->top++, ((lua_Number)clock())*(1.0/(lua_Number)CLOCKS_PER_SEC)); - return 1; -} - -/* ------------------------------------------------------------------------ */ - -static void setfield(lua_State *L, const char *key, int value) -{ - lua_pushinteger(L, value); - lua_setfield(L, -2, key); -} - -static void setboolfield(lua_State *L, const char *key, int value) -{ - if (value < 0) /* undefined? */ - return; /* does not set field */ - lua_pushboolean(L, value); - lua_setfield(L, -2, key); -} - -static int getboolfield(lua_State *L, const char *key) -{ - int res; - lua_getfield(L, -1, key); - res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1); - lua_pop(L, 1); - return res; -} - -static int getfield(lua_State *L, const char *key, int d) -{ - int res; - lua_getfield(L, -1, key); - if (lua_isnumber(L, -1)) { - res = (int)lua_tointeger(L, -1); - } else { - if (d < 0) - lj_err_callerv(L, LJ_ERR_OSDATEF, key); - res = d; - } - lua_pop(L, 1); - return res; -} - -LJLIB_CF(os_date) -{ - const char *s = luaL_optstring(L, 1, "%c"); - time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL)); - struct tm *stm; -#if LJ_TARGET_POSIX - struct tm rtm; -#endif - if (*s == '!') { /* UTC? */ - s++; /* Skip '!' */ -#if LJ_TARGET_POSIX - stm = gmtime_r(&t, &rtm); -#else - stm = gmtime(&t); -#endif - } else { -#if LJ_TARGET_POSIX - stm = localtime_r(&t, &rtm); -#else - stm = localtime(&t); -#endif - } - if (stm == NULL) { /* Invalid date? */ - setnilV(L->top++); - } else if (strcmp(s, "*t") == 0) { - lua_createtable(L, 0, 9); /* 9 = number of fields */ - setfield(L, "sec", stm->tm_sec); - setfield(L, "min", stm->tm_min); - setfield(L, "hour", stm->tm_hour); - setfield(L, "day", stm->tm_mday); - setfield(L, "month", stm->tm_mon+1); - setfield(L, "year", stm->tm_year+1900); - setfield(L, "wday", stm->tm_wday+1); - setfield(L, "yday", stm->tm_yday+1); - setboolfield(L, "isdst", stm->tm_isdst); - } else if (*s) { - SBuf *sb = &G(L)->tmpbuf; - MSize sz = 0, retry = 4; - const char *q; - for (q = s; *q; q++) - sz += (*q == '%') ? 30 : 1; /* Overflow doesn't matter. */ - setsbufL(sb, L); - while (retry--) { /* Limit growth for invalid format or empty result. */ - char *buf = lj_buf_need(sb, sz); - size_t len = strftime(buf, sbufsz(sb), s, stm); - if (len) { - setstrV(L, L->top++, lj_str_new(L, buf, len)); - lj_gc_check(L); - break; - } - sz += (sz|1); - } - } else { - setstrV(L, L->top++, &G(L)->strempty); - } - return 1; -} - -LJLIB_CF(os_time) -{ - time_t t; - if (lua_isnoneornil(L, 1)) { /* called without args? */ - t = time(NULL); /* get current time */ - } else { - struct tm ts; - luaL_checktype(L, 1, LUA_TTABLE); - lua_settop(L, 1); /* make sure table is at the top */ - ts.tm_sec = getfield(L, "sec", 0); - ts.tm_min = getfield(L, "min", 0); - ts.tm_hour = getfield(L, "hour", 12); - ts.tm_mday = getfield(L, "day", -1); - ts.tm_mon = getfield(L, "month", -1) - 1; - ts.tm_year = getfield(L, "year", -1) - 1900; - ts.tm_isdst = getboolfield(L, "isdst"); - t = mktime(&ts); - } - if (t == (time_t)(-1)) - lua_pushnil(L); - else - lua_pushnumber(L, (lua_Number)t); - return 1; -} - -LJLIB_CF(os_difftime) -{ - lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)), - (time_t)(luaL_optnumber(L, 2, (lua_Number)0)))); - return 1; -} - -/* ------------------------------------------------------------------------ */ - -LJLIB_CF(os_setlocale) -{ -#if LJ_TARGET_PSVITA - lua_pushliteral(L, "C"); -#else - GCstr *s = lj_lib_optstr(L, 1); - const char *str = s ? strdata(s) : NULL; - int opt = lj_lib_checkopt(L, 2, 6, - "\5ctype\7numeric\4time\7collate\10monetary\1\377\3all"); - if (opt == 0) opt = LC_CTYPE; - else if (opt == 1) opt = LC_NUMERIC; - else if (opt == 2) opt = LC_TIME; - else if (opt == 3) opt = LC_COLLATE; - else if (opt == 4) opt = LC_MONETARY; - else if (opt == 6) opt = LC_ALL; - lua_pushstring(L, setlocale(opt, str)); -#endif - return 1; -} - -/* ------------------------------------------------------------------------ */ - -#include "lj_libdef.h" - -LUALIB_API int luaopen_os(lua_State *L) -{ - LJ_LIB_REG(L, LUA_OSLIBNAME, os); - return 1; -} - diff --git a/lib/LuaJIT/src/lib_package.c b/lib/LuaJIT/src/lib_package.c deleted file mode 100644 index bedd6d7..0000000 --- a/lib/LuaJIT/src/lib_package.c +++ /dev/null @@ -1,623 +0,0 @@ -/* -** Package library. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Major portions taken verbatim or adapted from the Lua interpreter. -** Copyright (C) 1994-2012 Lua.org, PUC-Rio. See Copyright Notice in lua.h -*/ - -#define lib_package_c -#define LUA_LIB - -#include "lua.h" -#include "lauxlib.h" -#include "lualib.h" - -#include "lj_obj.h" -#include "lj_err.h" -#include "lj_lib.h" - -/* ------------------------------------------------------------------------ */ - -/* Error codes for ll_loadfunc. */ -#define PACKAGE_ERR_LIB 1 -#define PACKAGE_ERR_FUNC 2 -#define PACKAGE_ERR_LOAD 3 - -/* Redefined in platform specific part. */ -#define PACKAGE_LIB_FAIL "open" -#define setprogdir(L) ((void)0) - -/* Symbol name prefixes. */ -#define SYMPREFIX_CF "luaopen_%s" -#define SYMPREFIX_BC "luaJIT_BC_%s" - -#if LJ_TARGET_DLOPEN - -#include - -static void ll_unloadlib(void *lib) -{ - dlclose(lib); -} - -static void *ll_load(lua_State *L, const char *path, int gl) -{ - void *lib = dlopen(path, RTLD_NOW | (gl ? RTLD_GLOBAL : RTLD_LOCAL)); - if (lib == NULL) lua_pushstring(L, dlerror()); - return lib; -} - -static lua_CFunction ll_sym(lua_State *L, void *lib, const char *sym) -{ - lua_CFunction f = (lua_CFunction)dlsym(lib, sym); - if (f == NULL) lua_pushstring(L, dlerror()); - return f; -} - -static const char *ll_bcsym(void *lib, const char *sym) -{ -#if defined(RTLD_DEFAULT) - if (lib == NULL) lib = RTLD_DEFAULT; -#elif LJ_TARGET_OSX || LJ_TARGET_BSD - if (lib == NULL) lib = (void *)(intptr_t)-2; -#endif - return (const char *)dlsym(lib, sym); -} - -#elif LJ_TARGET_WINDOWS - -#define WIN32_LEAN_AND_MEAN -#include - -#ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS -#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4 -#define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2 -BOOL WINAPI GetModuleHandleExA(DWORD, LPCSTR, HMODULE*); -#endif - -#if LJ_TARGET_UWP -void *LJ_WIN_LOADLIBA(const char *path) -{ - DWORD err = GetLastError(); - wchar_t wpath[256]; - HANDLE lib = NULL; - if (MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, 256) > 0) { - lib = LoadPackagedLibrary(wpath, 0); - } - SetLastError(err); - return lib; -} -#endif - -#undef setprogdir - -static void setprogdir(lua_State *L) -{ - char buff[MAX_PATH + 1]; - char *lb; - DWORD nsize = sizeof(buff); - DWORD n = GetModuleFileNameA(NULL, buff, nsize); - if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) { - luaL_error(L, "unable to get ModuleFileName"); - } else { - *lb = '\0'; - luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff); - lua_remove(L, -2); /* remove original string */ - } -} - -static void pusherror(lua_State *L) -{ - DWORD error = GetLastError(); -#if LJ_TARGET_XBOXONE - wchar_t wbuffer[128]; - char buffer[128*2]; - if (FormatMessageW(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, error, 0, wbuffer, sizeof(wbuffer)/sizeof(wchar_t), NULL) && - WideCharToMultiByte(CP_ACP, 0, wbuffer, 128, buffer, 128*2, NULL, NULL)) -#else - char buffer[128]; - if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, error, 0, buffer, sizeof(buffer), NULL)) -#endif - lua_pushstring(L, buffer); - else - lua_pushfstring(L, "system error %d\n", error); -} - -static void ll_unloadlib(void *lib) -{ - FreeLibrary((HINSTANCE)lib); -} - -static void *ll_load(lua_State *L, const char *path, int gl) -{ - HINSTANCE lib = LJ_WIN_LOADLIBA(path); - if (lib == NULL) pusherror(L); - UNUSED(gl); - return lib; -} - -static lua_CFunction ll_sym(lua_State *L, void *lib, const char *sym) -{ - lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym); - if (f == NULL) pusherror(L); - return f; -} - -#if LJ_TARGET_UWP -EXTERN_C IMAGE_DOS_HEADER __ImageBase; -#endif - -static const char *ll_bcsym(void *lib, const char *sym) -{ - if (lib) { - return (const char *)GetProcAddress((HINSTANCE)lib, sym); - } else { -#if LJ_TARGET_UWP - return (const char *)GetProcAddress((HINSTANCE)&__ImageBase, sym); -#else - HINSTANCE h = GetModuleHandleA(NULL); - const char *p = (const char *)GetProcAddress(h, sym); - if (p == NULL && GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, - (const char *)ll_bcsym, &h)) - p = (const char *)GetProcAddress(h, sym); - return p; -#endif - } -} - -#else - -#undef PACKAGE_LIB_FAIL -#define PACKAGE_LIB_FAIL "absent" - -#define DLMSG "dynamic libraries not enabled; no support for target OS" - -static void ll_unloadlib(void *lib) -{ - UNUSED(lib); -} - -static void *ll_load(lua_State *L, const char *path, int gl) -{ - UNUSED(path); UNUSED(gl); - lua_pushliteral(L, DLMSG); - return NULL; -} - -static lua_CFunction ll_sym(lua_State *L, void *lib, const char *sym) -{ - UNUSED(lib); UNUSED(sym); - lua_pushliteral(L, DLMSG); - return NULL; -} - -static const char *ll_bcsym(void *lib, const char *sym) -{ - UNUSED(lib); UNUSED(sym); - return NULL; -} - -#endif - -/* ------------------------------------------------------------------------ */ - -static void **ll_register(lua_State *L, const char *path) -{ - void **plib; - lua_pushfstring(L, "LOADLIB: %s", path); - lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */ - if (!lua_isnil(L, -1)) { /* is there an entry? */ - plib = (void **)lua_touserdata(L, -1); - } else { /* no entry yet; create one */ - lua_pop(L, 1); - plib = (void **)lua_newuserdata(L, sizeof(void *)); - *plib = NULL; - luaL_setmetatable(L, "_LOADLIB"); - lua_pushfstring(L, "LOADLIB: %s", path); - lua_pushvalue(L, -2); - lua_settable(L, LUA_REGISTRYINDEX); - } - return plib; -} - -static const char *mksymname(lua_State *L, const char *modname, - const char *prefix) -{ - const char *funcname; - const char *mark = strchr(modname, *LUA_IGMARK); - if (mark) modname = mark + 1; - funcname = luaL_gsub(L, modname, ".", "_"); - funcname = lua_pushfstring(L, prefix, funcname); - lua_remove(L, -2); /* remove 'gsub' result */ - return funcname; -} - -static int ll_loadfunc(lua_State *L, const char *path, const char *name, int r) -{ - void **reg = ll_register(L, path); - if (*reg == NULL) *reg = ll_load(L, path, (*name == '*')); - if (*reg == NULL) { - return PACKAGE_ERR_LIB; /* Unable to load library. */ - } else if (*name == '*') { /* Only load library into global namespace. */ - lua_pushboolean(L, 1); - return 0; - } else { - const char *sym = r ? name : mksymname(L, name, SYMPREFIX_CF); - lua_CFunction f = ll_sym(L, *reg, sym); - if (f) { - lua_pushcfunction(L, f); - return 0; - } - if (!r) { - const char *bcdata = ll_bcsym(*reg, mksymname(L, name, SYMPREFIX_BC)); - lua_pop(L, 1); - if (bcdata) { - if (luaL_loadbuffer(L, bcdata, LJ_MAX_BUF, name) != 0) - return PACKAGE_ERR_LOAD; - return 0; - } - } - return PACKAGE_ERR_FUNC; /* Unable to find function. */ - } -} - -static int lj_cf_package_loadlib(lua_State *L) -{ - const char *path = luaL_checkstring(L, 1); - const char *init = luaL_checkstring(L, 2); - int st = ll_loadfunc(L, path, init, 1); - if (st == 0) { /* no errors? */ - return 1; /* return the loaded function */ - } else { /* error; error message is on stack top */ - lua_pushnil(L); - lua_insert(L, -2); - lua_pushstring(L, (st == PACKAGE_ERR_LIB) ? PACKAGE_LIB_FAIL : "init"); - return 3; /* return nil, error message, and where */ - } -} - -static int lj_cf_package_unloadlib(lua_State *L) -{ - void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB"); - if (*lib) ll_unloadlib(*lib); - *lib = NULL; /* mark library as closed */ - return 0; -} - -/* ------------------------------------------------------------------------ */ - -static int readable(const char *filename) -{ - FILE *f = fopen(filename, "r"); /* try to open file */ - if (f == NULL) return 0; /* open failed */ - fclose(f); - return 1; -} - -static const char *pushnexttemplate(lua_State *L, const char *path) -{ - const char *l; - while (*path == *LUA_PATHSEP) path++; /* skip separators */ - if (*path == '\0') return NULL; /* no more templates */ - l = strchr(path, *LUA_PATHSEP); /* find next separator */ - if (l == NULL) l = path + strlen(path); - lua_pushlstring(L, path, (size_t)(l - path)); /* template */ - return l; -} - -static const char *searchpath (lua_State *L, const char *name, - const char *path, const char *sep, - const char *dirsep) -{ - luaL_Buffer msg; /* to build error message */ - luaL_buffinit(L, &msg); - if (*sep != '\0') /* non-empty separator? */ - name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */ - while ((path = pushnexttemplate(L, path)) != NULL) { - const char *filename = luaL_gsub(L, lua_tostring(L, -1), - LUA_PATH_MARK, name); - lua_remove(L, -2); /* remove path template */ - if (readable(filename)) /* does file exist and is readable? */ - return filename; /* return that file name */ - lua_pushfstring(L, "\n\tno file " LUA_QS, filename); - lua_remove(L, -2); /* remove file name */ - luaL_addvalue(&msg); /* concatenate error msg. entry */ - } - luaL_pushresult(&msg); /* create error message */ - return NULL; /* not found */ -} - -static int lj_cf_package_searchpath(lua_State *L) -{ - const char *f = searchpath(L, luaL_checkstring(L, 1), - luaL_checkstring(L, 2), - luaL_optstring(L, 3, "."), - luaL_optstring(L, 4, LUA_DIRSEP)); - if (f != NULL) { - return 1; - } else { /* error message is on top of the stack */ - lua_pushnil(L); - lua_insert(L, -2); - return 2; /* return nil + error message */ - } -} - -static const char *findfile(lua_State *L, const char *name, - const char *pname) -{ - const char *path; - lua_getfield(L, LUA_ENVIRONINDEX, pname); - path = lua_tostring(L, -1); - if (path == NULL) - luaL_error(L, LUA_QL("package.%s") " must be a string", pname); - return searchpath(L, name, path, ".", LUA_DIRSEP); -} - -static void loaderror(lua_State *L, const char *filename) -{ - luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s", - lua_tostring(L, 1), filename, lua_tostring(L, -1)); -} - -static int lj_cf_package_loader_lua(lua_State *L) -{ - const char *filename; - const char *name = luaL_checkstring(L, 1); - filename = findfile(L, name, "path"); - if (filename == NULL) return 1; /* library not found in this path */ - if (luaL_loadfile(L, filename) != 0) - loaderror(L, filename); - return 1; /* library loaded successfully */ -} - -static int lj_cf_package_loader_c(lua_State *L) -{ - const char *name = luaL_checkstring(L, 1); - const char *filename = findfile(L, name, "cpath"); - if (filename == NULL) return 1; /* library not found in this path */ - if (ll_loadfunc(L, filename, name, 0) != 0) - loaderror(L, filename); - return 1; /* library loaded successfully */ -} - -static int lj_cf_package_loader_croot(lua_State *L) -{ - const char *filename; - const char *name = luaL_checkstring(L, 1); - const char *p = strchr(name, '.'); - int st; - if (p == NULL) return 0; /* is root */ - lua_pushlstring(L, name, (size_t)(p - name)); - filename = findfile(L, lua_tostring(L, -1), "cpath"); - if (filename == NULL) return 1; /* root not found */ - if ((st = ll_loadfunc(L, filename, name, 0)) != 0) { - if (st != PACKAGE_ERR_FUNC) loaderror(L, filename); /* real error */ - lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, - name, filename); - return 1; /* function not found */ - } - return 1; -} - -static int lj_cf_package_loader_preload(lua_State *L) -{ - const char *name = luaL_checkstring(L, 1); - lua_getfield(L, LUA_ENVIRONINDEX, "preload"); - if (!lua_istable(L, -1)) - luaL_error(L, LUA_QL("package.preload") " must be a table"); - lua_getfield(L, -1, name); - if (lua_isnil(L, -1)) { /* Not found? */ - const char *bcname = mksymname(L, name, SYMPREFIX_BC); - const char *bcdata = ll_bcsym(NULL, bcname); - if (bcdata == NULL || luaL_loadbuffer(L, bcdata, LJ_MAX_BUF, name) != 0) - lua_pushfstring(L, "\n\tno field package.preload['%s']", name); - } - return 1; -} - -/* ------------------------------------------------------------------------ */ - -#define sentinel ((void *)0x4004) - -static int lj_cf_package_require(lua_State *L) -{ - const char *name = luaL_checkstring(L, 1); - int i; - lua_settop(L, 1); /* _LOADED table will be at index 2 */ - lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); - lua_getfield(L, 2, name); - if (lua_toboolean(L, -1)) { /* is it there? */ - if (lua_touserdata(L, -1) == sentinel) /* check loops */ - luaL_error(L, "loop or previous error loading module " LUA_QS, name); - return 1; /* package is already loaded */ - } - /* else must load it; iterate over available loaders */ - lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); - if (!lua_istable(L, -1)) - luaL_error(L, LUA_QL("package.loaders") " must be a table"); - lua_pushliteral(L, ""); /* error message accumulator */ - for (i = 1; ; i++) { - lua_rawgeti(L, -2, i); /* get a loader */ - if (lua_isnil(L, -1)) - luaL_error(L, "module " LUA_QS " not found:%s", - name, lua_tostring(L, -2)); - lua_pushstring(L, name); - lua_call(L, 1, 1); /* call it */ - if (lua_isfunction(L, -1)) /* did it find module? */ - break; /* module loaded successfully */ - else if (lua_isstring(L, -1)) /* loader returned error message? */ - lua_concat(L, 2); /* accumulate it */ - else - lua_pop(L, 1); - } - lua_pushlightuserdata(L, sentinel); - lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */ - lua_pushstring(L, name); /* pass name as argument to module */ - lua_call(L, 1, 1); /* run loaded module */ - if (!lua_isnil(L, -1)) /* non-nil return? */ - lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ - lua_getfield(L, 2, name); - if (lua_touserdata(L, -1) == sentinel) { /* module did not set a value? */ - lua_pushboolean(L, 1); /* use true as result */ - lua_pushvalue(L, -1); /* extra copy to be returned */ - lua_setfield(L, 2, name); /* _LOADED[name] = true */ - } - lj_lib_checkfpu(L); - return 1; -} - -/* ------------------------------------------------------------------------ */ - -static void setfenv(lua_State *L) -{ - lua_Debug ar; - if (lua_getstack(L, 1, &ar) == 0 || - lua_getinfo(L, "f", &ar) == 0 || /* get calling function */ - lua_iscfunction(L, -1)) - luaL_error(L, LUA_QL("module") " not called from a Lua function"); - lua_pushvalue(L, -2); - lua_setfenv(L, -2); - lua_pop(L, 1); -} - -static void dooptions(lua_State *L, int n) -{ - int i; - for (i = 2; i <= n; i++) { - lua_pushvalue(L, i); /* get option (a function) */ - lua_pushvalue(L, -2); /* module */ - lua_call(L, 1, 0); - } -} - -static void modinit(lua_State *L, const char *modname) -{ - const char *dot; - lua_pushvalue(L, -1); - lua_setfield(L, -2, "_M"); /* module._M = module */ - lua_pushstring(L, modname); - lua_setfield(L, -2, "_NAME"); - dot = strrchr(modname, '.'); /* look for last dot in module name */ - if (dot == NULL) dot = modname; else dot++; - /* set _PACKAGE as package name (full module name minus last part) */ - lua_pushlstring(L, modname, (size_t)(dot - modname)); - lua_setfield(L, -2, "_PACKAGE"); -} - -static int lj_cf_package_module(lua_State *L) -{ - const char *modname = luaL_checkstring(L, 1); - int lastarg = (int)(L->top - L->base); - luaL_pushmodule(L, modname, 1); - lua_getfield(L, -1, "_NAME"); - if (!lua_isnil(L, -1)) { /* Module already initialized? */ - lua_pop(L, 1); - } else { - lua_pop(L, 1); - modinit(L, modname); - } - lua_pushvalue(L, -1); - setfenv(L); - dooptions(L, lastarg); - return LJ_52; -} - -static int lj_cf_package_seeall(lua_State *L) -{ - luaL_checktype(L, 1, LUA_TTABLE); - if (!lua_getmetatable(L, 1)) { - lua_createtable(L, 0, 1); /* create new metatable */ - lua_pushvalue(L, -1); - lua_setmetatable(L, 1); - } - lua_pushvalue(L, LUA_GLOBALSINDEX); - lua_setfield(L, -2, "__index"); /* mt.__index = _G */ - return 0; -} - -/* ------------------------------------------------------------------------ */ - -#define AUXMARK "\1" - -static void setpath(lua_State *L, const char *fieldname, const char *envname, - const char *def, int noenv) -{ -#if LJ_TARGET_CONSOLE - const char *path = NULL; - UNUSED(envname); -#else - const char *path = getenv(envname); -#endif - if (path == NULL || noenv) { - lua_pushstring(L, def); - } else { - path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP, - LUA_PATHSEP AUXMARK LUA_PATHSEP); - luaL_gsub(L, path, AUXMARK, def); - lua_remove(L, -2); - } - setprogdir(L); - lua_setfield(L, -2, fieldname); -} - -static const luaL_Reg package_lib[] = { - { "loadlib", lj_cf_package_loadlib }, - { "searchpath", lj_cf_package_searchpath }, - { "seeall", lj_cf_package_seeall }, - { NULL, NULL } -}; - -static const luaL_Reg package_global[] = { - { "module", lj_cf_package_module }, - { "require", lj_cf_package_require }, - { NULL, NULL } -}; - -static const lua_CFunction package_loaders[] = -{ - lj_cf_package_loader_preload, - lj_cf_package_loader_lua, - lj_cf_package_loader_c, - lj_cf_package_loader_croot, - NULL -}; - -LUALIB_API int luaopen_package(lua_State *L) -{ - int i; - int noenv; - luaL_newmetatable(L, "_LOADLIB"); - lj_lib_pushcf(L, lj_cf_package_unloadlib, 1); - lua_setfield(L, -2, "__gc"); - luaL_register(L, LUA_LOADLIBNAME, package_lib); - lua_copy(L, -1, LUA_ENVIRONINDEX); - lua_createtable(L, sizeof(package_loaders)/sizeof(package_loaders[0])-1, 0); - for (i = 0; package_loaders[i] != NULL; i++) { - lj_lib_pushcf(L, package_loaders[i], 1); - lua_rawseti(L, -2, i+1); - } -#if LJ_52 - lua_pushvalue(L, -1); - lua_setfield(L, -3, "searchers"); -#endif - lua_setfield(L, -2, "loaders"); - lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); - noenv = lua_toboolean(L, -1); - lua_pop(L, 1); - setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT, noenv); - setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT, noenv); - lua_pushliteral(L, LUA_PATH_CONFIG); - lua_setfield(L, -2, "config"); - luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 16); - lua_setfield(L, -2, "loaded"); - luaL_findtable(L, LUA_REGISTRYINDEX, "_PRELOAD", 4); - lua_setfield(L, -2, "preload"); - lua_pushvalue(L, LUA_GLOBALSINDEX); - luaL_register(L, NULL, package_global); - lua_pop(L, 1); - return 1; -} - diff --git a/lib/LuaJIT/src/lib_string.c b/lib/LuaJIT/src/lib_string.c deleted file mode 100644 index 76b0730..0000000 --- a/lib/LuaJIT/src/lib_string.c +++ /dev/null @@ -1,748 +0,0 @@ -/* -** String library. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Major portions taken verbatim or adapted from the Lua interpreter. -** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h -*/ - -#define lib_string_c -#define LUA_LIB - -#include "lua.h" -#include "lauxlib.h" -#include "lualib.h" - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_buf.h" -#include "lj_str.h" -#include "lj_tab.h" -#include "lj_meta.h" -#include "lj_state.h" -#include "lj_ff.h" -#include "lj_bcdump.h" -#include "lj_char.h" -#include "lj_strfmt.h" -#include "lj_lib.h" - -/* ------------------------------------------------------------------------ */ - -#define LJLIB_MODULE_string - -LJLIB_LUA(string_len) /* - function(s) - CHECK_str(s) - return #s - end -*/ - -LJLIB_ASM(string_byte) LJLIB_REC(string_range 0) -{ - GCstr *s = lj_lib_checkstr(L, 1); - int32_t len = (int32_t)s->len; - int32_t start = lj_lib_optint(L, 2, 1); - int32_t stop = lj_lib_optint(L, 3, start); - int32_t n, i; - const unsigned char *p; - if (stop < 0) stop += len+1; - if (start < 0) start += len+1; - if (start <= 0) start = 1; - if (stop > len) stop = len; - if (start > stop) return FFH_RES(0); /* Empty interval: return no results. */ - start--; - n = stop - start; - if ((uint32_t)n > LUAI_MAXCSTACK) - lj_err_caller(L, LJ_ERR_STRSLC); - lj_state_checkstack(L, (MSize)n); - p = (const unsigned char *)strdata(s) + start; - for (i = 0; i < n; i++) - setintV(L->base + i-1-LJ_FR2, p[i]); - return FFH_RES(n); -} - -LJLIB_ASM(string_char) LJLIB_REC(.) -{ - int i, nargs = (int)(L->top - L->base); - char *buf = lj_buf_tmp(L, (MSize)nargs); - for (i = 1; i <= nargs; i++) { - int32_t k = lj_lib_checkint(L, i); - if (!checku8(k)) - lj_err_arg(L, i, LJ_ERR_BADVAL); - buf[i-1] = (char)k; - } - setstrV(L, L->base-1-LJ_FR2, lj_str_new(L, buf, (size_t)nargs)); - return FFH_RES(1); -} - -LJLIB_ASM(string_sub) LJLIB_REC(string_range 1) -{ - lj_lib_checkstr(L, 1); - lj_lib_checkint(L, 2); - setintV(L->base+2, lj_lib_optint(L, 3, -1)); - return FFH_RETRY; -} - -LJLIB_CF(string_rep) LJLIB_REC(.) -{ - GCstr *s = lj_lib_checkstr(L, 1); - int32_t rep = lj_lib_checkint(L, 2); - GCstr *sep = lj_lib_optstr(L, 3); - SBuf *sb = lj_buf_tmp_(L); - if (sep && rep > 1) { - GCstr *s2 = lj_buf_cat2str(L, sep, s); - lj_buf_reset(sb); - lj_buf_putstr(sb, s); - s = s2; - rep--; - } - sb = lj_buf_putstr_rep(sb, s, rep); - setstrV(L, L->top-1, lj_buf_str(L, sb)); - lj_gc_check(L); - return 1; -} - -LJLIB_ASM(string_reverse) LJLIB_REC(string_op IRCALL_lj_buf_putstr_reverse) -{ - lj_lib_checkstr(L, 1); - return FFH_RETRY; -} -LJLIB_ASM_(string_lower) LJLIB_REC(string_op IRCALL_lj_buf_putstr_lower) -LJLIB_ASM_(string_upper) LJLIB_REC(string_op IRCALL_lj_buf_putstr_upper) - -/* ------------------------------------------------------------------------ */ - -static int writer_buf(lua_State *L, const void *p, size_t size, void *sb) -{ - lj_buf_putmem((SBuf *)sb, p, (MSize)size); - UNUSED(L); - return 0; -} - -LJLIB_CF(string_dump) -{ - GCfunc *fn = lj_lib_checkfunc(L, 1); - int strip = L->base+1 < L->top && tvistruecond(L->base+1); - SBuf *sb = lj_buf_tmp_(L); /* Assumes lj_bcwrite() doesn't use tmpbuf. */ - L->top = L->base+1; - if (!isluafunc(fn) || lj_bcwrite(L, funcproto(fn), writer_buf, sb, strip)) - lj_err_caller(L, LJ_ERR_STRDUMP); - setstrV(L, L->top-1, lj_buf_str(L, sb)); - lj_gc_check(L); - return 1; -} - -/* ------------------------------------------------------------------------ */ - -/* macro to `unsign' a character */ -#define uchar(c) ((unsigned char)(c)) - -#define CAP_UNFINISHED (-1) -#define CAP_POSITION (-2) - -typedef struct MatchState { - const char *src_init; /* init of source string */ - const char *src_end; /* end (`\0') of source string */ - lua_State *L; - int level; /* total number of captures (finished or unfinished) */ - int depth; - struct { - const char *init; - ptrdiff_t len; - } capture[LUA_MAXCAPTURES]; -} MatchState; - -#define L_ESC '%' - -static int check_capture(MatchState *ms, int l) -{ - l -= '1'; - if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) - lj_err_caller(ms->L, LJ_ERR_STRCAPI); - return l; -} - -static int capture_to_close(MatchState *ms) -{ - int level = ms->level; - for (level--; level>=0; level--) - if (ms->capture[level].len == CAP_UNFINISHED) return level; - lj_err_caller(ms->L, LJ_ERR_STRPATC); - return 0; /* unreachable */ -} - -static const char *classend(MatchState *ms, const char *p) -{ - switch (*p++) { - case L_ESC: - if (*p == '\0') - lj_err_caller(ms->L, LJ_ERR_STRPATE); - return p+1; - case '[': - if (*p == '^') p++; - do { /* look for a `]' */ - if (*p == '\0') - lj_err_caller(ms->L, LJ_ERR_STRPATM); - if (*(p++) == L_ESC && *p != '\0') - p++; /* skip escapes (e.g. `%]') */ - } while (*p != ']'); - return p+1; - default: - return p; - } -} - -static const unsigned char match_class_map[32] = { - 0,LJ_CHAR_ALPHA,0,LJ_CHAR_CNTRL,LJ_CHAR_DIGIT,0,0,LJ_CHAR_GRAPH,0,0,0,0, - LJ_CHAR_LOWER,0,0,0,LJ_CHAR_PUNCT,0,0,LJ_CHAR_SPACE,0, - LJ_CHAR_UPPER,0,LJ_CHAR_ALNUM,LJ_CHAR_XDIGIT,0,0,0,0,0,0,0 -}; - -static int match_class(int c, int cl) -{ - if ((cl & 0xc0) == 0x40) { - int t = match_class_map[(cl&0x1f)]; - if (t) { - t = lj_char_isa(c, t); - return (cl & 0x20) ? t : !t; - } - if (cl == 'z') return c == 0; - if (cl == 'Z') return c != 0; - } - return (cl == c); -} - -static int matchbracketclass(int c, const char *p, const char *ec) -{ - int sig = 1; - if (*(p+1) == '^') { - sig = 0; - p++; /* skip the `^' */ - } - while (++p < ec) { - if (*p == L_ESC) { - p++; - if (match_class(c, uchar(*p))) - return sig; - } - else if ((*(p+1) == '-') && (p+2 < ec)) { - p+=2; - if (uchar(*(p-2)) <= c && c <= uchar(*p)) - return sig; - } - else if (uchar(*p) == c) return sig; - } - return !sig; -} - -static int singlematch(int c, const char *p, const char *ep) -{ - switch (*p) { - case '.': return 1; /* matches any char */ - case L_ESC: return match_class(c, uchar(*(p+1))); - case '[': return matchbracketclass(c, p, ep-1); - default: return (uchar(*p) == c); - } -} - -static const char *match(MatchState *ms, const char *s, const char *p); - -static const char *matchbalance(MatchState *ms, const char *s, const char *p) -{ - if (*p == 0 || *(p+1) == 0) - lj_err_caller(ms->L, LJ_ERR_STRPATU); - if (*s != *p) { - return NULL; - } else { - int b = *p; - int e = *(p+1); - int cont = 1; - while (++s < ms->src_end) { - if (*s == e) { - if (--cont == 0) return s+1; - } else if (*s == b) { - cont++; - } - } - } - return NULL; /* string ends out of balance */ -} - -static const char *max_expand(MatchState *ms, const char *s, - const char *p, const char *ep) -{ - ptrdiff_t i = 0; /* counts maximum expand for item */ - while ((s+i)src_end && singlematch(uchar(*(s+i)), p, ep)) - i++; - /* keeps trying to match with the maximum repetitions */ - while (i>=0) { - const char *res = match(ms, (s+i), ep+1); - if (res) return res; - i--; /* else didn't match; reduce 1 repetition to try again */ - } - return NULL; -} - -static const char *min_expand(MatchState *ms, const char *s, - const char *p, const char *ep) -{ - for (;;) { - const char *res = match(ms, s, ep+1); - if (res != NULL) - return res; - else if (ssrc_end && singlematch(uchar(*s), p, ep)) - s++; /* try with one more repetition */ - else - return NULL; - } -} - -static const char *start_capture(MatchState *ms, const char *s, - const char *p, int what) -{ - const char *res; - int level = ms->level; - if (level >= LUA_MAXCAPTURES) lj_err_caller(ms->L, LJ_ERR_STRCAPN); - ms->capture[level].init = s; - ms->capture[level].len = what; - ms->level = level+1; - if ((res=match(ms, s, p)) == NULL) /* match failed? */ - ms->level--; /* undo capture */ - return res; -} - -static const char *end_capture(MatchState *ms, const char *s, - const char *p) -{ - int l = capture_to_close(ms); - const char *res; - ms->capture[l].len = s - ms->capture[l].init; /* close capture */ - if ((res = match(ms, s, p)) == NULL) /* match failed? */ - ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ - return res; -} - -static const char *match_capture(MatchState *ms, const char *s, int l) -{ - size_t len; - l = check_capture(ms, l); - len = (size_t)ms->capture[l].len; - if ((size_t)(ms->src_end-s) >= len && - memcmp(ms->capture[l].init, s, len) == 0) - return s+len; - else - return NULL; -} - -static const char *match(MatchState *ms, const char *s, const char *p) -{ - if (++ms->depth > LJ_MAX_XLEVEL) - lj_err_caller(ms->L, LJ_ERR_STRPATX); - init: /* using goto's to optimize tail recursion */ - switch (*p) { - case '(': /* start capture */ - if (*(p+1) == ')') /* position capture? */ - s = start_capture(ms, s, p+2, CAP_POSITION); - else - s = start_capture(ms, s, p+1, CAP_UNFINISHED); - break; - case ')': /* end capture */ - s = end_capture(ms, s, p+1); - break; - case L_ESC: - switch (*(p+1)) { - case 'b': /* balanced string? */ - s = matchbalance(ms, s, p+2); - if (s == NULL) break; - p+=4; - goto init; /* else s = match(ms, s, p+4); */ - case 'f': { /* frontier? */ - const char *ep; char previous; - p += 2; - if (*p != '[') - lj_err_caller(ms->L, LJ_ERR_STRPATB); - ep = classend(ms, p); /* points to what is next */ - previous = (s == ms->src_init) ? '\0' : *(s-1); - if (matchbracketclass(uchar(previous), p, ep-1) || - !matchbracketclass(uchar(*s), p, ep-1)) { s = NULL; break; } - p=ep; - goto init; /* else s = match(ms, s, ep); */ - } - default: - if (lj_char_isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */ - s = match_capture(ms, s, uchar(*(p+1))); - if (s == NULL) break; - p+=2; - goto init; /* else s = match(ms, s, p+2) */ - } - goto dflt; /* case default */ - } - break; - case '\0': /* end of pattern */ - break; /* match succeeded */ - case '$': - /* is the `$' the last char in pattern? */ - if (*(p+1) != '\0') goto dflt; - if (s != ms->src_end) s = NULL; /* check end of string */ - break; - default: dflt: { /* it is a pattern item */ - const char *ep = classend(ms, p); /* points to what is next */ - int m = ssrc_end && singlematch(uchar(*s), p, ep); - switch (*ep) { - case '?': { /* optional */ - const char *res; - if (m && ((res=match(ms, s+1, ep+1)) != NULL)) { - s = res; - break; - } - p=ep+1; - goto init; /* else s = match(ms, s, ep+1); */ - } - case '*': /* 0 or more repetitions */ - s = max_expand(ms, s, p, ep); - break; - case '+': /* 1 or more repetitions */ - s = (m ? max_expand(ms, s+1, p, ep) : NULL); - break; - case '-': /* 0 or more repetitions (minimum) */ - s = min_expand(ms, s, p, ep); - break; - default: - if (m) { s++; p=ep; goto init; } /* else s = match(ms, s+1, ep); */ - s = NULL; - break; - } - break; - } - } - ms->depth--; - return s; -} - -static void push_onecapture(MatchState *ms, int i, const char *s, const char *e) -{ - if (i >= ms->level) { - if (i == 0) /* ms->level == 0, too */ - lua_pushlstring(ms->L, s, (size_t)(e - s)); /* add whole match */ - else - lj_err_caller(ms->L, LJ_ERR_STRCAPI); - } else { - ptrdiff_t l = ms->capture[i].len; - if (l == CAP_UNFINISHED) lj_err_caller(ms->L, LJ_ERR_STRCAPU); - if (l == CAP_POSITION) - lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); - else - lua_pushlstring(ms->L, ms->capture[i].init, (size_t)l); - } -} - -static int push_captures(MatchState *ms, const char *s, const char *e) -{ - int i; - int nlevels = (ms->level == 0 && s) ? 1 : ms->level; - luaL_checkstack(ms->L, nlevels, "too many captures"); - for (i = 0; i < nlevels; i++) - push_onecapture(ms, i, s, e); - return nlevels; /* number of strings pushed */ -} - -static int str_find_aux(lua_State *L, int find) -{ - GCstr *s = lj_lib_checkstr(L, 1); - GCstr *p = lj_lib_checkstr(L, 2); - int32_t start = lj_lib_optint(L, 3, 1); - MSize st; - if (start < 0) start += (int32_t)s->len; else start--; - if (start < 0) start = 0; - st = (MSize)start; - if (st > s->len) { -#if LJ_52 - setnilV(L->top-1); - return 1; -#else - st = s->len; -#endif - } - if (find && ((L->base+3 < L->top && tvistruecond(L->base+3)) || - !lj_str_haspattern(p))) { /* Search for fixed string. */ - const char *q = lj_str_find(strdata(s)+st, strdata(p), s->len-st, p->len); - if (q) { - setintV(L->top-2, (int32_t)(q-strdata(s)) + 1); - setintV(L->top-1, (int32_t)(q-strdata(s)) + (int32_t)p->len); - return 2; - } - } else { /* Search for pattern. */ - MatchState ms; - const char *pstr = strdata(p); - const char *sstr = strdata(s) + st; - int anchor = 0; - if (*pstr == '^') { pstr++; anchor = 1; } - ms.L = L; - ms.src_init = strdata(s); - ms.src_end = strdata(s) + s->len; - do { /* Loop through string and try to match the pattern. */ - const char *q; - ms.level = ms.depth = 0; - q = match(&ms, sstr, pstr); - if (q) { - if (find) { - setintV(L->top++, (int32_t)(sstr-(strdata(s)-1))); - setintV(L->top++, (int32_t)(q-strdata(s))); - return push_captures(&ms, NULL, NULL) + 2; - } else { - return push_captures(&ms, sstr, q); - } - } - } while (sstr++ < ms.src_end && !anchor); - } - setnilV(L->top-1); /* Not found. */ - return 1; -} - -LJLIB_CF(string_find) LJLIB_REC(.) -{ - return str_find_aux(L, 1); -} - -LJLIB_CF(string_match) -{ - return str_find_aux(L, 0); -} - -LJLIB_NOREG LJLIB_CF(string_gmatch_aux) -{ - const char *p = strVdata(lj_lib_upvalue(L, 2)); - GCstr *str = strV(lj_lib_upvalue(L, 1)); - const char *s = strdata(str); - TValue *tvpos = lj_lib_upvalue(L, 3); - const char *src = s + tvpos->u32.lo; - MatchState ms; - ms.L = L; - ms.src_init = s; - ms.src_end = s + str->len; - for (; src <= ms.src_end; src++) { - const char *e; - ms.level = ms.depth = 0; - if ((e = match(&ms, src, p)) != NULL) { - int32_t pos = (int32_t)(e - s); - if (e == src) pos++; /* Ensure progress for empty match. */ - tvpos->u32.lo = (uint32_t)pos; - return push_captures(&ms, src, e); - } - } - return 0; /* not found */ -} - -LJLIB_CF(string_gmatch) -{ - lj_lib_checkstr(L, 1); - lj_lib_checkstr(L, 2); - L->top = L->base+3; - (L->top-1)->u64 = 0; - lj_lib_pushcc(L, lj_cf_string_gmatch_aux, FF_string_gmatch_aux, 3); - return 1; -} - -static void add_s(MatchState *ms, luaL_Buffer *b, const char *s, const char *e) -{ - size_t l, i; - const char *news = lua_tolstring(ms->L, 3, &l); - for (i = 0; i < l; i++) { - if (news[i] != L_ESC) { - luaL_addchar(b, news[i]); - } else { - i++; /* skip ESC */ - if (!lj_char_isdigit(uchar(news[i]))) { - luaL_addchar(b, news[i]); - } else if (news[i] == '0') { - luaL_addlstring(b, s, (size_t)(e - s)); - } else { - push_onecapture(ms, news[i] - '1', s, e); - luaL_addvalue(b); /* add capture to accumulated result */ - } - } - } -} - -static void add_value(MatchState *ms, luaL_Buffer *b, - const char *s, const char *e) -{ - lua_State *L = ms->L; - switch (lua_type(L, 3)) { - case LUA_TNUMBER: - case LUA_TSTRING: { - add_s(ms, b, s, e); - return; - } - case LUA_TFUNCTION: { - int n; - lua_pushvalue(L, 3); - n = push_captures(ms, s, e); - lua_call(L, n, 1); - break; - } - case LUA_TTABLE: { - push_onecapture(ms, 0, s, e); - lua_gettable(L, 3); - break; - } - } - if (!lua_toboolean(L, -1)) { /* nil or false? */ - lua_pop(L, 1); - lua_pushlstring(L, s, (size_t)(e - s)); /* keep original text */ - } else if (!lua_isstring(L, -1)) { - lj_err_callerv(L, LJ_ERR_STRGSRV, luaL_typename(L, -1)); - } - luaL_addvalue(b); /* add result to accumulator */ -} - -LJLIB_CF(string_gsub) -{ - size_t srcl; - const char *src = luaL_checklstring(L, 1, &srcl); - const char *p = luaL_checkstring(L, 2); - int tr = lua_type(L, 3); - int max_s = luaL_optint(L, 4, (int)(srcl+1)); - int anchor = (*p == '^') ? (p++, 1) : 0; - int n = 0; - MatchState ms; - luaL_Buffer b; - if (!(tr == LUA_TNUMBER || tr == LUA_TSTRING || - tr == LUA_TFUNCTION || tr == LUA_TTABLE)) - lj_err_arg(L, 3, LJ_ERR_NOSFT); - luaL_buffinit(L, &b); - ms.L = L; - ms.src_init = src; - ms.src_end = src+srcl; - while (n < max_s) { - const char *e; - ms.level = ms.depth = 0; - e = match(&ms, src, p); - if (e) { - n++; - add_value(&ms, &b, src, e); - } - if (e && e>src) /* non empty match? */ - src = e; /* skip it */ - else if (src < ms.src_end) - luaL_addchar(&b, *src++); - else - break; - if (anchor) - break; - } - luaL_addlstring(&b, src, (size_t)(ms.src_end-src)); - luaL_pushresult(&b); - lua_pushinteger(L, n); /* number of substitutions */ - return 2; -} - -/* ------------------------------------------------------------------------ */ - -/* Emulate tostring() inline. */ -static GCstr *string_fmt_tostring(lua_State *L, int arg, int retry) -{ - TValue *o = L->base+arg-1; - cTValue *mo; - lua_assert(o < L->top); /* Caller already checks for existence. */ - if (LJ_LIKELY(tvisstr(o))) - return strV(o); - if (retry != 2 && !tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) { - copyTV(L, L->top++, mo); - copyTV(L, L->top++, o); - lua_call(L, 1, 1); - copyTV(L, L->base+arg-1, --L->top); - return NULL; /* Buffer may be overwritten, retry. */ - } - return lj_strfmt_obj(L, o); -} - -LJLIB_CF(string_format) LJLIB_REC(.) -{ - int arg, top = (int)(L->top - L->base); - GCstr *fmt; - SBuf *sb; - FormatState fs; - SFormat sf; - int retry = 0; -again: - arg = 1; - sb = lj_buf_tmp_(L); - fmt = lj_lib_checkstr(L, arg); - lj_strfmt_init(&fs, strdata(fmt), fmt->len); - while ((sf = lj_strfmt_parse(&fs)) != STRFMT_EOF) { - if (sf == STRFMT_LIT) { - lj_buf_putmem(sb, fs.str, fs.len); - } else if (sf == STRFMT_ERR) { - lj_err_callerv(L, LJ_ERR_STRFMT, strdata(lj_str_new(L, fs.str, fs.len))); - } else { - if (++arg > top) - luaL_argerror(L, arg, lj_obj_typename[0]); - switch (STRFMT_TYPE(sf)) { - case STRFMT_INT: - if (tvisint(L->base+arg-1)) { - int32_t k = intV(L->base+arg-1); - if (sf == STRFMT_INT) - lj_strfmt_putint(sb, k); /* Shortcut for plain %d. */ - else - lj_strfmt_putfxint(sb, sf, k); - } else { - lj_strfmt_putfnum_int(sb, sf, lj_lib_checknum(L, arg)); - } - break; - case STRFMT_UINT: - if (tvisint(L->base+arg-1)) - lj_strfmt_putfxint(sb, sf, intV(L->base+arg-1)); - else - lj_strfmt_putfnum_uint(sb, sf, lj_lib_checknum(L, arg)); - break; - case STRFMT_NUM: - lj_strfmt_putfnum(sb, sf, lj_lib_checknum(L, arg)); - break; - case STRFMT_STR: { - GCstr *str = string_fmt_tostring(L, arg, retry); - if (str == NULL) - retry = 1; - else if ((sf & STRFMT_T_QUOTED)) - lj_strfmt_putquoted(sb, str); /* No formatting. */ - else - lj_strfmt_putfstr(sb, sf, str); - break; - } - case STRFMT_CHAR: - lj_strfmt_putfchar(sb, sf, lj_lib_checkint(L, arg)); - break; - case STRFMT_PTR: /* No formatting. */ - lj_strfmt_putptr(sb, lj_obj_ptr(L->base+arg-1)); - break; - default: - lua_assert(0); - break; - } - } - } - if (retry++ == 1) goto again; - setstrV(L, L->top-1, lj_buf_str(L, sb)); - lj_gc_check(L); - return 1; -} - -/* ------------------------------------------------------------------------ */ - -#include "lj_libdef.h" - -LUALIB_API int luaopen_string(lua_State *L) -{ - GCtab *mt; - global_State *g; - LJ_LIB_REG(L, LUA_STRLIBNAME, string); - mt = lj_tab_new(L, 0, 1); - /* NOBARRIER: basemt is a GC root. */ - g = G(L); - setgcref(basemt_it(g, LJ_TSTR), obj2gco(mt)); - settabV(L, lj_tab_setstr(L, mt, mmname_str(g, MM_index)), tabV(L->top-1)); - mt->nomm = (uint8_t)(~(1u<array); - Node *node; - lua_Number m = 0; - ptrdiff_t i; - for (i = (ptrdiff_t)t->asize - 1; i >= 0; i--) - if (!tvisnil(&array[i])) { - m = (lua_Number)(int32_t)i; - break; - } - node = noderef(t->node); - for (i = (ptrdiff_t)t->hmask; i >= 0; i--) - if (!tvisnil(&node[i].val) && tvisnumber(&node[i].key)) { - lua_Number n = numberVnum(&node[i].key); - if (n > m) m = n; - } - setnumV(L->top-1, m); - return 1; -} - -LJLIB_CF(table_insert) LJLIB_REC(.) -{ - GCtab *t = lj_lib_checktab(L, 1); - int32_t n, i = (int32_t)lj_tab_len(t) + 1; - int nargs = (int)((char *)L->top - (char *)L->base); - if (nargs != 2*sizeof(TValue)) { - if (nargs != 3*sizeof(TValue)) - lj_err_caller(L, LJ_ERR_TABINS); - /* NOBARRIER: This just moves existing elements around. */ - for (n = lj_lib_checkint(L, 2); i > n; i--) { - /* The set may invalidate the get pointer, so need to do it first! */ - TValue *dst = lj_tab_setint(L, t, i); - cTValue *src = lj_tab_getint(t, i-1); - if (src) { - copyTV(L, dst, src); - } else { - setnilV(dst); - } - } - i = n; - } - { - TValue *dst = lj_tab_setint(L, t, i); - copyTV(L, dst, L->top-1); /* Set new value. */ - lj_gc_barriert(L, t, dst); - } - return 0; -} - -LJLIB_LUA(table_remove) /* - function(t, pos) - CHECK_tab(t) - local len = #t - if pos == nil then - if len ~= 0 then - local old = t[len] - t[len] = nil - return old - end - else - CHECK_int(pos) - if pos >= 1 and pos <= len then - local old = t[pos] - for i=pos+1,len do - t[i-1] = t[i] - end - t[len] = nil - return old - end - end - end -*/ - -LJLIB_LUA(table_move) /* - function(a1, f, e, t, a2) - CHECK_tab(a1) - CHECK_int(f) - CHECK_int(e) - CHECK_int(t) - if a2 == nil then a2 = a1 end - CHECK_tab(a2) - if e >= f then - local d = t - f - if t > e or t <= f or a2 ~= a1 then - for i=f,e do a2[i+d] = a1[i] end - else - for i=e,f,-1 do a2[i+d] = a1[i] end - end - end - return a2 - end -*/ - -LJLIB_CF(table_concat) LJLIB_REC(.) -{ - GCtab *t = lj_lib_checktab(L, 1); - GCstr *sep = lj_lib_optstr(L, 2); - int32_t i = lj_lib_optint(L, 3, 1); - int32_t e = (L->base+3 < L->top && !tvisnil(L->base+3)) ? - lj_lib_checkint(L, 4) : (int32_t)lj_tab_len(t); - SBuf *sb = lj_buf_tmp_(L); - SBuf *sbx = lj_buf_puttab(sb, t, sep, i, e); - if (LJ_UNLIKELY(!sbx)) { /* Error: bad element type. */ - int32_t idx = (int32_t)(intptr_t)sbufP(sb); - cTValue *o = lj_tab_getint(t, idx); - lj_err_callerv(L, LJ_ERR_TABCAT, - lj_obj_itypename[o ? itypemap(o) : ~LJ_TNIL], idx); - } - setstrV(L, L->top-1, lj_buf_str(L, sbx)); - lj_gc_check(L); - return 1; -} - -/* ------------------------------------------------------------------------ */ - -static void set2(lua_State *L, int i, int j) -{ - lua_rawseti(L, 1, i); - lua_rawseti(L, 1, j); -} - -static int sort_comp(lua_State *L, int a, int b) -{ - if (!lua_isnil(L, 2)) { /* function? */ - int res; - lua_pushvalue(L, 2); - lua_pushvalue(L, a-1); /* -1 to compensate function */ - lua_pushvalue(L, b-2); /* -2 to compensate function and `a' */ - lua_call(L, 2, 1); - res = lua_toboolean(L, -1); - lua_pop(L, 1); - return res; - } else { /* a < b? */ - return lua_lessthan(L, a, b); - } -} - -static void auxsort(lua_State *L, int l, int u) -{ - while (l < u) { /* for tail recursion */ - int i, j; - /* sort elements a[l], a[(l+u)/2] and a[u] */ - lua_rawgeti(L, 1, l); - lua_rawgeti(L, 1, u); - if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */ - set2(L, l, u); /* swap a[l] - a[u] */ - else - lua_pop(L, 2); - if (u-l == 1) break; /* only 2 elements */ - i = (l+u)/2; - lua_rawgeti(L, 1, i); - lua_rawgeti(L, 1, l); - if (sort_comp(L, -2, -1)) { /* a[i]= P */ - while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) { - if (i>=u) lj_err_caller(L, LJ_ERR_TABSORT); - lua_pop(L, 1); /* remove a[i] */ - } - /* repeat --j until a[j] <= P */ - while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) { - if (j<=l) lj_err_caller(L, LJ_ERR_TABSORT); - lua_pop(L, 1); /* remove a[j] */ - } - if (jbase+1)) - lj_lib_checkfunc(L, 2); - auxsort(L, 1, n); - return 0; -} - -#if LJ_52 -LJLIB_PUSH("n") -LJLIB_CF(table_pack) -{ - TValue *array, *base = L->base; - MSize i, n = (uint32_t)(L->top - base); - GCtab *t = lj_tab_new(L, n ? n+1 : 0, 1); - /* NOBARRIER: The table is new (marked white). */ - setintV(lj_tab_setstr(L, t, strV(lj_lib_upvalue(L, 1))), (int32_t)n); - for (array = tvref(t->array) + 1, i = 0; i < n; i++) - copyTV(L, &array[i], &base[i]); - settabV(L, base, t); - L->top = base+1; - lj_gc_check(L); - return 1; -} -#endif - -LJLIB_NOREG LJLIB_CF(table_new) LJLIB_REC(.) -{ - int32_t a = lj_lib_checkint(L, 1); - int32_t h = lj_lib_checkint(L, 2); - lua_createtable(L, a, h); - return 1; -} - -LJLIB_NOREG LJLIB_CF(table_clear) LJLIB_REC(.) -{ - lj_tab_clear(lj_lib_checktab(L, 1)); - return 0; -} - -static int luaopen_table_new(lua_State *L) -{ - return lj_lib_postreg(L, lj_cf_table_new, FF_table_new, "new"); -} - -static int luaopen_table_clear(lua_State *L) -{ - return lj_lib_postreg(L, lj_cf_table_clear, FF_table_clear, "clear"); -} - -/* ------------------------------------------------------------------------ */ - -#include "lj_libdef.h" - -LUALIB_API int luaopen_table(lua_State *L) -{ - LJ_LIB_REG(L, LUA_TABLIBNAME, table); -#if LJ_52 - lua_getglobal(L, "unpack"); - lua_setfield(L, -2, "unpack"); -#endif - lj_lib_prereg(L, LUA_TABLIBNAME ".new", luaopen_table_new, tabV(L->top-1)); - lj_lib_prereg(L, LUA_TABLIBNAME ".clear", luaopen_table_clear, tabV(L->top-1)); - return 1; -} - diff --git a/lib/LuaJIT/src/lj.supp b/lib/LuaJIT/src/lj.supp deleted file mode 100644 index 217f7c8..0000000 --- a/lib/LuaJIT/src/lj.supp +++ /dev/null @@ -1,41 +0,0 @@ -# Valgrind suppression file for LuaJIT 2.0. -{ - Optimized string compare - Memcheck:Addr4 - fun:lj_str_cmp -} -{ - Optimized string compare - Memcheck:Addr1 - fun:lj_str_cmp -} -{ - Optimized string compare - Memcheck:Addr4 - fun:lj_str_new -} -{ - Optimized string compare - Memcheck:Addr1 - fun:lj_str_new -} -{ - Optimized string compare - Memcheck:Cond - fun:lj_str_new -} -{ - Optimized string compare - Memcheck:Addr4 - fun:str_fastcmp -} -{ - Optimized string compare - Memcheck:Addr1 - fun:str_fastcmp -} -{ - Optimized string compare - Memcheck:Cond - fun:str_fastcmp -} diff --git a/lib/LuaJIT/src/lj_alloc.c b/lib/LuaJIT/src/lj_alloc.c deleted file mode 100644 index 33a2eb8..0000000 --- a/lib/LuaJIT/src/lj_alloc.c +++ /dev/null @@ -1,1490 +0,0 @@ -/* -** Bundled memory allocator. -** -** Beware: this is a HEAVILY CUSTOMIZED version of dlmalloc. -** The original bears the following remark: -** -** This is a version (aka dlmalloc) of malloc/free/realloc written by -** Doug Lea and released to the public domain, as explained at -** http://creativecommons.org/licenses/publicdomain. -** -** * Version pre-2.8.4 Wed Mar 29 19:46:29 2006 (dl at gee) -** -** No additional copyright is claimed over the customizations. -** Please do NOT bother the original author about this version here! -** -** If you want to use dlmalloc in another project, you should get -** the original from: ftp://gee.cs.oswego.edu/pub/misc/ -** For thread-safe derivatives, take a look at: -** - ptmalloc: http://www.malloc.de/ -** - nedmalloc: http://www.nedprod.com/programs/portable/nedmalloc/ -*/ - -#define lj_alloc_c -#define LUA_CORE - -/* To get the mremap prototype. Must be defined before any system includes. */ -#if defined(__linux__) && !defined(_GNU_SOURCE) -#define _GNU_SOURCE -#endif - -#include "lj_def.h" -#include "lj_arch.h" -#include "lj_alloc.h" - -#ifndef LUAJIT_USE_SYSMALLOC - -#define MAX_SIZE_T (~(size_t)0) -#define MALLOC_ALIGNMENT ((size_t)8U) - -#define DEFAULT_GRANULARITY ((size_t)128U * (size_t)1024U) -#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U) -#define DEFAULT_MMAP_THRESHOLD ((size_t)128U * (size_t)1024U) -#define MAX_RELEASE_CHECK_RATE 255 - -/* ------------------- size_t and alignment properties -------------------- */ - -/* The byte and bit size of a size_t */ -#define SIZE_T_SIZE (sizeof(size_t)) -#define SIZE_T_BITSIZE (sizeof(size_t) << 3) - -/* Some constants coerced to size_t */ -/* Annoying but necessary to avoid errors on some platforms */ -#define SIZE_T_ZERO ((size_t)0) -#define SIZE_T_ONE ((size_t)1) -#define SIZE_T_TWO ((size_t)2) -#define TWO_SIZE_T_SIZES (SIZE_T_SIZE<<1) -#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE<<2) -#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES) - -/* The bit mask value corresponding to MALLOC_ALIGNMENT */ -#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE) - -/* the number of bytes to offset an address to align it */ -#define align_offset(A)\ - ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\ - ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK)) - -/* -------------------------- MMAP support ------------------------------- */ - -#define MFAIL ((void *)(MAX_SIZE_T)) -#define CMFAIL ((char *)(MFAIL)) /* defined for convenience */ - -#define IS_DIRECT_BIT (SIZE_T_ONE) - - -/* Determine system-specific block allocation method. */ -#if LJ_TARGET_WINDOWS - -#define WIN32_LEAN_AND_MEAN -#include - -#define LJ_ALLOC_VIRTUALALLOC 1 - -#if LJ_64 && !LJ_GC64 -#define LJ_ALLOC_NTAVM 1 -#endif - -#else - -#include -/* If this include fails, then rebuild with: -DLUAJIT_USE_SYSMALLOC */ -#include - -#define LJ_ALLOC_MMAP 1 - -#if LJ_64 - -#define LJ_ALLOC_MMAP_PROBE 1 - -#if LJ_GC64 -#define LJ_ALLOC_MBITS 47 /* 128 TB in LJ_GC64 mode. */ -#elif LJ_TARGET_X64 && LJ_HASJIT -/* Due to limitations in the x64 compiler backend. */ -#define LJ_ALLOC_MBITS 31 /* 2 GB on x64 with !LJ_GC64. */ -#else -#define LJ_ALLOC_MBITS 32 /* 4 GB on other archs with !LJ_GC64. */ -#endif - -#endif - -#if LJ_64 && !LJ_GC64 && defined(MAP_32BIT) -#define LJ_ALLOC_MMAP32 1 -#endif - -#if LJ_TARGET_LINUX -#define LJ_ALLOC_MREMAP 1 -#endif - -#endif - - -#if LJ_ALLOC_VIRTUALALLOC - -#if LJ_ALLOC_NTAVM -/* Undocumented, but hey, that's what we all love so much about Windows. */ -typedef long (*PNTAVM)(HANDLE handle, void **addr, ULONG zbits, - size_t *size, ULONG alloctype, ULONG prot); -static PNTAVM ntavm; - -/* Number of top bits of the lower 32 bits of an address that must be zero. -** Apparently 0 gives us full 64 bit addresses and 1 gives us the lower 2GB. -*/ -#define NTAVM_ZEROBITS 1 - -static void init_mmap(void) -{ - ntavm = (PNTAVM)GetProcAddress(GetModuleHandleA("ntdll.dll"), - "NtAllocateVirtualMemory"); -} -#define INIT_MMAP() init_mmap() - -/* Win64 32 bit MMAP via NtAllocateVirtualMemory. */ -static void *CALL_MMAP(size_t size) -{ - DWORD olderr = GetLastError(); - void *ptr = NULL; - long st = ntavm(INVALID_HANDLE_VALUE, &ptr, NTAVM_ZEROBITS, &size, - MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); - SetLastError(olderr); - return st == 0 ? ptr : MFAIL; -} - -/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */ -static void *DIRECT_MMAP(size_t size) -{ - DWORD olderr = GetLastError(); - void *ptr = NULL; - long st = ntavm(INVALID_HANDLE_VALUE, &ptr, NTAVM_ZEROBITS, &size, - MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, PAGE_READWRITE); - SetLastError(olderr); - return st == 0 ? ptr : MFAIL; -} - -#else - -/* Win32 MMAP via VirtualAlloc */ -static void *CALL_MMAP(size_t size) -{ - DWORD olderr = GetLastError(); - void *ptr = LJ_WIN_VALLOC(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); - SetLastError(olderr); - return ptr ? ptr : MFAIL; -} - -/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */ -static void *DIRECT_MMAP(size_t size) -{ - DWORD olderr = GetLastError(); - void *ptr = LJ_WIN_VALLOC(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, - PAGE_READWRITE); - SetLastError(olderr); - return ptr ? ptr : MFAIL; -} - -#endif - -/* This function supports releasing coalesed segments */ -static int CALL_MUNMAP(void *ptr, size_t size) -{ - DWORD olderr = GetLastError(); - MEMORY_BASIC_INFORMATION minfo; - char *cptr = (char *)ptr; - while (size) { - if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0) - return -1; - if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr || - minfo.State != MEM_COMMIT || minfo.RegionSize > size) - return -1; - if (VirtualFree(cptr, 0, MEM_RELEASE) == 0) - return -1; - cptr += minfo.RegionSize; - size -= minfo.RegionSize; - } - SetLastError(olderr); - return 0; -} - -#elif LJ_ALLOC_MMAP - -#define MMAP_PROT (PROT_READ|PROT_WRITE) -#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) -#define MAP_ANONYMOUS MAP_ANON -#endif -#define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS) - -#if LJ_ALLOC_MMAP_PROBE - -#ifdef MAP_TRYFIXED -#define MMAP_FLAGS_PROBE (MMAP_FLAGS|MAP_TRYFIXED) -#else -#define MMAP_FLAGS_PROBE MMAP_FLAGS -#endif - -#define LJ_ALLOC_MMAP_PROBE_MAX 30 -#define LJ_ALLOC_MMAP_PROBE_LINEAR 5 - -#define LJ_ALLOC_MMAP_PROBE_LOWER ((uintptr_t)0x4000) - -/* No point in a giant ifdef mess. Just try to open /dev/urandom. -** It doesn't really matter if this fails, since we get some ASLR bits from -** every unsuitable allocation, too. And we prefer linear allocation, anyway. -*/ -#include -#include - -static uintptr_t mmap_probe_seed(void) -{ - uintptr_t val; - int fd = open("/dev/urandom", O_RDONLY); - if (fd != -1) { - int ok = ((size_t)read(fd, &val, sizeof(val)) == sizeof(val)); - (void)close(fd); - if (ok) return val; - } - return 1; /* Punt. */ -} - -static void *mmap_probe(size_t size) -{ - /* Hint for next allocation. Doesn't need to be thread-safe. */ - static uintptr_t hint_addr = 0; - static uintptr_t hint_prng = 0; - int olderr = errno; - int retry; - for (retry = 0; retry < LJ_ALLOC_MMAP_PROBE_MAX; retry++) { - void *p = mmap((void *)hint_addr, size, MMAP_PROT, MMAP_FLAGS_PROBE, -1, 0); - uintptr_t addr = (uintptr_t)p; - if ((addr >> LJ_ALLOC_MBITS) == 0 && addr >= LJ_ALLOC_MMAP_PROBE_LOWER && - ((addr + size) >> LJ_ALLOC_MBITS) == 0) { - /* We got a suitable address. Bump the hint address. */ - hint_addr = addr + size; - errno = olderr; - return p; - } - if (p != MFAIL) { - munmap(p, size); - } else if (errno == ENOMEM) { - return MFAIL; - } - if (hint_addr) { - /* First, try linear probing. */ - if (retry < LJ_ALLOC_MMAP_PROBE_LINEAR) { - hint_addr += 0x1000000; - if (((hint_addr + size) >> LJ_ALLOC_MBITS) != 0) - hint_addr = 0; - continue; - } else if (retry == LJ_ALLOC_MMAP_PROBE_LINEAR) { - /* Next, try a no-hint probe to get back an ASLR address. */ - hint_addr = 0; - continue; - } - } - /* Finally, try pseudo-random probing. */ - if (LJ_UNLIKELY(hint_prng == 0)) { - hint_prng = mmap_probe_seed(); - } - /* The unsuitable address we got has some ASLR PRNG bits. */ - hint_addr ^= addr & ~((uintptr_t)(LJ_PAGESIZE-1)); - do { /* The PRNG itself is very weak, but see above. */ - hint_prng = hint_prng * 1103515245 + 12345; - hint_addr ^= hint_prng * (uintptr_t)LJ_PAGESIZE; - hint_addr &= (((uintptr_t)1 << LJ_ALLOC_MBITS)-1); - } while (hint_addr < LJ_ALLOC_MMAP_PROBE_LOWER); - } - errno = olderr; - return MFAIL; -} - -#endif - -#if LJ_ALLOC_MMAP32 - -#if defined(__sun__) -#define LJ_ALLOC_MMAP32_START ((uintptr_t)0x1000) -#else -#define LJ_ALLOC_MMAP32_START ((uintptr_t)0) -#endif - -static void *mmap_map32(size_t size) -{ -#if LJ_ALLOC_MMAP_PROBE - static int fallback = 0; - if (fallback) - return mmap_probe(size); -#endif - { - int olderr = errno; - void *ptr = mmap((void *)LJ_ALLOC_MMAP32_START, size, MMAP_PROT, MAP_32BIT|MMAP_FLAGS, -1, 0); - errno = olderr; - /* This only allows 1GB on Linux. So fallback to probing to get 2GB. */ -#if LJ_ALLOC_MMAP_PROBE - if (ptr == MFAIL) { - fallback = 1; - return mmap_probe(size); - } -#endif - return ptr; - } -} - -#endif - -#if LJ_ALLOC_MMAP32 -#define CALL_MMAP(size) mmap_map32(size) -#elif LJ_ALLOC_MMAP_PROBE -#define CALL_MMAP(size) mmap_probe(size) -#else -static void *CALL_MMAP(size_t size) -{ - int olderr = errno; - void *ptr = mmap(NULL, size, MMAP_PROT, MMAP_FLAGS, -1, 0); - errno = olderr; - return ptr; -} -#endif - -#if LJ_64 && !LJ_GC64 && ((defined(__FreeBSD__) && __FreeBSD__ < 10) || defined(__FreeBSD_kernel__)) && !LJ_TARGET_PS4 - -#include - -static void init_mmap(void) -{ - struct rlimit rlim; - rlim.rlim_cur = rlim.rlim_max = 0x10000; - setrlimit(RLIMIT_DATA, &rlim); /* Ignore result. May fail later. */ -} -#define INIT_MMAP() init_mmap() - -#endif - -static int CALL_MUNMAP(void *ptr, size_t size) -{ - int olderr = errno; - int ret = munmap(ptr, size); - errno = olderr; - return ret; -} - -#if LJ_ALLOC_MREMAP -/* Need to define _GNU_SOURCE to get the mremap prototype. */ -static void *CALL_MREMAP_(void *ptr, size_t osz, size_t nsz, int flags) -{ - int olderr = errno; - ptr = mremap(ptr, osz, nsz, flags); - errno = olderr; - return ptr; -} - -#define CALL_MREMAP(addr, osz, nsz, mv) CALL_MREMAP_((addr), (osz), (nsz), (mv)) -#define CALL_MREMAP_NOMOVE 0 -#define CALL_MREMAP_MAYMOVE 1 -#if LJ_64 && !LJ_GC64 -#define CALL_MREMAP_MV CALL_MREMAP_NOMOVE -#else -#define CALL_MREMAP_MV CALL_MREMAP_MAYMOVE -#endif -#endif - -#endif - - -#ifndef INIT_MMAP -#define INIT_MMAP() ((void)0) -#endif - -#ifndef DIRECT_MMAP -#define DIRECT_MMAP(s) CALL_MMAP(s) -#endif - -#ifndef CALL_MREMAP -#define CALL_MREMAP(addr, osz, nsz, mv) ((void)osz, MFAIL) -#endif - -/* ----------------------- Chunk representations ------------------------ */ - -struct malloc_chunk { - size_t prev_foot; /* Size of previous chunk (if free). */ - size_t head; /* Size and inuse bits. */ - struct malloc_chunk *fd; /* double links -- used only if free. */ - struct malloc_chunk *bk; -}; - -typedef struct malloc_chunk mchunk; -typedef struct malloc_chunk *mchunkptr; -typedef struct malloc_chunk *sbinptr; /* The type of bins of chunks */ -typedef size_t bindex_t; /* Described below */ -typedef unsigned int binmap_t; /* Described below */ -typedef unsigned int flag_t; /* The type of various bit flag sets */ - -/* ------------------- Chunks sizes and alignments ----------------------- */ - -#define MCHUNK_SIZE (sizeof(mchunk)) - -#define CHUNK_OVERHEAD (SIZE_T_SIZE) - -/* Direct chunks need a second word of overhead ... */ -#define DIRECT_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) -/* ... and additional padding for fake next-chunk at foot */ -#define DIRECT_FOOT_PAD (FOUR_SIZE_T_SIZES) - -/* The smallest size we can malloc is an aligned minimal chunk */ -#define MIN_CHUNK_SIZE\ - ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) - -/* conversion from malloc headers to user pointers, and back */ -#define chunk2mem(p) ((void *)((char *)(p) + TWO_SIZE_T_SIZES)) -#define mem2chunk(mem) ((mchunkptr)((char *)(mem) - TWO_SIZE_T_SIZES)) -/* chunk associated with aligned address A */ -#define align_as_chunk(A) (mchunkptr)((A) + align_offset(chunk2mem(A))) - -/* Bounds on request (not chunk) sizes. */ -#define MAX_REQUEST ((~MIN_CHUNK_SIZE+1) << 2) -#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE) - -/* pad request bytes into a usable size */ -#define pad_request(req) \ - (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) - -/* pad request, checking for minimum (but not maximum) */ -#define request2size(req) \ - (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req)) - -/* ------------------ Operations on head and foot fields ----------------- */ - -#define PINUSE_BIT (SIZE_T_ONE) -#define CINUSE_BIT (SIZE_T_TWO) -#define INUSE_BITS (PINUSE_BIT|CINUSE_BIT) - -/* Head value for fenceposts */ -#define FENCEPOST_HEAD (INUSE_BITS|SIZE_T_SIZE) - -/* extraction of fields from head words */ -#define cinuse(p) ((p)->head & CINUSE_BIT) -#define pinuse(p) ((p)->head & PINUSE_BIT) -#define chunksize(p) ((p)->head & ~(INUSE_BITS)) - -#define clear_pinuse(p) ((p)->head &= ~PINUSE_BIT) -#define clear_cinuse(p) ((p)->head &= ~CINUSE_BIT) - -/* Treat space at ptr +/- offset as a chunk */ -#define chunk_plus_offset(p, s) ((mchunkptr)(((char *)(p)) + (s))) -#define chunk_minus_offset(p, s) ((mchunkptr)(((char *)(p)) - (s))) - -/* Ptr to next or previous physical malloc_chunk. */ -#define next_chunk(p) ((mchunkptr)(((char *)(p)) + ((p)->head & ~INUSE_BITS))) -#define prev_chunk(p) ((mchunkptr)(((char *)(p)) - ((p)->prev_foot) )) - -/* extract next chunk's pinuse bit */ -#define next_pinuse(p) ((next_chunk(p)->head) & PINUSE_BIT) - -/* Get/set size at footer */ -#define get_foot(p, s) (((mchunkptr)((char *)(p) + (s)))->prev_foot) -#define set_foot(p, s) (((mchunkptr)((char *)(p) + (s)))->prev_foot = (s)) - -/* Set size, pinuse bit, and foot */ -#define set_size_and_pinuse_of_free_chunk(p, s)\ - ((p)->head = (s|PINUSE_BIT), set_foot(p, s)) - -/* Set size, pinuse bit, foot, and clear next pinuse */ -#define set_free_with_pinuse(p, s, n)\ - (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s)) - -#define is_direct(p)\ - (!((p)->head & PINUSE_BIT) && ((p)->prev_foot & IS_DIRECT_BIT)) - -/* Get the internal overhead associated with chunk p */ -#define overhead_for(p)\ - (is_direct(p)? DIRECT_CHUNK_OVERHEAD : CHUNK_OVERHEAD) - -/* ---------------------- Overlaid data structures ----------------------- */ - -struct malloc_tree_chunk { - /* The first four fields must be compatible with malloc_chunk */ - size_t prev_foot; - size_t head; - struct malloc_tree_chunk *fd; - struct malloc_tree_chunk *bk; - - struct malloc_tree_chunk *child[2]; - struct malloc_tree_chunk *parent; - bindex_t index; -}; - -typedef struct malloc_tree_chunk tchunk; -typedef struct malloc_tree_chunk *tchunkptr; -typedef struct malloc_tree_chunk *tbinptr; /* The type of bins of trees */ - -/* A little helper macro for trees */ -#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1]) - -/* ----------------------------- Segments -------------------------------- */ - -struct malloc_segment { - char *base; /* base address */ - size_t size; /* allocated size */ - struct malloc_segment *next; /* ptr to next segment */ -}; - -typedef struct malloc_segment msegment; -typedef struct malloc_segment *msegmentptr; - -/* ---------------------------- malloc_state ----------------------------- */ - -/* Bin types, widths and sizes */ -#define NSMALLBINS (32U) -#define NTREEBINS (32U) -#define SMALLBIN_SHIFT (3U) -#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT) -#define TREEBIN_SHIFT (8U) -#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT) -#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE) -#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD) - -struct malloc_state { - binmap_t smallmap; - binmap_t treemap; - size_t dvsize; - size_t topsize; - mchunkptr dv; - mchunkptr top; - size_t trim_check; - size_t release_checks; - mchunkptr smallbins[(NSMALLBINS+1)*2]; - tbinptr treebins[NTREEBINS]; - msegment seg; -}; - -typedef struct malloc_state *mstate; - -#define is_initialized(M) ((M)->top != 0) - -/* -------------------------- system alloc setup ------------------------- */ - -/* page-align a size */ -#define page_align(S)\ - (((S) + (LJ_PAGESIZE - SIZE_T_ONE)) & ~(LJ_PAGESIZE - SIZE_T_ONE)) - -/* granularity-align a size */ -#define granularity_align(S)\ - (((S) + (DEFAULT_GRANULARITY - SIZE_T_ONE))\ - & ~(DEFAULT_GRANULARITY - SIZE_T_ONE)) - -#if LJ_TARGET_WINDOWS -#define mmap_align(S) granularity_align(S) -#else -#define mmap_align(S) page_align(S) -#endif - -/* True if segment S holds address A */ -#define segment_holds(S, A)\ - ((char *)(A) >= S->base && (char *)(A) < S->base + S->size) - -/* Return segment holding given address */ -static msegmentptr segment_holding(mstate m, char *addr) -{ - msegmentptr sp = &m->seg; - for (;;) { - if (addr >= sp->base && addr < sp->base + sp->size) - return sp; - if ((sp = sp->next) == 0) - return 0; - } -} - -/* Return true if segment contains a segment link */ -static int has_segment_link(mstate m, msegmentptr ss) -{ - msegmentptr sp = &m->seg; - for (;;) { - if ((char *)sp >= ss->base && (char *)sp < ss->base + ss->size) - return 1; - if ((sp = sp->next) == 0) - return 0; - } -} - -/* - TOP_FOOT_SIZE is padding at the end of a segment, including space - that may be needed to place segment records and fenceposts when new - noncontiguous segments are added. -*/ -#define TOP_FOOT_SIZE\ - (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE) - -/* ---------------------------- Indexing Bins ---------------------------- */ - -#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS) -#define small_index(s) ((s) >> SMALLBIN_SHIFT) -#define small_index2size(i) ((i) << SMALLBIN_SHIFT) -#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE)) - -/* addressing by index. See above about smallbin repositioning */ -#define smallbin_at(M, i) ((sbinptr)((char *)&((M)->smallbins[(i)<<1]))) -#define treebin_at(M,i) (&((M)->treebins[i])) - -/* assign tree index for size S to variable I */ -#define compute_tree_index(S, I)\ -{\ - unsigned int X = (unsigned int)(S >> TREEBIN_SHIFT);\ - if (X == 0) {\ - I = 0;\ - } else if (X > 0xFFFF) {\ - I = NTREEBINS-1;\ - } else {\ - unsigned int K = lj_fls(X);\ - I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ - }\ -} - -/* Bit representing maximum resolved size in a treebin at i */ -#define bit_for_tree_index(i) \ - (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2) - -/* Shift placing maximum resolved bit in a treebin at i as sign bit */ -#define leftshift_for_tree_index(i) \ - ((i == NTREEBINS-1)? 0 : \ - ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2))) - -/* The size of the smallest chunk held in bin with index i */ -#define minsize_for_tree_index(i) \ - ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | \ - (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1))) - -/* ------------------------ Operations on bin maps ----------------------- */ - -/* bit corresponding to given index */ -#define idx2bit(i) ((binmap_t)(1) << (i)) - -/* Mark/Clear bits with given index */ -#define mark_smallmap(M,i) ((M)->smallmap |= idx2bit(i)) -#define clear_smallmap(M,i) ((M)->smallmap &= ~idx2bit(i)) -#define smallmap_is_marked(M,i) ((M)->smallmap & idx2bit(i)) - -#define mark_treemap(M,i) ((M)->treemap |= idx2bit(i)) -#define clear_treemap(M,i) ((M)->treemap &= ~idx2bit(i)) -#define treemap_is_marked(M,i) ((M)->treemap & idx2bit(i)) - -/* mask with all bits to left of least bit of x on */ -#define left_bits(x) ((x<<1) | (~(x<<1)+1)) - -/* Set cinuse bit and pinuse bit of next chunk */ -#define set_inuse(M,p,s)\ - ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ - ((mchunkptr)(((char *)(p)) + (s)))->head |= PINUSE_BIT) - -/* Set cinuse and pinuse of this chunk and pinuse of next chunk */ -#define set_inuse_and_pinuse(M,p,s)\ - ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ - ((mchunkptr)(((char *)(p)) + (s)))->head |= PINUSE_BIT) - -/* Set size, cinuse and pinuse bit of this chunk */ -#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ - ((p)->head = (s|PINUSE_BIT|CINUSE_BIT)) - -/* ----------------------- Operations on smallbins ----------------------- */ - -/* Link a free chunk into a smallbin */ -#define insert_small_chunk(M, P, S) {\ - bindex_t I = small_index(S);\ - mchunkptr B = smallbin_at(M, I);\ - mchunkptr F = B;\ - if (!smallmap_is_marked(M, I))\ - mark_smallmap(M, I);\ - else\ - F = B->fd;\ - B->fd = P;\ - F->bk = P;\ - P->fd = F;\ - P->bk = B;\ -} - -/* Unlink a chunk from a smallbin */ -#define unlink_small_chunk(M, P, S) {\ - mchunkptr F = P->fd;\ - mchunkptr B = P->bk;\ - bindex_t I = small_index(S);\ - if (F == B) {\ - clear_smallmap(M, I);\ - } else {\ - F->bk = B;\ - B->fd = F;\ - }\ -} - -/* Unlink the first chunk from a smallbin */ -#define unlink_first_small_chunk(M, B, P, I) {\ - mchunkptr F = P->fd;\ - if (B == F) {\ - clear_smallmap(M, I);\ - } else {\ - B->fd = F;\ - F->bk = B;\ - }\ -} - -/* Replace dv node, binning the old one */ -/* Used only when dvsize known to be small */ -#define replace_dv(M, P, S) {\ - size_t DVS = M->dvsize;\ - if (DVS != 0) {\ - mchunkptr DV = M->dv;\ - insert_small_chunk(M, DV, DVS);\ - }\ - M->dvsize = S;\ - M->dv = P;\ -} - -/* ------------------------- Operations on trees ------------------------- */ - -/* Insert chunk into tree */ -#define insert_large_chunk(M, X, S) {\ - tbinptr *H;\ - bindex_t I;\ - compute_tree_index(S, I);\ - H = treebin_at(M, I);\ - X->index = I;\ - X->child[0] = X->child[1] = 0;\ - if (!treemap_is_marked(M, I)) {\ - mark_treemap(M, I);\ - *H = X;\ - X->parent = (tchunkptr)H;\ - X->fd = X->bk = X;\ - } else {\ - tchunkptr T = *H;\ - size_t K = S << leftshift_for_tree_index(I);\ - for (;;) {\ - if (chunksize(T) != S) {\ - tchunkptr *C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\ - K <<= 1;\ - if (*C != 0) {\ - T = *C;\ - } else {\ - *C = X;\ - X->parent = T;\ - X->fd = X->bk = X;\ - break;\ - }\ - } else {\ - tchunkptr F = T->fd;\ - T->fd = F->bk = X;\ - X->fd = F;\ - X->bk = T;\ - X->parent = 0;\ - break;\ - }\ - }\ - }\ -} - -#define unlink_large_chunk(M, X) {\ - tchunkptr XP = X->parent;\ - tchunkptr R;\ - if (X->bk != X) {\ - tchunkptr F = X->fd;\ - R = X->bk;\ - F->bk = R;\ - R->fd = F;\ - } else {\ - tchunkptr *RP;\ - if (((R = *(RP = &(X->child[1]))) != 0) ||\ - ((R = *(RP = &(X->child[0]))) != 0)) {\ - tchunkptr *CP;\ - while ((*(CP = &(R->child[1])) != 0) ||\ - (*(CP = &(R->child[0])) != 0)) {\ - R = *(RP = CP);\ - }\ - *RP = 0;\ - }\ - }\ - if (XP != 0) {\ - tbinptr *H = treebin_at(M, X->index);\ - if (X == *H) {\ - if ((*H = R) == 0) \ - clear_treemap(M, X->index);\ - } else {\ - if (XP->child[0] == X) \ - XP->child[0] = R;\ - else \ - XP->child[1] = R;\ - }\ - if (R != 0) {\ - tchunkptr C0, C1;\ - R->parent = XP;\ - if ((C0 = X->child[0]) != 0) {\ - R->child[0] = C0;\ - C0->parent = R;\ - }\ - if ((C1 = X->child[1]) != 0) {\ - R->child[1] = C1;\ - C1->parent = R;\ - }\ - }\ - }\ -} - -/* Relays to large vs small bin operations */ - -#define insert_chunk(M, P, S)\ - if (is_small(S)) { insert_small_chunk(M, P, S)\ - } else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); } - -#define unlink_chunk(M, P, S)\ - if (is_small(S)) { unlink_small_chunk(M, P, S)\ - } else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); } - -/* ----------------------- Direct-mmapping chunks ----------------------- */ - -static void *direct_alloc(size_t nb) -{ - size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); - if (LJ_LIKELY(mmsize > nb)) { /* Check for wrap around 0 */ - char *mm = (char *)(DIRECT_MMAP(mmsize)); - if (mm != CMFAIL) { - size_t offset = align_offset(chunk2mem(mm)); - size_t psize = mmsize - offset - DIRECT_FOOT_PAD; - mchunkptr p = (mchunkptr)(mm + offset); - p->prev_foot = offset | IS_DIRECT_BIT; - p->head = psize|CINUSE_BIT; - chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD; - chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0; - return chunk2mem(p); - } - } - return NULL; -} - -static mchunkptr direct_resize(mchunkptr oldp, size_t nb) -{ - size_t oldsize = chunksize(oldp); - if (is_small(nb)) /* Can't shrink direct regions below small size */ - return NULL; - /* Keep old chunk if big enough but not too big */ - if (oldsize >= nb + SIZE_T_SIZE && - (oldsize - nb) <= (DEFAULT_GRANULARITY >> 1)) { - return oldp; - } else { - size_t offset = oldp->prev_foot & ~IS_DIRECT_BIT; - size_t oldmmsize = oldsize + offset + DIRECT_FOOT_PAD; - size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); - char *cp = (char *)CALL_MREMAP((char *)oldp - offset, - oldmmsize, newmmsize, CALL_MREMAP_MV); - if (cp != CMFAIL) { - mchunkptr newp = (mchunkptr)(cp + offset); - size_t psize = newmmsize - offset - DIRECT_FOOT_PAD; - newp->head = psize|CINUSE_BIT; - chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD; - chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0; - return newp; - } - } - return NULL; -} - -/* -------------------------- mspace management -------------------------- */ - -/* Initialize top chunk and its size */ -static void init_top(mstate m, mchunkptr p, size_t psize) -{ - /* Ensure alignment */ - size_t offset = align_offset(chunk2mem(p)); - p = (mchunkptr)((char *)p + offset); - psize -= offset; - - m->top = p; - m->topsize = psize; - p->head = psize | PINUSE_BIT; - /* set size of fake trailing chunk holding overhead space only once */ - chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE; - m->trim_check = DEFAULT_TRIM_THRESHOLD; /* reset on each update */ -} - -/* Initialize bins for a new mstate that is otherwise zeroed out */ -static void init_bins(mstate m) -{ - /* Establish circular links for smallbins */ - bindex_t i; - for (i = 0; i < NSMALLBINS; i++) { - sbinptr bin = smallbin_at(m,i); - bin->fd = bin->bk = bin; - } -} - -/* Allocate chunk and prepend remainder with chunk in successor base. */ -static void *prepend_alloc(mstate m, char *newbase, char *oldbase, size_t nb) -{ - mchunkptr p = align_as_chunk(newbase); - mchunkptr oldfirst = align_as_chunk(oldbase); - size_t psize = (size_t)((char *)oldfirst - (char *)p); - mchunkptr q = chunk_plus_offset(p, nb); - size_t qsize = psize - nb; - set_size_and_pinuse_of_inuse_chunk(m, p, nb); - - /* consolidate remainder with first chunk of old base */ - if (oldfirst == m->top) { - size_t tsize = m->topsize += qsize; - m->top = q; - q->head = tsize | PINUSE_BIT; - } else if (oldfirst == m->dv) { - size_t dsize = m->dvsize += qsize; - m->dv = q; - set_size_and_pinuse_of_free_chunk(q, dsize); - } else { - if (!cinuse(oldfirst)) { - size_t nsize = chunksize(oldfirst); - unlink_chunk(m, oldfirst, nsize); - oldfirst = chunk_plus_offset(oldfirst, nsize); - qsize += nsize; - } - set_free_with_pinuse(q, qsize, oldfirst); - insert_chunk(m, q, qsize); - } - - return chunk2mem(p); -} - -/* Add a segment to hold a new noncontiguous region */ -static void add_segment(mstate m, char *tbase, size_t tsize) -{ - /* Determine locations and sizes of segment, fenceposts, old top */ - char *old_top = (char *)m->top; - msegmentptr oldsp = segment_holding(m, old_top); - char *old_end = oldsp->base + oldsp->size; - size_t ssize = pad_request(sizeof(struct malloc_segment)); - char *rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK); - size_t offset = align_offset(chunk2mem(rawsp)); - char *asp = rawsp + offset; - char *csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp; - mchunkptr sp = (mchunkptr)csp; - msegmentptr ss = (msegmentptr)(chunk2mem(sp)); - mchunkptr tnext = chunk_plus_offset(sp, ssize); - mchunkptr p = tnext; - - /* reset top to new space */ - init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); - - /* Set up segment record */ - set_size_and_pinuse_of_inuse_chunk(m, sp, ssize); - *ss = m->seg; /* Push current record */ - m->seg.base = tbase; - m->seg.size = tsize; - m->seg.next = ss; - - /* Insert trailing fenceposts */ - for (;;) { - mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE); - p->head = FENCEPOST_HEAD; - if ((char *)(&(nextp->head)) < old_end) - p = nextp; - else - break; - } - - /* Insert the rest of old top into a bin as an ordinary free chunk */ - if (csp != old_top) { - mchunkptr q = (mchunkptr)old_top; - size_t psize = (size_t)(csp - old_top); - mchunkptr tn = chunk_plus_offset(q, psize); - set_free_with_pinuse(q, psize, tn); - insert_chunk(m, q, psize); - } -} - -/* -------------------------- System allocation -------------------------- */ - -static void *alloc_sys(mstate m, size_t nb) -{ - char *tbase = CMFAIL; - size_t tsize = 0; - - /* Directly map large chunks */ - if (LJ_UNLIKELY(nb >= DEFAULT_MMAP_THRESHOLD)) { - void *mem = direct_alloc(nb); - if (mem != 0) - return mem; - } - - { - size_t req = nb + TOP_FOOT_SIZE + SIZE_T_ONE; - size_t rsize = granularity_align(req); - if (LJ_LIKELY(rsize > nb)) { /* Fail if wraps around zero */ - char *mp = (char *)(CALL_MMAP(rsize)); - if (mp != CMFAIL) { - tbase = mp; - tsize = rsize; - } - } - } - - if (tbase != CMFAIL) { - msegmentptr sp = &m->seg; - /* Try to merge with an existing segment */ - while (sp != 0 && tbase != sp->base + sp->size) - sp = sp->next; - if (sp != 0 && segment_holds(sp, m->top)) { /* append */ - sp->size += tsize; - init_top(m, m->top, m->topsize + tsize); - } else { - sp = &m->seg; - while (sp != 0 && sp->base != tbase + tsize) - sp = sp->next; - if (sp != 0) { - char *oldbase = sp->base; - sp->base = tbase; - sp->size += tsize; - return prepend_alloc(m, tbase, oldbase, nb); - } else { - add_segment(m, tbase, tsize); - } - } - - if (nb < m->topsize) { /* Allocate from new or extended top space */ - size_t rsize = m->topsize -= nb; - mchunkptr p = m->top; - mchunkptr r = m->top = chunk_plus_offset(p, nb); - r->head = rsize | PINUSE_BIT; - set_size_and_pinuse_of_inuse_chunk(m, p, nb); - return chunk2mem(p); - } - } - - return NULL; -} - -/* ----------------------- system deallocation -------------------------- */ - -/* Unmap and unlink any mmapped segments that don't contain used chunks */ -static size_t release_unused_segments(mstate m) -{ - size_t released = 0; - size_t nsegs = 0; - msegmentptr pred = &m->seg; - msegmentptr sp = pred->next; - while (sp != 0) { - char *base = sp->base; - size_t size = sp->size; - msegmentptr next = sp->next; - nsegs++; - { - mchunkptr p = align_as_chunk(base); - size_t psize = chunksize(p); - /* Can unmap if first chunk holds entire segment and not pinned */ - if (!cinuse(p) && (char *)p + psize >= base + size - TOP_FOOT_SIZE) { - tchunkptr tp = (tchunkptr)p; - if (p == m->dv) { - m->dv = 0; - m->dvsize = 0; - } else { - unlink_large_chunk(m, tp); - } - if (CALL_MUNMAP(base, size) == 0) { - released += size; - /* unlink obsoleted record */ - sp = pred; - sp->next = next; - } else { /* back out if cannot unmap */ - insert_large_chunk(m, tp, psize); - } - } - } - pred = sp; - sp = next; - } - /* Reset check counter */ - m->release_checks = nsegs > MAX_RELEASE_CHECK_RATE ? - nsegs : MAX_RELEASE_CHECK_RATE; - return released; -} - -static int alloc_trim(mstate m, size_t pad) -{ - size_t released = 0; - if (pad < MAX_REQUEST && is_initialized(m)) { - pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */ - - if (m->topsize > pad) { - /* Shrink top space in granularity-size units, keeping at least one */ - size_t unit = DEFAULT_GRANULARITY; - size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit - - SIZE_T_ONE) * unit; - msegmentptr sp = segment_holding(m, (char *)m->top); - - if (sp->size >= extra && - !has_segment_link(m, sp)) { /* can't shrink if pinned */ - size_t newsize = sp->size - extra; - /* Prefer mremap, fall back to munmap */ - if ((CALL_MREMAP(sp->base, sp->size, newsize, CALL_MREMAP_NOMOVE) != MFAIL) || - (CALL_MUNMAP(sp->base + newsize, extra) == 0)) { - released = extra; - } - } - - if (released != 0) { - sp->size -= released; - init_top(m, m->top, m->topsize - released); - } - } - - /* Unmap any unused mmapped segments */ - released += release_unused_segments(m); - - /* On failure, disable autotrim to avoid repeated failed future calls */ - if (released == 0 && m->topsize > m->trim_check) - m->trim_check = MAX_SIZE_T; - } - - return (released != 0)? 1 : 0; -} - -/* ---------------------------- malloc support --------------------------- */ - -/* allocate a large request from the best fitting chunk in a treebin */ -static void *tmalloc_large(mstate m, size_t nb) -{ - tchunkptr v = 0; - size_t rsize = ~nb+1; /* Unsigned negation */ - tchunkptr t; - bindex_t idx; - compute_tree_index(nb, idx); - - if ((t = *treebin_at(m, idx)) != 0) { - /* Traverse tree for this bin looking for node with size == nb */ - size_t sizebits = nb << leftshift_for_tree_index(idx); - tchunkptr rst = 0; /* The deepest untaken right subtree */ - for (;;) { - tchunkptr rt; - size_t trem = chunksize(t) - nb; - if (trem < rsize) { - v = t; - if ((rsize = trem) == 0) - break; - } - rt = t->child[1]; - t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; - if (rt != 0 && rt != t) - rst = rt; - if (t == 0) { - t = rst; /* set t to least subtree holding sizes > nb */ - break; - } - sizebits <<= 1; - } - } - - if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */ - binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap; - if (leftbits != 0) - t = *treebin_at(m, lj_ffs(leftbits)); - } - - while (t != 0) { /* find smallest of tree or subtree */ - size_t trem = chunksize(t) - nb; - if (trem < rsize) { - rsize = trem; - v = t; - } - t = leftmost_child(t); - } - - /* If dv is a better fit, return NULL so malloc will use it */ - if (v != 0 && rsize < (size_t)(m->dvsize - nb)) { - mchunkptr r = chunk_plus_offset(v, nb); - unlink_large_chunk(m, v); - if (rsize < MIN_CHUNK_SIZE) { - set_inuse_and_pinuse(m, v, (rsize + nb)); - } else { - set_size_and_pinuse_of_inuse_chunk(m, v, nb); - set_size_and_pinuse_of_free_chunk(r, rsize); - insert_chunk(m, r, rsize); - } - return chunk2mem(v); - } - return NULL; -} - -/* allocate a small request from the best fitting chunk in a treebin */ -static void *tmalloc_small(mstate m, size_t nb) -{ - tchunkptr t, v; - mchunkptr r; - size_t rsize; - bindex_t i = lj_ffs(m->treemap); - - v = t = *treebin_at(m, i); - rsize = chunksize(t) - nb; - - while ((t = leftmost_child(t)) != 0) { - size_t trem = chunksize(t) - nb; - if (trem < rsize) { - rsize = trem; - v = t; - } - } - - r = chunk_plus_offset(v, nb); - unlink_large_chunk(m, v); - if (rsize < MIN_CHUNK_SIZE) { - set_inuse_and_pinuse(m, v, (rsize + nb)); - } else { - set_size_and_pinuse_of_inuse_chunk(m, v, nb); - set_size_and_pinuse_of_free_chunk(r, rsize); - replace_dv(m, r, rsize); - } - return chunk2mem(v); -} - -/* ----------------------------------------------------------------------- */ - -void *lj_alloc_create(void) -{ - size_t tsize = DEFAULT_GRANULARITY; - char *tbase; - INIT_MMAP(); - tbase = (char *)(CALL_MMAP(tsize)); - if (tbase != CMFAIL) { - size_t msize = pad_request(sizeof(struct malloc_state)); - mchunkptr mn; - mchunkptr msp = align_as_chunk(tbase); - mstate m = (mstate)(chunk2mem(msp)); - memset(m, 0, msize); - msp->head = (msize|PINUSE_BIT|CINUSE_BIT); - m->seg.base = tbase; - m->seg.size = tsize; - m->release_checks = MAX_RELEASE_CHECK_RATE; - init_bins(m); - mn = next_chunk(mem2chunk(m)); - init_top(m, mn, (size_t)((tbase + tsize) - (char *)mn) - TOP_FOOT_SIZE); - return m; - } - return NULL; -} - -void lj_alloc_destroy(void *msp) -{ - mstate ms = (mstate)msp; - msegmentptr sp = &ms->seg; - while (sp != 0) { - char *base = sp->base; - size_t size = sp->size; - sp = sp->next; - CALL_MUNMAP(base, size); - } -} - -static LJ_NOINLINE void *lj_alloc_malloc(void *msp, size_t nsize) -{ - mstate ms = (mstate)msp; - void *mem; - size_t nb; - if (nsize <= MAX_SMALL_REQUEST) { - bindex_t idx; - binmap_t smallbits; - nb = (nsize < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(nsize); - idx = small_index(nb); - smallbits = ms->smallmap >> idx; - - if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ - mchunkptr b, p; - idx += ~smallbits & 1; /* Uses next bin if idx empty */ - b = smallbin_at(ms, idx); - p = b->fd; - unlink_first_small_chunk(ms, b, p, idx); - set_inuse_and_pinuse(ms, p, small_index2size(idx)); - mem = chunk2mem(p); - return mem; - } else if (nb > ms->dvsize) { - if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ - mchunkptr b, p, r; - size_t rsize; - binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); - bindex_t i = lj_ffs(leftbits); - b = smallbin_at(ms, i); - p = b->fd; - unlink_first_small_chunk(ms, b, p, i); - rsize = small_index2size(i) - nb; - /* Fit here cannot be remainderless if 4byte sizes */ - if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) { - set_inuse_and_pinuse(ms, p, small_index2size(i)); - } else { - set_size_and_pinuse_of_inuse_chunk(ms, p, nb); - r = chunk_plus_offset(p, nb); - set_size_and_pinuse_of_free_chunk(r, rsize); - replace_dv(ms, r, rsize); - } - mem = chunk2mem(p); - return mem; - } else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) { - return mem; - } - } - } else if (nsize >= MAX_REQUEST) { - nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ - } else { - nb = pad_request(nsize); - if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) { - return mem; - } - } - - if (nb <= ms->dvsize) { - size_t rsize = ms->dvsize - nb; - mchunkptr p = ms->dv; - if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ - mchunkptr r = ms->dv = chunk_plus_offset(p, nb); - ms->dvsize = rsize; - set_size_and_pinuse_of_free_chunk(r, rsize); - set_size_and_pinuse_of_inuse_chunk(ms, p, nb); - } else { /* exhaust dv */ - size_t dvs = ms->dvsize; - ms->dvsize = 0; - ms->dv = 0; - set_inuse_and_pinuse(ms, p, dvs); - } - mem = chunk2mem(p); - return mem; - } else if (nb < ms->topsize) { /* Split top */ - size_t rsize = ms->topsize -= nb; - mchunkptr p = ms->top; - mchunkptr r = ms->top = chunk_plus_offset(p, nb); - r->head = rsize | PINUSE_BIT; - set_size_and_pinuse_of_inuse_chunk(ms, p, nb); - mem = chunk2mem(p); - return mem; - } - return alloc_sys(ms, nb); -} - -static LJ_NOINLINE void *lj_alloc_free(void *msp, void *ptr) -{ - if (ptr != 0) { - mchunkptr p = mem2chunk(ptr); - mstate fm = (mstate)msp; - size_t psize = chunksize(p); - mchunkptr next = chunk_plus_offset(p, psize); - if (!pinuse(p)) { - size_t prevsize = p->prev_foot; - if ((prevsize & IS_DIRECT_BIT) != 0) { - prevsize &= ~IS_DIRECT_BIT; - psize += prevsize + DIRECT_FOOT_PAD; - CALL_MUNMAP((char *)p - prevsize, psize); - return NULL; - } else { - mchunkptr prev = chunk_minus_offset(p, prevsize); - psize += prevsize; - p = prev; - /* consolidate backward */ - if (p != fm->dv) { - unlink_chunk(fm, p, prevsize); - } else if ((next->head & INUSE_BITS) == INUSE_BITS) { - fm->dvsize = psize; - set_free_with_pinuse(p, psize, next); - return NULL; - } - } - } - if (!cinuse(next)) { /* consolidate forward */ - if (next == fm->top) { - size_t tsize = fm->topsize += psize; - fm->top = p; - p->head = tsize | PINUSE_BIT; - if (p == fm->dv) { - fm->dv = 0; - fm->dvsize = 0; - } - if (tsize > fm->trim_check) - alloc_trim(fm, 0); - return NULL; - } else if (next == fm->dv) { - size_t dsize = fm->dvsize += psize; - fm->dv = p; - set_size_and_pinuse_of_free_chunk(p, dsize); - return NULL; - } else { - size_t nsize = chunksize(next); - psize += nsize; - unlink_chunk(fm, next, nsize); - set_size_and_pinuse_of_free_chunk(p, psize); - if (p == fm->dv) { - fm->dvsize = psize; - return NULL; - } - } - } else { - set_free_with_pinuse(p, psize, next); - } - - if (is_small(psize)) { - insert_small_chunk(fm, p, psize); - } else { - tchunkptr tp = (tchunkptr)p; - insert_large_chunk(fm, tp, psize); - if (--fm->release_checks == 0) - release_unused_segments(fm); - } - } - return NULL; -} - -static LJ_NOINLINE void *lj_alloc_realloc(void *msp, void *ptr, size_t nsize) -{ - if (nsize >= MAX_REQUEST) { - return NULL; - } else { - mstate m = (mstate)msp; - mchunkptr oldp = mem2chunk(ptr); - size_t oldsize = chunksize(oldp); - mchunkptr next = chunk_plus_offset(oldp, oldsize); - mchunkptr newp = 0; - size_t nb = request2size(nsize); - - /* Try to either shrink or extend into top. Else malloc-copy-free */ - if (is_direct(oldp)) { - newp = direct_resize(oldp, nb); /* this may return NULL. */ - } else if (oldsize >= nb) { /* already big enough */ - size_t rsize = oldsize - nb; - newp = oldp; - if (rsize >= MIN_CHUNK_SIZE) { - mchunkptr rem = chunk_plus_offset(newp, nb); - set_inuse(m, newp, nb); - set_inuse(m, rem, rsize); - lj_alloc_free(m, chunk2mem(rem)); - } - } else if (next == m->top && oldsize + m->topsize > nb) { - /* Expand into top */ - size_t newsize = oldsize + m->topsize; - size_t newtopsize = newsize - nb; - mchunkptr newtop = chunk_plus_offset(oldp, nb); - set_inuse(m, oldp, nb); - newtop->head = newtopsize |PINUSE_BIT; - m->top = newtop; - m->topsize = newtopsize; - newp = oldp; - } - - if (newp != 0) { - return chunk2mem(newp); - } else { - void *newmem = lj_alloc_malloc(m, nsize); - if (newmem != 0) { - size_t oc = oldsize - overhead_for(oldp); - memcpy(newmem, ptr, oc < nsize ? oc : nsize); - lj_alloc_free(m, ptr); - } - return newmem; - } - } -} - -void *lj_alloc_f(void *msp, void *ptr, size_t osize, size_t nsize) -{ - (void)osize; - if (nsize == 0) { - return lj_alloc_free(msp, ptr); - } else if (ptr == NULL) { - return lj_alloc_malloc(msp, nsize); - } else { - return lj_alloc_realloc(msp, ptr, nsize); - } -} - -#endif diff --git a/lib/LuaJIT/src/lj_alloc.h b/lib/LuaJIT/src/lj_alloc.h deleted file mode 100644 index f87a7cf..0000000 --- a/lib/LuaJIT/src/lj_alloc.h +++ /dev/null @@ -1,17 +0,0 @@ -/* -** Bundled memory allocator. -** Donated to the public domain. -*/ - -#ifndef _LJ_ALLOC_H -#define _LJ_ALLOC_H - -#include "lj_def.h" - -#ifndef LUAJIT_USE_SYSMALLOC -LJ_FUNC void *lj_alloc_create(void); -LJ_FUNC void lj_alloc_destroy(void *msp); -LJ_FUNC void *lj_alloc_f(void *msp, void *ptr, size_t osize, size_t nsize); -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_api.c b/lib/LuaJIT/src/lj_api.c deleted file mode 100644 index d17a575..0000000 --- a/lib/LuaJIT/src/lj_api.c +++ /dev/null @@ -1,1292 +0,0 @@ -/* -** Public Lua/C API. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Major portions taken verbatim or adapted from the Lua interpreter. -** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h -*/ - -#define lj_api_c -#define LUA_CORE - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_debug.h" -#include "lj_str.h" -#include "lj_tab.h" -#include "lj_func.h" -#include "lj_udata.h" -#include "lj_meta.h" -#include "lj_state.h" -#include "lj_bc.h" -#include "lj_frame.h" -#include "lj_trace.h" -#include "lj_vm.h" -#include "lj_strscan.h" -#include "lj_strfmt.h" - -/* -- Common helper functions --------------------------------------------- */ - -#define api_checknelems(L, n) api_check(L, (n) <= (L->top - L->base)) -#define api_checkvalidindex(L, i) api_check(L, (i) != niltv(L)) - -static TValue *index2adr(lua_State *L, int idx) -{ - if (idx > 0) { - TValue *o = L->base + (idx - 1); - return o < L->top ? o : niltv(L); - } else if (idx > LUA_REGISTRYINDEX) { - api_check(L, idx != 0 && -idx <= L->top - L->base); - return L->top + idx; - } else if (idx == LUA_GLOBALSINDEX) { - TValue *o = &G(L)->tmptv; - settabV(L, o, tabref(L->env)); - return o; - } else if (idx == LUA_REGISTRYINDEX) { - return registry(L); - } else { - GCfunc *fn = curr_func(L); - api_check(L, fn->c.gct == ~LJ_TFUNC && !isluafunc(fn)); - if (idx == LUA_ENVIRONINDEX) { - TValue *o = &G(L)->tmptv; - settabV(L, o, tabref(fn->c.env)); - return o; - } else { - idx = LUA_GLOBALSINDEX - idx; - return idx <= fn->c.nupvalues ? &fn->c.upvalue[idx-1] : niltv(L); - } - } -} - -static TValue *stkindex2adr(lua_State *L, int idx) -{ - if (idx > 0) { - TValue *o = L->base + (idx - 1); - return o < L->top ? o : niltv(L); - } else { - api_check(L, idx != 0 && -idx <= L->top - L->base); - return L->top + idx; - } -} - -static GCtab *getcurrenv(lua_State *L) -{ - GCfunc *fn = curr_func(L); - return fn->c.gct == ~LJ_TFUNC ? tabref(fn->c.env) : tabref(L->env); -} - -/* -- Miscellaneous API functions ----------------------------------------- */ - -LUA_API int lua_status(lua_State *L) -{ - return L->status; -} - -LUA_API int lua_checkstack(lua_State *L, int size) -{ - if (size > LUAI_MAXCSTACK || (L->top - L->base + size) > LUAI_MAXCSTACK) { - return 0; /* Stack overflow. */ - } else if (size > 0) { - lj_state_checkstack(L, (MSize)size); - } - return 1; -} - -LUALIB_API void luaL_checkstack(lua_State *L, int size, const char *msg) -{ - if (!lua_checkstack(L, size)) - lj_err_callerv(L, LJ_ERR_STKOVM, msg); -} - -LUA_API void lua_xmove(lua_State *from, lua_State *to, int n) -{ - TValue *f, *t; - if (from == to) return; - api_checknelems(from, n); - api_check(from, G(from) == G(to)); - lj_state_checkstack(to, (MSize)n); - f = from->top; - t = to->top = to->top + n; - while (--n >= 0) copyTV(to, --t, --f); - from->top = f; -} - -LUA_API const lua_Number *lua_version(lua_State *L) -{ - static const lua_Number version = LUA_VERSION_NUM; - UNUSED(L); - return &version; -} - -/* -- Stack manipulation -------------------------------------------------- */ - -LUA_API int lua_gettop(lua_State *L) -{ - return (int)(L->top - L->base); -} - -LUA_API void lua_settop(lua_State *L, int idx) -{ - if (idx >= 0) { - api_check(L, idx <= tvref(L->maxstack) - L->base); - if (L->base + idx > L->top) { - if (L->base + idx >= tvref(L->maxstack)) - lj_state_growstack(L, (MSize)idx - (MSize)(L->top - L->base)); - do { setnilV(L->top++); } while (L->top < L->base + idx); - } else { - L->top = L->base + idx; - } - } else { - api_check(L, -(idx+1) <= (L->top - L->base)); - L->top += idx+1; /* Shrinks top (idx < 0). */ - } -} - -LUA_API void lua_remove(lua_State *L, int idx) -{ - TValue *p = stkindex2adr(L, idx); - api_checkvalidindex(L, p); - while (++p < L->top) copyTV(L, p-1, p); - L->top--; -} - -LUA_API void lua_insert(lua_State *L, int idx) -{ - TValue *q, *p = stkindex2adr(L, idx); - api_checkvalidindex(L, p); - for (q = L->top; q > p; q--) copyTV(L, q, q-1); - copyTV(L, p, L->top); -} - -static void copy_slot(lua_State *L, TValue *f, int idx) -{ - if (idx == LUA_GLOBALSINDEX) { - api_check(L, tvistab(f)); - /* NOBARRIER: A thread (i.e. L) is never black. */ - setgcref(L->env, obj2gco(tabV(f))); - } else if (idx == LUA_ENVIRONINDEX) { - GCfunc *fn = curr_func(L); - if (fn->c.gct != ~LJ_TFUNC) - lj_err_msg(L, LJ_ERR_NOENV); - api_check(L, tvistab(f)); - setgcref(fn->c.env, obj2gco(tabV(f))); - lj_gc_barrier(L, fn, f); - } else { - TValue *o = index2adr(L, idx); - api_checkvalidindex(L, o); - copyTV(L, o, f); - if (idx < LUA_GLOBALSINDEX) /* Need a barrier for upvalues. */ - lj_gc_barrier(L, curr_func(L), f); - } -} - -LUA_API void lua_replace(lua_State *L, int idx) -{ - api_checknelems(L, 1); - copy_slot(L, L->top - 1, idx); - L->top--; -} - -LUA_API void lua_copy(lua_State *L, int fromidx, int toidx) -{ - copy_slot(L, index2adr(L, fromidx), toidx); -} - -LUA_API void lua_pushvalue(lua_State *L, int idx) -{ - copyTV(L, L->top, index2adr(L, idx)); - incr_top(L); -} - -/* -- Stack getters ------------------------------------------------------- */ - -LUA_API int lua_type(lua_State *L, int idx) -{ - cTValue *o = index2adr(L, idx); - if (tvisnumber(o)) { - return LUA_TNUMBER; -#if LJ_64 && !LJ_GC64 - } else if (tvislightud(o)) { - return LUA_TLIGHTUSERDATA; -#endif - } else if (o == niltv(L)) { - return LUA_TNONE; - } else { /* Magic internal/external tag conversion. ORDER LJ_T */ - uint32_t t = ~itype(o); -#if LJ_64 - int tt = (int)((U64x(75a06,98042110) >> 4*t) & 15u); -#else - int tt = (int)(((t < 8 ? 0x98042110u : 0x75a06u) >> 4*(t&7)) & 15u); -#endif - lua_assert(tt != LUA_TNIL || tvisnil(o)); - return tt; - } -} - -LUALIB_API void luaL_checktype(lua_State *L, int idx, int tt) -{ - if (lua_type(L, idx) != tt) - lj_err_argt(L, idx, tt); -} - -LUALIB_API void luaL_checkany(lua_State *L, int idx) -{ - if (index2adr(L, idx) == niltv(L)) - lj_err_arg(L, idx, LJ_ERR_NOVAL); -} - -LUA_API const char *lua_typename(lua_State *L, int t) -{ - UNUSED(L); - return lj_obj_typename[t+1]; -} - -LUA_API int lua_iscfunction(lua_State *L, int idx) -{ - cTValue *o = index2adr(L, idx); - return tvisfunc(o) && !isluafunc(funcV(o)); -} - -LUA_API int lua_isnumber(lua_State *L, int idx) -{ - cTValue *o = index2adr(L, idx); - TValue tmp; - return (tvisnumber(o) || (tvisstr(o) && lj_strscan_number(strV(o), &tmp))); -} - -LUA_API int lua_isstring(lua_State *L, int idx) -{ - cTValue *o = index2adr(L, idx); - return (tvisstr(o) || tvisnumber(o)); -} - -LUA_API int lua_isuserdata(lua_State *L, int idx) -{ - cTValue *o = index2adr(L, idx); - return (tvisudata(o) || tvislightud(o)); -} - -LUA_API int lua_rawequal(lua_State *L, int idx1, int idx2) -{ - cTValue *o1 = index2adr(L, idx1); - cTValue *o2 = index2adr(L, idx2); - return (o1 == niltv(L) || o2 == niltv(L)) ? 0 : lj_obj_equal(o1, o2); -} - -LUA_API int lua_equal(lua_State *L, int idx1, int idx2) -{ - cTValue *o1 = index2adr(L, idx1); - cTValue *o2 = index2adr(L, idx2); - if (tvisint(o1) && tvisint(o2)) { - return intV(o1) == intV(o2); - } else if (tvisnumber(o1) && tvisnumber(o2)) { - return numberVnum(o1) == numberVnum(o2); - } else if (itype(o1) != itype(o2)) { - return 0; - } else if (tvispri(o1)) { - return o1 != niltv(L) && o2 != niltv(L); -#if LJ_64 && !LJ_GC64 - } else if (tvislightud(o1)) { - return o1->u64 == o2->u64; -#endif - } else if (gcrefeq(o1->gcr, o2->gcr)) { - return 1; - } else if (!tvistabud(o1)) { - return 0; - } else { - TValue *base = lj_meta_equal(L, gcV(o1), gcV(o2), 0); - if ((uintptr_t)base <= 1) { - return (int)(uintptr_t)base; - } else { - L->top = base+2; - lj_vm_call(L, base, 1+1); - L->top -= 2+LJ_FR2; - return tvistruecond(L->top+1+LJ_FR2); - } - } -} - -LUA_API int lua_lessthan(lua_State *L, int idx1, int idx2) -{ - cTValue *o1 = index2adr(L, idx1); - cTValue *o2 = index2adr(L, idx2); - if (o1 == niltv(L) || o2 == niltv(L)) { - return 0; - } else if (tvisint(o1) && tvisint(o2)) { - return intV(o1) < intV(o2); - } else if (tvisnumber(o1) && tvisnumber(o2)) { - return numberVnum(o1) < numberVnum(o2); - } else { - TValue *base = lj_meta_comp(L, o1, o2, 0); - if ((uintptr_t)base <= 1) { - return (int)(uintptr_t)base; - } else { - L->top = base+2; - lj_vm_call(L, base, 1+1); - L->top -= 2+LJ_FR2; - return tvistruecond(L->top+1+LJ_FR2); - } - } -} - -LUA_API lua_Number lua_tonumber(lua_State *L, int idx) -{ - cTValue *o = index2adr(L, idx); - TValue tmp; - if (LJ_LIKELY(tvisnumber(o))) - return numberVnum(o); - else if (tvisstr(o) && lj_strscan_num(strV(o), &tmp)) - return numV(&tmp); - else - return 0; -} - -LUA_API lua_Number lua_tonumberx(lua_State *L, int idx, int *ok) -{ - cTValue *o = index2adr(L, idx); - TValue tmp; - if (LJ_LIKELY(tvisnumber(o))) { - if (ok) *ok = 1; - return numberVnum(o); - } else if (tvisstr(o) && lj_strscan_num(strV(o), &tmp)) { - if (ok) *ok = 1; - return numV(&tmp); - } else { - if (ok) *ok = 0; - return 0; - } -} - -LUALIB_API lua_Number luaL_checknumber(lua_State *L, int idx) -{ - cTValue *o = index2adr(L, idx); - TValue tmp; - if (LJ_LIKELY(tvisnumber(o))) - return numberVnum(o); - else if (!(tvisstr(o) && lj_strscan_num(strV(o), &tmp))) - lj_err_argt(L, idx, LUA_TNUMBER); - return numV(&tmp); -} - -LUALIB_API lua_Number luaL_optnumber(lua_State *L, int idx, lua_Number def) -{ - cTValue *o = index2adr(L, idx); - TValue tmp; - if (LJ_LIKELY(tvisnumber(o))) - return numberVnum(o); - else if (tvisnil(o)) - return def; - else if (!(tvisstr(o) && lj_strscan_num(strV(o), &tmp))) - lj_err_argt(L, idx, LUA_TNUMBER); - return numV(&tmp); -} - -LUA_API lua_Integer lua_tointeger(lua_State *L, int idx) -{ - cTValue *o = index2adr(L, idx); - TValue tmp; - lua_Number n; - if (LJ_LIKELY(tvisint(o))) { - return intV(o); - } else if (LJ_LIKELY(tvisnum(o))) { - n = numV(o); - } else { - if (!(tvisstr(o) && lj_strscan_number(strV(o), &tmp))) - return 0; - if (tvisint(&tmp)) - return intV(&tmp); - n = numV(&tmp); - } -#if LJ_64 - return (lua_Integer)n; -#else - return lj_num2int(n); -#endif -} - -LUA_API lua_Integer lua_tointegerx(lua_State *L, int idx, int *ok) -{ - cTValue *o = index2adr(L, idx); - TValue tmp; - lua_Number n; - if (LJ_LIKELY(tvisint(o))) { - if (ok) *ok = 1; - return intV(o); - } else if (LJ_LIKELY(tvisnum(o))) { - n = numV(o); - } else { - if (!(tvisstr(o) && lj_strscan_number(strV(o), &tmp))) { - if (ok) *ok = 0; - return 0; - } - if (tvisint(&tmp)) { - if (ok) *ok = 1; - return intV(&tmp); - } - n = numV(&tmp); - } - if (ok) *ok = 1; -#if LJ_64 - return (lua_Integer)n; -#else - return lj_num2int(n); -#endif -} - -LUALIB_API lua_Integer luaL_checkinteger(lua_State *L, int idx) -{ - cTValue *o = index2adr(L, idx); - TValue tmp; - lua_Number n; - if (LJ_LIKELY(tvisint(o))) { - return intV(o); - } else if (LJ_LIKELY(tvisnum(o))) { - n = numV(o); - } else { - if (!(tvisstr(o) && lj_strscan_number(strV(o), &tmp))) - lj_err_argt(L, idx, LUA_TNUMBER); - if (tvisint(&tmp)) - return (lua_Integer)intV(&tmp); - n = numV(&tmp); - } -#if LJ_64 - return (lua_Integer)n; -#else - return lj_num2int(n); -#endif -} - -LUALIB_API lua_Integer luaL_optinteger(lua_State *L, int idx, lua_Integer def) -{ - cTValue *o = index2adr(L, idx); - TValue tmp; - lua_Number n; - if (LJ_LIKELY(tvisint(o))) { - return intV(o); - } else if (LJ_LIKELY(tvisnum(o))) { - n = numV(o); - } else if (tvisnil(o)) { - return def; - } else { - if (!(tvisstr(o) && lj_strscan_number(strV(o), &tmp))) - lj_err_argt(L, idx, LUA_TNUMBER); - if (tvisint(&tmp)) - return (lua_Integer)intV(&tmp); - n = numV(&tmp); - } -#if LJ_64 - return (lua_Integer)n; -#else - return lj_num2int(n); -#endif -} - -LUA_API int lua_toboolean(lua_State *L, int idx) -{ - cTValue *o = index2adr(L, idx); - return tvistruecond(o); -} - -LUA_API const char *lua_tolstring(lua_State *L, int idx, size_t *len) -{ - TValue *o = index2adr(L, idx); - GCstr *s; - if (LJ_LIKELY(tvisstr(o))) { - s = strV(o); - } else if (tvisnumber(o)) { - lj_gc_check(L); - o = index2adr(L, idx); /* GC may move the stack. */ - s = lj_strfmt_number(L, o); - setstrV(L, o, s); - } else { - if (len != NULL) *len = 0; - return NULL; - } - if (len != NULL) *len = s->len; - return strdata(s); -} - -LUALIB_API const char *luaL_checklstring(lua_State *L, int idx, size_t *len) -{ - TValue *o = index2adr(L, idx); - GCstr *s; - if (LJ_LIKELY(tvisstr(o))) { - s = strV(o); - } else if (tvisnumber(o)) { - lj_gc_check(L); - o = index2adr(L, idx); /* GC may move the stack. */ - s = lj_strfmt_number(L, o); - setstrV(L, o, s); - } else { - lj_err_argt(L, idx, LUA_TSTRING); - } - if (len != NULL) *len = s->len; - return strdata(s); -} - -LUALIB_API const char *luaL_optlstring(lua_State *L, int idx, - const char *def, size_t *len) -{ - TValue *o = index2adr(L, idx); - GCstr *s; - if (LJ_LIKELY(tvisstr(o))) { - s = strV(o); - } else if (tvisnil(o)) { - if (len != NULL) *len = def ? strlen(def) : 0; - return def; - } else if (tvisnumber(o)) { - lj_gc_check(L); - o = index2adr(L, idx); /* GC may move the stack. */ - s = lj_strfmt_number(L, o); - setstrV(L, o, s); - } else { - lj_err_argt(L, idx, LUA_TSTRING); - } - if (len != NULL) *len = s->len; - return strdata(s); -} - -LUALIB_API int luaL_checkoption(lua_State *L, int idx, const char *def, - const char *const lst[]) -{ - ptrdiff_t i; - const char *s = lua_tolstring(L, idx, NULL); - if (s == NULL && (s = def) == NULL) - lj_err_argt(L, idx, LUA_TSTRING); - for (i = 0; lst[i]; i++) - if (strcmp(lst[i], s) == 0) - return (int)i; - lj_err_argv(L, idx, LJ_ERR_INVOPTM, s); -} - -LUA_API size_t lua_objlen(lua_State *L, int idx) -{ - TValue *o = index2adr(L, idx); - if (tvisstr(o)) { - return strV(o)->len; - } else if (tvistab(o)) { - return (size_t)lj_tab_len(tabV(o)); - } else if (tvisudata(o)) { - return udataV(o)->len; - } else if (tvisnumber(o)) { - GCstr *s = lj_strfmt_number(L, o); - setstrV(L, o, s); - return s->len; - } else { - return 0; - } -} - -LUA_API lua_CFunction lua_tocfunction(lua_State *L, int idx) -{ - cTValue *o = index2adr(L, idx); - if (tvisfunc(o)) { - BCOp op = bc_op(*mref(funcV(o)->c.pc, BCIns)); - if (op == BC_FUNCC || op == BC_FUNCCW) - return funcV(o)->c.f; - } - return NULL; -} - -LUA_API void *lua_touserdata(lua_State *L, int idx) -{ - cTValue *o = index2adr(L, idx); - if (tvisudata(o)) - return uddata(udataV(o)); - else if (tvislightud(o)) - return lightudV(o); - else - return NULL; -} - -LUA_API lua_State *lua_tothread(lua_State *L, int idx) -{ - cTValue *o = index2adr(L, idx); - return (!tvisthread(o)) ? NULL : threadV(o); -} - -LUA_API const void *lua_topointer(lua_State *L, int idx) -{ - return lj_obj_ptr(index2adr(L, idx)); -} - -/* -- Stack setters (object creation) ------------------------------------- */ - -LUA_API void lua_pushnil(lua_State *L) -{ - setnilV(L->top); - incr_top(L); -} - -LUA_API void lua_pushnumber(lua_State *L, lua_Number n) -{ - setnumV(L->top, n); - if (LJ_UNLIKELY(tvisnan(L->top))) - setnanV(L->top); /* Canonicalize injected NaNs. */ - incr_top(L); -} - -LUA_API void lua_pushinteger(lua_State *L, lua_Integer n) -{ - setintptrV(L->top, n); - incr_top(L); -} - -LUA_API void lua_pushlstring(lua_State *L, const char *str, size_t len) -{ - GCstr *s; - lj_gc_check(L); - s = lj_str_new(L, str, len); - setstrV(L, L->top, s); - incr_top(L); -} - -LUA_API void lua_pushstring(lua_State *L, const char *str) -{ - if (str == NULL) { - setnilV(L->top); - } else { - GCstr *s; - lj_gc_check(L); - s = lj_str_newz(L, str); - setstrV(L, L->top, s); - } - incr_top(L); -} - -LUA_API const char *lua_pushvfstring(lua_State *L, const char *fmt, - va_list argp) -{ - lj_gc_check(L); - return lj_strfmt_pushvf(L, fmt, argp); -} - -LUA_API const char *lua_pushfstring(lua_State *L, const char *fmt, ...) -{ - const char *ret; - va_list argp; - lj_gc_check(L); - va_start(argp, fmt); - ret = lj_strfmt_pushvf(L, fmt, argp); - va_end(argp); - return ret; -} - -LUA_API void lua_pushcclosure(lua_State *L, lua_CFunction f, int n) -{ - GCfunc *fn; - lj_gc_check(L); - api_checknelems(L, n); - fn = lj_func_newC(L, (MSize)n, getcurrenv(L)); - fn->c.f = f; - L->top -= n; - while (n--) - copyTV(L, &fn->c.upvalue[n], L->top+n); - setfuncV(L, L->top, fn); - lua_assert(iswhite(obj2gco(fn))); - incr_top(L); -} - -LUA_API void lua_pushboolean(lua_State *L, int b) -{ - setboolV(L->top, (b != 0)); - incr_top(L); -} - -LUA_API void lua_pushlightuserdata(lua_State *L, void *p) -{ - setlightudV(L->top, checklightudptr(L, p)); - incr_top(L); -} - -LUA_API void lua_createtable(lua_State *L, int narray, int nrec) -{ - lj_gc_check(L); - settabV(L, L->top, lj_tab_new_ah(L, narray, nrec)); - incr_top(L); -} - -LUALIB_API int luaL_newmetatable(lua_State *L, const char *tname) -{ - GCtab *regt = tabV(registry(L)); - TValue *tv = lj_tab_setstr(L, regt, lj_str_newz(L, tname)); - if (tvisnil(tv)) { - GCtab *mt = lj_tab_new(L, 0, 1); - settabV(L, tv, mt); - settabV(L, L->top++, mt); - lj_gc_anybarriert(L, regt); - return 1; - } else { - copyTV(L, L->top++, tv); - return 0; - } -} - -LUA_API int lua_pushthread(lua_State *L) -{ - setthreadV(L, L->top, L); - incr_top(L); - return (mainthread(G(L)) == L); -} - -LUA_API lua_State *lua_newthread(lua_State *L) -{ - lua_State *L1; - lj_gc_check(L); - L1 = lj_state_new(L); - setthreadV(L, L->top, L1); - incr_top(L); - return L1; -} - -LUA_API void *lua_newuserdata(lua_State *L, size_t size) -{ - GCudata *ud; - lj_gc_check(L); - if (size > LJ_MAX_UDATA) - lj_err_msg(L, LJ_ERR_UDATAOV); - ud = lj_udata_new(L, (MSize)size, getcurrenv(L)); - setudataV(L, L->top, ud); - incr_top(L); - return uddata(ud); -} - -LUA_API void lua_concat(lua_State *L, int n) -{ - api_checknelems(L, n); - if (n >= 2) { - n--; - do { - TValue *top = lj_meta_cat(L, L->top-1, -n); - if (top == NULL) { - L->top -= n; - break; - } - n -= (int)(L->top - top); - L->top = top+2; - lj_vm_call(L, top, 1+1); - L->top -= 1+LJ_FR2; - copyTV(L, L->top-1, L->top+LJ_FR2); - } while (--n > 0); - } else if (n == 0) { /* Push empty string. */ - setstrV(L, L->top, &G(L)->strempty); - incr_top(L); - } - /* else n == 1: nothing to do. */ -} - -/* -- Object getters ------------------------------------------------------ */ - -LUA_API void lua_gettable(lua_State *L, int idx) -{ - cTValue *v, *t = index2adr(L, idx); - api_checkvalidindex(L, t); - v = lj_meta_tget(L, t, L->top-1); - if (v == NULL) { - L->top += 2; - lj_vm_call(L, L->top-2, 1+1); - L->top -= 2+LJ_FR2; - v = L->top+1+LJ_FR2; - } - copyTV(L, L->top-1, v); -} - -LUA_API void lua_getfield(lua_State *L, int idx, const char *k) -{ - cTValue *v, *t = index2adr(L, idx); - TValue key; - api_checkvalidindex(L, t); - setstrV(L, &key, lj_str_newz(L, k)); - v = lj_meta_tget(L, t, &key); - if (v == NULL) { - L->top += 2; - lj_vm_call(L, L->top-2, 1+1); - L->top -= 2+LJ_FR2; - v = L->top+1+LJ_FR2; - } - copyTV(L, L->top, v); - incr_top(L); -} - -LUA_API void lua_rawget(lua_State *L, int idx) -{ - cTValue *t = index2adr(L, idx); - api_check(L, tvistab(t)); - copyTV(L, L->top-1, lj_tab_get(L, tabV(t), L->top-1)); -} - -LUA_API void lua_rawgeti(lua_State *L, int idx, int n) -{ - cTValue *v, *t = index2adr(L, idx); - api_check(L, tvistab(t)); - v = lj_tab_getint(tabV(t), n); - if (v) { - copyTV(L, L->top, v); - } else { - setnilV(L->top); - } - incr_top(L); -} - -LUA_API int lua_getmetatable(lua_State *L, int idx) -{ - cTValue *o = index2adr(L, idx); - GCtab *mt = NULL; - if (tvistab(o)) - mt = tabref(tabV(o)->metatable); - else if (tvisudata(o)) - mt = tabref(udataV(o)->metatable); - else - mt = tabref(basemt_obj(G(L), o)); - if (mt == NULL) - return 0; - settabV(L, L->top, mt); - incr_top(L); - return 1; -} - -LUALIB_API int luaL_getmetafield(lua_State *L, int idx, const char *field) -{ - if (lua_getmetatable(L, idx)) { - cTValue *tv = lj_tab_getstr(tabV(L->top-1), lj_str_newz(L, field)); - if (tv && !tvisnil(tv)) { - copyTV(L, L->top-1, tv); - return 1; - } - L->top--; - } - return 0; -} - -LUA_API void lua_getfenv(lua_State *L, int idx) -{ - cTValue *o = index2adr(L, idx); - api_checkvalidindex(L, o); - if (tvisfunc(o)) { - settabV(L, L->top, tabref(funcV(o)->c.env)); - } else if (tvisudata(o)) { - settabV(L, L->top, tabref(udataV(o)->env)); - } else if (tvisthread(o)) { - settabV(L, L->top, tabref(threadV(o)->env)); - } else { - setnilV(L->top); - } - incr_top(L); -} - -LUA_API int lua_next(lua_State *L, int idx) -{ - cTValue *t = index2adr(L, idx); - int more; - api_check(L, tvistab(t)); - more = lj_tab_next(L, tabV(t), L->top-1); - if (more) { - incr_top(L); /* Return new key and value slot. */ - } else { /* End of traversal. */ - L->top--; /* Remove key slot. */ - } - return more; -} - -LUA_API const char *lua_getupvalue(lua_State *L, int idx, int n) -{ - TValue *val; - const char *name = lj_debug_uvnamev(index2adr(L, idx), (uint32_t)(n-1), &val); - if (name) { - copyTV(L, L->top, val); - incr_top(L); - } - return name; -} - -LUA_API void *lua_upvalueid(lua_State *L, int idx, int n) -{ - GCfunc *fn = funcV(index2adr(L, idx)); - n--; - api_check(L, (uint32_t)n < fn->l.nupvalues); - return isluafunc(fn) ? (void *)gcref(fn->l.uvptr[n]) : - (void *)&fn->c.upvalue[n]; -} - -LUA_API void lua_upvaluejoin(lua_State *L, int idx1, int n1, int idx2, int n2) -{ - GCfunc *fn1 = funcV(index2adr(L, idx1)); - GCfunc *fn2 = funcV(index2adr(L, idx2)); - n1--; n2--; - api_check(L, isluafunc(fn1) && (uint32_t)n1 < fn1->l.nupvalues); - api_check(L, isluafunc(fn2) && (uint32_t)n2 < fn2->l.nupvalues); - setgcrefr(fn1->l.uvptr[n1], fn2->l.uvptr[n2]); - lj_gc_objbarrier(L, fn1, gcref(fn1->l.uvptr[n1])); -} - -LUALIB_API void *luaL_testudata(lua_State *L, int idx, const char *tname) -{ - cTValue *o = index2adr(L, idx); - if (tvisudata(o)) { - GCudata *ud = udataV(o); - cTValue *tv = lj_tab_getstr(tabV(registry(L)), lj_str_newz(L, tname)); - if (tv && tvistab(tv) && tabV(tv) == tabref(ud->metatable)) - return uddata(ud); - } - return NULL; /* value is not a userdata with a metatable */ -} - -LUALIB_API void *luaL_checkudata(lua_State *L, int idx, const char *tname) -{ - void *p = luaL_testudata(L, idx, tname); - if (!p) lj_err_argtype(L, idx, tname); - return p; -} - -/* -- Object setters ------------------------------------------------------ */ - -LUA_API void lua_settable(lua_State *L, int idx) -{ - TValue *o; - cTValue *t = index2adr(L, idx); - api_checknelems(L, 2); - api_checkvalidindex(L, t); - o = lj_meta_tset(L, t, L->top-2); - if (o) { - /* NOBARRIER: lj_meta_tset ensures the table is not black. */ - L->top -= 2; - copyTV(L, o, L->top+1); - } else { - TValue *base = L->top; - copyTV(L, base+2, base-3-2*LJ_FR2); - L->top = base+3; - lj_vm_call(L, base, 0+1); - L->top -= 3+LJ_FR2; - } -} - -LUA_API void lua_setfield(lua_State *L, int idx, const char *k) -{ - TValue *o; - TValue key; - cTValue *t = index2adr(L, idx); - api_checknelems(L, 1); - api_checkvalidindex(L, t); - setstrV(L, &key, lj_str_newz(L, k)); - o = lj_meta_tset(L, t, &key); - if (o) { - /* NOBARRIER: lj_meta_tset ensures the table is not black. */ - copyTV(L, o, --L->top); - } else { - TValue *base = L->top; - copyTV(L, base+2, base-3-2*LJ_FR2); - L->top = base+3; - lj_vm_call(L, base, 0+1); - L->top -= 2+LJ_FR2; - } -} - -LUA_API void lua_rawset(lua_State *L, int idx) -{ - GCtab *t = tabV(index2adr(L, idx)); - TValue *dst, *key; - api_checknelems(L, 2); - key = L->top-2; - dst = lj_tab_set(L, t, key); - copyTV(L, dst, key+1); - lj_gc_anybarriert(L, t); - L->top = key; -} - -LUA_API void lua_rawseti(lua_State *L, int idx, int n) -{ - GCtab *t = tabV(index2adr(L, idx)); - TValue *dst, *src; - api_checknelems(L, 1); - dst = lj_tab_setint(L, t, n); - src = L->top-1; - copyTV(L, dst, src); - lj_gc_barriert(L, t, dst); - L->top = src; -} - -LUA_API int lua_setmetatable(lua_State *L, int idx) -{ - global_State *g; - GCtab *mt; - cTValue *o = index2adr(L, idx); - api_checknelems(L, 1); - api_checkvalidindex(L, o); - if (tvisnil(L->top-1)) { - mt = NULL; - } else { - api_check(L, tvistab(L->top-1)); - mt = tabV(L->top-1); - } - g = G(L); - if (tvistab(o)) { - setgcref(tabV(o)->metatable, obj2gco(mt)); - if (mt) - lj_gc_objbarriert(L, tabV(o), mt); - } else if (tvisudata(o)) { - setgcref(udataV(o)->metatable, obj2gco(mt)); - if (mt) - lj_gc_objbarrier(L, udataV(o), mt); - } else { - /* Flush cache, since traces specialize to basemt. But not during __gc. */ - if (lj_trace_flushall(L)) - lj_err_caller(L, LJ_ERR_NOGCMM); - if (tvisbool(o)) { - /* NOBARRIER: basemt is a GC root. */ - setgcref(basemt_it(g, LJ_TTRUE), obj2gco(mt)); - setgcref(basemt_it(g, LJ_TFALSE), obj2gco(mt)); - } else { - /* NOBARRIER: basemt is a GC root. */ - setgcref(basemt_obj(g, o), obj2gco(mt)); - } - } - L->top--; - return 1; -} - -LUALIB_API void luaL_setmetatable(lua_State *L, const char *tname) -{ - lua_getfield(L, LUA_REGISTRYINDEX, tname); - lua_setmetatable(L, -2); -} - -LUA_API int lua_setfenv(lua_State *L, int idx) -{ - cTValue *o = index2adr(L, idx); - GCtab *t; - api_checknelems(L, 1); - api_checkvalidindex(L, o); - api_check(L, tvistab(L->top-1)); - t = tabV(L->top-1); - if (tvisfunc(o)) { - setgcref(funcV(o)->c.env, obj2gco(t)); - } else if (tvisudata(o)) { - setgcref(udataV(o)->env, obj2gco(t)); - } else if (tvisthread(o)) { - setgcref(threadV(o)->env, obj2gco(t)); - } else { - L->top--; - return 0; - } - lj_gc_objbarrier(L, gcV(o), t); - L->top--; - return 1; -} - -LUA_API const char *lua_setupvalue(lua_State *L, int idx, int n) -{ - cTValue *f = index2adr(L, idx); - TValue *val; - const char *name; - api_checknelems(L, 1); - name = lj_debug_uvnamev(f, (uint32_t)(n-1), &val); - if (name) { - L->top--; - copyTV(L, val, L->top); - lj_gc_barrier(L, funcV(f), L->top); - } - return name; -} - -/* -- Calls --------------------------------------------------------------- */ - -#if LJ_FR2 -static TValue *api_call_base(lua_State *L, int nargs) -{ - TValue *o = L->top, *base = o - nargs; - L->top = o+1; - for (; o > base; o--) copyTV(L, o, o-1); - setnilV(o); - return o+1; -} -#else -#define api_call_base(L, nargs) (L->top - (nargs)) -#endif - -LUA_API void lua_call(lua_State *L, int nargs, int nresults) -{ - api_check(L, L->status == LUA_OK || L->status == LUA_ERRERR); - api_checknelems(L, nargs+1); - lj_vm_call(L, api_call_base(L, nargs), nresults+1); -} - -LUA_API int lua_pcall(lua_State *L, int nargs, int nresults, int errfunc) -{ - global_State *g = G(L); - uint8_t oldh = hook_save(g); - ptrdiff_t ef; - int status; - api_check(L, L->status == LUA_OK || L->status == LUA_ERRERR); - api_checknelems(L, nargs+1); - if (errfunc == 0) { - ef = 0; - } else { - cTValue *o = stkindex2adr(L, errfunc); - api_checkvalidindex(L, o); - ef = savestack(L, o); - } - status = lj_vm_pcall(L, api_call_base(L, nargs), nresults+1, ef); - if (status) hook_restore(g, oldh); - return status; -} - -static TValue *cpcall(lua_State *L, lua_CFunction func, void *ud) -{ - GCfunc *fn = lj_func_newC(L, 0, getcurrenv(L)); - TValue *top = L->top; - fn->c.f = func; - setfuncV(L, top++, fn); - if (LJ_FR2) setnilV(top++); - setlightudV(top++, checklightudptr(L, ud)); - cframe_nres(L->cframe) = 1+0; /* Zero results. */ - L->top = top; - return top-1; /* Now call the newly allocated C function. */ -} - -LUA_API int lua_cpcall(lua_State *L, lua_CFunction func, void *ud) -{ - global_State *g = G(L); - uint8_t oldh = hook_save(g); - int status; - api_check(L, L->status == LUA_OK || L->status == LUA_ERRERR); - status = lj_vm_cpcall(L, func, ud, cpcall); - if (status) hook_restore(g, oldh); - return status; -} - -LUALIB_API int luaL_callmeta(lua_State *L, int idx, const char *field) -{ - if (luaL_getmetafield(L, idx, field)) { - TValue *top = L->top--; - if (LJ_FR2) setnilV(top++); - copyTV(L, top++, index2adr(L, idx)); - L->top = top; - lj_vm_call(L, top-1, 1+1); - return 1; - } - return 0; -} - -/* -- Coroutine yield and resume ------------------------------------------ */ - -LUA_API int lua_isyieldable(lua_State *L) -{ - return cframe_canyield(L->cframe); -} - -LUA_API int lua_yield(lua_State *L, int nresults) -{ - void *cf = L->cframe; - global_State *g = G(L); - if (cframe_canyield(cf)) { - cf = cframe_raw(cf); - if (!hook_active(g)) { /* Regular yield: move results down if needed. */ - cTValue *f = L->top - nresults; - if (f > L->base) { - TValue *t = L->base; - while (--nresults >= 0) copyTV(L, t++, f++); - L->top = t; - } - L->cframe = NULL; - L->status = LUA_YIELD; - return -1; - } else { /* Yield from hook: add a pseudo-frame. */ - TValue *top = L->top; - hook_leave(g); - (top++)->u64 = cframe_multres(cf); - setcont(top, lj_cont_hook); - if (LJ_FR2) top++; - setframe_pc(top, cframe_pc(cf)-1); - if (LJ_FR2) top++; - setframe_gc(top, obj2gco(L), LJ_TTHREAD); - setframe_ftsz(top, ((char *)(top+1)-(char *)L->base)+FRAME_CONT); - L->top = L->base = top+1; -#if LJ_TARGET_X64 - lj_err_throw(L, LUA_YIELD); -#else - L->cframe = NULL; - L->status = LUA_YIELD; - lj_vm_unwind_c(cf, LUA_YIELD); -#endif - } - } - lj_err_msg(L, LJ_ERR_CYIELD); - return 0; /* unreachable */ -} - -LUA_API int lua_resume(lua_State *L, int nargs) -{ - if (L->cframe == NULL && L->status <= LUA_YIELD) - return lj_vm_resume(L, - L->status == LUA_OK ? api_call_base(L, nargs) : L->top - nargs, - 0, 0); - L->top = L->base; - setstrV(L, L->top, lj_err_str(L, LJ_ERR_COSUSP)); - incr_top(L); - return LUA_ERRRUN; -} - -/* -- GC and memory management -------------------------------------------- */ - -LUA_API int lua_gc(lua_State *L, int what, int data) -{ - global_State *g = G(L); - int res = 0; - switch (what) { - case LUA_GCSTOP: - g->gc.threshold = LJ_MAX_MEM; - break; - case LUA_GCRESTART: - g->gc.threshold = data == -1 ? (g->gc.total/100)*g->gc.pause : g->gc.total; - break; - case LUA_GCCOLLECT: - lj_gc_fullgc(L); - break; - case LUA_GCCOUNT: - res = (int)(g->gc.total >> 10); - break; - case LUA_GCCOUNTB: - res = (int)(g->gc.total & 0x3ff); - break; - case LUA_GCSTEP: { - GCSize a = (GCSize)data << 10; - g->gc.threshold = (a <= g->gc.total) ? (g->gc.total - a) : 0; - while (g->gc.total >= g->gc.threshold) - if (lj_gc_step(L) > 0) { - res = 1; - break; - } - break; - } - case LUA_GCSETPAUSE: - res = (int)(g->gc.pause); - g->gc.pause = (MSize)data; - break; - case LUA_GCSETSTEPMUL: - res = (int)(g->gc.stepmul); - g->gc.stepmul = (MSize)data; - break; - case LUA_GCISRUNNING: - res = (g->gc.threshold != LJ_MAX_MEM); - break; - default: - res = -1; /* Invalid option. */ - } - return res; -} - -LUA_API lua_Alloc lua_getallocf(lua_State *L, void **ud) -{ - global_State *g = G(L); - if (ud) *ud = g->allocd; - return g->allocf; -} - -LUA_API void lua_setallocf(lua_State *L, lua_Alloc f, void *ud) -{ - global_State *g = G(L); - g->allocd = ud; - g->allocf = f; -} - diff --git a/lib/LuaJIT/src/lj_arch.h b/lib/LuaJIT/src/lj_arch.h deleted file mode 100644 index 31a1159..0000000 --- a/lib/LuaJIT/src/lj_arch.h +++ /dev/null @@ -1,599 +0,0 @@ -/* -** Target architecture selection. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_ARCH_H -#define _LJ_ARCH_H - -#include "lua.h" - -/* Target endianess. */ -#define LUAJIT_LE 0 -#define LUAJIT_BE 1 - -/* Target architectures. */ -#define LUAJIT_ARCH_X86 1 -#define LUAJIT_ARCH_x86 1 -#define LUAJIT_ARCH_X64 2 -#define LUAJIT_ARCH_x64 2 -#define LUAJIT_ARCH_ARM 3 -#define LUAJIT_ARCH_arm 3 -#define LUAJIT_ARCH_ARM64 4 -#define LUAJIT_ARCH_arm64 4 -#define LUAJIT_ARCH_PPC 5 -#define LUAJIT_ARCH_ppc 5 -#define LUAJIT_ARCH_MIPS 6 -#define LUAJIT_ARCH_mips 6 -#define LUAJIT_ARCH_MIPS32 6 -#define LUAJIT_ARCH_mips32 6 -#define LUAJIT_ARCH_MIPS64 7 -#define LUAJIT_ARCH_mips64 7 - -/* Target OS. */ -#define LUAJIT_OS_OTHER 0 -#define LUAJIT_OS_WINDOWS 1 -#define LUAJIT_OS_LINUX 2 -#define LUAJIT_OS_OSX 3 -#define LUAJIT_OS_BSD 4 -#define LUAJIT_OS_POSIX 5 - -/* Select native target if no target defined. */ -#ifndef LUAJIT_TARGET - -#if defined(__i386) || defined(__i386__) || defined(_M_IX86) -#define LUAJIT_TARGET LUAJIT_ARCH_X86 -#elif defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) -#define LUAJIT_TARGET LUAJIT_ARCH_X64 -#elif defined(__arm__) || defined(__arm) || defined(__ARM__) || defined(__ARM) -#define LUAJIT_TARGET LUAJIT_ARCH_ARM -#elif defined(__aarch64__) -#define LUAJIT_TARGET LUAJIT_ARCH_ARM64 -#elif defined(__ppc__) || defined(__ppc) || defined(__PPC__) || defined(__PPC) || defined(__powerpc__) || defined(__powerpc) || defined(__POWERPC__) || defined(__POWERPC) || defined(_M_PPC) -#define LUAJIT_TARGET LUAJIT_ARCH_PPC -#elif defined(__mips64__) || defined(__mips64) || defined(__MIPS64__) || defined(__MIPS64) -#define LUAJIT_TARGET LUAJIT_ARCH_MIPS64 -#elif defined(__mips__) || defined(__mips) || defined(__MIPS__) || defined(__MIPS) -#define LUAJIT_TARGET LUAJIT_ARCH_MIPS32 -#else -#error "No support for this architecture (yet)" -#endif - -#endif - -/* Select native OS if no target OS defined. */ -#ifndef LUAJIT_OS - -#if defined(_WIN32) && !defined(_XBOX_VER) -#define LUAJIT_OS LUAJIT_OS_WINDOWS -#elif defined(__linux__) -#define LUAJIT_OS LUAJIT_OS_LINUX -#elif defined(__MACH__) && defined(__APPLE__) -#define LUAJIT_OS LUAJIT_OS_OSX -#elif (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ - defined(__NetBSD__) || defined(__OpenBSD__) || \ - defined(__DragonFly__)) && !defined(__ORBIS__) -#define LUAJIT_OS LUAJIT_OS_BSD -#elif (defined(__sun__) && defined(__svr4__)) || defined(__HAIKU__) -#define LUAJIT_OS LUAJIT_OS_POSIX -#elif defined(__CYGWIN__) -#define LJ_TARGET_CYGWIN 1 -#define LUAJIT_OS LUAJIT_OS_POSIX -#else -#define LUAJIT_OS LUAJIT_OS_OTHER -#endif - -#endif - -/* Set target OS properties. */ -#if LUAJIT_OS == LUAJIT_OS_WINDOWS -#define LJ_OS_NAME "Windows" -#elif LUAJIT_OS == LUAJIT_OS_LINUX -#define LJ_OS_NAME "Linux" -#elif LUAJIT_OS == LUAJIT_OS_OSX -#define LJ_OS_NAME "OSX" -#elif LUAJIT_OS == LUAJIT_OS_BSD -#define LJ_OS_NAME "BSD" -#elif LUAJIT_OS == LUAJIT_OS_POSIX -#define LJ_OS_NAME "POSIX" -#else -#define LJ_OS_NAME "Other" -#endif - -#define LJ_TARGET_WINDOWS (LUAJIT_OS == LUAJIT_OS_WINDOWS) -#define LJ_TARGET_LINUX (LUAJIT_OS == LUAJIT_OS_LINUX) -#define LJ_TARGET_OSX (LUAJIT_OS == LUAJIT_OS_OSX) -#define LJ_TARGET_IOS (LJ_TARGET_OSX && (LUAJIT_TARGET == LUAJIT_ARCH_ARM || LUAJIT_TARGET == LUAJIT_ARCH_ARM64)) -#define LJ_TARGET_POSIX (LUAJIT_OS > LUAJIT_OS_WINDOWS) -#define LJ_TARGET_DLOPEN LJ_TARGET_POSIX - -#ifdef __CELLOS_LV2__ -#define LJ_TARGET_PS3 1 -#define LJ_TARGET_CONSOLE 1 -#endif - -#ifdef __ORBIS__ -#define LJ_TARGET_PS4 1 -#define LJ_TARGET_CONSOLE 1 -#undef NULL -#define NULL ((void*)0) -#endif - -#ifdef __psp2__ -#define LJ_TARGET_PSVITA 1 -#define LJ_TARGET_CONSOLE 1 -#endif - -#if _XBOX_VER >= 200 -#define LJ_TARGET_XBOX360 1 -#define LJ_TARGET_CONSOLE 1 -#endif - -#ifdef _DURANGO -#define LJ_TARGET_XBOXONE 1 -#define LJ_TARGET_CONSOLE 1 -#define LJ_TARGET_GC64 1 -#endif - -#ifdef _UWP -#define LJ_TARGET_UWP 1 -#if LUAJIT_TARGET == LUAJIT_ARCH_X64 -#define LJ_TARGET_GC64 1 -#endif -#endif - -#define LJ_NUMMODE_SINGLE 0 /* Single-number mode only. */ -#define LJ_NUMMODE_SINGLE_DUAL 1 /* Default to single-number mode. */ -#define LJ_NUMMODE_DUAL 2 /* Dual-number mode only. */ -#define LJ_NUMMODE_DUAL_SINGLE 3 /* Default to dual-number mode. */ - -/* Set target architecture properties. */ -#if LUAJIT_TARGET == LUAJIT_ARCH_X86 - -#define LJ_ARCH_NAME "x86" -#define LJ_ARCH_BITS 32 -#define LJ_ARCH_ENDIAN LUAJIT_LE -#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN -#define LJ_ABI_WIN 1 -#else -#define LJ_ABI_WIN 0 -#endif -#define LJ_TARGET_X86 1 -#define LJ_TARGET_X86ORX64 1 -#define LJ_TARGET_EHRETREG 0 -#define LJ_TARGET_MASKSHIFT 1 -#define LJ_TARGET_MASKROT 1 -#define LJ_TARGET_UNALIGNED 1 -#define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE_DUAL - -#elif LUAJIT_TARGET == LUAJIT_ARCH_X64 - -#define LJ_ARCH_NAME "x64" -#define LJ_ARCH_BITS 64 -#define LJ_ARCH_ENDIAN LUAJIT_LE -#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN -#define LJ_ABI_WIN 1 -#else -#define LJ_ABI_WIN 0 -#endif -#define LJ_TARGET_X64 1 -#define LJ_TARGET_X86ORX64 1 -#define LJ_TARGET_EHRETREG 0 -#define LJ_TARGET_JUMPRANGE 31 /* +-2^31 = +-2GB */ -#define LJ_TARGET_MASKSHIFT 1 -#define LJ_TARGET_MASKROT 1 -#define LJ_TARGET_UNALIGNED 1 -#define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE_DUAL -#ifdef LUAJIT_ENABLE_GC64 -#define LJ_TARGET_GC64 1 -#endif - -#elif LUAJIT_TARGET == LUAJIT_ARCH_ARM - -#define LJ_ARCH_NAME "arm" -#define LJ_ARCH_BITS 32 -#define LJ_ARCH_ENDIAN LUAJIT_LE -#if !defined(LJ_ARCH_HASFPU) && __SOFTFP__ -#define LJ_ARCH_HASFPU 0 -#endif -#if !defined(LJ_ABI_SOFTFP) && !__ARM_PCS_VFP -#define LJ_ABI_SOFTFP 1 -#endif -#define LJ_ABI_EABI 1 -#define LJ_TARGET_ARM 1 -#define LJ_TARGET_EHRETREG 0 -#define LJ_TARGET_JUMPRANGE 25 /* +-2^25 = +-32MB */ -#define LJ_TARGET_MASKSHIFT 0 -#define LJ_TARGET_MASKROT 1 -#define LJ_TARGET_UNIFYROT 2 /* Want only IR_BROR. */ -#define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL - -#if __ARM_ARCH_8__ || __ARM_ARCH_8A__ -#define LJ_ARCH_VERSION 80 -#elif __ARM_ARCH_7__ || __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH_7S__ || __ARM_ARCH_7VE__ -#define LJ_ARCH_VERSION 70 -#elif __ARM_ARCH_6T2__ -#define LJ_ARCH_VERSION 61 -#elif __ARM_ARCH_6__ || __ARM_ARCH_6J__ || __ARM_ARCH_6K__ || __ARM_ARCH_6Z__ || __ARM_ARCH_6ZK__ -#define LJ_ARCH_VERSION 60 -#else -#define LJ_ARCH_VERSION 50 -#endif - -#elif LUAJIT_TARGET == LUAJIT_ARCH_ARM64 - -#define LJ_ARCH_BITS 64 -#if defined(__AARCH64EB__) -#define LJ_ARCH_NAME "arm64be" -#define LJ_ARCH_ENDIAN LUAJIT_BE -#else -#define LJ_ARCH_NAME "arm64" -#define LJ_ARCH_ENDIAN LUAJIT_LE -#endif -#define LJ_TARGET_ARM64 1 -#define LJ_TARGET_EHRETREG 0 -#define LJ_TARGET_JUMPRANGE 27 /* +-2^27 = +-128MB */ -#define LJ_TARGET_MASKSHIFT 1 -#define LJ_TARGET_MASKROT 1 -#define LJ_TARGET_UNIFYROT 2 /* Want only IR_BROR. */ -#define LJ_TARGET_GC64 1 -#define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL - -#define LJ_ARCH_VERSION 80 - -#elif LUAJIT_TARGET == LUAJIT_ARCH_PPC - -#ifndef LJ_ARCH_ENDIAN -#if __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__ -#define LJ_ARCH_ENDIAN LUAJIT_LE -#else -#define LJ_ARCH_ENDIAN LUAJIT_BE -#endif -#endif - -#if _LP64 -#define LJ_ARCH_BITS 64 -#if LJ_ARCH_ENDIAN == LUAJIT_LE -#define LJ_ARCH_NAME "ppc64le" -#else -#define LJ_ARCH_NAME "ppc64" -#endif -#else -#define LJ_ARCH_BITS 32 -#define LJ_ARCH_NAME "ppc" - -#if !defined(LJ_ARCH_HASFPU) -#if defined(_SOFT_FLOAT) || defined(_SOFT_DOUBLE) -#define LJ_ARCH_HASFPU 0 -#else -#define LJ_ARCH_HASFPU 1 -#endif -#endif - -#if !defined(LJ_ABI_SOFTFP) -#if defined(_SOFT_FLOAT) || defined(_SOFT_DOUBLE) -#define LJ_ABI_SOFTFP 1 -#else -#define LJ_ABI_SOFTFP 0 -#endif -#endif -#endif - -#if LJ_ABI_SOFTFP -#define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL -#else -#define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL_SINGLE -#endif - -#define LJ_TARGET_PPC 1 -#define LJ_TARGET_EHRETREG 3 -#define LJ_TARGET_JUMPRANGE 25 /* +-2^25 = +-32MB */ -#define LJ_TARGET_MASKSHIFT 0 -#define LJ_TARGET_MASKROT 1 -#define LJ_TARGET_UNIFYROT 1 /* Want only IR_BROL. */ - -#if LJ_TARGET_CONSOLE -#define LJ_ARCH_PPC32ON64 1 -#define LJ_ARCH_NOFFI 1 -#elif LJ_ARCH_BITS == 64 -#define LJ_ARCH_PPC64 1 -#define LJ_TARGET_GC64 1 -#define LJ_ARCH_NOJIT 1 /* NYI */ -#endif - -#if _ARCH_PWR7 -#define LJ_ARCH_VERSION 70 -#elif _ARCH_PWR6 -#define LJ_ARCH_VERSION 60 -#elif _ARCH_PWR5X -#define LJ_ARCH_VERSION 51 -#elif _ARCH_PWR5 -#define LJ_ARCH_VERSION 50 -#elif _ARCH_PWR4 -#define LJ_ARCH_VERSION 40 -#else -#define LJ_ARCH_VERSION 0 -#endif -#if _ARCH_PPCSQ -#define LJ_ARCH_SQRT 1 -#endif -#if _ARCH_PWR5X -#define LJ_ARCH_ROUND 1 -#endif -#if __PPU__ -#define LJ_ARCH_CELL 1 -#endif -#if LJ_TARGET_XBOX360 -#define LJ_ARCH_XENON 1 -#endif - -#elif LUAJIT_TARGET == LUAJIT_ARCH_MIPS32 || LUAJIT_TARGET == LUAJIT_ARCH_MIPS64 - -#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) -#if LUAJIT_TARGET == LUAJIT_ARCH_MIPS32 -#define LJ_ARCH_NAME "mipsel" -#else -#define LJ_ARCH_NAME "mips64el" -#endif -#define LJ_ARCH_ENDIAN LUAJIT_LE -#else -#if LUAJIT_TARGET == LUAJIT_ARCH_MIPS32 -#define LJ_ARCH_NAME "mips" -#else -#define LJ_ARCH_NAME "mips64" -#endif -#define LJ_ARCH_ENDIAN LUAJIT_BE -#endif - -#if !defined(LJ_ARCH_HASFPU) -#ifdef __mips_soft_float -#define LJ_ARCH_HASFPU 0 -#else -#define LJ_ARCH_HASFPU 1 -#endif -#endif - -#if !defined(LJ_ABI_SOFTFP) -#ifdef __mips_soft_float -#define LJ_ABI_SOFTFP 1 -#else -#define LJ_ABI_SOFTFP 0 -#endif -#endif - -#if LUAJIT_TARGET == LUAJIT_ARCH_MIPS32 -#define LJ_ARCH_BITS 32 -#define LJ_TARGET_MIPS32 1 -#else -#define LJ_ARCH_BITS 64 -#define LJ_TARGET_MIPS64 1 -#define LJ_TARGET_GC64 1 -#endif -#define LJ_TARGET_MIPS 1 -#define LJ_TARGET_EHRETREG 4 -#define LJ_TARGET_JUMPRANGE 27 /* 2*2^27 = 256MB-aligned region */ -#define LJ_TARGET_MASKSHIFT 1 -#define LJ_TARGET_MASKROT 1 -#define LJ_TARGET_UNIFYROT 2 /* Want only IR_BROR. */ -#define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL - -#if _MIPS_ARCH_MIPS32R2 || _MIPS_ARCH_MIPS64R2 -#define LJ_ARCH_VERSION 20 -#else -#define LJ_ARCH_VERSION 10 -#endif - -#else -#error "No target architecture defined" -#endif - -#ifndef LJ_PAGESIZE -#define LJ_PAGESIZE 4096 -#endif - -/* Check for minimum required compiler versions. */ -#if defined(__GNUC__) -#if LJ_TARGET_X86 -#if (__GNUC__ < 3) || ((__GNUC__ == 3) && __GNUC_MINOR__ < 4) -#error "Need at least GCC 3.4 or newer" -#endif -#elif LJ_TARGET_X64 -#if __GNUC__ < 4 -#error "Need at least GCC 4.0 or newer" -#endif -#elif LJ_TARGET_ARM -#if (__GNUC__ < 4) || ((__GNUC__ == 4) && __GNUC_MINOR__ < 2) -#error "Need at least GCC 4.2 or newer" -#endif -#elif LJ_TARGET_ARM64 -#if __clang__ -#if ((__clang_major__ < 3) || ((__clang_major__ == 3) && __clang_minor__ < 5)) && !defined(__NX_TOOLCHAIN_MAJOR__) -#error "Need at least Clang 3.5 or newer" -#endif -#else -#if (__GNUC__ < 4) || ((__GNUC__ == 4) && __GNUC_MINOR__ < 8) -#error "Need at least GCC 4.8 or newer" -#endif -#endif -#elif !LJ_TARGET_PS3 -#if (__GNUC__ < 4) || ((__GNUC__ == 4) && __GNUC_MINOR__ < 3) -#error "Need at least GCC 4.3 or newer" -#endif -#endif -#endif - -/* Check target-specific constraints. */ -#ifndef _BUILDVM_H -#if LJ_TARGET_X64 -#if __USING_SJLJ_EXCEPTIONS__ -#error "Need a C compiler with native exception handling on x64" -#endif -#elif LJ_TARGET_ARM -#if defined(__ARMEB__) -#error "No support for big-endian ARM" -#endif -#if __ARM_ARCH_6M__ || __ARM_ARCH_7M__ || __ARM_ARCH_7EM__ -#error "No support for Cortex-M CPUs" -#endif -#if !(__ARM_EABI__ || LJ_TARGET_IOS) -#error "Only ARM EABI or iOS 3.0+ ABI is supported" -#endif -#elif LJ_TARGET_ARM64 -#if defined(_ILP32) -#error "No support for ILP32 model on ARM64" -#endif -#elif LJ_TARGET_PPC -#if !LJ_ARCH_PPC64 && (defined(_LITTLE_ENDIAN) && (!defined(_BYTE_ORDER) || (_BYTE_ORDER == _LITTLE_ENDIAN))) -#error "No support for little-endian PPC32" -#endif -#if defined(__NO_FPRS__) && !defined(_SOFT_FLOAT) -#error "No support for PPC/e500 anymore (use LuaJIT 2.0)" -#endif -#elif LJ_TARGET_MIPS32 -#if !((defined(_MIPS_SIM_ABI32) && _MIPS_SIM == _MIPS_SIM_ABI32) || (defined(_ABIO32) && _MIPS_SIM == _ABIO32)) -#error "Only o32 ABI supported for MIPS32" -#endif -#elif LJ_TARGET_MIPS64 -#if !((defined(_MIPS_SIM_ABI64) && _MIPS_SIM == _MIPS_SIM_ABI64) || (defined(_ABI64) && _MIPS_SIM == _ABI64)) -#error "Only n64 ABI supported for MIPS64" -#endif -#endif -#endif - -/* Enable or disable the dual-number mode for the VM. */ -#if (LJ_ARCH_NUMMODE == LJ_NUMMODE_SINGLE && LUAJIT_NUMMODE == 2) || \ - (LJ_ARCH_NUMMODE == LJ_NUMMODE_DUAL && LUAJIT_NUMMODE == 1) -#error "No support for this number mode on this architecture" -#endif -#if LJ_ARCH_NUMMODE == LJ_NUMMODE_DUAL || \ - (LJ_ARCH_NUMMODE == LJ_NUMMODE_DUAL_SINGLE && LUAJIT_NUMMODE != 1) || \ - (LJ_ARCH_NUMMODE == LJ_NUMMODE_SINGLE_DUAL && LUAJIT_NUMMODE == 2) -#define LJ_DUALNUM 1 -#else -#define LJ_DUALNUM 0 -#endif - -#if LJ_TARGET_IOS || LJ_TARGET_CONSOLE -/* Runtime code generation is restricted on iOS. Complain to Apple, not me. */ -/* Ditto for the consoles. Complain to Sony or MS, not me. */ -#ifndef LUAJIT_ENABLE_JIT -#define LJ_OS_NOJIT 1 -#endif -#endif - -/* 64 bit GC references. */ -#if LJ_TARGET_GC64 -#define LJ_GC64 1 -#else -#define LJ_GC64 0 -#endif - -/* 2-slot frame info. */ -#if LJ_GC64 -#define LJ_FR2 1 -#else -#define LJ_FR2 0 -#endif - -/* Disable or enable the JIT compiler. */ -#if defined(LUAJIT_DISABLE_JIT) || defined(LJ_ARCH_NOJIT) || defined(LJ_OS_NOJIT) -#define LJ_HASJIT 0 -#else -#define LJ_HASJIT 1 -#endif - -/* Disable or enable the FFI extension. */ -#if defined(LUAJIT_DISABLE_FFI) || defined(LJ_ARCH_NOFFI) -#define LJ_HASFFI 0 -#else -#define LJ_HASFFI 1 -#endif - -#if defined(LUAJIT_DISABLE_PROFILE) -#define LJ_HASPROFILE 0 -#elif LJ_TARGET_POSIX -#define LJ_HASPROFILE 1 -#define LJ_PROFILE_SIGPROF 1 -#elif LJ_TARGET_PS3 -#define LJ_HASPROFILE 1 -#define LJ_PROFILE_PTHREAD 1 -#elif LJ_TARGET_WINDOWS || LJ_TARGET_XBOX360 -#define LJ_HASPROFILE 1 -#define LJ_PROFILE_WTHREAD 1 -#else -#define LJ_HASPROFILE 0 -#endif - -#ifndef LJ_ARCH_HASFPU -#define LJ_ARCH_HASFPU 1 -#endif -#ifndef LJ_ABI_SOFTFP -#define LJ_ABI_SOFTFP 0 -#endif -#define LJ_SOFTFP (!LJ_ARCH_HASFPU) -#define LJ_SOFTFP32 (LJ_SOFTFP && LJ_32) - -#if LJ_ARCH_ENDIAN == LUAJIT_BE -#define LJ_LE 0 -#define LJ_BE 1 -#define LJ_ENDIAN_SELECT(le, be) be -#define LJ_ENDIAN_LOHI(lo, hi) hi lo -#else -#define LJ_LE 1 -#define LJ_BE 0 -#define LJ_ENDIAN_SELECT(le, be) le -#define LJ_ENDIAN_LOHI(lo, hi) lo hi -#endif - -#if LJ_ARCH_BITS == 32 -#define LJ_32 1 -#define LJ_64 0 -#else -#define LJ_32 0 -#define LJ_64 1 -#endif - -#ifndef LJ_TARGET_UNALIGNED -#define LJ_TARGET_UNALIGNED 0 -#endif - -/* Various workarounds for embedded operating systems or weak C runtimes. */ -#if defined(__ANDROID__) || defined(__symbian__) || LJ_TARGET_XBOX360 || LJ_TARGET_WINDOWS -#define LUAJIT_NO_LOG2 -#endif -#if defined(__symbian__) || LJ_TARGET_WINDOWS -#define LUAJIT_NO_EXP2 -#endif -#if LJ_TARGET_CONSOLE || (LJ_TARGET_IOS && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0) -#define LJ_NO_SYSTEM 1 -#endif - -#if !defined(LUAJIT_NO_UNWIND) && __GNU_COMPACT_EH__ -/* NYI: no support for compact unwind specification, yet. */ -#define LUAJIT_NO_UNWIND 1 -#endif - -#if defined(LUAJIT_NO_UNWIND) || defined(__symbian__) || LJ_TARGET_IOS || LJ_TARGET_PS3 || LJ_TARGET_PS4 -#define LJ_NO_UNWIND 1 -#endif - -#if LJ_TARGET_WINDOWS -#if LJ_TARGET_UWP -#define LJ_WIN_VALLOC VirtualAllocFromApp -#define LJ_WIN_VPROTECT VirtualProtectFromApp -extern void *LJ_WIN_LOADLIBA(const char *path); -#else -#define LJ_WIN_VALLOC VirtualAlloc -#define LJ_WIN_VPROTECT VirtualProtect -#define LJ_WIN_LOADLIBA(path) LoadLibraryExA((path), NULL, 0) -#endif -#endif - -/* Compatibility with Lua 5.1 vs. 5.2. */ -#ifdef LUAJIT_ENABLE_LUA52COMPAT -#define LJ_52 1 -#else -#define LJ_52 0 -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_asm.c b/lib/LuaJIT/src/lj_asm.c deleted file mode 100644 index 992dcf5..0000000 --- a/lib/LuaJIT/src/lj_asm.c +++ /dev/null @@ -1,2414 +0,0 @@ -/* -** IR assembler (SSA IR -> machine code). -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_asm_c -#define LUA_CORE - -#include "lj_obj.h" - -#if LJ_HASJIT - -#include "lj_gc.h" -#include "lj_str.h" -#include "lj_tab.h" -#include "lj_frame.h" -#if LJ_HASFFI -#include "lj_ctype.h" -#endif -#include "lj_ir.h" -#include "lj_jit.h" -#include "lj_ircall.h" -#include "lj_iropt.h" -#include "lj_mcode.h" -#include "lj_iropt.h" -#include "lj_trace.h" -#include "lj_snap.h" -#include "lj_asm.h" -#include "lj_dispatch.h" -#include "lj_vm.h" -#include "lj_target.h" - -#ifdef LUA_USE_ASSERT -#include -#endif - -/* -- Assembler state and common macros ----------------------------------- */ - -/* Assembler state. */ -typedef struct ASMState { - RegCost cost[RID_MAX]; /* Reference and blended allocation cost for regs. */ - - MCode *mcp; /* Current MCode pointer (grows down). */ - MCode *mclim; /* Lower limit for MCode memory + red zone. */ -#ifdef LUA_USE_ASSERT - MCode *mcp_prev; /* Red zone overflow check. */ -#endif - - IRIns *ir; /* Copy of pointer to IR instructions/constants. */ - jit_State *J; /* JIT compiler state. */ - -#if LJ_TARGET_X86ORX64 - x86ModRM mrm; /* Fused x86 address operand. */ -#endif - - RegSet freeset; /* Set of free registers. */ - RegSet modset; /* Set of registers modified inside the loop. */ - RegSet weakset; /* Set of weakly referenced registers. */ - RegSet phiset; /* Set of PHI registers. */ - - uint32_t flags; /* Copy of JIT compiler flags. */ - int loopinv; /* Loop branch inversion (0:no, 1:yes, 2:yes+CC_P). */ - - int32_t evenspill; /* Next even spill slot. */ - int32_t oddspill; /* Next odd spill slot (or 0). */ - - IRRef curins; /* Reference of current instruction. */ - IRRef stopins; /* Stop assembly before hitting this instruction. */ - IRRef orignins; /* Original T->nins. */ - - IRRef snapref; /* Current snapshot is active after this reference. */ - IRRef snaprename; /* Rename highwater mark for snapshot check. */ - SnapNo snapno; /* Current snapshot number. */ - SnapNo loopsnapno; /* Loop snapshot number. */ - - IRRef fuseref; /* Fusion limit (loopref, 0 or FUSE_DISABLED). */ - IRRef sectref; /* Section base reference (loopref or 0). */ - IRRef loopref; /* Reference of LOOP instruction (or 0). */ - - BCReg topslot; /* Number of slots for stack check (unless 0). */ - int32_t gcsteps; /* Accumulated number of GC steps (per section). */ - - GCtrace *T; /* Trace to assemble. */ - GCtrace *parent; /* Parent trace (or NULL). */ - - MCode *mcbot; /* Bottom of reserved MCode. */ - MCode *mctop; /* Top of generated MCode. */ - MCode *mcloop; /* Pointer to loop MCode (or NULL). */ - MCode *invmcp; /* Points to invertible loop branch (or NULL). */ - MCode *flagmcp; /* Pending opportunity to merge flag setting ins. */ - MCode *realign; /* Realign loop if not NULL. */ - -#ifdef RID_NUM_KREF - intptr_t krefk[RID_NUM_KREF]; -#endif - IRRef1 phireg[RID_MAX]; /* PHI register references. */ - uint16_t parentmap[LJ_MAX_JSLOTS]; /* Parent instruction to RegSP map. */ -} ASMState; - -#define IR(ref) (&as->ir[(ref)]) - -#define ASMREF_TMP1 REF_TRUE /* Temp. register. */ -#define ASMREF_TMP2 REF_FALSE /* Temp. register. */ -#define ASMREF_L REF_NIL /* Stores register for L. */ - -/* Check for variant to invariant references. */ -#define iscrossref(as, ref) ((ref) < as->sectref) - -/* Inhibit memory op fusion from variant to invariant references. */ -#define FUSE_DISABLED (~(IRRef)0) -#define mayfuse(as, ref) ((ref) > as->fuseref) -#define neverfuse(as) (as->fuseref == FUSE_DISABLED) -#define canfuse(as, ir) (!neverfuse(as) && !irt_isphi((ir)->t)) -#define opisfusableload(o) \ - ((o) == IR_ALOAD || (o) == IR_HLOAD || (o) == IR_ULOAD || \ - (o) == IR_FLOAD || (o) == IR_XLOAD || (o) == IR_SLOAD || (o) == IR_VLOAD) - -/* Sparse limit checks using a red zone before the actual limit. */ -#define MCLIM_REDZONE 64 - -static LJ_NORET LJ_NOINLINE void asm_mclimit(ASMState *as) -{ - lj_mcode_limiterr(as->J, (size_t)(as->mctop - as->mcp + 4*MCLIM_REDZONE)); -} - -static LJ_AINLINE void checkmclim(ASMState *as) -{ -#ifdef LUA_USE_ASSERT - if (as->mcp + MCLIM_REDZONE < as->mcp_prev) { - IRIns *ir = IR(as->curins+1); - fprintf(stderr, "RED ZONE OVERFLOW: %p IR %04d %02d %04d %04d\n", as->mcp, - as->curins+1-REF_BIAS, ir->o, ir->op1-REF_BIAS, ir->op2-REF_BIAS); - lua_assert(0); - } -#endif - if (LJ_UNLIKELY(as->mcp < as->mclim)) asm_mclimit(as); -#ifdef LUA_USE_ASSERT - as->mcp_prev = as->mcp; -#endif -} - -#ifdef RID_NUM_KREF -#define ra_iskref(ref) ((ref) < RID_NUM_KREF) -#define ra_krefreg(ref) ((Reg)(RID_MIN_KREF + (Reg)(ref))) -#define ra_krefk(as, ref) (as->krefk[(ref)]) - -static LJ_AINLINE void ra_setkref(ASMState *as, Reg r, intptr_t k) -{ - IRRef ref = (IRRef)(r - RID_MIN_KREF); - as->krefk[ref] = k; - as->cost[r] = REGCOST(ref, ref); -} - -#else -#define ra_iskref(ref) 0 -#define ra_krefreg(ref) RID_MIN_GPR -#define ra_krefk(as, ref) 0 -#endif - -/* Arch-specific field offsets. */ -static const uint8_t field_ofs[IRFL__MAX+1] = { -#define FLOFS(name, ofs) (uint8_t)(ofs), -IRFLDEF(FLOFS) -#undef FLOFS - 0 -}; - -/* -- Target-specific instruction emitter --------------------------------- */ - -#if LJ_TARGET_X86ORX64 -#include "lj_emit_x86.h" -#elif LJ_TARGET_ARM -#include "lj_emit_arm.h" -#elif LJ_TARGET_ARM64 -#include "lj_emit_arm64.h" -#elif LJ_TARGET_PPC -#include "lj_emit_ppc.h" -#elif LJ_TARGET_MIPS -#include "lj_emit_mips.h" -#else -#error "Missing instruction emitter for target CPU" -#endif - -/* Generic load/store of register from/to stack slot. */ -#define emit_spload(as, ir, r, ofs) \ - emit_loadofs(as, ir, (r), RID_SP, (ofs)) -#define emit_spstore(as, ir, r, ofs) \ - emit_storeofs(as, ir, (r), RID_SP, (ofs)) - -/* -- Register allocator debugging ---------------------------------------- */ - -/* #define LUAJIT_DEBUG_RA */ - -#ifdef LUAJIT_DEBUG_RA - -#include -#include - -#define RIDNAME(name) #name, -static const char *const ra_regname[] = { - GPRDEF(RIDNAME) - FPRDEF(RIDNAME) - VRIDDEF(RIDNAME) - NULL -}; -#undef RIDNAME - -static char ra_dbg_buf[65536]; -static char *ra_dbg_p; -static char *ra_dbg_merge; -static MCode *ra_dbg_mcp; - -static void ra_dstart(void) -{ - ra_dbg_p = ra_dbg_buf; - ra_dbg_merge = NULL; - ra_dbg_mcp = NULL; -} - -static void ra_dflush(void) -{ - fwrite(ra_dbg_buf, 1, (size_t)(ra_dbg_p-ra_dbg_buf), stdout); - ra_dstart(); -} - -static void ra_dprintf(ASMState *as, const char *fmt, ...) -{ - char *p; - va_list argp; - va_start(argp, fmt); - p = ra_dbg_mcp == as->mcp ? ra_dbg_merge : ra_dbg_p; - ra_dbg_mcp = NULL; - p += sprintf(p, "%08x \e[36m%04d ", (uintptr_t)as->mcp, as->curins-REF_BIAS); - for (;;) { - const char *e = strchr(fmt, '$'); - if (e == NULL) break; - memcpy(p, fmt, (size_t)(e-fmt)); - p += e-fmt; - if (e[1] == 'r') { - Reg r = va_arg(argp, Reg) & RID_MASK; - if (r <= RID_MAX) { - const char *q; - for (q = ra_regname[r]; *q; q++) - *p++ = *q >= 'A' && *q <= 'Z' ? *q + 0x20 : *q; - } else { - *p++ = '?'; - lua_assert(0); - } - } else if (e[1] == 'f' || e[1] == 'i') { - IRRef ref; - if (e[1] == 'f') - ref = va_arg(argp, IRRef); - else - ref = va_arg(argp, IRIns *) - as->ir; - if (ref >= REF_BIAS) - p += sprintf(p, "%04d", ref - REF_BIAS); - else - p += sprintf(p, "K%03d", REF_BIAS - ref); - } else if (e[1] == 's') { - uint32_t slot = va_arg(argp, uint32_t); - p += sprintf(p, "[sp+0x%x]", sps_scale(slot)); - } else if (e[1] == 'x') { - p += sprintf(p, "%08x", va_arg(argp, int32_t)); - } else { - lua_assert(0); - } - fmt = e+2; - } - va_end(argp); - while (*fmt) - *p++ = *fmt++; - *p++ = '\e'; *p++ = '['; *p++ = 'm'; *p++ = '\n'; - if (p > ra_dbg_buf+sizeof(ra_dbg_buf)-256) { - fwrite(ra_dbg_buf, 1, (size_t)(p-ra_dbg_buf), stdout); - p = ra_dbg_buf; - } - ra_dbg_p = p; -} - -#define RA_DBG_START() ra_dstart() -#define RA_DBG_FLUSH() ra_dflush() -#define RA_DBG_REF() \ - do { char *_p = ra_dbg_p; ra_dprintf(as, ""); \ - ra_dbg_merge = _p; ra_dbg_mcp = as->mcp; } while (0) -#define RA_DBGX(x) ra_dprintf x - -#else -#define RA_DBG_START() ((void)0) -#define RA_DBG_FLUSH() ((void)0) -#define RA_DBG_REF() ((void)0) -#define RA_DBGX(x) ((void)0) -#endif - -/* -- Register allocator -------------------------------------------------- */ - -#define ra_free(as, r) rset_set(as->freeset, (r)) -#define ra_modified(as, r) rset_set(as->modset, (r)) -#define ra_weak(as, r) rset_set(as->weakset, (r)) -#define ra_noweak(as, r) rset_clear(as->weakset, (r)) - -#define ra_used(ir) (ra_hasreg((ir)->r) || ra_hasspill((ir)->s)) - -/* Setup register allocator. */ -static void ra_setup(ASMState *as) -{ - Reg r; - /* Initially all regs (except the stack pointer) are free for use. */ - as->freeset = RSET_INIT; - as->modset = RSET_EMPTY; - as->weakset = RSET_EMPTY; - as->phiset = RSET_EMPTY; - memset(as->phireg, 0, sizeof(as->phireg)); - for (r = RID_MIN_GPR; r < RID_MAX; r++) - as->cost[r] = REGCOST(~0u, 0u); -} - -/* Rematerialize constants. */ -static Reg ra_rematk(ASMState *as, IRRef ref) -{ - IRIns *ir; - Reg r; - if (ra_iskref(ref)) { - r = ra_krefreg(ref); - lua_assert(!rset_test(as->freeset, r)); - ra_free(as, r); - ra_modified(as, r); -#if LJ_64 - emit_loadu64(as, r, ra_krefk(as, ref)); -#else - emit_loadi(as, r, ra_krefk(as, ref)); -#endif - return r; - } - ir = IR(ref); - r = ir->r; - lua_assert(ra_hasreg(r) && !ra_hasspill(ir->s)); - ra_free(as, r); - ra_modified(as, r); - ir->r = RID_INIT; /* Do not keep any hint. */ - RA_DBGX((as, "remat $i $r", ir, r)); -#if !LJ_SOFTFP32 - if (ir->o == IR_KNUM) { - emit_loadk64(as, r, ir); - } else -#endif - if (emit_canremat(REF_BASE) && ir->o == IR_BASE) { - ra_sethint(ir->r, RID_BASE); /* Restore BASE register hint. */ - emit_getgl(as, r, jit_base); - } else if (emit_canremat(ASMREF_L) && ir->o == IR_KPRI) { - lua_assert(irt_isnil(ir->t)); /* REF_NIL stores ASMREF_L register. */ - emit_getgl(as, r, cur_L); -#if LJ_64 - } else if (ir->o == IR_KINT64) { - emit_loadu64(as, r, ir_kint64(ir)->u64); -#if LJ_GC64 - } else if (ir->o == IR_KGC) { - emit_loadu64(as, r, (uintptr_t)ir_kgc(ir)); - } else if (ir->o == IR_KPTR || ir->o == IR_KKPTR) { - emit_loadu64(as, r, (uintptr_t)ir_kptr(ir)); -#endif -#endif - } else { - lua_assert(ir->o == IR_KINT || ir->o == IR_KGC || - ir->o == IR_KPTR || ir->o == IR_KKPTR || ir->o == IR_KNULL); - emit_loadi(as, r, ir->i); - } - return r; -} - -/* Force a spill. Allocate a new spill slot if needed. */ -static int32_t ra_spill(ASMState *as, IRIns *ir) -{ - int32_t slot = ir->s; - lua_assert(ir >= as->ir + REF_TRUE); - if (!ra_hasspill(slot)) { - if (irt_is64(ir->t)) { - slot = as->evenspill; - as->evenspill += 2; - } else if (as->oddspill) { - slot = as->oddspill; - as->oddspill = 0; - } else { - slot = as->evenspill; - as->oddspill = slot+1; - as->evenspill += 2; - } - if (as->evenspill > 256) - lj_trace_err(as->J, LJ_TRERR_SPILLOV); - ir->s = (uint8_t)slot; - } - return sps_scale(slot); -} - -/* Release the temporarily allocated register in ASMREF_TMP1/ASMREF_TMP2. */ -static Reg ra_releasetmp(ASMState *as, IRRef ref) -{ - IRIns *ir = IR(ref); - Reg r = ir->r; - lua_assert(ra_hasreg(r) && !ra_hasspill(ir->s)); - ra_free(as, r); - ra_modified(as, r); - ir->r = RID_INIT; - return r; -} - -/* Restore a register (marked as free). Rematerialize or force a spill. */ -static Reg ra_restore(ASMState *as, IRRef ref) -{ - if (emit_canremat(ref)) { - return ra_rematk(as, ref); - } else { - IRIns *ir = IR(ref); - int32_t ofs = ra_spill(as, ir); /* Force a spill slot. */ - Reg r = ir->r; - lua_assert(ra_hasreg(r)); - ra_sethint(ir->r, r); /* Keep hint. */ - ra_free(as, r); - if (!rset_test(as->weakset, r)) { /* Only restore non-weak references. */ - ra_modified(as, r); - RA_DBGX((as, "restore $i $r", ir, r)); - emit_spload(as, ir, r, ofs); - } - return r; - } -} - -/* Save a register to a spill slot. */ -static void ra_save(ASMState *as, IRIns *ir, Reg r) -{ - RA_DBGX((as, "save $i $r", ir, r)); - emit_spstore(as, ir, r, sps_scale(ir->s)); -} - -#define MINCOST(name) \ - if (rset_test(RSET_ALL, RID_##name) && \ - LJ_LIKELY(allow&RID2RSET(RID_##name)) && as->cost[RID_##name] < cost) \ - cost = as->cost[RID_##name]; - -/* Evict the register with the lowest cost, forcing a restore. */ -static Reg ra_evict(ASMState *as, RegSet allow) -{ - IRRef ref; - RegCost cost = ~(RegCost)0; - lua_assert(allow != RSET_EMPTY); - if (RID_NUM_FPR == 0 || allow < RID2RSET(RID_MAX_GPR)) { - GPRDEF(MINCOST) - } else { - FPRDEF(MINCOST) - } - ref = regcost_ref(cost); - lua_assert(ra_iskref(ref) || (ref >= as->T->nk && ref < as->T->nins)); - /* Preferably pick any weak ref instead of a non-weak, non-const ref. */ - if (!irref_isk(ref) && (as->weakset & allow)) { - IRIns *ir = IR(ref); - if (!rset_test(as->weakset, ir->r)) - ref = regcost_ref(as->cost[rset_pickbot((as->weakset & allow))]); - } - return ra_restore(as, ref); -} - -/* Pick any register (marked as free). Evict on-demand. */ -static Reg ra_pick(ASMState *as, RegSet allow) -{ - RegSet pick = as->freeset & allow; - if (!pick) - return ra_evict(as, allow); - else - return rset_picktop(pick); -} - -/* Get a scratch register (marked as free). */ -static Reg ra_scratch(ASMState *as, RegSet allow) -{ - Reg r = ra_pick(as, allow); - ra_modified(as, r); - RA_DBGX((as, "scratch $r", r)); - return r; -} - -/* Evict all registers from a set (if not free). */ -static void ra_evictset(ASMState *as, RegSet drop) -{ - RegSet work; - as->modset |= drop; -#if !LJ_SOFTFP - work = (drop & ~as->freeset) & RSET_FPR; - while (work) { - Reg r = rset_pickbot(work); - ra_restore(as, regcost_ref(as->cost[r])); - rset_clear(work, r); - checkmclim(as); - } -#endif - work = (drop & ~as->freeset); - while (work) { - Reg r = rset_pickbot(work); - ra_restore(as, regcost_ref(as->cost[r])); - rset_clear(work, r); - checkmclim(as); - } -} - -/* Evict (rematerialize) all registers allocated to constants. */ -static void ra_evictk(ASMState *as) -{ - RegSet work; -#if !LJ_SOFTFP - work = ~as->freeset & RSET_FPR; - while (work) { - Reg r = rset_pickbot(work); - IRRef ref = regcost_ref(as->cost[r]); - if (emit_canremat(ref) && irref_isk(ref)) { - ra_rematk(as, ref); - checkmclim(as); - } - rset_clear(work, r); - } -#endif - work = ~as->freeset & RSET_GPR; - while (work) { - Reg r = rset_pickbot(work); - IRRef ref = regcost_ref(as->cost[r]); - if (emit_canremat(ref) && irref_isk(ref)) { - ra_rematk(as, ref); - checkmclim(as); - } - rset_clear(work, r); - } -} - -#ifdef RID_NUM_KREF -/* Allocate a register for a constant. */ -static Reg ra_allock(ASMState *as, intptr_t k, RegSet allow) -{ - /* First try to find a register which already holds the same constant. */ - RegSet pick, work = ~as->freeset & RSET_GPR; - Reg r; - while (work) { - IRRef ref; - r = rset_pickbot(work); - ref = regcost_ref(as->cost[r]); -#if LJ_64 - if (ref < ASMREF_L) { - if (ra_iskref(ref)) { - if (k == ra_krefk(as, ref)) - return r; - } else { - IRIns *ir = IR(ref); - if ((ir->o == IR_KINT64 && k == (int64_t)ir_kint64(ir)->u64) || -#if LJ_GC64 - (ir->o == IR_KINT && k == ir->i) || - (ir->o == IR_KGC && k == (intptr_t)ir_kgc(ir)) || - ((ir->o == IR_KPTR || ir->o == IR_KKPTR) && - k == (intptr_t)ir_kptr(ir)) -#else - (ir->o != IR_KINT64 && k == ir->i) -#endif - ) - return r; - } - } -#else - if (ref < ASMREF_L && - k == (ra_iskref(ref) ? ra_krefk(as, ref) : IR(ref)->i)) - return r; -#endif - rset_clear(work, r); - } - pick = as->freeset & allow; - if (pick) { - /* Constants should preferably get unmodified registers. */ - if ((pick & ~as->modset)) - pick &= ~as->modset; - r = rset_pickbot(pick); /* Reduce conflicts with inverse allocation. */ - } else { - r = ra_evict(as, allow); - } - RA_DBGX((as, "allock $x $r", k, r)); - ra_setkref(as, r, k); - rset_clear(as->freeset, r); - ra_noweak(as, r); - return r; -} - -/* Allocate a specific register for a constant. */ -static void ra_allockreg(ASMState *as, intptr_t k, Reg r) -{ - Reg kr = ra_allock(as, k, RID2RSET(r)); - if (kr != r) { - IRIns irdummy; - irdummy.t.irt = IRT_INT; - ra_scratch(as, RID2RSET(r)); - emit_movrr(as, &irdummy, r, kr); - } -} -#else -#define ra_allockreg(as, k, r) emit_loadi(as, (r), (k)) -#endif - -/* Allocate a register for ref from the allowed set of registers. -** Note: this function assumes the ref does NOT have a register yet! -** Picks an optimal register, sets the cost and marks the register as non-free. -*/ -static Reg ra_allocref(ASMState *as, IRRef ref, RegSet allow) -{ - IRIns *ir = IR(ref); - RegSet pick = as->freeset & allow; - Reg r; - lua_assert(ra_noreg(ir->r)); - if (pick) { - /* First check register hint from propagation or PHI. */ - if (ra_hashint(ir->r)) { - r = ra_gethint(ir->r); - if (rset_test(pick, r)) /* Use hint register if possible. */ - goto found; - /* Rematerialization is cheaper than missing a hint. */ - if (rset_test(allow, r) && emit_canremat(regcost_ref(as->cost[r]))) { - ra_rematk(as, regcost_ref(as->cost[r])); - goto found; - } - RA_DBGX((as, "hintmiss $f $r", ref, r)); - } - /* Invariants should preferably get unmodified registers. */ - if (ref < as->loopref && !irt_isphi(ir->t)) { - if ((pick & ~as->modset)) - pick &= ~as->modset; - r = rset_pickbot(pick); /* Reduce conflicts with inverse allocation. */ - } else { - /* We've got plenty of regs, so get callee-save regs if possible. */ - if (RID_NUM_GPR > 8 && (pick & ~RSET_SCRATCH)) - pick &= ~RSET_SCRATCH; - r = rset_picktop(pick); - } - } else { - r = ra_evict(as, allow); - } -found: - RA_DBGX((as, "alloc $f $r", ref, r)); - ir->r = (uint8_t)r; - rset_clear(as->freeset, r); - ra_noweak(as, r); - as->cost[r] = REGCOST_REF_T(ref, irt_t(ir->t)); - return r; -} - -/* Allocate a register on-demand. */ -static Reg ra_alloc1(ASMState *as, IRRef ref, RegSet allow) -{ - Reg r = IR(ref)->r; - /* Note: allow is ignored if the register is already allocated. */ - if (ra_noreg(r)) r = ra_allocref(as, ref, allow); - ra_noweak(as, r); - return r; -} - -/* Add a register rename to the IR. */ -static void ra_addrename(ASMState *as, Reg down, IRRef ref, SnapNo snapno) -{ - IRRef ren; - lj_ir_set(as->J, IRT(IR_RENAME, IRT_NIL), ref, snapno); - ren = tref_ref(lj_ir_emit(as->J)); - as->J->cur.ir[ren].r = (uint8_t)down; - as->J->cur.ir[ren].s = SPS_NONE; -} - -/* Rename register allocation and emit move. */ -static void ra_rename(ASMState *as, Reg down, Reg up) -{ - IRRef ref = regcost_ref(as->cost[up] = as->cost[down]); - IRIns *ir = IR(ref); - ir->r = (uint8_t)up; - as->cost[down] = 0; - lua_assert((down < RID_MAX_GPR) == (up < RID_MAX_GPR)); - lua_assert(!rset_test(as->freeset, down) && rset_test(as->freeset, up)); - ra_free(as, down); /* 'down' is free ... */ - ra_modified(as, down); - rset_clear(as->freeset, up); /* ... and 'up' is now allocated. */ - ra_noweak(as, up); - RA_DBGX((as, "rename $f $r $r", regcost_ref(as->cost[up]), down, up)); - emit_movrr(as, ir, down, up); /* Backwards codegen needs inverse move. */ - if (!ra_hasspill(IR(ref)->s)) { /* Add the rename to the IR. */ - ra_addrename(as, down, ref, as->snapno); - } -} - -/* Pick a destination register (marked as free). -** Caveat: allow is ignored if there's already a destination register. -** Use ra_destreg() to get a specific register. -*/ -static Reg ra_dest(ASMState *as, IRIns *ir, RegSet allow) -{ - Reg dest = ir->r; - if (ra_hasreg(dest)) { - ra_free(as, dest); - ra_modified(as, dest); - } else { - if (ra_hashint(dest) && rset_test((as->freeset&allow), ra_gethint(dest))) { - dest = ra_gethint(dest); - ra_modified(as, dest); - RA_DBGX((as, "dest $r", dest)); - } else { - dest = ra_scratch(as, allow); - } - ir->r = dest; - } - if (LJ_UNLIKELY(ra_hasspill(ir->s))) ra_save(as, ir, dest); - return dest; -} - -/* Force a specific destination register (marked as free). */ -static void ra_destreg(ASMState *as, IRIns *ir, Reg r) -{ - Reg dest = ra_dest(as, ir, RID2RSET(r)); - if (dest != r) { - lua_assert(rset_test(as->freeset, r)); - ra_modified(as, r); - emit_movrr(as, ir, dest, r); - } -} - -#if LJ_TARGET_X86ORX64 -/* Propagate dest register to left reference. Emit moves as needed. -** This is a required fixup step for all 2-operand machine instructions. -*/ -static void ra_left(ASMState *as, Reg dest, IRRef lref) -{ - IRIns *ir = IR(lref); - Reg left = ir->r; - if (ra_noreg(left)) { - if (irref_isk(lref)) { - if (ir->o == IR_KNUM) { - /* FP remat needs a load except for +0. Still better than eviction. */ - if (tvispzero(ir_knum(ir)) || !(as->freeset & RSET_FPR)) { - emit_loadk64(as, dest, ir); - return; - } -#if LJ_64 - } else if (ir->o == IR_KINT64) { - emit_loadk64(as, dest, ir); - return; -#if LJ_GC64 - } else if (ir->o == IR_KGC || ir->o == IR_KPTR || ir->o == IR_KKPTR) { - emit_loadk64(as, dest, ir); - return; -#endif -#endif - } else if (ir->o != IR_KPRI) { - lua_assert(ir->o == IR_KINT || ir->o == IR_KGC || - ir->o == IR_KPTR || ir->o == IR_KKPTR || ir->o == IR_KNULL); - emit_loadi(as, dest, ir->i); - return; - } - } - if (!ra_hashint(left) && !iscrossref(as, lref)) - ra_sethint(ir->r, dest); /* Propagate register hint. */ - left = ra_allocref(as, lref, dest < RID_MAX_GPR ? RSET_GPR : RSET_FPR); - } - ra_noweak(as, left); - /* Move needed for true 3-operand instruction: y=a+b ==> y=a; y+=b. */ - if (dest != left) { - /* Use register renaming if dest is the PHI reg. */ - if (irt_isphi(ir->t) && as->phireg[dest] == lref) { - ra_modified(as, left); - ra_rename(as, left, dest); - } else { - emit_movrr(as, ir, dest, left); - } - } -} -#else -/* Similar to ra_left, except we override any hints. */ -static void ra_leftov(ASMState *as, Reg dest, IRRef lref) -{ - IRIns *ir = IR(lref); - Reg left = ir->r; - if (ra_noreg(left)) { - ra_sethint(ir->r, dest); /* Propagate register hint. */ - left = ra_allocref(as, lref, - (LJ_SOFTFP || dest < RID_MAX_GPR) ? RSET_GPR : RSET_FPR); - } - ra_noweak(as, left); - if (dest != left) { - /* Use register renaming if dest is the PHI reg. */ - if (irt_isphi(ir->t) && as->phireg[dest] == lref) { - ra_modified(as, left); - ra_rename(as, left, dest); - } else { - emit_movrr(as, ir, dest, left); - } - } -} -#endif - -#if !LJ_64 -/* Force a RID_RETLO/RID_RETHI destination register pair (marked as free). */ -static void ra_destpair(ASMState *as, IRIns *ir) -{ - Reg destlo = ir->r, desthi = (ir+1)->r; - /* First spill unrelated refs blocking the destination registers. */ - if (!rset_test(as->freeset, RID_RETLO) && - destlo != RID_RETLO && desthi != RID_RETLO) - ra_restore(as, regcost_ref(as->cost[RID_RETLO])); - if (!rset_test(as->freeset, RID_RETHI) && - destlo != RID_RETHI && desthi != RID_RETHI) - ra_restore(as, regcost_ref(as->cost[RID_RETHI])); - /* Next free the destination registers (if any). */ - if (ra_hasreg(destlo)) { - ra_free(as, destlo); - ra_modified(as, destlo); - } else { - destlo = RID_RETLO; - } - if (ra_hasreg(desthi)) { - ra_free(as, desthi); - ra_modified(as, desthi); - } else { - desthi = RID_RETHI; - } - /* Check for conflicts and shuffle the registers as needed. */ - if (destlo == RID_RETHI) { - if (desthi == RID_RETLO) { -#if LJ_TARGET_X86 - *--as->mcp = XI_XCHGa + RID_RETHI; -#else - emit_movrr(as, ir, RID_RETHI, RID_TMP); - emit_movrr(as, ir, RID_RETLO, RID_RETHI); - emit_movrr(as, ir, RID_TMP, RID_RETLO); -#endif - } else { - emit_movrr(as, ir, RID_RETHI, RID_RETLO); - if (desthi != RID_RETHI) emit_movrr(as, ir, desthi, RID_RETHI); - } - } else if (desthi == RID_RETLO) { - emit_movrr(as, ir, RID_RETLO, RID_RETHI); - if (destlo != RID_RETLO) emit_movrr(as, ir, destlo, RID_RETLO); - } else { - if (desthi != RID_RETHI) emit_movrr(as, ir, desthi, RID_RETHI); - if (destlo != RID_RETLO) emit_movrr(as, ir, destlo, RID_RETLO); - } - /* Restore spill slots (if any). */ - if (ra_hasspill((ir+1)->s)) ra_save(as, ir+1, RID_RETHI); - if (ra_hasspill(ir->s)) ra_save(as, ir, RID_RETLO); -} -#endif - -/* -- Snapshot handling --------- ----------------------------------------- */ - -/* Can we rematerialize a KNUM instead of forcing a spill? */ -static int asm_snap_canremat(ASMState *as) -{ - Reg r; - for (r = RID_MIN_FPR; r < RID_MAX_FPR; r++) - if (irref_isk(regcost_ref(as->cost[r]))) - return 1; - return 0; -} - -/* Check whether a sunk store corresponds to an allocation. */ -static int asm_sunk_store(ASMState *as, IRIns *ira, IRIns *irs) -{ - if (irs->s == 255) { - if (irs->o == IR_ASTORE || irs->o == IR_HSTORE || - irs->o == IR_FSTORE || irs->o == IR_XSTORE) { - IRIns *irk = IR(irs->op1); - if (irk->o == IR_AREF || irk->o == IR_HREFK) - irk = IR(irk->op1); - return (IR(irk->op1) == ira); - } - return 0; - } else { - return (ira + irs->s == irs); /* Quick check. */ - } -} - -/* Allocate register or spill slot for a ref that escapes to a snapshot. */ -static void asm_snap_alloc1(ASMState *as, IRRef ref) -{ - IRIns *ir = IR(ref); - if (!irref_isk(ref) && (!(ra_used(ir) || ir->r == RID_SUNK))) { - if (ir->r == RID_SINK) { - ir->r = RID_SUNK; -#if LJ_HASFFI - if (ir->o == IR_CNEWI) { /* Allocate CNEWI value. */ - asm_snap_alloc1(as, ir->op2); - if (LJ_32 && (ir+1)->o == IR_HIOP) - asm_snap_alloc1(as, (ir+1)->op2); - } else -#endif - { /* Allocate stored values for TNEW, TDUP and CNEW. */ - IRIns *irs; - lua_assert(ir->o == IR_TNEW || ir->o == IR_TDUP || ir->o == IR_CNEW); - for (irs = IR(as->snapref-1); irs > ir; irs--) - if (irs->r == RID_SINK && asm_sunk_store(as, ir, irs)) { - lua_assert(irs->o == IR_ASTORE || irs->o == IR_HSTORE || - irs->o == IR_FSTORE || irs->o == IR_XSTORE); - asm_snap_alloc1(as, irs->op2); - if (LJ_32 && (irs+1)->o == IR_HIOP) - asm_snap_alloc1(as, (irs+1)->op2); - } - } - } else { - RegSet allow; - if (ir->o == IR_CONV && ir->op2 == IRCONV_NUM_INT) { - IRIns *irc; - for (irc = IR(as->curins); irc > ir; irc--) - if ((irc->op1 == ref || irc->op2 == ref) && - !(irc->r == RID_SINK || irc->r == RID_SUNK)) - goto nosink; /* Don't sink conversion if result is used. */ - asm_snap_alloc1(as, ir->op1); - return; - } - nosink: - allow = (!LJ_SOFTFP && irt_isfp(ir->t)) ? RSET_FPR : RSET_GPR; - if ((as->freeset & allow) || - (allow == RSET_FPR && asm_snap_canremat(as))) { - /* Get a weak register if we have a free one or can rematerialize. */ - Reg r = ra_allocref(as, ref, allow); /* Allocate a register. */ - if (!irt_isphi(ir->t)) - ra_weak(as, r); /* But mark it as weakly referenced. */ - checkmclim(as); - RA_DBGX((as, "snapreg $f $r", ref, ir->r)); - } else { - ra_spill(as, ir); /* Otherwise force a spill slot. */ - RA_DBGX((as, "snapspill $f $s", ref, ir->s)); - } - } - } -} - -/* Allocate refs escaping to a snapshot. */ -static void asm_snap_alloc(ASMState *as) -{ - SnapShot *snap = &as->T->snap[as->snapno]; - SnapEntry *map = &as->T->snapmap[snap->mapofs]; - MSize n, nent = snap->nent; - for (n = 0; n < nent; n++) { - SnapEntry sn = map[n]; - IRRef ref = snap_ref(sn); - if (!irref_isk(ref)) { - asm_snap_alloc1(as, ref); - if (LJ_SOFTFP && (sn & SNAP_SOFTFPNUM)) { - lua_assert(irt_type(IR(ref+1)->t) == IRT_SOFTFP); - asm_snap_alloc1(as, ref+1); - } - } - } -} - -/* All guards for a snapshot use the same exitno. This is currently the -** same as the snapshot number. Since the exact origin of the exit cannot -** be determined, all guards for the same snapshot must exit with the same -** RegSP mapping. -** A renamed ref which has been used in a prior guard for the same snapshot -** would cause an inconsistency. The easy way out is to force a spill slot. -*/ -static int asm_snap_checkrename(ASMState *as, IRRef ren) -{ - SnapShot *snap = &as->T->snap[as->snapno]; - SnapEntry *map = &as->T->snapmap[snap->mapofs]; - MSize n, nent = snap->nent; - for (n = 0; n < nent; n++) { - SnapEntry sn = map[n]; - IRRef ref = snap_ref(sn); - if (ref == ren || (LJ_SOFTFP && (sn & SNAP_SOFTFPNUM) && ++ref == ren)) { - IRIns *ir = IR(ref); - ra_spill(as, ir); /* Register renamed, so force a spill slot. */ - RA_DBGX((as, "snaprensp $f $s", ref, ir->s)); - return 1; /* Found. */ - } - } - return 0; /* Not found. */ -} - -/* Prepare snapshot for next guard instruction. */ -static void asm_snap_prep(ASMState *as) -{ - if (as->curins < as->snapref) { - do { - if (as->snapno == 0) return; /* Called by sunk stores before snap #0. */ - as->snapno--; - as->snapref = as->T->snap[as->snapno].ref; - } while (as->curins < as->snapref); - asm_snap_alloc(as); - as->snaprename = as->T->nins; - } else { - /* Process any renames above the highwater mark. */ - for (; as->snaprename < as->T->nins; as->snaprename++) { - IRIns *ir = &as->T->ir[as->snaprename]; - if (asm_snap_checkrename(as, ir->op1)) - ir->op2 = REF_BIAS-1; /* Kill rename. */ - } - } -} - -/* -- Miscellaneous helpers ----------------------------------------------- */ - -/* Calculate stack adjustment. */ -static int32_t asm_stack_adjust(ASMState *as) -{ - if (as->evenspill <= SPS_FIXED) - return 0; - return sps_scale(sps_align(as->evenspill)); -} - -/* Must match with hash*() in lj_tab.c. */ -static uint32_t ir_khash(IRIns *ir) -{ - uint32_t lo, hi; - if (irt_isstr(ir->t)) { - return ir_kstr(ir)->hash; - } else if (irt_isnum(ir->t)) { - lo = ir_knum(ir)->u32.lo; - hi = ir_knum(ir)->u32.hi << 1; - } else if (irt_ispri(ir->t)) { - lua_assert(!irt_isnil(ir->t)); - return irt_type(ir->t)-IRT_FALSE; - } else { - lua_assert(irt_isgcv(ir->t)); - lo = u32ptr(ir_kgc(ir)); -#if LJ_GC64 - hi = (uint32_t)(u64ptr(ir_kgc(ir)) >> 32) | (irt_toitype(ir->t) << 15); -#else - hi = lo + HASH_BIAS; -#endif - } - return hashrot(lo, hi); -} - -/* -- Allocations --------------------------------------------------------- */ - -static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args); -static void asm_setupresult(ASMState *as, IRIns *ir, const CCallInfo *ci); - -static void asm_snew(ASMState *as, IRIns *ir) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_str_new]; - IRRef args[3]; - args[0] = ASMREF_L; /* lua_State *L */ - args[1] = ir->op1; /* const char *str */ - args[2] = ir->op2; /* size_t len */ - as->gcsteps++; - asm_setupresult(as, ir, ci); /* GCstr * */ - asm_gencall(as, ci, args); -} - -static void asm_tnew(ASMState *as, IRIns *ir) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_tab_new1]; - IRRef args[2]; - args[0] = ASMREF_L; /* lua_State *L */ - args[1] = ASMREF_TMP1; /* uint32_t ahsize */ - as->gcsteps++; - asm_setupresult(as, ir, ci); /* GCtab * */ - asm_gencall(as, ci, args); - ra_allockreg(as, ir->op1 | (ir->op2 << 24), ra_releasetmp(as, ASMREF_TMP1)); -} - -static void asm_tdup(ASMState *as, IRIns *ir) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_tab_dup]; - IRRef args[2]; - args[0] = ASMREF_L; /* lua_State *L */ - args[1] = ir->op1; /* const GCtab *kt */ - as->gcsteps++; - asm_setupresult(as, ir, ci); /* GCtab * */ - asm_gencall(as, ci, args); -} - -static void asm_gc_check(ASMState *as); - -/* Explicit GC step. */ -static void asm_gcstep(ASMState *as, IRIns *ir) -{ - IRIns *ira; - for (ira = IR(as->stopins+1); ira < ir; ira++) - if ((ira->o == IR_TNEW || ira->o == IR_TDUP || - (LJ_HASFFI && (ira->o == IR_CNEW || ira->o == IR_CNEWI))) && - ra_used(ira)) - as->gcsteps++; - if (as->gcsteps) - asm_gc_check(as); - as->gcsteps = 0x80000000; /* Prevent implicit GC check further up. */ -} - -/* -- Buffer operations --------------------------------------------------- */ - -static void asm_tvptr(ASMState *as, Reg dest, IRRef ref); - -static void asm_bufhdr(ASMState *as, IRIns *ir) -{ - Reg sb = ra_dest(as, ir, RSET_GPR); - if ((ir->op2 & IRBUFHDR_APPEND)) { - /* Rematerialize const buffer pointer instead of likely spill. */ - IRIns *irp = IR(ir->op1); - if (!(ra_hasreg(irp->r) || irp == ir-1 || - (irp == ir-2 && !ra_used(ir-1)))) { - while (!(irp->o == IR_BUFHDR && !(irp->op2 & IRBUFHDR_APPEND))) - irp = IR(irp->op1); - if (irref_isk(irp->op1)) { - ra_weak(as, ra_allocref(as, ir->op1, RSET_GPR)); - ir = irp; - } - } - } else { - Reg tmp = ra_scratch(as, rset_exclude(RSET_GPR, sb)); - /* Passing ir isn't strictly correct, but it's an IRT_PGC, too. */ - emit_storeofs(as, ir, tmp, sb, offsetof(SBuf, p)); - emit_loadofs(as, ir, tmp, sb, offsetof(SBuf, b)); - } -#if LJ_TARGET_X86ORX64 - ra_left(as, sb, ir->op1); -#else - ra_leftov(as, sb, ir->op1); -#endif -} - -static void asm_bufput(ASMState *as, IRIns *ir) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_buf_putstr]; - IRRef args[3]; - IRIns *irs; - int kchar = -129; - args[0] = ir->op1; /* SBuf * */ - args[1] = ir->op2; /* GCstr * */ - irs = IR(ir->op2); - lua_assert(irt_isstr(irs->t)); - if (irs->o == IR_KGC) { - GCstr *s = ir_kstr(irs); - if (s->len == 1) { /* Optimize put of single-char string constant. */ - kchar = (int8_t)strdata(s)[0]; /* Signed! */ - args[1] = ASMREF_TMP1; /* int, truncated to char */ - ci = &lj_ir_callinfo[IRCALL_lj_buf_putchar]; - } - } else if (mayfuse(as, ir->op2) && ra_noreg(irs->r)) { - if (irs->o == IR_TOSTR) { /* Fuse number to string conversions. */ - if (irs->op2 == IRTOSTR_NUM) { - args[1] = ASMREF_TMP1; /* TValue * */ - ci = &lj_ir_callinfo[IRCALL_lj_strfmt_putnum]; - } else { - lua_assert(irt_isinteger(IR(irs->op1)->t)); - args[1] = irs->op1; /* int */ - if (irs->op2 == IRTOSTR_INT) - ci = &lj_ir_callinfo[IRCALL_lj_strfmt_putint]; - else - ci = &lj_ir_callinfo[IRCALL_lj_buf_putchar]; - } - } else if (irs->o == IR_SNEW) { /* Fuse string allocation. */ - args[1] = irs->op1; /* const void * */ - args[2] = irs->op2; /* MSize */ - ci = &lj_ir_callinfo[IRCALL_lj_buf_putmem]; - } - } - asm_setupresult(as, ir, ci); /* SBuf * */ - asm_gencall(as, ci, args); - if (args[1] == ASMREF_TMP1) { - Reg tmp = ra_releasetmp(as, ASMREF_TMP1); - if (kchar == -129) - asm_tvptr(as, tmp, irs->op1); - else - ra_allockreg(as, kchar, tmp); - } -} - -static void asm_bufstr(ASMState *as, IRIns *ir) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_buf_tostr]; - IRRef args[1]; - args[0] = ir->op1; /* SBuf *sb */ - as->gcsteps++; - asm_setupresult(as, ir, ci); /* GCstr * */ - asm_gencall(as, ci, args); -} - -/* -- Type conversions ---------------------------------------------------- */ - -static void asm_tostr(ASMState *as, IRIns *ir) -{ - const CCallInfo *ci; - IRRef args[2]; - args[0] = ASMREF_L; - as->gcsteps++; - if (ir->op2 == IRTOSTR_NUM) { - args[1] = ASMREF_TMP1; /* cTValue * */ - ci = &lj_ir_callinfo[IRCALL_lj_strfmt_num]; - } else { - args[1] = ir->op1; /* int32_t k */ - if (ir->op2 == IRTOSTR_INT) - ci = &lj_ir_callinfo[IRCALL_lj_strfmt_int]; - else - ci = &lj_ir_callinfo[IRCALL_lj_strfmt_char]; - } - asm_setupresult(as, ir, ci); /* GCstr * */ - asm_gencall(as, ci, args); - if (ir->op2 == IRTOSTR_NUM) - asm_tvptr(as, ra_releasetmp(as, ASMREF_TMP1), ir->op1); -} - -#if LJ_32 && LJ_HASFFI && !LJ_SOFTFP && !LJ_TARGET_X86 -static void asm_conv64(ASMState *as, IRIns *ir) -{ - IRType st = (IRType)((ir-1)->op2 & IRCONV_SRCMASK); - IRType dt = (((ir-1)->op2 & IRCONV_DSTMASK) >> IRCONV_DSH); - IRCallID id; - IRRef args[2]; - lua_assert((ir-1)->o == IR_CONV && ir->o == IR_HIOP); - args[LJ_BE] = (ir-1)->op1; - args[LJ_LE] = ir->op1; - if (st == IRT_NUM || st == IRT_FLOAT) { - id = IRCALL_fp64_d2l + ((st == IRT_FLOAT) ? 2 : 0) + (dt - IRT_I64); - ir--; - } else { - id = IRCALL_fp64_l2d + ((dt == IRT_FLOAT) ? 2 : 0) + (st - IRT_I64); - } - { -#if LJ_TARGET_ARM && !LJ_ABI_SOFTFP - CCallInfo cim = lj_ir_callinfo[id], *ci = &cim; - cim.flags |= CCI_VARARG; /* These calls don't use the hard-float ABI! */ -#else - const CCallInfo *ci = &lj_ir_callinfo[id]; -#endif - asm_setupresult(as, ir, ci); - asm_gencall(as, ci, args); - } -} -#endif - -/* -- Memory references --------------------------------------------------- */ - -static void asm_newref(ASMState *as, IRIns *ir) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_tab_newkey]; - IRRef args[3]; - if (ir->r == RID_SINK) - return; - args[0] = ASMREF_L; /* lua_State *L */ - args[1] = ir->op1; /* GCtab *t */ - args[2] = ASMREF_TMP1; /* cTValue *key */ - asm_setupresult(as, ir, ci); /* TValue * */ - asm_gencall(as, ci, args); - asm_tvptr(as, ra_releasetmp(as, ASMREF_TMP1), ir->op2); -} - -static void asm_lref(ASMState *as, IRIns *ir) -{ - Reg r = ra_dest(as, ir, RSET_GPR); -#if LJ_TARGET_X86ORX64 - ra_left(as, r, ASMREF_L); -#else - ra_leftov(as, r, ASMREF_L); -#endif -} - -/* -- Calls --------------------------------------------------------------- */ - -/* Collect arguments from CALL* and CARG instructions. */ -static void asm_collectargs(ASMState *as, IRIns *ir, - const CCallInfo *ci, IRRef *args) -{ - uint32_t n = CCI_XNARGS(ci); - lua_assert(n <= CCI_NARGS_MAX*2); /* Account for split args. */ - if ((ci->flags & CCI_L)) { *args++ = ASMREF_L; n--; } - while (n-- > 1) { - ir = IR(ir->op1); - lua_assert(ir->o == IR_CARG); - args[n] = ir->op2 == REF_NIL ? 0 : ir->op2; - } - args[0] = ir->op1 == REF_NIL ? 0 : ir->op1; - lua_assert(IR(ir->op1)->o != IR_CARG); -} - -/* Reconstruct CCallInfo flags for CALLX*. */ -static uint32_t asm_callx_flags(ASMState *as, IRIns *ir) -{ - uint32_t nargs = 0; - if (ir->op1 != REF_NIL) { /* Count number of arguments first. */ - IRIns *ira = IR(ir->op1); - nargs++; - while (ira->o == IR_CARG) { nargs++; ira = IR(ira->op1); } - } -#if LJ_HASFFI - if (IR(ir->op2)->o == IR_CARG) { /* Copy calling convention info. */ - CTypeID id = (CTypeID)IR(IR(ir->op2)->op2)->i; - CType *ct = ctype_get(ctype_ctsG(J2G(as->J)), id); - nargs |= ((ct->info & CTF_VARARG) ? CCI_VARARG : 0); -#if LJ_TARGET_X86 - nargs |= (ctype_cconv(ct->info) << CCI_CC_SHIFT); -#endif - } -#endif - return (nargs | (ir->t.irt << CCI_OTSHIFT)); -} - -static void asm_callid(ASMState *as, IRIns *ir, IRCallID id) -{ - const CCallInfo *ci = &lj_ir_callinfo[id]; - IRRef args[2]; - args[0] = ir->op1; - args[1] = ir->op2; - asm_setupresult(as, ir, ci); - asm_gencall(as, ci, args); -} - -static void asm_call(ASMState *as, IRIns *ir) -{ - IRRef args[CCI_NARGS_MAX]; - const CCallInfo *ci = &lj_ir_callinfo[ir->op2]; - asm_collectargs(as, ir, ci, args); - asm_setupresult(as, ir, ci); - asm_gencall(as, ci, args); -} - -#if !LJ_SOFTFP32 -static void asm_fppow(ASMState *as, IRIns *ir, IRRef lref, IRRef rref) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_pow]; - IRRef args[2]; - args[0] = lref; - args[1] = rref; - asm_setupresult(as, ir, ci); - asm_gencall(as, ci, args); -} - -static int asm_fpjoin_pow(ASMState *as, IRIns *ir) -{ - IRIns *irp = IR(ir->op1); - if (irp == ir-1 && irp->o == IR_MUL && !ra_used(irp)) { - IRIns *irpp = IR(irp->op1); - if (irpp == ir-2 && irpp->o == IR_FPMATH && - irpp->op2 == IRFPM_LOG2 && !ra_used(irpp)) { - asm_fppow(as, ir, irpp->op1, irp->op2); - return 1; - } - } - return 0; -} -#endif - -/* -- PHI and loop handling ----------------------------------------------- */ - -/* Break a PHI cycle by renaming to a free register (evict if needed). */ -static void asm_phi_break(ASMState *as, RegSet blocked, RegSet blockedby, - RegSet allow) -{ - RegSet candidates = blocked & allow; - if (candidates) { /* If this register file has candidates. */ - /* Note: the set for ra_pick cannot be empty, since each register file - ** has some registers never allocated to PHIs. - */ - Reg down, up = ra_pick(as, ~blocked & allow); /* Get a free register. */ - if (candidates & ~blockedby) /* Optimize shifts, else it's a cycle. */ - candidates = candidates & ~blockedby; - down = rset_picktop(candidates); /* Pick candidate PHI register. */ - ra_rename(as, down, up); /* And rename it to the free register. */ - } -} - -/* PHI register shuffling. -** -** The allocator tries hard to preserve PHI register assignments across -** the loop body. Most of the time this loop does nothing, since there -** are no register mismatches. -** -** If a register mismatch is detected and ... -** - the register is currently free: rename it. -** - the register is blocked by an invariant: restore/remat and rename it. -** - Otherwise the register is used by another PHI, so mark it as blocked. -** -** The renames are order-sensitive, so just retry the loop if a register -** is marked as blocked, but has been freed in the meantime. A cycle is -** detected if all of the blocked registers are allocated. To break the -** cycle rename one of them to a free register and retry. -** -** Note that PHI spill slots are kept in sync and don't need to be shuffled. -*/ -static void asm_phi_shuffle(ASMState *as) -{ - RegSet work; - - /* Find and resolve PHI register mismatches. */ - for (;;) { - RegSet blocked = RSET_EMPTY; - RegSet blockedby = RSET_EMPTY; - RegSet phiset = as->phiset; - while (phiset) { /* Check all left PHI operand registers. */ - Reg r = rset_pickbot(phiset); - IRIns *irl = IR(as->phireg[r]); - Reg left = irl->r; - if (r != left) { /* Mismatch? */ - if (!rset_test(as->freeset, r)) { /* PHI register blocked? */ - IRRef ref = regcost_ref(as->cost[r]); - /* Blocked by other PHI (w/reg)? */ - if (!ra_iskref(ref) && irt_ismarked(IR(ref)->t)) { - rset_set(blocked, r); - if (ra_hasreg(left)) - rset_set(blockedby, left); - left = RID_NONE; - } else { /* Otherwise grab register from invariant. */ - ra_restore(as, ref); - checkmclim(as); - } - } - if (ra_hasreg(left)) { - ra_rename(as, left, r); - checkmclim(as); - } - } - rset_clear(phiset, r); - } - if (!blocked) break; /* Finished. */ - if (!(as->freeset & blocked)) { /* Break cycles if none are free. */ - asm_phi_break(as, blocked, blockedby, RSET_GPR); - if (!LJ_SOFTFP) asm_phi_break(as, blocked, blockedby, RSET_FPR); - checkmclim(as); - } /* Else retry some more renames. */ - } - - /* Restore/remat invariants whose registers are modified inside the loop. */ -#if !LJ_SOFTFP - work = as->modset & ~(as->freeset | as->phiset) & RSET_FPR; - while (work) { - Reg r = rset_pickbot(work); - ra_restore(as, regcost_ref(as->cost[r])); - rset_clear(work, r); - checkmclim(as); - } -#endif - work = as->modset & ~(as->freeset | as->phiset); - while (work) { - Reg r = rset_pickbot(work); - ra_restore(as, regcost_ref(as->cost[r])); - rset_clear(work, r); - checkmclim(as); - } - - /* Allocate and save all unsaved PHI regs and clear marks. */ - work = as->phiset; - while (work) { - Reg r = rset_picktop(work); - IRRef lref = as->phireg[r]; - IRIns *ir = IR(lref); - if (ra_hasspill(ir->s)) { /* Left PHI gained a spill slot? */ - irt_clearmark(ir->t); /* Handled here, so clear marker now. */ - ra_alloc1(as, lref, RID2RSET(r)); - ra_save(as, ir, r); /* Save to spill slot inside the loop. */ - checkmclim(as); - } - rset_clear(work, r); - } -} - -/* Copy unsynced left/right PHI spill slots. Rarely needed. */ -static void asm_phi_copyspill(ASMState *as) -{ - int need = 0; - IRIns *ir; - for (ir = IR(as->orignins-1); ir->o == IR_PHI; ir--) - if (ra_hasspill(ir->s) && ra_hasspill(IR(ir->op1)->s)) - need |= irt_isfp(ir->t) ? 2 : 1; /* Unsynced spill slot? */ - if ((need & 1)) { /* Copy integer spill slots. */ -#if !LJ_TARGET_X86ORX64 - Reg r = RID_TMP; -#else - Reg r = RID_RET; - if ((as->freeset & RSET_GPR)) - r = rset_pickbot((as->freeset & RSET_GPR)); - else - emit_spload(as, IR(regcost_ref(as->cost[r])), r, SPOFS_TMP); -#endif - for (ir = IR(as->orignins-1); ir->o == IR_PHI; ir--) { - if (ra_hasspill(ir->s)) { - IRIns *irl = IR(ir->op1); - if (ra_hasspill(irl->s) && !irt_isfp(ir->t)) { - emit_spstore(as, irl, r, sps_scale(irl->s)); - emit_spload(as, ir, r, sps_scale(ir->s)); - checkmclim(as); - } - } - } -#if LJ_TARGET_X86ORX64 - if (!rset_test(as->freeset, r)) - emit_spstore(as, IR(regcost_ref(as->cost[r])), r, SPOFS_TMP); -#endif - } -#if !LJ_SOFTFP - if ((need & 2)) { /* Copy FP spill slots. */ -#if LJ_TARGET_X86 - Reg r = RID_XMM0; -#else - Reg r = RID_FPRET; -#endif - if ((as->freeset & RSET_FPR)) - r = rset_pickbot((as->freeset & RSET_FPR)); - if (!rset_test(as->freeset, r)) - emit_spload(as, IR(regcost_ref(as->cost[r])), r, SPOFS_TMP); - for (ir = IR(as->orignins-1); ir->o == IR_PHI; ir--) { - if (ra_hasspill(ir->s)) { - IRIns *irl = IR(ir->op1); - if (ra_hasspill(irl->s) && irt_isfp(ir->t)) { - emit_spstore(as, irl, r, sps_scale(irl->s)); - emit_spload(as, ir, r, sps_scale(ir->s)); - checkmclim(as); - } - } - } - if (!rset_test(as->freeset, r)) - emit_spstore(as, IR(regcost_ref(as->cost[r])), r, SPOFS_TMP); - } -#endif -} - -/* Emit renames for left PHIs which are only spilled outside the loop. */ -static void asm_phi_fixup(ASMState *as) -{ - RegSet work = as->phiset; - while (work) { - Reg r = rset_picktop(work); - IRRef lref = as->phireg[r]; - IRIns *ir = IR(lref); - if (irt_ismarked(ir->t)) { - irt_clearmark(ir->t); - /* Left PHI gained a spill slot before the loop? */ - if (ra_hasspill(ir->s)) { - ra_addrename(as, r, lref, as->loopsnapno); - } - } - rset_clear(work, r); - } -} - -/* Setup right PHI reference. */ -static void asm_phi(ASMState *as, IRIns *ir) -{ - RegSet allow = ((!LJ_SOFTFP && irt_isfp(ir->t)) ? RSET_FPR : RSET_GPR) & - ~as->phiset; - RegSet afree = (as->freeset & allow); - IRIns *irl = IR(ir->op1); - IRIns *irr = IR(ir->op2); - if (ir->r == RID_SINK) /* Sink PHI. */ - return; - /* Spill slot shuffling is not implemented yet (but rarely needed). */ - if (ra_hasspill(irl->s) || ra_hasspill(irr->s)) - lj_trace_err(as->J, LJ_TRERR_NYIPHI); - /* Leave at least one register free for non-PHIs (and PHI cycle breaking). */ - if ((afree & (afree-1))) { /* Two or more free registers? */ - Reg r; - if (ra_noreg(irr->r)) { /* Get a register for the right PHI. */ - r = ra_allocref(as, ir->op2, allow); - } else { /* Duplicate right PHI, need a copy (rare). */ - r = ra_scratch(as, allow); - emit_movrr(as, irr, r, irr->r); - } - ir->r = (uint8_t)r; - rset_set(as->phiset, r); - as->phireg[r] = (IRRef1)ir->op1; - irt_setmark(irl->t); /* Marks left PHIs _with_ register. */ - if (ra_noreg(irl->r)) - ra_sethint(irl->r, r); /* Set register hint for left PHI. */ - } else { /* Otherwise allocate a spill slot. */ - /* This is overly restrictive, but it triggers only on synthetic code. */ - if (ra_hasreg(irl->r) || ra_hasreg(irr->r)) - lj_trace_err(as->J, LJ_TRERR_NYIPHI); - ra_spill(as, ir); - irr->s = ir->s; /* Set right PHI spill slot. Sync left slot later. */ - } -} - -static void asm_loop_fixup(ASMState *as); - -/* Middle part of a loop. */ -static void asm_loop(ASMState *as) -{ - MCode *mcspill; - /* LOOP is a guard, so the snapno is up to date. */ - as->loopsnapno = as->snapno; - if (as->gcsteps) - asm_gc_check(as); - /* LOOP marks the transition from the variant to the invariant part. */ - as->flagmcp = as->invmcp = NULL; - as->sectref = 0; - if (!neverfuse(as)) as->fuseref = 0; - asm_phi_shuffle(as); - mcspill = as->mcp; - asm_phi_copyspill(as); - asm_loop_fixup(as); - as->mcloop = as->mcp; - RA_DBGX((as, "===== LOOP =====")); - if (!as->realign) RA_DBG_FLUSH(); - if (as->mcp != mcspill) - emit_jmp(as, mcspill); -} - -/* -- Target-specific assembler ------------------------------------------- */ - -#if LJ_TARGET_X86ORX64 -#include "lj_asm_x86.h" -#elif LJ_TARGET_ARM -#include "lj_asm_arm.h" -#elif LJ_TARGET_ARM64 -#include "lj_asm_arm64.h" -#elif LJ_TARGET_PPC -#include "lj_asm_ppc.h" -#elif LJ_TARGET_MIPS -#include "lj_asm_mips.h" -#else -#error "Missing assembler for target CPU" -#endif - -/* -- Instruction dispatch ------------------------------------------------ */ - -/* Assemble a single instruction. */ -static void asm_ir(ASMState *as, IRIns *ir) -{ - switch ((IROp)ir->o) { - /* Miscellaneous ops. */ - case IR_LOOP: asm_loop(as); break; - case IR_NOP: case IR_XBAR: lua_assert(!ra_used(ir)); break; - case IR_USE: - ra_alloc1(as, ir->op1, irt_isfp(ir->t) ? RSET_FPR : RSET_GPR); break; - case IR_PHI: asm_phi(as, ir); break; - case IR_HIOP: asm_hiop(as, ir); break; - case IR_GCSTEP: asm_gcstep(as, ir); break; - case IR_PROF: asm_prof(as, ir); break; - - /* Guarded assertions. */ - case IR_LT: case IR_GE: case IR_LE: case IR_GT: - case IR_ULT: case IR_UGE: case IR_ULE: case IR_UGT: - case IR_ABC: - asm_comp(as, ir); - break; - case IR_EQ: case IR_NE: - if ((ir-1)->o == IR_HREF && ir->op1 == as->curins-1) { - as->curins--; - asm_href(as, ir-1, (IROp)ir->o); - } else { - asm_equal(as, ir); - } - break; - - case IR_RETF: asm_retf(as, ir); break; - - /* Bit ops. */ - case IR_BNOT: asm_bnot(as, ir); break; - case IR_BSWAP: asm_bswap(as, ir); break; - case IR_BAND: asm_band(as, ir); break; - case IR_BOR: asm_bor(as, ir); break; - case IR_BXOR: asm_bxor(as, ir); break; - case IR_BSHL: asm_bshl(as, ir); break; - case IR_BSHR: asm_bshr(as, ir); break; - case IR_BSAR: asm_bsar(as, ir); break; - case IR_BROL: asm_brol(as, ir); break; - case IR_BROR: asm_bror(as, ir); break; - - /* Arithmetic ops. */ - case IR_ADD: asm_add(as, ir); break; - case IR_SUB: asm_sub(as, ir); break; - case IR_MUL: asm_mul(as, ir); break; - case IR_MOD: asm_mod(as, ir); break; - case IR_NEG: asm_neg(as, ir); break; -#if LJ_SOFTFP32 - case IR_DIV: case IR_POW: case IR_ABS: - case IR_ATAN2: case IR_LDEXP: case IR_FPMATH: case IR_TOBIT: - lua_assert(0); /* Unused for LJ_SOFTFP32. */ - break; -#else - case IR_DIV: asm_div(as, ir); break; - case IR_POW: asm_pow(as, ir); break; - case IR_ABS: asm_abs(as, ir); break; - case IR_ATAN2: asm_atan2(as, ir); break; - case IR_LDEXP: asm_ldexp(as, ir); break; - case IR_FPMATH: asm_fpmath(as, ir); break; - case IR_TOBIT: asm_tobit(as, ir); break; -#endif - case IR_MIN: asm_min(as, ir); break; - case IR_MAX: asm_max(as, ir); break; - - /* Overflow-checking arithmetic ops. */ - case IR_ADDOV: asm_addov(as, ir); break; - case IR_SUBOV: asm_subov(as, ir); break; - case IR_MULOV: asm_mulov(as, ir); break; - - /* Memory references. */ - case IR_AREF: asm_aref(as, ir); break; - case IR_HREF: asm_href(as, ir, 0); break; - case IR_HREFK: asm_hrefk(as, ir); break; - case IR_NEWREF: asm_newref(as, ir); break; - case IR_UREFO: case IR_UREFC: asm_uref(as, ir); break; - case IR_FREF: asm_fref(as, ir); break; - case IR_STRREF: asm_strref(as, ir); break; - case IR_LREF: asm_lref(as, ir); break; - - /* Loads and stores. */ - case IR_ALOAD: case IR_HLOAD: case IR_ULOAD: case IR_VLOAD: - asm_ahuvload(as, ir); - break; - case IR_FLOAD: asm_fload(as, ir); break; - case IR_XLOAD: asm_xload(as, ir); break; - case IR_SLOAD: asm_sload(as, ir); break; - - case IR_ASTORE: case IR_HSTORE: case IR_USTORE: asm_ahustore(as, ir); break; - case IR_FSTORE: asm_fstore(as, ir); break; - case IR_XSTORE: asm_xstore(as, ir); break; - - /* Allocations. */ - case IR_SNEW: case IR_XSNEW: asm_snew(as, ir); break; - case IR_TNEW: asm_tnew(as, ir); break; - case IR_TDUP: asm_tdup(as, ir); break; - case IR_CNEW: case IR_CNEWI: asm_cnew(as, ir); break; - - /* Buffer operations. */ - case IR_BUFHDR: asm_bufhdr(as, ir); break; - case IR_BUFPUT: asm_bufput(as, ir); break; - case IR_BUFSTR: asm_bufstr(as, ir); break; - - /* Write barriers. */ - case IR_TBAR: asm_tbar(as, ir); break; - case IR_OBAR: asm_obar(as, ir); break; - - /* Type conversions. */ - case IR_CONV: asm_conv(as, ir); break; - case IR_TOSTR: asm_tostr(as, ir); break; - case IR_STRTO: asm_strto(as, ir); break; - - /* Calls. */ - case IR_CALLA: - as->gcsteps++; - /* fallthrough */ - case IR_CALLN: case IR_CALLL: case IR_CALLS: asm_call(as, ir); break; - case IR_CALLXS: asm_callx(as, ir); break; - case IR_CARG: break; - - default: - setintV(&as->J->errinfo, ir->o); - lj_trace_err_info(as->J, LJ_TRERR_NYIIR); - break; - } -} - -/* -- Head of trace ------------------------------------------------------- */ - -/* Head of a root trace. */ -static void asm_head_root(ASMState *as) -{ - int32_t spadj; - asm_head_root_base(as); - emit_setvmstate(as, (int32_t)as->T->traceno); - spadj = asm_stack_adjust(as); - as->T->spadjust = (uint16_t)spadj; - emit_spsub(as, spadj); - /* Root traces assume a checked stack for the starting proto. */ - as->T->topslot = gcref(as->T->startpt)->pt.framesize; -} - -/* Head of a side trace. -** -** The current simplistic algorithm requires that all slots inherited -** from the parent are live in a register between pass 2 and pass 3. This -** avoids the complexity of stack slot shuffling. But of course this may -** overflow the register set in some cases and cause the dreaded error: -** "NYI: register coalescing too complex". A refined algorithm is needed. -*/ -static void asm_head_side(ASMState *as) -{ - IRRef1 sloadins[RID_MAX]; - RegSet allow = RSET_ALL; /* Inverse of all coalesced registers. */ - RegSet live = RSET_EMPTY; /* Live parent registers. */ - IRIns *irp = &as->parent->ir[REF_BASE]; /* Parent base. */ - int32_t spadj, spdelta; - int pass2 = 0; - int pass3 = 0; - IRRef i; - - if (as->snapno && as->topslot > as->parent->topslot) { - /* Force snap #0 alloc to prevent register overwrite in stack check. */ - as->snapno = 0; - asm_snap_alloc(as); - } - allow = asm_head_side_base(as, irp, allow); - - /* Scan all parent SLOADs and collect register dependencies. */ - for (i = as->stopins; i > REF_BASE; i--) { - IRIns *ir = IR(i); - RegSP rs; - lua_assert((ir->o == IR_SLOAD && (ir->op2 & IRSLOAD_PARENT)) || - (LJ_SOFTFP && ir->o == IR_HIOP) || ir->o == IR_PVAL); - rs = as->parentmap[i - REF_FIRST]; - if (ra_hasreg(ir->r)) { - rset_clear(allow, ir->r); - if (ra_hasspill(ir->s)) { - ra_save(as, ir, ir->r); - checkmclim(as); - } - } else if (ra_hasspill(ir->s)) { - irt_setmark(ir->t); - pass2 = 1; - } - if (ir->r == rs) { /* Coalesce matching registers right now. */ - ra_free(as, ir->r); - } else if (ra_hasspill(regsp_spill(rs))) { - if (ra_hasreg(ir->r)) - pass3 = 1; - } else if (ra_used(ir)) { - sloadins[rs] = (IRRef1)i; - rset_set(live, rs); /* Block live parent register. */ - } - } - - /* Calculate stack frame adjustment. */ - spadj = asm_stack_adjust(as); - spdelta = spadj - (int32_t)as->parent->spadjust; - if (spdelta < 0) { /* Don't shrink the stack frame. */ - spadj = (int32_t)as->parent->spadjust; - spdelta = 0; - } - as->T->spadjust = (uint16_t)spadj; - - /* Reload spilled target registers. */ - if (pass2) { - for (i = as->stopins; i > REF_BASE; i--) { - IRIns *ir = IR(i); - if (irt_ismarked(ir->t)) { - RegSet mask; - Reg r; - RegSP rs; - irt_clearmark(ir->t); - rs = as->parentmap[i - REF_FIRST]; - if (!ra_hasspill(regsp_spill(rs))) - ra_sethint(ir->r, rs); /* Hint may be gone, set it again. */ - else if (sps_scale(regsp_spill(rs))+spdelta == sps_scale(ir->s)) - continue; /* Same spill slot, do nothing. */ - mask = ((!LJ_SOFTFP && irt_isfp(ir->t)) ? RSET_FPR : RSET_GPR) & allow; - if (mask == RSET_EMPTY) - lj_trace_err(as->J, LJ_TRERR_NYICOAL); - r = ra_allocref(as, i, mask); - ra_save(as, ir, r); - rset_clear(allow, r); - if (r == rs) { /* Coalesce matching registers right now. */ - ra_free(as, r); - rset_clear(live, r); - } else if (ra_hasspill(regsp_spill(rs))) { - pass3 = 1; - } - checkmclim(as); - } - } - } - - /* Store trace number and adjust stack frame relative to the parent. */ - emit_setvmstate(as, (int32_t)as->T->traceno); - emit_spsub(as, spdelta); - -#if !LJ_TARGET_X86ORX64 - /* Restore BASE register from parent spill slot. */ - if (ra_hasspill(irp->s)) - emit_spload(as, IR(REF_BASE), IR(REF_BASE)->r, sps_scale(irp->s)); -#endif - - /* Restore target registers from parent spill slots. */ - if (pass3) { - RegSet work = ~as->freeset & RSET_ALL; - while (work) { - Reg r = rset_pickbot(work); - IRRef ref = regcost_ref(as->cost[r]); - RegSP rs = as->parentmap[ref - REF_FIRST]; - rset_clear(work, r); - if (ra_hasspill(regsp_spill(rs))) { - int32_t ofs = sps_scale(regsp_spill(rs)); - ra_free(as, r); - emit_spload(as, IR(ref), r, ofs); - checkmclim(as); - } - } - } - - /* Shuffle registers to match up target regs with parent regs. */ - for (;;) { - RegSet work; - - /* Repeatedly coalesce free live registers by moving to their target. */ - while ((work = as->freeset & live) != RSET_EMPTY) { - Reg rp = rset_pickbot(work); - IRIns *ir = IR(sloadins[rp]); - rset_clear(live, rp); - rset_clear(allow, rp); - ra_free(as, ir->r); - emit_movrr(as, ir, ir->r, rp); - checkmclim(as); - } - - /* We're done if no live registers remain. */ - if (live == RSET_EMPTY) - break; - - /* Break cycles by renaming one target to a temp. register. */ - if (live & RSET_GPR) { - RegSet tmpset = as->freeset & ~live & allow & RSET_GPR; - if (tmpset == RSET_EMPTY) - lj_trace_err(as->J, LJ_TRERR_NYICOAL); - ra_rename(as, rset_pickbot(live & RSET_GPR), rset_pickbot(tmpset)); - } - if (!LJ_SOFTFP && (live & RSET_FPR)) { - RegSet tmpset = as->freeset & ~live & allow & RSET_FPR; - if (tmpset == RSET_EMPTY) - lj_trace_err(as->J, LJ_TRERR_NYICOAL); - ra_rename(as, rset_pickbot(live & RSET_FPR), rset_pickbot(tmpset)); - } - checkmclim(as); - /* Continue with coalescing to fix up the broken cycle(s). */ - } - - /* Inherit top stack slot already checked by parent trace. */ - as->T->topslot = as->parent->topslot; - if (as->topslot > as->T->topslot) { /* Need to check for higher slot? */ -#ifdef EXITSTATE_CHECKEXIT - /* Highest exit + 1 indicates stack check. */ - ExitNo exitno = as->T->nsnap; -#else - /* Reuse the parent exit in the context of the parent trace. */ - ExitNo exitno = as->J->exitno; -#endif - as->T->topslot = (uint8_t)as->topslot; /* Remember for child traces. */ - asm_stack_check(as, as->topslot, irp, allow & RSET_GPR, exitno); - } -} - -/* -- Tail of trace ------------------------------------------------------- */ - -/* Get base slot for a snapshot. */ -static BCReg asm_baseslot(ASMState *as, SnapShot *snap, int *gotframe) -{ - SnapEntry *map = &as->T->snapmap[snap->mapofs]; - MSize n; - for (n = snap->nent; n > 0; n--) { - SnapEntry sn = map[n-1]; - if ((sn & SNAP_FRAME)) { - *gotframe = 1; - return snap_slot(sn) - LJ_FR2; - } - } - return 0; -} - -/* Link to another trace. */ -static void asm_tail_link(ASMState *as) -{ - SnapNo snapno = as->T->nsnap-1; /* Last snapshot. */ - SnapShot *snap = &as->T->snap[snapno]; - int gotframe = 0; - BCReg baseslot = asm_baseslot(as, snap, &gotframe); - - as->topslot = snap->topslot; - checkmclim(as); - ra_allocref(as, REF_BASE, RID2RSET(RID_BASE)); - - if (as->T->link == 0) { - /* Setup fixed registers for exit to interpreter. */ - const BCIns *pc = snap_pc(&as->T->snapmap[snap->mapofs + snap->nent]); - int32_t mres; - if (bc_op(*pc) == BC_JLOOP) { /* NYI: find a better way to do this. */ - BCIns *retpc = &traceref(as->J, bc_d(*pc))->startins; - if (bc_isret(bc_op(*retpc))) - pc = retpc; - } -#if LJ_GC64 - emit_loadu64(as, RID_LPC, u64ptr(pc)); -#else - ra_allockreg(as, i32ptr(J2GG(as->J)->dispatch), RID_DISPATCH); - ra_allockreg(as, i32ptr(pc), RID_LPC); -#endif - mres = (int32_t)(snap->nslots - baseslot - LJ_FR2); - switch (bc_op(*pc)) { - case BC_CALLM: case BC_CALLMT: - mres -= (int32_t)(1 + LJ_FR2 + bc_a(*pc) + bc_c(*pc)); break; - case BC_RETM: mres -= (int32_t)(bc_a(*pc) + bc_d(*pc)); break; - case BC_TSETM: mres -= (int32_t)bc_a(*pc); break; - default: if (bc_op(*pc) < BC_FUNCF) mres = 0; break; - } - ra_allockreg(as, mres, RID_RET); /* Return MULTRES or 0. */ - } else if (baseslot) { - /* Save modified BASE for linking to trace with higher start frame. */ - emit_setgl(as, RID_BASE, jit_base); - } - emit_addptr(as, RID_BASE, 8*(int32_t)baseslot); - - if (as->J->ktrace) { /* Patch ktrace slot with the final GCtrace pointer. */ - setgcref(IR(as->J->ktrace)[LJ_GC64].gcr, obj2gco(as->J->curfinal)); - IR(as->J->ktrace)->o = IR_KGC; - } - - /* Sync the interpreter state with the on-trace state. */ - asm_stack_restore(as, snap); - - /* Root traces that add frames need to check the stack at the end. */ - if (!as->parent && gotframe) - asm_stack_check(as, as->topslot, NULL, as->freeset & RSET_GPR, snapno); -} - -/* -- Trace setup --------------------------------------------------------- */ - -/* Clear reg/sp for all instructions and add register hints. */ -static void asm_setup_regsp(ASMState *as) -{ - GCtrace *T = as->T; - int sink = T->sinktags; - IRRef nins = T->nins; - IRIns *ir, *lastir; - int inloop; -#if LJ_TARGET_ARM - uint32_t rload = 0xa6402a64; -#endif - - ra_setup(as); - - /* Clear reg/sp for constants. */ - for (ir = IR(T->nk), lastir = IR(REF_BASE); ir < lastir; ir++) { - ir->prev = REGSP_INIT; - if (irt_is64(ir->t) && ir->o != IR_KNULL) { -#if LJ_GC64 - /* The false-positive of irt_is64() for ASMREF_L (REF_NIL) is OK here. */ - ir->i = 0; /* Will become non-zero only for RIP-relative addresses. */ -#else - /* Make life easier for backends by putting address of constant in i. */ - ir->i = (int32_t)(intptr_t)(ir+1); -#endif - ir++; - } - } - - /* REF_BASE is used for implicit references to the BASE register. */ - lastir->prev = REGSP_HINT(RID_BASE); - - as->snaprename = nins; - as->snapref = nins; - as->snapno = T->nsnap; - - as->stopins = REF_BASE; - as->orignins = nins; - as->curins = nins; - - /* Setup register hints for parent link instructions. */ - ir = IR(REF_FIRST); - if (as->parent) { - uint16_t *p; - lastir = lj_snap_regspmap(as->parent, as->J->exitno, ir); - if (lastir - ir > LJ_MAX_JSLOTS) - lj_trace_err(as->J, LJ_TRERR_NYICOAL); - as->stopins = (IRRef)((lastir-1) - as->ir); - for (p = as->parentmap; ir < lastir; ir++) { - RegSP rs = ir->prev; - *p++ = (uint16_t)rs; /* Copy original parent RegSP to parentmap. */ - if (!ra_hasspill(regsp_spill(rs))) - ir->prev = (uint16_t)REGSP_HINT(regsp_reg(rs)); - else - ir->prev = REGSP_INIT; - } - } - - inloop = 0; - as->evenspill = SPS_FIRST; - for (lastir = IR(nins); ir < lastir; ir++) { - if (sink) { - if (ir->r == RID_SINK) - continue; - if (ir->r == RID_SUNK) { /* Revert after ASM restart. */ - ir->r = RID_SINK; - continue; - } - } - switch (ir->o) { - case IR_LOOP: - inloop = 1; - break; -#if LJ_TARGET_ARM - case IR_SLOAD: - if (!((ir->op2 & IRSLOAD_TYPECHECK) || (ir+1)->o == IR_HIOP)) - break; - /* fallthrough */ - case IR_ALOAD: case IR_HLOAD: case IR_ULOAD: case IR_VLOAD: - if (!LJ_SOFTFP && irt_isnum(ir->t)) break; - ir->prev = (uint16_t)REGSP_HINT((rload & 15)); - rload = lj_ror(rload, 4); - continue; -#endif - case IR_CALLXS: { - CCallInfo ci; - ci.flags = asm_callx_flags(as, ir); - ir->prev = asm_setup_call_slots(as, ir, &ci); - if (inloop) - as->modset |= RSET_SCRATCH; - continue; - } - case IR_CALLN: case IR_CALLA: case IR_CALLL: case IR_CALLS: { - const CCallInfo *ci = &lj_ir_callinfo[ir->op2]; - ir->prev = asm_setup_call_slots(as, ir, ci); - if (inloop) - as->modset |= (ci->flags & CCI_NOFPRCLOBBER) ? - (RSET_SCRATCH & ~RSET_FPR) : RSET_SCRATCH; - continue; - } -#if LJ_SOFTFP || (LJ_32 && LJ_HASFFI) - case IR_HIOP: - switch ((ir-1)->o) { -#if LJ_SOFTFP && LJ_TARGET_ARM - case IR_SLOAD: case IR_ALOAD: case IR_HLOAD: case IR_ULOAD: case IR_VLOAD: - if (ra_hashint((ir-1)->r)) { - ir->prev = (ir-1)->prev + 1; - continue; - } - break; -#endif -#if !LJ_SOFTFP && LJ_NEED_FP64 - case IR_CONV: - if (irt_isfp((ir-1)->t)) { - ir->prev = REGSP_HINT(RID_FPRET); - continue; - } - /* fallthrough */ -#endif - case IR_CALLN: case IR_CALLXS: -#if LJ_SOFTFP - case IR_MIN: case IR_MAX: -#endif - (ir-1)->prev = REGSP_HINT(RID_RETLO); - ir->prev = REGSP_HINT(RID_RETHI); - continue; - default: - break; - } - break; -#endif -#if LJ_SOFTFP - case IR_MIN: case IR_MAX: - if ((ir+1)->o != IR_HIOP) break; - /* fallthrough */ -#endif - /* C calls evict all scratch regs and return results in RID_RET. */ - case IR_SNEW: case IR_XSNEW: case IR_NEWREF: case IR_BUFPUT: - if (REGARG_NUMGPR < 3 && as->evenspill < 3) - as->evenspill = 3; /* lj_str_new and lj_tab_newkey need 3 args. */ -#if LJ_TARGET_X86 && LJ_HASFFI - if (0) { - case IR_CNEW: - if (ir->op2 != REF_NIL && as->evenspill < 4) - as->evenspill = 4; /* lj_cdata_newv needs 4 args. */ - } - /* fallthrough */ -#else - /* fallthrough */ - case IR_CNEW: -#endif - /* fallthrough */ - case IR_TNEW: case IR_TDUP: case IR_CNEWI: case IR_TOSTR: - case IR_BUFSTR: - ir->prev = REGSP_HINT(RID_RET); - if (inloop) - as->modset = RSET_SCRATCH; - continue; - case IR_STRTO: case IR_OBAR: - if (inloop) - as->modset = RSET_SCRATCH; - break; -#if !LJ_SOFTFP - case IR_ATAN2: -#if LJ_TARGET_X86 - if (as->evenspill < 4) /* Leave room to call atan2(). */ - as->evenspill = 4; -#endif -#if !LJ_TARGET_X86ORX64 - case IR_LDEXP: -#endif -#endif - /* fallthrough */ - case IR_POW: - if (!LJ_SOFTFP && irt_isnum(ir->t)) { - if (inloop) - as->modset |= RSET_SCRATCH; -#if LJ_TARGET_X86 - break; -#else - ir->prev = REGSP_HINT(RID_FPRET); - continue; -#endif - } - /* fallthrough */ /* for integer POW */ - case IR_DIV: case IR_MOD: - if (!irt_isnum(ir->t)) { - ir->prev = REGSP_HINT(RID_RET); - if (inloop) - as->modset |= (RSET_SCRATCH & RSET_GPR); - continue; - } - break; - case IR_FPMATH: -#if LJ_TARGET_X86ORX64 - if (ir->op2 <= IRFPM_TRUNC) { - if (!(as->flags & JIT_F_SSE4_1)) { - ir->prev = REGSP_HINT(RID_XMM0); - if (inloop) - as->modset |= RSET_RANGE(RID_XMM0, RID_XMM3+1)|RID2RSET(RID_EAX); - continue; - } - break; - } else if (ir->op2 == IRFPM_EXP2 && !LJ_64) { - if (as->evenspill < 4) /* Leave room to call pow(). */ - as->evenspill = 4; - } -#endif - if (inloop) - as->modset |= RSET_SCRATCH; -#if LJ_TARGET_X86 - break; -#else - ir->prev = REGSP_HINT(RID_FPRET); - continue; -#endif -#if LJ_TARGET_X86ORX64 - /* Non-constant shift counts need to be in RID_ECX on x86/x64. */ - case IR_BSHL: case IR_BSHR: case IR_BSAR: - if ((as->flags & JIT_F_BMI2)) /* Except if BMI2 is available. */ - break; - /* fallthrough */ - case IR_BROL: case IR_BROR: - if (!irref_isk(ir->op2) && !ra_hashint(IR(ir->op2)->r)) { - IR(ir->op2)->r = REGSP_HINT(RID_ECX); - if (inloop) - rset_set(as->modset, RID_ECX); - } - break; -#endif - /* Do not propagate hints across type conversions or loads. */ - case IR_TOBIT: - case IR_XLOAD: -#if !LJ_TARGET_ARM - case IR_ALOAD: case IR_HLOAD: case IR_ULOAD: case IR_VLOAD: -#endif - break; - case IR_CONV: - if (irt_isfp(ir->t) || (ir->op2 & IRCONV_SRCMASK) == IRT_NUM || - (ir->op2 & IRCONV_SRCMASK) == IRT_FLOAT) - break; - /* fallthrough */ - default: - /* Propagate hints across likely 'op reg, imm' or 'op reg'. */ - if (irref_isk(ir->op2) && !irref_isk(ir->op1) && - ra_hashint(regsp_reg(IR(ir->op1)->prev))) { - ir->prev = IR(ir->op1)->prev; - continue; - } - break; - } - ir->prev = REGSP_INIT; - } - if ((as->evenspill & 1)) - as->oddspill = as->evenspill++; - else - as->oddspill = 0; -} - -/* -- Assembler core ------------------------------------------------------ */ - -/* Assemble a trace. */ -void lj_asm_trace(jit_State *J, GCtrace *T) -{ - ASMState as_; - ASMState *as = &as_; - MCode *origtop; - - /* Remove nops/renames left over from ASM restart due to LJ_TRERR_MCODELM. */ - { - IRRef nins = T->nins; - IRIns *ir = &T->ir[nins-1]; - if (ir->o == IR_NOP || ir->o == IR_RENAME) { - do { ir--; nins--; } while (ir->o == IR_NOP || ir->o == IR_RENAME); - T->nins = nins; - } - } - - /* Ensure an initialized instruction beyond the last one for HIOP checks. */ - /* This also allows one RENAME to be added without reallocating curfinal. */ - as->orignins = lj_ir_nextins(J); - J->cur.ir[as->orignins].o = IR_NOP; - - /* Setup initial state. Copy some fields to reduce indirections. */ - as->J = J; - as->T = T; - J->curfinal = lj_trace_alloc(J->L, T); /* This copies the IR, too. */ - as->flags = J->flags; - as->loopref = J->loopref; - as->realign = NULL; - as->loopinv = 0; - as->parent = J->parent ? traceref(J, J->parent) : NULL; - - /* Reserve MCode memory. */ - as->mctop = origtop = lj_mcode_reserve(J, &as->mcbot); - as->mcp = as->mctop; - as->mclim = as->mcbot + MCLIM_REDZONE; - asm_setup_target(as); - - /* - ** This is a loop, because the MCode may have to be (re-)assembled - ** multiple times: - ** - ** 1. as->realign is set (and the assembly aborted), if the arch-specific - ** backend wants the MCode to be aligned differently. - ** - ** This is currently only the case on x86/x64, where small loops get - ** an aligned loop body plus a short branch. Not much effort is wasted, - ** because the abort happens very quickly and only once. - ** - ** 2. The IR is immovable, since the MCode embeds pointers to various - ** constants inside the IR. But RENAMEs may need to be added to the IR - ** during assembly, which might grow and reallocate the IR. We check - ** at the end if the IR (in J->cur.ir) has actually grown, resize the - ** copy (in J->curfinal.ir) and try again. - ** - ** 95% of all traces have zero RENAMEs, 3% have one RENAME, 1.5% have - ** 2 RENAMEs and only 0.5% have more than that. That's why we opt to - ** always have one spare slot in the IR (see above), which means we - ** have to redo the assembly for only ~2% of all traces. - ** - ** Very, very rarely, this needs to be done repeatedly, since the - ** location of constants inside the IR (actually, reachability from - ** a global pointer) may affect register allocation and thus the - ** number of RENAMEs. - */ - for (;;) { - as->mcp = as->mctop; -#ifdef LUA_USE_ASSERT - as->mcp_prev = as->mcp; -#endif - as->ir = J->curfinal->ir; /* Use the copied IR. */ - as->curins = J->cur.nins = as->orignins; - - RA_DBG_START(); - RA_DBGX((as, "===== STOP =====")); - - /* General trace setup. Emit tail of trace. */ - asm_tail_prep(as); - as->mcloop = NULL; - as->flagmcp = NULL; - as->topslot = 0; - as->gcsteps = 0; - as->sectref = as->loopref; - as->fuseref = (as->flags & JIT_F_OPT_FUSE) ? as->loopref : FUSE_DISABLED; - asm_setup_regsp(as); - if (!as->loopref) - asm_tail_link(as); - - /* Assemble a trace in linear backwards order. */ - for (as->curins--; as->curins > as->stopins; as->curins--) { - IRIns *ir = IR(as->curins); - lua_assert(!(LJ_32 && irt_isint64(ir->t))); /* Handled by SPLIT. */ - if (!ra_used(ir) && !ir_sideeff(ir) && (as->flags & JIT_F_OPT_DCE)) - continue; /* Dead-code elimination can be soooo easy. */ - if (irt_isguard(ir->t)) - asm_snap_prep(as); - RA_DBG_REF(); - checkmclim(as); - asm_ir(as, ir); - } - - if (as->realign && J->curfinal->nins >= T->nins) - continue; /* Retry in case only the MCode needs to be realigned. */ - - /* Emit head of trace. */ - RA_DBG_REF(); - checkmclim(as); - if (as->gcsteps > 0) { - as->curins = as->T->snap[0].ref; - asm_snap_prep(as); /* The GC check is a guard. */ - asm_gc_check(as); - as->curins = as->stopins; - } - ra_evictk(as); - if (as->parent) - asm_head_side(as); - else - asm_head_root(as); - asm_phi_fixup(as); - - if (J->curfinal->nins >= T->nins) { /* IR didn't grow? */ - lua_assert(J->curfinal->nk == T->nk); - memcpy(J->curfinal->ir + as->orignins, T->ir + as->orignins, - (T->nins - as->orignins) * sizeof(IRIns)); /* Copy RENAMEs. */ - T->nins = J->curfinal->nins; - break; /* Done. */ - } - - /* Otherwise try again with a bigger IR. */ - lj_trace_free(J2G(J), J->curfinal); - J->curfinal = NULL; /* In case lj_trace_alloc() OOMs. */ - J->curfinal = lj_trace_alloc(J->L, T); - as->realign = NULL; - } - - RA_DBGX((as, "===== START ====")); - RA_DBG_FLUSH(); - if (as->freeset != RSET_ALL) - lj_trace_err(as->J, LJ_TRERR_BADRA); /* Ouch! Should never happen. */ - - /* Set trace entry point before fixing up tail to allow link to self. */ - T->mcode = as->mcp; - T->mcloop = as->mcloop ? (MSize)((char *)as->mcloop - (char *)as->mcp) : 0; - if (!as->loopref) - asm_tail_fixup(as, T->link); /* Note: this may change as->mctop! */ - T->szmcode = (MSize)((char *)as->mctop - (char *)as->mcp); -#if LJ_TARGET_MCODE_FIXUP - asm_mcode_fixup(T->mcode, T->szmcode); -#endif - lj_mcode_sync(T->mcode, origtop); -} - -#undef IR - -#endif diff --git a/lib/LuaJIT/src/lj_asm.h b/lib/LuaJIT/src/lj_asm.h deleted file mode 100644 index 2819481..0000000 --- a/lib/LuaJIT/src/lj_asm.h +++ /dev/null @@ -1,17 +0,0 @@ -/* -** IR assembler (SSA IR -> machine code). -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_ASM_H -#define _LJ_ASM_H - -#include "lj_jit.h" - -#if LJ_HASJIT -LJ_FUNC void lj_asm_trace(jit_State *J, GCtrace *T); -LJ_FUNC void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, - MCode *target); -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_asm_arm.h b/lib/LuaJIT/src/lj_asm_arm.h deleted file mode 100644 index 37bfa40..0000000 --- a/lib/LuaJIT/src/lj_asm_arm.h +++ /dev/null @@ -1,2210 +0,0 @@ -/* -** ARM IR assembler (SSA IR -> machine code). -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -/* -- Register allocator extensions --------------------------------------- */ - -/* Allocate a register with a hint. */ -static Reg ra_hintalloc(ASMState *as, IRRef ref, Reg hint, RegSet allow) -{ - Reg r = IR(ref)->r; - if (ra_noreg(r)) { - if (!ra_hashint(r) && !iscrossref(as, ref)) - ra_sethint(IR(ref)->r, hint); /* Propagate register hint. */ - r = ra_allocref(as, ref, allow); - } - ra_noweak(as, r); - return r; -} - -/* Allocate a scratch register pair. */ -static Reg ra_scratchpair(ASMState *as, RegSet allow) -{ - RegSet pick1 = as->freeset & allow; - RegSet pick2 = pick1 & (pick1 >> 1) & RSET_GPREVEN; - Reg r; - if (pick2) { - r = rset_picktop(pick2); - } else { - RegSet pick = pick1 & (allow >> 1) & RSET_GPREVEN; - if (pick) { - r = rset_picktop(pick); - ra_restore(as, regcost_ref(as->cost[r+1])); - } else { - pick = pick1 & (allow << 1) & RSET_GPRODD; - if (pick) { - r = ra_restore(as, regcost_ref(as->cost[rset_picktop(pick)-1])); - } else { - r = ra_evict(as, allow & (allow >> 1) & RSET_GPREVEN); - ra_restore(as, regcost_ref(as->cost[r+1])); - } - } - } - lua_assert(rset_test(RSET_GPREVEN, r)); - ra_modified(as, r); - ra_modified(as, r+1); - RA_DBGX((as, "scratchpair $r $r", r, r+1)); - return r; -} - -#if !LJ_SOFTFP -/* Allocate two source registers for three-operand instructions. */ -static Reg ra_alloc2(ASMState *as, IRIns *ir, RegSet allow) -{ - IRIns *irl = IR(ir->op1), *irr = IR(ir->op2); - Reg left = irl->r, right = irr->r; - if (ra_hasreg(left)) { - ra_noweak(as, left); - if (ra_noreg(right)) - right = ra_allocref(as, ir->op2, rset_exclude(allow, left)); - else - ra_noweak(as, right); - } else if (ra_hasreg(right)) { - ra_noweak(as, right); - left = ra_allocref(as, ir->op1, rset_exclude(allow, right)); - } else if (ra_hashint(right)) { - right = ra_allocref(as, ir->op2, allow); - left = ra_alloc1(as, ir->op1, rset_exclude(allow, right)); - } else { - left = ra_allocref(as, ir->op1, allow); - right = ra_alloc1(as, ir->op2, rset_exclude(allow, left)); - } - return left | (right << 8); -} -#endif - -/* -- Guard handling ------------------------------------------------------ */ - -/* Generate an exit stub group at the bottom of the reserved MCode memory. */ -static MCode *asm_exitstub_gen(ASMState *as, ExitNo group) -{ - MCode *mxp = as->mcbot; - int i; - if (mxp + 4*4+4*EXITSTUBS_PER_GROUP >= as->mctop) - asm_mclimit(as); - /* str lr, [sp]; bl ->vm_exit_handler; .long DISPATCH_address, group. */ - *mxp++ = ARMI_STR|ARMI_LS_P|ARMI_LS_U|ARMF_D(RID_LR)|ARMF_N(RID_SP); - *mxp = ARMI_BL|((((MCode *)(void *)lj_vm_exit_handler-mxp)-2)&0x00ffffffu); - mxp++; - *mxp++ = (MCode)i32ptr(J2GG(as->J)->dispatch); /* DISPATCH address */ - *mxp++ = group*EXITSTUBS_PER_GROUP; - for (i = 0; i < EXITSTUBS_PER_GROUP; i++) - *mxp++ = ARMI_B|((-6-i)&0x00ffffffu); - lj_mcode_sync(as->mcbot, mxp); - lj_mcode_commitbot(as->J, mxp); - as->mcbot = mxp; - as->mclim = as->mcbot + MCLIM_REDZONE; - return mxp - EXITSTUBS_PER_GROUP; -} - -/* Setup all needed exit stubs. */ -static void asm_exitstub_setup(ASMState *as, ExitNo nexits) -{ - ExitNo i; - if (nexits >= EXITSTUBS_PER_GROUP*LJ_MAX_EXITSTUBGR) - lj_trace_err(as->J, LJ_TRERR_SNAPOV); - for (i = 0; i < (nexits+EXITSTUBS_PER_GROUP-1)/EXITSTUBS_PER_GROUP; i++) - if (as->J->exitstubgroup[i] == NULL) - as->J->exitstubgroup[i] = asm_exitstub_gen(as, i); -} - -/* Emit conditional branch to exit for guard. */ -static void asm_guardcc(ASMState *as, ARMCC cc) -{ - MCode *target = exitstub_addr(as->J, as->snapno); - MCode *p = as->mcp; - if (LJ_UNLIKELY(p == as->invmcp)) { - as->loopinv = 1; - *p = ARMI_BL | ((target-p-2) & 0x00ffffffu); - emit_branch(as, ARMF_CC(ARMI_B, cc^1), p+1); - return; - } - emit_branch(as, ARMF_CC(ARMI_BL, cc), target); -} - -/* -- Operand fusion ------------------------------------------------------ */ - -/* Limit linear search to this distance. Avoids O(n^2) behavior. */ -#define CONFLICT_SEARCH_LIM 31 - -/* Check if there's no conflicting instruction between curins and ref. */ -static int noconflict(ASMState *as, IRRef ref, IROp conflict) -{ - IRIns *ir = as->ir; - IRRef i = as->curins; - if (i > ref + CONFLICT_SEARCH_LIM) - return 0; /* Give up, ref is too far away. */ - while (--i > ref) - if (ir[i].o == conflict) - return 0; /* Conflict found. */ - return 1; /* Ok, no conflict. */ -} - -/* Fuse the array base of colocated arrays. */ -static int32_t asm_fuseabase(ASMState *as, IRRef ref) -{ - IRIns *ir = IR(ref); - if (ir->o == IR_TNEW && ir->op1 <= LJ_MAX_COLOSIZE && - !neverfuse(as) && noconflict(as, ref, IR_NEWREF)) - return (int32_t)sizeof(GCtab); - return 0; -} - -/* Fuse array/hash/upvalue reference into register+offset operand. */ -static Reg asm_fuseahuref(ASMState *as, IRRef ref, int32_t *ofsp, RegSet allow, - int lim) -{ - IRIns *ir = IR(ref); - if (ra_noreg(ir->r)) { - if (ir->o == IR_AREF) { - if (mayfuse(as, ref)) { - if (irref_isk(ir->op2)) { - IRRef tab = IR(ir->op1)->op1; - int32_t ofs = asm_fuseabase(as, tab); - IRRef refa = ofs ? tab : ir->op1; - ofs += 8*IR(ir->op2)->i; - if (ofs > -lim && ofs < lim) { - *ofsp = ofs; - return ra_alloc1(as, refa, allow); - } - } - } - } else if (ir->o == IR_HREFK) { - if (mayfuse(as, ref)) { - int32_t ofs = (int32_t)(IR(ir->op2)->op2 * sizeof(Node)); - if (ofs < lim) { - *ofsp = ofs; - return ra_alloc1(as, ir->op1, allow); - } - } - } else if (ir->o == IR_UREFC) { - if (irref_isk(ir->op1)) { - GCfunc *fn = ir_kfunc(IR(ir->op1)); - int32_t ofs = i32ptr(&gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.tv); - *ofsp = (ofs & 255); /* Mask out less bits to allow LDRD. */ - return ra_allock(as, (ofs & ~255), allow); - } - } - } - *ofsp = 0; - return ra_alloc1(as, ref, allow); -} - -/* Fuse m operand into arithmetic/logic instructions. */ -static uint32_t asm_fuseopm(ASMState *as, ARMIns ai, IRRef ref, RegSet allow) -{ - IRIns *ir = IR(ref); - if (ra_hasreg(ir->r)) { - ra_noweak(as, ir->r); - return ARMF_M(ir->r); - } else if (irref_isk(ref)) { - uint32_t k = emit_isk12(ai, ir->i); - if (k) - return k; - } else if (mayfuse(as, ref)) { - if (ir->o >= IR_BSHL && ir->o <= IR_BROR) { - Reg m = ra_alloc1(as, ir->op1, allow); - ARMShift sh = ir->o == IR_BSHL ? ARMSH_LSL : - ir->o == IR_BSHR ? ARMSH_LSR : - ir->o == IR_BSAR ? ARMSH_ASR : ARMSH_ROR; - if (irref_isk(ir->op2)) { - return m | ARMF_SH(sh, (IR(ir->op2)->i & 31)); - } else { - Reg s = ra_alloc1(as, ir->op2, rset_exclude(allow, m)); - return m | ARMF_RSH(sh, s); - } - } else if (ir->o == IR_ADD && ir->op1 == ir->op2) { - Reg m = ra_alloc1(as, ir->op1, allow); - return m | ARMF_SH(ARMSH_LSL, 1); - } - } - return ra_allocref(as, ref, allow); -} - -/* Fuse shifts into loads/stores. Only bother with BSHL 2 => lsl #2. */ -static IRRef asm_fuselsl2(ASMState *as, IRRef ref) -{ - IRIns *ir = IR(ref); - if (ra_noreg(ir->r) && mayfuse(as, ref) && ir->o == IR_BSHL && - irref_isk(ir->op2) && IR(ir->op2)->i == 2) - return ir->op1; - return 0; /* No fusion. */ -} - -/* Fuse XLOAD/XSTORE reference into load/store operand. */ -static void asm_fusexref(ASMState *as, ARMIns ai, Reg rd, IRRef ref, - RegSet allow, int32_t ofs) -{ - IRIns *ir = IR(ref); - Reg base; - if (ra_noreg(ir->r) && canfuse(as, ir)) { - int32_t lim = (!LJ_SOFTFP && (ai & 0x08000000)) ? 1024 : - (ai & 0x04000000) ? 4096 : 256; - if (ir->o == IR_ADD) { - int32_t ofs2; - if (irref_isk(ir->op2) && - (ofs2 = ofs + IR(ir->op2)->i) > -lim && ofs2 < lim && - (!(!LJ_SOFTFP && (ai & 0x08000000)) || !(ofs2 & 3))) { - ofs = ofs2; - ref = ir->op1; - } else if (ofs == 0 && !(!LJ_SOFTFP && (ai & 0x08000000))) { - IRRef lref = ir->op1, rref = ir->op2; - Reg rn, rm; - if ((ai & 0x04000000)) { - IRRef sref = asm_fuselsl2(as, rref); - if (sref) { - rref = sref; - ai |= ARMF_SH(ARMSH_LSL, 2); - } else if ((sref = asm_fuselsl2(as, lref)) != 0) { - lref = rref; - rref = sref; - ai |= ARMF_SH(ARMSH_LSL, 2); - } - } - rn = ra_alloc1(as, lref, allow); - rm = ra_alloc1(as, rref, rset_exclude(allow, rn)); - if ((ai & 0x04000000)) ai |= ARMI_LS_R; - emit_dnm(as, ai|ARMI_LS_P|ARMI_LS_U, rd, rn, rm); - return; - } - } else if (ir->o == IR_STRREF && !(!LJ_SOFTFP && (ai & 0x08000000))) { - lua_assert(ofs == 0); - ofs = (int32_t)sizeof(GCstr); - if (irref_isk(ir->op2)) { - ofs += IR(ir->op2)->i; - ref = ir->op1; - } else if (irref_isk(ir->op1)) { - ofs += IR(ir->op1)->i; - ref = ir->op2; - } else { - /* NYI: Fuse ADD with constant. */ - Reg rn = ra_alloc1(as, ir->op1, allow); - uint32_t m = asm_fuseopm(as, 0, ir->op2, rset_exclude(allow, rn)); - if ((ai & 0x04000000)) - emit_lso(as, ai, rd, rd, ofs); - else - emit_lsox(as, ai, rd, rd, ofs); - emit_dn(as, ARMI_ADD^m, rd, rn); - return; - } - if (ofs <= -lim || ofs >= lim) { - Reg rn = ra_alloc1(as, ref, allow); - Reg rm = ra_allock(as, ofs, rset_exclude(allow, rn)); - if ((ai & 0x04000000)) ai |= ARMI_LS_R; - emit_dnm(as, ai|ARMI_LS_P|ARMI_LS_U, rd, rn, rm); - return; - } - } - } - base = ra_alloc1(as, ref, allow); -#if !LJ_SOFTFP - if ((ai & 0x08000000)) - emit_vlso(as, ai, rd, base, ofs); - else -#endif - if ((ai & 0x04000000)) - emit_lso(as, ai, rd, base, ofs); - else - emit_lsox(as, ai, rd, base, ofs); -} - -#if !LJ_SOFTFP -/* Fuse to multiply-add/sub instruction. */ -static int asm_fusemadd(ASMState *as, IRIns *ir, ARMIns ai, ARMIns air) -{ - IRRef lref = ir->op1, rref = ir->op2; - IRIns *irm; - if (lref != rref && - ((mayfuse(as, lref) && (irm = IR(lref), irm->o == IR_MUL) && - ra_noreg(irm->r)) || - (mayfuse(as, rref) && (irm = IR(rref), irm->o == IR_MUL) && - (rref = lref, ai = air, ra_noreg(irm->r))))) { - Reg dest = ra_dest(as, ir, RSET_FPR); - Reg add = ra_hintalloc(as, rref, dest, RSET_FPR); - Reg right, left = ra_alloc2(as, irm, - rset_exclude(rset_exclude(RSET_FPR, dest), add)); - right = (left >> 8); left &= 255; - emit_dnm(as, ai, (dest & 15), (left & 15), (right & 15)); - if (dest != add) emit_dm(as, ARMI_VMOV_D, (dest & 15), (add & 15)); - return 1; - } - return 0; -} -#endif - -/* -- Calls --------------------------------------------------------------- */ - -/* Generate a call to a C function. */ -static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) -{ - uint32_t n, nargs = CCI_XNARGS(ci); - int32_t ofs = 0; -#if LJ_SOFTFP - Reg gpr = REGARG_FIRSTGPR; -#else - Reg gpr, fpr = REGARG_FIRSTFPR, fprodd = 0; -#endif - if ((void *)ci->func) - emit_call(as, (void *)ci->func); -#if !LJ_SOFTFP - for (gpr = REGARG_FIRSTGPR; gpr <= REGARG_LASTGPR; gpr++) - as->cost[gpr] = REGCOST(~0u, ASMREF_L); - gpr = REGARG_FIRSTGPR; -#endif - for (n = 0; n < nargs; n++) { /* Setup args. */ - IRRef ref = args[n]; - IRIns *ir = IR(ref); -#if !LJ_SOFTFP - if (ref && irt_isfp(ir->t)) { - RegSet of = as->freeset; - Reg src; - if (!LJ_ABI_SOFTFP && !(ci->flags & CCI_VARARG)) { - if (irt_isnum(ir->t)) { - if (fpr <= REGARG_LASTFPR) { - ra_leftov(as, fpr, ref); - fpr++; - continue; - } - } else if (fprodd) { /* Ick. */ - src = ra_alloc1(as, ref, RSET_FPR); - emit_dm(as, ARMI_VMOV_S, (fprodd & 15), (src & 15) | 0x00400000); - fprodd = 0; - continue; - } else if (fpr <= REGARG_LASTFPR) { - ra_leftov(as, fpr, ref); - fprodd = fpr++; - continue; - } - /* Workaround to protect argument GPRs from being used for remat. */ - as->freeset &= ~RSET_RANGE(REGARG_FIRSTGPR, REGARG_LASTGPR+1); - src = ra_alloc1(as, ref, RSET_FPR); /* May alloc GPR to remat FPR. */ - as->freeset |= (of & RSET_RANGE(REGARG_FIRSTGPR, REGARG_LASTGPR+1)); - fprodd = 0; - goto stackfp; - } - /* Workaround to protect argument GPRs from being used for remat. */ - as->freeset &= ~RSET_RANGE(REGARG_FIRSTGPR, REGARG_LASTGPR+1); - src = ra_alloc1(as, ref, RSET_FPR); /* May alloc GPR to remat FPR. */ - as->freeset |= (of & RSET_RANGE(REGARG_FIRSTGPR, REGARG_LASTGPR+1)); - if (irt_isnum(ir->t)) gpr = (gpr+1) & ~1u; - if (gpr <= REGARG_LASTGPR) { - lua_assert(rset_test(as->freeset, gpr)); /* Must have been evicted. */ - if (irt_isnum(ir->t)) { - lua_assert(rset_test(as->freeset, gpr+1)); /* Ditto. */ - emit_dnm(as, ARMI_VMOV_RR_D, gpr, gpr+1, (src & 15)); - gpr += 2; - } else { - emit_dn(as, ARMI_VMOV_R_S, gpr, (src & 15)); - gpr++; - } - } else { - stackfp: - if (irt_isnum(ir->t)) ofs = (ofs + 4) & ~4; - emit_spstore(as, ir, src, ofs); - ofs += irt_isnum(ir->t) ? 8 : 4; - } - } else -#endif - { - if (gpr <= REGARG_LASTGPR) { - lua_assert(rset_test(as->freeset, gpr)); /* Must have been evicted. */ - if (ref) ra_leftov(as, gpr, ref); - gpr++; - } else { - if (ref) { - Reg r = ra_alloc1(as, ref, RSET_GPR); - emit_spstore(as, ir, r, ofs); - } - ofs += 4; - } - } - } -} - -/* Setup result reg/sp for call. Evict scratch regs. */ -static void asm_setupresult(ASMState *as, IRIns *ir, const CCallInfo *ci) -{ - RegSet drop = RSET_SCRATCH; - int hiop = ((ir+1)->o == IR_HIOP && !irt_isnil((ir+1)->t)); - if (ra_hasreg(ir->r)) - rset_clear(drop, ir->r); /* Dest reg handled below. */ - if (hiop && ra_hasreg((ir+1)->r)) - rset_clear(drop, (ir+1)->r); /* Dest reg handled below. */ - ra_evictset(as, drop); /* Evictions must be performed first. */ - if (ra_used(ir)) { - lua_assert(!irt_ispri(ir->t)); - if (!LJ_SOFTFP && irt_isfp(ir->t)) { - if (LJ_ABI_SOFTFP || (ci->flags & (CCI_CASTU64|CCI_VARARG))) { - Reg dest = (ra_dest(as, ir, RSET_FPR) & 15); - if (irt_isnum(ir->t)) - emit_dnm(as, ARMI_VMOV_D_RR, RID_RETLO, RID_RETHI, dest); - else - emit_dn(as, ARMI_VMOV_S_R, RID_RET, dest); - } else { - ra_destreg(as, ir, RID_FPRET); - } - } else if (hiop) { - ra_destpair(as, ir); - } else { - ra_destreg(as, ir, RID_RET); - } - } - UNUSED(ci); -} - -static void asm_callx(ASMState *as, IRIns *ir) -{ - IRRef args[CCI_NARGS_MAX*2]; - CCallInfo ci; - IRRef func; - IRIns *irf; - ci.flags = asm_callx_flags(as, ir); - asm_collectargs(as, ir, &ci, args); - asm_setupresult(as, ir, &ci); - func = ir->op2; irf = IR(func); - if (irf->o == IR_CARG) { func = irf->op1; irf = IR(func); } - if (irref_isk(func)) { /* Call to constant address. */ - ci.func = (ASMFunction)(void *)(irf->i); - } else { /* Need a non-argument register for indirect calls. */ - Reg freg = ra_alloc1(as, func, RSET_RANGE(RID_R4, RID_R12+1)); - emit_m(as, ARMI_BLXr, freg); - ci.func = (ASMFunction)(void *)0; - } - asm_gencall(as, &ci, args); -} - -/* -- Returns ------------------------------------------------------------- */ - -/* Return to lower frame. Guard that it goes to the right spot. */ -static void asm_retf(ASMState *as, IRIns *ir) -{ - Reg base = ra_alloc1(as, REF_BASE, RSET_GPR); - void *pc = ir_kptr(IR(ir->op2)); - int32_t delta = 1+LJ_FR2+bc_a(*((const BCIns *)pc - 1)); - as->topslot -= (BCReg)delta; - if ((int32_t)as->topslot < 0) as->topslot = 0; - irt_setmark(IR(REF_BASE)->t); /* Children must not coalesce with BASE reg. */ - /* Need to force a spill on REF_BASE now to update the stack slot. */ - emit_lso(as, ARMI_STR, base, RID_SP, ra_spill(as, IR(REF_BASE))); - emit_setgl(as, base, jit_base); - emit_addptr(as, base, -8*delta); - asm_guardcc(as, CC_NE); - emit_nm(as, ARMI_CMP, RID_TMP, - ra_allock(as, i32ptr(pc), rset_exclude(RSET_GPR, base))); - emit_lso(as, ARMI_LDR, RID_TMP, base, -4); -} - -/* -- Type conversions ---------------------------------------------------- */ - -#if !LJ_SOFTFP -static void asm_tointg(ASMState *as, IRIns *ir, Reg left) -{ - Reg tmp = ra_scratch(as, rset_exclude(RSET_FPR, left)); - Reg dest = ra_dest(as, ir, RSET_GPR); - asm_guardcc(as, CC_NE); - emit_d(as, ARMI_VMRS, 0); - emit_dm(as, ARMI_VCMP_D, (tmp & 15), (left & 15)); - emit_dm(as, ARMI_VCVT_F64_S32, (tmp & 15), (tmp & 15)); - emit_dn(as, ARMI_VMOV_R_S, dest, (tmp & 15)); - emit_dm(as, ARMI_VCVT_S32_F64, (tmp & 15), (left & 15)); -} - -static void asm_tobit(ASMState *as, IRIns *ir) -{ - RegSet allow = RSET_FPR; - Reg left = ra_alloc1(as, ir->op1, allow); - Reg right = ra_alloc1(as, ir->op2, rset_clear(allow, left)); - Reg tmp = ra_scratch(as, rset_clear(allow, right)); - Reg dest = ra_dest(as, ir, RSET_GPR); - emit_dn(as, ARMI_VMOV_R_S, dest, (tmp & 15)); - emit_dnm(as, ARMI_VADD_D, (tmp & 15), (left & 15), (right & 15)); -} -#endif - -static void asm_conv(ASMState *as, IRIns *ir) -{ - IRType st = (IRType)(ir->op2 & IRCONV_SRCMASK); -#if !LJ_SOFTFP - int stfp = (st == IRT_NUM || st == IRT_FLOAT); -#endif - IRRef lref = ir->op1; - /* 64 bit integer conversions are handled by SPLIT. */ - lua_assert(!irt_isint64(ir->t) && !(st == IRT_I64 || st == IRT_U64)); -#if LJ_SOFTFP - /* FP conversions are handled by SPLIT. */ - lua_assert(!irt_isfp(ir->t) && !(st == IRT_NUM || st == IRT_FLOAT)); - /* Can't check for same types: SPLIT uses CONV int.int + BXOR for sfp NEG. */ -#else - lua_assert(irt_type(ir->t) != st); - if (irt_isfp(ir->t)) { - Reg dest = ra_dest(as, ir, RSET_FPR); - if (stfp) { /* FP to FP conversion. */ - emit_dm(as, st == IRT_NUM ? ARMI_VCVT_F32_F64 : ARMI_VCVT_F64_F32, - (dest & 15), (ra_alloc1(as, lref, RSET_FPR) & 15)); - } else { /* Integer to FP conversion. */ - Reg left = ra_alloc1(as, lref, RSET_GPR); - ARMIns ai = irt_isfloat(ir->t) ? - (st == IRT_INT ? ARMI_VCVT_F32_S32 : ARMI_VCVT_F32_U32) : - (st == IRT_INT ? ARMI_VCVT_F64_S32 : ARMI_VCVT_F64_U32); - emit_dm(as, ai, (dest & 15), (dest & 15)); - emit_dn(as, ARMI_VMOV_S_R, left, (dest & 15)); - } - } else if (stfp) { /* FP to integer conversion. */ - if (irt_isguard(ir->t)) { - /* Checked conversions are only supported from number to int. */ - lua_assert(irt_isint(ir->t) && st == IRT_NUM); - asm_tointg(as, ir, ra_alloc1(as, lref, RSET_FPR)); - } else { - Reg left = ra_alloc1(as, lref, RSET_FPR); - Reg tmp = ra_scratch(as, rset_exclude(RSET_FPR, left)); - Reg dest = ra_dest(as, ir, RSET_GPR); - ARMIns ai; - emit_dn(as, ARMI_VMOV_R_S, dest, (tmp & 15)); - ai = irt_isint(ir->t) ? - (st == IRT_NUM ? ARMI_VCVT_S32_F64 : ARMI_VCVT_S32_F32) : - (st == IRT_NUM ? ARMI_VCVT_U32_F64 : ARMI_VCVT_U32_F32); - emit_dm(as, ai, (tmp & 15), (left & 15)); - } - } else -#endif - { - Reg dest = ra_dest(as, ir, RSET_GPR); - if (st >= IRT_I8 && st <= IRT_U16) { /* Extend to 32 bit integer. */ - Reg left = ra_alloc1(as, lref, RSET_GPR); - lua_assert(irt_isint(ir->t) || irt_isu32(ir->t)); - if ((as->flags & JIT_F_ARMV6)) { - ARMIns ai = st == IRT_I8 ? ARMI_SXTB : - st == IRT_U8 ? ARMI_UXTB : - st == IRT_I16 ? ARMI_SXTH : ARMI_UXTH; - emit_dm(as, ai, dest, left); - } else if (st == IRT_U8) { - emit_dn(as, ARMI_AND|ARMI_K12|255, dest, left); - } else { - uint32_t shift = st == IRT_I8 ? 24 : 16; - ARMShift sh = st == IRT_U16 ? ARMSH_LSR : ARMSH_ASR; - emit_dm(as, ARMI_MOV|ARMF_SH(sh, shift), dest, RID_TMP); - emit_dm(as, ARMI_MOV|ARMF_SH(ARMSH_LSL, shift), RID_TMP, left); - } - } else { /* Handle 32/32 bit no-op (cast). */ - ra_leftov(as, dest, lref); /* Do nothing, but may need to move regs. */ - } - } -} - -static void asm_strto(ASMState *as, IRIns *ir) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_strscan_num]; - IRRef args[2]; - Reg rlo = 0, rhi = 0, tmp; - int destused = ra_used(ir); - int32_t ofs = 0; - ra_evictset(as, RSET_SCRATCH); -#if LJ_SOFTFP - if (destused) { - if (ra_hasspill(ir->s) && ra_hasspill((ir+1)->s) && - (ir->s & 1) == 0 && ir->s + 1 == (ir+1)->s) { - int i; - for (i = 0; i < 2; i++) { - Reg r = (ir+i)->r; - if (ra_hasreg(r)) { - ra_free(as, r); - ra_modified(as, r); - emit_spload(as, ir+i, r, sps_scale((ir+i)->s)); - } - } - ofs = sps_scale(ir->s); - destused = 0; - } else { - rhi = ra_dest(as, ir+1, RSET_GPR); - rlo = ra_dest(as, ir, rset_exclude(RSET_GPR, rhi)); - } - } - asm_guardcc(as, CC_EQ); - if (destused) { - emit_lso(as, ARMI_LDR, rhi, RID_SP, 4); - emit_lso(as, ARMI_LDR, rlo, RID_SP, 0); - } -#else - UNUSED(rhi); - if (destused) { - if (ra_hasspill(ir->s)) { - ofs = sps_scale(ir->s); - destused = 0; - if (ra_hasreg(ir->r)) { - ra_free(as, ir->r); - ra_modified(as, ir->r); - emit_spload(as, ir, ir->r, ofs); - } - } else { - rlo = ra_dest(as, ir, RSET_FPR); - } - } - asm_guardcc(as, CC_EQ); - if (destused) - emit_vlso(as, ARMI_VLDR_D, rlo, RID_SP, 0); -#endif - emit_n(as, ARMI_CMP|ARMI_K12|0, RID_RET); /* Test return status. */ - args[0] = ir->op1; /* GCstr *str */ - args[1] = ASMREF_TMP1; /* TValue *n */ - asm_gencall(as, ci, args); - tmp = ra_releasetmp(as, ASMREF_TMP1); - if (ofs == 0) - emit_dm(as, ARMI_MOV, tmp, RID_SP); - else - emit_opk(as, ARMI_ADD, tmp, RID_SP, ofs, RSET_GPR); -} - -/* -- Memory references --------------------------------------------------- */ - -/* Get pointer to TValue. */ -static void asm_tvptr(ASMState *as, Reg dest, IRRef ref) -{ - IRIns *ir = IR(ref); - if (irt_isnum(ir->t)) { - if (irref_isk(ref)) { - /* Use the number constant itself as a TValue. */ - ra_allockreg(as, i32ptr(ir_knum(ir)), dest); - } else { -#if LJ_SOFTFP - lua_assert(0); -#else - /* Otherwise force a spill and use the spill slot. */ - emit_opk(as, ARMI_ADD, dest, RID_SP, ra_spill(as, ir), RSET_GPR); -#endif - } - } else { - /* Otherwise use [sp] and [sp+4] to hold the TValue. */ - RegSet allow = rset_exclude(RSET_GPR, dest); - Reg type; - emit_dm(as, ARMI_MOV, dest, RID_SP); - if (!irt_ispri(ir->t)) { - Reg src = ra_alloc1(as, ref, allow); - emit_lso(as, ARMI_STR, src, RID_SP, 0); - } - if (LJ_SOFTFP && (ir+1)->o == IR_HIOP) - type = ra_alloc1(as, ref+1, allow); - else - type = ra_allock(as, irt_toitype(ir->t), allow); - emit_lso(as, ARMI_STR, type, RID_SP, 4); - } -} - -static void asm_aref(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg idx, base; - if (irref_isk(ir->op2)) { - IRRef tab = IR(ir->op1)->op1; - int32_t ofs = asm_fuseabase(as, tab); - IRRef refa = ofs ? tab : ir->op1; - uint32_t k = emit_isk12(ARMI_ADD, ofs + 8*IR(ir->op2)->i); - if (k) { - base = ra_alloc1(as, refa, RSET_GPR); - emit_dn(as, ARMI_ADD^k, dest, base); - return; - } - } - base = ra_alloc1(as, ir->op1, RSET_GPR); - idx = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, base)); - emit_dnm(as, ARMI_ADD|ARMF_SH(ARMSH_LSL, 3), dest, base, idx); -} - -/* Inlined hash lookup. Specialized for key type and for const keys. -** The equivalent C code is: -** Node *n = hashkey(t, key); -** do { -** if (lj_obj_equal(&n->key, key)) return &n->val; -** } while ((n = nextnode(n))); -** return niltv(L); -*/ -static void asm_href(ASMState *as, IRIns *ir, IROp merge) -{ - RegSet allow = RSET_GPR; - int destused = ra_used(ir); - Reg dest = ra_dest(as, ir, allow); - Reg tab = ra_alloc1(as, ir->op1, rset_clear(allow, dest)); - Reg key = 0, keyhi = 0, keynumhi = RID_NONE, tmp = RID_TMP; - IRRef refkey = ir->op2; - IRIns *irkey = IR(refkey); - IRType1 kt = irkey->t; - int32_t k = 0, khi = emit_isk12(ARMI_CMP, irt_toitype(kt)); - uint32_t khash; - MCLabel l_end, l_loop; - rset_clear(allow, tab); - if (!irref_isk(refkey) || irt_isstr(kt)) { -#if LJ_SOFTFP - key = ra_alloc1(as, refkey, allow); - rset_clear(allow, key); - if (irkey[1].o == IR_HIOP) { - if (ra_hasreg((irkey+1)->r)) { - keynumhi = (irkey+1)->r; - keyhi = RID_TMP; - ra_noweak(as, keynumhi); - } else { - keyhi = keynumhi = ra_allocref(as, refkey+1, allow); - } - rset_clear(allow, keynumhi); - khi = 0; - } -#else - if (irt_isnum(kt)) { - key = ra_scratch(as, allow); - rset_clear(allow, key); - keyhi = keynumhi = ra_scratch(as, allow); - rset_clear(allow, keyhi); - khi = 0; - } else { - key = ra_alloc1(as, refkey, allow); - rset_clear(allow, key); - } -#endif - } else if (irt_isnum(kt)) { - int32_t val = (int32_t)ir_knum(irkey)->u32.lo; - k = emit_isk12(ARMI_CMP, val); - if (!k) { - key = ra_allock(as, val, allow); - rset_clear(allow, key); - } - val = (int32_t)ir_knum(irkey)->u32.hi; - khi = emit_isk12(ARMI_CMP, val); - if (!khi) { - keyhi = ra_allock(as, val, allow); - rset_clear(allow, keyhi); - } - } else if (!irt_ispri(kt)) { - k = emit_isk12(ARMI_CMP, irkey->i); - if (!k) { - key = ra_alloc1(as, refkey, allow); - rset_clear(allow, key); - } - } - if (!irt_ispri(kt)) - tmp = ra_scratchpair(as, allow); - - /* Key not found in chain: jump to exit (if merged) or load niltv. */ - l_end = emit_label(as); - as->invmcp = NULL; - if (merge == IR_NE) - asm_guardcc(as, CC_AL); - else if (destused) - emit_loada(as, dest, niltvg(J2G(as->J))); - - /* Follow hash chain until the end. */ - l_loop = --as->mcp; - emit_n(as, ARMI_CMP|ARMI_K12|0, dest); - emit_lso(as, ARMI_LDR, dest, dest, (int32_t)offsetof(Node, next)); - - /* Type and value comparison. */ - if (merge == IR_EQ) - asm_guardcc(as, CC_EQ); - else - emit_branch(as, ARMF_CC(ARMI_B, CC_EQ), l_end); - if (!irt_ispri(kt)) { - emit_nm(as, ARMF_CC(ARMI_CMP, CC_EQ)^k, tmp, key); - emit_nm(as, ARMI_CMP^khi, tmp+1, keyhi); - emit_lsox(as, ARMI_LDRD, tmp, dest, (int32_t)offsetof(Node, key)); - } else { - emit_n(as, ARMI_CMP^khi, tmp); - emit_lso(as, ARMI_LDR, tmp, dest, (int32_t)offsetof(Node, key.it)); - } - *l_loop = ARMF_CC(ARMI_B, CC_NE) | ((as->mcp-l_loop-2) & 0x00ffffffu); - - /* Load main position relative to tab->node into dest. */ - khash = irref_isk(refkey) ? ir_khash(irkey) : 1; - if (khash == 0) { - emit_lso(as, ARMI_LDR, dest, tab, (int32_t)offsetof(GCtab, node)); - } else { - emit_dnm(as, ARMI_ADD|ARMF_SH(ARMSH_LSL, 3), dest, dest, tmp); - emit_dnm(as, ARMI_ADD|ARMF_SH(ARMSH_LSL, 1), tmp, tmp, tmp); - if (irt_isstr(kt)) { /* Fetch of str->hash is cheaper than ra_allock. */ - emit_dnm(as, ARMI_AND, tmp, tmp+1, RID_TMP); - emit_lso(as, ARMI_LDR, dest, tab, (int32_t)offsetof(GCtab, node)); - emit_lso(as, ARMI_LDR, tmp+1, key, (int32_t)offsetof(GCstr, hash)); - emit_lso(as, ARMI_LDR, RID_TMP, tab, (int32_t)offsetof(GCtab, hmask)); - } else if (irref_isk(refkey)) { - emit_opk(as, ARMI_AND, tmp, RID_TMP, (int32_t)khash, - rset_exclude(rset_exclude(RSET_GPR, tab), dest)); - emit_lso(as, ARMI_LDR, dest, tab, (int32_t)offsetof(GCtab, node)); - emit_lso(as, ARMI_LDR, RID_TMP, tab, (int32_t)offsetof(GCtab, hmask)); - } else { /* Must match with hash*() in lj_tab.c. */ - if (ra_hasreg(keynumhi)) { /* Canonicalize +-0.0 to 0.0. */ - if (keyhi == RID_TMP) - emit_dm(as, ARMF_CC(ARMI_MOV, CC_NE), keyhi, keynumhi); - emit_d(as, ARMF_CC(ARMI_MOV, CC_EQ)|ARMI_K12|0, keyhi); - } - emit_dnm(as, ARMI_AND, tmp, tmp, RID_TMP); - emit_dnm(as, ARMI_SUB|ARMF_SH(ARMSH_ROR, 32-HASH_ROT3), tmp, tmp, tmp+1); - emit_lso(as, ARMI_LDR, dest, tab, (int32_t)offsetof(GCtab, node)); - emit_dnm(as, ARMI_EOR|ARMF_SH(ARMSH_ROR, 32-((HASH_ROT2+HASH_ROT1)&31)), - tmp, tmp+1, tmp); - emit_lso(as, ARMI_LDR, RID_TMP, tab, (int32_t)offsetof(GCtab, hmask)); - emit_dnm(as, ARMI_SUB|ARMF_SH(ARMSH_ROR, 32-HASH_ROT1), tmp+1, tmp+1, tmp); - if (ra_hasreg(keynumhi)) { - emit_dnm(as, ARMI_EOR, tmp+1, tmp, key); - emit_dnm(as, ARMI_ORR|ARMI_S, RID_TMP, tmp, key); /* Test for +-0.0. */ - emit_dnm(as, ARMI_ADD, tmp, keynumhi, keynumhi); -#if !LJ_SOFTFP - emit_dnm(as, ARMI_VMOV_RR_D, key, keynumhi, - (ra_alloc1(as, refkey, RSET_FPR) & 15)); -#endif - } else { - emit_dnm(as, ARMI_EOR, tmp+1, tmp, key); - emit_opk(as, ARMI_ADD, tmp, key, (int32_t)HASH_BIAS, - rset_exclude(rset_exclude(RSET_GPR, tab), key)); - } - } - } -} - -static void asm_hrefk(ASMState *as, IRIns *ir) -{ - IRIns *kslot = IR(ir->op2); - IRIns *irkey = IR(kslot->op1); - int32_t ofs = (int32_t)(kslot->op2 * sizeof(Node)); - int32_t kofs = ofs + (int32_t)offsetof(Node, key); - Reg dest = (ra_used(ir) || ofs > 4095) ? ra_dest(as, ir, RSET_GPR) : RID_NONE; - Reg node = ra_alloc1(as, ir->op1, RSET_GPR); - Reg key = RID_NONE, type = RID_TMP, idx = node; - RegSet allow = rset_exclude(RSET_GPR, node); - lua_assert(ofs % sizeof(Node) == 0); - if (ofs > 4095) { - idx = dest; - rset_clear(allow, dest); - kofs = (int32_t)offsetof(Node, key); - } else if (ra_hasreg(dest)) { - emit_opk(as, ARMI_ADD, dest, node, ofs, allow); - } - asm_guardcc(as, CC_NE); - if (!irt_ispri(irkey->t)) { - RegSet even = (as->freeset & allow); - even = even & (even >> 1) & RSET_GPREVEN; - if (even) { - key = ra_scratch(as, even); - if (rset_test(as->freeset, key+1)) { - type = key+1; - ra_modified(as, type); - } - } else { - key = ra_scratch(as, allow); - } - rset_clear(allow, key); - } - rset_clear(allow, type); - if (irt_isnum(irkey->t)) { - emit_opk(as, ARMF_CC(ARMI_CMP, CC_EQ), 0, type, - (int32_t)ir_knum(irkey)->u32.hi, allow); - emit_opk(as, ARMI_CMP, 0, key, - (int32_t)ir_knum(irkey)->u32.lo, allow); - } else { - if (ra_hasreg(key)) - emit_opk(as, ARMF_CC(ARMI_CMP, CC_EQ), 0, key, irkey->i, allow); - emit_n(as, ARMI_CMN|ARMI_K12|-irt_toitype(irkey->t), type); - } - emit_lso(as, ARMI_LDR, type, idx, kofs+4); - if (ra_hasreg(key)) emit_lso(as, ARMI_LDR, key, idx, kofs); - if (ofs > 4095) - emit_opk(as, ARMI_ADD, dest, node, ofs, RSET_GPR); -} - -static void asm_uref(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - if (irref_isk(ir->op1)) { - GCfunc *fn = ir_kfunc(IR(ir->op1)); - MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v; - emit_lsptr(as, ARMI_LDR, dest, v); - } else { - Reg uv = ra_scratch(as, RSET_GPR); - Reg func = ra_alloc1(as, ir->op1, RSET_GPR); - if (ir->o == IR_UREFC) { - asm_guardcc(as, CC_NE); - emit_n(as, ARMI_CMP|ARMI_K12|1, RID_TMP); - emit_opk(as, ARMI_ADD, dest, uv, - (int32_t)offsetof(GCupval, tv), RSET_GPR); - emit_lso(as, ARMI_LDRB, RID_TMP, uv, (int32_t)offsetof(GCupval, closed)); - } else { - emit_lso(as, ARMI_LDR, dest, uv, (int32_t)offsetof(GCupval, v)); - } - emit_lso(as, ARMI_LDR, uv, func, - (int32_t)offsetof(GCfuncL, uvptr) + 4*(int32_t)(ir->op2 >> 8)); - } -} - -static void asm_fref(ASMState *as, IRIns *ir) -{ - UNUSED(as); UNUSED(ir); - lua_assert(!ra_used(ir)); -} - -static void asm_strref(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - IRRef ref = ir->op2, refk = ir->op1; - Reg r; - if (irref_isk(ref)) { - IRRef tmp = refk; refk = ref; ref = tmp; - } else if (!irref_isk(refk)) { - uint32_t k, m = ARMI_K12|sizeof(GCstr); - Reg right, left = ra_alloc1(as, ir->op1, RSET_GPR); - IRIns *irr = IR(ir->op2); - if (ra_hasreg(irr->r)) { - ra_noweak(as, irr->r); - right = irr->r; - } else if (mayfuse(as, irr->op2) && - irr->o == IR_ADD && irref_isk(irr->op2) && - (k = emit_isk12(ARMI_ADD, - (int32_t)sizeof(GCstr) + IR(irr->op2)->i))) { - m = k; - right = ra_alloc1(as, irr->op1, rset_exclude(RSET_GPR, left)); - } else { - right = ra_allocref(as, ir->op2, rset_exclude(RSET_GPR, left)); - } - emit_dn(as, ARMI_ADD^m, dest, dest); - emit_dnm(as, ARMI_ADD, dest, left, right); - return; - } - r = ra_alloc1(as, ref, RSET_GPR); - emit_opk(as, ARMI_ADD, dest, r, - sizeof(GCstr) + IR(refk)->i, rset_exclude(RSET_GPR, r)); -} - -/* -- Loads and stores ---------------------------------------------------- */ - -static ARMIns asm_fxloadins(IRIns *ir) -{ - switch (irt_type(ir->t)) { - case IRT_I8: return ARMI_LDRSB; - case IRT_U8: return ARMI_LDRB; - case IRT_I16: return ARMI_LDRSH; - case IRT_U16: return ARMI_LDRH; - case IRT_NUM: lua_assert(!LJ_SOFTFP); return ARMI_VLDR_D; - case IRT_FLOAT: if (!LJ_SOFTFP) return ARMI_VLDR_S; - default: return ARMI_LDR; - } -} - -static ARMIns asm_fxstoreins(IRIns *ir) -{ - switch (irt_type(ir->t)) { - case IRT_I8: case IRT_U8: return ARMI_STRB; - case IRT_I16: case IRT_U16: return ARMI_STRH; - case IRT_NUM: lua_assert(!LJ_SOFTFP); return ARMI_VSTR_D; - case IRT_FLOAT: if (!LJ_SOFTFP) return ARMI_VSTR_S; - default: return ARMI_STR; - } -} - -static void asm_fload(ASMState *as, IRIns *ir) -{ - if (ir->op1 == REF_NIL) { - lua_assert(!ra_used(ir)); /* We can end up here if DCE is turned off. */ - } else { - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg idx = ra_alloc1(as, ir->op1, RSET_GPR); - ARMIns ai = asm_fxloadins(ir); - int32_t ofs; - if (ir->op2 == IRFL_TAB_ARRAY) { - ofs = asm_fuseabase(as, ir->op1); - if (ofs) { /* Turn the t->array load into an add for colocated arrays. */ - emit_dn(as, ARMI_ADD|ARMI_K12|ofs, dest, idx); - return; - } - } - ofs = field_ofs[ir->op2]; - if ((ai & 0x04000000)) - emit_lso(as, ai, dest, idx, ofs); - else - emit_lsox(as, ai, dest, idx, ofs); - } -} - -static void asm_fstore(ASMState *as, IRIns *ir) -{ - if (ir->r != RID_SINK) { - Reg src = ra_alloc1(as, ir->op2, RSET_GPR); - IRIns *irf = IR(ir->op1); - Reg idx = ra_alloc1(as, irf->op1, rset_exclude(RSET_GPR, src)); - int32_t ofs = field_ofs[irf->op2]; - ARMIns ai = asm_fxstoreins(ir); - if ((ai & 0x04000000)) - emit_lso(as, ai, src, idx, ofs); - else - emit_lsox(as, ai, src, idx, ofs); - } -} - -static void asm_xload(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, - (!LJ_SOFTFP && irt_isfp(ir->t)) ? RSET_FPR : RSET_GPR); - lua_assert(!(ir->op2 & IRXLOAD_UNALIGNED)); - asm_fusexref(as, asm_fxloadins(ir), dest, ir->op1, RSET_GPR, 0); -} - -static void asm_xstore_(ASMState *as, IRIns *ir, int32_t ofs) -{ - if (ir->r != RID_SINK) { - Reg src = ra_alloc1(as, ir->op2, - (!LJ_SOFTFP && irt_isfp(ir->t)) ? RSET_FPR : RSET_GPR); - asm_fusexref(as, asm_fxstoreins(ir), src, ir->op1, - rset_exclude(RSET_GPR, src), ofs); - } -} - -#define asm_xstore(as, ir) asm_xstore_(as, ir, 0) - -static void asm_ahuvload(ASMState *as, IRIns *ir) -{ - int hiop = (LJ_SOFTFP && (ir+1)->o == IR_HIOP); - IRType t = hiop ? IRT_NUM : irt_type(ir->t); - Reg dest = RID_NONE, type = RID_NONE, idx; - RegSet allow = RSET_GPR; - int32_t ofs = 0; - if (hiop && ra_used(ir+1)) { - type = ra_dest(as, ir+1, allow); - rset_clear(allow, type); - } - if (ra_used(ir)) { - lua_assert((LJ_SOFTFP ? 0 : irt_isnum(ir->t)) || - irt_isint(ir->t) || irt_isaddr(ir->t)); - dest = ra_dest(as, ir, (!LJ_SOFTFP && t == IRT_NUM) ? RSET_FPR : allow); - rset_clear(allow, dest); - } - idx = asm_fuseahuref(as, ir->op1, &ofs, allow, - (!LJ_SOFTFP && t == IRT_NUM) ? 1024 : 4096); - if (!hiop || type == RID_NONE) { - rset_clear(allow, idx); - if (ofs < 256 && ra_hasreg(dest) && (dest & 1) == 0 && - rset_test((as->freeset & allow), dest+1)) { - type = dest+1; - ra_modified(as, type); - } else { - type = RID_TMP; - } - } - asm_guardcc(as, t == IRT_NUM ? CC_HS : CC_NE); - emit_n(as, ARMI_CMN|ARMI_K12|-irt_toitype_(t), type); - if (ra_hasreg(dest)) { -#if !LJ_SOFTFP - if (t == IRT_NUM) - emit_vlso(as, ARMI_VLDR_D, dest, idx, ofs); - else -#endif - emit_lso(as, ARMI_LDR, dest, idx, ofs); - } - emit_lso(as, ARMI_LDR, type, idx, ofs+4); -} - -static void asm_ahustore(ASMState *as, IRIns *ir) -{ - if (ir->r != RID_SINK) { - RegSet allow = RSET_GPR; - Reg idx, src = RID_NONE, type = RID_NONE; - int32_t ofs = 0; -#if !LJ_SOFTFP - if (irt_isnum(ir->t)) { - src = ra_alloc1(as, ir->op2, RSET_FPR); - idx = asm_fuseahuref(as, ir->op1, &ofs, allow, 1024); - emit_vlso(as, ARMI_VSTR_D, src, idx, ofs); - } else -#endif - { - int hiop = (LJ_SOFTFP && (ir+1)->o == IR_HIOP); - if (!irt_ispri(ir->t)) { - src = ra_alloc1(as, ir->op2, allow); - rset_clear(allow, src); - } - if (hiop) - type = ra_alloc1(as, (ir+1)->op2, allow); - else - type = ra_allock(as, (int32_t)irt_toitype(ir->t), allow); - idx = asm_fuseahuref(as, ir->op1, &ofs, rset_exclude(allow, type), 4096); - if (ra_hasreg(src)) emit_lso(as, ARMI_STR, src, idx, ofs); - emit_lso(as, ARMI_STR, type, idx, ofs+4); - } - } -} - -static void asm_sload(ASMState *as, IRIns *ir) -{ - int32_t ofs = 8*((int32_t)ir->op1-1) + ((ir->op2 & IRSLOAD_FRAME) ? 4 : 0); - int hiop = (LJ_SOFTFP && (ir+1)->o == IR_HIOP); - IRType t = hiop ? IRT_NUM : irt_type(ir->t); - Reg dest = RID_NONE, type = RID_NONE, base; - RegSet allow = RSET_GPR; - lua_assert(!(ir->op2 & IRSLOAD_PARENT)); /* Handled by asm_head_side(). */ - lua_assert(irt_isguard(ir->t) || !(ir->op2 & IRSLOAD_TYPECHECK)); -#if LJ_SOFTFP - lua_assert(!(ir->op2 & IRSLOAD_CONVERT)); /* Handled by LJ_SOFTFP SPLIT. */ - if (hiop && ra_used(ir+1)) { - type = ra_dest(as, ir+1, allow); - rset_clear(allow, type); - } -#else - if ((ir->op2 & IRSLOAD_CONVERT) && irt_isguard(ir->t) && t == IRT_INT) { - dest = ra_scratch(as, RSET_FPR); - asm_tointg(as, ir, dest); - t = IRT_NUM; /* Continue with a regular number type check. */ - } else -#endif - if (ra_used(ir)) { - Reg tmp = RID_NONE; - if ((ir->op2 & IRSLOAD_CONVERT)) - tmp = ra_scratch(as, t == IRT_INT ? RSET_FPR : RSET_GPR); - lua_assert((LJ_SOFTFP ? 0 : irt_isnum(ir->t)) || - irt_isint(ir->t) || irt_isaddr(ir->t)); - dest = ra_dest(as, ir, (!LJ_SOFTFP && t == IRT_NUM) ? RSET_FPR : allow); - rset_clear(allow, dest); - base = ra_alloc1(as, REF_BASE, allow); - if ((ir->op2 & IRSLOAD_CONVERT)) { - if (t == IRT_INT) { - emit_dn(as, ARMI_VMOV_R_S, dest, (tmp & 15)); - emit_dm(as, ARMI_VCVT_S32_F64, (tmp & 15), (tmp & 15)); - t = IRT_NUM; /* Check for original type. */ - } else { - emit_dm(as, ARMI_VCVT_F64_S32, (dest & 15), (dest & 15)); - emit_dn(as, ARMI_VMOV_S_R, tmp, (dest & 15)); - t = IRT_INT; /* Check for original type. */ - } - dest = tmp; - } - goto dotypecheck; - } - base = ra_alloc1(as, REF_BASE, allow); -dotypecheck: - rset_clear(allow, base); - if ((ir->op2 & IRSLOAD_TYPECHECK)) { - if (ra_noreg(type)) { - if (ofs < 256 && ra_hasreg(dest) && (dest & 1) == 0 && - rset_test((as->freeset & allow), dest+1)) { - type = dest+1; - ra_modified(as, type); - } else { - type = RID_TMP; - } - } - asm_guardcc(as, t == IRT_NUM ? CC_HS : CC_NE); - emit_n(as, ARMI_CMN|ARMI_K12|-irt_toitype_(t), type); - } - if (ra_hasreg(dest)) { -#if !LJ_SOFTFP - if (t == IRT_NUM) { - if (ofs < 1024) { - emit_vlso(as, ARMI_VLDR_D, dest, base, ofs); - } else { - if (ra_hasreg(type)) emit_lso(as, ARMI_LDR, type, base, ofs+4); - emit_vlso(as, ARMI_VLDR_D, dest, RID_TMP, 0); - emit_opk(as, ARMI_ADD, RID_TMP, base, ofs, allow); - return; - } - } else -#endif - emit_lso(as, ARMI_LDR, dest, base, ofs); - } - if (ra_hasreg(type)) emit_lso(as, ARMI_LDR, type, base, ofs+4); -} - -/* -- Allocations --------------------------------------------------------- */ - -#if LJ_HASFFI -static void asm_cnew(ASMState *as, IRIns *ir) -{ - CTState *cts = ctype_ctsG(J2G(as->J)); - CTypeID id = (CTypeID)IR(ir->op1)->i; - CTSize sz; - CTInfo info = lj_ctype_info(cts, id, &sz); - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_mem_newgco]; - IRRef args[4]; - RegSet allow = (RSET_GPR & ~RSET_SCRATCH); - RegSet drop = RSET_SCRATCH; - lua_assert(sz != CTSIZE_INVALID || (ir->o == IR_CNEW && ir->op2 != REF_NIL)); - - as->gcsteps++; - if (ra_hasreg(ir->r)) - rset_clear(drop, ir->r); /* Dest reg handled below. */ - ra_evictset(as, drop); - if (ra_used(ir)) - ra_destreg(as, ir, RID_RET); /* GCcdata * */ - - /* Initialize immutable cdata object. */ - if (ir->o == IR_CNEWI) { - int32_t ofs = sizeof(GCcdata); - lua_assert(sz == 4 || sz == 8); - if (sz == 8) { - ofs += 4; ir++; - lua_assert(ir->o == IR_HIOP); - } - for (;;) { - Reg r = ra_alloc1(as, ir->op2, allow); - emit_lso(as, ARMI_STR, r, RID_RET, ofs); - rset_clear(allow, r); - if (ofs == sizeof(GCcdata)) break; - ofs -= 4; ir--; - } - } else if (ir->op2 != REF_NIL) { /* Create VLA/VLS/aligned cdata. */ - ci = &lj_ir_callinfo[IRCALL_lj_cdata_newv]; - args[0] = ASMREF_L; /* lua_State *L */ - args[1] = ir->op1; /* CTypeID id */ - args[2] = ir->op2; /* CTSize sz */ - args[3] = ASMREF_TMP1; /* CTSize align */ - asm_gencall(as, ci, args); - emit_loadi(as, ra_releasetmp(as, ASMREF_TMP1), (int32_t)ctype_align(info)); - return; - } - - /* Initialize gct and ctypeid. lj_mem_newgco() already sets marked. */ - { - uint32_t k = emit_isk12(ARMI_MOV, id); - Reg r = k ? RID_R1 : ra_allock(as, id, allow); - emit_lso(as, ARMI_STRB, RID_TMP, RID_RET, offsetof(GCcdata, gct)); - emit_lsox(as, ARMI_STRH, r, RID_RET, offsetof(GCcdata, ctypeid)); - emit_d(as, ARMI_MOV|ARMI_K12|~LJ_TCDATA, RID_TMP); - if (k) emit_d(as, ARMI_MOV^k, RID_R1); - } - args[0] = ASMREF_L; /* lua_State *L */ - args[1] = ASMREF_TMP1; /* MSize size */ - asm_gencall(as, ci, args); - ra_allockreg(as, (int32_t)(sz+sizeof(GCcdata)), - ra_releasetmp(as, ASMREF_TMP1)); -} -#else -#define asm_cnew(as, ir) ((void)0) -#endif - -/* -- Write barriers ------------------------------------------------------ */ - -static void asm_tbar(ASMState *as, IRIns *ir) -{ - Reg tab = ra_alloc1(as, ir->op1, RSET_GPR); - Reg link = ra_scratch(as, rset_exclude(RSET_GPR, tab)); - Reg gr = ra_allock(as, i32ptr(J2G(as->J)), - rset_exclude(rset_exclude(RSET_GPR, tab), link)); - Reg mark = RID_TMP; - MCLabel l_end = emit_label(as); - emit_lso(as, ARMI_STR, link, tab, (int32_t)offsetof(GCtab, gclist)); - emit_lso(as, ARMI_STRB, mark, tab, (int32_t)offsetof(GCtab, marked)); - emit_lso(as, ARMI_STR, tab, gr, - (int32_t)offsetof(global_State, gc.grayagain)); - emit_dn(as, ARMI_BIC|ARMI_K12|LJ_GC_BLACK, mark, mark); - emit_lso(as, ARMI_LDR, link, gr, - (int32_t)offsetof(global_State, gc.grayagain)); - emit_branch(as, ARMF_CC(ARMI_B, CC_EQ), l_end); - emit_n(as, ARMI_TST|ARMI_K12|LJ_GC_BLACK, mark); - emit_lso(as, ARMI_LDRB, mark, tab, (int32_t)offsetof(GCtab, marked)); -} - -static void asm_obar(ASMState *as, IRIns *ir) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_gc_barrieruv]; - IRRef args[2]; - MCLabel l_end; - Reg obj, val, tmp; - /* No need for other object barriers (yet). */ - lua_assert(IR(ir->op1)->o == IR_UREFC); - ra_evictset(as, RSET_SCRATCH); - l_end = emit_label(as); - args[0] = ASMREF_TMP1; /* global_State *g */ - args[1] = ir->op1; /* TValue *tv */ - asm_gencall(as, ci, args); - if ((l_end[-1] >> 28) == CC_AL) - l_end[-1] = ARMF_CC(l_end[-1], CC_NE); - else - emit_branch(as, ARMF_CC(ARMI_B, CC_EQ), l_end); - ra_allockreg(as, i32ptr(J2G(as->J)), ra_releasetmp(as, ASMREF_TMP1)); - obj = IR(ir->op1)->r; - tmp = ra_scratch(as, rset_exclude(RSET_GPR, obj)); - emit_n(as, ARMF_CC(ARMI_TST, CC_NE)|ARMI_K12|LJ_GC_BLACK, tmp); - emit_n(as, ARMI_TST|ARMI_K12|LJ_GC_WHITES, RID_TMP); - val = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, obj)); - emit_lso(as, ARMI_LDRB, tmp, obj, - (int32_t)offsetof(GCupval, marked)-(int32_t)offsetof(GCupval, tv)); - emit_lso(as, ARMI_LDRB, RID_TMP, val, (int32_t)offsetof(GChead, marked)); -} - -/* -- Arithmetic and logic operations ------------------------------------- */ - -#if !LJ_SOFTFP -static void asm_fparith(ASMState *as, IRIns *ir, ARMIns ai) -{ - Reg dest = ra_dest(as, ir, RSET_FPR); - Reg right, left = ra_alloc2(as, ir, RSET_FPR); - right = (left >> 8); left &= 255; - emit_dnm(as, ai, (dest & 15), (left & 15), (right & 15)); -} - -static void asm_fpunary(ASMState *as, IRIns *ir, ARMIns ai) -{ - Reg dest = ra_dest(as, ir, RSET_FPR); - Reg left = ra_hintalloc(as, ir->op1, dest, RSET_FPR); - emit_dm(as, ai, (dest & 15), (left & 15)); -} - -static void asm_callround(ASMState *as, IRIns *ir, int id) -{ - /* The modified regs must match with the *.dasc implementation. */ - RegSet drop = RID2RSET(RID_R0)|RID2RSET(RID_R1)|RID2RSET(RID_R2)| - RID2RSET(RID_R3)|RID2RSET(RID_R12); - RegSet of; - Reg dest, src; - ra_evictset(as, drop); - dest = ra_dest(as, ir, RSET_FPR); - emit_dnm(as, ARMI_VMOV_D_RR, RID_RETLO, RID_RETHI, (dest & 15)); - emit_call(as, id == IRFPM_FLOOR ? (void *)lj_vm_floor_sf : - id == IRFPM_CEIL ? (void *)lj_vm_ceil_sf : - (void *)lj_vm_trunc_sf); - /* Workaround to protect argument GPRs from being used for remat. */ - of = as->freeset; - as->freeset &= ~RSET_RANGE(RID_R0, RID_R1+1); - as->cost[RID_R0] = as->cost[RID_R1] = REGCOST(~0u, ASMREF_L); - src = ra_alloc1(as, ir->op1, RSET_FPR); /* May alloc GPR to remat FPR. */ - as->freeset |= (of & RSET_RANGE(RID_R0, RID_R1+1)); - emit_dnm(as, ARMI_VMOV_RR_D, RID_R0, RID_R1, (src & 15)); -} - -static void asm_fpmath(ASMState *as, IRIns *ir) -{ - if (ir->op2 == IRFPM_EXP2 && asm_fpjoin_pow(as, ir)) - return; - if (ir->op2 <= IRFPM_TRUNC) - asm_callround(as, ir, ir->op2); - else if (ir->op2 == IRFPM_SQRT) - asm_fpunary(as, ir, ARMI_VSQRT_D); - else - asm_callid(as, ir, IRCALL_lj_vm_floor + ir->op2); -} -#endif - -static int asm_swapops(ASMState *as, IRRef lref, IRRef rref) -{ - IRIns *ir; - if (irref_isk(rref)) - return 0; /* Don't swap constants to the left. */ - if (irref_isk(lref)) - return 1; /* But swap constants to the right. */ - ir = IR(rref); - if ((ir->o >= IR_BSHL && ir->o <= IR_BROR) || - (ir->o == IR_ADD && ir->op1 == ir->op2)) - return 0; /* Don't swap fusable operands to the left. */ - ir = IR(lref); - if ((ir->o >= IR_BSHL && ir->o <= IR_BROR) || - (ir->o == IR_ADD && ir->op1 == ir->op2)) - return 1; /* But swap fusable operands to the right. */ - return 0; /* Otherwise don't swap. */ -} - -static void asm_intop(ASMState *as, IRIns *ir, ARMIns ai) -{ - IRRef lref = ir->op1, rref = ir->op2; - Reg left, dest = ra_dest(as, ir, RSET_GPR); - uint32_t m; - if (asm_swapops(as, lref, rref)) { - IRRef tmp = lref; lref = rref; rref = tmp; - if ((ai & ~ARMI_S) == ARMI_SUB || (ai & ~ARMI_S) == ARMI_SBC) - ai ^= (ARMI_SUB^ARMI_RSB); - } - left = ra_hintalloc(as, lref, dest, RSET_GPR); - m = asm_fuseopm(as, ai, rref, rset_exclude(RSET_GPR, left)); - if (irt_isguard(ir->t)) { /* For IR_ADDOV etc. */ - asm_guardcc(as, CC_VS); - ai |= ARMI_S; - } - emit_dn(as, ai^m, dest, left); -} - -static void asm_intop_s(ASMState *as, IRIns *ir, ARMIns ai) -{ - if (as->flagmcp == as->mcp) { /* Drop cmp r, #0. */ - as->flagmcp = NULL; - as->mcp++; - ai |= ARMI_S; - } - asm_intop(as, ir, ai); -} - -static void asm_intneg(ASMState *as, IRIns *ir, ARMIns ai) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); - emit_dn(as, ai|ARMI_K12|0, dest, left); -} - -/* NYI: use add/shift for MUL(OV) with constants. FOLD only does 2^k. */ -static void asm_intmul(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_alloc1(as, ir->op1, rset_exclude(RSET_GPR, dest)); - Reg right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left)); - Reg tmp = RID_NONE; - /* ARMv5 restriction: dest != left and dest_hi != left. */ - if (dest == left && left != right) { left = right; right = dest; } - if (irt_isguard(ir->t)) { /* IR_MULOV */ - if (!(as->flags & JIT_F_ARMV6) && dest == left) - tmp = left = ra_scratch(as, rset_exclude(RSET_GPR, left)); - asm_guardcc(as, CC_NE); - emit_nm(as, ARMI_TEQ|ARMF_SH(ARMSH_ASR, 31), RID_TMP, dest); - emit_dnm(as, ARMI_SMULL|ARMF_S(right), dest, RID_TMP, left); - } else { - if (!(as->flags & JIT_F_ARMV6) && dest == left) tmp = left = RID_TMP; - emit_nm(as, ARMI_MUL|ARMF_S(right), dest, left); - } - /* Only need this for the dest == left == right case. */ - if (ra_hasreg(tmp)) emit_dm(as, ARMI_MOV, tmp, right); -} - -static void asm_add(ASMState *as, IRIns *ir) -{ -#if !LJ_SOFTFP - if (irt_isnum(ir->t)) { - if (!asm_fusemadd(as, ir, ARMI_VMLA_D, ARMI_VMLA_D)) - asm_fparith(as, ir, ARMI_VADD_D); - return; - } -#endif - asm_intop_s(as, ir, ARMI_ADD); -} - -static void asm_sub(ASMState *as, IRIns *ir) -{ -#if !LJ_SOFTFP - if (irt_isnum(ir->t)) { - if (!asm_fusemadd(as, ir, ARMI_VNMLS_D, ARMI_VMLS_D)) - asm_fparith(as, ir, ARMI_VSUB_D); - return; - } -#endif - asm_intop_s(as, ir, ARMI_SUB); -} - -static void asm_mul(ASMState *as, IRIns *ir) -{ -#if !LJ_SOFTFP - if (irt_isnum(ir->t)) { - asm_fparith(as, ir, ARMI_VMUL_D); - return; - } -#endif - asm_intmul(as, ir); -} - -#define asm_addov(as, ir) asm_add(as, ir) -#define asm_subov(as, ir) asm_sub(as, ir) -#define asm_mulov(as, ir) asm_mul(as, ir) - -#if !LJ_SOFTFP -#define asm_div(as, ir) asm_fparith(as, ir, ARMI_VDIV_D) -#define asm_pow(as, ir) asm_callid(as, ir, IRCALL_lj_vm_powi) -#define asm_abs(as, ir) asm_fpunary(as, ir, ARMI_VABS_D) -#define asm_atan2(as, ir) asm_callid(as, ir, IRCALL_atan2) -#define asm_ldexp(as, ir) asm_callid(as, ir, IRCALL_ldexp) -#endif - -#define asm_mod(as, ir) asm_callid(as, ir, IRCALL_lj_vm_modi) - -static void asm_neg(ASMState *as, IRIns *ir) -{ -#if !LJ_SOFTFP - if (irt_isnum(ir->t)) { - asm_fpunary(as, ir, ARMI_VNEG_D); - return; - } -#endif - asm_intneg(as, ir, ARMI_RSB); -} - -static void asm_bitop(ASMState *as, IRIns *ir, ARMIns ai) -{ - if (as->flagmcp == as->mcp) { /* Try to drop cmp r, #0. */ - uint32_t cc = (as->mcp[1] >> 28); - as->flagmcp = NULL; - if (cc <= CC_NE) { - as->mcp++; - ai |= ARMI_S; - } else if (cc == CC_GE) { - *++as->mcp ^= ((CC_GE^CC_PL) << 28); - ai |= ARMI_S; - } else if (cc == CC_LT) { - *++as->mcp ^= ((CC_LT^CC_MI) << 28); - ai |= ARMI_S; - } /* else: other conds don't work with bit ops. */ - } - if (ir->op2 == 0) { - Reg dest = ra_dest(as, ir, RSET_GPR); - uint32_t m = asm_fuseopm(as, ai, ir->op1, RSET_GPR); - emit_d(as, ai^m, dest); - } else { - /* NYI: Turn BAND !k12 into uxtb, uxth or bfc or shl+shr. */ - asm_intop(as, ir, ai); - } -} - -#define asm_bnot(as, ir) asm_bitop(as, ir, ARMI_MVN) - -static void asm_bswap(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_alloc1(as, ir->op1, RSET_GPR); - if ((as->flags & JIT_F_ARMV6)) { - emit_dm(as, ARMI_REV, dest, left); - } else { - Reg tmp2 = dest; - if (tmp2 == left) - tmp2 = ra_scratch(as, rset_exclude(rset_exclude(RSET_GPR, dest), left)); - emit_dnm(as, ARMI_EOR|ARMF_SH(ARMSH_LSR, 8), dest, tmp2, RID_TMP); - emit_dm(as, ARMI_MOV|ARMF_SH(ARMSH_ROR, 8), tmp2, left); - emit_dn(as, ARMI_BIC|ARMI_K12|256*8|255, RID_TMP, RID_TMP); - emit_dnm(as, ARMI_EOR|ARMF_SH(ARMSH_ROR, 16), RID_TMP, left, left); - } -} - -#define asm_band(as, ir) asm_bitop(as, ir, ARMI_AND) -#define asm_bor(as, ir) asm_bitop(as, ir, ARMI_ORR) -#define asm_bxor(as, ir) asm_bitop(as, ir, ARMI_EOR) - -static void asm_bitshift(ASMState *as, IRIns *ir, ARMShift sh) -{ - if (irref_isk(ir->op2)) { /* Constant shifts. */ - /* NYI: Turn SHL+SHR or BAND+SHR into uxtb, uxth or ubfx. */ - /* NYI: Turn SHL+ASR into sxtb, sxth or sbfx. */ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_alloc1(as, ir->op1, RSET_GPR); - int32_t shift = (IR(ir->op2)->i & 31); - emit_dm(as, ARMI_MOV|ARMF_SH(sh, shift), dest, left); - } else { - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_alloc1(as, ir->op1, RSET_GPR); - Reg right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left)); - emit_dm(as, ARMI_MOV|ARMF_RSH(sh, right), dest, left); - } -} - -#define asm_bshl(as, ir) asm_bitshift(as, ir, ARMSH_LSL) -#define asm_bshr(as, ir) asm_bitshift(as, ir, ARMSH_LSR) -#define asm_bsar(as, ir) asm_bitshift(as, ir, ARMSH_ASR) -#define asm_bror(as, ir) asm_bitshift(as, ir, ARMSH_ROR) -#define asm_brol(as, ir) lua_assert(0) - -static void asm_intmin_max(ASMState *as, IRIns *ir, int cc) -{ - uint32_t kcmp = 0, kmov = 0; - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); - Reg right = 0; - if (irref_isk(ir->op2)) { - kcmp = emit_isk12(ARMI_CMP, IR(ir->op2)->i); - if (kcmp) kmov = emit_isk12(ARMI_MOV, IR(ir->op2)->i); - } - if (!kmov) { - kcmp = 0; - right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left)); - } - if (kmov || dest != right) { - emit_dm(as, ARMF_CC(ARMI_MOV, cc)^kmov, dest, right); - cc ^= 1; /* Must use opposite conditions for paired moves. */ - } else { - cc ^= (CC_LT^CC_GT); /* Otherwise may swap CC_LT <-> CC_GT. */ - } - if (dest != left) emit_dm(as, ARMF_CC(ARMI_MOV, cc), dest, left); - emit_nm(as, ARMI_CMP^kcmp, left, right); -} - -#if LJ_SOFTFP -static void asm_sfpmin_max(ASMState *as, IRIns *ir, int cc) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_softfp_cmp]; - RegSet drop = RSET_SCRATCH; - Reg r; - IRRef args[4]; - args[0] = ir->op1; args[1] = (ir+1)->op1; - args[2] = ir->op2; args[3] = (ir+1)->op2; - /* __aeabi_cdcmple preserves r0-r3. */ - if (ra_hasreg(ir->r)) rset_clear(drop, ir->r); - if (ra_hasreg((ir+1)->r)) rset_clear(drop, (ir+1)->r); - if (!rset_test(as->freeset, RID_R2) && - regcost_ref(as->cost[RID_R2]) == args[2]) rset_clear(drop, RID_R2); - if (!rset_test(as->freeset, RID_R3) && - regcost_ref(as->cost[RID_R3]) == args[3]) rset_clear(drop, RID_R3); - ra_evictset(as, drop); - ra_destpair(as, ir); - emit_dm(as, ARMF_CC(ARMI_MOV, cc), RID_RETHI, RID_R3); - emit_dm(as, ARMF_CC(ARMI_MOV, cc), RID_RETLO, RID_R2); - emit_call(as, (void *)ci->func); - for (r = RID_R0; r <= RID_R3; r++) - ra_leftov(as, r, args[r-RID_R0]); -} -#else -static void asm_fpmin_max(ASMState *as, IRIns *ir, int cc) -{ - Reg dest = (ra_dest(as, ir, RSET_FPR) & 15); - Reg right, left = ra_alloc2(as, ir, RSET_FPR); - right = ((left >> 8) & 15); left &= 15; - if (dest != left) emit_dm(as, ARMF_CC(ARMI_VMOV_D, cc^1), dest, left); - if (dest != right) emit_dm(as, ARMF_CC(ARMI_VMOV_D, cc), dest, right); - emit_d(as, ARMI_VMRS, 0); - emit_dm(as, ARMI_VCMP_D, left, right); -} -#endif - -static void asm_min_max(ASMState *as, IRIns *ir, int cc, int fcc) -{ -#if LJ_SOFTFP - UNUSED(fcc); -#else - if (irt_isnum(ir->t)) - asm_fpmin_max(as, ir, fcc); - else -#endif - asm_intmin_max(as, ir, cc); -} - -#define asm_min(as, ir) asm_min_max(as, ir, CC_GT, CC_HI) -#define asm_max(as, ir) asm_min_max(as, ir, CC_LT, CC_LO) - -/* -- Comparisons --------------------------------------------------------- */ - -/* Map of comparisons to flags. ORDER IR. */ -static const uint8_t asm_compmap[IR_ABC+1] = { - /* op FP swp int cc FP cc */ - /* LT */ CC_GE + (CC_HS << 4), - /* GE x */ CC_LT + (CC_HI << 4), - /* LE */ CC_GT + (CC_HI << 4), - /* GT x */ CC_LE + (CC_HS << 4), - /* ULT x */ CC_HS + (CC_LS << 4), - /* UGE */ CC_LO + (CC_LO << 4), - /* ULE x */ CC_HI + (CC_LO << 4), - /* UGT */ CC_LS + (CC_LS << 4), - /* EQ */ CC_NE + (CC_NE << 4), - /* NE */ CC_EQ + (CC_EQ << 4), - /* ABC */ CC_LS + (CC_LS << 4) /* Same as UGT. */ -}; - -#if LJ_SOFTFP -/* FP comparisons. */ -static void asm_sfpcomp(ASMState *as, IRIns *ir) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_softfp_cmp]; - RegSet drop = RSET_SCRATCH; - Reg r; - IRRef args[4]; - int swp = (((ir->o ^ (ir->o >> 2)) & ~(ir->o >> 3) & 1) << 1); - args[swp^0] = ir->op1; args[swp^1] = (ir+1)->op1; - args[swp^2] = ir->op2; args[swp^3] = (ir+1)->op2; - /* __aeabi_cdcmple preserves r0-r3. This helps to reduce spills. */ - for (r = RID_R0; r <= RID_R3; r++) - if (!rset_test(as->freeset, r) && - regcost_ref(as->cost[r]) == args[r-RID_R0]) rset_clear(drop, r); - ra_evictset(as, drop); - asm_guardcc(as, (asm_compmap[ir->o] >> 4)); - emit_call(as, (void *)ci->func); - for (r = RID_R0; r <= RID_R3; r++) - ra_leftov(as, r, args[r-RID_R0]); -} -#else -/* FP comparisons. */ -static void asm_fpcomp(ASMState *as, IRIns *ir) -{ - Reg left, right; - ARMIns ai; - int swp = ((ir->o ^ (ir->o >> 2)) & ~(ir->o >> 3) & 1); - if (!swp && irref_isk(ir->op2) && ir_knum(IR(ir->op2))->u64 == 0) { - left = (ra_alloc1(as, ir->op1, RSET_FPR) & 15); - right = 0; - ai = ARMI_VCMPZ_D; - } else { - left = ra_alloc2(as, ir, RSET_FPR); - if (swp) { - right = (left & 15); left = ((left >> 8) & 15); - } else { - right = ((left >> 8) & 15); left &= 15; - } - ai = ARMI_VCMP_D; - } - asm_guardcc(as, (asm_compmap[ir->o] >> 4)); - emit_d(as, ARMI_VMRS, 0); - emit_dm(as, ai, left, right); -} -#endif - -/* Integer comparisons. */ -static void asm_intcomp(ASMState *as, IRIns *ir) -{ - ARMCC cc = (asm_compmap[ir->o] & 15); - IRRef lref = ir->op1, rref = ir->op2; - Reg left; - uint32_t m; - int cmpprev0 = 0; - lua_assert(irt_isint(ir->t) || irt_isu32(ir->t) || irt_isaddr(ir->t)); - if (asm_swapops(as, lref, rref)) { - Reg tmp = lref; lref = rref; rref = tmp; - if (cc >= CC_GE) cc ^= 7; /* LT <-> GT, LE <-> GE */ - else if (cc > CC_NE) cc ^= 11; /* LO <-> HI, LS <-> HS */ - } - if (irref_isk(rref) && IR(rref)->i == 0) { - IRIns *irl = IR(lref); - cmpprev0 = (irl+1 == ir); - /* Combine comp(BAND(left, right), 0) into tst left, right. */ - if (cmpprev0 && irl->o == IR_BAND && !ra_used(irl)) { - IRRef blref = irl->op1, brref = irl->op2; - uint32_t m2 = 0; - Reg bleft; - if (asm_swapops(as, blref, brref)) { - Reg tmp = blref; blref = brref; brref = tmp; - } - if (irref_isk(brref)) { - m2 = emit_isk12(ARMI_AND, IR(brref)->i); - if ((m2 & (ARMI_AND^ARMI_BIC))) - goto notst; /* Not beneficial if we miss a constant operand. */ - } - if (cc == CC_GE) cc = CC_PL; - else if (cc == CC_LT) cc = CC_MI; - else if (cc > CC_NE) goto notst; /* Other conds don't work with tst. */ - bleft = ra_alloc1(as, blref, RSET_GPR); - if (!m2) m2 = asm_fuseopm(as, 0, brref, rset_exclude(RSET_GPR, bleft)); - asm_guardcc(as, cc); - emit_n(as, ARMI_TST^m2, bleft); - return; - } - } -notst: - left = ra_alloc1(as, lref, RSET_GPR); - m = asm_fuseopm(as, ARMI_CMP, rref, rset_exclude(RSET_GPR, left)); - asm_guardcc(as, cc); - emit_n(as, ARMI_CMP^m, left); - /* Signed comparison with zero and referencing previous ins? */ - if (cmpprev0 && (cc <= CC_NE || cc >= CC_GE)) - as->flagmcp = as->mcp; /* Allow elimination of the compare. */ -} - -static void asm_comp(ASMState *as, IRIns *ir) -{ -#if !LJ_SOFTFP - if (irt_isnum(ir->t)) - asm_fpcomp(as, ir); - else -#endif - asm_intcomp(as, ir); -} - -#define asm_equal(as, ir) asm_comp(as, ir) - -#if LJ_HASFFI -/* 64 bit integer comparisons. */ -static void asm_int64comp(ASMState *as, IRIns *ir) -{ - int signedcomp = (ir->o <= IR_GT); - ARMCC cclo, cchi; - Reg leftlo, lefthi; - uint32_t mlo, mhi; - RegSet allow = RSET_GPR, oldfree; - - /* Always use unsigned comparison for loword. */ - cclo = asm_compmap[ir->o + (signedcomp ? 4 : 0)] & 15; - leftlo = ra_alloc1(as, ir->op1, allow); - oldfree = as->freeset; - mlo = asm_fuseopm(as, ARMI_CMP, ir->op2, rset_clear(allow, leftlo)); - allow &= ~(oldfree & ~as->freeset); /* Update for allocs of asm_fuseopm. */ - - /* Use signed or unsigned comparison for hiword. */ - cchi = asm_compmap[ir->o] & 15; - lefthi = ra_alloc1(as, (ir+1)->op1, allow); - mhi = asm_fuseopm(as, ARMI_CMP, (ir+1)->op2, rset_clear(allow, lefthi)); - - /* All register allocations must be performed _before_ this point. */ - if (signedcomp) { - MCLabel l_around = emit_label(as); - asm_guardcc(as, cclo); - emit_n(as, ARMI_CMP^mlo, leftlo); - emit_branch(as, ARMF_CC(ARMI_B, CC_NE), l_around); - if (cchi == CC_GE || cchi == CC_LE) cchi ^= 6; /* GE -> GT, LE -> LT */ - asm_guardcc(as, cchi); - } else { - asm_guardcc(as, cclo); - emit_n(as, ARMF_CC(ARMI_CMP, CC_EQ)^mlo, leftlo); - } - emit_n(as, ARMI_CMP^mhi, lefthi); -} -#endif - -/* -- Support for 64 bit ops in 32 bit mode ------------------------------- */ - -/* Hiword op of a split 64 bit op. Previous op must be the loword op. */ -static void asm_hiop(ASMState *as, IRIns *ir) -{ -#if LJ_HASFFI || LJ_SOFTFP - /* HIOP is marked as a store because it needs its own DCE logic. */ - int uselo = ra_used(ir-1), usehi = ra_used(ir); /* Loword/hiword used? */ - if (LJ_UNLIKELY(!(as->flags & JIT_F_OPT_DCE))) uselo = usehi = 1; - if ((ir-1)->o <= IR_NE) { /* 64 bit integer or FP comparisons. ORDER IR. */ - as->curins--; /* Always skip the loword comparison. */ -#if LJ_SOFTFP - if (!irt_isint(ir->t)) { - asm_sfpcomp(as, ir-1); - return; - } -#endif -#if LJ_HASFFI - asm_int64comp(as, ir-1); -#endif - return; -#if LJ_SOFTFP - } else if ((ir-1)->o == IR_MIN || (ir-1)->o == IR_MAX) { - as->curins--; /* Always skip the loword min/max. */ - if (uselo || usehi) - asm_sfpmin_max(as, ir-1, (ir-1)->o == IR_MIN ? CC_HI : CC_LO); - return; -#elif LJ_HASFFI - } else if ((ir-1)->o == IR_CONV) { - as->curins--; /* Always skip the CONV. */ - if (usehi || uselo) - asm_conv64(as, ir); - return; -#endif - } else if ((ir-1)->o == IR_XSTORE) { - if ((ir-1)->r != RID_SINK) - asm_xstore_(as, ir, 4); - return; - } - if (!usehi) return; /* Skip unused hiword op for all remaining ops. */ - switch ((ir-1)->o) { -#if LJ_HASFFI - case IR_ADD: - as->curins--; - asm_intop(as, ir, ARMI_ADC); - asm_intop(as, ir-1, ARMI_ADD|ARMI_S); - break; - case IR_SUB: - as->curins--; - asm_intop(as, ir, ARMI_SBC); - asm_intop(as, ir-1, ARMI_SUB|ARMI_S); - break; - case IR_NEG: - as->curins--; - asm_intneg(as, ir, ARMI_RSC); - asm_intneg(as, ir-1, ARMI_RSB|ARMI_S); - break; -#endif -#if LJ_SOFTFP - case IR_SLOAD: case IR_ALOAD: case IR_HLOAD: case IR_ULOAD: case IR_VLOAD: - case IR_STRTO: - if (!uselo) - ra_allocref(as, ir->op1, RSET_GPR); /* Mark lo op as used. */ - break; -#endif - case IR_CALLN: - case IR_CALLS: - case IR_CALLXS: - if (!uselo) - ra_allocref(as, ir->op1, RID2RSET(RID_RETLO)); /* Mark lo op as used. */ - break; -#if LJ_SOFTFP - case IR_ASTORE: case IR_HSTORE: case IR_USTORE: case IR_TOSTR: -#endif - case IR_CNEWI: - /* Nothing to do here. Handled by lo op itself. */ - break; - default: lua_assert(0); break; - } -#else - UNUSED(as); UNUSED(ir); lua_assert(0); -#endif -} - -/* -- Profiling ----------------------------------------------------------- */ - -static void asm_prof(ASMState *as, IRIns *ir) -{ - UNUSED(ir); - asm_guardcc(as, CC_NE); - emit_n(as, ARMI_TST|ARMI_K12|HOOK_PROFILE, RID_TMP); - emit_lsptr(as, ARMI_LDRB, RID_TMP, (void *)&J2G(as->J)->hookmask); -} - -/* -- Stack handling ------------------------------------------------------ */ - -/* Check Lua stack size for overflow. Use exit handler as fallback. */ -static void asm_stack_check(ASMState *as, BCReg topslot, - IRIns *irp, RegSet allow, ExitNo exitno) -{ - Reg pbase; - uint32_t k; - if (irp) { - if (!ra_hasspill(irp->s)) { - pbase = irp->r; - lua_assert(ra_hasreg(pbase)); - } else if (allow) { - pbase = rset_pickbot(allow); - } else { - pbase = RID_RET; - emit_lso(as, ARMI_LDR, RID_RET, RID_SP, 0); /* Restore temp. register. */ - } - } else { - pbase = RID_BASE; - } - emit_branch(as, ARMF_CC(ARMI_BL, CC_LS), exitstub_addr(as->J, exitno)); - k = emit_isk12(0, (int32_t)(8*topslot)); - lua_assert(k); - emit_n(as, ARMI_CMP^k, RID_TMP); - emit_dnm(as, ARMI_SUB, RID_TMP, RID_TMP, pbase); - emit_lso(as, ARMI_LDR, RID_TMP, RID_TMP, - (int32_t)offsetof(lua_State, maxstack)); - if (irp) { /* Must not spill arbitrary registers in head of side trace. */ - int32_t i = i32ptr(&J2G(as->J)->cur_L); - if (ra_hasspill(irp->s)) - emit_lso(as, ARMI_LDR, pbase, RID_SP, sps_scale(irp->s)); - emit_lso(as, ARMI_LDR, RID_TMP, RID_TMP, (i & 4095)); - if (ra_hasspill(irp->s) && !allow) - emit_lso(as, ARMI_STR, RID_RET, RID_SP, 0); /* Save temp. register. */ - emit_loadi(as, RID_TMP, (i & ~4095)); - } else { - emit_getgl(as, RID_TMP, cur_L); - } -} - -/* Restore Lua stack from on-trace state. */ -static void asm_stack_restore(ASMState *as, SnapShot *snap) -{ - SnapEntry *map = &as->T->snapmap[snap->mapofs]; - SnapEntry *flinks = &as->T->snapmap[snap_nextofs(as->T, snap)-1]; - MSize n, nent = snap->nent; - /* Store the value of all modified slots to the Lua stack. */ - for (n = 0; n < nent; n++) { - SnapEntry sn = map[n]; - BCReg s = snap_slot(sn); - int32_t ofs = 8*((int32_t)s-1); - IRRef ref = snap_ref(sn); - IRIns *ir = IR(ref); - if ((sn & SNAP_NORESTORE)) - continue; - if (irt_isnum(ir->t)) { -#if LJ_SOFTFP - RegSet odd = rset_exclude(RSET_GPRODD, RID_BASE); - Reg tmp; - lua_assert(irref_isk(ref)); /* LJ_SOFTFP: must be a number constant. */ - tmp = ra_allock(as, (int32_t)ir_knum(ir)->u32.lo, - rset_exclude(RSET_GPREVEN, RID_BASE)); - emit_lso(as, ARMI_STR, tmp, RID_BASE, ofs); - if (rset_test(as->freeset, tmp+1)) odd = RID2RSET(tmp+1); - tmp = ra_allock(as, (int32_t)ir_knum(ir)->u32.hi, odd); - emit_lso(as, ARMI_STR, tmp, RID_BASE, ofs+4); -#else - Reg src = ra_alloc1(as, ref, RSET_FPR); - emit_vlso(as, ARMI_VSTR_D, src, RID_BASE, ofs); -#endif - } else { - RegSet odd = rset_exclude(RSET_GPRODD, RID_BASE); - Reg type; - lua_assert(irt_ispri(ir->t) || irt_isaddr(ir->t) || irt_isinteger(ir->t)); - if (!irt_ispri(ir->t)) { - Reg src = ra_alloc1(as, ref, rset_exclude(RSET_GPREVEN, RID_BASE)); - emit_lso(as, ARMI_STR, src, RID_BASE, ofs); - if (rset_test(as->freeset, src+1)) odd = RID2RSET(src+1); - } - if ((sn & (SNAP_CONT|SNAP_FRAME))) { - if (s == 0) continue; /* Do not overwrite link to previous frame. */ - type = ra_allock(as, (int32_t)(*flinks--), odd); -#if LJ_SOFTFP - } else if ((sn & SNAP_SOFTFPNUM)) { - type = ra_alloc1(as, ref+1, rset_exclude(RSET_GPRODD, RID_BASE)); -#endif - } else { - type = ra_allock(as, (int32_t)irt_toitype(ir->t), odd); - } - emit_lso(as, ARMI_STR, type, RID_BASE, ofs+4); - } - checkmclim(as); - } - lua_assert(map + nent == flinks); -} - -/* -- GC handling --------------------------------------------------------- */ - -/* Check GC threshold and do one or more GC steps. */ -static void asm_gc_check(ASMState *as) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_gc_step_jit]; - IRRef args[2]; - MCLabel l_end; - Reg tmp1, tmp2; - ra_evictset(as, RSET_SCRATCH); - l_end = emit_label(as); - /* Exit trace if in GCSatomic or GCSfinalize. Avoids syncing GC objects. */ - asm_guardcc(as, CC_NE); /* Assumes asm_snap_prep() already done. */ - emit_n(as, ARMI_CMP|ARMI_K12|0, RID_RET); - args[0] = ASMREF_TMP1; /* global_State *g */ - args[1] = ASMREF_TMP2; /* MSize steps */ - asm_gencall(as, ci, args); - tmp1 = ra_releasetmp(as, ASMREF_TMP1); - tmp2 = ra_releasetmp(as, ASMREF_TMP2); - emit_loadi(as, tmp2, as->gcsteps); - /* Jump around GC step if GC total < GC threshold. */ - emit_branch(as, ARMF_CC(ARMI_B, CC_LS), l_end); - emit_nm(as, ARMI_CMP, RID_TMP, tmp2); - emit_lso(as, ARMI_LDR, tmp2, tmp1, - (int32_t)offsetof(global_State, gc.threshold)); - emit_lso(as, ARMI_LDR, RID_TMP, tmp1, - (int32_t)offsetof(global_State, gc.total)); - ra_allockreg(as, i32ptr(J2G(as->J)), tmp1); - as->gcsteps = 0; - checkmclim(as); -} - -/* -- Loop handling ------------------------------------------------------- */ - -/* Fixup the loop branch. */ -static void asm_loop_fixup(ASMState *as) -{ - MCode *p = as->mctop; - MCode *target = as->mcp; - if (as->loopinv) { /* Inverted loop branch? */ - /* asm_guardcc already inverted the bcc and patched the final bl. */ - p[-2] |= ((uint32_t)(target-p) & 0x00ffffffu); - } else { - p[-1] = ARMI_B | ((uint32_t)((target-p)-1) & 0x00ffffffu); - } -} - -/* -- Head of trace ------------------------------------------------------- */ - -/* Reload L register from g->cur_L. */ -static void asm_head_lreg(ASMState *as) -{ - IRIns *ir = IR(ASMREF_L); - if (ra_used(ir)) { - Reg r = ra_dest(as, ir, RSET_GPR); - emit_getgl(as, r, cur_L); - ra_evictk(as); - } -} - -/* Coalesce BASE register for a root trace. */ -static void asm_head_root_base(ASMState *as) -{ - IRIns *ir; - asm_head_lreg(as); - ir = IR(REF_BASE); - if (ra_hasreg(ir->r) && (rset_test(as->modset, ir->r) || irt_ismarked(ir->t))) - ra_spill(as, ir); - ra_destreg(as, ir, RID_BASE); -} - -/* Coalesce BASE register for a side trace. */ -static RegSet asm_head_side_base(ASMState *as, IRIns *irp, RegSet allow) -{ - IRIns *ir; - asm_head_lreg(as); - ir = IR(REF_BASE); - if (ra_hasreg(ir->r) && (rset_test(as->modset, ir->r) || irt_ismarked(ir->t))) - ra_spill(as, ir); - if (ra_hasspill(irp->s)) { - rset_clear(allow, ra_dest(as, ir, allow)); - } else { - Reg r = irp->r; - lua_assert(ra_hasreg(r)); - rset_clear(allow, r); - if (r != ir->r && !rset_test(as->freeset, r)) - ra_restore(as, regcost_ref(as->cost[r])); - ra_destreg(as, ir, r); - } - return allow; -} - -/* -- Tail of trace ------------------------------------------------------- */ - -/* Fixup the tail code. */ -static void asm_tail_fixup(ASMState *as, TraceNo lnk) -{ - MCode *p = as->mctop; - MCode *target; - int32_t spadj = as->T->spadjust; - if (spadj == 0) { - as->mctop = --p; - } else { - /* Patch stack adjustment. */ - uint32_t k = emit_isk12(ARMI_ADD, spadj); - lua_assert(k); - p[-2] = (ARMI_ADD^k) | ARMF_D(RID_SP) | ARMF_N(RID_SP); - } - /* Patch exit branch. */ - target = lnk ? traceref(as->J, lnk)->mcode : (MCode *)lj_vm_exit_interp; - p[-1] = ARMI_B|(((target-p)-1)&0x00ffffffu); -} - -/* Prepare tail of code. */ -static void asm_tail_prep(ASMState *as) -{ - MCode *p = as->mctop - 1; /* Leave room for exit branch. */ - if (as->loopref) { - as->invmcp = as->mcp = p; - } else { - as->mcp = p-1; /* Leave room for stack pointer adjustment. */ - as->invmcp = NULL; - } - *p = 0; /* Prevent load/store merging. */ -} - -/* -- Trace setup --------------------------------------------------------- */ - -/* Ensure there are enough stack slots for call arguments. */ -static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci) -{ - IRRef args[CCI_NARGS_MAX*2]; - uint32_t i, nargs = CCI_XNARGS(ci); - int nslots = 0, ngpr = REGARG_NUMGPR, nfpr = REGARG_NUMFPR, fprodd = 0; - asm_collectargs(as, ir, ci, args); - for (i = 0; i < nargs; i++) { - if (!LJ_SOFTFP && args[i] && irt_isfp(IR(args[i])->t)) { - if (!LJ_ABI_SOFTFP && !(ci->flags & CCI_VARARG)) { - if (irt_isnum(IR(args[i])->t)) { - if (nfpr > 0) nfpr--; - else fprodd = 0, nslots = (nslots + 3) & ~1; - } else { - if (fprodd) fprodd--; - else if (nfpr > 0) fprodd = 1, nfpr--; - else nslots++; - } - } else if (irt_isnum(IR(args[i])->t)) { - ngpr &= ~1; - if (ngpr > 0) ngpr -= 2; else nslots += 2; - } else { - if (ngpr > 0) ngpr--; else nslots++; - } - } else { - if (ngpr > 0) ngpr--; else nslots++; - } - } - if (nslots > as->evenspill) /* Leave room for args in stack slots. */ - as->evenspill = nslots; - return REGSP_HINT(RID_RET); -} - -static void asm_setup_target(ASMState *as) -{ - /* May need extra exit for asm_stack_check on side traces. */ - asm_exitstub_setup(as, as->T->nsnap + (as->parent ? 1 : 0)); -} - -/* -- Trace patching ------------------------------------------------------ */ - -/* Patch exit jumps of existing machine code to a new target. */ -void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, MCode *target) -{ - MCode *p = T->mcode; - MCode *pe = (MCode *)((char *)p + T->szmcode); - MCode *cstart = NULL, *cend = p; - MCode *mcarea = lj_mcode_patch(J, p, 0); - MCode *px = exitstub_addr(J, exitno) - 2; - for (; p < pe; p++) { - /* Look for bl_cc exitstub, replace with b_cc target. */ - uint32_t ins = *p; - if ((ins & 0x0f000000u) == 0x0b000000u && ins < 0xf0000000u && - ((ins ^ (px-p)) & 0x00ffffffu) == 0) { - *p = (ins & 0xfe000000u) | (((target-p)-2) & 0x00ffffffu); - cend = p+1; - if (!cstart) cstart = p; - } - } - lua_assert(cstart != NULL); - lj_mcode_sync(cstart, cend); - lj_mcode_patch(J, mcarea, 1); -} - diff --git a/lib/LuaJIT/src/lj_asm_arm64.h b/lib/LuaJIT/src/lj_asm_arm64.h deleted file mode 100644 index baafa21..0000000 --- a/lib/LuaJIT/src/lj_asm_arm64.h +++ /dev/null @@ -1,2031 +0,0 @@ -/* -** ARM64 IR assembler (SSA IR -> machine code). -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Contributed by Djordje Kovacevic and Stefan Pejic from RT-RK.com. -** Sponsored by Cisco Systems, Inc. -*/ - -/* -- Register allocator extensions --------------------------------------- */ - -/* Allocate a register with a hint. */ -static Reg ra_hintalloc(ASMState *as, IRRef ref, Reg hint, RegSet allow) -{ - Reg r = IR(ref)->r; - if (ra_noreg(r)) { - if (!ra_hashint(r) && !iscrossref(as, ref)) - ra_sethint(IR(ref)->r, hint); /* Propagate register hint. */ - r = ra_allocref(as, ref, allow); - } - ra_noweak(as, r); - return r; -} - -/* Allocate two source registers for three-operand instructions. */ -static Reg ra_alloc2(ASMState *as, IRIns *ir, RegSet allow) -{ - IRIns *irl = IR(ir->op1), *irr = IR(ir->op2); - Reg left = irl->r, right = irr->r; - if (ra_hasreg(left)) { - ra_noweak(as, left); - if (ra_noreg(right)) - right = ra_allocref(as, ir->op2, rset_exclude(allow, left)); - else - ra_noweak(as, right); - } else if (ra_hasreg(right)) { - ra_noweak(as, right); - left = ra_allocref(as, ir->op1, rset_exclude(allow, right)); - } else if (ra_hashint(right)) { - right = ra_allocref(as, ir->op2, allow); - left = ra_alloc1(as, ir->op1, rset_exclude(allow, right)); - } else { - left = ra_allocref(as, ir->op1, allow); - right = ra_alloc1(as, ir->op2, rset_exclude(allow, left)); - } - return left | (right << 8); -} - -/* -- Guard handling ------------------------------------------------------ */ - -/* Setup all needed exit stubs. */ -static void asm_exitstub_setup(ASMState *as, ExitNo nexits) -{ - ExitNo i; - MCode *mxp = as->mctop; - if (mxp - (nexits + 3 + MCLIM_REDZONE) < as->mclim) - asm_mclimit(as); - /* 1: str lr,[sp]; bl ->vm_exit_handler; movz w0,traceno; bl <1; bl <1; ... */ - for (i = nexits-1; (int32_t)i >= 0; i--) - *--mxp = A64I_LE(A64I_BL | A64F_S26(-3-i)); - *--mxp = A64I_LE(A64I_MOVZw | A64F_U16(as->T->traceno)); - mxp--; - *mxp = A64I_LE(A64I_BL | A64F_S26(((MCode *)(void *)lj_vm_exit_handler-mxp))); - *--mxp = A64I_LE(A64I_STRx | A64F_D(RID_LR) | A64F_N(RID_SP)); - as->mctop = mxp; -} - -static MCode *asm_exitstub_addr(ASMState *as, ExitNo exitno) -{ - /* Keep this in-sync with exitstub_trace_addr(). */ - return as->mctop + exitno + 3; -} - -/* Emit conditional branch to exit for guard. */ -static void asm_guardcc(ASMState *as, A64CC cc) -{ - MCode *target = asm_exitstub_addr(as, as->snapno); - MCode *p = as->mcp; - if (LJ_UNLIKELY(p == as->invmcp)) { - as->loopinv = 1; - *p = A64I_B | A64F_S26(target-p); - emit_cond_branch(as, cc^1, p-1); - return; - } - emit_cond_branch(as, cc, target); -} - -/* Emit test and branch instruction to exit for guard. */ -static void asm_guardtnb(ASMState *as, A64Ins ai, Reg r, uint32_t bit) -{ - MCode *target = asm_exitstub_addr(as, as->snapno); - MCode *p = as->mcp; - if (LJ_UNLIKELY(p == as->invmcp)) { - as->loopinv = 1; - *p = A64I_B | A64F_S26(target-p); - emit_tnb(as, ai^0x01000000u, r, bit, p-1); - return; - } - emit_tnb(as, ai, r, bit, target); -} - -/* Emit compare and branch instruction to exit for guard. */ -static void asm_guardcnb(ASMState *as, A64Ins ai, Reg r) -{ - MCode *target = asm_exitstub_addr(as, as->snapno); - MCode *p = as->mcp; - if (LJ_UNLIKELY(p == as->invmcp)) { - as->loopinv = 1; - *p = A64I_B | A64F_S26(target-p); - emit_cnb(as, ai^0x01000000u, r, p-1); - return; - } - emit_cnb(as, ai, r, target); -} - -/* -- Operand fusion ------------------------------------------------------ */ - -/* Limit linear search to this distance. Avoids O(n^2) behavior. */ -#define CONFLICT_SEARCH_LIM 31 - -static int asm_isk32(ASMState *as, IRRef ref, int32_t *k) -{ - if (irref_isk(ref)) { - IRIns *ir = IR(ref); - if (ir->o == IR_KNULL || !irt_is64(ir->t)) { - *k = ir->i; - return 1; - } else if (checki32((int64_t)ir_k64(ir)->u64)) { - *k = (int32_t)ir_k64(ir)->u64; - return 1; - } - } - return 0; -} - -/* Check if there's no conflicting instruction between curins and ref. */ -static int noconflict(ASMState *as, IRRef ref, IROp conflict) -{ - IRIns *ir = as->ir; - IRRef i = as->curins; - if (i > ref + CONFLICT_SEARCH_LIM) - return 0; /* Give up, ref is too far away. */ - while (--i > ref) - if (ir[i].o == conflict) - return 0; /* Conflict found. */ - return 1; /* Ok, no conflict. */ -} - -/* Fuse the array base of colocated arrays. */ -static int32_t asm_fuseabase(ASMState *as, IRRef ref) -{ - IRIns *ir = IR(ref); - if (ir->o == IR_TNEW && ir->op1 <= LJ_MAX_COLOSIZE && - !neverfuse(as) && noconflict(as, ref, IR_NEWREF)) - return (int32_t)sizeof(GCtab); - return 0; -} - -#define FUSE_REG 0x40000000 - -/* Fuse array/hash/upvalue reference into register+offset operand. */ -static Reg asm_fuseahuref(ASMState *as, IRRef ref, int32_t *ofsp, RegSet allow, - A64Ins ins) -{ - IRIns *ir = IR(ref); - if (ra_noreg(ir->r)) { - if (ir->o == IR_AREF) { - if (mayfuse(as, ref)) { - if (irref_isk(ir->op2)) { - IRRef tab = IR(ir->op1)->op1; - int32_t ofs = asm_fuseabase(as, tab); - IRRef refa = ofs ? tab : ir->op1; - ofs += 8*IR(ir->op2)->i; - if (emit_checkofs(ins, ofs)) { - *ofsp = ofs; - return ra_alloc1(as, refa, allow); - } - } else { - Reg base = ra_alloc1(as, ir->op1, allow); - *ofsp = FUSE_REG|ra_alloc1(as, ir->op2, rset_exclude(allow, base)); - return base; - } - } - } else if (ir->o == IR_HREFK) { - if (mayfuse(as, ref)) { - int32_t ofs = (int32_t)(IR(ir->op2)->op2 * sizeof(Node)); - if (emit_checkofs(ins, ofs)) { - *ofsp = ofs; - return ra_alloc1(as, ir->op1, allow); - } - } - } else if (ir->o == IR_UREFC) { - if (irref_isk(ir->op1)) { - GCfunc *fn = ir_kfunc(IR(ir->op1)); - GCupval *uv = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv; - int64_t ofs = glofs(as, &uv->tv); - if (emit_checkofs(ins, ofs)) { - *ofsp = (int32_t)ofs; - return RID_GL; - } - } - } - } - *ofsp = 0; - return ra_alloc1(as, ref, allow); -} - -/* Fuse m operand into arithmetic/logic instructions. */ -static uint32_t asm_fuseopm(ASMState *as, A64Ins ai, IRRef ref, RegSet allow) -{ - IRIns *ir = IR(ref); - if (ra_hasreg(ir->r)) { - ra_noweak(as, ir->r); - return A64F_M(ir->r); - } else if (irref_isk(ref)) { - uint32_t m; - int64_t k = get_k64val(ir); - if ((ai & 0x1f000000) == 0x0a000000) - m = emit_isk13(k, irt_is64(ir->t)); - else - m = emit_isk12(k); - if (m) - return m; - } else if (mayfuse(as, ref)) { - if ((ir->o >= IR_BSHL && ir->o <= IR_BSAR && irref_isk(ir->op2)) || - (ir->o == IR_ADD && ir->op1 == ir->op2)) { - A64Shift sh = ir->o == IR_BSHR ? A64SH_LSR : - ir->o == IR_BSAR ? A64SH_ASR : A64SH_LSL; - int shift = ir->o == IR_ADD ? 1 : - (IR(ir->op2)->i & (irt_is64(ir->t) ? 63 : 31)); - IRIns *irl = IR(ir->op1); - if (sh == A64SH_LSL && - irl->o == IR_CONV && - irl->op2 == ((IRT_I64<op1, allow); - return A64F_M(m) | A64F_EXSH(A64EX_SXTW, shift); - } else { - Reg m = ra_alloc1(as, ir->op1, allow); - return A64F_M(m) | A64F_SH(sh, shift); - } - } else if (ir->o == IR_CONV && - ir->op2 == ((IRT_I64<op1, allow); - return A64F_M(m) | A64F_EX(A64EX_SXTW); - } - } - return A64F_M(ra_allocref(as, ref, allow)); -} - -/* Fuse XLOAD/XSTORE reference into load/store operand. */ -static void asm_fusexref(ASMState *as, A64Ins ai, Reg rd, IRRef ref, - RegSet allow) -{ - IRIns *ir = IR(ref); - Reg base; - int32_t ofs = 0; - if (ra_noreg(ir->r) && canfuse(as, ir)) { - if (ir->o == IR_ADD) { - if (asm_isk32(as, ir->op2, &ofs) && emit_checkofs(ai, ofs)) { - ref = ir->op1; - } else { - Reg rn, rm; - IRRef lref = ir->op1, rref = ir->op2; - IRIns *irl = IR(lref); - if (mayfuse(as, irl->op1)) { - unsigned int shift = 4; - if (irl->o == IR_BSHL && irref_isk(irl->op2)) { - shift = (IR(irl->op2)->i & 63); - } else if (irl->o == IR_ADD && irl->op1 == irl->op2) { - shift = 1; - } - if ((ai >> 30) == shift) { - lref = irl->op1; - irl = IR(lref); - ai |= A64I_LS_SH; - } - } - if (irl->o == IR_CONV && - irl->op2 == ((IRT_I64<op1; - ai |= A64I_LS_SXTWx; - } else { - ai |= A64I_LS_LSLx; - } - rm = ra_alloc1(as, lref, allow); - rn = ra_alloc1(as, rref, rset_exclude(allow, rm)); - emit_dnm(as, (ai^A64I_LS_R), (rd & 31), rn, rm); - return; - } - } else if (ir->o == IR_STRREF) { - if (asm_isk32(as, ir->op2, &ofs)) { - ref = ir->op1; - } else if (asm_isk32(as, ir->op1, &ofs)) { - ref = ir->op2; - } else { - Reg rn = ra_alloc1(as, ir->op1, allow); - IRIns *irr = IR(ir->op2); - uint32_t m; - if (irr+1 == ir && !ra_used(irr) && - irr->o == IR_ADD && irref_isk(irr->op2)) { - ofs = sizeof(GCstr) + IR(irr->op2)->i; - if (emit_checkofs(ai, ofs)) { - Reg rm = ra_alloc1(as, irr->op1, rset_exclude(allow, rn)); - m = A64F_M(rm) | A64F_EX(A64EX_SXTW); - goto skipopm; - } - } - m = asm_fuseopm(as, 0, ir->op2, rset_exclude(allow, rn)); - ofs = sizeof(GCstr); - skipopm: - emit_lso(as, ai, rd, rd, ofs); - emit_dn(as, A64I_ADDx^m, rd, rn); - return; - } - ofs += sizeof(GCstr); - if (!emit_checkofs(ai, ofs)) { - Reg rn = ra_alloc1(as, ref, allow); - Reg rm = ra_allock(as, ofs, rset_exclude(allow, rn)); - emit_dnm(as, (ai^A64I_LS_R)|A64I_LS_UXTWx, rd, rn, rm); - return; - } - } - } - base = ra_alloc1(as, ref, allow); - emit_lso(as, ai, (rd & 31), base, ofs); -} - -/* Fuse FP multiply-add/sub. */ -static int asm_fusemadd(ASMState *as, IRIns *ir, A64Ins ai, A64Ins air) -{ - IRRef lref = ir->op1, rref = ir->op2; - IRIns *irm; - if (lref != rref && - ((mayfuse(as, lref) && (irm = IR(lref), irm->o == IR_MUL) && - ra_noreg(irm->r)) || - (mayfuse(as, rref) && (irm = IR(rref), irm->o == IR_MUL) && - (rref = lref, ai = air, ra_noreg(irm->r))))) { - Reg dest = ra_dest(as, ir, RSET_FPR); - Reg add = ra_hintalloc(as, rref, dest, RSET_FPR); - Reg left = ra_alloc2(as, irm, - rset_exclude(rset_exclude(RSET_FPR, dest), add)); - Reg right = (left >> 8); left &= 255; - emit_dnma(as, ai, (dest & 31), (left & 31), (right & 31), (add & 31)); - return 1; - } - return 0; -} - -/* Fuse BAND + BSHL/BSHR into UBFM. */ -static int asm_fuseandshift(ASMState *as, IRIns *ir) -{ - IRIns *irl = IR(ir->op1); - lua_assert(ir->o == IR_BAND); - if (canfuse(as, irl) && irref_isk(ir->op2)) { - uint64_t mask = get_k64val(IR(ir->op2)); - if (irref_isk(irl->op2) && (irl->o == IR_BSHR || irl->o == IR_BSHL)) { - int32_t shmask = irt_is64(irl->t) ? 63 : 31; - int32_t shift = (IR(irl->op2)->i & shmask); - int32_t imms = shift; - if (irl->o == IR_BSHL) { - mask >>= shift; - shift = (shmask-shift+1) & shmask; - imms = 0; - } - if (mask && !((mask+1) & mask)) { /* Contiguous 1-bits at the bottom. */ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_alloc1(as, irl->op1, RSET_GPR); - A64Ins ai = shmask == 63 ? A64I_UBFMx : A64I_UBFMw; - imms += 63 - emit_clz64(mask); - if (imms > shmask) imms = shmask; - emit_dn(as, ai | A64F_IMMS(imms) | A64F_IMMR(shift), dest, left); - return 1; - } - } - } - return 0; -} - -/* Fuse BOR(BSHL, BSHR) into EXTR/ROR. */ -static int asm_fuseorshift(ASMState *as, IRIns *ir) -{ - IRIns *irl = IR(ir->op1), *irr = IR(ir->op2); - lua_assert(ir->o == IR_BOR); - if (canfuse(as, irl) && canfuse(as, irr) && - ((irl->o == IR_BSHR && irr->o == IR_BSHL) || - (irl->o == IR_BSHL && irr->o == IR_BSHR))) { - if (irref_isk(irl->op2) && irref_isk(irr->op2)) { - IRRef lref = irl->op1, rref = irr->op1; - uint32_t lshift = IR(irl->op2)->i, rshift = IR(irr->op2)->i; - if (irl->o == IR_BSHR) { /* BSHR needs to be the right operand. */ - uint32_t tmp2; - IRRef tmp1 = lref; lref = rref; rref = tmp1; - tmp2 = lshift; lshift = rshift; rshift = tmp2; - } - if (rshift + lshift == (irt_is64(ir->t) ? 64 : 32)) { - A64Ins ai = irt_is64(ir->t) ? A64I_EXTRx : A64I_EXTRw; - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_alloc1(as, lref, RSET_GPR); - Reg right = ra_alloc1(as, rref, rset_exclude(RSET_GPR, left)); - emit_dnm(as, ai | A64F_IMMS(rshift), dest, left, right); - return 1; - } - } - } - return 0; -} - -/* -- Calls --------------------------------------------------------------- */ - -/* Generate a call to a C function. */ -static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) -{ - uint32_t n, nargs = CCI_XNARGS(ci); - int32_t ofs = 0; - Reg gpr, fpr = REGARG_FIRSTFPR; - if ((void *)ci->func) - emit_call(as, (void *)ci->func); - for (gpr = REGARG_FIRSTGPR; gpr <= REGARG_LASTGPR; gpr++) - as->cost[gpr] = REGCOST(~0u, ASMREF_L); - gpr = REGARG_FIRSTGPR; - for (n = 0; n < nargs; n++) { /* Setup args. */ - IRRef ref = args[n]; - IRIns *ir = IR(ref); - if (ref) { - if (irt_isfp(ir->t)) { - if (fpr <= REGARG_LASTFPR) { - lua_assert(rset_test(as->freeset, fpr)); /* Must have been evicted. */ - ra_leftov(as, fpr, ref); - fpr++; - } else { - Reg r = ra_alloc1(as, ref, RSET_FPR); - emit_spstore(as, ir, r, ofs + ((LJ_BE && !irt_isnum(ir->t)) ? 4 : 0)); - ofs += 8; - } - } else { - if (gpr <= REGARG_LASTGPR) { - lua_assert(rset_test(as->freeset, gpr)); /* Must have been evicted. */ - ra_leftov(as, gpr, ref); - gpr++; - } else { - Reg r = ra_alloc1(as, ref, RSET_GPR); - emit_spstore(as, ir, r, ofs + ((LJ_BE && !irt_is64(ir->t)) ? 4 : 0)); - ofs += 8; - } - } - } - } -} - -/* Setup result reg/sp for call. Evict scratch regs. */ -static void asm_setupresult(ASMState *as, IRIns *ir, const CCallInfo *ci) -{ - RegSet drop = RSET_SCRATCH; - if (ra_hasreg(ir->r)) - rset_clear(drop, ir->r); /* Dest reg handled below. */ - ra_evictset(as, drop); /* Evictions must be performed first. */ - if (ra_used(ir)) { - lua_assert(!irt_ispri(ir->t)); - if (irt_isfp(ir->t)) { - if (ci->flags & CCI_CASTU64) { - Reg dest = ra_dest(as, ir, RSET_FPR) & 31; - emit_dn(as, irt_isnum(ir->t) ? A64I_FMOV_D_R : A64I_FMOV_S_R, - dest, RID_RET); - } else { - ra_destreg(as, ir, RID_FPRET); - } - } else { - ra_destreg(as, ir, RID_RET); - } - } - UNUSED(ci); -} - -static void asm_callx(ASMState *as, IRIns *ir) -{ - IRRef args[CCI_NARGS_MAX*2]; - CCallInfo ci; - IRRef func; - IRIns *irf; - ci.flags = asm_callx_flags(as, ir); - asm_collectargs(as, ir, &ci, args); - asm_setupresult(as, ir, &ci); - func = ir->op2; irf = IR(func); - if (irf->o == IR_CARG) { func = irf->op1; irf = IR(func); } - if (irref_isk(func)) { /* Call to constant address. */ - ci.func = (ASMFunction)(ir_k64(irf)->u64); - } else { /* Need a non-argument register for indirect calls. */ - Reg freg = ra_alloc1(as, func, RSET_RANGE(RID_X8, RID_MAX_GPR)-RSET_FIXED); - emit_n(as, A64I_BLR, freg); - ci.func = (ASMFunction)(void *)0; - } - asm_gencall(as, &ci, args); -} - -/* -- Returns ------------------------------------------------------------- */ - -/* Return to lower frame. Guard that it goes to the right spot. */ -static void asm_retf(ASMState *as, IRIns *ir) -{ - Reg base = ra_alloc1(as, REF_BASE, RSET_GPR); - void *pc = ir_kptr(IR(ir->op2)); - int32_t delta = 1+LJ_FR2+bc_a(*((const BCIns *)pc - 1)); - as->topslot -= (BCReg)delta; - if ((int32_t)as->topslot < 0) as->topslot = 0; - irt_setmark(IR(REF_BASE)->t); /* Children must not coalesce with BASE reg. */ - /* Need to force a spill on REF_BASE now to update the stack slot. */ - emit_lso(as, A64I_STRx, base, RID_SP, ra_spill(as, IR(REF_BASE))); - emit_setgl(as, base, jit_base); - emit_addptr(as, base, -8*delta); - asm_guardcc(as, CC_NE); - emit_nm(as, A64I_CMPx, RID_TMP, - ra_allock(as, i64ptr(pc), rset_exclude(RSET_GPR, base))); - emit_lso(as, A64I_LDRx, RID_TMP, base, -8); -} - -/* -- Type conversions ---------------------------------------------------- */ - -static void asm_tointg(ASMState *as, IRIns *ir, Reg left) -{ - Reg tmp = ra_scratch(as, rset_exclude(RSET_FPR, left)); - Reg dest = ra_dest(as, ir, RSET_GPR); - asm_guardcc(as, CC_NE); - emit_nm(as, A64I_FCMPd, (tmp & 31), (left & 31)); - emit_dn(as, A64I_FCVT_F64_S32, (tmp & 31), dest); - emit_dn(as, A64I_FCVT_S32_F64, dest, (left & 31)); -} - -static void asm_tobit(ASMState *as, IRIns *ir) -{ - RegSet allow = RSET_FPR; - Reg left = ra_alloc1(as, ir->op1, allow); - Reg right = ra_alloc1(as, ir->op2, rset_clear(allow, left)); - Reg tmp = ra_scratch(as, rset_clear(allow, right)); - Reg dest = ra_dest(as, ir, RSET_GPR); - emit_dn(as, A64I_FMOV_R_S, dest, (tmp & 31)); - emit_dnm(as, A64I_FADDd, (tmp & 31), (left & 31), (right & 31)); -} - -static void asm_conv(ASMState *as, IRIns *ir) -{ - IRType st = (IRType)(ir->op2 & IRCONV_SRCMASK); - int st64 = (st == IRT_I64 || st == IRT_U64 || st == IRT_P64); - int stfp = (st == IRT_NUM || st == IRT_FLOAT); - IRRef lref = ir->op1; - lua_assert(irt_type(ir->t) != st); - if (irt_isfp(ir->t)) { - Reg dest = ra_dest(as, ir, RSET_FPR); - if (stfp) { /* FP to FP conversion. */ - emit_dn(as, st == IRT_NUM ? A64I_FCVT_F32_F64 : A64I_FCVT_F64_F32, - (dest & 31), (ra_alloc1(as, lref, RSET_FPR) & 31)); - } else { /* Integer to FP conversion. */ - Reg left = ra_alloc1(as, lref, RSET_GPR); - A64Ins ai = irt_isfloat(ir->t) ? - (((IRT_IS64 >> st) & 1) ? - (st == IRT_I64 ? A64I_FCVT_F32_S64 : A64I_FCVT_F32_U64) : - (st == IRT_INT ? A64I_FCVT_F32_S32 : A64I_FCVT_F32_U32)) : - (((IRT_IS64 >> st) & 1) ? - (st == IRT_I64 ? A64I_FCVT_F64_S64 : A64I_FCVT_F64_U64) : - (st == IRT_INT ? A64I_FCVT_F64_S32 : A64I_FCVT_F64_U32)); - emit_dn(as, ai, (dest & 31), left); - } - } else if (stfp) { /* FP to integer conversion. */ - if (irt_isguard(ir->t)) { - /* Checked conversions are only supported from number to int. */ - lua_assert(irt_isint(ir->t) && st == IRT_NUM); - asm_tointg(as, ir, ra_alloc1(as, lref, RSET_FPR)); - } else { - Reg left = ra_alloc1(as, lref, RSET_FPR); - Reg dest = ra_dest(as, ir, RSET_GPR); - A64Ins ai = irt_is64(ir->t) ? - (st == IRT_NUM ? - (irt_isi64(ir->t) ? A64I_FCVT_S64_F64 : A64I_FCVT_U64_F64) : - (irt_isi64(ir->t) ? A64I_FCVT_S64_F32 : A64I_FCVT_U64_F32)) : - (st == IRT_NUM ? - (irt_isint(ir->t) ? A64I_FCVT_S32_F64 : A64I_FCVT_U32_F64) : - (irt_isint(ir->t) ? A64I_FCVT_S32_F32 : A64I_FCVT_U32_F32)); - emit_dn(as, ai, dest, (left & 31)); - } - } else if (st >= IRT_I8 && st <= IRT_U16) { /* Extend to 32 bit integer. */ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_alloc1(as, lref, RSET_GPR); - A64Ins ai = st == IRT_I8 ? A64I_SXTBw : - st == IRT_U8 ? A64I_UXTBw : - st == IRT_I16 ? A64I_SXTHw : A64I_UXTHw; - lua_assert(irt_isint(ir->t) || irt_isu32(ir->t)); - emit_dn(as, ai, dest, left); - } else { - Reg dest = ra_dest(as, ir, RSET_GPR); - if (irt_is64(ir->t)) { - if (st64 || !(ir->op2 & IRCONV_SEXT)) { - /* 64/64 bit no-op (cast) or 32 to 64 bit zero extension. */ - ra_leftov(as, dest, lref); /* Do nothing, but may need to move regs. */ - } else { /* 32 to 64 bit sign extension. */ - Reg left = ra_alloc1(as, lref, RSET_GPR); - emit_dn(as, A64I_SXTW, dest, left); - } - } else { - if (st64) { - /* This is either a 32 bit reg/reg mov which zeroes the hiword - ** or a load of the loword from a 64 bit address. - */ - Reg left = ra_alloc1(as, lref, RSET_GPR); - emit_dm(as, A64I_MOVw, dest, left); - } else { /* 32/32 bit no-op (cast). */ - ra_leftov(as, dest, lref); /* Do nothing, but may need to move regs. */ - } - } - } -} - -static void asm_strto(ASMState *as, IRIns *ir) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_strscan_num]; - IRRef args[2]; - Reg dest = 0, tmp; - int destused = ra_used(ir); - int32_t ofs = 0; - ra_evictset(as, RSET_SCRATCH); - if (destused) { - if (ra_hasspill(ir->s)) { - ofs = sps_scale(ir->s); - destused = 0; - if (ra_hasreg(ir->r)) { - ra_free(as, ir->r); - ra_modified(as, ir->r); - emit_spload(as, ir, ir->r, ofs); - } - } else { - dest = ra_dest(as, ir, RSET_FPR); - } - } - if (destused) - emit_lso(as, A64I_LDRd, (dest & 31), RID_SP, 0); - asm_guardcnb(as, A64I_CBZ, RID_RET); - args[0] = ir->op1; /* GCstr *str */ - args[1] = ASMREF_TMP1; /* TValue *n */ - asm_gencall(as, ci, args); - tmp = ra_releasetmp(as, ASMREF_TMP1); - emit_opk(as, A64I_ADDx, tmp, RID_SP, ofs, RSET_GPR); -} - -/* -- Memory references --------------------------------------------------- */ - -/* Store tagged value for ref at base+ofs. */ -static void asm_tvstore64(ASMState *as, Reg base, int32_t ofs, IRRef ref) -{ - RegSet allow = rset_exclude(RSET_GPR, base); - IRIns *ir = IR(ref); - lua_assert(irt_ispri(ir->t) || irt_isaddr(ir->t) || irt_isinteger(ir->t)); - if (irref_isk(ref)) { - TValue k; - lj_ir_kvalue(as->J->L, &k, ir); - emit_lso(as, A64I_STRx, ra_allock(as, k.u64, allow), base, ofs); - } else { - Reg src = ra_alloc1(as, ref, allow); - rset_clear(allow, src); - if (irt_isinteger(ir->t)) { - Reg type = ra_allock(as, (int64_t)irt_toitype(ir->t) << 47, allow); - emit_lso(as, A64I_STRx, RID_TMP, base, ofs); - emit_dnm(as, A64I_ADDx | A64F_EX(A64EX_UXTW), RID_TMP, type, src); - } else { - Reg type = ra_allock(as, (int32_t)irt_toitype(ir->t), allow); - emit_lso(as, A64I_STRx, RID_TMP, base, ofs); - emit_dnm(as, A64I_ADDx | A64F_SH(A64SH_LSL, 47), RID_TMP, src, type); - } - } -} - -/* Get pointer to TValue. */ -static void asm_tvptr(ASMState *as, Reg dest, IRRef ref) -{ - IRIns *ir = IR(ref); - if (irt_isnum(ir->t)) { - if (irref_isk(ref)) { - /* Use the number constant itself as a TValue. */ - ra_allockreg(as, i64ptr(ir_knum(ir)), dest); - } else { - /* Otherwise force a spill and use the spill slot. */ - emit_opk(as, A64I_ADDx, dest, RID_SP, ra_spill(as, ir), RSET_GPR); - } - } else { - /* Otherwise use g->tmptv to hold the TValue. */ - asm_tvstore64(as, dest, 0, ref); - ra_allockreg(as, i64ptr(&J2G(as->J)->tmptv), dest); - } -} - -static void asm_aref(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg idx, base; - if (irref_isk(ir->op2)) { - IRRef tab = IR(ir->op1)->op1; - int32_t ofs = asm_fuseabase(as, tab); - IRRef refa = ofs ? tab : ir->op1; - uint32_t k = emit_isk12(ofs + 8*IR(ir->op2)->i); - if (k) { - base = ra_alloc1(as, refa, RSET_GPR); - emit_dn(as, A64I_ADDx^k, dest, base); - return; - } - } - base = ra_alloc1(as, ir->op1, RSET_GPR); - idx = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, base)); - emit_dnm(as, A64I_ADDx | A64F_EXSH(A64EX_UXTW, 3), dest, base, idx); -} - -/* Inlined hash lookup. Specialized for key type and for const keys. -** The equivalent C code is: -** Node *n = hashkey(t, key); -** do { -** if (lj_obj_equal(&n->key, key)) return &n->val; -** } while ((n = nextnode(n))); -** return niltv(L); -*/ -static void asm_href(ASMState *as, IRIns *ir, IROp merge) -{ - RegSet allow = RSET_GPR; - int destused = ra_used(ir); - Reg dest = ra_dest(as, ir, allow); - Reg tab = ra_alloc1(as, ir->op1, rset_clear(allow, dest)); - Reg key = 0, tmp = RID_TMP; - IRRef refkey = ir->op2; - IRIns *irkey = IR(refkey); - int isk = irref_isk(ir->op2); - IRType1 kt = irkey->t; - uint32_t k = 0; - uint32_t khash; - MCLabel l_end, l_loop, l_next; - rset_clear(allow, tab); - - if (!isk) { - key = ra_alloc1(as, ir->op2, irt_isnum(kt) ? RSET_FPR : allow); - rset_clear(allow, key); - if (!irt_isstr(kt)) { - tmp = ra_scratch(as, allow); - rset_clear(allow, tmp); - } - } else if (irt_isnum(kt)) { - int64_t val = (int64_t)ir_knum(irkey)->u64; - if (!(k = emit_isk12(val))) { - key = ra_allock(as, val, allow); - rset_clear(allow, key); - } - } else if (!irt_ispri(kt)) { - if (!(k = emit_isk12(irkey->i))) { - key = ra_alloc1(as, refkey, allow); - rset_clear(allow, key); - } - } - - /* Key not found in chain: jump to exit (if merged) or load niltv. */ - l_end = emit_label(as); - as->invmcp = NULL; - if (merge == IR_NE) - asm_guardcc(as, CC_AL); - else if (destused) - emit_loada(as, dest, niltvg(J2G(as->J))); - - /* Follow hash chain until the end. */ - l_loop = --as->mcp; - emit_n(as, A64I_CMPx^A64I_K12^0, dest); - emit_lso(as, A64I_LDRx, dest, dest, offsetof(Node, next)); - l_next = emit_label(as); - - /* Type and value comparison. */ - if (merge == IR_EQ) - asm_guardcc(as, CC_EQ); - else - emit_cond_branch(as, CC_EQ, l_end); - - if (irt_isnum(kt)) { - if (isk) { - /* Assumes -0.0 is already canonicalized to +0.0. */ - if (k) - emit_n(as, A64I_CMPx^k, tmp); - else - emit_nm(as, A64I_CMPx, key, tmp); - emit_lso(as, A64I_LDRx, tmp, dest, offsetof(Node, key.u64)); - } else { - Reg tisnum = ra_allock(as, LJ_TISNUM << 15, allow); - Reg ftmp = ra_scratch(as, rset_exclude(RSET_FPR, key)); - rset_clear(allow, tisnum); - emit_nm(as, A64I_FCMPd, key, ftmp); - emit_dn(as, A64I_FMOV_D_R, (ftmp & 31), (tmp & 31)); - emit_cond_branch(as, CC_LO, l_next); - emit_nm(as, A64I_CMPx | A64F_SH(A64SH_LSR, 32), tisnum, tmp); - emit_lso(as, A64I_LDRx, tmp, dest, offsetof(Node, key.n)); - } - } else if (irt_isaddr(kt)) { - Reg scr; - if (isk) { - int64_t kk = ((int64_t)irt_toitype(irkey->t) << 47) | irkey[1].tv.u64; - scr = ra_allock(as, kk, allow); - emit_nm(as, A64I_CMPx, scr, tmp); - emit_lso(as, A64I_LDRx, tmp, dest, offsetof(Node, key.u64)); - } else { - scr = ra_scratch(as, allow); - emit_nm(as, A64I_CMPx, tmp, scr); - emit_lso(as, A64I_LDRx, scr, dest, offsetof(Node, key.u64)); - } - rset_clear(allow, scr); - } else { - Reg type, scr; - lua_assert(irt_ispri(kt) && !irt_isnil(kt)); - type = ra_allock(as, ~((int64_t)~irt_toitype(ir->t) << 47), allow); - scr = ra_scratch(as, rset_clear(allow, type)); - rset_clear(allow, scr); - emit_nm(as, A64I_CMPw, scr, type); - emit_lso(as, A64I_LDRx, scr, dest, offsetof(Node, key)); - } - - *l_loop = A64I_BCC | A64F_S19(as->mcp - l_loop) | CC_NE; - if (!isk && irt_isaddr(kt)) { - Reg type = ra_allock(as, (int32_t)irt_toitype(kt), allow); - emit_dnm(as, A64I_ADDx | A64F_SH(A64SH_LSL, 47), tmp, key, type); - rset_clear(allow, type); - } - /* Load main position relative to tab->node into dest. */ - khash = isk ? ir_khash(irkey) : 1; - if (khash == 0) { - emit_lso(as, A64I_LDRx, dest, tab, offsetof(GCtab, node)); - } else { - emit_dnm(as, A64I_ADDx | A64F_SH(A64SH_LSL, 3), dest, tmp, dest); - emit_dnm(as, A64I_ADDx | A64F_SH(A64SH_LSL, 1), dest, dest, dest); - emit_lso(as, A64I_LDRx, tmp, tab, offsetof(GCtab, node)); - if (isk) { - Reg tmphash = ra_allock(as, khash, allow); - emit_dnm(as, A64I_ANDw, dest, dest, tmphash); - emit_lso(as, A64I_LDRw, dest, tab, offsetof(GCtab, hmask)); - } else if (irt_isstr(kt)) { - /* Fetch of str->hash is cheaper than ra_allock. */ - emit_dnm(as, A64I_ANDw, dest, dest, tmp); - emit_lso(as, A64I_LDRw, tmp, key, offsetof(GCstr, hash)); - emit_lso(as, A64I_LDRw, dest, tab, offsetof(GCtab, hmask)); - } else { /* Must match with hash*() in lj_tab.c. */ - emit_dnm(as, A64I_ANDw, dest, dest, tmp); - emit_lso(as, A64I_LDRw, tmp, tab, offsetof(GCtab, hmask)); - emit_dnm(as, A64I_SUBw, dest, dest, tmp); - emit_dnm(as, A64I_EXTRw | (A64F_IMMS(32-HASH_ROT3)), tmp, tmp, tmp); - emit_dnm(as, A64I_EORw, dest, dest, tmp); - emit_dnm(as, A64I_EXTRw | (A64F_IMMS(32-HASH_ROT2)), dest, dest, dest); - emit_dnm(as, A64I_SUBw, tmp, tmp, dest); - emit_dnm(as, A64I_EXTRw | (A64F_IMMS(32-HASH_ROT1)), dest, dest, dest); - emit_dnm(as, A64I_EORw, tmp, tmp, dest); - if (irt_isnum(kt)) { - emit_dnm(as, A64I_ADDw, dest, dest, dest); - emit_dn(as, A64I_LSRx | A64F_IMMR(32)|A64F_IMMS(32), dest, dest); - emit_dm(as, A64I_MOVw, tmp, dest); - emit_dn(as, A64I_FMOV_R_D, dest, (key & 31)); - } else { - checkmclim(as); - emit_dm(as, A64I_MOVw, tmp, key); - emit_dnm(as, A64I_EORw, dest, dest, - ra_allock(as, irt_toitype(kt) << 15, allow)); - emit_dn(as, A64I_LSRx | A64F_IMMR(32)|A64F_IMMS(32), dest, dest); - emit_dm(as, A64I_MOVx, dest, key); - } - } - } -} - -static void asm_hrefk(ASMState *as, IRIns *ir) -{ - IRIns *kslot = IR(ir->op2); - IRIns *irkey = IR(kslot->op1); - int32_t ofs = (int32_t)(kslot->op2 * sizeof(Node)); - int32_t kofs = ofs + (int32_t)offsetof(Node, key); - int bigofs = !emit_checkofs(A64I_LDRx, ofs); - Reg dest = (ra_used(ir) || bigofs) ? ra_dest(as, ir, RSET_GPR) : RID_NONE; - Reg node = ra_alloc1(as, ir->op1, RSET_GPR); - Reg key, idx = node; - RegSet allow = rset_exclude(RSET_GPR, node); - uint64_t k; - lua_assert(ofs % sizeof(Node) == 0); - if (bigofs) { - idx = dest; - rset_clear(allow, dest); - kofs = (int32_t)offsetof(Node, key); - } else if (ra_hasreg(dest)) { - emit_opk(as, A64I_ADDx, dest, node, ofs, allow); - } - asm_guardcc(as, CC_NE); - if (irt_ispri(irkey->t)) { - k = ~((int64_t)~irt_toitype(irkey->t) << 47); - } else if (irt_isnum(irkey->t)) { - k = ir_knum(irkey)->u64; - } else { - k = ((uint64_t)irt_toitype(irkey->t) << 47) | (uint64_t)ir_kgc(irkey); - } - key = ra_scratch(as, allow); - emit_nm(as, A64I_CMPx, key, ra_allock(as, k, rset_exclude(allow, key))); - emit_lso(as, A64I_LDRx, key, idx, kofs); - if (bigofs) - emit_opk(as, A64I_ADDx, dest, node, ofs, RSET_GPR); -} - -static void asm_uref(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - if (irref_isk(ir->op1)) { - GCfunc *fn = ir_kfunc(IR(ir->op1)); - MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v; - emit_lsptr(as, A64I_LDRx, dest, v); - } else { - Reg uv = ra_scratch(as, RSET_GPR); - Reg func = ra_alloc1(as, ir->op1, RSET_GPR); - if (ir->o == IR_UREFC) { - asm_guardcc(as, CC_NE); - emit_n(as, (A64I_CMPx^A64I_K12) | A64F_U12(1), RID_TMP); - emit_opk(as, A64I_ADDx, dest, uv, - (int32_t)offsetof(GCupval, tv), RSET_GPR); - emit_lso(as, A64I_LDRB, RID_TMP, uv, (int32_t)offsetof(GCupval, closed)); - } else { - emit_lso(as, A64I_LDRx, dest, uv, (int32_t)offsetof(GCupval, v)); - } - emit_lso(as, A64I_LDRx, uv, func, - (int32_t)offsetof(GCfuncL, uvptr) + 8*(int32_t)(ir->op2 >> 8)); - } -} - -static void asm_fref(ASMState *as, IRIns *ir) -{ - UNUSED(as); UNUSED(ir); - lua_assert(!ra_used(ir)); -} - -static void asm_strref(ASMState *as, IRIns *ir) -{ - RegSet allow = RSET_GPR; - Reg dest = ra_dest(as, ir, allow); - Reg base = ra_alloc1(as, ir->op1, allow); - IRIns *irr = IR(ir->op2); - int32_t ofs = sizeof(GCstr); - uint32_t m; - rset_clear(allow, base); - if (irref_isk(ir->op2) && (m = emit_isk12(ofs + irr->i))) { - emit_dn(as, A64I_ADDx^m, dest, base); - } else { - emit_dn(as, (A64I_ADDx^A64I_K12) | A64F_U12(ofs), dest, dest); - emit_dnm(as, A64I_ADDx, dest, base, ra_alloc1(as, ir->op2, allow)); - } -} - -/* -- Loads and stores ---------------------------------------------------- */ - -static A64Ins asm_fxloadins(IRIns *ir) -{ - switch (irt_type(ir->t)) { - case IRT_I8: return A64I_LDRB ^ A64I_LS_S; - case IRT_U8: return A64I_LDRB; - case IRT_I16: return A64I_LDRH ^ A64I_LS_S; - case IRT_U16: return A64I_LDRH; - case IRT_NUM: return A64I_LDRd; - case IRT_FLOAT: return A64I_LDRs; - default: return irt_is64(ir->t) ? A64I_LDRx : A64I_LDRw; - } -} - -static A64Ins asm_fxstoreins(IRIns *ir) -{ - switch (irt_type(ir->t)) { - case IRT_I8: case IRT_U8: return A64I_STRB; - case IRT_I16: case IRT_U16: return A64I_STRH; - case IRT_NUM: return A64I_STRd; - case IRT_FLOAT: return A64I_STRs; - default: return irt_is64(ir->t) ? A64I_STRx : A64I_STRw; - } -} - -static void asm_fload(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg idx; - A64Ins ai = asm_fxloadins(ir); - int32_t ofs; - if (ir->op1 == REF_NIL) { - idx = RID_GL; - ofs = (ir->op2 << 2) - GG_OFS(g); - } else { - idx = ra_alloc1(as, ir->op1, RSET_GPR); - if (ir->op2 == IRFL_TAB_ARRAY) { - ofs = asm_fuseabase(as, ir->op1); - if (ofs) { /* Turn the t->array load into an add for colocated arrays. */ - emit_dn(as, (A64I_ADDx^A64I_K12) | A64F_U12(ofs), dest, idx); - return; - } - } - ofs = field_ofs[ir->op2]; - } - emit_lso(as, ai, (dest & 31), idx, ofs); -} - -static void asm_fstore(ASMState *as, IRIns *ir) -{ - if (ir->r != RID_SINK) { - Reg src = ra_alloc1(as, ir->op2, RSET_GPR); - IRIns *irf = IR(ir->op1); - Reg idx = ra_alloc1(as, irf->op1, rset_exclude(RSET_GPR, src)); - int32_t ofs = field_ofs[irf->op2]; - emit_lso(as, asm_fxstoreins(ir), (src & 31), idx, ofs); - } -} - -static void asm_xload(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, irt_isfp(ir->t) ? RSET_FPR : RSET_GPR); - lua_assert(!(ir->op2 & IRXLOAD_UNALIGNED)); - asm_fusexref(as, asm_fxloadins(ir), dest, ir->op1, RSET_GPR); -} - -static void asm_xstore(ASMState *as, IRIns *ir) -{ - if (ir->r != RID_SINK) { - Reg src = ra_alloc1(as, ir->op2, irt_isfp(ir->t) ? RSET_FPR : RSET_GPR); - asm_fusexref(as, asm_fxstoreins(ir), src, ir->op1, - rset_exclude(RSET_GPR, src)); - } -} - -static void asm_ahuvload(ASMState *as, IRIns *ir) -{ - Reg idx, tmp, type; - int32_t ofs = 0; - RegSet gpr = RSET_GPR, allow = irt_isnum(ir->t) ? RSET_FPR : RSET_GPR; - lua_assert(irt_isnum(ir->t) || irt_ispri(ir->t) || irt_isaddr(ir->t) || - irt_isint(ir->t)); - if (ra_used(ir)) { - Reg dest = ra_dest(as, ir, allow); - tmp = irt_isnum(ir->t) ? ra_scratch(as, rset_clear(gpr, dest)) : dest; - if (irt_isaddr(ir->t)) { - emit_dn(as, A64I_ANDx^emit_isk13(LJ_GCVMASK, 1), dest, dest); - } else if (irt_isnum(ir->t)) { - emit_dn(as, A64I_FMOV_D_R, (dest & 31), tmp); - } else if (irt_isint(ir->t)) { - emit_dm(as, A64I_MOVw, dest, dest); - } - } else { - tmp = ra_scratch(as, gpr); - } - type = ra_scratch(as, rset_clear(gpr, tmp)); - idx = asm_fuseahuref(as, ir->op1, &ofs, rset_clear(gpr, type), A64I_LDRx); - /* Always do the type check, even if the load result is unused. */ - asm_guardcc(as, irt_isnum(ir->t) ? CC_LS : CC_NE); - if (irt_type(ir->t) >= IRT_NUM) { - lua_assert(irt_isinteger(ir->t) || irt_isnum(ir->t)); - emit_nm(as, A64I_CMPx | A64F_SH(A64SH_LSR, 32), - ra_allock(as, LJ_TISNUM << 15, rset_exclude(gpr, idx)), tmp); - } else if (irt_isaddr(ir->t)) { - emit_n(as, (A64I_CMNx^A64I_K12) | A64F_U12(-irt_toitype(ir->t)), type); - emit_dn(as, A64I_ASRx | A64F_IMMR(47), type, tmp); - } else if (irt_isnil(ir->t)) { - emit_n(as, (A64I_CMNx^A64I_K12) | A64F_U12(1), tmp); - } else { - emit_nm(as, A64I_CMPx | A64F_SH(A64SH_LSR, 32), - ra_allock(as, (irt_toitype(ir->t) << 15) | 0x7fff, allow), tmp); - } - if (ofs & FUSE_REG) - emit_dnm(as, (A64I_LDRx^A64I_LS_R)|A64I_LS_UXTWx|A64I_LS_SH, tmp, idx, (ofs & 31)); - else - emit_lso(as, A64I_LDRx, tmp, idx, ofs); -} - -static void asm_ahustore(ASMState *as, IRIns *ir) -{ - if (ir->r != RID_SINK) { - RegSet allow = RSET_GPR; - Reg idx, src = RID_NONE, tmp = RID_TMP, type = RID_NONE; - int32_t ofs = 0; - if (irt_isnum(ir->t)) { - src = ra_alloc1(as, ir->op2, RSET_FPR); - idx = asm_fuseahuref(as, ir->op1, &ofs, allow, A64I_STRd); - if (ofs & FUSE_REG) - emit_dnm(as, (A64I_STRd^A64I_LS_R)|A64I_LS_UXTWx|A64I_LS_SH, (src & 31), idx, (ofs &31)); - else - emit_lso(as, A64I_STRd, (src & 31), idx, ofs); - } else { - if (!irt_ispri(ir->t)) { - src = ra_alloc1(as, ir->op2, allow); - rset_clear(allow, src); - if (irt_isinteger(ir->t)) - type = ra_allock(as, (uint64_t)(int32_t)LJ_TISNUM << 47, allow); - else - type = ra_allock(as, irt_toitype(ir->t), allow); - } else { - tmp = type = ra_allock(as, ~((int64_t)~irt_toitype(ir->t)<<47), allow); - } - idx = asm_fuseahuref(as, ir->op1, &ofs, rset_exclude(allow, type), - A64I_STRx); - if (ofs & FUSE_REG) - emit_dnm(as, (A64I_STRx^A64I_LS_R)|A64I_LS_UXTWx|A64I_LS_SH, tmp, idx, (ofs & 31)); - else - emit_lso(as, A64I_STRx, tmp, idx, ofs); - if (ra_hasreg(src)) { - if (irt_isinteger(ir->t)) { - emit_dnm(as, A64I_ADDx | A64F_EX(A64EX_UXTW), tmp, type, src); - } else { - emit_dnm(as, A64I_ADDx | A64F_SH(A64SH_LSL, 47), tmp, src, type); - } - } - } - } -} - -static void asm_sload(ASMState *as, IRIns *ir) -{ - int32_t ofs = 8*((int32_t)ir->op1-2); - IRType1 t = ir->t; - Reg dest = RID_NONE, base; - RegSet allow = RSET_GPR; - lua_assert(!(ir->op2 & IRSLOAD_PARENT)); /* Handled by asm_head_side(). */ - lua_assert(irt_isguard(t) || !(ir->op2 & IRSLOAD_TYPECHECK)); - if ((ir->op2 & IRSLOAD_CONVERT) && irt_isguard(t) && irt_isint(t)) { - dest = ra_scratch(as, RSET_FPR); - asm_tointg(as, ir, dest); - t.irt = IRT_NUM; /* Continue with a regular number type check. */ - } else if (ra_used(ir)) { - Reg tmp = RID_NONE; - if ((ir->op2 & IRSLOAD_CONVERT)) - tmp = ra_scratch(as, irt_isint(t) ? RSET_FPR : RSET_GPR); - lua_assert((irt_isnum(t)) || irt_isint(t) || irt_isaddr(t)); - dest = ra_dest(as, ir, irt_isnum(t) ? RSET_FPR : allow); - base = ra_alloc1(as, REF_BASE, rset_clear(allow, dest)); - if (irt_isaddr(t)) { - emit_dn(as, A64I_ANDx^emit_isk13(LJ_GCVMASK, 1), dest, dest); - } else if ((ir->op2 & IRSLOAD_CONVERT)) { - if (irt_isint(t)) { - emit_dn(as, A64I_FCVT_S32_F64, dest, (tmp & 31)); - /* If value is already loaded for type check, move it to FPR. */ - if ((ir->op2 & IRSLOAD_TYPECHECK)) - emit_dn(as, A64I_FMOV_D_R, (tmp & 31), dest); - else - dest = tmp; - t.irt = IRT_NUM; /* Check for original type. */ - } else { - emit_dn(as, A64I_FCVT_F64_S32, (dest & 31), tmp); - dest = tmp; - t.irt = IRT_INT; /* Check for original type. */ - } - } else if (irt_isint(t) && (ir->op2 & IRSLOAD_TYPECHECK)) { - emit_dm(as, A64I_MOVw, dest, dest); - } - goto dotypecheck; - } - base = ra_alloc1(as, REF_BASE, allow); -dotypecheck: - rset_clear(allow, base); - if ((ir->op2 & IRSLOAD_TYPECHECK)) { - Reg tmp; - if (ra_hasreg(dest) && rset_test(RSET_GPR, dest)) { - tmp = dest; - } else { - tmp = ra_scratch(as, allow); - rset_clear(allow, tmp); - } - if (irt_isnum(t) && !(ir->op2 & IRSLOAD_CONVERT)) - emit_dn(as, A64I_FMOV_D_R, (dest & 31), tmp); - /* Need type check, even if the load result is unused. */ - asm_guardcc(as, irt_isnum(t) ? CC_LS : CC_NE); - if (irt_type(t) >= IRT_NUM) { - lua_assert(irt_isinteger(t) || irt_isnum(t)); - emit_nm(as, A64I_CMPx | A64F_SH(A64SH_LSR, 32), - ra_allock(as, LJ_TISNUM << 15, allow), tmp); - } else if (irt_isnil(t)) { - emit_n(as, (A64I_CMNx^A64I_K12) | A64F_U12(1), tmp); - } else if (irt_ispri(t)) { - emit_nm(as, A64I_CMPx, - ra_allock(as, ~((int64_t)~irt_toitype(t) << 47) , allow), tmp); - } else { - Reg type = ra_scratch(as, allow); - emit_n(as, (A64I_CMNx^A64I_K12) | A64F_U12(-irt_toitype(t)), type); - emit_dn(as, A64I_ASRx | A64F_IMMR(47), type, tmp); - } - emit_lso(as, A64I_LDRx, tmp, base, ofs); - return; - } - if (ra_hasreg(dest)) { - emit_lso(as, irt_isnum(t) ? A64I_LDRd : - (irt_isint(t) ? A64I_LDRw : A64I_LDRx), (dest & 31), base, - ofs ^ ((LJ_BE && irt_isint(t) ? 4 : 0))); - } -} - -/* -- Allocations --------------------------------------------------------- */ - -#if LJ_HASFFI -static void asm_cnew(ASMState *as, IRIns *ir) -{ - CTState *cts = ctype_ctsG(J2G(as->J)); - CTypeID id = (CTypeID)IR(ir->op1)->i; - CTSize sz; - CTInfo info = lj_ctype_info(cts, id, &sz); - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_mem_newgco]; - IRRef args[4]; - RegSet allow = (RSET_GPR & ~RSET_SCRATCH); - lua_assert(sz != CTSIZE_INVALID || (ir->o == IR_CNEW && ir->op2 != REF_NIL)); - - as->gcsteps++; - asm_setupresult(as, ir, ci); /* GCcdata * */ - /* Initialize immutable cdata object. */ - if (ir->o == IR_CNEWI) { - int32_t ofs = sizeof(GCcdata); - Reg r = ra_alloc1(as, ir->op2, allow); - lua_assert(sz == 4 || sz == 8); - emit_lso(as, sz == 8 ? A64I_STRx : A64I_STRw, r, RID_RET, ofs); - } else if (ir->op2 != REF_NIL) { /* Create VLA/VLS/aligned cdata. */ - ci = &lj_ir_callinfo[IRCALL_lj_cdata_newv]; - args[0] = ASMREF_L; /* lua_State *L */ - args[1] = ir->op1; /* CTypeID id */ - args[2] = ir->op2; /* CTSize sz */ - args[3] = ASMREF_TMP1; /* CTSize align */ - asm_gencall(as, ci, args); - emit_loadi(as, ra_releasetmp(as, ASMREF_TMP1), (int32_t)ctype_align(info)); - return; - } - - /* Initialize gct and ctypeid. lj_mem_newgco() already sets marked. */ - { - Reg r = (id < 65536) ? RID_X1 : ra_allock(as, id, allow); - emit_lso(as, A64I_STRB, RID_TMP, RID_RET, offsetof(GCcdata, gct)); - emit_lso(as, A64I_STRH, r, RID_RET, offsetof(GCcdata, ctypeid)); - emit_d(as, A64I_MOVZw | A64F_U16(~LJ_TCDATA), RID_TMP); - if (id < 65536) emit_d(as, A64I_MOVZw | A64F_U16(id), RID_X1); - } - args[0] = ASMREF_L; /* lua_State *L */ - args[1] = ASMREF_TMP1; /* MSize size */ - asm_gencall(as, ci, args); - ra_allockreg(as, (int32_t)(sz+sizeof(GCcdata)), - ra_releasetmp(as, ASMREF_TMP1)); -} -#else -#define asm_cnew(as, ir) ((void)0) -#endif - -/* -- Write barriers ------------------------------------------------------ */ - -static void asm_tbar(ASMState *as, IRIns *ir) -{ - Reg tab = ra_alloc1(as, ir->op1, RSET_GPR); - Reg link = ra_scratch(as, rset_exclude(RSET_GPR, tab)); - Reg gr = ra_allock(as, i64ptr(J2G(as->J)), - rset_exclude(rset_exclude(RSET_GPR, tab), link)); - Reg mark = RID_TMP; - MCLabel l_end = emit_label(as); - emit_lso(as, A64I_STRx, link, tab, (int32_t)offsetof(GCtab, gclist)); - emit_lso(as, A64I_STRB, mark, tab, (int32_t)offsetof(GCtab, marked)); - emit_lso(as, A64I_STRx, tab, gr, - (int32_t)offsetof(global_State, gc.grayagain)); - emit_dn(as, A64I_ANDw^emit_isk13(~LJ_GC_BLACK, 0), mark, mark); - emit_lso(as, A64I_LDRx, link, gr, - (int32_t)offsetof(global_State, gc.grayagain)); - emit_cond_branch(as, CC_EQ, l_end); - emit_n(as, A64I_TSTw^emit_isk13(LJ_GC_BLACK, 0), mark); - emit_lso(as, A64I_LDRB, mark, tab, (int32_t)offsetof(GCtab, marked)); -} - -static void asm_obar(ASMState *as, IRIns *ir) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_gc_barrieruv]; - IRRef args[2]; - MCLabel l_end; - RegSet allow = RSET_GPR; - Reg obj, val, tmp; - /* No need for other object barriers (yet). */ - lua_assert(IR(ir->op1)->o == IR_UREFC); - ra_evictset(as, RSET_SCRATCH); - l_end = emit_label(as); - args[0] = ASMREF_TMP1; /* global_State *g */ - args[1] = ir->op1; /* TValue *tv */ - asm_gencall(as, ci, args); - ra_allockreg(as, i64ptr(J2G(as->J)), ra_releasetmp(as, ASMREF_TMP1) ); - obj = IR(ir->op1)->r; - tmp = ra_scratch(as, rset_exclude(allow, obj)); - emit_cond_branch(as, CC_EQ, l_end); - emit_n(as, A64I_TSTw^emit_isk13(LJ_GC_BLACK, 0), tmp); - emit_cond_branch(as, CC_EQ, l_end); - emit_n(as, A64I_TSTw^emit_isk13(LJ_GC_WHITES, 0), RID_TMP); - val = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, obj)); - emit_lso(as, A64I_LDRB, tmp, obj, - (int32_t)offsetof(GCupval, marked)-(int32_t)offsetof(GCupval, tv)); - emit_lso(as, A64I_LDRB, RID_TMP, val, (int32_t)offsetof(GChead, marked)); -} - -/* -- Arithmetic and logic operations ------------------------------------- */ - -static void asm_fparith(ASMState *as, IRIns *ir, A64Ins ai) -{ - Reg dest = ra_dest(as, ir, RSET_FPR); - Reg right, left = ra_alloc2(as, ir, RSET_FPR); - right = (left >> 8); left &= 255; - emit_dnm(as, ai, (dest & 31), (left & 31), (right & 31)); -} - -static void asm_fpunary(ASMState *as, IRIns *ir, A64Ins ai) -{ - Reg dest = ra_dest(as, ir, RSET_FPR); - Reg left = ra_hintalloc(as, ir->op1, dest, RSET_FPR); - emit_dn(as, ai, (dest & 31), (left & 31)); -} - -static void asm_fpmath(ASMState *as, IRIns *ir) -{ - IRFPMathOp fpm = (IRFPMathOp)ir->op2; - if (fpm == IRFPM_SQRT) { - asm_fpunary(as, ir, A64I_FSQRTd); - } else if (fpm <= IRFPM_TRUNC) { - asm_fpunary(as, ir, fpm == IRFPM_FLOOR ? A64I_FRINTMd : - fpm == IRFPM_CEIL ? A64I_FRINTPd : A64I_FRINTZd); - } else if (fpm == IRFPM_EXP2 && asm_fpjoin_pow(as, ir)) { - return; - } else { - asm_callid(as, ir, IRCALL_lj_vm_floor + fpm); - } -} - -static int asm_swapops(ASMState *as, IRRef lref, IRRef rref) -{ - IRIns *ir; - if (irref_isk(rref)) - return 0; /* Don't swap constants to the left. */ - if (irref_isk(lref)) - return 1; /* But swap constants to the right. */ - ir = IR(rref); - if ((ir->o >= IR_BSHL && ir->o <= IR_BSAR) || - (ir->o == IR_ADD && ir->op1 == ir->op2) || - (ir->o == IR_CONV && ir->op2 == ((IRT_I64<o >= IR_BSHL && ir->o <= IR_BSAR) || - (ir->o == IR_ADD && ir->op1 == ir->op2) || - (ir->o == IR_CONV && ir->op2 == ((IRT_I64<op1, rref = ir->op2; - Reg left, dest = ra_dest(as, ir, RSET_GPR); - uint32_t m; - if ((ai & ~A64I_S) != A64I_SUBw && asm_swapops(as, lref, rref)) { - IRRef tmp = lref; lref = rref; rref = tmp; - } - left = ra_hintalloc(as, lref, dest, RSET_GPR); - if (irt_is64(ir->t)) ai |= A64I_X; - m = asm_fuseopm(as, ai, rref, rset_exclude(RSET_GPR, left)); - if (irt_isguard(ir->t)) { /* For IR_ADDOV etc. */ - asm_guardcc(as, CC_VS); - ai |= A64I_S; - } - emit_dn(as, ai^m, dest, left); -} - -static void asm_intop_s(ASMState *as, IRIns *ir, A64Ins ai) -{ - if (as->flagmcp == as->mcp) { /* Drop cmp r, #0. */ - as->flagmcp = NULL; - as->mcp++; - ai |= A64I_S; - } - asm_intop(as, ir, ai); -} - -static void asm_intneg(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); - emit_dm(as, irt_is64(ir->t) ? A64I_NEGx : A64I_NEGw, dest, left); -} - -/* NYI: use add/shift for MUL(OV) with constants. FOLD only does 2^k. */ -static void asm_intmul(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_alloc1(as, ir->op1, rset_exclude(RSET_GPR, dest)); - Reg right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left)); - if (irt_isguard(ir->t)) { /* IR_MULOV */ - asm_guardcc(as, CC_NE); - emit_dm(as, A64I_MOVw, dest, dest); /* Zero-extend. */ - emit_nm(as, A64I_CMPw | A64F_SH(A64SH_ASR, 31), RID_TMP, dest); - emit_dn(as, A64I_ASRx | A64F_IMMR(32), RID_TMP, dest); - emit_dnm(as, A64I_SMULL, dest, right, left); - } else { - emit_dnm(as, irt_is64(ir->t) ? A64I_MULx : A64I_MULw, dest, left, right); - } -} - -static void asm_add(ASMState *as, IRIns *ir) -{ - if (irt_isnum(ir->t)) { - if (!asm_fusemadd(as, ir, A64I_FMADDd, A64I_FMADDd)) - asm_fparith(as, ir, A64I_FADDd); - return; - } - asm_intop_s(as, ir, A64I_ADDw); -} - -static void asm_sub(ASMState *as, IRIns *ir) -{ - if (irt_isnum(ir->t)) { - if (!asm_fusemadd(as, ir, A64I_FNMSUBd, A64I_FMSUBd)) - asm_fparith(as, ir, A64I_FSUBd); - return; - } - asm_intop_s(as, ir, A64I_SUBw); -} - -static void asm_mul(ASMState *as, IRIns *ir) -{ - if (irt_isnum(ir->t)) { - asm_fparith(as, ir, A64I_FMULd); - return; - } - asm_intmul(as, ir); -} - -static void asm_div(ASMState *as, IRIns *ir) -{ -#if LJ_HASFFI - if (!irt_isnum(ir->t)) - asm_callid(as, ir, irt_isi64(ir->t) ? IRCALL_lj_carith_divi64 : - IRCALL_lj_carith_divu64); - else -#endif - asm_fparith(as, ir, A64I_FDIVd); -} - -static void asm_pow(ASMState *as, IRIns *ir) -{ -#if LJ_HASFFI - if (!irt_isnum(ir->t)) - asm_callid(as, ir, irt_isi64(ir->t) ? IRCALL_lj_carith_powi64 : - IRCALL_lj_carith_powu64); - else -#endif - asm_callid(as, ir, IRCALL_lj_vm_powi); -} - -#define asm_addov(as, ir) asm_add(as, ir) -#define asm_subov(as, ir) asm_sub(as, ir) -#define asm_mulov(as, ir) asm_mul(as, ir) - -#define asm_abs(as, ir) asm_fpunary(as, ir, A64I_FABS) -#define asm_atan2(as, ir) asm_callid(as, ir, IRCALL_atan2) -#define asm_ldexp(as, ir) asm_callid(as, ir, IRCALL_ldexp) - -static void asm_mod(ASMState *as, IRIns *ir) -{ -#if LJ_HASFFI - if (!irt_isint(ir->t)) - asm_callid(as, ir, irt_isi64(ir->t) ? IRCALL_lj_carith_modi64 : - IRCALL_lj_carith_modu64); - else -#endif - asm_callid(as, ir, IRCALL_lj_vm_modi); -} - -static void asm_neg(ASMState *as, IRIns *ir) -{ - if (irt_isnum(ir->t)) { - asm_fpunary(as, ir, A64I_FNEGd); - return; - } - asm_intneg(as, ir); -} - -static void asm_band(ASMState *as, IRIns *ir) -{ - A64Ins ai = A64I_ANDw; - if (asm_fuseandshift(as, ir)) - return; - if (as->flagmcp == as->mcp) { - /* Try to drop cmp r, #0. */ - as->flagmcp = NULL; - as->mcp++; - ai = A64I_ANDSw; - } - asm_intop(as, ir, ai); -} - -static void asm_borbxor(ASMState *as, IRIns *ir, A64Ins ai) -{ - IRRef lref = ir->op1, rref = ir->op2; - IRIns *irl = IR(lref), *irr = IR(rref); - if ((canfuse(as, irl) && irl->o == IR_BNOT && !irref_isk(rref)) || - (canfuse(as, irr) && irr->o == IR_BNOT && !irref_isk(lref))) { - Reg left, dest = ra_dest(as, ir, RSET_GPR); - uint32_t m; - if (irl->o == IR_BNOT) { - IRRef tmp = lref; lref = rref; rref = tmp; - } - left = ra_alloc1(as, lref, RSET_GPR); - ai |= A64I_ON; - if (irt_is64(ir->t)) ai |= A64I_X; - m = asm_fuseopm(as, ai, IR(rref)->op1, rset_exclude(RSET_GPR, left)); - emit_dn(as, ai^m, dest, left); - } else { - asm_intop(as, ir, ai); - } -} - -static void asm_bor(ASMState *as, IRIns *ir) -{ - if (asm_fuseorshift(as, ir)) - return; - asm_borbxor(as, ir, A64I_ORRw); -} - -#define asm_bxor(as, ir) asm_borbxor(as, ir, A64I_EORw) - -static void asm_bnot(ASMState *as, IRIns *ir) -{ - A64Ins ai = A64I_MVNw; - Reg dest = ra_dest(as, ir, RSET_GPR); - uint32_t m = asm_fuseopm(as, ai, ir->op1, RSET_GPR); - if (irt_is64(ir->t)) ai |= A64I_X; - emit_d(as, ai^m, dest); -} - -static void asm_bswap(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_alloc1(as, ir->op1, RSET_GPR); - emit_dn(as, irt_is64(ir->t) ? A64I_REVx : A64I_REVw, dest, left); -} - -static void asm_bitshift(ASMState *as, IRIns *ir, A64Ins ai, A64Shift sh) -{ - int32_t shmask = irt_is64(ir->t) ? 63 : 31; - if (irref_isk(ir->op2)) { /* Constant shifts. */ - Reg left, dest = ra_dest(as, ir, RSET_GPR); - int32_t shift = (IR(ir->op2)->i & shmask); - IRIns *irl = IR(ir->op1); - if (shmask == 63) ai += A64I_UBFMx - A64I_UBFMw; - - /* Fuse BSHL + BSHR/BSAR into UBFM/SBFM aka UBFX/SBFX/UBFIZ/SBFIZ. */ - if ((sh == A64SH_LSR || sh == A64SH_ASR) && canfuse(as, irl)) { - if (irl->o == IR_BSHL && irref_isk(irl->op2)) { - int32_t shift2 = (IR(irl->op2)->i & shmask); - shift = ((shift - shift2) & shmask); - shmask -= shift2; - ir = irl; - } - } - - left = ra_alloc1(as, ir->op1, RSET_GPR); - switch (sh) { - case A64SH_LSL: - emit_dn(as, ai | A64F_IMMS(shmask-shift) | - A64F_IMMR((shmask-shift+1)&shmask), dest, left); - break; - case A64SH_LSR: case A64SH_ASR: - emit_dn(as, ai | A64F_IMMS(shmask) | A64F_IMMR(shift), dest, left); - break; - case A64SH_ROR: - emit_dnm(as, ai | A64F_IMMS(shift), dest, left, left); - break; - } - } else { /* Variable-length shifts. */ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_alloc1(as, ir->op1, RSET_GPR); - Reg right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left)); - emit_dnm(as, (shmask == 63 ? A64I_SHRx : A64I_SHRw) | A64F_BSH(sh), dest, left, right); - } -} - -#define asm_bshl(as, ir) asm_bitshift(as, ir, A64I_UBFMw, A64SH_LSL) -#define asm_bshr(as, ir) asm_bitshift(as, ir, A64I_UBFMw, A64SH_LSR) -#define asm_bsar(as, ir) asm_bitshift(as, ir, A64I_SBFMw, A64SH_ASR) -#define asm_bror(as, ir) asm_bitshift(as, ir, A64I_EXTRw, A64SH_ROR) -#define asm_brol(as, ir) lua_assert(0) - -static void asm_intmin_max(ASMState *as, IRIns *ir, A64CC cc) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); - Reg right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left)); - emit_dnm(as, A64I_CSELw|A64F_CC(cc), dest, left, right); - emit_nm(as, A64I_CMPw, left, right); -} - -static void asm_fpmin_max(ASMState *as, IRIns *ir, A64CC fcc) -{ - Reg dest = (ra_dest(as, ir, RSET_FPR) & 31); - Reg right, left = ra_alloc2(as, ir, RSET_FPR); - right = ((left >> 8) & 31); left &= 31; - emit_dnm(as, A64I_FCSELd | A64F_CC(fcc), dest, left, right); - emit_nm(as, A64I_FCMPd, left, right); -} - -static void asm_min_max(ASMState *as, IRIns *ir, A64CC cc, A64CC fcc) -{ - if (irt_isnum(ir->t)) - asm_fpmin_max(as, ir, fcc); - else - asm_intmin_max(as, ir, cc); -} - -#define asm_max(as, ir) asm_min_max(as, ir, CC_GT, CC_HI) -#define asm_min(as, ir) asm_min_max(as, ir, CC_LT, CC_LO) - -/* -- Comparisons --------------------------------------------------------- */ - -/* Map of comparisons to flags. ORDER IR. */ -static const uint8_t asm_compmap[IR_ABC+1] = { - /* op FP swp int cc FP cc */ - /* LT */ CC_GE + (CC_HS << 4), - /* GE x */ CC_LT + (CC_HI << 4), - /* LE */ CC_GT + (CC_HI << 4), - /* GT x */ CC_LE + (CC_HS << 4), - /* ULT x */ CC_HS + (CC_LS << 4), - /* UGE */ CC_LO + (CC_LO << 4), - /* ULE x */ CC_HI + (CC_LO << 4), - /* UGT */ CC_LS + (CC_LS << 4), - /* EQ */ CC_NE + (CC_NE << 4), - /* NE */ CC_EQ + (CC_EQ << 4), - /* ABC */ CC_LS + (CC_LS << 4) /* Same as UGT. */ -}; - -/* FP comparisons. */ -static void asm_fpcomp(ASMState *as, IRIns *ir) -{ - Reg left, right; - A64Ins ai; - int swp = ((ir->o ^ (ir->o >> 2)) & ~(ir->o >> 3) & 1); - if (!swp && irref_isk(ir->op2) && ir_knum(IR(ir->op2))->u64 == 0) { - left = (ra_alloc1(as, ir->op1, RSET_FPR) & 31); - right = 0; - ai = A64I_FCMPZd; - } else { - left = ra_alloc2(as, ir, RSET_FPR); - if (swp) { - right = (left & 31); left = ((left >> 8) & 31); - } else { - right = ((left >> 8) & 31); left &= 31; - } - ai = A64I_FCMPd; - } - asm_guardcc(as, (asm_compmap[ir->o] >> 4)); - emit_nm(as, ai, left, right); -} - -/* Integer comparisons. */ -static void asm_intcomp(ASMState *as, IRIns *ir) -{ - A64CC oldcc, cc = (asm_compmap[ir->o] & 15); - A64Ins ai = irt_is64(ir->t) ? A64I_CMPx : A64I_CMPw; - IRRef lref = ir->op1, rref = ir->op2; - Reg left; - uint32_t m; - int cmpprev0 = 0; - lua_assert(irt_is64(ir->t) || irt_isint(ir->t) || - irt_isu32(ir->t) || irt_isaddr(ir->t) || irt_isu8(ir->t)); - if (asm_swapops(as, lref, rref)) { - IRRef tmp = lref; lref = rref; rref = tmp; - if (cc >= CC_GE) cc ^= 7; /* LT <-> GT, LE <-> GE */ - else if (cc > CC_NE) cc ^= 11; /* LO <-> HI, LS <-> HS */ - } - oldcc = cc; - if (irref_isk(rref) && get_k64val(IR(rref)) == 0) { - IRIns *irl = IR(lref); - if (cc == CC_GE) cc = CC_PL; - else if (cc == CC_LT) cc = CC_MI; - else if (cc > CC_NE) goto nocombine; /* Other conds don't work with tst. */ - cmpprev0 = (irl+1 == ir); - /* Combine and-cmp-bcc into tbz/tbnz or and-cmp into tst. */ - if (cmpprev0 && irl->o == IR_BAND && !ra_used(irl)) { - IRRef blref = irl->op1, brref = irl->op2; - uint32_t m2 = 0; - Reg bleft; - if (asm_swapops(as, blref, brref)) { - Reg tmp = blref; blref = brref; brref = tmp; - } - if (irref_isk(brref)) { - uint64_t k = get_k64val(IR(brref)); - if (k && !(k & (k-1)) && (cc == CC_EQ || cc == CC_NE)) { - asm_guardtnb(as, cc == CC_EQ ? A64I_TBZ : A64I_TBNZ, - ra_alloc1(as, blref, RSET_GPR), emit_ctz64(k)); - return; - } - m2 = emit_isk13(k, irt_is64(irl->t)); - } - bleft = ra_alloc1(as, blref, RSET_GPR); - ai = (irt_is64(irl->t) ? A64I_TSTx : A64I_TSTw); - if (!m2) - m2 = asm_fuseopm(as, ai, brref, rset_exclude(RSET_GPR, bleft)); - asm_guardcc(as, cc); - emit_n(as, ai^m2, bleft); - return; - } - if (cc == CC_EQ || cc == CC_NE) { - /* Combine cmp-bcc into cbz/cbnz. */ - ai = cc == CC_EQ ? A64I_CBZ : A64I_CBNZ; - if (irt_is64(ir->t)) ai |= A64I_X; - asm_guardcnb(as, ai, ra_alloc1(as, lref, RSET_GPR)); - return; - } - } -nocombine: - left = ra_alloc1(as, lref, RSET_GPR); - m = asm_fuseopm(as, ai, rref, rset_exclude(RSET_GPR, left)); - asm_guardcc(as, cc); - emit_n(as, ai^m, left); - /* Signed comparison with zero and referencing previous ins? */ - if (cmpprev0 && (oldcc <= CC_NE || oldcc >= CC_GE)) - as->flagmcp = as->mcp; /* Allow elimination of the compare. */ -} - -static void asm_comp(ASMState *as, IRIns *ir) -{ - if (irt_isnum(ir->t)) - asm_fpcomp(as, ir); - else - asm_intcomp(as, ir); -} - -#define asm_equal(as, ir) asm_comp(as, ir) - -/* -- Support for 64 bit ops in 32 bit mode ------------------------------- */ - -/* Hiword op of a split 64 bit op. Previous op must be the loword op. */ -static void asm_hiop(ASMState *as, IRIns *ir) -{ - UNUSED(as); UNUSED(ir); lua_assert(0); /* Unused on 64 bit. */ -} - -/* -- Profiling ----------------------------------------------------------- */ - -static void asm_prof(ASMState *as, IRIns *ir) -{ - uint32_t k = emit_isk13(HOOK_PROFILE, 0); - lua_assert(k != 0); - UNUSED(ir); - asm_guardcc(as, CC_NE); - emit_n(as, A64I_TSTw^k, RID_TMP); - emit_lsptr(as, A64I_LDRB, RID_TMP, (void *)&J2G(as->J)->hookmask); -} - -/* -- Stack handling ------------------------------------------------------ */ - -/* Check Lua stack size for overflow. Use exit handler as fallback. */ -static void asm_stack_check(ASMState *as, BCReg topslot, - IRIns *irp, RegSet allow, ExitNo exitno) -{ - Reg pbase; - uint32_t k; - if (irp) { - if (!ra_hasspill(irp->s)) { - pbase = irp->r; - lua_assert(ra_hasreg(pbase)); - } else if (allow) { - pbase = rset_pickbot(allow); - } else { - pbase = RID_RET; - emit_lso(as, A64I_LDRx, RID_RET, RID_SP, 0); /* Restore temp register. */ - } - } else { - pbase = RID_BASE; - } - emit_cond_branch(as, CC_LS, asm_exitstub_addr(as, exitno)); - k = emit_isk12((8*topslot)); - lua_assert(k); - emit_n(as, A64I_CMPx^k, RID_TMP); - emit_dnm(as, A64I_SUBx, RID_TMP, RID_TMP, pbase); - emit_lso(as, A64I_LDRx, RID_TMP, RID_TMP, - (int32_t)offsetof(lua_State, maxstack)); - if (irp) { /* Must not spill arbitrary registers in head of side trace. */ - if (ra_hasspill(irp->s)) - emit_lso(as, A64I_LDRx, pbase, RID_SP, sps_scale(irp->s)); - emit_lso(as, A64I_LDRx, RID_TMP, RID_GL, glofs(as, &J2G(as->J)->cur_L)); - if (ra_hasspill(irp->s) && !allow) - emit_lso(as, A64I_STRx, RID_RET, RID_SP, 0); /* Save temp register. */ - } else { - emit_getgl(as, RID_TMP, cur_L); - } -} - -/* Restore Lua stack from on-trace state. */ -static void asm_stack_restore(ASMState *as, SnapShot *snap) -{ - SnapEntry *map = &as->T->snapmap[snap->mapofs]; -#ifdef LUA_USE_ASSERT - SnapEntry *flinks = &as->T->snapmap[snap_nextofs(as->T, snap)-1-LJ_FR2]; -#endif - MSize n, nent = snap->nent; - /* Store the value of all modified slots to the Lua stack. */ - for (n = 0; n < nent; n++) { - SnapEntry sn = map[n]; - BCReg s = snap_slot(sn); - int32_t ofs = 8*((int32_t)s-1-LJ_FR2); - IRRef ref = snap_ref(sn); - IRIns *ir = IR(ref); - if ((sn & SNAP_NORESTORE)) - continue; - if (irt_isnum(ir->t)) { - Reg src = ra_alloc1(as, ref, RSET_FPR); - emit_lso(as, A64I_STRd, (src & 31), RID_BASE, ofs); - } else { - asm_tvstore64(as, RID_BASE, ofs, ref); - } - checkmclim(as); - } - lua_assert(map + nent == flinks); -} - -/* -- GC handling --------------------------------------------------------- */ - -/* Check GC threshold and do one or more GC steps. */ -static void asm_gc_check(ASMState *as) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_gc_step_jit]; - IRRef args[2]; - MCLabel l_end; - Reg tmp1, tmp2; - ra_evictset(as, RSET_SCRATCH); - l_end = emit_label(as); - /* Exit trace if in GCSatomic or GCSfinalize. Avoids syncing GC objects. */ - asm_guardcnb(as, A64I_CBNZ, RID_RET); /* Assumes asm_snap_prep() is done. */ - args[0] = ASMREF_TMP1; /* global_State *g */ - args[1] = ASMREF_TMP2; /* MSize steps */ - asm_gencall(as, ci, args); - tmp1 = ra_releasetmp(as, ASMREF_TMP1); - tmp2 = ra_releasetmp(as, ASMREF_TMP2); - emit_loadi(as, tmp2, as->gcsteps); - /* Jump around GC step if GC total < GC threshold. */ - emit_cond_branch(as, CC_LS, l_end); - emit_nm(as, A64I_CMPx, RID_TMP, tmp2); - emit_lso(as, A64I_LDRx, tmp2, tmp1, - (int32_t)offsetof(global_State, gc.threshold)); - emit_lso(as, A64I_LDRx, RID_TMP, tmp1, - (int32_t)offsetof(global_State, gc.total)); - ra_allockreg(as, i64ptr(J2G(as->J)), tmp1); - as->gcsteps = 0; - checkmclim(as); -} - -/* -- Loop handling ------------------------------------------------------- */ - -/* Fixup the loop branch. */ -static void asm_loop_fixup(ASMState *as) -{ - MCode *p = as->mctop; - MCode *target = as->mcp; - if (as->loopinv) { /* Inverted loop branch? */ - uint32_t mask = (p[-2] & 0x7e000000) == 0x36000000 ? 0x3fffu : 0x7ffffu; - ptrdiff_t delta = target - (p - 2); - /* asm_guard* already inverted the bcc/tnb/cnb and patched the final b. */ - p[-2] |= ((uint32_t)delta & mask) << 5; - } else { - ptrdiff_t delta = target - (p - 1); - p[-1] = A64I_B | A64F_S26(delta); - } -} - -/* -- Head of trace ------------------------------------------------------- */ - -/* Reload L register from g->cur_L. */ -static void asm_head_lreg(ASMState *as) -{ - IRIns *ir = IR(ASMREF_L); - if (ra_used(ir)) { - Reg r = ra_dest(as, ir, RSET_GPR); - emit_getgl(as, r, cur_L); - ra_evictk(as); - } -} - -/* Coalesce BASE register for a root trace. */ -static void asm_head_root_base(ASMState *as) -{ - IRIns *ir; - asm_head_lreg(as); - ir = IR(REF_BASE); - if (ra_hasreg(ir->r) && (rset_test(as->modset, ir->r) || irt_ismarked(ir->t))) - ra_spill(as, ir); - ra_destreg(as, ir, RID_BASE); -} - -/* Coalesce BASE register for a side trace. */ -static RegSet asm_head_side_base(ASMState *as, IRIns *irp, RegSet allow) -{ - IRIns *ir; - asm_head_lreg(as); - ir = IR(REF_BASE); - if (ra_hasreg(ir->r) && (rset_test(as->modset, ir->r) || irt_ismarked(ir->t))) - ra_spill(as, ir); - if (ra_hasspill(irp->s)) { - rset_clear(allow, ra_dest(as, ir, allow)); - } else { - Reg r = irp->r; - lua_assert(ra_hasreg(r)); - rset_clear(allow, r); - if (r != ir->r && !rset_test(as->freeset, r)) - ra_restore(as, regcost_ref(as->cost[r])); - ra_destreg(as, ir, r); - } - return allow; -} - -/* -- Tail of trace ------------------------------------------------------- */ - -/* Fixup the tail code. */ -static void asm_tail_fixup(ASMState *as, TraceNo lnk) -{ - MCode *p = as->mctop; - MCode *target; - /* Undo the sp adjustment in BC_JLOOP when exiting to the interpreter. */ - int32_t spadj = as->T->spadjust + (lnk ? 0 : sps_scale(SPS_FIXED)); - if (spadj == 0) { - *--p = A64I_LE(A64I_NOP); - as->mctop = p; - } else { - /* Patch stack adjustment. */ - uint32_t k = emit_isk12(spadj); - lua_assert(k); - p[-2] = (A64I_ADDx^k) | A64F_D(RID_SP) | A64F_N(RID_SP); - } - /* Patch exit branch. */ - target = lnk ? traceref(as->J, lnk)->mcode : (MCode *)lj_vm_exit_interp; - p[-1] = A64I_B | A64F_S26((target-p)+1); -} - -/* Prepare tail of code. */ -static void asm_tail_prep(ASMState *as) -{ - MCode *p = as->mctop - 1; /* Leave room for exit branch. */ - if (as->loopref) { - as->invmcp = as->mcp = p; - } else { - as->mcp = p-1; /* Leave room for stack pointer adjustment. */ - as->invmcp = NULL; - } - *p = 0; /* Prevent load/store merging. */ -} - -/* -- Trace setup --------------------------------------------------------- */ - -/* Ensure there are enough stack slots for call arguments. */ -static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci) -{ - IRRef args[CCI_NARGS_MAX*2]; - uint32_t i, nargs = CCI_XNARGS(ci); - int nslots = 0, ngpr = REGARG_NUMGPR, nfpr = REGARG_NUMFPR; - asm_collectargs(as, ir, ci, args); - for (i = 0; i < nargs; i++) { - if (args[i] && irt_isfp(IR(args[i])->t)) { - if (nfpr > 0) nfpr--; else nslots += 2; - } else { - if (ngpr > 0) ngpr--; else nslots += 2; - } - } - if (nslots > as->evenspill) /* Leave room for args in stack slots. */ - as->evenspill = nslots; - return REGSP_HINT(RID_RET); -} - -static void asm_setup_target(ASMState *as) -{ - /* May need extra exit for asm_stack_check on side traces. */ - asm_exitstub_setup(as, as->T->nsnap + (as->parent ? 1 : 0)); -} - -#if LJ_BE -/* ARM64 instructions are always little-endian. Swap for ARM64BE. */ -static void asm_mcode_fixup(MCode *mcode, MSize size) -{ - MCode *pe = (MCode *)((char *)mcode + size); - while (mcode < pe) { - MCode ins = *mcode; - *mcode++ = lj_bswap(ins); - } -} -#define LJ_TARGET_MCODE_FIXUP 1 -#endif - -/* -- Trace patching ------------------------------------------------------ */ - -/* Patch exit jumps of existing machine code to a new target. */ -void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, MCode *target) -{ - MCode *p = T->mcode; - MCode *pe = (MCode *)((char *)p + T->szmcode); - MCode *cstart = NULL; - MCode *mcarea = lj_mcode_patch(J, p, 0); - MCode *px = exitstub_trace_addr(T, exitno); - /* Note: this assumes a trace exit is only ever patched once. */ - for (; p < pe; p++) { - /* Look for exitstub branch, replace with branch to target. */ - ptrdiff_t delta = target - p; - MCode ins = A64I_LE(*p); - if ((ins & 0xff000000u) == 0x54000000u && - ((ins ^ ((px-p)<<5)) & 0x00ffffe0u) == 0) { - /* Patch bcc, if within range. */ - if (A64F_S_OK(delta, 19)) { - *p = A64I_LE((ins & 0xff00001fu) | A64F_S19(delta)); - if (!cstart) cstart = p; - } - } else if ((ins & 0xfc000000u) == 0x14000000u && - ((ins ^ (px-p)) & 0x03ffffffu) == 0) { - /* Patch b. */ - lua_assert(A64F_S_OK(delta, 26)); - *p = A64I_LE((ins & 0xfc000000u) | A64F_S26(delta)); - if (!cstart) cstart = p; - } else if ((ins & 0x7e000000u) == 0x34000000u && - ((ins ^ ((px-p)<<5)) & 0x00ffffe0u) == 0) { - /* Patch cbz/cbnz, if within range. */ - if (A64F_S_OK(delta, 19)) { - *p = A64I_LE((ins & 0xff00001fu) | A64F_S19(delta)); - if (!cstart) cstart = p; - } - } else if ((ins & 0x7e000000u) == 0x36000000u && - ((ins ^ ((px-p)<<5)) & 0x0007ffe0u) == 0) { - /* Patch tbz/tbnz, if within range. */ - if (A64F_S_OK(delta, 14)) { - *p = A64I_LE((ins & 0xfff8001fu) | A64F_S14(delta)); - if (!cstart) cstart = p; - } - } - } - { /* Always patch long-range branch in exit stub itself. */ - ptrdiff_t delta = target - px; - lua_assert(A64F_S_OK(delta, 26)); - *px = A64I_B | A64F_S26(delta); - if (!cstart) cstart = px; - } - lj_mcode_sync(cstart, px+1); - lj_mcode_patch(J, mcarea, 1); -} - diff --git a/lib/LuaJIT/src/lj_asm_mips.h b/lib/LuaJIT/src/lj_asm_mips.h deleted file mode 100644 index 3a4679b..0000000 --- a/lib/LuaJIT/src/lj_asm_mips.h +++ /dev/null @@ -1,2659 +0,0 @@ -/* -** MIPS IR assembler (SSA IR -> machine code). -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -/* -- Register allocator extensions --------------------------------------- */ - -/* Allocate a register with a hint. */ -static Reg ra_hintalloc(ASMState *as, IRRef ref, Reg hint, RegSet allow) -{ - Reg r = IR(ref)->r; - if (ra_noreg(r)) { - if (!ra_hashint(r) && !iscrossref(as, ref)) - ra_sethint(IR(ref)->r, hint); /* Propagate register hint. */ - r = ra_allocref(as, ref, allow); - } - ra_noweak(as, r); - return r; -} - -/* Allocate a register or RID_ZERO. */ -static Reg ra_alloc1z(ASMState *as, IRRef ref, RegSet allow) -{ - Reg r = IR(ref)->r; - if (ra_noreg(r)) { - if (!(allow & RSET_FPR) && irref_isk(ref) && get_kval(IR(ref)) == 0) - return RID_ZERO; - r = ra_allocref(as, ref, allow); - } else { - ra_noweak(as, r); - } - return r; -} - -/* Allocate two source registers for three-operand instructions. */ -static Reg ra_alloc2(ASMState *as, IRIns *ir, RegSet allow) -{ - IRIns *irl = IR(ir->op1), *irr = IR(ir->op2); - Reg left = irl->r, right = irr->r; - if (ra_hasreg(left)) { - ra_noweak(as, left); - if (ra_noreg(right)) - right = ra_alloc1z(as, ir->op2, rset_exclude(allow, left)); - else - ra_noweak(as, right); - } else if (ra_hasreg(right)) { - ra_noweak(as, right); - left = ra_alloc1z(as, ir->op1, rset_exclude(allow, right)); - } else if (ra_hashint(right)) { - right = ra_alloc1z(as, ir->op2, allow); - left = ra_alloc1z(as, ir->op1, rset_exclude(allow, right)); - } else { - left = ra_alloc1z(as, ir->op1, allow); - right = ra_alloc1z(as, ir->op2, rset_exclude(allow, left)); - } - return left | (right << 8); -} - -/* -- Guard handling ------------------------------------------------------ */ - -/* Need some spare long-range jump slots, for out-of-range branches. */ -#define MIPS_SPAREJUMP 4 - -/* Setup spare long-range jump slots per mcarea. */ -static void asm_sparejump_setup(ASMState *as) -{ - MCode *mxp = as->mcbot; - if (((uintptr_t)mxp & (LJ_PAGESIZE-1)) == sizeof(MCLink)) { - lua_assert(MIPSI_NOP == 0); - memset(mxp, 0, MIPS_SPAREJUMP*2*sizeof(MCode)); - mxp += MIPS_SPAREJUMP*2; - lua_assert(mxp < as->mctop); - lj_mcode_sync(as->mcbot, mxp); - lj_mcode_commitbot(as->J, mxp); - as->mcbot = mxp; - as->mclim = as->mcbot + MCLIM_REDZONE; - } -} - -/* Setup exit stub after the end of each trace. */ -static void asm_exitstub_setup(ASMState *as) -{ - MCode *mxp = as->mctop; - /* sw TMP, 0(sp); j ->vm_exit_handler; li TMP, traceno */ - *--mxp = MIPSI_LI|MIPSF_T(RID_TMP)|as->T->traceno; - *--mxp = MIPSI_J|((((uintptr_t)(void *)lj_vm_exit_handler)>>2)&0x03ffffffu); - lua_assert(((uintptr_t)mxp ^ (uintptr_t)(void *)lj_vm_exit_handler)>>28 == 0); - *--mxp = MIPSI_SW|MIPSF_T(RID_TMP)|MIPSF_S(RID_SP)|0; - as->mctop = mxp; -} - -/* Keep this in-sync with exitstub_trace_addr(). */ -#define asm_exitstub_addr(as) ((as)->mctop) - -/* Emit conditional branch to exit for guard. */ -static void asm_guard(ASMState *as, MIPSIns mi, Reg rs, Reg rt) -{ - MCode *target = asm_exitstub_addr(as); - MCode *p = as->mcp; - if (LJ_UNLIKELY(p == as->invmcp)) { - as->invmcp = NULL; - as->loopinv = 1; - as->mcp = p+1; - mi = mi ^ ((mi>>28) == 1 ? 0x04000000u : 0x00010000u); /* Invert cond. */ - target = p; /* Patch target later in asm_loop_fixup. */ - } - emit_ti(as, MIPSI_LI, RID_TMP, as->snapno); - emit_branch(as, mi, rs, rt, target); -} - -/* -- Operand fusion ------------------------------------------------------ */ - -/* Limit linear search to this distance. Avoids O(n^2) behavior. */ -#define CONFLICT_SEARCH_LIM 31 - -/* Check if there's no conflicting instruction between curins and ref. */ -static int noconflict(ASMState *as, IRRef ref, IROp conflict) -{ - IRIns *ir = as->ir; - IRRef i = as->curins; - if (i > ref + CONFLICT_SEARCH_LIM) - return 0; /* Give up, ref is too far away. */ - while (--i > ref) - if (ir[i].o == conflict) - return 0; /* Conflict found. */ - return 1; /* Ok, no conflict. */ -} - -/* Fuse the array base of colocated arrays. */ -static int32_t asm_fuseabase(ASMState *as, IRRef ref) -{ - IRIns *ir = IR(ref); - if (ir->o == IR_TNEW && ir->op1 <= LJ_MAX_COLOSIZE && - !neverfuse(as) && noconflict(as, ref, IR_NEWREF)) - return (int32_t)sizeof(GCtab); - return 0; -} - -/* Fuse array/hash/upvalue reference into register+offset operand. */ -static Reg asm_fuseahuref(ASMState *as, IRRef ref, int32_t *ofsp, RegSet allow) -{ - IRIns *ir = IR(ref); - if (ra_noreg(ir->r)) { - if (ir->o == IR_AREF) { - if (mayfuse(as, ref)) { - if (irref_isk(ir->op2)) { - IRRef tab = IR(ir->op1)->op1; - int32_t ofs = asm_fuseabase(as, tab); - IRRef refa = ofs ? tab : ir->op1; - ofs += 8*IR(ir->op2)->i; - if (checki16(ofs)) { - *ofsp = ofs; - return ra_alloc1(as, refa, allow); - } - } - } - } else if (ir->o == IR_HREFK) { - if (mayfuse(as, ref)) { - int32_t ofs = (int32_t)(IR(ir->op2)->op2 * sizeof(Node)); - if (checki16(ofs)) { - *ofsp = ofs; - return ra_alloc1(as, ir->op1, allow); - } - } - } else if (ir->o == IR_UREFC) { - if (irref_isk(ir->op1)) { - GCfunc *fn = ir_kfunc(IR(ir->op1)); - intptr_t ofs = (intptr_t)&gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.tv; - intptr_t jgl = (intptr_t)J2G(as->J); - if ((uintptr_t)(ofs-jgl) < 65536) { - *ofsp = ofs-jgl-32768; - return RID_JGL; - } else { - *ofsp = (int16_t)ofs; - return ra_allock(as, ofs-(int16_t)ofs, allow); - } - } - } - } - *ofsp = 0; - return ra_alloc1(as, ref, allow); -} - -/* Fuse XLOAD/XSTORE reference into load/store operand. */ -static void asm_fusexref(ASMState *as, MIPSIns mi, Reg rt, IRRef ref, - RegSet allow, int32_t ofs) -{ - IRIns *ir = IR(ref); - Reg base; - if (ra_noreg(ir->r) && canfuse(as, ir)) { - if (ir->o == IR_ADD) { - intptr_t ofs2; - if (irref_isk(ir->op2) && (ofs2 = ofs + get_kval(IR(ir->op2)), - checki16(ofs2))) { - ref = ir->op1; - ofs = (int32_t)ofs2; - } - } else if (ir->o == IR_STRREF) { - intptr_t ofs2 = 65536; - lua_assert(ofs == 0); - ofs = (int32_t)sizeof(GCstr); - if (irref_isk(ir->op2)) { - ofs2 = ofs + get_kval(IR(ir->op2)); - ref = ir->op1; - } else if (irref_isk(ir->op1)) { - ofs2 = ofs + get_kval(IR(ir->op1)); - ref = ir->op2; - } - if (!checki16(ofs2)) { - /* NYI: Fuse ADD with constant. */ - Reg right, left = ra_alloc2(as, ir, allow); - right = (left >> 8); left &= 255; - emit_hsi(as, mi, rt, RID_TMP, ofs); - emit_dst(as, MIPSI_AADDU, RID_TMP, left, right); - return; - } - ofs = ofs2; - } - } - base = ra_alloc1(as, ref, allow); - emit_hsi(as, mi, rt, base, ofs); -} - -/* -- Calls --------------------------------------------------------------- */ - -/* Generate a call to a C function. */ -static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) -{ - uint32_t n, nargs = CCI_XNARGS(ci); - int32_t ofs = LJ_32 ? 16 : 0; -#if LJ_SOFTFP - Reg gpr = REGARG_FIRSTGPR; -#else - Reg gpr, fpr = REGARG_FIRSTFPR; -#endif - if ((void *)ci->func) - emit_call(as, (void *)ci->func, 1); -#if !LJ_SOFTFP - for (gpr = REGARG_FIRSTGPR; gpr <= REGARG_LASTGPR; gpr++) - as->cost[gpr] = REGCOST(~0u, ASMREF_L); - gpr = REGARG_FIRSTGPR; -#endif - for (n = 0; n < nargs; n++) { /* Setup args. */ - IRRef ref = args[n]; - if (ref) { - IRIns *ir = IR(ref); -#if !LJ_SOFTFP - if (irt_isfp(ir->t) && fpr <= REGARG_LASTFPR && - !(ci->flags & CCI_VARARG)) { - lua_assert(rset_test(as->freeset, fpr)); /* Already evicted. */ - ra_leftov(as, fpr, ref); - fpr += LJ_32 ? 2 : 1; - gpr += (LJ_32 && irt_isnum(ir->t)) ? 2 : 1; - } else -#endif - { -#if LJ_32 && !LJ_SOFTFP - fpr = REGARG_LASTFPR+1; -#endif - if (LJ_32 && irt_isnum(ir->t)) gpr = (gpr+1) & ~1; - if (gpr <= REGARG_LASTGPR) { - lua_assert(rset_test(as->freeset, gpr)); /* Already evicted. */ -#if !LJ_SOFTFP - if (irt_isfp(ir->t)) { - RegSet of = as->freeset; - Reg r; - /* Workaround to protect argument GPRs from being used for remat. */ - as->freeset &= ~RSET_RANGE(REGARG_FIRSTGPR, REGARG_LASTGPR+1); - r = ra_alloc1(as, ref, RSET_FPR); - as->freeset |= (of & RSET_RANGE(REGARG_FIRSTGPR, REGARG_LASTGPR+1)); - if (irt_isnum(ir->t)) { -#if LJ_32 - emit_tg(as, MIPSI_MFC1, gpr+(LJ_BE?0:1), r+1); - emit_tg(as, MIPSI_MFC1, gpr+(LJ_BE?1:0), r); - lua_assert(rset_test(as->freeset, gpr+1)); /* Already evicted. */ - gpr += 2; -#else - emit_tg(as, MIPSI_DMFC1, gpr, r); - gpr++; fpr++; -#endif - } else if (irt_isfloat(ir->t)) { - emit_tg(as, MIPSI_MFC1, gpr, r); - gpr++; -#if LJ_64 - fpr++; -#endif - } - } else -#endif - { - ra_leftov(as, gpr, ref); - gpr++; -#if LJ_64 && !LJ_SOFTFP - fpr++; -#endif - } - } else { - Reg r = ra_alloc1z(as, ref, !LJ_SOFTFP && irt_isfp(ir->t) ? RSET_FPR : RSET_GPR); -#if LJ_32 - if (irt_isnum(ir->t)) ofs = (ofs + 4) & ~4; - emit_spstore(as, ir, r, ofs); - ofs += irt_isnum(ir->t) ? 8 : 4; -#else - emit_spstore(as, ir, r, ofs + ((LJ_BE && !irt_isfp(ir->t) && !irt_is64(ir->t)) ? 4 : 0)); - ofs += 8; -#endif - } - } - } else { -#if !LJ_SOFTFP - fpr = REGARG_LASTFPR+1; -#endif - if (gpr <= REGARG_LASTGPR) { - gpr++; -#if LJ_64 && !LJ_SOFTFP - fpr++; -#endif - } else { - ofs += LJ_32 ? 4 : 8; - } - } - checkmclim(as); - } -} - -/* Setup result reg/sp for call. Evict scratch regs. */ -static void asm_setupresult(ASMState *as, IRIns *ir, const CCallInfo *ci) -{ - RegSet drop = RSET_SCRATCH; -#if LJ_32 - int hiop = ((ir+1)->o == IR_HIOP && !irt_isnil((ir+1)->t)); -#endif -#if !LJ_SOFTFP - if ((ci->flags & CCI_NOFPRCLOBBER)) - drop &= ~RSET_FPR; -#endif - if (ra_hasreg(ir->r)) - rset_clear(drop, ir->r); /* Dest reg handled below. */ -#if LJ_32 - if (hiop && ra_hasreg((ir+1)->r)) - rset_clear(drop, (ir+1)->r); /* Dest reg handled below. */ -#endif - ra_evictset(as, drop); /* Evictions must be performed first. */ - if (ra_used(ir)) { - lua_assert(!irt_ispri(ir->t)); - if (!LJ_SOFTFP && irt_isfp(ir->t)) { - if ((ci->flags & CCI_CASTU64)) { - int32_t ofs = sps_scale(ir->s); - Reg dest = ir->r; - if (ra_hasreg(dest)) { - ra_free(as, dest); - ra_modified(as, dest); -#if LJ_32 - emit_tg(as, MIPSI_MTC1, RID_RETHI, dest+1); - emit_tg(as, MIPSI_MTC1, RID_RETLO, dest); -#else - emit_tg(as, MIPSI_DMTC1, RID_RET, dest); -#endif - } - if (ofs) { -#if LJ_32 - emit_tsi(as, MIPSI_SW, RID_RETLO, RID_SP, ofs+(LJ_BE?4:0)); - emit_tsi(as, MIPSI_SW, RID_RETHI, RID_SP, ofs+(LJ_BE?0:4)); -#else - emit_tsi(as, MIPSI_SD, RID_RET, RID_SP, ofs); -#endif - } - } else { - ra_destreg(as, ir, RID_FPRET); - } -#if LJ_32 - } else if (hiop) { - ra_destpair(as, ir); -#endif - } else { - ra_destreg(as, ir, RID_RET); - } - } -} - -static void asm_callx(ASMState *as, IRIns *ir) -{ - IRRef args[CCI_NARGS_MAX*2]; - CCallInfo ci; - IRRef func; - IRIns *irf; - ci.flags = asm_callx_flags(as, ir); - asm_collectargs(as, ir, &ci, args); - asm_setupresult(as, ir, &ci); - func = ir->op2; irf = IR(func); - if (irf->o == IR_CARG) { func = irf->op1; irf = IR(func); } - if (irref_isk(func)) { /* Call to constant address. */ - ci.func = (ASMFunction)(void *)get_kval(irf); - } else { /* Need specific register for indirect calls. */ - Reg r = ra_alloc1(as, func, RID2RSET(RID_CFUNCADDR)); - MCode *p = as->mcp; - if (r == RID_CFUNCADDR) - *--p = MIPSI_NOP; - else - *--p = MIPSI_MOVE | MIPSF_D(RID_CFUNCADDR) | MIPSF_S(r); - *--p = MIPSI_JALR | MIPSF_S(r); - as->mcp = p; - ci.func = (ASMFunction)(void *)0; - } - asm_gencall(as, &ci, args); -} - -#if !LJ_SOFTFP -static void asm_callround(ASMState *as, IRIns *ir, IRCallID id) -{ - /* The modified regs must match with the *.dasc implementation. */ - RegSet drop = RID2RSET(RID_R1)|RID2RSET(RID_R12)|RID2RSET(RID_FPRET)| - RID2RSET(RID_F2)|RID2RSET(RID_F4)|RID2RSET(REGARG_FIRSTFPR); - if (ra_hasreg(ir->r)) rset_clear(drop, ir->r); - ra_evictset(as, drop); - ra_destreg(as, ir, RID_FPRET); - emit_call(as, (void *)lj_ir_callinfo[id].func, 0); - ra_leftov(as, REGARG_FIRSTFPR, ir->op1); -} -#endif - -/* -- Returns ------------------------------------------------------------- */ - -/* Return to lower frame. Guard that it goes to the right spot. */ -static void asm_retf(ASMState *as, IRIns *ir) -{ - Reg base = ra_alloc1(as, REF_BASE, RSET_GPR); - void *pc = ir_kptr(IR(ir->op2)); - int32_t delta = 1+LJ_FR2+bc_a(*((const BCIns *)pc - 1)); - as->topslot -= (BCReg)delta; - if ((int32_t)as->topslot < 0) as->topslot = 0; - irt_setmark(IR(REF_BASE)->t); /* Children must not coalesce with BASE reg. */ - emit_setgl(as, base, jit_base); - emit_addptr(as, base, -8*delta); - asm_guard(as, MIPSI_BNE, RID_TMP, - ra_allock(as, igcptr(pc), rset_exclude(RSET_GPR, base))); - emit_tsi(as, MIPSI_AL, RID_TMP, base, -8); -} - -/* -- Type conversions ---------------------------------------------------- */ - -#if !LJ_SOFTFP -static void asm_tointg(ASMState *as, IRIns *ir, Reg left) -{ - Reg tmp = ra_scratch(as, rset_exclude(RSET_FPR, left)); - Reg dest = ra_dest(as, ir, RSET_GPR); - asm_guard(as, MIPSI_BC1F, 0, 0); - emit_fgh(as, MIPSI_C_EQ_D, 0, tmp, left); - emit_fg(as, MIPSI_CVT_D_W, tmp, tmp); - emit_tg(as, MIPSI_MFC1, dest, tmp); - emit_fg(as, MIPSI_CVT_W_D, tmp, left); -} - -static void asm_tobit(ASMState *as, IRIns *ir) -{ - RegSet allow = RSET_FPR; - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_alloc1(as, ir->op1, allow); - Reg right = ra_alloc1(as, ir->op2, rset_clear(allow, left)); - Reg tmp = ra_scratch(as, rset_clear(allow, right)); - emit_tg(as, MIPSI_MFC1, dest, tmp); - emit_fgh(as, MIPSI_ADD_D, tmp, left, right); -} -#elif LJ_64 /* && LJ_SOFTFP */ -static void asm_tointg(ASMState *as, IRIns *ir, Reg r) -{ - /* The modified regs must match with the *.dasc implementation. */ - RegSet drop = RID2RSET(REGARG_FIRSTGPR)|RID2RSET(RID_RET)|RID2RSET(RID_RET+1)| - RID2RSET(RID_R1)|RID2RSET(RID_R12); - if (ra_hasreg(ir->r)) rset_clear(drop, ir->r); - ra_evictset(as, drop); - /* Return values are in RID_RET (converted value) and RID_RET+1 (status). */ - ra_destreg(as, ir, RID_RET); - asm_guard(as, MIPSI_BNE, RID_RET+1, RID_ZERO); - emit_call(as, (void *)lj_ir_callinfo[IRCALL_lj_vm_tointg].func, 0); - if (r == RID_NONE) - ra_leftov(as, REGARG_FIRSTGPR, ir->op1); - else if (r != REGARG_FIRSTGPR) - emit_move(as, REGARG_FIRSTGPR, r); -} - -static void asm_tobit(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - emit_dta(as, MIPSI_SLL, dest, dest, 0); - asm_callid(as, ir, IRCALL_lj_vm_tobit); -} -#endif - -static void asm_conv(ASMState *as, IRIns *ir) -{ - IRType st = (IRType)(ir->op2 & IRCONV_SRCMASK); -#if !LJ_SOFTFP32 - int stfp = (st == IRT_NUM || st == IRT_FLOAT); -#endif -#if LJ_64 - int st64 = (st == IRT_I64 || st == IRT_U64 || st == IRT_P64); -#endif - IRRef lref = ir->op1; -#if LJ_32 - lua_assert(!(irt_isint64(ir->t) || - (st == IRT_I64 || st == IRT_U64))); /* Handled by SPLIT. */ -#endif -#if LJ_SOFTFP32 - /* FP conversions are handled by SPLIT. */ - lua_assert(!irt_isfp(ir->t) && !(st == IRT_NUM || st == IRT_FLOAT)); - /* Can't check for same types: SPLIT uses CONV int.int + BXOR for sfp NEG. */ -#else - lua_assert(irt_type(ir->t) != st); -#if !LJ_SOFTFP - if (irt_isfp(ir->t)) { - Reg dest = ra_dest(as, ir, RSET_FPR); - if (stfp) { /* FP to FP conversion. */ - emit_fg(as, st == IRT_NUM ? MIPSI_CVT_S_D : MIPSI_CVT_D_S, - dest, ra_alloc1(as, lref, RSET_FPR)); - } else if (st == IRT_U32) { /* U32 to FP conversion. */ - /* y = (x ^ 0x8000000) + 2147483648.0 */ - Reg left = ra_alloc1(as, lref, RSET_GPR); - Reg tmp = ra_scratch(as, rset_exclude(RSET_FPR, dest)); - if (irt_isfloat(ir->t)) - emit_fg(as, MIPSI_CVT_S_D, dest, dest); - /* Must perform arithmetic with doubles to keep the precision. */ - emit_fgh(as, MIPSI_ADD_D, dest, dest, tmp); - emit_fg(as, MIPSI_CVT_D_W, dest, dest); - emit_lsptr(as, MIPSI_LDC1, (tmp & 31), - (void *)&as->J->k64[LJ_K64_2P31], RSET_GPR); - emit_tg(as, MIPSI_MTC1, RID_TMP, dest); - emit_dst(as, MIPSI_XOR, RID_TMP, RID_TMP, left); - emit_ti(as, MIPSI_LUI, RID_TMP, 0x8000); -#if LJ_64 - } else if(st == IRT_U64) { /* U64 to FP conversion. */ - /* if (x >= 1u<<63) y = (double)(int64_t)(x&(1u<<63)-1) + pow(2.0, 63) */ - Reg left = ra_alloc1(as, lref, RSET_GPR); - Reg tmp = ra_scratch(as, rset_exclude(RSET_FPR, dest)); - MCLabel l_end = emit_label(as); - if (irt_isfloat(ir->t)) { - emit_fgh(as, MIPSI_ADD_S, dest, dest, tmp); - emit_lsptr(as, MIPSI_LWC1, (tmp & 31), (void *)&as->J->k32[LJ_K32_2P63], - rset_exclude(RSET_GPR, left)); - emit_fg(as, MIPSI_CVT_S_L, dest, dest); - } else { - emit_fgh(as, MIPSI_ADD_D, dest, dest, tmp); - emit_lsptr(as, MIPSI_LDC1, (tmp & 31), (void *)&as->J->k64[LJ_K64_2P63], - rset_exclude(RSET_GPR, left)); - emit_fg(as, MIPSI_CVT_D_L, dest, dest); - } - emit_branch(as, MIPSI_BGEZ, left, RID_ZERO, l_end); - emit_tg(as, MIPSI_DMTC1, RID_TMP, dest); - emit_tsml(as, MIPSI_DEXTM, RID_TMP, left, 30, 0); -#endif - } else { /* Integer to FP conversion. */ - Reg left = ra_alloc1(as, lref, RSET_GPR); -#if LJ_32 - emit_fg(as, irt_isfloat(ir->t) ? MIPSI_CVT_S_W : MIPSI_CVT_D_W, - dest, dest); - emit_tg(as, MIPSI_MTC1, left, dest); -#else - MIPSIns mi = irt_isfloat(ir->t) ? - (st64 ? MIPSI_CVT_S_L : MIPSI_CVT_S_W) : - (st64 ? MIPSI_CVT_D_L : MIPSI_CVT_D_W); - emit_fg(as, mi, dest, dest); - emit_tg(as, st64 ? MIPSI_DMTC1 : MIPSI_MTC1, left, dest); -#endif - } - } else if (stfp) { /* FP to integer conversion. */ - if (irt_isguard(ir->t)) { - /* Checked conversions are only supported from number to int. */ - lua_assert(irt_isint(ir->t) && st == IRT_NUM); - asm_tointg(as, ir, ra_alloc1(as, lref, RSET_FPR)); - } else { - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_alloc1(as, lref, RSET_FPR); - Reg tmp = ra_scratch(as, rset_exclude(RSET_FPR, left)); - if (irt_isu32(ir->t)) { /* FP to U32 conversion. */ - /* y = (int)floor(x - 2147483648.0) ^ 0x80000000 */ - emit_dst(as, MIPSI_XOR, dest, dest, RID_TMP); - emit_ti(as, MIPSI_LUI, RID_TMP, 0x8000); - emit_tg(as, MIPSI_MFC1, dest, tmp); - emit_fg(as, st == IRT_FLOAT ? MIPSI_FLOOR_W_S : MIPSI_FLOOR_W_D, - tmp, tmp); - emit_fgh(as, st == IRT_FLOAT ? MIPSI_SUB_S : MIPSI_SUB_D, - tmp, left, tmp); - if (st == IRT_FLOAT) - emit_lsptr(as, MIPSI_LWC1, (tmp & 31), - (void *)&as->J->k32[LJ_K32_2P31], RSET_GPR); - else - emit_lsptr(as, MIPSI_LDC1, (tmp & 31), - (void *)&as->J->k64[LJ_K64_2P31], RSET_GPR); -#if LJ_64 - } else if (irt_isu64(ir->t)) { /* FP to U64 conversion. */ - MCLabel l_end; - emit_tg(as, MIPSI_DMFC1, dest, tmp); - l_end = emit_label(as); - /* For inputs >= 2^63 add -2^64 and convert again. */ - if (st == IRT_NUM) { - emit_fg(as, MIPSI_TRUNC_L_D, tmp, tmp); - emit_fgh(as, MIPSI_ADD_D, tmp, left, tmp); - emit_lsptr(as, MIPSI_LDC1, (tmp & 31), - (void *)&as->J->k64[LJ_K64_M2P64], - rset_exclude(RSET_GPR, dest)); - emit_fg(as, MIPSI_TRUNC_L_D, tmp, left); /* Delay slot. */ - emit_branch(as, MIPSI_BC1T, 0, 0, l_end); - emit_fgh(as, MIPSI_C_OLT_D, 0, left, tmp); - emit_lsptr(as, MIPSI_LDC1, (tmp & 31), - (void *)&as->J->k64[LJ_K64_2P63], - rset_exclude(RSET_GPR, dest)); - } else { - emit_fg(as, MIPSI_TRUNC_L_S, tmp, tmp); - emit_fgh(as, MIPSI_ADD_S, tmp, left, tmp); - emit_lsptr(as, MIPSI_LWC1, (tmp & 31), - (void *)&as->J->k32[LJ_K32_M2P64], - rset_exclude(RSET_GPR, dest)); - emit_fg(as, MIPSI_TRUNC_L_S, tmp, left); /* Delay slot. */ - emit_branch(as, MIPSI_BC1T, 0, 0, l_end); - emit_fgh(as, MIPSI_C_OLT_S, 0, left, tmp); - emit_lsptr(as, MIPSI_LWC1, (tmp & 31), - (void *)&as->J->k32[LJ_K32_2P63], - rset_exclude(RSET_GPR, dest)); - } -#endif - } else { -#if LJ_32 - emit_tg(as, MIPSI_MFC1, dest, tmp); - emit_fg(as, st == IRT_FLOAT ? MIPSI_TRUNC_W_S : MIPSI_TRUNC_W_D, - tmp, left); -#else - MIPSIns mi = irt_is64(ir->t) ? - (st == IRT_NUM ? MIPSI_TRUNC_L_D : MIPSI_TRUNC_L_S) : - (st == IRT_NUM ? MIPSI_TRUNC_W_D : MIPSI_TRUNC_W_S); - emit_tg(as, irt_is64(ir->t) ? MIPSI_DMFC1 : MIPSI_MFC1, dest, left); - emit_fg(as, mi, left, left); -#endif - } - } - } else -#else - if (irt_isfp(ir->t)) { -#if LJ_64 && LJ_HASFFI - if (stfp) { /* FP to FP conversion. */ - asm_callid(as, ir, irt_isnum(ir->t) ? IRCALL_softfp_f2d : - IRCALL_softfp_d2f); - } else { /* Integer to FP conversion. */ - IRCallID cid = ((IRT_IS64 >> st) & 1) ? - (irt_isnum(ir->t) ? - (st == IRT_I64 ? IRCALL_fp64_l2d : IRCALL_fp64_ul2d) : - (st == IRT_I64 ? IRCALL_fp64_l2f : IRCALL_fp64_ul2f)) : - (irt_isnum(ir->t) ? - (st == IRT_INT ? IRCALL_softfp_i2d : IRCALL_softfp_ui2d) : - (st == IRT_INT ? IRCALL_softfp_i2f : IRCALL_softfp_ui2f)); - asm_callid(as, ir, cid); - } -#else - asm_callid(as, ir, IRCALL_softfp_i2d); -#endif - } else if (stfp) { /* FP to integer conversion. */ - if (irt_isguard(ir->t)) { - /* Checked conversions are only supported from number to int. */ - lua_assert(irt_isint(ir->t) && st == IRT_NUM); - asm_tointg(as, ir, RID_NONE); - } else { - IRCallID cid = irt_is64(ir->t) ? - ((st == IRT_NUM) ? - (irt_isi64(ir->t) ? IRCALL_fp64_d2l : IRCALL_fp64_d2ul) : - (irt_isi64(ir->t) ? IRCALL_fp64_f2l : IRCALL_fp64_f2ul)) : - ((st == IRT_NUM) ? - (irt_isint(ir->t) ? IRCALL_softfp_d2i : IRCALL_softfp_d2ui) : - (irt_isint(ir->t) ? IRCALL_softfp_f2i : IRCALL_softfp_f2ui)); - asm_callid(as, ir, cid); - } - } else -#endif -#endif - { - Reg dest = ra_dest(as, ir, RSET_GPR); - if (st >= IRT_I8 && st <= IRT_U16) { /* Extend to 32 bit integer. */ - Reg left = ra_alloc1(as, ir->op1, RSET_GPR); - lua_assert(irt_isint(ir->t) || irt_isu32(ir->t)); - if ((ir->op2 & IRCONV_SEXT)) { - if (LJ_64 || (as->flags & JIT_F_MIPSXXR2)) { - emit_dst(as, st == IRT_I8 ? MIPSI_SEB : MIPSI_SEH, dest, 0, left); - } else { - uint32_t shift = st == IRT_I8 ? 24 : 16; - emit_dta(as, MIPSI_SRA, dest, dest, shift); - emit_dta(as, MIPSI_SLL, dest, left, shift); - } - } else { - emit_tsi(as, MIPSI_ANDI, dest, left, - (int32_t)(st == IRT_U8 ? 0xff : 0xffff)); - } - } else { /* 32/64 bit integer conversions. */ -#if LJ_32 - /* Only need to handle 32/32 bit no-op (cast) on 32 bit archs. */ - ra_leftov(as, dest, lref); /* Do nothing, but may need to move regs. */ -#else - if (irt_is64(ir->t)) { - if (st64) { - /* 64/64 bit no-op (cast)*/ - ra_leftov(as, dest, lref); - } else { - Reg left = ra_alloc1(as, lref, RSET_GPR); - if ((ir->op2 & IRCONV_SEXT)) { /* 32 to 64 bit sign extension. */ - emit_dta(as, MIPSI_SLL, dest, left, 0); - } else { /* 32 to 64 bit zero extension. */ - emit_tsml(as, MIPSI_DEXT, dest, left, 31, 0); - } - } - } else { - if (st64) { - /* This is either a 32 bit reg/reg mov which zeroes the hiword - ** or a load of the loword from a 64 bit address. - */ - Reg left = ra_alloc1(as, lref, RSET_GPR); - emit_tsml(as, MIPSI_DEXT, dest, left, 31, 0); - } else { /* 32/32 bit no-op (cast). */ - /* Do nothing, but may need to move regs. */ - ra_leftov(as, dest, lref); - } - } -#endif - } - } -} - -static void asm_strto(ASMState *as, IRIns *ir) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_strscan_num]; - IRRef args[2]; - int32_t ofs = 0; -#if LJ_SOFTFP32 - ra_evictset(as, RSET_SCRATCH); - if (ra_used(ir)) { - if (ra_hasspill(ir->s) && ra_hasspill((ir+1)->s) && - (ir->s & 1) == LJ_BE && (ir->s ^ 1) == (ir+1)->s) { - int i; - for (i = 0; i < 2; i++) { - Reg r = (ir+i)->r; - if (ra_hasreg(r)) { - ra_free(as, r); - ra_modified(as, r); - emit_spload(as, ir+i, r, sps_scale((ir+i)->s)); - } - } - ofs = sps_scale(ir->s & ~1); - } else { - Reg rhi = ra_dest(as, ir+1, RSET_GPR); - Reg rlo = ra_dest(as, ir, rset_exclude(RSET_GPR, rhi)); - emit_tsi(as, MIPSI_LW, rhi, RID_SP, ofs+(LJ_BE?0:4)); - emit_tsi(as, MIPSI_LW, rlo, RID_SP, ofs+(LJ_BE?4:0)); - } - } -#else - RegSet drop = RSET_SCRATCH; - if (ra_hasreg(ir->r)) rset_set(drop, ir->r); /* Spill dest reg (if any). */ - ra_evictset(as, drop); - ofs = sps_scale(ir->s); -#endif - asm_guard(as, MIPSI_BEQ, RID_RET, RID_ZERO); /* Test return status. */ - args[0] = ir->op1; /* GCstr *str */ - args[1] = ASMREF_TMP1; /* TValue *n */ - asm_gencall(as, ci, args); - /* Store the result to the spill slot or temp slots. */ - emit_tsi(as, MIPSI_AADDIU, ra_releasetmp(as, ASMREF_TMP1), - RID_SP, ofs); -} - -/* -- Memory references --------------------------------------------------- */ - -#if LJ_64 -/* Store tagged value for ref at base+ofs. */ -static void asm_tvstore64(ASMState *as, Reg base, int32_t ofs, IRRef ref) -{ - RegSet allow = rset_exclude(RSET_GPR, base); - IRIns *ir = IR(ref); - lua_assert(irt_ispri(ir->t) || irt_isaddr(ir->t) || irt_isinteger(ir->t)); - if (irref_isk(ref)) { - TValue k; - lj_ir_kvalue(as->J->L, &k, ir); - emit_tsi(as, MIPSI_SD, ra_allock(as, (int64_t)k.u64, allow), base, ofs); - } else { - Reg src = ra_alloc1(as, ref, allow); - Reg type = ra_allock(as, (int64_t)irt_toitype(ir->t) << 47, - rset_exclude(allow, src)); - emit_tsi(as, MIPSI_SD, RID_TMP, base, ofs); - if (irt_isinteger(ir->t)) { - emit_dst(as, MIPSI_DADDU, RID_TMP, RID_TMP, type); - emit_tsml(as, MIPSI_DEXT, RID_TMP, src, 31, 0); - } else { - emit_dst(as, MIPSI_DADDU, RID_TMP, src, type); - } - } -} -#endif - -/* Get pointer to TValue. */ -static void asm_tvptr(ASMState *as, Reg dest, IRRef ref) -{ - IRIns *ir = IR(ref); - if (irt_isnum(ir->t)) { - if (irref_isk(ref)) /* Use the number constant itself as a TValue. */ - ra_allockreg(as, igcptr(ir_knum(ir)), dest); - else /* Otherwise force a spill and use the spill slot. */ - emit_tsi(as, MIPSI_AADDIU, dest, RID_SP, ra_spill(as, ir)); - } else { - /* Otherwise use g->tmptv to hold the TValue. */ -#if LJ_32 - RegSet allow = rset_exclude(RSET_GPR, dest); - Reg type; - emit_tsi(as, MIPSI_ADDIU, dest, RID_JGL, (int32_t)(offsetof(global_State, tmptv)-32768)); - if (!irt_ispri(ir->t)) { - Reg src = ra_alloc1(as, ref, allow); - emit_setgl(as, src, tmptv.gcr); - } - if (LJ_SOFTFP && (ir+1)->o == IR_HIOP) - type = ra_alloc1(as, ref+1, allow); - else - type = ra_allock(as, (int32_t)irt_toitype(ir->t), allow); - emit_setgl(as, type, tmptv.it); -#else - asm_tvstore64(as, dest, 0, ref); - emit_tsi(as, MIPSI_DADDIU, dest, RID_JGL, - (int32_t)(offsetof(global_State, tmptv)-32768)); -#endif - } -} - -static void asm_aref(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg idx, base; - if (irref_isk(ir->op2)) { - IRRef tab = IR(ir->op1)->op1; - int32_t ofs = asm_fuseabase(as, tab); - IRRef refa = ofs ? tab : ir->op1; - ofs += 8*IR(ir->op2)->i; - if (checki16(ofs)) { - base = ra_alloc1(as, refa, RSET_GPR); - emit_tsi(as, MIPSI_AADDIU, dest, base, ofs); - return; - } - } - base = ra_alloc1(as, ir->op1, RSET_GPR); - idx = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, base)); - emit_dst(as, MIPSI_AADDU, dest, RID_TMP, base); - emit_dta(as, MIPSI_SLL, RID_TMP, idx, 3); -} - -/* Inlined hash lookup. Specialized for key type and for const keys. -** The equivalent C code is: -** Node *n = hashkey(t, key); -** do { -** if (lj_obj_equal(&n->key, key)) return &n->val; -** } while ((n = nextnode(n))); -** return niltv(L); -*/ -static void asm_href(ASMState *as, IRIns *ir, IROp merge) -{ - RegSet allow = RSET_GPR; - int destused = ra_used(ir); - Reg dest = ra_dest(as, ir, allow); - Reg tab = ra_alloc1(as, ir->op1, rset_clear(allow, dest)); - Reg key = RID_NONE, type = RID_NONE, tmpnum = RID_NONE, tmp1 = RID_TMP, tmp2; -#if LJ_64 - Reg cmp64 = RID_NONE; -#endif - IRRef refkey = ir->op2; - IRIns *irkey = IR(refkey); - int isk = irref_isk(refkey); - IRType1 kt = irkey->t; - uint32_t khash; - MCLabel l_end, l_loop, l_next; - - rset_clear(allow, tab); -#if LJ_SOFTFP32 - if (!isk) { - key = ra_alloc1(as, refkey, allow); - rset_clear(allow, key); - if (irkey[1].o == IR_HIOP) { - if (ra_hasreg((irkey+1)->r)) { - type = tmpnum = (irkey+1)->r; - tmp1 = ra_scratch(as, allow); - rset_clear(allow, tmp1); - ra_noweak(as, tmpnum); - } else { - type = tmpnum = ra_allocref(as, refkey+1, allow); - } - rset_clear(allow, tmpnum); - } else { - type = ra_allock(as, (int32_t)irt_toitype(irkey->t), allow); - rset_clear(allow, type); - } - } -#else - if (!LJ_SOFTFP && irt_isnum(kt)) { - key = ra_alloc1(as, refkey, RSET_FPR); - tmpnum = ra_scratch(as, rset_exclude(RSET_FPR, key)); - } else if (!irt_ispri(kt)) { - key = ra_alloc1(as, refkey, allow); - rset_clear(allow, key); -#if LJ_32 - type = ra_allock(as, (int32_t)irt_toitype(irkey->t), allow); - rset_clear(allow, type); -#endif - } -#endif - tmp2 = ra_scratch(as, allow); - rset_clear(allow, tmp2); -#if LJ_64 - if (LJ_SOFTFP || !irt_isnum(kt)) { - /* Allocate cmp64 register used for 64-bit comparisons */ - if (LJ_SOFTFP && irt_isnum(kt)) { - cmp64 = key; - } else if (!isk && irt_isaddr(kt)) { - cmp64 = tmp2; - } else { - int64_t k; - if (isk && irt_isaddr(kt)) { - k = ((int64_t)irt_toitype(irkey->t) << 47) | irkey[1].tv.u64; - } else { - lua_assert(irt_ispri(kt) && !irt_isnil(kt)); - k = ~((int64_t)~irt_toitype(ir->t) << 47); - } - cmp64 = ra_allock(as, k, allow); - rset_clear(allow, cmp64); - } - } -#endif - - /* Key not found in chain: jump to exit (if merged) or load niltv. */ - l_end = emit_label(as); - as->invmcp = NULL; - if (merge == IR_NE) - asm_guard(as, MIPSI_B, RID_ZERO, RID_ZERO); - else if (destused) - emit_loada(as, dest, niltvg(J2G(as->J))); - /* Follow hash chain until the end. */ - emit_move(as, dest, tmp1); - l_loop = --as->mcp; - emit_tsi(as, MIPSI_AL, tmp1, dest, (int32_t)offsetof(Node, next)); - l_next = emit_label(as); - - /* Type and value comparison. */ - if (merge == IR_EQ) { /* Must match asm_guard(). */ - emit_ti(as, MIPSI_LI, RID_TMP, as->snapno); - l_end = asm_exitstub_addr(as); - } - if (!LJ_SOFTFP && irt_isnum(kt)) { - emit_branch(as, MIPSI_BC1T, 0, 0, l_end); - emit_fgh(as, MIPSI_C_EQ_D, 0, tmpnum, key); - *--as->mcp = MIPSI_NOP; /* Avoid NaN comparison overhead. */ - emit_branch(as, MIPSI_BEQ, tmp1, RID_ZERO, l_next); - emit_tsi(as, MIPSI_SLTIU, tmp1, tmp1, (int32_t)LJ_TISNUM); -#if LJ_32 - emit_hsi(as, MIPSI_LDC1, tmpnum, dest, (int32_t)offsetof(Node, key.n)); - } else { - if (irt_ispri(kt)) { - emit_branch(as, MIPSI_BEQ, tmp1, type, l_end); - } else { - emit_branch(as, MIPSI_BEQ, tmp2, key, l_end); - emit_tsi(as, MIPSI_LW, tmp2, dest, (int32_t)offsetof(Node, key.gcr)); - emit_branch(as, MIPSI_BNE, tmp1, type, l_next); - } - } - emit_tsi(as, MIPSI_LW, tmp1, dest, (int32_t)offsetof(Node, key.it)); - *l_loop = MIPSI_BNE | MIPSF_S(tmp1) | ((as->mcp-l_loop-1) & 0xffffu); -#else - emit_dta(as, MIPSI_DSRA32, tmp1, tmp1, 15); - emit_tg(as, MIPSI_DMTC1, tmp1, tmpnum); - emit_tsi(as, MIPSI_LD, tmp1, dest, (int32_t)offsetof(Node, key.u64)); - } else { - emit_branch(as, MIPSI_BEQ, tmp1, cmp64, l_end); - emit_tsi(as, MIPSI_LD, tmp1, dest, (int32_t)offsetof(Node, key.u64)); - } - *l_loop = MIPSI_BNE | MIPSF_S(tmp1) | ((as->mcp-l_loop-1) & 0xffffu); - if (!isk && irt_isaddr(kt)) { - type = ra_allock(as, (int64_t)irt_toitype(kt) << 47, allow); - emit_dst(as, MIPSI_DADDU, tmp2, key, type); - rset_clear(allow, type); - } -#endif - - /* Load main position relative to tab->node into dest. */ - khash = isk ? ir_khash(irkey) : 1; - if (khash == 0) { - emit_tsi(as, MIPSI_AL, dest, tab, (int32_t)offsetof(GCtab, node)); - } else { - Reg tmphash = tmp1; - if (isk) - tmphash = ra_allock(as, khash, allow); - emit_dst(as, MIPSI_AADDU, dest, dest, tmp1); - lua_assert(sizeof(Node) == 24); - emit_dst(as, MIPSI_SUBU, tmp1, tmp2, tmp1); - emit_dta(as, MIPSI_SLL, tmp1, tmp1, 3); - emit_dta(as, MIPSI_SLL, tmp2, tmp1, 5); - emit_dst(as, MIPSI_AND, tmp1, tmp2, tmphash); - emit_tsi(as, MIPSI_AL, dest, tab, (int32_t)offsetof(GCtab, node)); - emit_tsi(as, MIPSI_LW, tmp2, tab, (int32_t)offsetof(GCtab, hmask)); - if (isk) { - /* Nothing to do. */ - } else if (irt_isstr(kt)) { - emit_tsi(as, MIPSI_LW, tmp1, key, (int32_t)offsetof(GCstr, hash)); - } else { /* Must match with hash*() in lj_tab.c. */ - emit_dst(as, MIPSI_SUBU, tmp1, tmp1, tmp2); - emit_rotr(as, tmp2, tmp2, dest, (-HASH_ROT3)&31); - emit_dst(as, MIPSI_XOR, tmp1, tmp1, tmp2); - emit_rotr(as, tmp1, tmp1, dest, (-HASH_ROT2-HASH_ROT1)&31); - emit_dst(as, MIPSI_SUBU, tmp2, tmp2, dest); -#if LJ_32 - if (LJ_SOFTFP ? (irkey[1].o == IR_HIOP) : irt_isnum(kt)) { - emit_dst(as, MIPSI_XOR, tmp2, tmp2, tmp1); - if ((as->flags & JIT_F_MIPSXXR2)) { - emit_dta(as, MIPSI_ROTR, dest, tmp1, (-HASH_ROT1)&31); - } else { - emit_dst(as, MIPSI_OR, dest, dest, tmp1); - emit_dta(as, MIPSI_SLL, tmp1, tmp1, HASH_ROT1); - emit_dta(as, MIPSI_SRL, dest, tmp1, (-HASH_ROT1)&31); - } - emit_dst(as, MIPSI_ADDU, tmp1, tmp1, tmp1); -#if LJ_SOFTFP - emit_ds(as, MIPSI_MOVE, tmp1, type); - emit_ds(as, MIPSI_MOVE, tmp2, key); -#else - emit_tg(as, MIPSI_MFC1, tmp2, key); - emit_tg(as, MIPSI_MFC1, tmp1, key+1); -#endif - } else { - emit_dst(as, MIPSI_XOR, tmp2, key, tmp1); - emit_rotr(as, dest, tmp1, tmp2, (-HASH_ROT1)&31); - emit_dst(as, MIPSI_ADDU, tmp1, key, ra_allock(as, HASH_BIAS, allow)); - } -#else - emit_dst(as, MIPSI_XOR, tmp2, tmp2, tmp1); - emit_dta(as, MIPSI_ROTR, dest, tmp1, (-HASH_ROT1)&31); - if (irt_isnum(kt)) { - emit_dst(as, MIPSI_ADDU, tmp1, tmp1, tmp1); - emit_dta(as, MIPSI_DSRA32, tmp1, LJ_SOFTFP ? key : tmp1, 0); - emit_dta(as, MIPSI_SLL, tmp2, LJ_SOFTFP ? key : tmp1, 0); -#if !LJ_SOFTFP - emit_tg(as, MIPSI_DMFC1, tmp1, key); -#endif - } else { - checkmclim(as); - emit_dta(as, MIPSI_DSRA32, tmp1, tmp1, 0); - emit_dta(as, MIPSI_SLL, tmp2, key, 0); - emit_dst(as, MIPSI_DADDU, tmp1, key, type); - } -#endif - } - } -} - -static void asm_hrefk(ASMState *as, IRIns *ir) -{ - IRIns *kslot = IR(ir->op2); - IRIns *irkey = IR(kslot->op1); - int32_t ofs = (int32_t)(kslot->op2 * sizeof(Node)); - int32_t kofs = ofs + (int32_t)offsetof(Node, key); - Reg dest = (ra_used(ir)||ofs > 32736) ? ra_dest(as, ir, RSET_GPR) : RID_NONE; - Reg node = ra_alloc1(as, ir->op1, RSET_GPR); - RegSet allow = rset_exclude(RSET_GPR, node); - Reg idx = node; -#if LJ_32 - Reg key = RID_NONE, type = RID_TMP; - int32_t lo, hi; -#else - Reg key = ra_scratch(as, allow); - int64_t k; -#endif - lua_assert(ofs % sizeof(Node) == 0); - if (ofs > 32736) { - idx = dest; - rset_clear(allow, dest); - kofs = (int32_t)offsetof(Node, key); - } else if (ra_hasreg(dest)) { - emit_tsi(as, MIPSI_AADDIU, dest, node, ofs); - } -#if LJ_32 - if (!irt_ispri(irkey->t)) { - key = ra_scratch(as, allow); - rset_clear(allow, key); - } - if (irt_isnum(irkey->t)) { - lo = (int32_t)ir_knum(irkey)->u32.lo; - hi = (int32_t)ir_knum(irkey)->u32.hi; - } else { - lo = irkey->i; - hi = irt_toitype(irkey->t); - if (!ra_hasreg(key)) - goto nolo; - } - asm_guard(as, MIPSI_BNE, key, lo ? ra_allock(as, lo, allow) : RID_ZERO); -nolo: - asm_guard(as, MIPSI_BNE, type, hi ? ra_allock(as, hi, allow) : RID_ZERO); - if (ra_hasreg(key)) emit_tsi(as, MIPSI_LW, key, idx, kofs+(LJ_BE?4:0)); - emit_tsi(as, MIPSI_LW, type, idx, kofs+(LJ_BE?0:4)); -#else - if (irt_ispri(irkey->t)) { - lua_assert(!irt_isnil(irkey->t)); - k = ~((int64_t)~irt_toitype(irkey->t) << 47); - } else if (irt_isnum(irkey->t)) { - k = (int64_t)ir_knum(irkey)->u64; - } else { - k = ((int64_t)irt_toitype(irkey->t) << 47) | (int64_t)ir_kgc(irkey); - } - asm_guard(as, MIPSI_BNE, key, ra_allock(as, k, allow)); - emit_tsi(as, MIPSI_LD, key, idx, kofs); -#endif - if (ofs > 32736) - emit_tsi(as, MIPSI_AADDU, dest, node, ra_allock(as, ofs, allow)); -} - -static void asm_uref(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - if (irref_isk(ir->op1)) { - GCfunc *fn = ir_kfunc(IR(ir->op1)); - MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v; - emit_lsptr(as, MIPSI_AL, dest, v, RSET_GPR); - } else { - Reg uv = ra_scratch(as, RSET_GPR); - Reg func = ra_alloc1(as, ir->op1, RSET_GPR); - if (ir->o == IR_UREFC) { - asm_guard(as, MIPSI_BEQ, RID_TMP, RID_ZERO); - emit_tsi(as, MIPSI_AADDIU, dest, uv, (int32_t)offsetof(GCupval, tv)); - emit_tsi(as, MIPSI_LBU, RID_TMP, uv, (int32_t)offsetof(GCupval, closed)); - } else { - emit_tsi(as, MIPSI_AL, dest, uv, (int32_t)offsetof(GCupval, v)); - } - emit_tsi(as, MIPSI_AL, uv, func, (int32_t)offsetof(GCfuncL, uvptr) + - (int32_t)sizeof(MRef) * (int32_t)(ir->op2 >> 8)); - } -} - -static void asm_fref(ASMState *as, IRIns *ir) -{ - UNUSED(as); UNUSED(ir); - lua_assert(!ra_used(ir)); -} - -static void asm_strref(ASMState *as, IRIns *ir) -{ -#if LJ_32 - Reg dest = ra_dest(as, ir, RSET_GPR); - IRRef ref = ir->op2, refk = ir->op1; - int32_t ofs = (int32_t)sizeof(GCstr); - Reg r; - if (irref_isk(ref)) { - IRRef tmp = refk; refk = ref; ref = tmp; - } else if (!irref_isk(refk)) { - Reg right, left = ra_alloc1(as, ir->op1, RSET_GPR); - IRIns *irr = IR(ir->op2); - if (ra_hasreg(irr->r)) { - ra_noweak(as, irr->r); - right = irr->r; - } else if (mayfuse(as, irr->op2) && - irr->o == IR_ADD && irref_isk(irr->op2) && - checki16(ofs + IR(irr->op2)->i)) { - ofs += IR(irr->op2)->i; - right = ra_alloc1(as, irr->op1, rset_exclude(RSET_GPR, left)); - } else { - right = ra_allocref(as, ir->op2, rset_exclude(RSET_GPR, left)); - } - emit_tsi(as, MIPSI_ADDIU, dest, dest, ofs); - emit_dst(as, MIPSI_ADDU, dest, left, right); - return; - } - r = ra_alloc1(as, ref, RSET_GPR); - ofs += IR(refk)->i; - if (checki16(ofs)) - emit_tsi(as, MIPSI_ADDIU, dest, r, ofs); - else - emit_dst(as, MIPSI_ADDU, dest, r, - ra_allock(as, ofs, rset_exclude(RSET_GPR, r))); -#else - RegSet allow = RSET_GPR; - Reg dest = ra_dest(as, ir, allow); - Reg base = ra_alloc1(as, ir->op1, allow); - IRIns *irr = IR(ir->op2); - int32_t ofs = sizeof(GCstr); - rset_clear(allow, base); - if (irref_isk(ir->op2) && checki16(ofs + irr->i)) { - emit_tsi(as, MIPSI_DADDIU, dest, base, ofs + irr->i); - } else { - emit_tsi(as, MIPSI_DADDIU, dest, dest, ofs); - emit_dst(as, MIPSI_DADDU, dest, base, ra_alloc1(as, ir->op2, allow)); - } -#endif -} - -/* -- Loads and stores ---------------------------------------------------- */ - -static MIPSIns asm_fxloadins(IRIns *ir) -{ - switch (irt_type(ir->t)) { - case IRT_I8: return MIPSI_LB; - case IRT_U8: return MIPSI_LBU; - case IRT_I16: return MIPSI_LH; - case IRT_U16: return MIPSI_LHU; - case IRT_NUM: lua_assert(!LJ_SOFTFP32); if (!LJ_SOFTFP) return MIPSI_LDC1; - case IRT_FLOAT: if (!LJ_SOFTFP) return MIPSI_LWC1; - default: return (LJ_64 && irt_is64(ir->t)) ? MIPSI_LD : MIPSI_LW; - } -} - -static MIPSIns asm_fxstoreins(IRIns *ir) -{ - switch (irt_type(ir->t)) { - case IRT_I8: case IRT_U8: return MIPSI_SB; - case IRT_I16: case IRT_U16: return MIPSI_SH; - case IRT_NUM: lua_assert(!LJ_SOFTFP32); if (!LJ_SOFTFP) return MIPSI_SDC1; - case IRT_FLOAT: if (!LJ_SOFTFP) return MIPSI_SWC1; - default: return (LJ_64 && irt_is64(ir->t)) ? MIPSI_SD : MIPSI_SW; - } -} - -static void asm_fload(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - MIPSIns mi = asm_fxloadins(ir); - Reg idx; - int32_t ofs; - if (ir->op1 == REF_NIL) { - idx = RID_JGL; - ofs = (ir->op2 << 2) - 32768 - GG_OFS(g); - } else { - idx = ra_alloc1(as, ir->op1, RSET_GPR); - if (ir->op2 == IRFL_TAB_ARRAY) { - ofs = asm_fuseabase(as, ir->op1); - if (ofs) { /* Turn the t->array load into an add for colocated arrays. */ - emit_tsi(as, MIPSI_AADDIU, dest, idx, ofs); - return; - } - } - ofs = field_ofs[ir->op2]; - } - lua_assert(!irt_isfp(ir->t)); - emit_tsi(as, mi, dest, idx, ofs); -} - -static void asm_fstore(ASMState *as, IRIns *ir) -{ - if (ir->r != RID_SINK) { - Reg src = ra_alloc1z(as, ir->op2, RSET_GPR); - IRIns *irf = IR(ir->op1); - Reg idx = ra_alloc1(as, irf->op1, rset_exclude(RSET_GPR, src)); - int32_t ofs = field_ofs[irf->op2]; - MIPSIns mi = asm_fxstoreins(ir); - lua_assert(!irt_isfp(ir->t)); - emit_tsi(as, mi, src, idx, ofs); - } -} - -static void asm_xload(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, - (!LJ_SOFTFP && irt_isfp(ir->t)) ? RSET_FPR : RSET_GPR); - lua_assert(!(ir->op2 & IRXLOAD_UNALIGNED)); - asm_fusexref(as, asm_fxloadins(ir), dest, ir->op1, RSET_GPR, 0); -} - -static void asm_xstore_(ASMState *as, IRIns *ir, int32_t ofs) -{ - if (ir->r != RID_SINK) { - Reg src = ra_alloc1z(as, ir->op2, - (!LJ_SOFTFP && irt_isfp(ir->t)) ? RSET_FPR : RSET_GPR); - asm_fusexref(as, asm_fxstoreins(ir), src, ir->op1, - rset_exclude(RSET_GPR, src), ofs); - } -} - -#define asm_xstore(as, ir) asm_xstore_(as, ir, 0) - -static void asm_ahuvload(ASMState *as, IRIns *ir) -{ - int hiop = (LJ_SOFTFP32 && (ir+1)->o == IR_HIOP); - Reg dest = RID_NONE, type = RID_TMP, idx; - RegSet allow = RSET_GPR; - int32_t ofs = 0; - IRType1 t = ir->t; - if (hiop) { - t.irt = IRT_NUM; - if (ra_used(ir+1)) { - type = ra_dest(as, ir+1, allow); - rset_clear(allow, type); - } - } - if (ra_used(ir)) { - lua_assert((LJ_SOFTFP32 ? 0 : irt_isnum(ir->t)) || - irt_isint(ir->t) || irt_isaddr(ir->t)); - dest = ra_dest(as, ir, (!LJ_SOFTFP && irt_isnum(t)) ? RSET_FPR : allow); - rset_clear(allow, dest); -#if LJ_64 - if (irt_isaddr(t)) - emit_tsml(as, MIPSI_DEXTM, dest, dest, 14, 0); - else if (irt_isint(t)) - emit_dta(as, MIPSI_SLL, dest, dest, 0); -#endif - } - idx = asm_fuseahuref(as, ir->op1, &ofs, allow); - rset_clear(allow, idx); - if (irt_isnum(t)) { - asm_guard(as, MIPSI_BEQ, RID_TMP, RID_ZERO); - emit_tsi(as, MIPSI_SLTIU, RID_TMP, type, (int32_t)LJ_TISNUM); - } else { - asm_guard(as, MIPSI_BNE, type, - ra_allock(as, (int32_t)irt_toitype(t), allow)); - } -#if LJ_32 - if (ra_hasreg(dest)) { - if (!LJ_SOFTFP && irt_isnum(t)) - emit_hsi(as, MIPSI_LDC1, dest, idx, ofs); - else - emit_tsi(as, MIPSI_LW, dest, idx, ofs+(LJ_BE?4:0)); - } - emit_tsi(as, MIPSI_LW, type, idx, ofs+(LJ_BE?0:4)); -#else - if (ra_hasreg(dest)) { - if (!LJ_SOFTFP && irt_isnum(t)) { - emit_hsi(as, MIPSI_LDC1, dest, idx, ofs); - dest = type; - } - } else { - dest = type; - } - emit_dta(as, MIPSI_DSRA32, type, dest, 15); - emit_tsi(as, MIPSI_LD, dest, idx, ofs); -#endif -} - -static void asm_ahustore(ASMState *as, IRIns *ir) -{ - RegSet allow = RSET_GPR; - Reg idx, src = RID_NONE, type = RID_NONE; - int32_t ofs = 0; - if (ir->r == RID_SINK) - return; - if (!LJ_SOFTFP32 && irt_isnum(ir->t)) { - src = ra_alloc1(as, ir->op2, LJ_SOFTFP ? RSET_GPR : RSET_FPR); - idx = asm_fuseahuref(as, ir->op1, &ofs, allow); - emit_hsi(as, LJ_SOFTFP ? MIPSI_SD : MIPSI_SDC1, src, idx, ofs); - } else { -#if LJ_32 - if (!irt_ispri(ir->t)) { - src = ra_alloc1(as, ir->op2, allow); - rset_clear(allow, src); - } - if (LJ_SOFTFP && (ir+1)->o == IR_HIOP) - type = ra_alloc1(as, (ir+1)->op2, allow); - else - type = ra_allock(as, (int32_t)irt_toitype(ir->t), allow); - rset_clear(allow, type); - idx = asm_fuseahuref(as, ir->op1, &ofs, allow); - if (ra_hasreg(src)) - emit_tsi(as, MIPSI_SW, src, idx, ofs+(LJ_BE?4:0)); - emit_tsi(as, MIPSI_SW, type, idx, ofs+(LJ_BE?0:4)); -#else - Reg tmp = RID_TMP; - if (irt_ispri(ir->t)) { - tmp = ra_allock(as, ~((int64_t)~irt_toitype(ir->t) << 47), allow); - rset_clear(allow, tmp); - } else { - src = ra_alloc1(as, ir->op2, allow); - rset_clear(allow, src); - type = ra_allock(as, (int64_t)irt_toitype(ir->t) << 47, allow); - rset_clear(allow, type); - } - idx = asm_fuseahuref(as, ir->op1, &ofs, allow); - emit_tsi(as, MIPSI_SD, tmp, idx, ofs); - if (ra_hasreg(src)) { - if (irt_isinteger(ir->t)) { - emit_dst(as, MIPSI_DADDU, tmp, tmp, type); - emit_tsml(as, MIPSI_DEXT, tmp, src, 31, 0); - } else { - emit_dst(as, MIPSI_DADDU, tmp, src, type); - } - } -#endif - } -} - -static void asm_sload(ASMState *as, IRIns *ir) -{ - Reg dest = RID_NONE, type = RID_NONE, base; - RegSet allow = RSET_GPR; - IRType1 t = ir->t; -#if LJ_32 - int32_t ofs = 8*((int32_t)ir->op1-1) + ((ir->op2 & IRSLOAD_FRAME) ? 4 : 0); - int hiop = (LJ_SOFTFP32 && (ir+1)->o == IR_HIOP); - if (hiop) - t.irt = IRT_NUM; -#else - int32_t ofs = 8*((int32_t)ir->op1-2); -#endif - lua_assert(!(ir->op2 & IRSLOAD_PARENT)); /* Handled by asm_head_side(). */ - lua_assert(irt_isguard(ir->t) || !(ir->op2 & IRSLOAD_TYPECHECK)); -#if LJ_SOFTFP32 - lua_assert(!(ir->op2 & IRSLOAD_CONVERT)); /* Handled by LJ_SOFTFP SPLIT. */ - if (hiop && ra_used(ir+1)) { - type = ra_dest(as, ir+1, allow); - rset_clear(allow, type); - } -#else - if ((ir->op2 & IRSLOAD_CONVERT) && irt_isguard(t) && irt_isint(t)) { - dest = ra_scratch(as, LJ_SOFTFP ? allow : RSET_FPR); - asm_tointg(as, ir, dest); - t.irt = IRT_NUM; /* Continue with a regular number type check. */ - } else -#endif - if (ra_used(ir)) { - lua_assert((LJ_SOFTFP32 ? 0 : irt_isnum(ir->t)) || - irt_isint(ir->t) || irt_isaddr(ir->t)); - dest = ra_dest(as, ir, (!LJ_SOFTFP && irt_isnum(t)) ? RSET_FPR : allow); - rset_clear(allow, dest); - base = ra_alloc1(as, REF_BASE, allow); - rset_clear(allow, base); - if (!LJ_SOFTFP32 && (ir->op2 & IRSLOAD_CONVERT)) { - if (irt_isint(t)) { - Reg tmp = ra_scratch(as, LJ_SOFTFP ? RSET_GPR : RSET_FPR); -#if LJ_SOFTFP - ra_evictset(as, rset_exclude(RSET_SCRATCH, dest)); - ra_destreg(as, ir, RID_RET); - emit_call(as, (void *)lj_ir_callinfo[IRCALL_softfp_d2i].func, 0); - if (tmp != REGARG_FIRSTGPR) - emit_move(as, REGARG_FIRSTGPR, tmp); -#else - emit_tg(as, MIPSI_MFC1, dest, tmp); - emit_fg(as, MIPSI_TRUNC_W_D, tmp, tmp); -#endif - dest = tmp; - t.irt = IRT_NUM; /* Check for original type. */ - } else { - Reg tmp = ra_scratch(as, RSET_GPR); -#if LJ_SOFTFP - ra_evictset(as, rset_exclude(RSET_SCRATCH, dest)); - ra_destreg(as, ir, RID_RET); - emit_call(as, (void *)lj_ir_callinfo[IRCALL_softfp_i2d].func, 0); - emit_dta(as, MIPSI_SLL, REGARG_FIRSTGPR, tmp, 0); -#else - emit_fg(as, MIPSI_CVT_D_W, dest, dest); - emit_tg(as, MIPSI_MTC1, tmp, dest); -#endif - dest = tmp; - t.irt = IRT_INT; /* Check for original type. */ - } - } -#if LJ_64 - else if (irt_isaddr(t)) { - /* Clear type from pointers. */ - emit_tsml(as, MIPSI_DEXTM, dest, dest, 14, 0); - } else if (irt_isint(t) && (ir->op2 & IRSLOAD_TYPECHECK)) { - /* Sign-extend integers. */ - emit_dta(as, MIPSI_SLL, dest, dest, 0); - } -#endif - goto dotypecheck; - } - base = ra_alloc1(as, REF_BASE, allow); - rset_clear(allow, base); -dotypecheck: -#if LJ_32 - if ((ir->op2 & IRSLOAD_TYPECHECK)) { - if (ra_noreg(type)) - type = RID_TMP; - if (irt_isnum(t)) { - asm_guard(as, MIPSI_BEQ, RID_TMP, RID_ZERO); - emit_tsi(as, MIPSI_SLTIU, RID_TMP, type, (int32_t)LJ_TISNUM); - } else { - Reg ktype = ra_allock(as, irt_toitype(t), allow); - asm_guard(as, MIPSI_BNE, type, ktype); - } - } - if (ra_hasreg(dest)) { - if (!LJ_SOFTFP && irt_isnum(t)) - emit_hsi(as, MIPSI_LDC1, dest, base, ofs); - else - emit_tsi(as, MIPSI_LW, dest, base, ofs ^ (LJ_BE?4:0)); - } - if (ra_hasreg(type)) - emit_tsi(as, MIPSI_LW, type, base, ofs ^ (LJ_BE?0:4)); -#else - if ((ir->op2 & IRSLOAD_TYPECHECK)) { - type = dest < RID_MAX_GPR ? dest : RID_TMP; - if (irt_ispri(t)) { - asm_guard(as, MIPSI_BNE, type, - ra_allock(as, ~((int64_t)~irt_toitype(t) << 47) , allow)); - } else { - if (irt_isnum(t)) { - asm_guard(as, MIPSI_BEQ, RID_TMP, RID_ZERO); - emit_tsi(as, MIPSI_SLTIU, RID_TMP, RID_TMP, (int32_t)LJ_TISNUM); - if (!LJ_SOFTFP && ra_hasreg(dest)) - emit_hsi(as, MIPSI_LDC1, dest, base, ofs); - } else { - asm_guard(as, MIPSI_BNE, RID_TMP, - ra_allock(as, (int32_t)irt_toitype(t), allow)); - } - emit_dta(as, MIPSI_DSRA32, RID_TMP, type, 15); - } - emit_tsi(as, MIPSI_LD, type, base, ofs); - } else if (ra_hasreg(dest)) { - if (!LJ_SOFTFP && irt_isnum(t)) - emit_hsi(as, MIPSI_LDC1, dest, base, ofs); - else - emit_tsi(as, irt_isint(t) ? MIPSI_LW : MIPSI_LD, dest, base, - ofs ^ ((LJ_BE && irt_isint(t)) ? 4 : 0)); - } -#endif -} - -/* -- Allocations --------------------------------------------------------- */ - -#if LJ_HASFFI -static void asm_cnew(ASMState *as, IRIns *ir) -{ - CTState *cts = ctype_ctsG(J2G(as->J)); - CTypeID id = (CTypeID)IR(ir->op1)->i; - CTSize sz; - CTInfo info = lj_ctype_info(cts, id, &sz); - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_mem_newgco]; - IRRef args[4]; - RegSet drop = RSET_SCRATCH; - lua_assert(sz != CTSIZE_INVALID || (ir->o == IR_CNEW && ir->op2 != REF_NIL)); - - as->gcsteps++; - if (ra_hasreg(ir->r)) - rset_clear(drop, ir->r); /* Dest reg handled below. */ - ra_evictset(as, drop); - if (ra_used(ir)) - ra_destreg(as, ir, RID_RET); /* GCcdata * */ - - /* Initialize immutable cdata object. */ - if (ir->o == IR_CNEWI) { - RegSet allow = (RSET_GPR & ~RSET_SCRATCH); -#if LJ_32 - int32_t ofs = sizeof(GCcdata); - if (sz == 8) { - ofs += 4; - lua_assert((ir+1)->o == IR_HIOP); - if (LJ_LE) ir++; - } - for (;;) { - Reg r = ra_alloc1z(as, ir->op2, allow); - emit_tsi(as, MIPSI_SW, r, RID_RET, ofs); - rset_clear(allow, r); - if (ofs == sizeof(GCcdata)) break; - ofs -= 4; if (LJ_BE) ir++; else ir--; - } -#else - emit_tsi(as, MIPSI_SD, ra_alloc1(as, ir->op2, allow), - RID_RET, sizeof(GCcdata)); -#endif - lua_assert(sz == 4 || sz == 8); - } else if (ir->op2 != REF_NIL) { /* Create VLA/VLS/aligned cdata. */ - ci = &lj_ir_callinfo[IRCALL_lj_cdata_newv]; - args[0] = ASMREF_L; /* lua_State *L */ - args[1] = ir->op1; /* CTypeID id */ - args[2] = ir->op2; /* CTSize sz */ - args[3] = ASMREF_TMP1; /* CTSize align */ - asm_gencall(as, ci, args); - emit_loadi(as, ra_releasetmp(as, ASMREF_TMP1), (int32_t)ctype_align(info)); - return; - } - - /* Initialize gct and ctypeid. lj_mem_newgco() already sets marked. */ - emit_tsi(as, MIPSI_SB, RID_RET+1, RID_RET, offsetof(GCcdata, gct)); - emit_tsi(as, MIPSI_SH, RID_TMP, RID_RET, offsetof(GCcdata, ctypeid)); - emit_ti(as, MIPSI_LI, RID_RET+1, ~LJ_TCDATA); - emit_ti(as, MIPSI_LI, RID_TMP, id); /* Lower 16 bit used. Sign-ext ok. */ - args[0] = ASMREF_L; /* lua_State *L */ - args[1] = ASMREF_TMP1; /* MSize size */ - asm_gencall(as, ci, args); - ra_allockreg(as, (int32_t)(sz+sizeof(GCcdata)), - ra_releasetmp(as, ASMREF_TMP1)); -} -#else -#define asm_cnew(as, ir) ((void)0) -#endif - -/* -- Write barriers ------------------------------------------------------ */ - -static void asm_tbar(ASMState *as, IRIns *ir) -{ - Reg tab = ra_alloc1(as, ir->op1, RSET_GPR); - Reg mark = ra_scratch(as, rset_exclude(RSET_GPR, tab)); - Reg link = RID_TMP; - MCLabel l_end = emit_label(as); - emit_tsi(as, MIPSI_AS, link, tab, (int32_t)offsetof(GCtab, gclist)); - emit_tsi(as, MIPSI_SB, mark, tab, (int32_t)offsetof(GCtab, marked)); - emit_setgl(as, tab, gc.grayagain); - emit_getgl(as, link, gc.grayagain); - emit_dst(as, MIPSI_XOR, mark, mark, RID_TMP); /* Clear black bit. */ - emit_branch(as, MIPSI_BEQ, RID_TMP, RID_ZERO, l_end); - emit_tsi(as, MIPSI_ANDI, RID_TMP, mark, LJ_GC_BLACK); - emit_tsi(as, MIPSI_LBU, mark, tab, (int32_t)offsetof(GCtab, marked)); -} - -static void asm_obar(ASMState *as, IRIns *ir) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_gc_barrieruv]; - IRRef args[2]; - MCLabel l_end; - Reg obj, val, tmp; - /* No need for other object barriers (yet). */ - lua_assert(IR(ir->op1)->o == IR_UREFC); - ra_evictset(as, RSET_SCRATCH); - l_end = emit_label(as); - args[0] = ASMREF_TMP1; /* global_State *g */ - args[1] = ir->op1; /* TValue *tv */ - asm_gencall(as, ci, args); - emit_tsi(as, MIPSI_AADDIU, ra_releasetmp(as, ASMREF_TMP1), RID_JGL, -32768); - obj = IR(ir->op1)->r; - tmp = ra_scratch(as, rset_exclude(RSET_GPR, obj)); - emit_branch(as, MIPSI_BEQ, RID_TMP, RID_ZERO, l_end); - emit_tsi(as, MIPSI_ANDI, tmp, tmp, LJ_GC_BLACK); - emit_branch(as, MIPSI_BEQ, RID_TMP, RID_ZERO, l_end); - emit_tsi(as, MIPSI_ANDI, RID_TMP, RID_TMP, LJ_GC_WHITES); - val = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, obj)); - emit_tsi(as, MIPSI_LBU, tmp, obj, - (int32_t)offsetof(GCupval, marked)-(int32_t)offsetof(GCupval, tv)); - emit_tsi(as, MIPSI_LBU, RID_TMP, val, (int32_t)offsetof(GChead, marked)); -} - -/* -- Arithmetic and logic operations ------------------------------------- */ - -#if !LJ_SOFTFP -static void asm_fparith(ASMState *as, IRIns *ir, MIPSIns mi) -{ - Reg dest = ra_dest(as, ir, RSET_FPR); - Reg right, left = ra_alloc2(as, ir, RSET_FPR); - right = (left >> 8); left &= 255; - emit_fgh(as, mi, dest, left, right); -} - -static void asm_fpunary(ASMState *as, IRIns *ir, MIPSIns mi) -{ - Reg dest = ra_dest(as, ir, RSET_FPR); - Reg left = ra_hintalloc(as, ir->op1, dest, RSET_FPR); - emit_fg(as, mi, dest, left); -} -#endif - -#if !LJ_SOFTFP32 -static void asm_fpmath(ASMState *as, IRIns *ir) -{ - if (ir->op2 == IRFPM_EXP2 && asm_fpjoin_pow(as, ir)) - return; -#if !LJ_SOFTFP - if (ir->op2 <= IRFPM_TRUNC) - asm_callround(as, ir, IRCALL_lj_vm_floor + ir->op2); - else if (ir->op2 == IRFPM_SQRT) - asm_fpunary(as, ir, MIPSI_SQRT_D); - else -#endif - asm_callid(as, ir, IRCALL_lj_vm_floor + ir->op2); -} -#endif - -#if !LJ_SOFTFP -#define asm_fpadd(as, ir) asm_fparith(as, ir, MIPSI_ADD_D) -#define asm_fpsub(as, ir) asm_fparith(as, ir, MIPSI_SUB_D) -#define asm_fpmul(as, ir) asm_fparith(as, ir, MIPSI_MUL_D) -#elif LJ_64 /* && LJ_SOFTFP */ -#define asm_fpadd(as, ir) asm_callid(as, ir, IRCALL_softfp_add) -#define asm_fpsub(as, ir) asm_callid(as, ir, IRCALL_softfp_sub) -#define asm_fpmul(as, ir) asm_callid(as, ir, IRCALL_softfp_mul) -#endif - -static void asm_add(ASMState *as, IRIns *ir) -{ - IRType1 t = ir->t; -#if !LJ_SOFTFP32 - if (irt_isnum(t)) { - asm_fpadd(as, ir); - } else -#endif - { - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg right, left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); - if (irref_isk(ir->op2)) { - intptr_t k = get_kval(IR(ir->op2)); - if (checki16(k)) { - emit_tsi(as, (LJ_64 && irt_is64(t)) ? MIPSI_DADDIU : MIPSI_ADDIU, dest, - left, k); - return; - } - } - right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left)); - emit_dst(as, (LJ_64 && irt_is64(t)) ? MIPSI_DADDU : MIPSI_ADDU, dest, - left, right); - } -} - -static void asm_sub(ASMState *as, IRIns *ir) -{ -#if !LJ_SOFTFP32 - if (irt_isnum(ir->t)) { - asm_fpsub(as, ir); - } else -#endif - { - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg right, left = ra_alloc2(as, ir, RSET_GPR); - right = (left >> 8); left &= 255; - emit_dst(as, (LJ_64 && irt_is64(ir->t)) ? MIPSI_DSUBU : MIPSI_SUBU, dest, - left, right); - } -} - -static void asm_mul(ASMState *as, IRIns *ir) -{ -#if !LJ_SOFTFP32 - if (irt_isnum(ir->t)) { - asm_fpmul(as, ir); - } else -#endif - { - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg right, left = ra_alloc2(as, ir, RSET_GPR); - right = (left >> 8); left &= 255; - if (LJ_64 && irt_is64(ir->t)) { - emit_dst(as, MIPSI_MFLO, dest, 0, 0); - emit_dst(as, MIPSI_DMULT, 0, left, right); - } else { - emit_dst(as, MIPSI_MUL, dest, left, right); - } - } -} - -static void asm_mod(ASMState *as, IRIns *ir) -{ -#if LJ_64 && LJ_HASFFI - if (!irt_isint(ir->t)) - asm_callid(as, ir, irt_isi64(ir->t) ? IRCALL_lj_carith_modi64 : - IRCALL_lj_carith_modu64); - else -#endif - asm_callid(as, ir, IRCALL_lj_vm_modi); -} - -#if !LJ_SOFTFP32 -static void asm_pow(ASMState *as, IRIns *ir) -{ -#if LJ_64 && LJ_HASFFI - if (!irt_isnum(ir->t)) - asm_callid(as, ir, irt_isi64(ir->t) ? IRCALL_lj_carith_powi64 : - IRCALL_lj_carith_powu64); - else -#endif - asm_callid(as, ir, IRCALL_lj_vm_powi); -} - -static void asm_div(ASMState *as, IRIns *ir) -{ -#if LJ_64 && LJ_HASFFI - if (!irt_isnum(ir->t)) - asm_callid(as, ir, irt_isi64(ir->t) ? IRCALL_lj_carith_divi64 : - IRCALL_lj_carith_divu64); - else -#endif -#if !LJ_SOFTFP - asm_fparith(as, ir, MIPSI_DIV_D); -#else - asm_callid(as, ir, IRCALL_softfp_div); -#endif -} -#endif - -static void asm_neg(ASMState *as, IRIns *ir) -{ -#if !LJ_SOFTFP - if (irt_isnum(ir->t)) { - asm_fpunary(as, ir, MIPSI_NEG_D); - } else -#elif LJ_64 /* && LJ_SOFTFP */ - if (irt_isnum(ir->t)) { - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); - emit_dst(as, MIPSI_XOR, dest, left, - ra_allock(as, 0x8000000000000000ll, rset_exclude(RSET_GPR, dest))); - } else -#endif - { - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); - emit_dst(as, (LJ_64 && irt_is64(ir->t)) ? MIPSI_DSUBU : MIPSI_SUBU, dest, - RID_ZERO, left); - } -} - -#if !LJ_SOFTFP -#define asm_abs(as, ir) asm_fpunary(as, ir, MIPSI_ABS_D) -#elif LJ_64 /* && LJ_SOFTFP */ -static void asm_abs(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_alloc1(as, ir->op1, RSET_GPR); - emit_tsml(as, MIPSI_DEXTM, dest, left, 30, 0); -} -#endif - -#define asm_atan2(as, ir) asm_callid(as, ir, IRCALL_atan2) -#define asm_ldexp(as, ir) asm_callid(as, ir, IRCALL_ldexp) - -static void asm_arithov(ASMState *as, IRIns *ir) -{ - Reg right, left, tmp, dest = ra_dest(as, ir, RSET_GPR); - lua_assert(!irt_is64(ir->t)); - if (irref_isk(ir->op2)) { - int k = IR(ir->op2)->i; - if (ir->o == IR_SUBOV) k = -k; - if (checki16(k)) { /* (dest < left) == (k >= 0 ? 1 : 0) */ - left = ra_alloc1(as, ir->op1, RSET_GPR); - asm_guard(as, k >= 0 ? MIPSI_BNE : MIPSI_BEQ, RID_TMP, RID_ZERO); - emit_dst(as, MIPSI_SLT, RID_TMP, dest, dest == left ? RID_TMP : left); - emit_tsi(as, MIPSI_ADDIU, dest, left, k); - if (dest == left) emit_move(as, RID_TMP, left); - return; - } - } - left = ra_alloc2(as, ir, RSET_GPR); - right = (left >> 8); left &= 255; - tmp = ra_scratch(as, rset_exclude(rset_exclude(rset_exclude(RSET_GPR, left), - right), dest)); - asm_guard(as, MIPSI_BLTZ, RID_TMP, 0); - emit_dst(as, MIPSI_AND, RID_TMP, RID_TMP, tmp); - if (ir->o == IR_ADDOV) { /* ((dest^left) & (dest^right)) < 0 */ - emit_dst(as, MIPSI_XOR, RID_TMP, dest, dest == right ? RID_TMP : right); - } else { /* ((dest^left) & (dest^~right)) < 0 */ - emit_dst(as, MIPSI_XOR, RID_TMP, RID_TMP, dest); - emit_dst(as, MIPSI_NOR, RID_TMP, dest == right ? RID_TMP : right, RID_ZERO); - } - emit_dst(as, MIPSI_XOR, tmp, dest, dest == left ? RID_TMP : left); - emit_dst(as, ir->o == IR_ADDOV ? MIPSI_ADDU : MIPSI_SUBU, dest, left, right); - if (dest == left || dest == right) - emit_move(as, RID_TMP, dest == left ? left : right); -} - -#define asm_addov(as, ir) asm_arithov(as, ir) -#define asm_subov(as, ir) asm_arithov(as, ir) - -static void asm_mulov(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg tmp, right, left = ra_alloc2(as, ir, RSET_GPR); - right = (left >> 8); left &= 255; - tmp = ra_scratch(as, rset_exclude(rset_exclude(rset_exclude(RSET_GPR, left), - right), dest)); - asm_guard(as, MIPSI_BNE, RID_TMP, tmp); - emit_dta(as, MIPSI_SRA, RID_TMP, dest, 31); - emit_dst(as, MIPSI_MFHI, tmp, 0, 0); - emit_dst(as, MIPSI_MFLO, dest, 0, 0); - emit_dst(as, MIPSI_MULT, 0, left, right); -} - -#if LJ_32 && LJ_HASFFI -static void asm_add64(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg right, left = ra_alloc1(as, ir->op1, RSET_GPR); - if (irref_isk(ir->op2)) { - int32_t k = IR(ir->op2)->i; - if (k == 0) { - emit_dst(as, MIPSI_ADDU, dest, left, RID_TMP); - goto loarith; - } else if (checki16(k)) { - emit_dst(as, MIPSI_ADDU, dest, dest, RID_TMP); - emit_tsi(as, MIPSI_ADDIU, dest, left, k); - goto loarith; - } - } - emit_dst(as, MIPSI_ADDU, dest, dest, RID_TMP); - right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left)); - emit_dst(as, MIPSI_ADDU, dest, left, right); -loarith: - ir--; - dest = ra_dest(as, ir, RSET_GPR); - left = ra_alloc1(as, ir->op1, RSET_GPR); - if (irref_isk(ir->op2)) { - int32_t k = IR(ir->op2)->i; - if (k == 0) { - if (dest != left) - emit_move(as, dest, left); - return; - } else if (checki16(k)) { - if (dest == left) { - Reg tmp = ra_scratch(as, rset_exclude(RSET_GPR, left)); - emit_move(as, dest, tmp); - dest = tmp; - } - emit_dst(as, MIPSI_SLTU, RID_TMP, dest, left); - emit_tsi(as, MIPSI_ADDIU, dest, left, k); - return; - } - } - right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left)); - if (dest == left && dest == right) { - Reg tmp = ra_scratch(as, rset_exclude(rset_exclude(RSET_GPR, left), right)); - emit_move(as, dest, tmp); - dest = tmp; - } - emit_dst(as, MIPSI_SLTU, RID_TMP, dest, dest == left ? right : left); - emit_dst(as, MIPSI_ADDU, dest, left, right); -} - -static void asm_sub64(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg right, left = ra_alloc2(as, ir, RSET_GPR); - right = (left >> 8); left &= 255; - emit_dst(as, MIPSI_SUBU, dest, dest, RID_TMP); - emit_dst(as, MIPSI_SUBU, dest, left, right); - ir--; - dest = ra_dest(as, ir, RSET_GPR); - left = ra_alloc2(as, ir, RSET_GPR); - right = (left >> 8); left &= 255; - if (dest == left) { - Reg tmp = ra_scratch(as, rset_exclude(rset_exclude(RSET_GPR, left), right)); - emit_move(as, dest, tmp); - dest = tmp; - } - emit_dst(as, MIPSI_SLTU, RID_TMP, left, dest); - emit_dst(as, MIPSI_SUBU, dest, left, right); -} - -static void asm_neg64(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_alloc1(as, ir->op1, RSET_GPR); - emit_dst(as, MIPSI_SUBU, dest, dest, RID_TMP); - emit_dst(as, MIPSI_SUBU, dest, RID_ZERO, left); - ir--; - dest = ra_dest(as, ir, RSET_GPR); - left = ra_alloc1(as, ir->op1, RSET_GPR); - emit_dst(as, MIPSI_SLTU, RID_TMP, RID_ZERO, dest); - emit_dst(as, MIPSI_SUBU, dest, RID_ZERO, left); -} -#endif - -static void asm_bnot(ASMState *as, IRIns *ir) -{ - Reg left, right, dest = ra_dest(as, ir, RSET_GPR); - IRIns *irl = IR(ir->op1); - if (mayfuse(as, ir->op1) && irl->o == IR_BOR) { - left = ra_alloc2(as, irl, RSET_GPR); - right = (left >> 8); left &= 255; - } else { - left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); - right = RID_ZERO; - } - emit_dst(as, MIPSI_NOR, dest, left, right); -} - -static void asm_bswap(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_alloc1(as, ir->op1, RSET_GPR); -#if LJ_32 - if ((as->flags & JIT_F_MIPSXXR2)) { - emit_dta(as, MIPSI_ROTR, dest, RID_TMP, 16); - emit_dst(as, MIPSI_WSBH, RID_TMP, 0, left); - } else { - Reg tmp = ra_scratch(as, rset_exclude(rset_exclude(RSET_GPR, left), dest)); - emit_dst(as, MIPSI_OR, dest, dest, tmp); - emit_dst(as, MIPSI_OR, dest, dest, RID_TMP); - emit_tsi(as, MIPSI_ANDI, dest, dest, 0xff00); - emit_dta(as, MIPSI_SLL, RID_TMP, RID_TMP, 8); - emit_dta(as, MIPSI_SRL, dest, left, 8); - emit_tsi(as, MIPSI_ANDI, RID_TMP, left, 0xff00); - emit_dst(as, MIPSI_OR, tmp, tmp, RID_TMP); - emit_dta(as, MIPSI_SRL, tmp, left, 24); - emit_dta(as, MIPSI_SLL, RID_TMP, left, 24); - } -#else - if (irt_is64(ir->t)) { - emit_dst(as, MIPSI_DSHD, dest, 0, RID_TMP); - emit_dst(as, MIPSI_DSBH, RID_TMP, 0, left); - } else { - emit_dta(as, MIPSI_ROTR, dest, RID_TMP, 16); - emit_dst(as, MIPSI_WSBH, RID_TMP, 0, left); - } -#endif -} - -static void asm_bitop(ASMState *as, IRIns *ir, MIPSIns mi, MIPSIns mik) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg right, left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); - if (irref_isk(ir->op2)) { - intptr_t k = get_kval(IR(ir->op2)); - if (checku16(k)) { - emit_tsi(as, mik, dest, left, k); - return; - } - } - right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left)); - emit_dst(as, mi, dest, left, right); -} - -#define asm_band(as, ir) asm_bitop(as, ir, MIPSI_AND, MIPSI_ANDI) -#define asm_bor(as, ir) asm_bitop(as, ir, MIPSI_OR, MIPSI_ORI) -#define asm_bxor(as, ir) asm_bitop(as, ir, MIPSI_XOR, MIPSI_XORI) - -static void asm_bitshift(ASMState *as, IRIns *ir, MIPSIns mi, MIPSIns mik) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - if (irref_isk(ir->op2)) { /* Constant shifts. */ - uint32_t shift = (uint32_t)IR(ir->op2)->i; - if (LJ_64 && irt_is64(ir->t)) mik |= (shift & 32) ? MIPSI_D32 : MIPSI_D; - emit_dta(as, mik, dest, ra_hintalloc(as, ir->op1, dest, RSET_GPR), - (shift & 31)); - } else { - Reg right, left = ra_alloc2(as, ir, RSET_GPR); - right = (left >> 8); left &= 255; - if (LJ_64 && irt_is64(ir->t)) mi |= MIPSI_DV; - emit_dst(as, mi, dest, right, left); /* Shift amount is in rs. */ - } -} - -#define asm_bshl(as, ir) asm_bitshift(as, ir, MIPSI_SLLV, MIPSI_SLL) -#define asm_bshr(as, ir) asm_bitshift(as, ir, MIPSI_SRLV, MIPSI_SRL) -#define asm_bsar(as, ir) asm_bitshift(as, ir, MIPSI_SRAV, MIPSI_SRA) -#define asm_brol(as, ir) lua_assert(0) - -static void asm_bror(ASMState *as, IRIns *ir) -{ - if (LJ_64 || (as->flags & JIT_F_MIPSXXR2)) { - asm_bitshift(as, ir, MIPSI_ROTRV, MIPSI_ROTR); - } else { - Reg dest = ra_dest(as, ir, RSET_GPR); - if (irref_isk(ir->op2)) { /* Constant shifts. */ - uint32_t shift = (uint32_t)(IR(ir->op2)->i & 31); - Reg left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); - emit_rotr(as, dest, left, RID_TMP, shift); - } else { - Reg right, left = ra_alloc2(as, ir, RSET_GPR); - right = (left >> 8); left &= 255; - emit_dst(as, MIPSI_OR, dest, dest, RID_TMP); - emit_dst(as, MIPSI_SRLV, dest, right, left); - emit_dst(as, MIPSI_SLLV, RID_TMP, RID_TMP, left); - emit_dst(as, MIPSI_SUBU, RID_TMP, ra_allock(as, 32, RSET_GPR), right); - } - } -} - -#if LJ_SOFTFP -static void asm_sfpmin_max(ASMState *as, IRIns *ir) -{ - CCallInfo ci = lj_ir_callinfo[(IROp)ir->o == IR_MIN ? IRCALL_lj_vm_sfmin : IRCALL_lj_vm_sfmax]; -#if LJ_64 - IRRef args[2]; - args[0] = ir->op1; - args[1] = ir->op2; -#else - IRRef args[4]; - args[0^LJ_BE] = ir->op1; - args[1^LJ_BE] = (ir+1)->op1; - args[2^LJ_BE] = ir->op2; - args[3^LJ_BE] = (ir+1)->op2; -#endif - asm_setupresult(as, ir, &ci); - emit_call(as, (void *)ci.func, 0); - ci.func = NULL; - asm_gencall(as, &ci, args); -} -#endif - -static void asm_min_max(ASMState *as, IRIns *ir, int ismax) -{ - if (!LJ_SOFTFP32 && irt_isnum(ir->t)) { -#if LJ_SOFTFP - asm_sfpmin_max(as, ir); -#else - Reg dest = ra_dest(as, ir, RSET_FPR); - Reg right, left = ra_alloc2(as, ir, RSET_FPR); - right = (left >> 8); left &= 255; - if (dest == left) { - emit_fg(as, MIPSI_MOVT_D, dest, right); - } else { - emit_fg(as, MIPSI_MOVF_D, dest, left); - if (dest != right) emit_fg(as, MIPSI_MOV_D, dest, right); - } - emit_fgh(as, MIPSI_C_OLT_D, 0, ismax ? left : right, ismax ? right : left); -#endif - } else { - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg right, left = ra_alloc2(as, ir, RSET_GPR); - right = (left >> 8); left &= 255; - if (dest == left) { - emit_dst(as, MIPSI_MOVN, dest, right, RID_TMP); - } else { - emit_dst(as, MIPSI_MOVZ, dest, left, RID_TMP); - if (dest != right) emit_move(as, dest, right); - } - emit_dst(as, MIPSI_SLT, RID_TMP, - ismax ? left : right, ismax ? right : left); - } -} - -#define asm_min(as, ir) asm_min_max(as, ir, 0) -#define asm_max(as, ir) asm_min_max(as, ir, 1) - -/* -- Comparisons --------------------------------------------------------- */ - -#if LJ_SOFTFP -/* SFP comparisons. */ -static void asm_sfpcomp(ASMState *as, IRIns *ir) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_softfp_cmp]; - RegSet drop = RSET_SCRATCH; - Reg r; -#if LJ_64 - IRRef args[2]; - args[0] = ir->op1; - args[1] = ir->op2; -#else - IRRef args[4]; - args[LJ_LE ? 0 : 1] = ir->op1; args[LJ_LE ? 1 : 0] = (ir+1)->op1; - args[LJ_LE ? 2 : 3] = ir->op2; args[LJ_LE ? 3 : 2] = (ir+1)->op2; -#endif - - for (r = REGARG_FIRSTGPR; r <= REGARG_FIRSTGPR+(LJ_64?1:3); r++) { - if (!rset_test(as->freeset, r) && - regcost_ref(as->cost[r]) == args[r-REGARG_FIRSTGPR]) - rset_clear(drop, r); - } - ra_evictset(as, drop); - - asm_setupresult(as, ir, ci); - - switch ((IROp)ir->o) { - case IR_LT: - asm_guard(as, MIPSI_BGEZ, RID_RET, 0); - break; - case IR_ULT: - asm_guard(as, MIPSI_BEQ, RID_RET, RID_TMP); - emit_loadi(as, RID_TMP, 1); - asm_guard(as, MIPSI_BEQ, RID_RET, RID_ZERO); - break; - case IR_GE: - asm_guard(as, MIPSI_BEQ, RID_RET, RID_TMP); - emit_loadi(as, RID_TMP, 2); - asm_guard(as, MIPSI_BLTZ, RID_RET, 0); - break; - case IR_LE: - asm_guard(as, MIPSI_BGTZ, RID_RET, 0); - break; - case IR_GT: - asm_guard(as, MIPSI_BEQ, RID_RET, RID_TMP); - emit_loadi(as, RID_TMP, 2); - asm_guard(as, MIPSI_BLEZ, RID_RET, 0); - break; - case IR_UGE: - asm_guard(as, MIPSI_BLTZ, RID_RET, 0); - break; - case IR_ULE: - asm_guard(as, MIPSI_BEQ, RID_RET, RID_TMP); - emit_loadi(as, RID_TMP, 1); - break; - case IR_UGT: case IR_ABC: - asm_guard(as, MIPSI_BLEZ, RID_RET, 0); - break; - case IR_EQ: case IR_NE: - asm_guard(as, (ir->o & 1) ? MIPSI_BEQ : MIPSI_BNE, RID_RET, RID_ZERO); - default: - break; - } - asm_gencall(as, ci, args); -} -#endif - -static void asm_comp(ASMState *as, IRIns *ir) -{ - /* ORDER IR: LT GE LE GT ULT UGE ULE UGT. */ - IROp op = ir->o; - if (!LJ_SOFTFP32 && irt_isnum(ir->t)) { -#if LJ_SOFTFP - asm_sfpcomp(as, ir); -#else - Reg right, left = ra_alloc2(as, ir, RSET_FPR); - right = (left >> 8); left &= 255; - asm_guard(as, (op&1) ? MIPSI_BC1T : MIPSI_BC1F, 0, 0); - emit_fgh(as, MIPSI_C_OLT_D + ((op&3) ^ ((op>>2)&1)), 0, left, right); -#endif - } else { - Reg right, left = ra_alloc1(as, ir->op1, RSET_GPR); - if (op == IR_ABC) op = IR_UGT; - if ((op&4) == 0 && irref_isk(ir->op2) && get_kval(IR(ir->op2)) == 0) { - MIPSIns mi = (op&2) ? ((op&1) ? MIPSI_BLEZ : MIPSI_BGTZ) : - ((op&1) ? MIPSI_BLTZ : MIPSI_BGEZ); - asm_guard(as, mi, left, 0); - } else { - if (irref_isk(ir->op2)) { - intptr_t k = get_kval(IR(ir->op2)); - if ((op&2)) k++; - if (checki16(k)) { - asm_guard(as, (op&1) ? MIPSI_BNE : MIPSI_BEQ, RID_TMP, RID_ZERO); - emit_tsi(as, (op&4) ? MIPSI_SLTIU : MIPSI_SLTI, - RID_TMP, left, k); - return; - } - } - right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left)); - asm_guard(as, ((op^(op>>1))&1) ? MIPSI_BNE : MIPSI_BEQ, RID_TMP, RID_ZERO); - emit_dst(as, (op&4) ? MIPSI_SLTU : MIPSI_SLT, - RID_TMP, (op&2) ? right : left, (op&2) ? left : right); - } - } -} - -static void asm_equal(ASMState *as, IRIns *ir) -{ - Reg right, left = ra_alloc2(as, ir, (!LJ_SOFTFP && irt_isnum(ir->t)) ? - RSET_FPR : RSET_GPR); - right = (left >> 8); left &= 255; - if (!LJ_SOFTFP32 && irt_isnum(ir->t)) { -#if LJ_SOFTFP - asm_sfpcomp(as, ir); -#else - asm_guard(as, (ir->o & 1) ? MIPSI_BC1T : MIPSI_BC1F, 0, 0); - emit_fgh(as, MIPSI_C_EQ_D, 0, left, right); -#endif - } else { - asm_guard(as, (ir->o & 1) ? MIPSI_BEQ : MIPSI_BNE, left, right); - } -} - -#if LJ_32 && LJ_HASFFI -/* 64 bit integer comparisons. */ -static void asm_comp64(ASMState *as, IRIns *ir) -{ - /* ORDER IR: LT GE LE GT ULT UGE ULE UGT. */ - IROp op = (ir-1)->o; - MCLabel l_end; - Reg rightlo, leftlo, righthi, lefthi = ra_alloc2(as, ir, RSET_GPR); - righthi = (lefthi >> 8); lefthi &= 255; - leftlo = ra_alloc2(as, ir-1, - rset_exclude(rset_exclude(RSET_GPR, lefthi), righthi)); - rightlo = (leftlo >> 8); leftlo &= 255; - asm_guard(as, ((op^(op>>1))&1) ? MIPSI_BNE : MIPSI_BEQ, RID_TMP, RID_ZERO); - l_end = emit_label(as); - if (lefthi != righthi) - emit_dst(as, (op&4) ? MIPSI_SLTU : MIPSI_SLT, RID_TMP, - (op&2) ? righthi : lefthi, (op&2) ? lefthi : righthi); - emit_dst(as, MIPSI_SLTU, RID_TMP, - (op&2) ? rightlo : leftlo, (op&2) ? leftlo : rightlo); - if (lefthi != righthi) - emit_branch(as, MIPSI_BEQ, lefthi, righthi, l_end); -} - -static void asm_comp64eq(ASMState *as, IRIns *ir) -{ - Reg tmp, right, left = ra_alloc2(as, ir, RSET_GPR); - right = (left >> 8); left &= 255; - asm_guard(as, ((ir-1)->o & 1) ? MIPSI_BEQ : MIPSI_BNE, RID_TMP, RID_ZERO); - tmp = ra_scratch(as, rset_exclude(rset_exclude(RSET_GPR, left), right)); - emit_dst(as, MIPSI_OR, RID_TMP, RID_TMP, tmp); - emit_dst(as, MIPSI_XOR, tmp, left, right); - left = ra_alloc2(as, ir-1, RSET_GPR); - right = (left >> 8); left &= 255; - emit_dst(as, MIPSI_XOR, RID_TMP, left, right); -} -#endif - -/* -- Support for 64 bit ops in 32 bit mode ------------------------------- */ - -/* Hiword op of a split 64 bit op. Previous op must be the loword op. */ -static void asm_hiop(ASMState *as, IRIns *ir) -{ -#if LJ_32 && (LJ_HASFFI || LJ_SOFTFP) - /* HIOP is marked as a store because it needs its own DCE logic. */ - int uselo = ra_used(ir-1), usehi = ra_used(ir); /* Loword/hiword used? */ - if (LJ_UNLIKELY(!(as->flags & JIT_F_OPT_DCE))) uselo = usehi = 1; - if ((ir-1)->o == IR_CONV) { /* Conversions to/from 64 bit. */ - as->curins--; /* Always skip the CONV. */ -#if LJ_HASFFI && !LJ_SOFTFP - if (usehi || uselo) - asm_conv64(as, ir); - return; -#endif - } else if ((ir-1)->o < IR_EQ) { /* 64 bit integer comparisons. ORDER IR. */ - as->curins--; /* Always skip the loword comparison. */ -#if LJ_SOFTFP - if (!irt_isint(ir->t)) { - asm_sfpcomp(as, ir-1); - return; - } -#endif -#if LJ_HASFFI - asm_comp64(as, ir); -#endif - return; - } else if ((ir-1)->o <= IR_NE) { /* 64 bit integer comparisons. ORDER IR. */ - as->curins--; /* Always skip the loword comparison. */ -#if LJ_SOFTFP - if (!irt_isint(ir->t)) { - asm_sfpcomp(as, ir-1); - return; - } -#endif -#if LJ_HASFFI - asm_comp64eq(as, ir); -#endif - return; -#if LJ_SOFTFP - } else if ((ir-1)->o == IR_MIN || (ir-1)->o == IR_MAX) { - as->curins--; /* Always skip the loword min/max. */ - if (uselo || usehi) - asm_sfpmin_max(as, ir-1); - return; -#endif - } else if ((ir-1)->o == IR_XSTORE) { - as->curins--; /* Handle both stores here. */ - if ((ir-1)->r != RID_SINK) { - asm_xstore_(as, ir, LJ_LE ? 4 : 0); - asm_xstore_(as, ir-1, LJ_LE ? 0 : 4); - } - return; - } - if (!usehi) return; /* Skip unused hiword op for all remaining ops. */ - switch ((ir-1)->o) { -#if LJ_HASFFI - case IR_ADD: as->curins--; asm_add64(as, ir); break; - case IR_SUB: as->curins--; asm_sub64(as, ir); break; - case IR_NEG: as->curins--; asm_neg64(as, ir); break; -#endif -#if LJ_SOFTFP - case IR_SLOAD: case IR_ALOAD: case IR_HLOAD: case IR_ULOAD: case IR_VLOAD: - case IR_STRTO: - if (!uselo) - ra_allocref(as, ir->op1, RSET_GPR); /* Mark lo op as used. */ - break; -#endif - case IR_CALLN: - case IR_CALLS: - case IR_CALLXS: - if (!uselo) - ra_allocref(as, ir->op1, RID2RSET(RID_RETLO)); /* Mark lo op as used. */ - break; -#if LJ_SOFTFP - case IR_ASTORE: case IR_HSTORE: case IR_USTORE: case IR_TOSTR: -#endif - case IR_CNEWI: - /* Nothing to do here. Handled by lo op itself. */ - break; - default: lua_assert(0); break; - } -#else - UNUSED(as); UNUSED(ir); lua_assert(0); /* Unused without FFI. */ -#endif -} - -/* -- Profiling ----------------------------------------------------------- */ - -static void asm_prof(ASMState *as, IRIns *ir) -{ - UNUSED(ir); - asm_guard(as, MIPSI_BNE, RID_TMP, RID_ZERO); - emit_tsi(as, MIPSI_ANDI, RID_TMP, RID_TMP, HOOK_PROFILE); - emit_lsglptr(as, MIPSI_LBU, RID_TMP, - (int32_t)offsetof(global_State, hookmask)); -} - -/* -- Stack handling ------------------------------------------------------ */ - -/* Check Lua stack size for overflow. Use exit handler as fallback. */ -static void asm_stack_check(ASMState *as, BCReg topslot, - IRIns *irp, RegSet allow, ExitNo exitno) -{ - /* Try to get an unused temp. register, otherwise spill/restore RID_RET*. */ - Reg tmp, pbase = irp ? (ra_hasreg(irp->r) ? irp->r : RID_TMP) : RID_BASE; - ExitNo oldsnap = as->snapno; - rset_clear(allow, pbase); -#if LJ_32 - tmp = allow ? rset_pickbot(allow) : - (pbase == RID_RETHI ? RID_RETLO : RID_RETHI); -#else - tmp = allow ? rset_pickbot(allow) : RID_RET; -#endif - as->snapno = exitno; - asm_guard(as, MIPSI_BNE, RID_TMP, RID_ZERO); - as->snapno = oldsnap; - if (allow == RSET_EMPTY) /* Restore temp. register. */ - emit_tsi(as, MIPSI_AL, tmp, RID_SP, 0); - else - ra_modified(as, tmp); - emit_tsi(as, MIPSI_SLTIU, RID_TMP, RID_TMP, (int32_t)(8*topslot)); - emit_dst(as, MIPSI_ASUBU, RID_TMP, tmp, pbase); - emit_tsi(as, MIPSI_AL, tmp, tmp, offsetof(lua_State, maxstack)); - if (pbase == RID_TMP) - emit_getgl(as, RID_TMP, jit_base); - emit_getgl(as, tmp, cur_L); - if (allow == RSET_EMPTY) /* Spill temp. register. */ - emit_tsi(as, MIPSI_AS, tmp, RID_SP, 0); -} - -/* Restore Lua stack from on-trace state. */ -static void asm_stack_restore(ASMState *as, SnapShot *snap) -{ - SnapEntry *map = &as->T->snapmap[snap->mapofs]; -#if LJ_32 || defined(LUA_USE_ASSERT) - SnapEntry *flinks = &as->T->snapmap[snap_nextofs(as->T, snap)-1-LJ_FR2]; -#endif - MSize n, nent = snap->nent; - /* Store the value of all modified slots to the Lua stack. */ - for (n = 0; n < nent; n++) { - SnapEntry sn = map[n]; - BCReg s = snap_slot(sn); - int32_t ofs = 8*((int32_t)s-1-LJ_FR2); - IRRef ref = snap_ref(sn); - IRIns *ir = IR(ref); - if ((sn & SNAP_NORESTORE)) - continue; - if (irt_isnum(ir->t)) { -#if LJ_SOFTFP32 - Reg tmp; - RegSet allow = rset_exclude(RSET_GPR, RID_BASE); - lua_assert(irref_isk(ref)); /* LJ_SOFTFP: must be a number constant. */ - tmp = ra_allock(as, (int32_t)ir_knum(ir)->u32.lo, allow); - emit_tsi(as, MIPSI_SW, tmp, RID_BASE, ofs+(LJ_BE?4:0)); - if (rset_test(as->freeset, tmp+1)) allow = RID2RSET(tmp+1); - tmp = ra_allock(as, (int32_t)ir_knum(ir)->u32.hi, allow); - emit_tsi(as, MIPSI_SW, tmp, RID_BASE, ofs+(LJ_BE?0:4)); -#elif LJ_SOFTFP /* && LJ_64 */ - Reg src = ra_alloc1(as, ref, rset_exclude(RSET_GPR, RID_BASE)); - emit_tsi(as, MIPSI_SD, src, RID_BASE, ofs); -#else - Reg src = ra_alloc1(as, ref, RSET_FPR); - emit_hsi(as, MIPSI_SDC1, src, RID_BASE, ofs); -#endif - } else { -#if LJ_32 - RegSet allow = rset_exclude(RSET_GPR, RID_BASE); - Reg type; - lua_assert(irt_ispri(ir->t) || irt_isaddr(ir->t) || irt_isinteger(ir->t)); - if (!irt_ispri(ir->t)) { - Reg src = ra_alloc1(as, ref, allow); - rset_clear(allow, src); - emit_tsi(as, MIPSI_SW, src, RID_BASE, ofs+(LJ_BE?4:0)); - } - if ((sn & (SNAP_CONT|SNAP_FRAME))) { - if (s == 0) continue; /* Do not overwrite link to previous frame. */ - type = ra_allock(as, (int32_t)(*flinks--), allow); -#if LJ_SOFTFP - } else if ((sn & SNAP_SOFTFPNUM)) { - type = ra_alloc1(as, ref+1, rset_exclude(RSET_GPR, RID_BASE)); -#endif - } else { - type = ra_allock(as, (int32_t)irt_toitype(ir->t), allow); - } - emit_tsi(as, MIPSI_SW, type, RID_BASE, ofs+(LJ_BE?0:4)); -#else - asm_tvstore64(as, RID_BASE, ofs, ref); -#endif - } - checkmclim(as); - } - lua_assert(map + nent == flinks); -} - -/* -- GC handling --------------------------------------------------------- */ - -/* Check GC threshold and do one or more GC steps. */ -static void asm_gc_check(ASMState *as) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_gc_step_jit]; - IRRef args[2]; - MCLabel l_end; - Reg tmp; - ra_evictset(as, RSET_SCRATCH); - l_end = emit_label(as); - /* Exit trace if in GCSatomic or GCSfinalize. Avoids syncing GC objects. */ - /* Assumes asm_snap_prep() already done. */ - asm_guard(as, MIPSI_BNE, RID_RET, RID_ZERO); - args[0] = ASMREF_TMP1; /* global_State *g */ - args[1] = ASMREF_TMP2; /* MSize steps */ - asm_gencall(as, ci, args); - emit_tsi(as, MIPSI_AADDIU, ra_releasetmp(as, ASMREF_TMP1), RID_JGL, -32768); - tmp = ra_releasetmp(as, ASMREF_TMP2); - emit_loadi(as, tmp, as->gcsteps); - /* Jump around GC step if GC total < GC threshold. */ - emit_branch(as, MIPSI_BNE, RID_TMP, RID_ZERO, l_end); - emit_dst(as, MIPSI_SLTU, RID_TMP, RID_TMP, tmp); - emit_getgl(as, tmp, gc.threshold); - emit_getgl(as, RID_TMP, gc.total); - as->gcsteps = 0; - checkmclim(as); -} - -/* -- Loop handling ------------------------------------------------------- */ - -/* Fixup the loop branch. */ -static void asm_loop_fixup(ASMState *as) -{ - MCode *p = as->mctop; - MCode *target = as->mcp; - p[-1] = MIPSI_NOP; - if (as->loopinv) { /* Inverted loop branch? */ - /* asm_guard already inverted the cond branch. Only patch the target. */ - p[-3] |= ((target-p+2) & 0x0000ffffu); - } else { - p[-2] = MIPSI_J|(((uintptr_t)target>>2)&0x03ffffffu); - } -} - -/* -- Head of trace ------------------------------------------------------- */ - -/* Coalesce BASE register for a root trace. */ -static void asm_head_root_base(ASMState *as) -{ - IRIns *ir = IR(REF_BASE); - Reg r = ir->r; - if (as->loopinv) as->mctop--; - if (ra_hasreg(r)) { - ra_free(as, r); - if (rset_test(as->modset, r) || irt_ismarked(ir->t)) - ir->r = RID_INIT; /* No inheritance for modified BASE register. */ - if (r != RID_BASE) - emit_move(as, r, RID_BASE); - } -} - -/* Coalesce BASE register for a side trace. */ -static RegSet asm_head_side_base(ASMState *as, IRIns *irp, RegSet allow) -{ - IRIns *ir = IR(REF_BASE); - Reg r = ir->r; - if (as->loopinv) as->mctop--; - if (ra_hasreg(r)) { - ra_free(as, r); - if (rset_test(as->modset, r) || irt_ismarked(ir->t)) - ir->r = RID_INIT; /* No inheritance for modified BASE register. */ - if (irp->r == r) { - rset_clear(allow, r); /* Mark same BASE register as coalesced. */ - } else if (ra_hasreg(irp->r) && rset_test(as->freeset, irp->r)) { - rset_clear(allow, irp->r); - emit_move(as, r, irp->r); /* Move from coalesced parent reg. */ - } else { - emit_getgl(as, r, jit_base); /* Otherwise reload BASE. */ - } - } - return allow; -} - -/* -- Tail of trace ------------------------------------------------------- */ - -/* Fixup the tail code. */ -static void asm_tail_fixup(ASMState *as, TraceNo lnk) -{ - MCode *target = lnk ? traceref(as->J,lnk)->mcode : (MCode *)lj_vm_exit_interp; - int32_t spadj = as->T->spadjust; - MCode *p = as->mctop-1; - *p = spadj ? (MIPSI_AADDIU|MIPSF_T(RID_SP)|MIPSF_S(RID_SP)|spadj) : MIPSI_NOP; - p[-1] = MIPSI_J|(((uintptr_t)target>>2)&0x03ffffffu); -} - -/* Prepare tail of code. */ -static void asm_tail_prep(ASMState *as) -{ - as->mcp = as->mctop-2; /* Leave room for branch plus nop or stack adj. */ - as->invmcp = as->loopref ? as->mcp : NULL; -} - -/* -- Trace setup --------------------------------------------------------- */ - -/* Ensure there are enough stack slots for call arguments. */ -static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci) -{ - IRRef args[CCI_NARGS_MAX*2]; - uint32_t i, nargs = CCI_XNARGS(ci); -#if LJ_32 - int nslots = 4, ngpr = REGARG_NUMGPR, nfpr = REGARG_NUMFPR; -#else - int nslots = 0, ngpr = REGARG_NUMGPR; -#endif - asm_collectargs(as, ir, ci, args); - for (i = 0; i < nargs; i++) { -#if LJ_32 - if (!LJ_SOFTFP && args[i] && irt_isfp(IR(args[i])->t) && - nfpr > 0 && !(ci->flags & CCI_VARARG)) { - nfpr--; - ngpr -= irt_isnum(IR(args[i])->t) ? 2 : 1; - } else if (!LJ_SOFTFP && args[i] && irt_isnum(IR(args[i])->t)) { - nfpr = 0; - ngpr = ngpr & ~1; - if (ngpr > 0) ngpr -= 2; else nslots = (nslots+3) & ~1; - } else { - nfpr = 0; - if (ngpr > 0) ngpr--; else nslots++; - } -#else - if (ngpr > 0) ngpr--; else nslots += 2; -#endif - } - if (nslots > as->evenspill) /* Leave room for args in stack slots. */ - as->evenspill = nslots; - return irt_isfp(ir->t) ? REGSP_HINT(RID_FPRET) : REGSP_HINT(RID_RET); -} - -static void asm_setup_target(ASMState *as) -{ - asm_sparejump_setup(as); - asm_exitstub_setup(as); -} - -/* -- Trace patching ------------------------------------------------------ */ - -/* Patch exit jumps of existing machine code to a new target. */ -void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, MCode *target) -{ - MCode *p = T->mcode; - MCode *pe = (MCode *)((char *)p + T->szmcode); - MCode *px = exitstub_trace_addr(T, exitno); - MCode *cstart = NULL, *cstop = NULL; - MCode *mcarea = lj_mcode_patch(J, p, 0); - MCode exitload = MIPSI_LI | MIPSF_T(RID_TMP) | exitno; - MCode tjump = MIPSI_J|(((uintptr_t)target>>2)&0x03ffffffu); - for (p++; p < pe; p++) { - if (*p == exitload) { /* Look for load of exit number. */ - /* Look for exitstub branch. Yes, this covers all used branch variants. */ - if (((p[-1] ^ (px-p)) & 0xffffu) == 0 && - ((p[-1] & 0xf0000000u) == MIPSI_BEQ || - (p[-1] & 0xfc1e0000u) == MIPSI_BLTZ || - (p[-1] & 0xffe00000u) == MIPSI_BC1F)) { - ptrdiff_t delta = target - p; - if (((delta + 0x8000) >> 16) == 0) { /* Patch in-range branch. */ - patchbranch: - p[-1] = (p[-1] & 0xffff0000u) | (delta & 0xffffu); - *p = MIPSI_NOP; /* Replace the load of the exit number. */ - cstop = p; - if (!cstart) cstart = p-1; - } else { /* Branch out of range. Use spare jump slot in mcarea. */ - int i; - for (i = (int)(sizeof(MCLink)/sizeof(MCode)); - i < (int)(sizeof(MCLink)/sizeof(MCode)+MIPS_SPAREJUMP*2); - i += 2) { - if (mcarea[i] == tjump) { - delta = mcarea+i - p; - goto patchbranch; - } else if (mcarea[i] == MIPSI_NOP) { - mcarea[i] = tjump; - cstart = mcarea+i; - delta = mcarea+i - p; - goto patchbranch; - } - } - /* Ignore jump slot overflow. Child trace is simply not attached. */ - } - } else if (p+1 == pe) { - /* Patch NOP after code for inverted loop branch. Use of J is ok. */ - lua_assert(p[1] == MIPSI_NOP); - p[1] = tjump; - *p = MIPSI_NOP; /* Replace the load of the exit number. */ - cstop = p+2; - if (!cstart) cstart = p+1; - } - } - } - if (cstart) lj_mcode_sync(cstart, cstop); - lj_mcode_patch(J, mcarea, 1); -} - diff --git a/lib/LuaJIT/src/lj_asm_ppc.h b/lib/LuaJIT/src/lj_asm_ppc.h deleted file mode 100644 index 1955429..0000000 --- a/lib/LuaJIT/src/lj_asm_ppc.h +++ /dev/null @@ -1,2251 +0,0 @@ -/* -** PPC IR assembler (SSA IR -> machine code). -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -/* -- Register allocator extensions --------------------------------------- */ - -/* Allocate a register with a hint. */ -static Reg ra_hintalloc(ASMState *as, IRRef ref, Reg hint, RegSet allow) -{ - Reg r = IR(ref)->r; - if (ra_noreg(r)) { - if (!ra_hashint(r) && !iscrossref(as, ref)) - ra_sethint(IR(ref)->r, hint); /* Propagate register hint. */ - r = ra_allocref(as, ref, allow); - } - ra_noweak(as, r); - return r; -} - -/* Allocate two source registers for three-operand instructions. */ -static Reg ra_alloc2(ASMState *as, IRIns *ir, RegSet allow) -{ - IRIns *irl = IR(ir->op1), *irr = IR(ir->op2); - Reg left = irl->r, right = irr->r; - if (ra_hasreg(left)) { - ra_noweak(as, left); - if (ra_noreg(right)) - right = ra_allocref(as, ir->op2, rset_exclude(allow, left)); - else - ra_noweak(as, right); - } else if (ra_hasreg(right)) { - ra_noweak(as, right); - left = ra_allocref(as, ir->op1, rset_exclude(allow, right)); - } else if (ra_hashint(right)) { - right = ra_allocref(as, ir->op2, allow); - left = ra_alloc1(as, ir->op1, rset_exclude(allow, right)); - } else { - left = ra_allocref(as, ir->op1, allow); - right = ra_alloc1(as, ir->op2, rset_exclude(allow, left)); - } - return left | (right << 8); -} - -/* -- Guard handling ------------------------------------------------------ */ - -/* Setup exit stubs after the end of each trace. */ -static void asm_exitstub_setup(ASMState *as, ExitNo nexits) -{ - ExitNo i; - MCode *mxp = as->mctop; - if (mxp - (nexits + 3 + MCLIM_REDZONE) < as->mclim) - asm_mclimit(as); - /* 1: mflr r0; bl ->vm_exit_handler; li r0, traceno; bl <1; bl <1; ... */ - for (i = nexits-1; (int32_t)i >= 0; i--) - *--mxp = PPCI_BL|(((-3-i)&0x00ffffffu)<<2); - *--mxp = PPCI_LI|PPCF_T(RID_TMP)|as->T->traceno; /* Read by exit handler. */ - mxp--; - *mxp = PPCI_BL|((((MCode *)(void *)lj_vm_exit_handler-mxp)&0x00ffffffu)<<2); - *--mxp = PPCI_MFLR|PPCF_T(RID_TMP); - as->mctop = mxp; -} - -static MCode *asm_exitstub_addr(ASMState *as, ExitNo exitno) -{ - /* Keep this in-sync with exitstub_trace_addr(). */ - return as->mctop + exitno + 3; -} - -/* Emit conditional branch to exit for guard. */ -static void asm_guardcc(ASMState *as, PPCCC cc) -{ - MCode *target = asm_exitstub_addr(as, as->snapno); - MCode *p = as->mcp; - if (LJ_UNLIKELY(p == as->invmcp)) { - as->loopinv = 1; - *p = PPCI_B | (((target-p) & 0x00ffffffu) << 2); - emit_condbranch(as, PPCI_BC, cc^4, p); - return; - } - emit_condbranch(as, PPCI_BC, cc, target); -} - -/* -- Operand fusion ------------------------------------------------------ */ - -/* Limit linear search to this distance. Avoids O(n^2) behavior. */ -#define CONFLICT_SEARCH_LIM 31 - -/* Check if there's no conflicting instruction between curins and ref. */ -static int noconflict(ASMState *as, IRRef ref, IROp conflict) -{ - IRIns *ir = as->ir; - IRRef i = as->curins; - if (i > ref + CONFLICT_SEARCH_LIM) - return 0; /* Give up, ref is too far away. */ - while (--i > ref) - if (ir[i].o == conflict) - return 0; /* Conflict found. */ - return 1; /* Ok, no conflict. */ -} - -/* Fuse the array base of colocated arrays. */ -static int32_t asm_fuseabase(ASMState *as, IRRef ref) -{ - IRIns *ir = IR(ref); - if (ir->o == IR_TNEW && ir->op1 <= LJ_MAX_COLOSIZE && - !neverfuse(as) && noconflict(as, ref, IR_NEWREF)) - return (int32_t)sizeof(GCtab); - return 0; -} - -/* Indicates load/store indexed is ok. */ -#define AHUREF_LSX ((int32_t)0x80000000) - -/* Fuse array/hash/upvalue reference into register+offset operand. */ -static Reg asm_fuseahuref(ASMState *as, IRRef ref, int32_t *ofsp, RegSet allow) -{ - IRIns *ir = IR(ref); - if (ra_noreg(ir->r)) { - if (ir->o == IR_AREF) { - if (mayfuse(as, ref)) { - if (irref_isk(ir->op2)) { - IRRef tab = IR(ir->op1)->op1; - int32_t ofs = asm_fuseabase(as, tab); - IRRef refa = ofs ? tab : ir->op1; - ofs += 8*IR(ir->op2)->i; - if (checki16(ofs)) { - *ofsp = ofs; - return ra_alloc1(as, refa, allow); - } - } - if (*ofsp == AHUREF_LSX) { - Reg base = ra_alloc1(as, ir->op1, allow); - Reg idx = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, base)); - return base | (idx << 8); - } - } - } else if (ir->o == IR_HREFK) { - if (mayfuse(as, ref)) { - int32_t ofs = (int32_t)(IR(ir->op2)->op2 * sizeof(Node)); - if (checki16(ofs)) { - *ofsp = ofs; - return ra_alloc1(as, ir->op1, allow); - } - } - } else if (ir->o == IR_UREFC) { - if (irref_isk(ir->op1)) { - GCfunc *fn = ir_kfunc(IR(ir->op1)); - int32_t ofs = i32ptr(&gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.tv); - int32_t jgl = (intptr_t)J2G(as->J); - if ((uint32_t)(ofs-jgl) < 65536) { - *ofsp = ofs-jgl-32768; - return RID_JGL; - } else { - *ofsp = (int16_t)ofs; - return ra_allock(as, ofs-(int16_t)ofs, allow); - } - } - } - } - *ofsp = 0; - return ra_alloc1(as, ref, allow); -} - -/* Fuse XLOAD/XSTORE reference into load/store operand. */ -static void asm_fusexref(ASMState *as, PPCIns pi, Reg rt, IRRef ref, - RegSet allow, int32_t ofs) -{ - IRIns *ir = IR(ref); - Reg base; - if (ra_noreg(ir->r) && canfuse(as, ir)) { - if (ir->o == IR_ADD) { - int32_t ofs2; - if (irref_isk(ir->op2) && (ofs2 = ofs + IR(ir->op2)->i, checki16(ofs2))) { - ofs = ofs2; - ref = ir->op1; - } else if (ofs == 0) { - Reg right, left = ra_alloc2(as, ir, allow); - right = (left >> 8); left &= 255; - emit_fab(as, PPCI_LWZX | ((pi >> 20) & 0x780), rt, left, right); - return; - } - } else if (ir->o == IR_STRREF) { - lua_assert(ofs == 0); - ofs = (int32_t)sizeof(GCstr); - if (irref_isk(ir->op2)) { - ofs += IR(ir->op2)->i; - ref = ir->op1; - } else if (irref_isk(ir->op1)) { - ofs += IR(ir->op1)->i; - ref = ir->op2; - } else { - /* NYI: Fuse ADD with constant. */ - Reg tmp, right, left = ra_alloc2(as, ir, allow); - right = (left >> 8); left &= 255; - tmp = ra_scratch(as, rset_exclude(rset_exclude(allow, left), right)); - emit_fai(as, pi, rt, tmp, ofs); - emit_tab(as, PPCI_ADD, tmp, left, right); - return; - } - if (!checki16(ofs)) { - Reg left = ra_alloc1(as, ref, allow); - Reg right = ra_allock(as, ofs, rset_exclude(allow, left)); - emit_fab(as, PPCI_LWZX | ((pi >> 20) & 0x780), rt, left, right); - return; - } - } - } - base = ra_alloc1(as, ref, allow); - emit_fai(as, pi, rt, base, ofs); -} - -/* Fuse XLOAD/XSTORE reference into indexed-only load/store operand. */ -static void asm_fusexrefx(ASMState *as, PPCIns pi, Reg rt, IRRef ref, - RegSet allow) -{ - IRIns *ira = IR(ref); - Reg right, left; - if (canfuse(as, ira) && ira->o == IR_ADD && ra_noreg(ira->r)) { - left = ra_alloc2(as, ira, allow); - right = (left >> 8); left &= 255; - } else { - right = ra_alloc1(as, ref, allow); - left = RID_R0; - } - emit_tab(as, pi, rt, left, right); -} - -#if !LJ_SOFTFP -/* Fuse to multiply-add/sub instruction. */ -static int asm_fusemadd(ASMState *as, IRIns *ir, PPCIns pi, PPCIns pir) -{ - IRRef lref = ir->op1, rref = ir->op2; - IRIns *irm; - if (lref != rref && - ((mayfuse(as, lref) && (irm = IR(lref), irm->o == IR_MUL) && - ra_noreg(irm->r)) || - (mayfuse(as, rref) && (irm = IR(rref), irm->o == IR_MUL) && - (rref = lref, pi = pir, ra_noreg(irm->r))))) { - Reg dest = ra_dest(as, ir, RSET_FPR); - Reg add = ra_alloc1(as, rref, RSET_FPR); - Reg right, left = ra_alloc2(as, irm, rset_exclude(RSET_FPR, add)); - right = (left >> 8); left &= 255; - emit_facb(as, pi, dest, left, right, add); - return 1; - } - return 0; -} -#endif - -/* -- Calls --------------------------------------------------------------- */ - -/* Generate a call to a C function. */ -static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) -{ - uint32_t n, nargs = CCI_XNARGS(ci); - int32_t ofs = 8; - Reg gpr = REGARG_FIRSTGPR; -#if !LJ_SOFTFP - Reg fpr = REGARG_FIRSTFPR; -#endif - if ((void *)ci->func) - emit_call(as, (void *)ci->func); - for (n = 0; n < nargs; n++) { /* Setup args. */ - IRRef ref = args[n]; - if (ref) { - IRIns *ir = IR(ref); -#if !LJ_SOFTFP - if (irt_isfp(ir->t)) { - if (fpr <= REGARG_LASTFPR) { - lua_assert(rset_test(as->freeset, fpr)); /* Already evicted. */ - ra_leftov(as, fpr, ref); - fpr++; - } else { - Reg r = ra_alloc1(as, ref, RSET_FPR); - if (irt_isnum(ir->t)) ofs = (ofs + 4) & ~4; - emit_spstore(as, ir, r, ofs); - ofs += irt_isnum(ir->t) ? 8 : 4; - } - } else -#endif - { - if (gpr <= REGARG_LASTGPR) { - lua_assert(rset_test(as->freeset, gpr)); /* Already evicted. */ - ra_leftov(as, gpr, ref); - gpr++; - } else { - Reg r = ra_alloc1(as, ref, RSET_GPR); - emit_spstore(as, ir, r, ofs); - ofs += 4; - } - } - } else { - if (gpr <= REGARG_LASTGPR) - gpr++; - else - ofs += 4; - } - checkmclim(as); - } -#if !LJ_SOFTFP - if ((ci->flags & CCI_VARARG)) /* Vararg calls need to know about FPR use. */ - emit_tab(as, fpr == REGARG_FIRSTFPR ? PPCI_CRXOR : PPCI_CREQV, 6, 6, 6); -#endif -} - -/* Setup result reg/sp for call. Evict scratch regs. */ -static void asm_setupresult(ASMState *as, IRIns *ir, const CCallInfo *ci) -{ - RegSet drop = RSET_SCRATCH; - int hiop = ((ir+1)->o == IR_HIOP && !irt_isnil((ir+1)->t)); -#if !LJ_SOFTFP - if ((ci->flags & CCI_NOFPRCLOBBER)) - drop &= ~RSET_FPR; -#endif - if (ra_hasreg(ir->r)) - rset_clear(drop, ir->r); /* Dest reg handled below. */ - if (hiop && ra_hasreg((ir+1)->r)) - rset_clear(drop, (ir+1)->r); /* Dest reg handled below. */ - ra_evictset(as, drop); /* Evictions must be performed first. */ - if (ra_used(ir)) { - lua_assert(!irt_ispri(ir->t)); - if (!LJ_SOFTFP && irt_isfp(ir->t)) { - if ((ci->flags & CCI_CASTU64)) { - /* Use spill slot or temp slots. */ - int32_t ofs = ir->s ? sps_scale(ir->s) : SPOFS_TMP; - Reg dest = ir->r; - if (ra_hasreg(dest)) { - ra_free(as, dest); - ra_modified(as, dest); - emit_fai(as, PPCI_LFD, dest, RID_SP, ofs); - } - emit_tai(as, PPCI_STW, RID_RETHI, RID_SP, ofs); - emit_tai(as, PPCI_STW, RID_RETLO, RID_SP, ofs+4); - } else { - ra_destreg(as, ir, RID_FPRET); - } -#if LJ_32 - } else if (hiop) { - ra_destpair(as, ir); -#endif - } else { - ra_destreg(as, ir, RID_RET); - } - } -} - -static void asm_callx(ASMState *as, IRIns *ir) -{ - IRRef args[CCI_NARGS_MAX*2]; - CCallInfo ci; - IRRef func; - IRIns *irf; - ci.flags = asm_callx_flags(as, ir); - asm_collectargs(as, ir, &ci, args); - asm_setupresult(as, ir, &ci); - func = ir->op2; irf = IR(func); - if (irf->o == IR_CARG) { func = irf->op1; irf = IR(func); } - if (irref_isk(func)) { /* Call to constant address. */ - ci.func = (ASMFunction)(void *)(intptr_t)(irf->i); - } else { /* Need a non-argument register for indirect calls. */ - RegSet allow = RSET_GPR & ~RSET_RANGE(RID_R0, REGARG_LASTGPR+1); - Reg freg = ra_alloc1(as, func, allow); - *--as->mcp = PPCI_BCTRL; - *--as->mcp = PPCI_MTCTR | PPCF_T(freg); - ci.func = (ASMFunction)(void *)0; - } - asm_gencall(as, &ci, args); -} - -/* -- Returns ------------------------------------------------------------- */ - -/* Return to lower frame. Guard that it goes to the right spot. */ -static void asm_retf(ASMState *as, IRIns *ir) -{ - Reg base = ra_alloc1(as, REF_BASE, RSET_GPR); - void *pc = ir_kptr(IR(ir->op2)); - int32_t delta = 1+LJ_FR2+bc_a(*((const BCIns *)pc - 1)); - as->topslot -= (BCReg)delta; - if ((int32_t)as->topslot < 0) as->topslot = 0; - irt_setmark(IR(REF_BASE)->t); /* Children must not coalesce with BASE reg. */ - emit_setgl(as, base, jit_base); - emit_addptr(as, base, -8*delta); - asm_guardcc(as, CC_NE); - emit_ab(as, PPCI_CMPW, RID_TMP, - ra_allock(as, i32ptr(pc), rset_exclude(RSET_GPR, base))); - emit_tai(as, PPCI_LWZ, RID_TMP, base, -8); -} - -/* -- Type conversions ---------------------------------------------------- */ - -#if !LJ_SOFTFP -static void asm_tointg(ASMState *as, IRIns *ir, Reg left) -{ - RegSet allow = RSET_FPR; - Reg tmp = ra_scratch(as, rset_clear(allow, left)); - Reg fbias = ra_scratch(as, rset_clear(allow, tmp)); - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg hibias = ra_allock(as, 0x43300000, rset_exclude(RSET_GPR, dest)); - asm_guardcc(as, CC_NE); - emit_fab(as, PPCI_FCMPU, 0, tmp, left); - emit_fab(as, PPCI_FSUB, tmp, tmp, fbias); - emit_fai(as, PPCI_LFD, tmp, RID_SP, SPOFS_TMP); - emit_tai(as, PPCI_STW, RID_TMP, RID_SP, SPOFS_TMPLO); - emit_tai(as, PPCI_STW, hibias, RID_SP, SPOFS_TMPHI); - emit_asi(as, PPCI_XORIS, RID_TMP, dest, 0x8000); - emit_tai(as, PPCI_LWZ, dest, RID_SP, SPOFS_TMPLO); - emit_lsptr(as, PPCI_LFS, (fbias & 31), - (void *)&as->J->k32[LJ_K32_2P52_2P31], RSET_GPR); - emit_fai(as, PPCI_STFD, tmp, RID_SP, SPOFS_TMP); - emit_fb(as, PPCI_FCTIWZ, tmp, left); -} - -static void asm_tobit(ASMState *as, IRIns *ir) -{ - RegSet allow = RSET_FPR; - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_alloc1(as, ir->op1, allow); - Reg right = ra_alloc1(as, ir->op2, rset_clear(allow, left)); - Reg tmp = ra_scratch(as, rset_clear(allow, right)); - emit_tai(as, PPCI_LWZ, dest, RID_SP, SPOFS_TMPLO); - emit_fai(as, PPCI_STFD, tmp, RID_SP, SPOFS_TMP); - emit_fab(as, PPCI_FADD, tmp, left, right); -} -#endif - -static void asm_conv(ASMState *as, IRIns *ir) -{ - IRType st = (IRType)(ir->op2 & IRCONV_SRCMASK); -#if !LJ_SOFTFP - int stfp = (st == IRT_NUM || st == IRT_FLOAT); -#endif - IRRef lref = ir->op1; - lua_assert(!(irt_isint64(ir->t) || - (st == IRT_I64 || st == IRT_U64))); /* Handled by SPLIT. */ -#if LJ_SOFTFP - /* FP conversions are handled by SPLIT. */ - lua_assert(!irt_isfp(ir->t) && !(st == IRT_NUM || st == IRT_FLOAT)); - /* Can't check for same types: SPLIT uses CONV int.int + BXOR for sfp NEG. */ -#else - lua_assert(irt_type(ir->t) != st); - if (irt_isfp(ir->t)) { - Reg dest = ra_dest(as, ir, RSET_FPR); - if (stfp) { /* FP to FP conversion. */ - if (st == IRT_NUM) /* double -> float conversion. */ - emit_fb(as, PPCI_FRSP, dest, ra_alloc1(as, lref, RSET_FPR)); - else /* float -> double conversion is a no-op on PPC. */ - ra_leftov(as, dest, lref); /* Do nothing, but may need to move regs. */ - } else { /* Integer to FP conversion. */ - /* IRT_INT: Flip hibit, bias with 2^52, subtract 2^52+2^31. */ - /* IRT_U32: Bias with 2^52, subtract 2^52. */ - RegSet allow = RSET_GPR; - Reg left = ra_alloc1(as, lref, allow); - Reg hibias = ra_allock(as, 0x43300000, rset_clear(allow, left)); - Reg fbias = ra_scratch(as, rset_exclude(RSET_FPR, dest)); - if (irt_isfloat(ir->t)) emit_fb(as, PPCI_FRSP, dest, dest); - emit_fab(as, PPCI_FSUB, dest, dest, fbias); - emit_fai(as, PPCI_LFD, dest, RID_SP, SPOFS_TMP); - emit_lsptr(as, PPCI_LFS, (fbias & 31), - &as->J->k32[st == IRT_U32 ? LJ_K32_2P52 : LJ_K32_2P52_2P31], - rset_clear(allow, hibias)); - emit_tai(as, PPCI_STW, st == IRT_U32 ? left : RID_TMP, - RID_SP, SPOFS_TMPLO); - emit_tai(as, PPCI_STW, hibias, RID_SP, SPOFS_TMPHI); - if (st != IRT_U32) emit_asi(as, PPCI_XORIS, RID_TMP, left, 0x8000); - } - } else if (stfp) { /* FP to integer conversion. */ - if (irt_isguard(ir->t)) { - /* Checked conversions are only supported from number to int. */ - lua_assert(irt_isint(ir->t) && st == IRT_NUM); - asm_tointg(as, ir, ra_alloc1(as, lref, RSET_FPR)); - } else { - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_alloc1(as, lref, RSET_FPR); - Reg tmp = ra_scratch(as, rset_exclude(RSET_FPR, left)); - if (irt_isu32(ir->t)) { - /* Convert both x and x-2^31 to int and merge results. */ - Reg tmpi = ra_scratch(as, rset_exclude(RSET_GPR, dest)); - emit_asb(as, PPCI_OR, dest, dest, tmpi); /* Select with mask idiom. */ - emit_asb(as, PPCI_AND, tmpi, tmpi, RID_TMP); - emit_asb(as, PPCI_ANDC, dest, dest, RID_TMP); - emit_tai(as, PPCI_LWZ, tmpi, RID_SP, SPOFS_TMPLO); /* tmp = (int)(x) */ - emit_tai(as, PPCI_ADDIS, dest, dest, 0x8000); /* dest += 2^31 */ - emit_asb(as, PPCI_SRAWI, RID_TMP, dest, 31); /* mask = -(dest < 0) */ - emit_fai(as, PPCI_STFD, tmp, RID_SP, SPOFS_TMP); - emit_tai(as, PPCI_LWZ, dest, - RID_SP, SPOFS_TMPLO); /* dest = (int)(x-2^31) */ - emit_fb(as, PPCI_FCTIWZ, tmp, left); - emit_fai(as, PPCI_STFD, tmp, RID_SP, SPOFS_TMP); - emit_fb(as, PPCI_FCTIWZ, tmp, tmp); - emit_fab(as, PPCI_FSUB, tmp, left, tmp); - emit_lsptr(as, PPCI_LFS, (tmp & 31), - (void *)&as->J->k32[LJ_K32_2P31], RSET_GPR); - } else { - emit_tai(as, PPCI_LWZ, dest, RID_SP, SPOFS_TMPLO); - emit_fai(as, PPCI_STFD, tmp, RID_SP, SPOFS_TMP); - emit_fb(as, PPCI_FCTIWZ, tmp, left); - } - } - } else -#endif - { - Reg dest = ra_dest(as, ir, RSET_GPR); - if (st >= IRT_I8 && st <= IRT_U16) { /* Extend to 32 bit integer. */ - Reg left = ra_alloc1(as, ir->op1, RSET_GPR); - lua_assert(irt_isint(ir->t) || irt_isu32(ir->t)); - if ((ir->op2 & IRCONV_SEXT)) - emit_as(as, st == IRT_I8 ? PPCI_EXTSB : PPCI_EXTSH, dest, left); - else - emit_rot(as, PPCI_RLWINM, dest, left, 0, st == IRT_U8 ? 24 : 16, 31); - } else { /* 32/64 bit integer conversions. */ - /* Only need to handle 32/32 bit no-op (cast) on 32 bit archs. */ - ra_leftov(as, dest, lref); /* Do nothing, but may need to move regs. */ - } - } -} - -static void asm_strto(ASMState *as, IRIns *ir) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_strscan_num]; - IRRef args[2]; - int32_t ofs = SPOFS_TMP; -#if LJ_SOFTFP - ra_evictset(as, RSET_SCRATCH); - if (ra_used(ir)) { - if (ra_hasspill(ir->s) && ra_hasspill((ir+1)->s) && - (ir->s & 1) == LJ_BE && (ir->s ^ 1) == (ir+1)->s) { - int i; - for (i = 0; i < 2; i++) { - Reg r = (ir+i)->r; - if (ra_hasreg(r)) { - ra_free(as, r); - ra_modified(as, r); - emit_spload(as, ir+i, r, sps_scale((ir+i)->s)); - } - } - ofs = sps_scale(ir->s & ~1); - } else { - Reg rhi = ra_dest(as, ir+1, RSET_GPR); - Reg rlo = ra_dest(as, ir, rset_exclude(RSET_GPR, rhi)); - emit_tai(as, PPCI_LWZ, rhi, RID_SP, ofs); - emit_tai(as, PPCI_LWZ, rlo, RID_SP, ofs+4); - } - } -#else - RegSet drop = RSET_SCRATCH; - if (ra_hasreg(ir->r)) rset_set(drop, ir->r); /* Spill dest reg (if any). */ - ra_evictset(as, drop); - if (ir->s) ofs = sps_scale(ir->s); -#endif - asm_guardcc(as, CC_EQ); - emit_ai(as, PPCI_CMPWI, RID_RET, 0); /* Test return status. */ - args[0] = ir->op1; /* GCstr *str */ - args[1] = ASMREF_TMP1; /* TValue *n */ - asm_gencall(as, ci, args); - /* Store the result to the spill slot or temp slots. */ - emit_tai(as, PPCI_ADDI, ra_releasetmp(as, ASMREF_TMP1), RID_SP, ofs); -} - -/* -- Memory references --------------------------------------------------- */ - -/* Get pointer to TValue. */ -static void asm_tvptr(ASMState *as, Reg dest, IRRef ref) -{ - IRIns *ir = IR(ref); - if (irt_isnum(ir->t)) { - if (irref_isk(ref)) /* Use the number constant itself as a TValue. */ - ra_allockreg(as, i32ptr(ir_knum(ir)), dest); - else /* Otherwise force a spill and use the spill slot. */ - emit_tai(as, PPCI_ADDI, dest, RID_SP, ra_spill(as, ir)); - } else { - /* Otherwise use g->tmptv to hold the TValue. */ - RegSet allow = rset_exclude(RSET_GPR, dest); - Reg type; - emit_tai(as, PPCI_ADDI, dest, RID_JGL, (int32_t)offsetof(global_State, tmptv)-32768); - if (!irt_ispri(ir->t)) { - Reg src = ra_alloc1(as, ref, allow); - emit_setgl(as, src, tmptv.gcr); - } - if (LJ_SOFTFP && (ir+1)->o == IR_HIOP) - type = ra_alloc1(as, ref+1, allow); - else - type = ra_allock(as, irt_toitype(ir->t), allow); - emit_setgl(as, type, tmptv.it); - } -} - -static void asm_aref(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg idx, base; - if (irref_isk(ir->op2)) { - IRRef tab = IR(ir->op1)->op1; - int32_t ofs = asm_fuseabase(as, tab); - IRRef refa = ofs ? tab : ir->op1; - ofs += 8*IR(ir->op2)->i; - if (checki16(ofs)) { - base = ra_alloc1(as, refa, RSET_GPR); - emit_tai(as, PPCI_ADDI, dest, base, ofs); - return; - } - } - base = ra_alloc1(as, ir->op1, RSET_GPR); - idx = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, base)); - emit_tab(as, PPCI_ADD, dest, RID_TMP, base); - emit_slwi(as, RID_TMP, idx, 3); -} - -/* Inlined hash lookup. Specialized for key type and for const keys. -** The equivalent C code is: -** Node *n = hashkey(t, key); -** do { -** if (lj_obj_equal(&n->key, key)) return &n->val; -** } while ((n = nextnode(n))); -** return niltv(L); -*/ -static void asm_href(ASMState *as, IRIns *ir, IROp merge) -{ - RegSet allow = RSET_GPR; - int destused = ra_used(ir); - Reg dest = ra_dest(as, ir, allow); - Reg tab = ra_alloc1(as, ir->op1, rset_clear(allow, dest)); - Reg key = RID_NONE, tmp1 = RID_TMP, tmp2; - Reg tisnum = RID_NONE, tmpnum = RID_NONE; - IRRef refkey = ir->op2; - IRIns *irkey = IR(refkey); - int isk = irref_isk(refkey); - IRType1 kt = irkey->t; - uint32_t khash; - MCLabel l_end, l_loop, l_next; - - rset_clear(allow, tab); -#if LJ_SOFTFP - if (!isk) { - key = ra_alloc1(as, refkey, allow); - rset_clear(allow, key); - if (irkey[1].o == IR_HIOP) { - if (ra_hasreg((irkey+1)->r)) { - tmpnum = (irkey+1)->r; - ra_noweak(as, tmpnum); - } else { - tmpnum = ra_allocref(as, refkey+1, allow); - } - rset_clear(allow, tmpnum); - } - } -#else - if (irt_isnum(kt)) { - key = ra_alloc1(as, refkey, RSET_FPR); - tmpnum = ra_scratch(as, rset_exclude(RSET_FPR, key)); - tisnum = ra_allock(as, (int32_t)LJ_TISNUM, allow); - rset_clear(allow, tisnum); - } else if (!irt_ispri(kt)) { - key = ra_alloc1(as, refkey, allow); - rset_clear(allow, key); - } -#endif - tmp2 = ra_scratch(as, allow); - rset_clear(allow, tmp2); - - /* Key not found in chain: jump to exit (if merged) or load niltv. */ - l_end = emit_label(as); - as->invmcp = NULL; - if (merge == IR_NE) - asm_guardcc(as, CC_EQ); - else if (destused) - emit_loada(as, dest, niltvg(J2G(as->J))); - - /* Follow hash chain until the end. */ - l_loop = --as->mcp; - emit_ai(as, PPCI_CMPWI, dest, 0); - emit_tai(as, PPCI_LWZ, dest, dest, (int32_t)offsetof(Node, next)); - l_next = emit_label(as); - - /* Type and value comparison. */ - if (merge == IR_EQ) - asm_guardcc(as, CC_EQ); - else - emit_condbranch(as, PPCI_BC|PPCF_Y, CC_EQ, l_end); - if (!LJ_SOFTFP && irt_isnum(kt)) { - emit_fab(as, PPCI_FCMPU, 0, tmpnum, key); - emit_condbranch(as, PPCI_BC, CC_GE, l_next); - emit_ab(as, PPCI_CMPLW, tmp1, tisnum); - emit_fai(as, PPCI_LFD, tmpnum, dest, (int32_t)offsetof(Node, key.n)); - } else { - if (!irt_ispri(kt)) { - emit_ab(as, PPCI_CMPW, tmp2, key); - emit_condbranch(as, PPCI_BC, CC_NE, l_next); - } - if (LJ_SOFTFP && ra_hasreg(tmpnum)) - emit_ab(as, PPCI_CMPW, tmp1, tmpnum); - else - emit_ai(as, PPCI_CMPWI, tmp1, irt_toitype(irkey->t)); - if (!irt_ispri(kt)) - emit_tai(as, PPCI_LWZ, tmp2, dest, (int32_t)offsetof(Node, key.gcr)); - } - emit_tai(as, PPCI_LWZ, tmp1, dest, (int32_t)offsetof(Node, key.it)); - *l_loop = PPCI_BC | PPCF_Y | PPCF_CC(CC_NE) | - (((char *)as->mcp-(char *)l_loop) & 0xffffu); - - /* Load main position relative to tab->node into dest. */ - khash = isk ? ir_khash(irkey) : 1; - if (khash == 0) { - emit_tai(as, PPCI_LWZ, dest, tab, (int32_t)offsetof(GCtab, node)); - } else { - Reg tmphash = tmp1; - if (isk) - tmphash = ra_allock(as, khash, allow); - emit_tab(as, PPCI_ADD, dest, dest, tmp1); - emit_tai(as, PPCI_MULLI, tmp1, tmp1, sizeof(Node)); - emit_asb(as, PPCI_AND, tmp1, tmp2, tmphash); - emit_tai(as, PPCI_LWZ, dest, tab, (int32_t)offsetof(GCtab, node)); - emit_tai(as, PPCI_LWZ, tmp2, tab, (int32_t)offsetof(GCtab, hmask)); - if (isk) { - /* Nothing to do. */ - } else if (irt_isstr(kt)) { - emit_tai(as, PPCI_LWZ, tmp1, key, (int32_t)offsetof(GCstr, hash)); - } else { /* Must match with hash*() in lj_tab.c. */ - emit_tab(as, PPCI_SUBF, tmp1, tmp2, tmp1); - emit_rotlwi(as, tmp2, tmp2, HASH_ROT3); - emit_asb(as, PPCI_XOR, tmp1, tmp1, tmp2); - emit_rotlwi(as, tmp1, tmp1, (HASH_ROT2+HASH_ROT1)&31); - emit_tab(as, PPCI_SUBF, tmp2, dest, tmp2); - if (LJ_SOFTFP ? (irkey[1].o == IR_HIOP) : irt_isnum(kt)) { -#if LJ_SOFTFP - emit_asb(as, PPCI_XOR, tmp2, key, tmp1); - emit_rotlwi(as, dest, tmp1, HASH_ROT1); - emit_tab(as, PPCI_ADD, tmp1, tmpnum, tmpnum); -#else - int32_t ofs = ra_spill(as, irkey); - emit_asb(as, PPCI_XOR, tmp2, tmp2, tmp1); - emit_rotlwi(as, dest, tmp1, HASH_ROT1); - emit_tab(as, PPCI_ADD, tmp1, tmp1, tmp1); - emit_tai(as, PPCI_LWZ, tmp2, RID_SP, ofs+4); - emit_tai(as, PPCI_LWZ, tmp1, RID_SP, ofs); -#endif - } else { - emit_asb(as, PPCI_XOR, tmp2, key, tmp1); - emit_rotlwi(as, dest, tmp1, HASH_ROT1); - emit_tai(as, PPCI_ADDI, tmp1, tmp2, HASH_BIAS); - emit_tai(as, PPCI_ADDIS, tmp2, key, (HASH_BIAS + 32768)>>16); - } - } - } -} - -static void asm_hrefk(ASMState *as, IRIns *ir) -{ - IRIns *kslot = IR(ir->op2); - IRIns *irkey = IR(kslot->op1); - int32_t ofs = (int32_t)(kslot->op2 * sizeof(Node)); - int32_t kofs = ofs + (int32_t)offsetof(Node, key); - Reg dest = (ra_used(ir)||ofs > 32736) ? ra_dest(as, ir, RSET_GPR) : RID_NONE; - Reg node = ra_alloc1(as, ir->op1, RSET_GPR); - Reg key = RID_NONE, type = RID_TMP, idx = node; - RegSet allow = rset_exclude(RSET_GPR, node); - lua_assert(ofs % sizeof(Node) == 0); - if (ofs > 32736) { - idx = dest; - rset_clear(allow, dest); - kofs = (int32_t)offsetof(Node, key); - } else if (ra_hasreg(dest)) { - emit_tai(as, PPCI_ADDI, dest, node, ofs); - } - asm_guardcc(as, CC_NE); - if (!irt_ispri(irkey->t)) { - key = ra_scratch(as, allow); - rset_clear(allow, key); - } - rset_clear(allow, type); - if (irt_isnum(irkey->t)) { - emit_cmpi(as, key, (int32_t)ir_knum(irkey)->u32.lo); - asm_guardcc(as, CC_NE); - emit_cmpi(as, type, (int32_t)ir_knum(irkey)->u32.hi); - } else { - if (ra_hasreg(key)) { - emit_cmpi(as, key, irkey->i); /* May use RID_TMP, i.e. type. */ - asm_guardcc(as, CC_NE); - } - emit_ai(as, PPCI_CMPWI, type, irt_toitype(irkey->t)); - } - if (ra_hasreg(key)) emit_tai(as, PPCI_LWZ, key, idx, kofs+4); - emit_tai(as, PPCI_LWZ, type, idx, kofs); - if (ofs > 32736) { - emit_tai(as, PPCI_ADDIS, dest, dest, (ofs + 32768) >> 16); - emit_tai(as, PPCI_ADDI, dest, node, ofs); - } -} - -static void asm_uref(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - if (irref_isk(ir->op1)) { - GCfunc *fn = ir_kfunc(IR(ir->op1)); - MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v; - emit_lsptr(as, PPCI_LWZ, dest, v, RSET_GPR); - } else { - Reg uv = ra_scratch(as, RSET_GPR); - Reg func = ra_alloc1(as, ir->op1, RSET_GPR); - if (ir->o == IR_UREFC) { - asm_guardcc(as, CC_NE); - emit_ai(as, PPCI_CMPWI, RID_TMP, 1); - emit_tai(as, PPCI_ADDI, dest, uv, (int32_t)offsetof(GCupval, tv)); - emit_tai(as, PPCI_LBZ, RID_TMP, uv, (int32_t)offsetof(GCupval, closed)); - } else { - emit_tai(as, PPCI_LWZ, dest, uv, (int32_t)offsetof(GCupval, v)); - } - emit_tai(as, PPCI_LWZ, uv, func, - (int32_t)offsetof(GCfuncL, uvptr) + 4*(int32_t)(ir->op2 >> 8)); - } -} - -static void asm_fref(ASMState *as, IRIns *ir) -{ - UNUSED(as); UNUSED(ir); - lua_assert(!ra_used(ir)); -} - -static void asm_strref(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - IRRef ref = ir->op2, refk = ir->op1; - int32_t ofs = (int32_t)sizeof(GCstr); - Reg r; - if (irref_isk(ref)) { - IRRef tmp = refk; refk = ref; ref = tmp; - } else if (!irref_isk(refk)) { - Reg right, left = ra_alloc1(as, ir->op1, RSET_GPR); - IRIns *irr = IR(ir->op2); - if (ra_hasreg(irr->r)) { - ra_noweak(as, irr->r); - right = irr->r; - } else if (mayfuse(as, irr->op2) && - irr->o == IR_ADD && irref_isk(irr->op2) && - checki16(ofs + IR(irr->op2)->i)) { - ofs += IR(irr->op2)->i; - right = ra_alloc1(as, irr->op1, rset_exclude(RSET_GPR, left)); - } else { - right = ra_allocref(as, ir->op2, rset_exclude(RSET_GPR, left)); - } - emit_tai(as, PPCI_ADDI, dest, dest, ofs); - emit_tab(as, PPCI_ADD, dest, left, right); - return; - } - r = ra_alloc1(as, ref, RSET_GPR); - ofs += IR(refk)->i; - if (checki16(ofs)) - emit_tai(as, PPCI_ADDI, dest, r, ofs); - else - emit_tab(as, PPCI_ADD, dest, r, - ra_allock(as, ofs, rset_exclude(RSET_GPR, r))); -} - -/* -- Loads and stores ---------------------------------------------------- */ - -static PPCIns asm_fxloadins(IRIns *ir) -{ - switch (irt_type(ir->t)) { - case IRT_I8: return PPCI_LBZ; /* Needs sign-extension. */ - case IRT_U8: return PPCI_LBZ; - case IRT_I16: return PPCI_LHA; - case IRT_U16: return PPCI_LHZ; - case IRT_NUM: lua_assert(!LJ_SOFTFP); return PPCI_LFD; - case IRT_FLOAT: if (!LJ_SOFTFP) return PPCI_LFS; - default: return PPCI_LWZ; - } -} - -static PPCIns asm_fxstoreins(IRIns *ir) -{ - switch (irt_type(ir->t)) { - case IRT_I8: case IRT_U8: return PPCI_STB; - case IRT_I16: case IRT_U16: return PPCI_STH; - case IRT_NUM: lua_assert(!LJ_SOFTFP); return PPCI_STFD; - case IRT_FLOAT: if (!LJ_SOFTFP) return PPCI_STFS; - default: return PPCI_STW; - } -} - -static void asm_fload(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - PPCIns pi = asm_fxloadins(ir); - Reg idx; - int32_t ofs; - if (ir->op1 == REF_NIL) { - idx = RID_JGL; - ofs = (ir->op2 << 2) - 32768; - } else { - idx = ra_alloc1(as, ir->op1, RSET_GPR); - if (ir->op2 == IRFL_TAB_ARRAY) { - ofs = asm_fuseabase(as, ir->op1); - if (ofs) { /* Turn the t->array load into an add for colocated arrays. */ - emit_tai(as, PPCI_ADDI, dest, idx, ofs); - return; - } - } - ofs = field_ofs[ir->op2]; - } - lua_assert(!irt_isi8(ir->t)); - emit_tai(as, pi, dest, idx, ofs); -} - -static void asm_fstore(ASMState *as, IRIns *ir) -{ - if (ir->r != RID_SINK) { - Reg src = ra_alloc1(as, ir->op2, RSET_GPR); - IRIns *irf = IR(ir->op1); - Reg idx = ra_alloc1(as, irf->op1, rset_exclude(RSET_GPR, src)); - int32_t ofs = field_ofs[irf->op2]; - PPCIns pi = asm_fxstoreins(ir); - emit_tai(as, pi, src, idx, ofs); - } -} - -static void asm_xload(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, - (!LJ_SOFTFP && irt_isfp(ir->t)) ? RSET_FPR : RSET_GPR); - lua_assert(!(ir->op2 & IRXLOAD_UNALIGNED)); - if (irt_isi8(ir->t)) - emit_as(as, PPCI_EXTSB, dest, dest); - asm_fusexref(as, asm_fxloadins(ir), dest, ir->op1, RSET_GPR, 0); -} - -static void asm_xstore_(ASMState *as, IRIns *ir, int32_t ofs) -{ - IRIns *irb; - if (ir->r == RID_SINK) - return; - if (ofs == 0 && mayfuse(as, ir->op2) && (irb = IR(ir->op2))->o == IR_BSWAP && - ra_noreg(irb->r) && (irt_isint(ir->t) || irt_isu32(ir->t))) { - /* Fuse BSWAP with XSTORE to stwbrx. */ - Reg src = ra_alloc1(as, irb->op1, RSET_GPR); - asm_fusexrefx(as, PPCI_STWBRX, src, ir->op1, rset_exclude(RSET_GPR, src)); - } else { - Reg src = ra_alloc1(as, ir->op2, - (!LJ_SOFTFP && irt_isfp(ir->t)) ? RSET_FPR : RSET_GPR); - asm_fusexref(as, asm_fxstoreins(ir), src, ir->op1, - rset_exclude(RSET_GPR, src), ofs); - } -} - -#define asm_xstore(as, ir) asm_xstore_(as, ir, 0) - -static void asm_ahuvload(ASMState *as, IRIns *ir) -{ - IRType1 t = ir->t; - Reg dest = RID_NONE, type = RID_TMP, tmp = RID_TMP, idx; - RegSet allow = RSET_GPR; - int32_t ofs = AHUREF_LSX; - if (LJ_SOFTFP && (ir+1)->o == IR_HIOP) { - t.irt = IRT_NUM; - if (ra_used(ir+1)) { - type = ra_dest(as, ir+1, allow); - rset_clear(allow, type); - } - ofs = 0; - } - if (ra_used(ir)) { - lua_assert((LJ_SOFTFP ? 0 : irt_isnum(ir->t)) || - irt_isint(ir->t) || irt_isaddr(ir->t)); - if (LJ_SOFTFP || !irt_isnum(t)) ofs = 0; - dest = ra_dest(as, ir, (!LJ_SOFTFP && irt_isnum(t)) ? RSET_FPR : allow); - rset_clear(allow, dest); - } - idx = asm_fuseahuref(as, ir->op1, &ofs, allow); - if (irt_isnum(t)) { - Reg tisnum = ra_allock(as, (int32_t)LJ_TISNUM, rset_exclude(allow, idx)); - asm_guardcc(as, CC_GE); - emit_ab(as, PPCI_CMPLW, type, tisnum); - if (ra_hasreg(dest)) { - if (!LJ_SOFTFP && ofs == AHUREF_LSX) { - tmp = ra_scratch(as, rset_exclude(rset_exclude(RSET_GPR, - (idx&255)), (idx>>8))); - emit_fab(as, PPCI_LFDX, dest, (idx&255), tmp); - } else { - emit_fai(as, LJ_SOFTFP ? PPCI_LWZ : PPCI_LFD, dest, idx, - ofs+4*LJ_SOFTFP); - } - } - } else { - asm_guardcc(as, CC_NE); - emit_ai(as, PPCI_CMPWI, type, irt_toitype(t)); - if (ra_hasreg(dest)) emit_tai(as, PPCI_LWZ, dest, idx, ofs+4); - } - if (ofs == AHUREF_LSX) { - emit_tab(as, PPCI_LWZX, type, (idx&255), tmp); - emit_slwi(as, tmp, (idx>>8), 3); - } else { - emit_tai(as, PPCI_LWZ, type, idx, ofs); - } -} - -static void asm_ahustore(ASMState *as, IRIns *ir) -{ - RegSet allow = RSET_GPR; - Reg idx, src = RID_NONE, type = RID_NONE; - int32_t ofs = AHUREF_LSX; - if (ir->r == RID_SINK) - return; - if (!LJ_SOFTFP && irt_isnum(ir->t)) { - src = ra_alloc1(as, ir->op2, RSET_FPR); - } else { - if (!irt_ispri(ir->t)) { - src = ra_alloc1(as, ir->op2, allow); - rset_clear(allow, src); - ofs = 0; - } - if (LJ_SOFTFP && (ir+1)->o == IR_HIOP) - type = ra_alloc1(as, (ir+1)->op2, allow); - else - type = ra_allock(as, (int32_t)irt_toitype(ir->t), allow); - rset_clear(allow, type); - } - idx = asm_fuseahuref(as, ir->op1, &ofs, allow); - if (!LJ_SOFTFP && irt_isnum(ir->t)) { - if (ofs == AHUREF_LSX) { - emit_fab(as, PPCI_STFDX, src, (idx&255), RID_TMP); - emit_slwi(as, RID_TMP, (idx>>8), 3); - } else { - emit_fai(as, PPCI_STFD, src, idx, ofs); - } - } else { - if (ra_hasreg(src)) - emit_tai(as, PPCI_STW, src, idx, ofs+4); - if (ofs == AHUREF_LSX) { - emit_tab(as, PPCI_STWX, type, (idx&255), RID_TMP); - emit_slwi(as, RID_TMP, (idx>>8), 3); - } else { - emit_tai(as, PPCI_STW, type, idx, ofs); - } - } -} - -static void asm_sload(ASMState *as, IRIns *ir) -{ - int32_t ofs = 8*((int32_t)ir->op1-1) + ((ir->op2 & IRSLOAD_FRAME) ? 0 : 4); - IRType1 t = ir->t; - Reg dest = RID_NONE, type = RID_NONE, base; - RegSet allow = RSET_GPR; - int hiop = (LJ_SOFTFP && (ir+1)->o == IR_HIOP); - if (hiop) - t.irt = IRT_NUM; - lua_assert(!(ir->op2 & IRSLOAD_PARENT)); /* Handled by asm_head_side(). */ - lua_assert(irt_isguard(ir->t) || !(ir->op2 & IRSLOAD_TYPECHECK)); - lua_assert(LJ_DUALNUM || - !irt_isint(t) || (ir->op2 & (IRSLOAD_CONVERT|IRSLOAD_FRAME))); -#if LJ_SOFTFP - lua_assert(!(ir->op2 & IRSLOAD_CONVERT)); /* Handled by LJ_SOFTFP SPLIT. */ - if (hiop && ra_used(ir+1)) { - type = ra_dest(as, ir+1, allow); - rset_clear(allow, type); - } -#else - if ((ir->op2 & IRSLOAD_CONVERT) && irt_isguard(t) && irt_isint(t)) { - dest = ra_scratch(as, RSET_FPR); - asm_tointg(as, ir, dest); - t.irt = IRT_NUM; /* Continue with a regular number type check. */ - } else -#endif - if (ra_used(ir)) { - lua_assert(irt_isnum(t) || irt_isint(t) || irt_isaddr(t)); - dest = ra_dest(as, ir, (!LJ_SOFTFP && irt_isnum(t)) ? RSET_FPR : allow); - rset_clear(allow, dest); - base = ra_alloc1(as, REF_BASE, allow); - rset_clear(allow, base); - if (!LJ_SOFTFP && (ir->op2 & IRSLOAD_CONVERT)) { - if (irt_isint(t)) { - emit_tai(as, PPCI_LWZ, dest, RID_SP, SPOFS_TMPLO); - dest = ra_scratch(as, RSET_FPR); - emit_fai(as, PPCI_STFD, dest, RID_SP, SPOFS_TMP); - emit_fb(as, PPCI_FCTIWZ, dest, dest); - t.irt = IRT_NUM; /* Check for original type. */ - } else { - Reg tmp = ra_scratch(as, allow); - Reg hibias = ra_allock(as, 0x43300000, rset_clear(allow, tmp)); - Reg fbias = ra_scratch(as, rset_exclude(RSET_FPR, dest)); - emit_fab(as, PPCI_FSUB, dest, dest, fbias); - emit_fai(as, PPCI_LFD, dest, RID_SP, SPOFS_TMP); - emit_lsptr(as, PPCI_LFS, (fbias & 31), - (void *)&as->J->k32[LJ_K32_2P52_2P31], - rset_clear(allow, hibias)); - emit_tai(as, PPCI_STW, tmp, RID_SP, SPOFS_TMPLO); - emit_tai(as, PPCI_STW, hibias, RID_SP, SPOFS_TMPHI); - emit_asi(as, PPCI_XORIS, tmp, tmp, 0x8000); - dest = tmp; - t.irt = IRT_INT; /* Check for original type. */ - } - } - goto dotypecheck; - } - base = ra_alloc1(as, REF_BASE, allow); - rset_clear(allow, base); -dotypecheck: - if (irt_isnum(t)) { - if ((ir->op2 & IRSLOAD_TYPECHECK)) { - Reg tisnum = ra_allock(as, (int32_t)LJ_TISNUM, allow); - asm_guardcc(as, CC_GE); -#if !LJ_SOFTFP - type = RID_TMP; -#endif - emit_ab(as, PPCI_CMPLW, type, tisnum); - } - if (ra_hasreg(dest)) emit_fai(as, LJ_SOFTFP ? PPCI_LWZ : PPCI_LFD, dest, - base, ofs-(LJ_SOFTFP?0:4)); - } else { - if ((ir->op2 & IRSLOAD_TYPECHECK)) { - asm_guardcc(as, CC_NE); - emit_ai(as, PPCI_CMPWI, RID_TMP, irt_toitype(t)); - type = RID_TMP; - } - if (ra_hasreg(dest)) emit_tai(as, PPCI_LWZ, dest, base, ofs); - } - if (ra_hasreg(type)) emit_tai(as, PPCI_LWZ, type, base, ofs-4); -} - -/* -- Allocations --------------------------------------------------------- */ - -#if LJ_HASFFI -static void asm_cnew(ASMState *as, IRIns *ir) -{ - CTState *cts = ctype_ctsG(J2G(as->J)); - CTypeID id = (CTypeID)IR(ir->op1)->i; - CTSize sz; - CTInfo info = lj_ctype_info(cts, id, &sz); - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_mem_newgco]; - IRRef args[4]; - RegSet drop = RSET_SCRATCH; - lua_assert(sz != CTSIZE_INVALID || (ir->o == IR_CNEW && ir->op2 != REF_NIL)); - - as->gcsteps++; - if (ra_hasreg(ir->r)) - rset_clear(drop, ir->r); /* Dest reg handled below. */ - ra_evictset(as, drop); - if (ra_used(ir)) - ra_destreg(as, ir, RID_RET); /* GCcdata * */ - - /* Initialize immutable cdata object. */ - if (ir->o == IR_CNEWI) { - RegSet allow = (RSET_GPR & ~RSET_SCRATCH); - int32_t ofs = sizeof(GCcdata); - lua_assert(sz == 4 || sz == 8); - if (sz == 8) { - ofs += 4; - lua_assert((ir+1)->o == IR_HIOP); - } - for (;;) { - Reg r = ra_alloc1(as, ir->op2, allow); - emit_tai(as, PPCI_STW, r, RID_RET, ofs); - rset_clear(allow, r); - if (ofs == sizeof(GCcdata)) break; - ofs -= 4; ir++; - } - } else if (ir->op2 != REF_NIL) { /* Create VLA/VLS/aligned cdata. */ - ci = &lj_ir_callinfo[IRCALL_lj_cdata_newv]; - args[0] = ASMREF_L; /* lua_State *L */ - args[1] = ir->op1; /* CTypeID id */ - args[2] = ir->op2; /* CTSize sz */ - args[3] = ASMREF_TMP1; /* CTSize align */ - asm_gencall(as, ci, args); - emit_loadi(as, ra_releasetmp(as, ASMREF_TMP1), (int32_t)ctype_align(info)); - return; - } - - /* Initialize gct and ctypeid. lj_mem_newgco() already sets marked. */ - emit_tai(as, PPCI_STB, RID_RET+1, RID_RET, offsetof(GCcdata, gct)); - emit_tai(as, PPCI_STH, RID_TMP, RID_RET, offsetof(GCcdata, ctypeid)); - emit_ti(as, PPCI_LI, RID_RET+1, ~LJ_TCDATA); - emit_ti(as, PPCI_LI, RID_TMP, id); /* Lower 16 bit used. Sign-ext ok. */ - args[0] = ASMREF_L; /* lua_State *L */ - args[1] = ASMREF_TMP1; /* MSize size */ - asm_gencall(as, ci, args); - ra_allockreg(as, (int32_t)(sz+sizeof(GCcdata)), - ra_releasetmp(as, ASMREF_TMP1)); -} -#else -#define asm_cnew(as, ir) ((void)0) -#endif - -/* -- Write barriers ------------------------------------------------------ */ - -static void asm_tbar(ASMState *as, IRIns *ir) -{ - Reg tab = ra_alloc1(as, ir->op1, RSET_GPR); - Reg mark = ra_scratch(as, rset_exclude(RSET_GPR, tab)); - Reg link = RID_TMP; - MCLabel l_end = emit_label(as); - emit_tai(as, PPCI_STW, link, tab, (int32_t)offsetof(GCtab, gclist)); - emit_tai(as, PPCI_STB, mark, tab, (int32_t)offsetof(GCtab, marked)); - emit_setgl(as, tab, gc.grayagain); - lua_assert(LJ_GC_BLACK == 0x04); - emit_rot(as, PPCI_RLWINM, mark, mark, 0, 30, 28); /* Clear black bit. */ - emit_getgl(as, link, gc.grayagain); - emit_condbranch(as, PPCI_BC|PPCF_Y, CC_EQ, l_end); - emit_asi(as, PPCI_ANDIDOT, RID_TMP, mark, LJ_GC_BLACK); - emit_tai(as, PPCI_LBZ, mark, tab, (int32_t)offsetof(GCtab, marked)); -} - -static void asm_obar(ASMState *as, IRIns *ir) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_gc_barrieruv]; - IRRef args[2]; - MCLabel l_end; - Reg obj, val, tmp; - /* No need for other object barriers (yet). */ - lua_assert(IR(ir->op1)->o == IR_UREFC); - ra_evictset(as, RSET_SCRATCH); - l_end = emit_label(as); - args[0] = ASMREF_TMP1; /* global_State *g */ - args[1] = ir->op1; /* TValue *tv */ - asm_gencall(as, ci, args); - emit_tai(as, PPCI_ADDI, ra_releasetmp(as, ASMREF_TMP1), RID_JGL, -32768); - obj = IR(ir->op1)->r; - tmp = ra_scratch(as, rset_exclude(RSET_GPR, obj)); - emit_condbranch(as, PPCI_BC|PPCF_Y, CC_EQ, l_end); - emit_asi(as, PPCI_ANDIDOT, tmp, tmp, LJ_GC_BLACK); - emit_condbranch(as, PPCI_BC, CC_EQ, l_end); - emit_asi(as, PPCI_ANDIDOT, RID_TMP, RID_TMP, LJ_GC_WHITES); - val = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, obj)); - emit_tai(as, PPCI_LBZ, tmp, obj, - (int32_t)offsetof(GCupval, marked)-(int32_t)offsetof(GCupval, tv)); - emit_tai(as, PPCI_LBZ, RID_TMP, val, (int32_t)offsetof(GChead, marked)); -} - -/* -- Arithmetic and logic operations ------------------------------------- */ - -#if !LJ_SOFTFP -static void asm_fparith(ASMState *as, IRIns *ir, PPCIns pi) -{ - Reg dest = ra_dest(as, ir, RSET_FPR); - Reg right, left = ra_alloc2(as, ir, RSET_FPR); - right = (left >> 8); left &= 255; - if (pi == PPCI_FMUL) - emit_fac(as, pi, dest, left, right); - else - emit_fab(as, pi, dest, left, right); -} - -static void asm_fpunary(ASMState *as, IRIns *ir, PPCIns pi) -{ - Reg dest = ra_dest(as, ir, RSET_FPR); - Reg left = ra_hintalloc(as, ir->op1, dest, RSET_FPR); - emit_fb(as, pi, dest, left); -} - -static void asm_fpmath(ASMState *as, IRIns *ir) -{ - if (ir->op2 == IRFPM_EXP2 && asm_fpjoin_pow(as, ir)) - return; - if (ir->op2 == IRFPM_SQRT && (as->flags & JIT_F_SQRT)) - asm_fpunary(as, ir, PPCI_FSQRT); - else - asm_callid(as, ir, IRCALL_lj_vm_floor + ir->op2); -} -#endif - -static void asm_add(ASMState *as, IRIns *ir) -{ -#if !LJ_SOFTFP - if (irt_isnum(ir->t)) { - if (!asm_fusemadd(as, ir, PPCI_FMADD, PPCI_FMADD)) - asm_fparith(as, ir, PPCI_FADD); - } else -#endif - { - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg right, left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); - PPCIns pi; - if (irref_isk(ir->op2)) { - int32_t k = IR(ir->op2)->i; - if (checki16(k)) { - pi = PPCI_ADDI; - /* May fail due to spills/restores above, but simplifies the logic. */ - if (as->flagmcp == as->mcp) { - as->flagmcp = NULL; - as->mcp++; - pi = PPCI_ADDICDOT; - } - emit_tai(as, pi, dest, left, k); - return; - } else if ((k & 0xffff) == 0) { - emit_tai(as, PPCI_ADDIS, dest, left, (k >> 16)); - return; - } else if (!as->sectref) { - emit_tai(as, PPCI_ADDIS, dest, dest, (k + 32768) >> 16); - emit_tai(as, PPCI_ADDI, dest, left, k); - return; - } - } - pi = PPCI_ADD; - /* May fail due to spills/restores above, but simplifies the logic. */ - if (as->flagmcp == as->mcp) { - as->flagmcp = NULL; - as->mcp++; - pi |= PPCF_DOT; - } - right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left)); - emit_tab(as, pi, dest, left, right); - } -} - -static void asm_sub(ASMState *as, IRIns *ir) -{ -#if !LJ_SOFTFP - if (irt_isnum(ir->t)) { - if (!asm_fusemadd(as, ir, PPCI_FMSUB, PPCI_FNMSUB)) - asm_fparith(as, ir, PPCI_FSUB); - } else -#endif - { - PPCIns pi = PPCI_SUBF; - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left, right; - if (irref_isk(ir->op1)) { - int32_t k = IR(ir->op1)->i; - if (checki16(k)) { - right = ra_alloc1(as, ir->op2, RSET_GPR); - emit_tai(as, PPCI_SUBFIC, dest, right, k); - return; - } - } - /* May fail due to spills/restores above, but simplifies the logic. */ - if (as->flagmcp == as->mcp) { - as->flagmcp = NULL; - as->mcp++; - pi |= PPCF_DOT; - } - left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); - right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left)); - emit_tab(as, pi, dest, right, left); /* Subtract right _from_ left. */ - } -} - -static void asm_mul(ASMState *as, IRIns *ir) -{ -#if !LJ_SOFTFP - if (irt_isnum(ir->t)) { - asm_fparith(as, ir, PPCI_FMUL); - } else -#endif - { - PPCIns pi = PPCI_MULLW; - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg right, left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); - if (irref_isk(ir->op2)) { - int32_t k = IR(ir->op2)->i; - if (checki16(k)) { - emit_tai(as, PPCI_MULLI, dest, left, k); - return; - } - } - /* May fail due to spills/restores above, but simplifies the logic. */ - if (as->flagmcp == as->mcp) { - as->flagmcp = NULL; - as->mcp++; - pi |= PPCF_DOT; - } - right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left)); - emit_tab(as, pi, dest, left, right); - } -} - -#define asm_div(as, ir) asm_fparith(as, ir, PPCI_FDIV) -#define asm_mod(as, ir) asm_callid(as, ir, IRCALL_lj_vm_modi) -#define asm_pow(as, ir) asm_callid(as, ir, IRCALL_lj_vm_powi) - -static void asm_neg(ASMState *as, IRIns *ir) -{ -#if !LJ_SOFTFP - if (irt_isnum(ir->t)) { - asm_fpunary(as, ir, PPCI_FNEG); - } else -#endif - { - Reg dest, left; - PPCIns pi = PPCI_NEG; - if (as->flagmcp == as->mcp) { - as->flagmcp = NULL; - as->mcp++; - pi |= PPCF_DOT; - } - dest = ra_dest(as, ir, RSET_GPR); - left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); - emit_tab(as, pi, dest, left, 0); - } -} - -#define asm_abs(as, ir) asm_fpunary(as, ir, PPCI_FABS) -#define asm_atan2(as, ir) asm_callid(as, ir, IRCALL_atan2) -#define asm_ldexp(as, ir) asm_callid(as, ir, IRCALL_ldexp) - -static void asm_arithov(ASMState *as, IRIns *ir, PPCIns pi) -{ - Reg dest, left, right; - if (as->flagmcp == as->mcp) { - as->flagmcp = NULL; - as->mcp++; - } - asm_guardcc(as, CC_SO); - dest = ra_dest(as, ir, RSET_GPR); - left = ra_alloc2(as, ir, RSET_GPR); - right = (left >> 8); left &= 255; - if (pi == PPCI_SUBFO) { Reg tmp = left; left = right; right = tmp; } - emit_tab(as, pi|PPCF_DOT, dest, left, right); -} - -#define asm_addov(as, ir) asm_arithov(as, ir, PPCI_ADDO) -#define asm_subov(as, ir) asm_arithov(as, ir, PPCI_SUBFO) -#define asm_mulov(as, ir) asm_arithov(as, ir, PPCI_MULLWO) - -#if LJ_HASFFI -static void asm_add64(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg right, left = ra_alloc1(as, ir->op1, RSET_GPR); - PPCIns pi = PPCI_ADDE; - if (irref_isk(ir->op2)) { - int32_t k = IR(ir->op2)->i; - if (k == 0) - pi = PPCI_ADDZE; - else if (k == -1) - pi = PPCI_ADDME; - else - goto needright; - right = 0; - } else { - needright: - right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left)); - } - emit_tab(as, pi, dest, left, right); - ir--; - dest = ra_dest(as, ir, RSET_GPR); - left = ra_alloc1(as, ir->op1, RSET_GPR); - if (irref_isk(ir->op2)) { - int32_t k = IR(ir->op2)->i; - if (checki16(k)) { - emit_tai(as, PPCI_ADDIC, dest, left, k); - return; - } - } - right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left)); - emit_tab(as, PPCI_ADDC, dest, left, right); -} - -static void asm_sub64(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left, right = ra_alloc1(as, ir->op2, RSET_GPR); - PPCIns pi = PPCI_SUBFE; - if (irref_isk(ir->op1)) { - int32_t k = IR(ir->op1)->i; - if (k == 0) - pi = PPCI_SUBFZE; - else if (k == -1) - pi = PPCI_SUBFME; - else - goto needleft; - left = 0; - } else { - needleft: - left = ra_alloc1(as, ir->op1, rset_exclude(RSET_GPR, right)); - } - emit_tab(as, pi, dest, right, left); /* Subtract right _from_ left. */ - ir--; - dest = ra_dest(as, ir, RSET_GPR); - right = ra_alloc1(as, ir->op2, RSET_GPR); - if (irref_isk(ir->op1)) { - int32_t k = IR(ir->op1)->i; - if (checki16(k)) { - emit_tai(as, PPCI_SUBFIC, dest, right, k); - return; - } - } - left = ra_alloc1(as, ir->op1, rset_exclude(RSET_GPR, right)); - emit_tab(as, PPCI_SUBFC, dest, right, left); -} - -static void asm_neg64(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg left = ra_alloc1(as, ir->op1, RSET_GPR); - emit_tab(as, PPCI_SUBFZE, dest, left, 0); - ir--; - dest = ra_dest(as, ir, RSET_GPR); - left = ra_alloc1(as, ir->op1, RSET_GPR); - emit_tai(as, PPCI_SUBFIC, dest, left, 0); -} -#endif - -static void asm_bnot(ASMState *as, IRIns *ir) -{ - Reg dest, left, right; - PPCIns pi = PPCI_NOR; - if (as->flagmcp == as->mcp) { - as->flagmcp = NULL; - as->mcp++; - pi |= PPCF_DOT; - } - dest = ra_dest(as, ir, RSET_GPR); - if (mayfuse(as, ir->op1)) { - IRIns *irl = IR(ir->op1); - if (irl->o == IR_BAND) - pi ^= (PPCI_NOR ^ PPCI_NAND); - else if (irl->o == IR_BXOR) - pi ^= (PPCI_NOR ^ PPCI_EQV); - else if (irl->o != IR_BOR) - goto nofuse; - left = ra_hintalloc(as, irl->op1, dest, RSET_GPR); - right = ra_alloc1(as, irl->op2, rset_exclude(RSET_GPR, left)); - } else { -nofuse: - left = right = ra_hintalloc(as, ir->op1, dest, RSET_GPR); - } - emit_asb(as, pi, dest, left, right); -} - -static void asm_bswap(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - IRIns *irx; - if (mayfuse(as, ir->op1) && (irx = IR(ir->op1))->o == IR_XLOAD && - ra_noreg(irx->r) && (irt_isint(irx->t) || irt_isu32(irx->t))) { - /* Fuse BSWAP with XLOAD to lwbrx. */ - asm_fusexrefx(as, PPCI_LWBRX, dest, irx->op1, RSET_GPR); - } else { - Reg left = ra_alloc1(as, ir->op1, RSET_GPR); - Reg tmp = dest; - if (tmp == left) { - tmp = RID_TMP; - emit_mr(as, dest, RID_TMP); - } - emit_rot(as, PPCI_RLWIMI, tmp, left, 24, 16, 23); - emit_rot(as, PPCI_RLWIMI, tmp, left, 24, 0, 7); - emit_rotlwi(as, tmp, left, 8); - } -} - -/* Fuse BAND with contiguous bitmask and a shift to rlwinm. */ -static void asm_fuseandsh(ASMState *as, PPCIns pi, int32_t mask, IRRef ref) -{ - IRIns *ir; - Reg left; - if (mayfuse(as, ref) && (ir = IR(ref), ra_noreg(ir->r)) && - irref_isk(ir->op2) && ir->o >= IR_BSHL && ir->o <= IR_BROR) { - int32_t sh = (IR(ir->op2)->i & 31); - switch (ir->o) { - case IR_BSHL: - if ((mask & ((1u<>sh))) goto nofuse; - sh = ((32-sh)&31); - break; - case IR_BROL: - break; - default: - goto nofuse; - } - left = ra_alloc1(as, ir->op1, RSET_GPR); - *--as->mcp = pi | PPCF_T(left) | PPCF_B(sh); - return; - } -nofuse: - left = ra_alloc1(as, ref, RSET_GPR); - *--as->mcp = pi | PPCF_T(left); -} - -static void asm_band(ASMState *as, IRIns *ir) -{ - Reg dest, left, right; - IRRef lref = ir->op1; - PPCIns dot = 0; - IRRef op2; - if (as->flagmcp == as->mcp) { - as->flagmcp = NULL; - as->mcp++; - dot = PPCF_DOT; - } - dest = ra_dest(as, ir, RSET_GPR); - if (irref_isk(ir->op2)) { - int32_t k = IR(ir->op2)->i; - if (k) { - /* First check for a contiguous bitmask as used by rlwinm. */ - uint32_t s1 = lj_ffs((uint32_t)k); - uint32_t k1 = ((uint32_t)k >> s1); - if ((k1 & (k1+1)) == 0) { - asm_fuseandsh(as, PPCI_RLWINM|dot | PPCF_A(dest) | - PPCF_MB(31-lj_fls((uint32_t)k)) | PPCF_ME(31-s1), - k, lref); - return; - } - if (~(uint32_t)k) { - uint32_t s2 = lj_ffs(~(uint32_t)k); - uint32_t k2 = (~(uint32_t)k >> s2); - if ((k2 & (k2+1)) == 0) { - asm_fuseandsh(as, PPCI_RLWINM|dot | PPCF_A(dest) | - PPCF_MB(32-s2) | PPCF_ME(30-lj_fls(~(uint32_t)k)), - k, lref); - return; - } - } - } - if (checku16(k)) { - left = ra_alloc1(as, lref, RSET_GPR); - emit_asi(as, PPCI_ANDIDOT, dest, left, k); - return; - } else if ((k & 0xffff) == 0) { - left = ra_alloc1(as, lref, RSET_GPR); - emit_asi(as, PPCI_ANDISDOT, dest, left, (k >> 16)); - return; - } - } - op2 = ir->op2; - if (mayfuse(as, op2) && IR(op2)->o == IR_BNOT && ra_noreg(IR(op2)->r)) { - dot ^= (PPCI_AND ^ PPCI_ANDC); - op2 = IR(op2)->op1; - } - left = ra_hintalloc(as, lref, dest, RSET_GPR); - right = ra_alloc1(as, op2, rset_exclude(RSET_GPR, left)); - emit_asb(as, PPCI_AND ^ dot, dest, left, right); -} - -static void asm_bitop(ASMState *as, IRIns *ir, PPCIns pi, PPCIns pik) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg right, left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); - if (irref_isk(ir->op2)) { - int32_t k = IR(ir->op2)->i; - Reg tmp = left; - if ((checku16(k) || (k & 0xffff) == 0) || (tmp = dest, !as->sectref)) { - if (!checku16(k)) { - emit_asi(as, pik ^ (PPCI_ORI ^ PPCI_ORIS), dest, tmp, (k >> 16)); - if ((k & 0xffff) == 0) return; - } - emit_asi(as, pik, dest, left, k); - return; - } - } - /* May fail due to spills/restores above, but simplifies the logic. */ - if (as->flagmcp == as->mcp) { - as->flagmcp = NULL; - as->mcp++; - pi |= PPCF_DOT; - } - right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left)); - emit_asb(as, pi, dest, left, right); -} - -#define asm_bor(as, ir) asm_bitop(as, ir, PPCI_OR, PPCI_ORI) -#define asm_bxor(as, ir) asm_bitop(as, ir, PPCI_XOR, PPCI_XORI) - -static void asm_bitshift(ASMState *as, IRIns *ir, PPCIns pi, PPCIns pik) -{ - Reg dest, left; - Reg dot = 0; - if (as->flagmcp == as->mcp) { - as->flagmcp = NULL; - as->mcp++; - dot = PPCF_DOT; - } - dest = ra_dest(as, ir, RSET_GPR); - left = ra_alloc1(as, ir->op1, RSET_GPR); - if (irref_isk(ir->op2)) { /* Constant shifts. */ - int32_t shift = (IR(ir->op2)->i & 31); - if (pik == 0) /* SLWI */ - emit_rot(as, PPCI_RLWINM|dot, dest, left, shift, 0, 31-shift); - else if (pik == 1) /* SRWI */ - emit_rot(as, PPCI_RLWINM|dot, dest, left, (32-shift)&31, shift, 31); - else - emit_asb(as, pik|dot, dest, left, shift); - } else { - Reg right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left)); - emit_asb(as, pi|dot, dest, left, right); - } -} - -#define asm_bshl(as, ir) asm_bitshift(as, ir, PPCI_SLW, 0) -#define asm_bshr(as, ir) asm_bitshift(as, ir, PPCI_SRW, 1) -#define asm_bsar(as, ir) asm_bitshift(as, ir, PPCI_SRAW, PPCI_SRAWI) -#define asm_brol(as, ir) \ - asm_bitshift(as, ir, PPCI_RLWNM|PPCF_MB(0)|PPCF_ME(31), \ - PPCI_RLWINM|PPCF_MB(0)|PPCF_ME(31)) -#define asm_bror(as, ir) lua_assert(0) - -#if LJ_SOFTFP -static void asm_sfpmin_max(ASMState *as, IRIns *ir) -{ - CCallInfo ci = lj_ir_callinfo[IRCALL_softfp_cmp]; - IRRef args[4]; - MCLabel l_right, l_end; - Reg desthi = ra_dest(as, ir, RSET_GPR), destlo = ra_dest(as, ir+1, RSET_GPR); - Reg righthi, lefthi = ra_alloc2(as, ir, RSET_GPR); - Reg rightlo, leftlo = ra_alloc2(as, ir+1, RSET_GPR); - PPCCC cond = (IROp)ir->o == IR_MIN ? CC_EQ : CC_NE; - righthi = (lefthi >> 8); lefthi &= 255; - rightlo = (leftlo >> 8); leftlo &= 255; - args[0^LJ_BE] = ir->op1; args[1^LJ_BE] = (ir+1)->op1; - args[2^LJ_BE] = ir->op2; args[3^LJ_BE] = (ir+1)->op2; - l_end = emit_label(as); - if (desthi != righthi) emit_mr(as, desthi, righthi); - if (destlo != rightlo) emit_mr(as, destlo, rightlo); - l_right = emit_label(as); - if (l_end != l_right) emit_jmp(as, l_end); - if (desthi != lefthi) emit_mr(as, desthi, lefthi); - if (destlo != leftlo) emit_mr(as, destlo, leftlo); - if (l_right == as->mcp+1) { - cond ^= 4; l_right = l_end; ++as->mcp; - } - emit_condbranch(as, PPCI_BC, cond, l_right); - ra_evictset(as, RSET_SCRATCH); - emit_cmpi(as, RID_RET, 1); - asm_gencall(as, &ci, args); -} -#endif - -static void asm_min_max(ASMState *as, IRIns *ir, int ismax) -{ - if (!LJ_SOFTFP && irt_isnum(ir->t)) { - Reg dest = ra_dest(as, ir, RSET_FPR); - Reg tmp = dest; - Reg right, left = ra_alloc2(as, ir, RSET_FPR); - right = (left >> 8); left &= 255; - if (tmp == left || tmp == right) - tmp = ra_scratch(as, rset_exclude(rset_exclude(rset_exclude(RSET_FPR, - dest), left), right)); - emit_facb(as, PPCI_FSEL, dest, tmp, - ismax ? left : right, ismax ? right : left); - emit_fab(as, PPCI_FSUB, tmp, left, right); - } else { - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg tmp1 = RID_TMP, tmp2 = dest; - Reg right, left = ra_alloc2(as, ir, RSET_GPR); - right = (left >> 8); left &= 255; - if (tmp2 == left || tmp2 == right) - tmp2 = ra_scratch(as, rset_exclude(rset_exclude(rset_exclude(RSET_GPR, - dest), left), right)); - emit_tab(as, PPCI_ADD, dest, tmp2, right); - emit_asb(as, ismax ? PPCI_ANDC : PPCI_AND, tmp2, tmp2, tmp1); - emit_tab(as, PPCI_SUBFE, tmp1, tmp1, tmp1); - emit_tab(as, PPCI_SUBFC, tmp2, tmp2, tmp1); - emit_asi(as, PPCI_XORIS, tmp2, right, 0x8000); - emit_asi(as, PPCI_XORIS, tmp1, left, 0x8000); - } -} - -#define asm_min(as, ir) asm_min_max(as, ir, 0) -#define asm_max(as, ir) asm_min_max(as, ir, 1) - -/* -- Comparisons --------------------------------------------------------- */ - -#define CC_UNSIGNED 0x08 /* Unsigned integer comparison. */ -#define CC_TWO 0x80 /* Check two flags for FP comparison. */ - -/* Map of comparisons to flags. ORDER IR. */ -static const uint8_t asm_compmap[IR_ABC+1] = { - /* op int cc FP cc */ - /* LT */ CC_GE + (CC_GE<<4), - /* GE */ CC_LT + (CC_LE<<4) + CC_TWO, - /* LE */ CC_GT + (CC_GE<<4) + CC_TWO, - /* GT */ CC_LE + (CC_LE<<4), - /* ULT */ CC_GE + CC_UNSIGNED + (CC_GT<<4) + CC_TWO, - /* UGE */ CC_LT + CC_UNSIGNED + (CC_LT<<4), - /* ULE */ CC_GT + CC_UNSIGNED + (CC_GT<<4), - /* UGT */ CC_LE + CC_UNSIGNED + (CC_LT<<4) + CC_TWO, - /* EQ */ CC_NE + (CC_NE<<4), - /* NE */ CC_EQ + (CC_EQ<<4), - /* ABC */ CC_LE + CC_UNSIGNED + (CC_LT<<4) + CC_TWO /* Same as UGT. */ -}; - -static void asm_intcomp_(ASMState *as, IRRef lref, IRRef rref, Reg cr, PPCCC cc) -{ - Reg right, left = ra_alloc1(as, lref, RSET_GPR); - if (irref_isk(rref)) { - int32_t k = IR(rref)->i; - if ((cc & CC_UNSIGNED) == 0) { /* Signed comparison with constant. */ - if (checki16(k)) { - emit_tai(as, PPCI_CMPWI, cr, left, k); - /* Signed comparison with zero and referencing previous ins? */ - if (k == 0 && lref == as->curins-1) - as->flagmcp = as->mcp; /* Allow elimination of the compare. */ - return; - } else if ((cc & 3) == (CC_EQ & 3)) { /* Use CMPLWI for EQ or NE. */ - if (checku16(k)) { - emit_tai(as, PPCI_CMPLWI, cr, left, k); - return; - } else if (!as->sectref && ra_noreg(IR(rref)->r)) { - emit_tai(as, PPCI_CMPLWI, cr, RID_TMP, k); - emit_asi(as, PPCI_XORIS, RID_TMP, left, (k >> 16)); - return; - } - } - } else { /* Unsigned comparison with constant. */ - if (checku16(k)) { - emit_tai(as, PPCI_CMPLWI, cr, left, k); - return; - } - } - } - right = ra_alloc1(as, rref, rset_exclude(RSET_GPR, left)); - emit_tab(as, (cc & CC_UNSIGNED) ? PPCI_CMPLW : PPCI_CMPW, cr, left, right); -} - -static void asm_comp(ASMState *as, IRIns *ir) -{ - PPCCC cc = asm_compmap[ir->o]; - if (!LJ_SOFTFP && irt_isnum(ir->t)) { - Reg right, left = ra_alloc2(as, ir, RSET_FPR); - right = (left >> 8); left &= 255; - asm_guardcc(as, (cc >> 4)); - if ((cc & CC_TWO)) - emit_tab(as, PPCI_CROR, ((cc>>4)&3), ((cc>>4)&3), (CC_EQ&3)); - emit_fab(as, PPCI_FCMPU, 0, left, right); - } else { - IRRef lref = ir->op1, rref = ir->op2; - if (irref_isk(lref) && !irref_isk(rref)) { - /* Swap constants to the right (only for ABC). */ - IRRef tmp = lref; lref = rref; rref = tmp; - if ((cc & 2) == 0) cc ^= 1; /* LT <-> GT, LE <-> GE */ - } - asm_guardcc(as, cc); - asm_intcomp_(as, lref, rref, 0, cc); - } -} - -#define asm_equal(as, ir) asm_comp(as, ir) - -#if LJ_SOFTFP -/* SFP comparisons. */ -static void asm_sfpcomp(ASMState *as, IRIns *ir) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_softfp_cmp]; - RegSet drop = RSET_SCRATCH; - Reg r; - IRRef args[4]; - args[0^LJ_BE] = ir->op1; args[1^LJ_BE] = (ir+1)->op1; - args[2^LJ_BE] = ir->op2; args[3^LJ_BE] = (ir+1)->op2; - - for (r = REGARG_FIRSTGPR; r <= REGARG_FIRSTGPR+3; r++) { - if (!rset_test(as->freeset, r) && - regcost_ref(as->cost[r]) == args[r-REGARG_FIRSTGPR]) - rset_clear(drop, r); - } - ra_evictset(as, drop); - asm_setupresult(as, ir, ci); - switch ((IROp)ir->o) { - case IR_ULT: - asm_guardcc(as, CC_EQ); - emit_ai(as, PPCI_CMPWI, RID_RET, 0); - case IR_ULE: - asm_guardcc(as, CC_EQ); - emit_ai(as, PPCI_CMPWI, RID_RET, 1); - break; - case IR_GE: case IR_GT: - asm_guardcc(as, CC_EQ); - emit_ai(as, PPCI_CMPWI, RID_RET, 2); - default: - asm_guardcc(as, (asm_compmap[ir->o] & 0xf)); - emit_ai(as, PPCI_CMPWI, RID_RET, 0); - break; - } - asm_gencall(as, ci, args); -} -#endif - -#if LJ_HASFFI -/* 64 bit integer comparisons. */ -static void asm_comp64(ASMState *as, IRIns *ir) -{ - PPCCC cc = asm_compmap[(ir-1)->o]; - if ((cc&3) == (CC_EQ&3)) { - asm_guardcc(as, cc); - emit_tab(as, (cc&4) ? PPCI_CRAND : PPCI_CROR, - (CC_EQ&3), (CC_EQ&3), 4+(CC_EQ&3)); - } else { - asm_guardcc(as, CC_EQ); - emit_tab(as, PPCI_CROR, (CC_EQ&3), (CC_EQ&3), ((cc^~(cc>>2))&1)); - emit_tab(as, (cc&4) ? PPCI_CRAND : PPCI_CRANDC, - (CC_EQ&3), (CC_EQ&3), 4+(cc&3)); - } - /* Loword comparison sets cr1 and is unsigned, except for equality. */ - asm_intcomp_(as, (ir-1)->op1, (ir-1)->op2, 4, - cc | ((cc&3) == (CC_EQ&3) ? 0 : CC_UNSIGNED)); - /* Hiword comparison sets cr0. */ - asm_intcomp_(as, ir->op1, ir->op2, 0, cc); - as->flagmcp = NULL; /* Doesn't work here. */ -} -#endif - -/* -- Support for 64 bit ops in 32 bit mode ------------------------------- */ - -/* Hiword op of a split 64 bit op. Previous op must be the loword op. */ -static void asm_hiop(ASMState *as, IRIns *ir) -{ -#if LJ_HASFFI || LJ_SOFTFP - /* HIOP is marked as a store because it needs its own DCE logic. */ - int uselo = ra_used(ir-1), usehi = ra_used(ir); /* Loword/hiword used? */ - if (LJ_UNLIKELY(!(as->flags & JIT_F_OPT_DCE))) uselo = usehi = 1; - if ((ir-1)->o == IR_CONV) { /* Conversions to/from 64 bit. */ - as->curins--; /* Always skip the CONV. */ -#if LJ_HASFFI && !LJ_SOFTFP - if (usehi || uselo) - asm_conv64(as, ir); - return; -#endif - } else if ((ir-1)->o <= IR_NE) { /* 64 bit integer comparisons. ORDER IR. */ - as->curins--; /* Always skip the loword comparison. */ -#if LJ_SOFTFP - if (!irt_isint(ir->t)) { - asm_sfpcomp(as, ir-1); - return; - } -#endif -#if LJ_HASFFI - asm_comp64(as, ir); -#endif - return; -#if LJ_SOFTFP - } else if ((ir-1)->o == IR_MIN || (ir-1)->o == IR_MAX) { - as->curins--; /* Always skip the loword min/max. */ - if (uselo || usehi) - asm_sfpmin_max(as, ir-1); - return; -#endif - } else if ((ir-1)->o == IR_XSTORE) { - as->curins--; /* Handle both stores here. */ - if ((ir-1)->r != RID_SINK) { - asm_xstore_(as, ir, 0); - asm_xstore_(as, ir-1, 4); - } - return; - } - if (!usehi) return; /* Skip unused hiword op for all remaining ops. */ - switch ((ir-1)->o) { -#if LJ_HASFFI - case IR_ADD: as->curins--; asm_add64(as, ir); break; - case IR_SUB: as->curins--; asm_sub64(as, ir); break; - case IR_NEG: as->curins--; asm_neg64(as, ir); break; -#endif -#if LJ_SOFTFP - case IR_SLOAD: case IR_ALOAD: case IR_HLOAD: case IR_ULOAD: case IR_VLOAD: - case IR_STRTO: - if (!uselo) - ra_allocref(as, ir->op1, RSET_GPR); /* Mark lo op as used. */ - break; -#endif - case IR_CALLN: - case IR_CALLS: - case IR_CALLXS: - if (!uselo) - ra_allocref(as, ir->op1, RID2RSET(RID_RETLO)); /* Mark lo op as used. */ - break; -#if LJ_SOFTFP - case IR_ASTORE: case IR_HSTORE: case IR_USTORE: case IR_TOSTR: -#endif - case IR_CNEWI: - /* Nothing to do here. Handled by lo op itself. */ - break; - default: lua_assert(0); break; - } -#else - UNUSED(as); UNUSED(ir); lua_assert(0); /* Unused without FFI. */ -#endif -} - -/* -- Profiling ----------------------------------------------------------- */ - -static void asm_prof(ASMState *as, IRIns *ir) -{ - UNUSED(ir); - asm_guardcc(as, CC_NE); - emit_asi(as, PPCI_ANDIDOT, RID_TMP, RID_TMP, HOOK_PROFILE); - emit_lsglptr(as, PPCI_LBZ, RID_TMP, - (int32_t)offsetof(global_State, hookmask)); -} - -/* -- Stack handling ------------------------------------------------------ */ - -/* Check Lua stack size for overflow. Use exit handler as fallback. */ -static void asm_stack_check(ASMState *as, BCReg topslot, - IRIns *irp, RegSet allow, ExitNo exitno) -{ - /* Try to get an unused temp. register, otherwise spill/restore RID_RET*. */ - Reg tmp, pbase = irp ? (ra_hasreg(irp->r) ? irp->r : RID_TMP) : RID_BASE; - rset_clear(allow, pbase); - tmp = allow ? rset_pickbot(allow) : - (pbase == RID_RETHI ? RID_RETLO : RID_RETHI); - emit_condbranch(as, PPCI_BC, CC_LT, asm_exitstub_addr(as, exitno)); - if (allow == RSET_EMPTY) /* Restore temp. register. */ - emit_tai(as, PPCI_LWZ, tmp, RID_SP, SPOFS_TMPW); - else - ra_modified(as, tmp); - emit_ai(as, PPCI_CMPLWI, RID_TMP, (int32_t)(8*topslot)); - emit_tab(as, PPCI_SUBF, RID_TMP, pbase, tmp); - emit_tai(as, PPCI_LWZ, tmp, tmp, offsetof(lua_State, maxstack)); - if (pbase == RID_TMP) - emit_getgl(as, RID_TMP, jit_base); - emit_getgl(as, tmp, cur_L); - if (allow == RSET_EMPTY) /* Spill temp. register. */ - emit_tai(as, PPCI_STW, tmp, RID_SP, SPOFS_TMPW); -} - -/* Restore Lua stack from on-trace state. */ -static void asm_stack_restore(ASMState *as, SnapShot *snap) -{ - SnapEntry *map = &as->T->snapmap[snap->mapofs]; - SnapEntry *flinks = &as->T->snapmap[snap_nextofs(as->T, snap)-1]; - MSize n, nent = snap->nent; - /* Store the value of all modified slots to the Lua stack. */ - for (n = 0; n < nent; n++) { - SnapEntry sn = map[n]; - BCReg s = snap_slot(sn); - int32_t ofs = 8*((int32_t)s-1); - IRRef ref = snap_ref(sn); - IRIns *ir = IR(ref); - if ((sn & SNAP_NORESTORE)) - continue; - if (irt_isnum(ir->t)) { -#if LJ_SOFTFP - Reg tmp; - RegSet allow = rset_exclude(RSET_GPR, RID_BASE); - lua_assert(irref_isk(ref)); /* LJ_SOFTFP: must be a number constant. */ - tmp = ra_allock(as, (int32_t)ir_knum(ir)->u32.lo, allow); - emit_tai(as, PPCI_STW, tmp, RID_BASE, ofs+(LJ_BE?4:0)); - if (rset_test(as->freeset, tmp+1)) allow = RID2RSET(tmp+1); - tmp = ra_allock(as, (int32_t)ir_knum(ir)->u32.hi, allow); - emit_tai(as, PPCI_STW, tmp, RID_BASE, ofs+(LJ_BE?0:4)); -#else - Reg src = ra_alloc1(as, ref, RSET_FPR); - emit_fai(as, PPCI_STFD, src, RID_BASE, ofs); -#endif - } else { - Reg type; - RegSet allow = rset_exclude(RSET_GPR, RID_BASE); - lua_assert(irt_ispri(ir->t) || irt_isaddr(ir->t) || irt_isinteger(ir->t)); - if (!irt_ispri(ir->t)) { - Reg src = ra_alloc1(as, ref, allow); - rset_clear(allow, src); - emit_tai(as, PPCI_STW, src, RID_BASE, ofs+4); - } - if ((sn & (SNAP_CONT|SNAP_FRAME))) { - if (s == 0) continue; /* Do not overwrite link to previous frame. */ - type = ra_allock(as, (int32_t)(*flinks--), allow); -#if LJ_SOFTFP - } else if ((sn & SNAP_SOFTFPNUM)) { - type = ra_alloc1(as, ref+1, rset_exclude(RSET_GPR, RID_BASE)); -#endif - } else { - type = ra_allock(as, (int32_t)irt_toitype(ir->t), allow); - } - emit_tai(as, PPCI_STW, type, RID_BASE, ofs); - } - checkmclim(as); - } - lua_assert(map + nent == flinks); -} - -/* -- GC handling --------------------------------------------------------- */ - -/* Check GC threshold and do one or more GC steps. */ -static void asm_gc_check(ASMState *as) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_gc_step_jit]; - IRRef args[2]; - MCLabel l_end; - Reg tmp; - ra_evictset(as, RSET_SCRATCH); - l_end = emit_label(as); - /* Exit trace if in GCSatomic or GCSfinalize. Avoids syncing GC objects. */ - asm_guardcc(as, CC_NE); /* Assumes asm_snap_prep() already done. */ - emit_ai(as, PPCI_CMPWI, RID_RET, 0); - args[0] = ASMREF_TMP1; /* global_State *g */ - args[1] = ASMREF_TMP2; /* MSize steps */ - asm_gencall(as, ci, args); - emit_tai(as, PPCI_ADDI, ra_releasetmp(as, ASMREF_TMP1), RID_JGL, -32768); - tmp = ra_releasetmp(as, ASMREF_TMP2); - emit_loadi(as, tmp, as->gcsteps); - /* Jump around GC step if GC total < GC threshold. */ - emit_condbranch(as, PPCI_BC|PPCF_Y, CC_LT, l_end); - emit_ab(as, PPCI_CMPLW, RID_TMP, tmp); - emit_getgl(as, tmp, gc.threshold); - emit_getgl(as, RID_TMP, gc.total); - as->gcsteps = 0; - checkmclim(as); -} - -/* -- Loop handling ------------------------------------------------------- */ - -/* Fixup the loop branch. */ -static void asm_loop_fixup(ASMState *as) -{ - MCode *p = as->mctop; - MCode *target = as->mcp; - if (as->loopinv) { /* Inverted loop branch? */ - /* asm_guardcc already inverted the cond branch and patched the final b. */ - p[-2] = (p[-2] & (0xffff0000u & ~PPCF_Y)) | (((target-p+2) & 0x3fffu) << 2); - } else { - p[-1] = PPCI_B|(((target-p+1)&0x00ffffffu)<<2); - } -} - -/* -- Head of trace ------------------------------------------------------- */ - -/* Coalesce BASE register for a root trace. */ -static void asm_head_root_base(ASMState *as) -{ - IRIns *ir = IR(REF_BASE); - Reg r = ir->r; - if (ra_hasreg(r)) { - ra_free(as, r); - if (rset_test(as->modset, r) || irt_ismarked(ir->t)) - ir->r = RID_INIT; /* No inheritance for modified BASE register. */ - if (r != RID_BASE) - emit_mr(as, r, RID_BASE); - } -} - -/* Coalesce BASE register for a side trace. */ -static RegSet asm_head_side_base(ASMState *as, IRIns *irp, RegSet allow) -{ - IRIns *ir = IR(REF_BASE); - Reg r = ir->r; - if (ra_hasreg(r)) { - ra_free(as, r); - if (rset_test(as->modset, r) || irt_ismarked(ir->t)) - ir->r = RID_INIT; /* No inheritance for modified BASE register. */ - if (irp->r == r) { - rset_clear(allow, r); /* Mark same BASE register as coalesced. */ - } else if (ra_hasreg(irp->r) && rset_test(as->freeset, irp->r)) { - rset_clear(allow, irp->r); - emit_mr(as, r, irp->r); /* Move from coalesced parent reg. */ - } else { - emit_getgl(as, r, jit_base); /* Otherwise reload BASE. */ - } - } - return allow; -} - -/* -- Tail of trace ------------------------------------------------------- */ - -/* Fixup the tail code. */ -static void asm_tail_fixup(ASMState *as, TraceNo lnk) -{ - MCode *p = as->mctop; - MCode *target; - int32_t spadj = as->T->spadjust; - if (spadj == 0) { - *--p = PPCI_NOP; - *--p = PPCI_NOP; - as->mctop = p; - } else { - /* Patch stack adjustment. */ - lua_assert(checki16(CFRAME_SIZE+spadj)); - p[-3] = PPCI_ADDI | PPCF_T(RID_TMP) | PPCF_A(RID_SP) | (CFRAME_SIZE+spadj); - p[-2] = PPCI_STWU | PPCF_T(RID_TMP) | PPCF_A(RID_SP) | spadj; - } - /* Patch exit branch. */ - target = lnk ? traceref(as->J, lnk)->mcode : (MCode *)lj_vm_exit_interp; - p[-1] = PPCI_B|(((target-p+1)&0x00ffffffu)<<2); -} - -/* Prepare tail of code. */ -static void asm_tail_prep(ASMState *as) -{ - MCode *p = as->mctop - 1; /* Leave room for exit branch. */ - if (as->loopref) { - as->invmcp = as->mcp = p; - } else { - as->mcp = p-2; /* Leave room for stack pointer adjustment. */ - as->invmcp = NULL; - } -} - -/* -- Trace setup --------------------------------------------------------- */ - -/* Ensure there are enough stack slots for call arguments. */ -static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci) -{ - IRRef args[CCI_NARGS_MAX*2]; - uint32_t i, nargs = CCI_XNARGS(ci); - int nslots = 2, ngpr = REGARG_NUMGPR, nfpr = REGARG_NUMFPR; - asm_collectargs(as, ir, ci, args); - for (i = 0; i < nargs; i++) - if (!LJ_SOFTFP && args[i] && irt_isfp(IR(args[i])->t)) { - if (nfpr > 0) nfpr--; else nslots = (nslots+3) & ~1; - } else { - if (ngpr > 0) ngpr--; else nslots++; - } - if (nslots > as->evenspill) /* Leave room for args in stack slots. */ - as->evenspill = nslots; - return (!LJ_SOFTFP && irt_isfp(ir->t)) ? REGSP_HINT(RID_FPRET) : - REGSP_HINT(RID_RET); -} - -static void asm_setup_target(ASMState *as) -{ - asm_exitstub_setup(as, as->T->nsnap + (as->parent ? 1 : 0)); -} - -/* -- Trace patching ------------------------------------------------------ */ - -/* Patch exit jumps of existing machine code to a new target. */ -void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, MCode *target) -{ - MCode *p = T->mcode; - MCode *pe = (MCode *)((char *)p + T->szmcode); - MCode *px = exitstub_trace_addr(T, exitno); - MCode *cstart = NULL; - MCode *mcarea = lj_mcode_patch(J, p, 0); - int clearso = 0; - for (; p < pe; p++) { - /* Look for exitstub branch, try to replace with branch to target. */ - uint32_t ins = *p; - if ((ins & 0xfc000000u) == 0x40000000u && - ((ins ^ ((char *)px-(char *)p)) & 0xffffu) == 0) { - ptrdiff_t delta = (char *)target - (char *)p; - if (((ins >> 16) & 3) == (CC_SO&3)) { - clearso = sizeof(MCode); - delta -= sizeof(MCode); - } - /* Many, but not all short-range branches can be patched directly. */ - if (((delta + 0x8000) >> 16) == 0) { - *p = (ins & 0xffdf0000u) | ((uint32_t)delta & 0xffffu) | - ((delta & 0x8000) * (PPCF_Y/0x8000)); - if (!cstart) cstart = p; - } - } else if ((ins & 0xfc000000u) == PPCI_B && - ((ins ^ ((char *)px-(char *)p)) & 0x03ffffffu) == 0) { - ptrdiff_t delta = (char *)target - (char *)p; - lua_assert(((delta + 0x02000000) >> 26) == 0); - *p = PPCI_B | ((uint32_t)delta & 0x03ffffffu); - if (!cstart) cstart = p; - } - } - { /* Always patch long-range branch in exit stub itself. */ - ptrdiff_t delta = (char *)target - (char *)px - clearso; - lua_assert(((delta + 0x02000000) >> 26) == 0); - *px = PPCI_B | ((uint32_t)delta & 0x03ffffffu); - } - if (!cstart) cstart = px; - lj_mcode_sync(cstart, px+1); - if (clearso) { /* Extend the current trace. Ugly workaround. */ - MCode *pp = J->cur.mcode; - J->cur.szmcode += sizeof(MCode); - *--pp = PPCI_MCRXR; /* Clear SO flag. */ - J->cur.mcode = pp; - lj_mcode_sync(pp, pp+1); - } - lj_mcode_patch(J, mcarea, 1); -} - diff --git a/lib/LuaJIT/src/lj_asm_x86.h b/lib/LuaJIT/src/lj_asm_x86.h deleted file mode 100644 index af54dc7..0000000 --- a/lib/LuaJIT/src/lj_asm_x86.h +++ /dev/null @@ -1,3121 +0,0 @@ -/* -** x86/x64 IR assembler (SSA IR -> machine code). -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -/* -- Guard handling ------------------------------------------------------ */ - -/* Generate an exit stub group at the bottom of the reserved MCode memory. */ -static MCode *asm_exitstub_gen(ASMState *as, ExitNo group) -{ - ExitNo i, groupofs = (group*EXITSTUBS_PER_GROUP) & 0xff; - MCode *mxp = as->mcbot; - MCode *mxpstart = mxp; - if (mxp + (2+2)*EXITSTUBS_PER_GROUP+8+5 >= as->mctop) - asm_mclimit(as); - /* Push low byte of exitno for each exit stub. */ - *mxp++ = XI_PUSHi8; *mxp++ = (MCode)groupofs; - for (i = 1; i < EXITSTUBS_PER_GROUP; i++) { - *mxp++ = XI_JMPs; *mxp++ = (MCode)((2+2)*(EXITSTUBS_PER_GROUP - i) - 2); - *mxp++ = XI_PUSHi8; *mxp++ = (MCode)(groupofs + i); - } - /* Push the high byte of the exitno for each exit stub group. */ - *mxp++ = XI_PUSHi8; *mxp++ = (MCode)((group*EXITSTUBS_PER_GROUP)>>8); -#if !LJ_GC64 - /* Store DISPATCH at original stack slot 0. Account for the two push ops. */ - *mxp++ = XI_MOVmi; - *mxp++ = MODRM(XM_OFS8, 0, RID_ESP); - *mxp++ = MODRM(XM_SCALE1, RID_ESP, RID_ESP); - *mxp++ = 2*sizeof(void *); - *(int32_t *)mxp = ptr2addr(J2GG(as->J)->dispatch); mxp += 4; -#endif - /* Jump to exit handler which fills in the ExitState. */ - *mxp++ = XI_JMP; mxp += 4; - *((int32_t *)(mxp-4)) = jmprel(mxp, (MCode *)(void *)lj_vm_exit_handler); - /* Commit the code for this group (even if assembly fails later on). */ - lj_mcode_commitbot(as->J, mxp); - as->mcbot = mxp; - as->mclim = as->mcbot + MCLIM_REDZONE; - return mxpstart; -} - -/* Setup all needed exit stubs. */ -static void asm_exitstub_setup(ASMState *as, ExitNo nexits) -{ - ExitNo i; - if (nexits >= EXITSTUBS_PER_GROUP*LJ_MAX_EXITSTUBGR) - lj_trace_err(as->J, LJ_TRERR_SNAPOV); - for (i = 0; i < (nexits+EXITSTUBS_PER_GROUP-1)/EXITSTUBS_PER_GROUP; i++) - if (as->J->exitstubgroup[i] == NULL) - as->J->exitstubgroup[i] = asm_exitstub_gen(as, i); -} - -/* Emit conditional branch to exit for guard. -** It's important to emit this *after* all registers have been allocated, -** because rematerializations may invalidate the flags. -*/ -static void asm_guardcc(ASMState *as, int cc) -{ - MCode *target = exitstub_addr(as->J, as->snapno); - MCode *p = as->mcp; - if (LJ_UNLIKELY(p == as->invmcp)) { - as->loopinv = 1; - *(int32_t *)(p+1) = jmprel(p+5, target); - target = p; - cc ^= 1; - if (as->realign) { - if (LJ_GC64 && LJ_UNLIKELY(as->mrm.base == RID_RIP)) - as->mrm.ofs += 2; /* Fixup RIP offset for pending fused load. */ - emit_sjcc(as, cc, target); - return; - } - } - if (LJ_GC64 && LJ_UNLIKELY(as->mrm.base == RID_RIP)) - as->mrm.ofs += 6; /* Fixup RIP offset for pending fused load. */ - emit_jcc(as, cc, target); -} - -/* -- Memory operand fusion ----------------------------------------------- */ - -/* Limit linear search to this distance. Avoids O(n^2) behavior. */ -#define CONFLICT_SEARCH_LIM 31 - -/* Check if a reference is a signed 32 bit constant. */ -static int asm_isk32(ASMState *as, IRRef ref, int32_t *k) -{ - if (irref_isk(ref)) { - IRIns *ir = IR(ref); -#if LJ_GC64 - if (ir->o == IR_KNULL || !irt_is64(ir->t)) { - *k = ir->i; - return 1; - } else if (checki32((int64_t)ir_k64(ir)->u64)) { - *k = (int32_t)ir_k64(ir)->u64; - return 1; - } -#else - if (ir->o != IR_KINT64) { - *k = ir->i; - return 1; - } else if (checki32((int64_t)ir_kint64(ir)->u64)) { - *k = (int32_t)ir_kint64(ir)->u64; - return 1; - } -#endif - } - return 0; -} - -/* Check if there's no conflicting instruction between curins and ref. -** Also avoid fusing loads if there are multiple references. -*/ -static int noconflict(ASMState *as, IRRef ref, IROp conflict, int noload) -{ - IRIns *ir = as->ir; - IRRef i = as->curins; - if (i > ref + CONFLICT_SEARCH_LIM) - return 0; /* Give up, ref is too far away. */ - while (--i > ref) { - if (ir[i].o == conflict) - return 0; /* Conflict found. */ - else if (!noload && (ir[i].op1 == ref || ir[i].op2 == ref)) - return 0; - } - return 1; /* Ok, no conflict. */ -} - -/* Fuse array base into memory operand. */ -static IRRef asm_fuseabase(ASMState *as, IRRef ref) -{ - IRIns *irb = IR(ref); - as->mrm.ofs = 0; - if (irb->o == IR_FLOAD) { - IRIns *ira = IR(irb->op1); - lua_assert(irb->op2 == IRFL_TAB_ARRAY); - /* We can avoid the FLOAD of t->array for colocated arrays. */ - if (ira->o == IR_TNEW && ira->op1 <= LJ_MAX_COLOSIZE && - !neverfuse(as) && noconflict(as, irb->op1, IR_NEWREF, 1)) { - as->mrm.ofs = (int32_t)sizeof(GCtab); /* Ofs to colocated array. */ - return irb->op1; /* Table obj. */ - } - } else if (irb->o == IR_ADD && irref_isk(irb->op2)) { - /* Fuse base offset (vararg load). */ - as->mrm.ofs = IR(irb->op2)->i; - return irb->op1; - } - return ref; /* Otherwise use the given array base. */ -} - -/* Fuse array reference into memory operand. */ -static void asm_fusearef(ASMState *as, IRIns *ir, RegSet allow) -{ - IRIns *irx; - lua_assert(ir->o == IR_AREF); - as->mrm.base = (uint8_t)ra_alloc1(as, asm_fuseabase(as, ir->op1), allow); - irx = IR(ir->op2); - if (irref_isk(ir->op2)) { - as->mrm.ofs += 8*irx->i; - as->mrm.idx = RID_NONE; - } else { - rset_clear(allow, as->mrm.base); - as->mrm.scale = XM_SCALE8; - /* Fuse a constant ADD (e.g. t[i+1]) into the offset. - ** Doesn't help much without ABCelim, but reduces register pressure. - */ - if (!LJ_64 && /* Has bad effects with negative index on x64. */ - mayfuse(as, ir->op2) && ra_noreg(irx->r) && - irx->o == IR_ADD && irref_isk(irx->op2)) { - as->mrm.ofs += 8*IR(irx->op2)->i; - as->mrm.idx = (uint8_t)ra_alloc1(as, irx->op1, allow); - } else { - as->mrm.idx = (uint8_t)ra_alloc1(as, ir->op2, allow); - } - } -} - -/* Fuse array/hash/upvalue reference into memory operand. -** Caveat: this may allocate GPRs for the base/idx registers. Be sure to -** pass the final allow mask, excluding any GPRs used for other inputs. -** In particular: 2-operand GPR instructions need to call ra_dest() first! -*/ -static void asm_fuseahuref(ASMState *as, IRRef ref, RegSet allow) -{ - IRIns *ir = IR(ref); - if (ra_noreg(ir->r)) { - switch ((IROp)ir->o) { - case IR_AREF: - if (mayfuse(as, ref)) { - asm_fusearef(as, ir, allow); - return; - } - break; - case IR_HREFK: - if (mayfuse(as, ref)) { - as->mrm.base = (uint8_t)ra_alloc1(as, ir->op1, allow); - as->mrm.ofs = (int32_t)(IR(ir->op2)->op2 * sizeof(Node)); - as->mrm.idx = RID_NONE; - return; - } - break; - case IR_UREFC: - if (irref_isk(ir->op1)) { - GCfunc *fn = ir_kfunc(IR(ir->op1)); - GCupval *uv = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv; -#if LJ_GC64 - int64_t ofs = dispofs(as, &uv->tv); - if (checki32(ofs) && checki32(ofs+4)) { - as->mrm.ofs = (int32_t)ofs; - as->mrm.base = RID_DISPATCH; - as->mrm.idx = RID_NONE; - return; - } -#else - as->mrm.ofs = ptr2addr(&uv->tv); - as->mrm.base = as->mrm.idx = RID_NONE; - return; -#endif - } - break; - default: - lua_assert(ir->o == IR_HREF || ir->o == IR_NEWREF || ir->o == IR_UREFO || - ir->o == IR_KKPTR); - break; - } - } - as->mrm.base = (uint8_t)ra_alloc1(as, ref, allow); - as->mrm.ofs = 0; - as->mrm.idx = RID_NONE; -} - -/* Fuse FLOAD/FREF reference into memory operand. */ -static void asm_fusefref(ASMState *as, IRIns *ir, RegSet allow) -{ - lua_assert(ir->o == IR_FLOAD || ir->o == IR_FREF); - as->mrm.idx = RID_NONE; - if (ir->op1 == REF_NIL) { -#if LJ_GC64 - as->mrm.ofs = (int32_t)(ir->op2 << 2) - GG_OFS(dispatch); - as->mrm.base = RID_DISPATCH; -#else - as->mrm.ofs = (int32_t)(ir->op2 << 2) + ptr2addr(J2GG(as->J)); - as->mrm.base = RID_NONE; -#endif - return; - } - as->mrm.ofs = field_ofs[ir->op2]; - if (irref_isk(ir->op1)) { - IRIns *op1 = IR(ir->op1); -#if LJ_GC64 - if (ir->op1 == REF_NIL) { - as->mrm.ofs -= GG_OFS(dispatch); - as->mrm.base = RID_DISPATCH; - return; - } else if (op1->o == IR_KPTR || op1->o == IR_KKPTR) { - intptr_t ofs = dispofs(as, ir_kptr(op1)); - if (checki32(as->mrm.ofs + ofs)) { - as->mrm.ofs += (int32_t)ofs; - as->mrm.base = RID_DISPATCH; - return; - } - } -#else - as->mrm.ofs += op1->i; - as->mrm.base = RID_NONE; - return; -#endif - } - as->mrm.base = (uint8_t)ra_alloc1(as, ir->op1, allow); -} - -/* Fuse string reference into memory operand. */ -static void asm_fusestrref(ASMState *as, IRIns *ir, RegSet allow) -{ - IRIns *irr; - lua_assert(ir->o == IR_STRREF); - as->mrm.base = as->mrm.idx = RID_NONE; - as->mrm.scale = XM_SCALE1; - as->mrm.ofs = sizeof(GCstr); - if (!LJ_GC64 && irref_isk(ir->op1)) { - as->mrm.ofs += IR(ir->op1)->i; - } else { - Reg r = ra_alloc1(as, ir->op1, allow); - rset_clear(allow, r); - as->mrm.base = (uint8_t)r; - } - irr = IR(ir->op2); - if (irref_isk(ir->op2)) { - as->mrm.ofs += irr->i; - } else { - Reg r; - /* Fuse a constant add into the offset, e.g. string.sub(s, i+10). */ - if (!LJ_64 && /* Has bad effects with negative index on x64. */ - mayfuse(as, ir->op2) && irr->o == IR_ADD && irref_isk(irr->op2)) { - as->mrm.ofs += IR(irr->op2)->i; - r = ra_alloc1(as, irr->op1, allow); - } else { - r = ra_alloc1(as, ir->op2, allow); - } - if (as->mrm.base == RID_NONE) - as->mrm.base = (uint8_t)r; - else - as->mrm.idx = (uint8_t)r; - } -} - -static void asm_fusexref(ASMState *as, IRRef ref, RegSet allow) -{ - IRIns *ir = IR(ref); - as->mrm.idx = RID_NONE; - if (ir->o == IR_KPTR || ir->o == IR_KKPTR) { -#if LJ_GC64 - intptr_t ofs = dispofs(as, ir_kptr(ir)); - if (checki32(ofs)) { - as->mrm.ofs = (int32_t)ofs; - as->mrm.base = RID_DISPATCH; - return; - } - } if (0) { -#else - as->mrm.ofs = ir->i; - as->mrm.base = RID_NONE; - } else if (ir->o == IR_STRREF) { - asm_fusestrref(as, ir, allow); -#endif - } else { - as->mrm.ofs = 0; - if (canfuse(as, ir) && ir->o == IR_ADD && ra_noreg(ir->r)) { - /* Gather (base+idx*sz)+ofs as emitted by cdata ptr/array indexing. */ - IRIns *irx; - IRRef idx; - Reg r; - if (asm_isk32(as, ir->op2, &as->mrm.ofs)) { /* Recognize x+ofs. */ - ref = ir->op1; - ir = IR(ref); - if (!(ir->o == IR_ADD && canfuse(as, ir) && ra_noreg(ir->r))) - goto noadd; - } - as->mrm.scale = XM_SCALE1; - idx = ir->op1; - ref = ir->op2; - irx = IR(idx); - if (!(irx->o == IR_BSHL || irx->o == IR_ADD)) { /* Try other operand. */ - idx = ir->op2; - ref = ir->op1; - irx = IR(idx); - } - if (canfuse(as, irx) && ra_noreg(irx->r)) { - if (irx->o == IR_BSHL && irref_isk(irx->op2) && IR(irx->op2)->i <= 3) { - /* Recognize idx<op1; - as->mrm.scale = (uint8_t)(IR(irx->op2)->i << 6); - } else if (irx->o == IR_ADD && irx->op1 == irx->op2) { - /* FOLD does idx*2 ==> idx<<1 ==> idx+idx. */ - idx = irx->op1; - as->mrm.scale = XM_SCALE2; - } - } - r = ra_alloc1(as, idx, allow); - rset_clear(allow, r); - as->mrm.idx = (uint8_t)r; - } - noadd: - as->mrm.base = (uint8_t)ra_alloc1(as, ref, allow); - } -} - -/* Fuse load of 64 bit IR constant into memory operand. */ -static Reg asm_fuseloadk64(ASMState *as, IRIns *ir) -{ - const uint64_t *k = &ir_k64(ir)->u64; - if (!LJ_GC64 || checki32((intptr_t)k)) { - as->mrm.ofs = ptr2addr(k); - as->mrm.base = RID_NONE; -#if LJ_GC64 - } else if (checki32(dispofs(as, k))) { - as->mrm.ofs = (int32_t)dispofs(as, k); - as->mrm.base = RID_DISPATCH; - } else if (checki32(mcpofs(as, k)) && checki32(mcpofs(as, k+1)) && - checki32(mctopofs(as, k)) && checki32(mctopofs(as, k+1))) { - as->mrm.ofs = (int32_t)mcpofs(as, k); - as->mrm.base = RID_RIP; - } else { - if (ir->i) { - lua_assert(*k == *(uint64_t*)(as->mctop - ir->i)); - } else { - while ((uintptr_t)as->mcbot & 7) *as->mcbot++ = XI_INT3; - *(uint64_t*)as->mcbot = *k; - ir->i = (int32_t)(as->mctop - as->mcbot); - as->mcbot += 8; - as->mclim = as->mcbot + MCLIM_REDZONE; - lj_mcode_commitbot(as->J, as->mcbot); - } - as->mrm.ofs = (int32_t)mcpofs(as, as->mctop - ir->i); - as->mrm.base = RID_RIP; -#endif - } - as->mrm.idx = RID_NONE; - return RID_MRM; -} - -/* Fuse load into memory operand. -** -** Important caveat: this may emit RIP-relative loads! So don't place any -** code emitters between this function and the use of its result. -** The only permitted exception is asm_guardcc(). -*/ -static Reg asm_fuseload(ASMState *as, IRRef ref, RegSet allow) -{ - IRIns *ir = IR(ref); - if (ra_hasreg(ir->r)) { - if (allow != RSET_EMPTY) { /* Fast path. */ - ra_noweak(as, ir->r); - return ir->r; - } - fusespill: - /* Force a spill if only memory operands are allowed (asm_x87load). */ - as->mrm.base = RID_ESP; - as->mrm.ofs = ra_spill(as, ir); - as->mrm.idx = RID_NONE; - return RID_MRM; - } - if (ir->o == IR_KNUM) { - RegSet avail = as->freeset & ~as->modset & RSET_FPR; - lua_assert(allow != RSET_EMPTY); - if (!(avail & (avail-1))) /* Fuse if less than two regs available. */ - return asm_fuseloadk64(as, ir); - } else if (ref == REF_BASE || ir->o == IR_KINT64) { - RegSet avail = as->freeset & ~as->modset & RSET_GPR; - lua_assert(allow != RSET_EMPTY); - if (!(avail & (avail-1))) { /* Fuse if less than two regs available. */ - if (ref == REF_BASE) { -#if LJ_GC64 - as->mrm.ofs = (int32_t)dispofs(as, &J2G(as->J)->jit_base); - as->mrm.base = RID_DISPATCH; -#else - as->mrm.ofs = ptr2addr(&J2G(as->J)->jit_base); - as->mrm.base = RID_NONE; -#endif - as->mrm.idx = RID_NONE; - return RID_MRM; - } else { - return asm_fuseloadk64(as, ir); - } - } - } else if (mayfuse(as, ref)) { - RegSet xallow = (allow & RSET_GPR) ? allow : RSET_GPR; - if (ir->o == IR_SLOAD) { - if (!(ir->op2 & (IRSLOAD_PARENT|IRSLOAD_CONVERT)) && - noconflict(as, ref, IR_RETF, 0) && - !(LJ_GC64 && irt_isaddr(ir->t))) { - as->mrm.base = (uint8_t)ra_alloc1(as, REF_BASE, xallow); - as->mrm.ofs = 8*((int32_t)ir->op1-1-LJ_FR2) + - (!LJ_FR2 && (ir->op2 & IRSLOAD_FRAME) ? 4 : 0); - as->mrm.idx = RID_NONE; - return RID_MRM; - } - } else if (ir->o == IR_FLOAD) { - /* Generic fusion is only ok for 32 bit operand (but see asm_comp). */ - if ((irt_isint(ir->t) || irt_isu32(ir->t) || irt_isaddr(ir->t)) && - noconflict(as, ref, IR_FSTORE, 0)) { - asm_fusefref(as, ir, xallow); - return RID_MRM; - } - } else if (ir->o == IR_ALOAD || ir->o == IR_HLOAD || ir->o == IR_ULOAD) { - if (noconflict(as, ref, ir->o + IRDELTA_L2S, 0) && - !(LJ_GC64 && irt_isaddr(ir->t))) { - asm_fuseahuref(as, ir->op1, xallow); - return RID_MRM; - } - } else if (ir->o == IR_XLOAD) { - /* Generic fusion is not ok for 8/16 bit operands (but see asm_comp). - ** Fusing unaligned memory operands is ok on x86 (except for SIMD types). - */ - if ((!irt_typerange(ir->t, IRT_I8, IRT_U16)) && - noconflict(as, ref, IR_XSTORE, 0)) { - asm_fusexref(as, ir->op1, xallow); - return RID_MRM; - } - } else if (ir->o == IR_VLOAD && !(LJ_GC64 && irt_isaddr(ir->t))) { - asm_fuseahuref(as, ir->op1, xallow); - return RID_MRM; - } - } - if (ir->o == IR_FLOAD && ir->op1 == REF_NIL) { - asm_fusefref(as, ir, RSET_EMPTY); - return RID_MRM; - } - if (!(as->freeset & allow) && !emit_canremat(ref) && - (allow == RSET_EMPTY || ra_hasspill(ir->s) || iscrossref(as, ref))) - goto fusespill; - return ra_allocref(as, ref, allow); -} - -#if LJ_64 -/* Don't fuse a 32 bit load into a 64 bit operation. */ -static Reg asm_fuseloadm(ASMState *as, IRRef ref, RegSet allow, int is64) -{ - if (is64 && !irt_is64(IR(ref)->t)) - return ra_alloc1(as, ref, allow); - return asm_fuseload(as, ref, allow); -} -#else -#define asm_fuseloadm(as, ref, allow, is64) asm_fuseload(as, (ref), (allow)) -#endif - -/* -- Calls --------------------------------------------------------------- */ - -/* Count the required number of stack slots for a call. */ -static int asm_count_call_slots(ASMState *as, const CCallInfo *ci, IRRef *args) -{ - uint32_t i, nargs = CCI_XNARGS(ci); - int nslots = 0; -#if LJ_64 - if (LJ_ABI_WIN) { - nslots = (int)(nargs*2); /* Only matters for more than four args. */ - } else { - int ngpr = REGARG_NUMGPR, nfpr = REGARG_NUMFPR; - for (i = 0; i < nargs; i++) - if (args[i] && irt_isfp(IR(args[i])->t)) { - if (nfpr > 0) nfpr--; else nslots += 2; - } else { - if (ngpr > 0) ngpr--; else nslots += 2; - } - } -#else - int ngpr = 0; - if ((ci->flags & CCI_CC_MASK) == CCI_CC_FASTCALL) - ngpr = 2; - else if ((ci->flags & CCI_CC_MASK) == CCI_CC_THISCALL) - ngpr = 1; - for (i = 0; i < nargs; i++) - if (args[i] && irt_isfp(IR(args[i])->t)) { - nslots += irt_isnum(IR(args[i])->t) ? 2 : 1; - } else { - if (ngpr > 0) ngpr--; else nslots++; - } -#endif - return nslots; -} - -/* Generate a call to a C function. */ -static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) -{ - uint32_t n, nargs = CCI_XNARGS(ci); - int32_t ofs = STACKARG_OFS; -#if LJ_64 - uint32_t gprs = REGARG_GPRS; - Reg fpr = REGARG_FIRSTFPR; -#if !LJ_ABI_WIN - MCode *patchnfpr = NULL; -#endif -#else - uint32_t gprs = 0; - if ((ci->flags & CCI_CC_MASK) != CCI_CC_CDECL) { - if ((ci->flags & CCI_CC_MASK) == CCI_CC_THISCALL) - gprs = (REGARG_GPRS & 31); - else if ((ci->flags & CCI_CC_MASK) == CCI_CC_FASTCALL) - gprs = REGARG_GPRS; - } -#endif - if ((void *)ci->func) - emit_call(as, ci->func); -#if LJ_64 - if ((ci->flags & CCI_VARARG)) { /* Special handling for vararg calls. */ -#if LJ_ABI_WIN - for (n = 0; n < 4 && n < nargs; n++) { - IRIns *ir = IR(args[n]); - if (irt_isfp(ir->t)) /* Duplicate FPRs in GPRs. */ - emit_rr(as, XO_MOVDto, (irt_isnum(ir->t) ? REX_64 : 0) | (fpr+n), - ((gprs >> (n*5)) & 31)); /* Either MOVD or MOVQ. */ - } -#else - patchnfpr = --as->mcp; /* Indicate number of used FPRs in register al. */ - *--as->mcp = XI_MOVrib | RID_EAX; -#endif - } -#endif - for (n = 0; n < nargs; n++) { /* Setup args. */ - IRRef ref = args[n]; - IRIns *ir = IR(ref); - Reg r; -#if LJ_64 && LJ_ABI_WIN - /* Windows/x64 argument registers are strictly positional. */ - r = irt_isfp(ir->t) ? (fpr <= REGARG_LASTFPR ? fpr : 0) : (gprs & 31); - fpr++; gprs >>= 5; -#elif LJ_64 - /* POSIX/x64 argument registers are used in order of appearance. */ - if (irt_isfp(ir->t)) { - r = fpr <= REGARG_LASTFPR ? fpr++ : 0; - } else { - r = gprs & 31; gprs >>= 5; - } -#else - if (ref && irt_isfp(ir->t)) { - r = 0; - } else { - r = gprs & 31; gprs >>= 5; - if (!ref) continue; - } -#endif - if (r) { /* Argument is in a register. */ - if (r < RID_MAX_GPR && ref < ASMREF_TMP1) { -#if LJ_64 - if (LJ_GC64 ? !(ir->o == IR_KINT || ir->o == IR_KNULL) : ir->o == IR_KINT64) - emit_loadu64(as, r, ir_k64(ir)->u64); - else -#endif - emit_loadi(as, r, ir->i); - } else { - lua_assert(rset_test(as->freeset, r)); /* Must have been evicted. */ - if (ra_hasreg(ir->r)) { - ra_noweak(as, ir->r); - emit_movrr(as, ir, r, ir->r); - } else { - ra_allocref(as, ref, RID2RSET(r)); - } - } - } else if (irt_isfp(ir->t)) { /* FP argument is on stack. */ - lua_assert(!(irt_isfloat(ir->t) && irref_isk(ref))); /* No float k. */ - if (LJ_32 && (ofs & 4) && irref_isk(ref)) { - /* Split stores for unaligned FP consts. */ - emit_movmroi(as, RID_ESP, ofs, (int32_t)ir_knum(ir)->u32.lo); - emit_movmroi(as, RID_ESP, ofs+4, (int32_t)ir_knum(ir)->u32.hi); - } else { - r = ra_alloc1(as, ref, RSET_FPR); - emit_rmro(as, irt_isnum(ir->t) ? XO_MOVSDto : XO_MOVSSto, - r, RID_ESP, ofs); - } - ofs += (LJ_32 && irt_isfloat(ir->t)) ? 4 : 8; - } else { /* Non-FP argument is on stack. */ - if (LJ_32 && ref < ASMREF_TMP1) { - emit_movmroi(as, RID_ESP, ofs, ir->i); - } else { - r = ra_alloc1(as, ref, RSET_GPR); - emit_movtomro(as, REX_64 + r, RID_ESP, ofs); - } - ofs += sizeof(intptr_t); - } - checkmclim(as); - } -#if LJ_64 && !LJ_ABI_WIN - if (patchnfpr) *patchnfpr = fpr - REGARG_FIRSTFPR; -#endif -} - -/* Setup result reg/sp for call. Evict scratch regs. */ -static void asm_setupresult(ASMState *as, IRIns *ir, const CCallInfo *ci) -{ - RegSet drop = RSET_SCRATCH; - int hiop = (LJ_32 && (ir+1)->o == IR_HIOP && !irt_isnil((ir+1)->t)); - if ((ci->flags & CCI_NOFPRCLOBBER)) - drop &= ~RSET_FPR; - if (ra_hasreg(ir->r)) - rset_clear(drop, ir->r); /* Dest reg handled below. */ - if (hiop && ra_hasreg((ir+1)->r)) - rset_clear(drop, (ir+1)->r); /* Dest reg handled below. */ - ra_evictset(as, drop); /* Evictions must be performed first. */ - if (ra_used(ir)) { - if (irt_isfp(ir->t)) { - int32_t ofs = sps_scale(ir->s); /* Use spill slot or temp slots. */ -#if LJ_64 - if ((ci->flags & CCI_CASTU64)) { - Reg dest = ir->r; - if (ra_hasreg(dest)) { - ra_free(as, dest); - ra_modified(as, dest); - emit_rr(as, XO_MOVD, dest|REX_64, RID_RET); /* Really MOVQ. */ - } - if (ofs) emit_movtomro(as, RID_RET|REX_64, RID_ESP, ofs); - } else { - ra_destreg(as, ir, RID_FPRET); - } -#else - /* Number result is in x87 st0 for x86 calling convention. */ - Reg dest = ir->r; - if (ra_hasreg(dest)) { - ra_free(as, dest); - ra_modified(as, dest); - emit_rmro(as, irt_isnum(ir->t) ? XO_MOVSD : XO_MOVSS, - dest, RID_ESP, ofs); - } - if ((ci->flags & CCI_CASTU64)) { - emit_movtomro(as, RID_RETLO, RID_ESP, ofs); - emit_movtomro(as, RID_RETHI, RID_ESP, ofs+4); - } else { - emit_rmro(as, irt_isnum(ir->t) ? XO_FSTPq : XO_FSTPd, - irt_isnum(ir->t) ? XOg_FSTPq : XOg_FSTPd, RID_ESP, ofs); - } -#endif -#if LJ_32 - } else if (hiop) { - ra_destpair(as, ir); -#endif - } else { - lua_assert(!irt_ispri(ir->t)); - ra_destreg(as, ir, RID_RET); - } - } else if (LJ_32 && irt_isfp(ir->t) && !(ci->flags & CCI_CASTU64)) { - emit_x87op(as, XI_FPOP); /* Pop unused result from x87 st0. */ - } -} - -/* Return a constant function pointer or NULL for indirect calls. */ -static void *asm_callx_func(ASMState *as, IRIns *irf, IRRef func) -{ -#if LJ_32 - UNUSED(as); - if (irref_isk(func)) - return (void *)irf->i; -#else - if (irref_isk(func)) { - MCode *p; - if (irf->o == IR_KINT64) - p = (MCode *)(void *)ir_k64(irf)->u64; - else - p = (MCode *)(void *)(uintptr_t)(uint32_t)irf->i; - if (p - as->mcp == (int32_t)(p - as->mcp)) - return p; /* Call target is still in +-2GB range. */ - /* Avoid the indirect case of emit_call(). Try to hoist func addr. */ - } -#endif - return NULL; -} - -static void asm_callx(ASMState *as, IRIns *ir) -{ - IRRef args[CCI_NARGS_MAX*2]; - CCallInfo ci; - IRRef func; - IRIns *irf; - int32_t spadj = 0; - ci.flags = asm_callx_flags(as, ir); - asm_collectargs(as, ir, &ci, args); - asm_setupresult(as, ir, &ci); -#if LJ_32 - /* Have to readjust stack after non-cdecl calls due to callee cleanup. */ - if ((ci.flags & CCI_CC_MASK) != CCI_CC_CDECL) - spadj = 4 * asm_count_call_slots(as, &ci, args); -#endif - func = ir->op2; irf = IR(func); - if (irf->o == IR_CARG) { func = irf->op1; irf = IR(func); } - ci.func = (ASMFunction)asm_callx_func(as, irf, func); - if (!(void *)ci.func) { - /* Use a (hoistable) non-scratch register for indirect calls. */ - RegSet allow = (RSET_GPR & ~RSET_SCRATCH); - Reg r = ra_alloc1(as, func, allow); - if (LJ_32) emit_spsub(as, spadj); /* Above code may cause restores! */ - emit_rr(as, XO_GROUP5, XOg_CALL, r); - } else if (LJ_32) { - emit_spsub(as, spadj); - } - asm_gencall(as, &ci, args); -} - -/* -- Returns ------------------------------------------------------------- */ - -/* Return to lower frame. Guard that it goes to the right spot. */ -static void asm_retf(ASMState *as, IRIns *ir) -{ - Reg base = ra_alloc1(as, REF_BASE, RSET_GPR); -#if LJ_FR2 - Reg rpc = ra_scratch(as, rset_exclude(RSET_GPR, base)); -#endif - void *pc = ir_kptr(IR(ir->op2)); - int32_t delta = 1+LJ_FR2+bc_a(*((const BCIns *)pc - 1)); - as->topslot -= (BCReg)delta; - if ((int32_t)as->topslot < 0) as->topslot = 0; - irt_setmark(IR(REF_BASE)->t); /* Children must not coalesce with BASE reg. */ - emit_setgl(as, base, jit_base); - emit_addptr(as, base, -8*delta); - asm_guardcc(as, CC_NE); -#if LJ_FR2 - emit_rmro(as, XO_CMP, rpc|REX_GC64, base, -8); - emit_loadu64(as, rpc, u64ptr(pc)); -#else - emit_gmroi(as, XG_ARITHi(XOg_CMP), base, -4, ptr2addr(pc)); -#endif -} - -/* -- Type conversions ---------------------------------------------------- */ - -static void asm_tointg(ASMState *as, IRIns *ir, Reg left) -{ - Reg tmp = ra_scratch(as, rset_exclude(RSET_FPR, left)); - Reg dest = ra_dest(as, ir, RSET_GPR); - asm_guardcc(as, CC_P); - asm_guardcc(as, CC_NE); - emit_rr(as, XO_UCOMISD, left, tmp); - emit_rr(as, XO_CVTSI2SD, tmp, dest); - emit_rr(as, XO_XORPS, tmp, tmp); /* Avoid partial register stall. */ - emit_rr(as, XO_CVTTSD2SI, dest, left); - /* Can't fuse since left is needed twice. */ -} - -static void asm_tobit(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - Reg tmp = ra_noreg(IR(ir->op1)->r) ? - ra_alloc1(as, ir->op1, RSET_FPR) : - ra_scratch(as, RSET_FPR); - Reg right; - emit_rr(as, XO_MOVDto, tmp, dest); - right = asm_fuseload(as, ir->op2, rset_exclude(RSET_FPR, tmp)); - emit_mrm(as, XO_ADDSD, tmp, right); - ra_left(as, tmp, ir->op1); -} - -static void asm_conv(ASMState *as, IRIns *ir) -{ - IRType st = (IRType)(ir->op2 & IRCONV_SRCMASK); - int st64 = (st == IRT_I64 || st == IRT_U64 || (LJ_64 && st == IRT_P64)); - int stfp = (st == IRT_NUM || st == IRT_FLOAT); - IRRef lref = ir->op1; - lua_assert(irt_type(ir->t) != st); - lua_assert(!(LJ_32 && (irt_isint64(ir->t) || st64))); /* Handled by SPLIT. */ - if (irt_isfp(ir->t)) { - Reg dest = ra_dest(as, ir, RSET_FPR); - if (stfp) { /* FP to FP conversion. */ - Reg left = asm_fuseload(as, lref, RSET_FPR); - emit_mrm(as, st == IRT_NUM ? XO_CVTSD2SS : XO_CVTSS2SD, dest, left); - if (left == dest) return; /* Avoid the XO_XORPS. */ - } else if (LJ_32 && st == IRT_U32) { /* U32 to FP conversion on x86. */ - /* number = (2^52+2^51 .. u32) - (2^52+2^51) */ - cTValue *k = &as->J->k64[LJ_K64_TOBIT]; - Reg bias = ra_scratch(as, rset_exclude(RSET_FPR, dest)); - if (irt_isfloat(ir->t)) - emit_rr(as, XO_CVTSD2SS, dest, dest); - emit_rr(as, XO_SUBSD, dest, bias); /* Subtract 2^52+2^51 bias. */ - emit_rr(as, XO_XORPS, dest, bias); /* Merge bias and integer. */ - emit_rma(as, XO_MOVSD, bias, k); - emit_mrm(as, XO_MOVD, dest, asm_fuseload(as, lref, RSET_GPR)); - return; - } else { /* Integer to FP conversion. */ - Reg left = (LJ_64 && (st == IRT_U32 || st == IRT_U64)) ? - ra_alloc1(as, lref, RSET_GPR) : - asm_fuseloadm(as, lref, RSET_GPR, st64); - if (LJ_64 && st == IRT_U64) { - MCLabel l_end = emit_label(as); - cTValue *k = &as->J->k64[LJ_K64_2P64]; - emit_rma(as, XO_ADDSD, dest, k); /* Add 2^64 to compensate. */ - emit_sjcc(as, CC_NS, l_end); - emit_rr(as, XO_TEST, left|REX_64, left); /* Check if u64 >= 2^63. */ - } - emit_mrm(as, irt_isnum(ir->t) ? XO_CVTSI2SD : XO_CVTSI2SS, - dest|((LJ_64 && (st64 || st == IRT_U32)) ? REX_64 : 0), left); - } - emit_rr(as, XO_XORPS, dest, dest); /* Avoid partial register stall. */ - } else if (stfp) { /* FP to integer conversion. */ - if (irt_isguard(ir->t)) { - /* Checked conversions are only supported from number to int. */ - lua_assert(irt_isint(ir->t) && st == IRT_NUM); - asm_tointg(as, ir, ra_alloc1(as, lref, RSET_FPR)); - } else { - Reg dest = ra_dest(as, ir, RSET_GPR); - x86Op op = st == IRT_NUM ? XO_CVTTSD2SI : XO_CVTTSS2SI; - if (LJ_64 ? irt_isu64(ir->t) : irt_isu32(ir->t)) { - /* LJ_64: For inputs >= 2^63 add -2^64, convert again. */ - /* LJ_32: For inputs >= 2^31 add -2^31, convert again and add 2^31. */ - Reg tmp = ra_noreg(IR(lref)->r) ? ra_alloc1(as, lref, RSET_FPR) : - ra_scratch(as, RSET_FPR); - MCLabel l_end = emit_label(as); - if (LJ_32) - emit_gri(as, XG_ARITHi(XOg_ADD), dest, (int32_t)0x80000000); - emit_rr(as, op, dest|REX_64, tmp); - if (st == IRT_NUM) - emit_rma(as, XO_ADDSD, tmp, &as->J->k64[LJ_K64_M2P64_31]); - else - emit_rma(as, XO_ADDSS, tmp, &as->J->k32[LJ_K32_M2P64_31]); - emit_sjcc(as, CC_NS, l_end); - emit_rr(as, XO_TEST, dest|REX_64, dest); /* Check if dest negative. */ - emit_rr(as, op, dest|REX_64, tmp); - ra_left(as, tmp, lref); - } else { - if (LJ_64 && irt_isu32(ir->t)) - emit_rr(as, XO_MOV, dest, dest); /* Zero hiword. */ - emit_mrm(as, op, - dest|((LJ_64 && - (irt_is64(ir->t) || irt_isu32(ir->t))) ? REX_64 : 0), - asm_fuseload(as, lref, RSET_FPR)); - } - } - } else if (st >= IRT_I8 && st <= IRT_U16) { /* Extend to 32 bit integer. */ - Reg left, dest = ra_dest(as, ir, RSET_GPR); - RegSet allow = RSET_GPR; - x86Op op; - lua_assert(irt_isint(ir->t) || irt_isu32(ir->t)); - if (st == IRT_I8) { - op = XO_MOVSXb; allow = RSET_GPR8; dest |= FORCE_REX; - } else if (st == IRT_U8) { - op = XO_MOVZXb; allow = RSET_GPR8; dest |= FORCE_REX; - } else if (st == IRT_I16) { - op = XO_MOVSXw; - } else { - op = XO_MOVZXw; - } - left = asm_fuseload(as, lref, allow); - /* Add extra MOV if source is already in wrong register. */ - if (!LJ_64 && left != RID_MRM && !rset_test(allow, left)) { - Reg tmp = ra_scratch(as, allow); - emit_rr(as, op, dest, tmp); - emit_rr(as, XO_MOV, tmp, left); - } else { - emit_mrm(as, op, dest, left); - } - } else { /* 32/64 bit integer conversions. */ - if (LJ_32) { /* Only need to handle 32/32 bit no-op (cast) on x86. */ - Reg dest = ra_dest(as, ir, RSET_GPR); - ra_left(as, dest, lref); /* Do nothing, but may need to move regs. */ - } else if (irt_is64(ir->t)) { - Reg dest = ra_dest(as, ir, RSET_GPR); - if (st64 || !(ir->op2 & IRCONV_SEXT)) { - /* 64/64 bit no-op (cast) or 32 to 64 bit zero extension. */ - ra_left(as, dest, lref); /* Do nothing, but may need to move regs. */ - } else { /* 32 to 64 bit sign extension. */ - Reg left = asm_fuseload(as, lref, RSET_GPR); - emit_mrm(as, XO_MOVSXd, dest|REX_64, left); - } - } else { - Reg dest = ra_dest(as, ir, RSET_GPR); - if (st64) { - Reg left = asm_fuseload(as, lref, RSET_GPR); - /* This is either a 32 bit reg/reg mov which zeroes the hiword - ** or a load of the loword from a 64 bit address. - */ - emit_mrm(as, XO_MOV, dest, left); - } else { /* 32/32 bit no-op (cast). */ - ra_left(as, dest, lref); /* Do nothing, but may need to move regs. */ - } - } - } -} - -#if LJ_32 && LJ_HASFFI -/* No SSE conversions to/from 64 bit on x86, so resort to ugly x87 code. */ - -/* 64 bit integer to FP conversion in 32 bit mode. */ -static void asm_conv_fp_int64(ASMState *as, IRIns *ir) -{ - Reg hi = ra_alloc1(as, ir->op1, RSET_GPR); - Reg lo = ra_alloc1(as, (ir-1)->op1, rset_exclude(RSET_GPR, hi)); - int32_t ofs = sps_scale(ir->s); /* Use spill slot or temp slots. */ - Reg dest = ir->r; - if (ra_hasreg(dest)) { - ra_free(as, dest); - ra_modified(as, dest); - emit_rmro(as, irt_isnum(ir->t) ? XO_MOVSD : XO_MOVSS, dest, RID_ESP, ofs); - } - emit_rmro(as, irt_isnum(ir->t) ? XO_FSTPq : XO_FSTPd, - irt_isnum(ir->t) ? XOg_FSTPq : XOg_FSTPd, RID_ESP, ofs); - if (((ir-1)->op2 & IRCONV_SRCMASK) == IRT_U64) { - /* For inputs in [2^63,2^64-1] add 2^64 to compensate. */ - MCLabel l_end = emit_label(as); - emit_rma(as, XO_FADDq, XOg_FADDq, &as->J->k64[LJ_K64_2P64]); - emit_sjcc(as, CC_NS, l_end); - emit_rr(as, XO_TEST, hi, hi); /* Check if u64 >= 2^63. */ - } else { - lua_assert(((ir-1)->op2 & IRCONV_SRCMASK) == IRT_I64); - } - emit_rmro(as, XO_FILDq, XOg_FILDq, RID_ESP, 0); - /* NYI: Avoid narrow-to-wide store-to-load forwarding stall. */ - emit_rmro(as, XO_MOVto, hi, RID_ESP, 4); - emit_rmro(as, XO_MOVto, lo, RID_ESP, 0); -} - -/* FP to 64 bit integer conversion in 32 bit mode. */ -static void asm_conv_int64_fp(ASMState *as, IRIns *ir) -{ - IRType st = (IRType)((ir-1)->op2 & IRCONV_SRCMASK); - IRType dt = (((ir-1)->op2 & IRCONV_DSTMASK) >> IRCONV_DSH); - Reg lo, hi; - lua_assert(st == IRT_NUM || st == IRT_FLOAT); - lua_assert(dt == IRT_I64 || dt == IRT_U64); - hi = ra_dest(as, ir, RSET_GPR); - lo = ra_dest(as, ir-1, rset_exclude(RSET_GPR, hi)); - if (ra_used(ir-1)) emit_rmro(as, XO_MOV, lo, RID_ESP, 0); - /* NYI: Avoid wide-to-narrow store-to-load forwarding stall. */ - if (!(as->flags & JIT_F_SSE3)) { /* Set FPU rounding mode to default. */ - emit_rmro(as, XO_FLDCW, XOg_FLDCW, RID_ESP, 4); - emit_rmro(as, XO_MOVto, lo, RID_ESP, 4); - emit_gri(as, XG_ARITHi(XOg_AND), lo, 0xf3ff); - } - if (dt == IRT_U64) { - /* For inputs in [2^63,2^64-1] add -2^64 and convert again. */ - MCLabel l_pop, l_end = emit_label(as); - emit_x87op(as, XI_FPOP); - l_pop = emit_label(as); - emit_sjmp(as, l_end); - emit_rmro(as, XO_MOV, hi, RID_ESP, 4); - if ((as->flags & JIT_F_SSE3)) - emit_rmro(as, XO_FISTTPq, XOg_FISTTPq, RID_ESP, 0); - else - emit_rmro(as, XO_FISTPq, XOg_FISTPq, RID_ESP, 0); - emit_rma(as, XO_FADDq, XOg_FADDq, &as->J->k64[LJ_K64_M2P64]); - emit_sjcc(as, CC_NS, l_pop); - emit_rr(as, XO_TEST, hi, hi); /* Check if out-of-range (2^63). */ - } - emit_rmro(as, XO_MOV, hi, RID_ESP, 4); - if ((as->flags & JIT_F_SSE3)) { /* Truncation is easy with SSE3. */ - emit_rmro(as, XO_FISTTPq, XOg_FISTTPq, RID_ESP, 0); - } else { /* Otherwise set FPU rounding mode to truncate before the store. */ - emit_rmro(as, XO_FISTPq, XOg_FISTPq, RID_ESP, 0); - emit_rmro(as, XO_FLDCW, XOg_FLDCW, RID_ESP, 0); - emit_rmro(as, XO_MOVtow, lo, RID_ESP, 0); - emit_rmro(as, XO_ARITHw(XOg_OR), lo, RID_ESP, 0); - emit_loadi(as, lo, 0xc00); - emit_rmro(as, XO_FNSTCW, XOg_FNSTCW, RID_ESP, 0); - } - if (dt == IRT_U64) - emit_x87op(as, XI_FDUP); - emit_mrm(as, st == IRT_NUM ? XO_FLDq : XO_FLDd, - st == IRT_NUM ? XOg_FLDq: XOg_FLDd, - asm_fuseload(as, ir->op1, RSET_EMPTY)); -} - -static void asm_conv64(ASMState *as, IRIns *ir) -{ - if (irt_isfp(ir->t)) - asm_conv_fp_int64(as, ir); - else - asm_conv_int64_fp(as, ir); -} -#endif - -static void asm_strto(ASMState *as, IRIns *ir) -{ - /* Force a spill slot for the destination register (if any). */ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_strscan_num]; - IRRef args[2]; - RegSet drop = RSET_SCRATCH; - if ((drop & RSET_FPR) != RSET_FPR && ra_hasreg(ir->r)) - rset_set(drop, ir->r); /* WIN64 doesn't spill all FPRs. */ - ra_evictset(as, drop); - asm_guardcc(as, CC_E); - emit_rr(as, XO_TEST, RID_RET, RID_RET); /* Test return status. */ - args[0] = ir->op1; /* GCstr *str */ - args[1] = ASMREF_TMP1; /* TValue *n */ - asm_gencall(as, ci, args); - /* Store the result to the spill slot or temp slots. */ - emit_rmro(as, XO_LEA, ra_releasetmp(as, ASMREF_TMP1)|REX_64, - RID_ESP, sps_scale(ir->s)); -} - -/* -- Memory references --------------------------------------------------- */ - -/* Get pointer to TValue. */ -static void asm_tvptr(ASMState *as, Reg dest, IRRef ref) -{ - IRIns *ir = IR(ref); - if (irt_isnum(ir->t)) { - /* For numbers use the constant itself or a spill slot as a TValue. */ - if (irref_isk(ref)) - emit_loada(as, dest, ir_knum(ir)); - else - emit_rmro(as, XO_LEA, dest|REX_64, RID_ESP, ra_spill(as, ir)); - } else { - /* Otherwise use g->tmptv to hold the TValue. */ -#if LJ_GC64 - if (irref_isk(ref)) { - TValue k; - lj_ir_kvalue(as->J->L, &k, ir); - emit_movmroi(as, dest, 4, k.u32.hi); - emit_movmroi(as, dest, 0, k.u32.lo); - } else { - /* TODO: 64 bit store + 32 bit load-modify-store is suboptimal. */ - Reg src = ra_alloc1(as, ref, rset_exclude(RSET_GPR, dest)); - if (irt_is64(ir->t)) { - emit_u32(as, irt_toitype(ir->t) << 15); - emit_rmro(as, XO_ARITHi, XOg_OR, dest, 4); - } else { - /* Currently, no caller passes integers that might end up here. */ - emit_movmroi(as, dest, 4, (irt_toitype(ir->t) << 15)); - } - emit_movtomro(as, REX_64IR(ir, src), dest, 0); - } -#else - if (!irref_isk(ref)) { - Reg src = ra_alloc1(as, ref, rset_exclude(RSET_GPR, dest)); - emit_movtomro(as, REX_64IR(ir, src), dest, 0); - } else if (!irt_ispri(ir->t)) { - emit_movmroi(as, dest, 0, ir->i); - } - if (!(LJ_64 && irt_islightud(ir->t))) - emit_movmroi(as, dest, 4, irt_toitype(ir->t)); -#endif - emit_loada(as, dest, &J2G(as->J)->tmptv); - } -} - -static void asm_aref(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - asm_fusearef(as, ir, RSET_GPR); - if (!(as->mrm.idx == RID_NONE && as->mrm.ofs == 0)) - emit_mrm(as, XO_LEA, dest|REX_GC64, RID_MRM); - else if (as->mrm.base != dest) - emit_rr(as, XO_MOV, dest|REX_GC64, as->mrm.base); -} - -/* Inlined hash lookup. Specialized for key type and for const keys. -** The equivalent C code is: -** Node *n = hashkey(t, key); -** do { -** if (lj_obj_equal(&n->key, key)) return &n->val; -** } while ((n = nextnode(n))); -** return niltv(L); -*/ -static void asm_href(ASMState *as, IRIns *ir, IROp merge) -{ - RegSet allow = RSET_GPR; - int destused = ra_used(ir); - Reg dest = ra_dest(as, ir, allow); - Reg tab = ra_alloc1(as, ir->op1, rset_clear(allow, dest)); - Reg key = RID_NONE, tmp = RID_NONE; - IRIns *irkey = IR(ir->op2); - int isk = irref_isk(ir->op2); - IRType1 kt = irkey->t; - uint32_t khash; - MCLabel l_end, l_loop, l_next; - - if (!isk) { - rset_clear(allow, tab); - key = ra_alloc1(as, ir->op2, irt_isnum(kt) ? RSET_FPR : allow); - if (LJ_GC64 || !irt_isstr(kt)) - tmp = ra_scratch(as, rset_exclude(allow, key)); - } - - /* Key not found in chain: jump to exit (if merged) or load niltv. */ - l_end = emit_label(as); - if (merge == IR_NE) - asm_guardcc(as, CC_E); /* XI_JMP is not found by lj_asm_patchexit. */ - else if (destused) - emit_loada(as, dest, niltvg(J2G(as->J))); - - /* Follow hash chain until the end. */ - l_loop = emit_sjcc_label(as, CC_NZ); - emit_rr(as, XO_TEST, dest|REX_GC64, dest); - emit_rmro(as, XO_MOV, dest|REX_GC64, dest, offsetof(Node, next)); - l_next = emit_label(as); - - /* Type and value comparison. */ - if (merge == IR_EQ) - asm_guardcc(as, CC_E); - else - emit_sjcc(as, CC_E, l_end); - if (irt_isnum(kt)) { - if (isk) { - /* Assumes -0.0 is already canonicalized to +0.0. */ - emit_gmroi(as, XG_ARITHi(XOg_CMP), dest, offsetof(Node, key.u32.lo), - (int32_t)ir_knum(irkey)->u32.lo); - emit_sjcc(as, CC_NE, l_next); - emit_gmroi(as, XG_ARITHi(XOg_CMP), dest, offsetof(Node, key.u32.hi), - (int32_t)ir_knum(irkey)->u32.hi); - } else { - emit_sjcc(as, CC_P, l_next); - emit_rmro(as, XO_UCOMISD, key, dest, offsetof(Node, key.n)); - emit_sjcc(as, CC_AE, l_next); - /* The type check avoids NaN penalties and complaints from Valgrind. */ -#if LJ_64 && !LJ_GC64 - emit_u32(as, LJ_TISNUM); - emit_rmro(as, XO_ARITHi, XOg_CMP, dest, offsetof(Node, key.it)); -#else - emit_i8(as, LJ_TISNUM); - emit_rmro(as, XO_ARITHi8, XOg_CMP, dest, offsetof(Node, key.it)); -#endif - } -#if LJ_64 && !LJ_GC64 - } else if (irt_islightud(kt)) { - emit_rmro(as, XO_CMP, key|REX_64, dest, offsetof(Node, key.u64)); -#endif -#if LJ_GC64 - } else if (irt_isaddr(kt)) { - if (isk) { - TValue k; - k.u64 = ((uint64_t)irt_toitype(irkey->t) << 47) | irkey[1].tv.u64; - emit_gmroi(as, XG_ARITHi(XOg_CMP), dest, offsetof(Node, key.u32.lo), - k.u32.lo); - emit_sjcc(as, CC_NE, l_next); - emit_gmroi(as, XG_ARITHi(XOg_CMP), dest, offsetof(Node, key.u32.hi), - k.u32.hi); - } else { - emit_rmro(as, XO_CMP, tmp|REX_64, dest, offsetof(Node, key.u64)); - } - } else { - lua_assert(irt_ispri(kt) && !irt_isnil(kt)); - emit_u32(as, (irt_toitype(kt)<<15)|0x7fff); - emit_rmro(as, XO_ARITHi, XOg_CMP, dest, offsetof(Node, key.it)); -#else - } else { - if (!irt_ispri(kt)) { - lua_assert(irt_isaddr(kt)); - if (isk) - emit_gmroi(as, XG_ARITHi(XOg_CMP), dest, offsetof(Node, key.gcr), - ptr2addr(ir_kgc(irkey))); - else - emit_rmro(as, XO_CMP, key, dest, offsetof(Node, key.gcr)); - emit_sjcc(as, CC_NE, l_next); - } - lua_assert(!irt_isnil(kt)); - emit_i8(as, irt_toitype(kt)); - emit_rmro(as, XO_ARITHi8, XOg_CMP, dest, offsetof(Node, key.it)); -#endif - } - emit_sfixup(as, l_loop); - checkmclim(as); -#if LJ_GC64 - if (!isk && irt_isaddr(kt)) { - emit_rr(as, XO_OR, tmp|REX_64, key); - emit_loadu64(as, tmp, (uint64_t)irt_toitype(kt) << 47); - } -#endif - - /* Load main position relative to tab->node into dest. */ - khash = isk ? ir_khash(irkey) : 1; - if (khash == 0) { - emit_rmro(as, XO_MOV, dest|REX_GC64, tab, offsetof(GCtab, node)); - } else { - emit_rmro(as, XO_ARITH(XOg_ADD), dest|REX_GC64, tab, offsetof(GCtab,node)); - if ((as->flags & JIT_F_PREFER_IMUL)) { - emit_i8(as, sizeof(Node)); - emit_rr(as, XO_IMULi8, dest, dest); - } else { - emit_shifti(as, XOg_SHL, dest, 3); - emit_rmrxo(as, XO_LEA, dest, dest, dest, XM_SCALE2, 0); - } - if (isk) { - emit_gri(as, XG_ARITHi(XOg_AND), dest, (int32_t)khash); - emit_rmro(as, XO_MOV, dest, tab, offsetof(GCtab, hmask)); - } else if (irt_isstr(kt)) { - emit_rmro(as, XO_ARITH(XOg_AND), dest, key, offsetof(GCstr, hash)); - emit_rmro(as, XO_MOV, dest, tab, offsetof(GCtab, hmask)); - } else { /* Must match with hashrot() in lj_tab.c. */ - emit_rmro(as, XO_ARITH(XOg_AND), dest, tab, offsetof(GCtab, hmask)); - emit_rr(as, XO_ARITH(XOg_SUB), dest, tmp); - emit_shifti(as, XOg_ROL, tmp, HASH_ROT3); - emit_rr(as, XO_ARITH(XOg_XOR), dest, tmp); - emit_shifti(as, XOg_ROL, dest, HASH_ROT2); - emit_rr(as, XO_ARITH(XOg_SUB), tmp, dest); - emit_shifti(as, XOg_ROL, dest, HASH_ROT1); - emit_rr(as, XO_ARITH(XOg_XOR), tmp, dest); - if (irt_isnum(kt)) { - emit_rr(as, XO_ARITH(XOg_ADD), dest, dest); -#if LJ_64 - emit_shifti(as, XOg_SHR|REX_64, dest, 32); - emit_rr(as, XO_MOV, tmp, dest); - emit_rr(as, XO_MOVDto, key|REX_64, dest); -#else - emit_rmro(as, XO_MOV, dest, RID_ESP, ra_spill(as, irkey)+4); - emit_rr(as, XO_MOVDto, key, tmp); -#endif - } else { - emit_rr(as, XO_MOV, tmp, key); -#if LJ_GC64 - checkmclim(as); - emit_gri(as, XG_ARITHi(XOg_XOR), dest, irt_toitype(kt) << 15); - if ((as->flags & JIT_F_BMI2)) { - emit_i8(as, 32); - emit_mrm(as, XV_RORX|VEX_64, dest, key); - } else { - emit_shifti(as, XOg_SHR|REX_64, dest, 32); - emit_rr(as, XO_MOV, dest|REX_64, key|REX_64); - } -#else - emit_rmro(as, XO_LEA, dest, key, HASH_BIAS); -#endif - } - } - } -} - -static void asm_hrefk(ASMState *as, IRIns *ir) -{ - IRIns *kslot = IR(ir->op2); - IRIns *irkey = IR(kslot->op1); - int32_t ofs = (int32_t)(kslot->op2 * sizeof(Node)); - Reg dest = ra_used(ir) ? ra_dest(as, ir, RSET_GPR) : RID_NONE; - Reg node = ra_alloc1(as, ir->op1, RSET_GPR); -#if !LJ_64 - MCLabel l_exit; -#endif - lua_assert(ofs % sizeof(Node) == 0); - if (ra_hasreg(dest)) { - if (ofs != 0) { - if (dest == node && !(as->flags & JIT_F_LEA_AGU)) - emit_gri(as, XG_ARITHi(XOg_ADD), dest|REX_GC64, ofs); - else - emit_rmro(as, XO_LEA, dest|REX_GC64, node, ofs); - } else if (dest != node) { - emit_rr(as, XO_MOV, dest|REX_GC64, node); - } - } - asm_guardcc(as, CC_NE); -#if LJ_64 - if (!irt_ispri(irkey->t)) { - Reg key = ra_scratch(as, rset_exclude(RSET_GPR, node)); - emit_rmro(as, XO_CMP, key|REX_64, node, - ofs + (int32_t)offsetof(Node, key.u64)); - lua_assert(irt_isnum(irkey->t) || irt_isgcv(irkey->t)); - /* Assumes -0.0 is already canonicalized to +0.0. */ - emit_loadu64(as, key, irt_isnum(irkey->t) ? ir_knum(irkey)->u64 : -#if LJ_GC64 - ((uint64_t)irt_toitype(irkey->t) << 47) | - (uint64_t)ir_kgc(irkey)); -#else - ((uint64_t)irt_toitype(irkey->t) << 32) | - (uint64_t)(uint32_t)ptr2addr(ir_kgc(irkey))); -#endif - } else { - lua_assert(!irt_isnil(irkey->t)); -#if LJ_GC64 - emit_i32(as, (irt_toitype(irkey->t)<<15)|0x7fff); - emit_rmro(as, XO_ARITHi, XOg_CMP, node, - ofs + (int32_t)offsetof(Node, key.it)); -#else - emit_i8(as, irt_toitype(irkey->t)); - emit_rmro(as, XO_ARITHi8, XOg_CMP, node, - ofs + (int32_t)offsetof(Node, key.it)); -#endif - } -#else - l_exit = emit_label(as); - if (irt_isnum(irkey->t)) { - /* Assumes -0.0 is already canonicalized to +0.0. */ - emit_gmroi(as, XG_ARITHi(XOg_CMP), node, - ofs + (int32_t)offsetof(Node, key.u32.lo), - (int32_t)ir_knum(irkey)->u32.lo); - emit_sjcc(as, CC_NE, l_exit); - emit_gmroi(as, XG_ARITHi(XOg_CMP), node, - ofs + (int32_t)offsetof(Node, key.u32.hi), - (int32_t)ir_knum(irkey)->u32.hi); - } else { - if (!irt_ispri(irkey->t)) { - lua_assert(irt_isgcv(irkey->t)); - emit_gmroi(as, XG_ARITHi(XOg_CMP), node, - ofs + (int32_t)offsetof(Node, key.gcr), - ptr2addr(ir_kgc(irkey))); - emit_sjcc(as, CC_NE, l_exit); - } - lua_assert(!irt_isnil(irkey->t)); - emit_i8(as, irt_toitype(irkey->t)); - emit_rmro(as, XO_ARITHi8, XOg_CMP, node, - ofs + (int32_t)offsetof(Node, key.it)); - } -#endif -} - -static void asm_uref(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - if (irref_isk(ir->op1)) { - GCfunc *fn = ir_kfunc(IR(ir->op1)); - MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v; - emit_rma(as, XO_MOV, dest|REX_GC64, v); - } else { - Reg uv = ra_scratch(as, RSET_GPR); - Reg func = ra_alloc1(as, ir->op1, RSET_GPR); - if (ir->o == IR_UREFC) { - emit_rmro(as, XO_LEA, dest|REX_GC64, uv, offsetof(GCupval, tv)); - asm_guardcc(as, CC_NE); - emit_i8(as, 1); - emit_rmro(as, XO_ARITHib, XOg_CMP, uv, offsetof(GCupval, closed)); - } else { - emit_rmro(as, XO_MOV, dest|REX_GC64, uv, offsetof(GCupval, v)); - } - emit_rmro(as, XO_MOV, uv|REX_GC64, func, - (int32_t)offsetof(GCfuncL, uvptr) + - (int32_t)sizeof(MRef) * (int32_t)(ir->op2 >> 8)); - } -} - -static void asm_fref(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - asm_fusefref(as, ir, RSET_GPR); - emit_mrm(as, XO_LEA, dest, RID_MRM); -} - -static void asm_strref(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - asm_fusestrref(as, ir, RSET_GPR); - if (as->mrm.base == RID_NONE) - emit_loadi(as, dest, as->mrm.ofs); - else if (as->mrm.base == dest && as->mrm.idx == RID_NONE) - emit_gri(as, XG_ARITHi(XOg_ADD), dest|REX_GC64, as->mrm.ofs); - else - emit_mrm(as, XO_LEA, dest|REX_GC64, RID_MRM); -} - -/* -- Loads and stores ---------------------------------------------------- */ - -static void asm_fxload(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, irt_isfp(ir->t) ? RSET_FPR : RSET_GPR); - x86Op xo; - if (ir->o == IR_FLOAD) - asm_fusefref(as, ir, RSET_GPR); - else - asm_fusexref(as, ir->op1, RSET_GPR); - /* ir->op2 is ignored -- unaligned loads are ok on x86. */ - switch (irt_type(ir->t)) { - case IRT_I8: xo = XO_MOVSXb; break; - case IRT_U8: xo = XO_MOVZXb; break; - case IRT_I16: xo = XO_MOVSXw; break; - case IRT_U16: xo = XO_MOVZXw; break; - case IRT_NUM: xo = XO_MOVSD; break; - case IRT_FLOAT: xo = XO_MOVSS; break; - default: - if (LJ_64 && irt_is64(ir->t)) - dest |= REX_64; - else - lua_assert(irt_isint(ir->t) || irt_isu32(ir->t) || irt_isaddr(ir->t)); - xo = XO_MOV; - break; - } - emit_mrm(as, xo, dest, RID_MRM); -} - -#define asm_fload(as, ir) asm_fxload(as, ir) -#define asm_xload(as, ir) asm_fxload(as, ir) - -static void asm_fxstore(ASMState *as, IRIns *ir) -{ - RegSet allow = RSET_GPR; - Reg src = RID_NONE, osrc = RID_NONE; - int32_t k = 0; - if (ir->r == RID_SINK) - return; - /* The IRT_I16/IRT_U16 stores should never be simplified for constant - ** values since mov word [mem], imm16 has a length-changing prefix. - */ - if (irt_isi16(ir->t) || irt_isu16(ir->t) || irt_isfp(ir->t) || - !asm_isk32(as, ir->op2, &k)) { - RegSet allow8 = irt_isfp(ir->t) ? RSET_FPR : - (irt_isi8(ir->t) || irt_isu8(ir->t)) ? RSET_GPR8 : RSET_GPR; - src = osrc = ra_alloc1(as, ir->op2, allow8); - if (!LJ_64 && !rset_test(allow8, src)) { /* Already in wrong register. */ - rset_clear(allow, osrc); - src = ra_scratch(as, allow8); - } - rset_clear(allow, src); - } - if (ir->o == IR_FSTORE) { - asm_fusefref(as, IR(ir->op1), allow); - } else { - asm_fusexref(as, ir->op1, allow); - if (LJ_32 && ir->o == IR_HIOP) as->mrm.ofs += 4; - } - if (ra_hasreg(src)) { - x86Op xo; - switch (irt_type(ir->t)) { - case IRT_I8: case IRT_U8: xo = XO_MOVtob; src |= FORCE_REX; break; - case IRT_I16: case IRT_U16: xo = XO_MOVtow; break; - case IRT_NUM: xo = XO_MOVSDto; break; - case IRT_FLOAT: xo = XO_MOVSSto; break; -#if LJ_64 && !LJ_GC64 - case IRT_LIGHTUD: lua_assert(0); /* NYI: mask 64 bit lightuserdata. */ -#endif - default: - if (LJ_64 && irt_is64(ir->t)) - src |= REX_64; - else - lua_assert(irt_isint(ir->t) || irt_isu32(ir->t) || irt_isaddr(ir->t)); - xo = XO_MOVto; - break; - } - emit_mrm(as, xo, src, RID_MRM); - if (!LJ_64 && src != osrc) { - ra_noweak(as, osrc); - emit_rr(as, XO_MOV, src, osrc); - } - } else { - if (irt_isi8(ir->t) || irt_isu8(ir->t)) { - emit_i8(as, k); - emit_mrm(as, XO_MOVmib, 0, RID_MRM); - } else { - lua_assert(irt_is64(ir->t) || irt_isint(ir->t) || irt_isu32(ir->t) || - irt_isaddr(ir->t)); - emit_i32(as, k); - emit_mrm(as, XO_MOVmi, REX_64IR(ir, 0), RID_MRM); - } - } -} - -#define asm_fstore(as, ir) asm_fxstore(as, ir) -#define asm_xstore(as, ir) asm_fxstore(as, ir) - -#if LJ_64 && !LJ_GC64 -static Reg asm_load_lightud64(ASMState *as, IRIns *ir, int typecheck) -{ - if (ra_used(ir) || typecheck) { - Reg dest = ra_dest(as, ir, RSET_GPR); - if (typecheck) { - Reg tmp = ra_scratch(as, rset_exclude(RSET_GPR, dest)); - asm_guardcc(as, CC_NE); - emit_i8(as, -2); - emit_rr(as, XO_ARITHi8, XOg_CMP, tmp); - emit_shifti(as, XOg_SAR|REX_64, tmp, 47); - emit_rr(as, XO_MOV, tmp|REX_64, dest); - } - return dest; - } else { - return RID_NONE; - } -} -#endif - -static void asm_ahuvload(ASMState *as, IRIns *ir) -{ -#if LJ_GC64 - Reg tmp = RID_NONE; -#endif - lua_assert(irt_isnum(ir->t) || irt_ispri(ir->t) || irt_isaddr(ir->t) || - (LJ_DUALNUM && irt_isint(ir->t))); -#if LJ_64 && !LJ_GC64 - if (irt_islightud(ir->t)) { - Reg dest = asm_load_lightud64(as, ir, 1); - if (ra_hasreg(dest)) { - asm_fuseahuref(as, ir->op1, RSET_GPR); - emit_mrm(as, XO_MOV, dest|REX_64, RID_MRM); - } - return; - } else -#endif - if (ra_used(ir)) { - RegSet allow = irt_isnum(ir->t) ? RSET_FPR : RSET_GPR; - Reg dest = ra_dest(as, ir, allow); - asm_fuseahuref(as, ir->op1, RSET_GPR); -#if LJ_GC64 - if (irt_isaddr(ir->t)) { - emit_shifti(as, XOg_SHR|REX_64, dest, 17); - asm_guardcc(as, CC_NE); - emit_i8(as, irt_toitype(ir->t)); - emit_rr(as, XO_ARITHi8, XOg_CMP, dest); - emit_i8(as, XI_O16); - if ((as->flags & JIT_F_BMI2)) { - emit_i8(as, 47); - emit_mrm(as, XV_RORX|VEX_64, dest, RID_MRM); - } else { - emit_shifti(as, XOg_ROR|REX_64, dest, 47); - emit_mrm(as, XO_MOV, dest|REX_64, RID_MRM); - } - return; - } else -#endif - emit_mrm(as, dest < RID_MAX_GPR ? XO_MOV : XO_MOVSD, dest, RID_MRM); - } else { - RegSet gpr = RSET_GPR; -#if LJ_GC64 - if (irt_isaddr(ir->t)) { - tmp = ra_scratch(as, RSET_GPR); - gpr = rset_exclude(gpr, tmp); - } -#endif - asm_fuseahuref(as, ir->op1, gpr); - } - /* Always do the type check, even if the load result is unused. */ - as->mrm.ofs += 4; - asm_guardcc(as, irt_isnum(ir->t) ? CC_AE : CC_NE); - if (LJ_64 && irt_type(ir->t) >= IRT_NUM) { - lua_assert(irt_isinteger(ir->t) || irt_isnum(ir->t)); -#if LJ_GC64 - emit_u32(as, LJ_TISNUM << 15); -#else - emit_u32(as, LJ_TISNUM); -#endif - emit_mrm(as, XO_ARITHi, XOg_CMP, RID_MRM); -#if LJ_GC64 - } else if (irt_isaddr(ir->t)) { - as->mrm.ofs -= 4; - emit_i8(as, irt_toitype(ir->t)); - emit_mrm(as, XO_ARITHi8, XOg_CMP, tmp); - emit_shifti(as, XOg_SAR|REX_64, tmp, 47); - emit_mrm(as, XO_MOV, tmp|REX_64, RID_MRM); - } else if (irt_isnil(ir->t)) { - as->mrm.ofs -= 4; - emit_i8(as, -1); - emit_mrm(as, XO_ARITHi8, XOg_CMP|REX_64, RID_MRM); - } else { - emit_u32(as, (irt_toitype(ir->t) << 15) | 0x7fff); - emit_mrm(as, XO_ARITHi, XOg_CMP, RID_MRM); -#else - } else { - emit_i8(as, irt_toitype(ir->t)); - emit_mrm(as, XO_ARITHi8, XOg_CMP, RID_MRM); -#endif - } -} - -static void asm_ahustore(ASMState *as, IRIns *ir) -{ - if (ir->r == RID_SINK) - return; - if (irt_isnum(ir->t)) { - Reg src = ra_alloc1(as, ir->op2, RSET_FPR); - asm_fuseahuref(as, ir->op1, RSET_GPR); - emit_mrm(as, XO_MOVSDto, src, RID_MRM); -#if LJ_64 && !LJ_GC64 - } else if (irt_islightud(ir->t)) { - Reg src = ra_alloc1(as, ir->op2, RSET_GPR); - asm_fuseahuref(as, ir->op1, rset_exclude(RSET_GPR, src)); - emit_mrm(as, XO_MOVto, src|REX_64, RID_MRM); -#endif -#if LJ_GC64 - } else if (irref_isk(ir->op2)) { - TValue k; - lj_ir_kvalue(as->J->L, &k, IR(ir->op2)); - asm_fuseahuref(as, ir->op1, RSET_GPR); - if (tvisnil(&k)) { - emit_i32(as, -1); - emit_mrm(as, XO_MOVmi, REX_64, RID_MRM); - } else { - emit_u32(as, k.u32.lo); - emit_mrm(as, XO_MOVmi, 0, RID_MRM); - as->mrm.ofs += 4; - emit_u32(as, k.u32.hi); - emit_mrm(as, XO_MOVmi, 0, RID_MRM); - } -#endif - } else { - IRIns *irr = IR(ir->op2); - RegSet allow = RSET_GPR; - Reg src = RID_NONE; - if (!irref_isk(ir->op2)) { - src = ra_alloc1(as, ir->op2, allow); - rset_clear(allow, src); - } - asm_fuseahuref(as, ir->op1, allow); - if (ra_hasreg(src)) { -#if LJ_GC64 - if (!(LJ_DUALNUM && irt_isinteger(ir->t))) { - /* TODO: 64 bit store + 32 bit load-modify-store is suboptimal. */ - as->mrm.ofs += 4; - emit_u32(as, irt_toitype(ir->t) << 15); - emit_mrm(as, XO_ARITHi, XOg_OR, RID_MRM); - as->mrm.ofs -= 4; - emit_mrm(as, XO_MOVto, src|REX_64, RID_MRM); - return; - } -#endif - emit_mrm(as, XO_MOVto, src, RID_MRM); - } else if (!irt_ispri(irr->t)) { - lua_assert(irt_isaddr(ir->t) || (LJ_DUALNUM && irt_isinteger(ir->t))); - emit_i32(as, irr->i); - emit_mrm(as, XO_MOVmi, 0, RID_MRM); - } - as->mrm.ofs += 4; -#if LJ_GC64 - lua_assert(LJ_DUALNUM && irt_isinteger(ir->t)); - emit_i32(as, LJ_TNUMX << 15); -#else - emit_i32(as, (int32_t)irt_toitype(ir->t)); -#endif - emit_mrm(as, XO_MOVmi, 0, RID_MRM); - } -} - -static void asm_sload(ASMState *as, IRIns *ir) -{ - int32_t ofs = 8*((int32_t)ir->op1-1-LJ_FR2) + - (!LJ_FR2 && (ir->op2 & IRSLOAD_FRAME) ? 4 : 0); - IRType1 t = ir->t; - Reg base; - lua_assert(!(ir->op2 & IRSLOAD_PARENT)); /* Handled by asm_head_side(). */ - lua_assert(irt_isguard(t) || !(ir->op2 & IRSLOAD_TYPECHECK)); - lua_assert(LJ_DUALNUM || - !irt_isint(t) || (ir->op2 & (IRSLOAD_CONVERT|IRSLOAD_FRAME))); - if ((ir->op2 & IRSLOAD_CONVERT) && irt_isguard(t) && irt_isint(t)) { - Reg left = ra_scratch(as, RSET_FPR); - asm_tointg(as, ir, left); /* Frees dest reg. Do this before base alloc. */ - base = ra_alloc1(as, REF_BASE, RSET_GPR); - emit_rmro(as, XO_MOVSD, left, base, ofs); - t.irt = IRT_NUM; /* Continue with a regular number type check. */ -#if LJ_64 && !LJ_GC64 - } else if (irt_islightud(t)) { - Reg dest = asm_load_lightud64(as, ir, (ir->op2 & IRSLOAD_TYPECHECK)); - if (ra_hasreg(dest)) { - base = ra_alloc1(as, REF_BASE, RSET_GPR); - emit_rmro(as, XO_MOV, dest|REX_64, base, ofs); - } - return; -#endif - } else if (ra_used(ir)) { - RegSet allow = irt_isnum(t) ? RSET_FPR : RSET_GPR; - Reg dest = ra_dest(as, ir, allow); - base = ra_alloc1(as, REF_BASE, RSET_GPR); - lua_assert(irt_isnum(t) || irt_isint(t) || irt_isaddr(t)); - if ((ir->op2 & IRSLOAD_CONVERT)) { - t.irt = irt_isint(t) ? IRT_NUM : IRT_INT; /* Check for original type. */ - emit_rmro(as, irt_isint(t) ? XO_CVTSI2SD : XO_CVTTSD2SI, dest, base, ofs); - } else { -#if LJ_GC64 - if (irt_isaddr(t)) { - /* LJ_GC64 type check + tag removal without BMI2 and with BMI2: - ** - ** mov r64, [addr] rorx r64, [addr], 47 - ** ror r64, 47 - ** cmp r16, itype cmp r16, itype - ** jne ->exit jne ->exit - ** shr r64, 16 shr r64, 16 - */ - emit_shifti(as, XOg_SHR|REX_64, dest, 17); - if ((ir->op2 & IRSLOAD_TYPECHECK)) { - asm_guardcc(as, CC_NE); - emit_i8(as, irt_toitype(t)); - emit_rr(as, XO_ARITHi8, XOg_CMP, dest); - emit_i8(as, XI_O16); - } - if ((as->flags & JIT_F_BMI2)) { - emit_i8(as, 47); - emit_rmro(as, XV_RORX|VEX_64, dest, base, ofs); - } else { - if ((ir->op2 & IRSLOAD_TYPECHECK)) - emit_shifti(as, XOg_ROR|REX_64, dest, 47); - else - emit_shifti(as, XOg_SHL|REX_64, dest, 17); - emit_rmro(as, XO_MOV, dest|REX_64, base, ofs); - } - return; - } else -#endif - emit_rmro(as, irt_isnum(t) ? XO_MOVSD : XO_MOV, dest, base, ofs); - } - } else { - if (!(ir->op2 & IRSLOAD_TYPECHECK)) - return; /* No type check: avoid base alloc. */ - base = ra_alloc1(as, REF_BASE, RSET_GPR); - } - if ((ir->op2 & IRSLOAD_TYPECHECK)) { - /* Need type check, even if the load result is unused. */ - asm_guardcc(as, irt_isnum(t) ? CC_AE : CC_NE); - if (LJ_64 && irt_type(t) >= IRT_NUM) { - lua_assert(irt_isinteger(t) || irt_isnum(t)); -#if LJ_GC64 - emit_u32(as, LJ_TISNUM << 15); -#else - emit_u32(as, LJ_TISNUM); -#endif - emit_rmro(as, XO_ARITHi, XOg_CMP, base, ofs+4); -#if LJ_GC64 - } else if (irt_isnil(t)) { - /* LJ_GC64 type check for nil: - ** - ** cmp qword [addr], -1 - ** jne ->exit - */ - emit_i8(as, -1); - emit_rmro(as, XO_ARITHi8, XOg_CMP|REX_64, base, ofs); - } else if (irt_ispri(t)) { - emit_u32(as, (irt_toitype(t) << 15) | 0x7fff); - emit_rmro(as, XO_ARITHi, XOg_CMP, base, ofs+4); - } else { - /* LJ_GC64 type check only: - ** - ** mov r64, [addr] - ** sar r64, 47 - ** cmp r32, itype - ** jne ->exit - */ - Reg tmp = ra_scratch(as, rset_exclude(RSET_GPR, base)); - emit_i8(as, irt_toitype(t)); - emit_rr(as, XO_ARITHi8, XOg_CMP, tmp); - emit_shifti(as, XOg_SAR|REX_64, tmp, 47); - emit_rmro(as, XO_MOV, tmp|REX_64, base, ofs); -#else - } else { - emit_i8(as, irt_toitype(t)); - emit_rmro(as, XO_ARITHi8, XOg_CMP, base, ofs+4); -#endif - } - } -} - -/* -- Allocations --------------------------------------------------------- */ - -#if LJ_HASFFI -static void asm_cnew(ASMState *as, IRIns *ir) -{ - CTState *cts = ctype_ctsG(J2G(as->J)); - CTypeID id = (CTypeID)IR(ir->op1)->i; - CTSize sz; - CTInfo info = lj_ctype_info(cts, id, &sz); - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_mem_newgco]; - IRRef args[4]; - lua_assert(sz != CTSIZE_INVALID || (ir->o == IR_CNEW && ir->op2 != REF_NIL)); - - as->gcsteps++; - asm_setupresult(as, ir, ci); /* GCcdata * */ - - /* Initialize immutable cdata object. */ - if (ir->o == IR_CNEWI) { - RegSet allow = (RSET_GPR & ~RSET_SCRATCH); -#if LJ_64 - Reg r64 = sz == 8 ? REX_64 : 0; - if (irref_isk(ir->op2)) { - IRIns *irk = IR(ir->op2); - uint64_t k = (irk->o == IR_KINT64 || - (LJ_GC64 && (irk->o == IR_KPTR || irk->o == IR_KKPTR))) ? - ir_k64(irk)->u64 : (uint64_t)(uint32_t)irk->i; - if (sz == 4 || checki32((int64_t)k)) { - emit_i32(as, (int32_t)k); - emit_rmro(as, XO_MOVmi, r64, RID_RET, sizeof(GCcdata)); - } else { - emit_movtomro(as, RID_ECX + r64, RID_RET, sizeof(GCcdata)); - emit_loadu64(as, RID_ECX, k); - } - } else { - Reg r = ra_alloc1(as, ir->op2, allow); - emit_movtomro(as, r + r64, RID_RET, sizeof(GCcdata)); - } -#else - int32_t ofs = sizeof(GCcdata); - if (sz == 8) { - ofs += 4; ir++; - lua_assert(ir->o == IR_HIOP); - } - do { - if (irref_isk(ir->op2)) { - emit_movmroi(as, RID_RET, ofs, IR(ir->op2)->i); - } else { - Reg r = ra_alloc1(as, ir->op2, allow); - emit_movtomro(as, r, RID_RET, ofs); - rset_clear(allow, r); - } - if (ofs == sizeof(GCcdata)) break; - ofs -= 4; ir--; - } while (1); -#endif - lua_assert(sz == 4 || sz == 8); - } else if (ir->op2 != REF_NIL) { /* Create VLA/VLS/aligned cdata. */ - ci = &lj_ir_callinfo[IRCALL_lj_cdata_newv]; - args[0] = ASMREF_L; /* lua_State *L */ - args[1] = ir->op1; /* CTypeID id */ - args[2] = ir->op2; /* CTSize sz */ - args[3] = ASMREF_TMP1; /* CTSize align */ - asm_gencall(as, ci, args); - emit_loadi(as, ra_releasetmp(as, ASMREF_TMP1), (int32_t)ctype_align(info)); - return; - } - - /* Combine initialization of marked, gct and ctypeid. */ - emit_movtomro(as, RID_ECX, RID_RET, offsetof(GCcdata, marked)); - emit_gri(as, XG_ARITHi(XOg_OR), RID_ECX, - (int32_t)((~LJ_TCDATA<<8)+(id<<16))); - emit_gri(as, XG_ARITHi(XOg_AND), RID_ECX, LJ_GC_WHITES); - emit_opgl(as, XO_MOVZXb, RID_ECX, gc.currentwhite); - - args[0] = ASMREF_L; /* lua_State *L */ - args[1] = ASMREF_TMP1; /* MSize size */ - asm_gencall(as, ci, args); - emit_loadi(as, ra_releasetmp(as, ASMREF_TMP1), (int32_t)(sz+sizeof(GCcdata))); -} -#else -#define asm_cnew(as, ir) ((void)0) -#endif - -/* -- Write barriers ------------------------------------------------------ */ - -static void asm_tbar(ASMState *as, IRIns *ir) -{ - Reg tab = ra_alloc1(as, ir->op1, RSET_GPR); - Reg tmp = ra_scratch(as, rset_exclude(RSET_GPR, tab)); - MCLabel l_end = emit_label(as); - emit_movtomro(as, tmp|REX_GC64, tab, offsetof(GCtab, gclist)); - emit_setgl(as, tab, gc.grayagain); - emit_getgl(as, tmp, gc.grayagain); - emit_i8(as, ~LJ_GC_BLACK); - emit_rmro(as, XO_ARITHib, XOg_AND, tab, offsetof(GCtab, marked)); - emit_sjcc(as, CC_Z, l_end); - emit_i8(as, LJ_GC_BLACK); - emit_rmro(as, XO_GROUP3b, XOg_TEST, tab, offsetof(GCtab, marked)); -} - -static void asm_obar(ASMState *as, IRIns *ir) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_gc_barrieruv]; - IRRef args[2]; - MCLabel l_end; - Reg obj; - /* No need for other object barriers (yet). */ - lua_assert(IR(ir->op1)->o == IR_UREFC); - ra_evictset(as, RSET_SCRATCH); - l_end = emit_label(as); - args[0] = ASMREF_TMP1; /* global_State *g */ - args[1] = ir->op1; /* TValue *tv */ - asm_gencall(as, ci, args); - emit_loada(as, ra_releasetmp(as, ASMREF_TMP1), J2G(as->J)); - obj = IR(ir->op1)->r; - emit_sjcc(as, CC_Z, l_end); - emit_i8(as, LJ_GC_WHITES); - if (irref_isk(ir->op2)) { - GCobj *vp = ir_kgc(IR(ir->op2)); - emit_rma(as, XO_GROUP3b, XOg_TEST, &vp->gch.marked); - } else { - Reg val = ra_alloc1(as, ir->op2, rset_exclude(RSET_SCRATCH&RSET_GPR, obj)); - emit_rmro(as, XO_GROUP3b, XOg_TEST, val, (int32_t)offsetof(GChead, marked)); - } - emit_sjcc(as, CC_Z, l_end); - emit_i8(as, LJ_GC_BLACK); - emit_rmro(as, XO_GROUP3b, XOg_TEST, obj, - (int32_t)offsetof(GCupval, marked)-(int32_t)offsetof(GCupval, tv)); -} - -/* -- FP/int arithmetic and logic operations ------------------------------ */ - -/* Load reference onto x87 stack. Force a spill to memory if needed. */ -static void asm_x87load(ASMState *as, IRRef ref) -{ - IRIns *ir = IR(ref); - if (ir->o == IR_KNUM) { - cTValue *tv = ir_knum(ir); - if (tvispzero(tv)) /* Use fldz only for +0. */ - emit_x87op(as, XI_FLDZ); - else if (tvispone(tv)) - emit_x87op(as, XI_FLD1); - else - emit_rma(as, XO_FLDq, XOg_FLDq, tv); - } else if (ir->o == IR_CONV && ir->op2 == IRCONV_NUM_INT && !ra_used(ir) && - !irref_isk(ir->op1) && mayfuse(as, ir->op1)) { - IRIns *iri = IR(ir->op1); - emit_rmro(as, XO_FILDd, XOg_FILDd, RID_ESP, ra_spill(as, iri)); - } else { - emit_mrm(as, XO_FLDq, XOg_FLDq, asm_fuseload(as, ref, RSET_EMPTY)); - } -} - -static void asm_fpmath(ASMState *as, IRIns *ir) -{ - IRFPMathOp fpm = (IRFPMathOp)ir->op2; - if (fpm == IRFPM_SQRT) { - Reg dest = ra_dest(as, ir, RSET_FPR); - Reg left = asm_fuseload(as, ir->op1, RSET_FPR); - emit_mrm(as, XO_SQRTSD, dest, left); - } else if (fpm <= IRFPM_TRUNC) { - if (as->flags & JIT_F_SSE4_1) { /* SSE4.1 has a rounding instruction. */ - Reg dest = ra_dest(as, ir, RSET_FPR); - Reg left = asm_fuseload(as, ir->op1, RSET_FPR); - /* ROUNDSD has a 4-byte opcode which doesn't fit in x86Op. - ** Let's pretend it's a 3-byte opcode, and compensate afterwards. - ** This is atrocious, but the alternatives are much worse. - */ - /* Round down/up/trunc == 1001/1010/1011. */ - emit_i8(as, 0x09 + fpm); - emit_mrm(as, XO_ROUNDSD, dest, left); - if (LJ_64 && as->mcp[1] != (MCode)(XO_ROUNDSD >> 16)) { - as->mcp[0] = as->mcp[1]; as->mcp[1] = 0x0f; /* Swap 0F and REX. */ - } - *--as->mcp = 0x66; /* 1st byte of ROUNDSD opcode. */ - } else { /* Call helper functions for SSE2 variant. */ - /* The modified regs must match with the *.dasc implementation. */ - RegSet drop = RSET_RANGE(RID_XMM0, RID_XMM3+1)|RID2RSET(RID_EAX); - if (ra_hasreg(ir->r)) - rset_clear(drop, ir->r); /* Dest reg handled below. */ - ra_evictset(as, drop); - ra_destreg(as, ir, RID_XMM0); - emit_call(as, fpm == IRFPM_FLOOR ? lj_vm_floor_sse : - fpm == IRFPM_CEIL ? lj_vm_ceil_sse : lj_vm_trunc_sse); - ra_left(as, RID_XMM0, ir->op1); - } - } else if (fpm == IRFPM_EXP2 && asm_fpjoin_pow(as, ir)) { - /* Rejoined to pow(). */ - } else { - asm_callid(as, ir, IRCALL_lj_vm_floor + fpm); - } -} - -#define asm_atan2(as, ir) asm_callid(as, ir, IRCALL_atan2) - -static void asm_ldexp(ASMState *as, IRIns *ir) -{ - int32_t ofs = sps_scale(ir->s); /* Use spill slot or temp slots. */ - Reg dest = ir->r; - if (ra_hasreg(dest)) { - ra_free(as, dest); - ra_modified(as, dest); - emit_rmro(as, XO_MOVSD, dest, RID_ESP, ofs); - } - emit_rmro(as, XO_FSTPq, XOg_FSTPq, RID_ESP, ofs); - emit_x87op(as, XI_FPOP1); - emit_x87op(as, XI_FSCALE); - asm_x87load(as, ir->op1); - asm_x87load(as, ir->op2); -} - -static void asm_fppowi(ASMState *as, IRIns *ir) -{ - /* The modified regs must match with the *.dasc implementation. */ - RegSet drop = RSET_RANGE(RID_XMM0, RID_XMM1+1)|RID2RSET(RID_EAX); - if (ra_hasreg(ir->r)) - rset_clear(drop, ir->r); /* Dest reg handled below. */ - ra_evictset(as, drop); - ra_destreg(as, ir, RID_XMM0); - emit_call(as, lj_vm_powi_sse); - ra_left(as, RID_XMM0, ir->op1); - ra_left(as, RID_EAX, ir->op2); -} - -static void asm_pow(ASMState *as, IRIns *ir) -{ -#if LJ_64 && LJ_HASFFI - if (!irt_isnum(ir->t)) - asm_callid(as, ir, irt_isi64(ir->t) ? IRCALL_lj_carith_powi64 : - IRCALL_lj_carith_powu64); - else -#endif - asm_fppowi(as, ir); -} - -static int asm_swapops(ASMState *as, IRIns *ir) -{ - IRIns *irl = IR(ir->op1); - IRIns *irr = IR(ir->op2); - lua_assert(ra_noreg(irr->r)); - if (!irm_iscomm(lj_ir_mode[ir->o])) - return 0; /* Can't swap non-commutative operations. */ - if (irref_isk(ir->op2)) - return 0; /* Don't swap constants to the left. */ - if (ra_hasreg(irl->r)) - return 1; /* Swap if left already has a register. */ - if (ra_samehint(ir->r, irr->r)) - return 1; /* Swap if dest and right have matching hints. */ - if (as->curins > as->loopref) { /* In variant part? */ - if (ir->op2 < as->loopref && !irt_isphi(irr->t)) - return 0; /* Keep invariants on the right. */ - if (ir->op1 < as->loopref && !irt_isphi(irl->t)) - return 1; /* Swap invariants to the right. */ - } - if (opisfusableload(irl->o)) - return 1; /* Swap fusable loads to the right. */ - return 0; /* Otherwise don't swap. */ -} - -static void asm_fparith(ASMState *as, IRIns *ir, x86Op xo) -{ - IRRef lref = ir->op1; - IRRef rref = ir->op2; - RegSet allow = RSET_FPR; - Reg dest; - Reg right = IR(rref)->r; - if (ra_hasreg(right)) { - rset_clear(allow, right); - ra_noweak(as, right); - } - dest = ra_dest(as, ir, allow); - if (lref == rref) { - right = dest; - } else if (ra_noreg(right)) { - if (asm_swapops(as, ir)) { - IRRef tmp = lref; lref = rref; rref = tmp; - } - right = asm_fuseload(as, rref, rset_clear(allow, dest)); - } - emit_mrm(as, xo, dest, right); - ra_left(as, dest, lref); -} - -static void asm_intarith(ASMState *as, IRIns *ir, x86Arith xa) -{ - IRRef lref = ir->op1; - IRRef rref = ir->op2; - RegSet allow = RSET_GPR; - Reg dest, right; - int32_t k = 0; - if (as->flagmcp == as->mcp) { /* Drop test r,r instruction. */ - MCode *p = as->mcp + ((LJ_64 && *as->mcp < XI_TESTb) ? 3 : 2); - if ((p[1] & 15) < 14) { - if ((p[1] & 15) >= 12) p[1] -= 4; /* L <->S, NL <-> NS */ - as->flagmcp = NULL; - as->mcp = p; - } /* else: cannot transform LE/NLE to cc without use of OF. */ - } - right = IR(rref)->r; - if (ra_hasreg(right)) { - rset_clear(allow, right); - ra_noweak(as, right); - } - dest = ra_dest(as, ir, allow); - if (lref == rref) { - right = dest; - } else if (ra_noreg(right) && !asm_isk32(as, rref, &k)) { - if (asm_swapops(as, ir)) { - IRRef tmp = lref; lref = rref; rref = tmp; - } - right = asm_fuseloadm(as, rref, rset_clear(allow, dest), irt_is64(ir->t)); - } - if (irt_isguard(ir->t)) /* For IR_ADDOV etc. */ - asm_guardcc(as, CC_O); - if (xa != XOg_X_IMUL) { - if (ra_hasreg(right)) - emit_mrm(as, XO_ARITH(xa), REX_64IR(ir, dest), right); - else - emit_gri(as, XG_ARITHi(xa), REX_64IR(ir, dest), k); - } else if (ra_hasreg(right)) { /* IMUL r, mrm. */ - emit_mrm(as, XO_IMUL, REX_64IR(ir, dest), right); - } else { /* IMUL r, r, k. */ - /* NYI: use lea/shl/add/sub (FOLD only does 2^k) depending on CPU. */ - Reg left = asm_fuseloadm(as, lref, RSET_GPR, irt_is64(ir->t)); - x86Op xo; - if (checki8(k)) { emit_i8(as, k); xo = XO_IMULi8; - } else { emit_i32(as, k); xo = XO_IMULi; } - emit_mrm(as, xo, REX_64IR(ir, dest), left); - return; - } - ra_left(as, dest, lref); -} - -/* LEA is really a 4-operand ADD with an independent destination register, -** up to two source registers and an immediate. One register can be scaled -** by 1, 2, 4 or 8. This can be used to avoid moves or to fuse several -** instructions. -** -** Currently only a few common cases are supported: -** - 3-operand ADD: y = a+b; y = a+k with a and b already allocated -** - Left ADD fusion: y = (a+b)+k; y = (a+k)+b -** - Right ADD fusion: y = a+(b+k) -** The ommited variants have already been reduced by FOLD. -** -** There are more fusion opportunities, like gathering shifts or joining -** common references. But these are probably not worth the trouble, since -** array indexing is not decomposed and already makes use of all fields -** of the ModRM operand. -*/ -static int asm_lea(ASMState *as, IRIns *ir) -{ - IRIns *irl = IR(ir->op1); - IRIns *irr = IR(ir->op2); - RegSet allow = RSET_GPR; - Reg dest; - as->mrm.base = as->mrm.idx = RID_NONE; - as->mrm.scale = XM_SCALE1; - as->mrm.ofs = 0; - if (ra_hasreg(irl->r)) { - rset_clear(allow, irl->r); - ra_noweak(as, irl->r); - as->mrm.base = irl->r; - if (irref_isk(ir->op2) || ra_hasreg(irr->r)) { - /* The PHI renaming logic does a better job in some cases. */ - if (ra_hasreg(ir->r) && - ((irt_isphi(irl->t) && as->phireg[ir->r] == ir->op1) || - (irt_isphi(irr->t) && as->phireg[ir->r] == ir->op2))) - return 0; - if (irref_isk(ir->op2)) { - as->mrm.ofs = irr->i; - } else { - rset_clear(allow, irr->r); - ra_noweak(as, irr->r); - as->mrm.idx = irr->r; - } - } else if (irr->o == IR_ADD && mayfuse(as, ir->op2) && - irref_isk(irr->op2)) { - Reg idx = ra_alloc1(as, irr->op1, allow); - rset_clear(allow, idx); - as->mrm.idx = (uint8_t)idx; - as->mrm.ofs = IR(irr->op2)->i; - } else { - return 0; - } - } else if (ir->op1 != ir->op2 && irl->o == IR_ADD && mayfuse(as, ir->op1) && - (irref_isk(ir->op2) || irref_isk(irl->op2))) { - Reg idx, base = ra_alloc1(as, irl->op1, allow); - rset_clear(allow, base); - as->mrm.base = (uint8_t)base; - if (irref_isk(ir->op2)) { - as->mrm.ofs = irr->i; - idx = ra_alloc1(as, irl->op2, allow); - } else { - as->mrm.ofs = IR(irl->op2)->i; - idx = ra_alloc1(as, ir->op2, allow); - } - rset_clear(allow, idx); - as->mrm.idx = (uint8_t)idx; - } else { - return 0; - } - dest = ra_dest(as, ir, allow); - emit_mrm(as, XO_LEA, dest, RID_MRM); - return 1; /* Success. */ -} - -static void asm_add(ASMState *as, IRIns *ir) -{ - if (irt_isnum(ir->t)) - asm_fparith(as, ir, XO_ADDSD); - else if ((as->flags & JIT_F_LEA_AGU) || as->flagmcp == as->mcp || - irt_is64(ir->t) || !asm_lea(as, ir)) - asm_intarith(as, ir, XOg_ADD); -} - -static void asm_sub(ASMState *as, IRIns *ir) -{ - if (irt_isnum(ir->t)) - asm_fparith(as, ir, XO_SUBSD); - else /* Note: no need for LEA trick here. i-k is encoded as i+(-k). */ - asm_intarith(as, ir, XOg_SUB); -} - -static void asm_mul(ASMState *as, IRIns *ir) -{ - if (irt_isnum(ir->t)) - asm_fparith(as, ir, XO_MULSD); - else - asm_intarith(as, ir, XOg_X_IMUL); -} - -static void asm_div(ASMState *as, IRIns *ir) -{ -#if LJ_64 && LJ_HASFFI - if (!irt_isnum(ir->t)) - asm_callid(as, ir, irt_isi64(ir->t) ? IRCALL_lj_carith_divi64 : - IRCALL_lj_carith_divu64); - else -#endif - asm_fparith(as, ir, XO_DIVSD); -} - -static void asm_mod(ASMState *as, IRIns *ir) -{ -#if LJ_64 && LJ_HASFFI - if (!irt_isint(ir->t)) - asm_callid(as, ir, irt_isi64(ir->t) ? IRCALL_lj_carith_modi64 : - IRCALL_lj_carith_modu64); - else -#endif - asm_callid(as, ir, IRCALL_lj_vm_modi); -} - -static void asm_neg_not(ASMState *as, IRIns *ir, x86Group3 xg) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - emit_rr(as, XO_GROUP3, REX_64IR(ir, xg), dest); - ra_left(as, dest, ir->op1); -} - -static void asm_neg(ASMState *as, IRIns *ir) -{ - if (irt_isnum(ir->t)) - asm_fparith(as, ir, XO_XORPS); - else - asm_neg_not(as, ir, XOg_NEG); -} - -#define asm_abs(as, ir) asm_fparith(as, ir, XO_ANDPS) - -static void asm_intmin_max(ASMState *as, IRIns *ir, int cc) -{ - Reg right, dest = ra_dest(as, ir, RSET_GPR); - IRRef lref = ir->op1, rref = ir->op2; - if (irref_isk(rref)) { lref = rref; rref = ir->op1; } - right = ra_alloc1(as, rref, rset_exclude(RSET_GPR, dest)); - emit_rr(as, XO_CMOV + (cc<<24), REX_64IR(ir, dest), right); - emit_rr(as, XO_CMP, REX_64IR(ir, dest), right); - ra_left(as, dest, lref); -} - -static void asm_min(ASMState *as, IRIns *ir) -{ - if (irt_isnum(ir->t)) - asm_fparith(as, ir, XO_MINSD); - else - asm_intmin_max(as, ir, CC_G); -} - -static void asm_max(ASMState *as, IRIns *ir) -{ - if (irt_isnum(ir->t)) - asm_fparith(as, ir, XO_MAXSD); - else - asm_intmin_max(as, ir, CC_L); -} - -/* Note: don't use LEA for overflow-checking arithmetic! */ -#define asm_addov(as, ir) asm_intarith(as, ir, XOg_ADD) -#define asm_subov(as, ir) asm_intarith(as, ir, XOg_SUB) -#define asm_mulov(as, ir) asm_intarith(as, ir, XOg_X_IMUL) - -#define asm_bnot(as, ir) asm_neg_not(as, ir, XOg_NOT) - -static void asm_bswap(ASMState *as, IRIns *ir) -{ - Reg dest = ra_dest(as, ir, RSET_GPR); - as->mcp = emit_op(XO_BSWAP + ((dest&7) << 24), - REX_64IR(ir, 0), dest, 0, as->mcp, 1); - ra_left(as, dest, ir->op1); -} - -#define asm_band(as, ir) asm_intarith(as, ir, XOg_AND) -#define asm_bor(as, ir) asm_intarith(as, ir, XOg_OR) -#define asm_bxor(as, ir) asm_intarith(as, ir, XOg_XOR) - -static void asm_bitshift(ASMState *as, IRIns *ir, x86Shift xs, x86Op xv) -{ - IRRef rref = ir->op2; - IRIns *irr = IR(rref); - Reg dest; - if (irref_isk(rref)) { /* Constant shifts. */ - int shift; - dest = ra_dest(as, ir, RSET_GPR); - shift = irr->i & (irt_is64(ir->t) ? 63 : 31); - if (!xv && shift && (as->flags & JIT_F_BMI2)) { - Reg left = asm_fuseloadm(as, ir->op1, RSET_GPR, irt_is64(ir->t)); - if (left != dest) { /* BMI2 rotate right by constant. */ - emit_i8(as, xs == XOg_ROL ? -shift : shift); - emit_mrm(as, VEX_64IR(ir, XV_RORX), dest, left); - return; - } - } - switch (shift) { - case 0: break; - case 1: emit_rr(as, XO_SHIFT1, REX_64IR(ir, xs), dest); break; - default: emit_shifti(as, REX_64IR(ir, xs), dest, shift); break; - } - } else if ((as->flags & JIT_F_BMI2) && xv) { /* BMI2 variable shifts. */ - Reg left, right; - dest = ra_dest(as, ir, RSET_GPR); - right = ra_alloc1(as, rref, RSET_GPR); - left = asm_fuseloadm(as, ir->op1, rset_exclude(RSET_GPR, right), - irt_is64(ir->t)); - emit_mrm(as, VEX_64IR(ir, xv) ^ (right << 19), dest, left); - return; - } else { /* Variable shifts implicitly use register cl (i.e. ecx). */ - Reg right; - dest = ra_dest(as, ir, rset_exclude(RSET_GPR, RID_ECX)); - if (dest == RID_ECX) { - dest = ra_scratch(as, rset_exclude(RSET_GPR, RID_ECX)); - emit_rr(as, XO_MOV, RID_ECX, dest); - } - right = irr->r; - if (ra_noreg(right)) - right = ra_allocref(as, rref, RID2RSET(RID_ECX)); - else if (right != RID_ECX) - ra_scratch(as, RID2RSET(RID_ECX)); - emit_rr(as, XO_SHIFTcl, REX_64IR(ir, xs), dest); - ra_noweak(as, right); - if (right != RID_ECX) - emit_rr(as, XO_MOV, RID_ECX, right); - } - ra_left(as, dest, ir->op1); - /* - ** Note: avoid using the flags resulting from a shift or rotate! - ** All of them cause a partial flag stall, except for r,1 shifts - ** (but not rotates). And a shift count of 0 leaves the flags unmodified. - */ -} - -#define asm_bshl(as, ir) asm_bitshift(as, ir, XOg_SHL, XV_SHLX) -#define asm_bshr(as, ir) asm_bitshift(as, ir, XOg_SHR, XV_SHRX) -#define asm_bsar(as, ir) asm_bitshift(as, ir, XOg_SAR, XV_SARX) -#define asm_brol(as, ir) asm_bitshift(as, ir, XOg_ROL, 0) -#define asm_bror(as, ir) asm_bitshift(as, ir, XOg_ROR, 0) - -/* -- Comparisons --------------------------------------------------------- */ - -/* Virtual flags for unordered FP comparisons. */ -#define VCC_U 0x1000 /* Unordered. */ -#define VCC_P 0x2000 /* Needs extra CC_P branch. */ -#define VCC_S 0x4000 /* Swap avoids CC_P branch. */ -#define VCC_PS (VCC_P|VCC_S) - -/* Map of comparisons to flags. ORDER IR. */ -#define COMPFLAGS(ci, cin, cu, cf) ((ci)+((cu)<<4)+((cin)<<8)+(cf)) -static const uint16_t asm_compmap[IR_ABC+1] = { - /* signed non-eq unsigned flags */ - /* LT */ COMPFLAGS(CC_GE, CC_G, CC_AE, VCC_PS), - /* GE */ COMPFLAGS(CC_L, CC_L, CC_B, 0), - /* LE */ COMPFLAGS(CC_G, CC_G, CC_A, VCC_PS), - /* GT */ COMPFLAGS(CC_LE, CC_L, CC_BE, 0), - /* ULT */ COMPFLAGS(CC_AE, CC_A, CC_AE, VCC_U), - /* UGE */ COMPFLAGS(CC_B, CC_B, CC_B, VCC_U|VCC_PS), - /* ULE */ COMPFLAGS(CC_A, CC_A, CC_A, VCC_U), - /* UGT */ COMPFLAGS(CC_BE, CC_B, CC_BE, VCC_U|VCC_PS), - /* EQ */ COMPFLAGS(CC_NE, CC_NE, CC_NE, VCC_P), - /* NE */ COMPFLAGS(CC_E, CC_E, CC_E, VCC_U|VCC_P), - /* ABC */ COMPFLAGS(CC_BE, CC_B, CC_BE, VCC_U|VCC_PS) /* Same as UGT. */ -}; - -/* FP and integer comparisons. */ -static void asm_comp(ASMState *as, IRIns *ir) -{ - uint32_t cc = asm_compmap[ir->o]; - if (irt_isnum(ir->t)) { - IRRef lref = ir->op1; - IRRef rref = ir->op2; - Reg left, right; - MCLabel l_around; - /* - ** An extra CC_P branch is required to preserve ordered/unordered - ** semantics for FP comparisons. This can be avoided by swapping - ** the operands and inverting the condition (except for EQ and UNE). - ** So always try to swap if possible. - ** - ** Another option would be to swap operands to achieve better memory - ** operand fusion. But it's unlikely that this outweighs the cost - ** of the extra branches. - */ - if (cc & VCC_S) { /* Swap? */ - IRRef tmp = lref; lref = rref; rref = tmp; - cc ^= (VCC_PS|(5<<4)); /* A <-> B, AE <-> BE, PS <-> none */ - } - left = ra_alloc1(as, lref, RSET_FPR); - l_around = emit_label(as); - asm_guardcc(as, cc >> 4); - if (cc & VCC_P) { /* Extra CC_P branch required? */ - if (!(cc & VCC_U)) { - asm_guardcc(as, CC_P); /* Branch to exit for ordered comparisons. */ - } else if (l_around != as->invmcp) { - emit_sjcc(as, CC_P, l_around); /* Branch around for unordered. */ - } else { - /* Patched to mcloop by asm_loop_fixup. */ - as->loopinv = 2; - if (as->realign) - emit_sjcc(as, CC_P, as->mcp); - else - emit_jcc(as, CC_P, as->mcp); - } - } - right = asm_fuseload(as, rref, rset_exclude(RSET_FPR, left)); - emit_mrm(as, XO_UCOMISD, left, right); - } else { - IRRef lref = ir->op1, rref = ir->op2; - IROp leftop = (IROp)(IR(lref)->o); - Reg r64 = REX_64IR(ir, 0); - int32_t imm = 0; - lua_assert(irt_is64(ir->t) || irt_isint(ir->t) || - irt_isu32(ir->t) || irt_isaddr(ir->t) || irt_isu8(ir->t)); - /* Swap constants (only for ABC) and fusable loads to the right. */ - if (irref_isk(lref) || (!irref_isk(rref) && opisfusableload(leftop))) { - if ((cc & 0xc) == 0xc) cc ^= 0x53; /* L <-> G, LE <-> GE */ - else if ((cc & 0xa) == 0x2) cc ^= 0x55; /* A <-> B, AE <-> BE */ - lref = ir->op2; rref = ir->op1; - } - if (asm_isk32(as, rref, &imm)) { - IRIns *irl = IR(lref); - /* Check wether we can use test ins. Not for unsigned, since CF=0. */ - int usetest = (imm == 0 && (cc & 0xa) != 0x2); - if (usetest && irl->o == IR_BAND && irl+1 == ir && !ra_used(irl)) { - /* Combine comp(BAND(ref, r/imm), 0) into test mrm, r/imm. */ - Reg right, left = RID_NONE; - RegSet allow = RSET_GPR; - if (!asm_isk32(as, irl->op2, &imm)) { - left = ra_alloc1(as, irl->op2, allow); - rset_clear(allow, left); - } else { /* Try to Fuse IRT_I8/IRT_U8 loads, too. See below. */ - IRIns *irll = IR(irl->op1); - if (opisfusableload((IROp)irll->o) && - (irt_isi8(irll->t) || irt_isu8(irll->t))) { - IRType1 origt = irll->t; /* Temporarily flip types. */ - irll->t.irt = (irll->t.irt & ~IRT_TYPE) | IRT_INT; - as->curins--; /* Skip to BAND to avoid failing in noconflict(). */ - right = asm_fuseload(as, irl->op1, RSET_GPR); - as->curins++; - irll->t = origt; - if (right != RID_MRM) goto test_nofuse; - /* Fusion succeeded, emit test byte mrm, imm8. */ - asm_guardcc(as, cc); - emit_i8(as, (imm & 0xff)); - emit_mrm(as, XO_GROUP3b, XOg_TEST, RID_MRM); - return; - } - } - as->curins--; /* Skip to BAND to avoid failing in noconflict(). */ - right = asm_fuseloadm(as, irl->op1, allow, r64); - as->curins++; /* Undo the above. */ - test_nofuse: - asm_guardcc(as, cc); - if (ra_noreg(left)) { - emit_i32(as, imm); - emit_mrm(as, XO_GROUP3, r64 + XOg_TEST, right); - } else { - emit_mrm(as, XO_TEST, r64 + left, right); - } - } else { - Reg left; - if (opisfusableload((IROp)irl->o) && - ((irt_isu8(irl->t) && checku8(imm)) || - ((irt_isi8(irl->t) || irt_isi16(irl->t)) && checki8(imm)) || - (irt_isu16(irl->t) && checku16(imm) && checki8((int16_t)imm)))) { - /* Only the IRT_INT case is fused by asm_fuseload. - ** The IRT_I8/IRT_U8 loads and some IRT_I16/IRT_U16 loads - ** are handled here. - ** Note that cmp word [mem], imm16 should not be generated, - ** since it has a length-changing prefix. Compares of a word - ** against a sign-extended imm8 are ok, however. - */ - IRType1 origt = irl->t; /* Temporarily flip types. */ - irl->t.irt = (irl->t.irt & ~IRT_TYPE) | IRT_INT; - left = asm_fuseload(as, lref, RSET_GPR); - irl->t = origt; - if (left == RID_MRM) { /* Fusion succeeded? */ - if (irt_isu8(irl->t) || irt_isu16(irl->t)) - cc >>= 4; /* Need unsigned compare. */ - asm_guardcc(as, cc); - emit_i8(as, imm); - emit_mrm(as, (irt_isi8(origt) || irt_isu8(origt)) ? - XO_ARITHib : XO_ARITHiw8, r64 + XOg_CMP, RID_MRM); - return; - } /* Otherwise handle register case as usual. */ - } else { - left = asm_fuseloadm(as, lref, - irt_isu8(ir->t) ? RSET_GPR8 : RSET_GPR, r64); - } - asm_guardcc(as, cc); - if (usetest && left != RID_MRM) { - /* Use test r,r instead of cmp r,0. */ - x86Op xo = XO_TEST; - if (irt_isu8(ir->t)) { - lua_assert(ir->o == IR_EQ || ir->o == IR_NE); - xo = XO_TESTb; - if (!rset_test(RSET_RANGE(RID_EAX, RID_EBX+1), left)) { - if (LJ_64) { - left |= FORCE_REX; - } else { - emit_i32(as, 0xff); - emit_mrm(as, XO_GROUP3, XOg_TEST, left); - return; - } - } - } - emit_rr(as, xo, r64 + left, left); - if (irl+1 == ir) /* Referencing previous ins? */ - as->flagmcp = as->mcp; /* Set flag to drop test r,r if possible. */ - } else { - emit_gmrmi(as, XG_ARITHi(XOg_CMP), r64 + left, imm); - } - } - } else { - Reg left = ra_alloc1(as, lref, RSET_GPR); - Reg right = asm_fuseloadm(as, rref, rset_exclude(RSET_GPR, left), r64); - asm_guardcc(as, cc); - emit_mrm(as, XO_CMP, r64 + left, right); - } - } -} - -#define asm_equal(as, ir) asm_comp(as, ir) - -#if LJ_32 && LJ_HASFFI -/* 64 bit integer comparisons in 32 bit mode. */ -static void asm_comp_int64(ASMState *as, IRIns *ir) -{ - uint32_t cc = asm_compmap[(ir-1)->o]; - RegSet allow = RSET_GPR; - Reg lefthi = RID_NONE, leftlo = RID_NONE; - Reg righthi = RID_NONE, rightlo = RID_NONE; - MCLabel l_around; - x86ModRM mrm; - - as->curins--; /* Skip loword ins. Avoids failing in noconflict(), too. */ - - /* Allocate/fuse hiword operands. */ - if (irref_isk(ir->op2)) { - lefthi = asm_fuseload(as, ir->op1, allow); - } else { - lefthi = ra_alloc1(as, ir->op1, allow); - rset_clear(allow, lefthi); - righthi = asm_fuseload(as, ir->op2, allow); - if (righthi == RID_MRM) { - if (as->mrm.base != RID_NONE) rset_clear(allow, as->mrm.base); - if (as->mrm.idx != RID_NONE) rset_clear(allow, as->mrm.idx); - } else { - rset_clear(allow, righthi); - } - } - mrm = as->mrm; /* Save state for hiword instruction. */ - - /* Allocate/fuse loword operands. */ - if (irref_isk((ir-1)->op2)) { - leftlo = asm_fuseload(as, (ir-1)->op1, allow); - } else { - leftlo = ra_alloc1(as, (ir-1)->op1, allow); - rset_clear(allow, leftlo); - rightlo = asm_fuseload(as, (ir-1)->op2, allow); - } - - /* All register allocations must be performed _before_ this point. */ - l_around = emit_label(as); - as->invmcp = as->flagmcp = NULL; /* Cannot use these optimizations. */ - - /* Loword comparison and branch. */ - asm_guardcc(as, cc >> 4); /* Always use unsigned compare for loword. */ - if (ra_noreg(rightlo)) { - int32_t imm = IR((ir-1)->op2)->i; - if (imm == 0 && ((cc >> 4) & 0xa) != 0x2 && leftlo != RID_MRM) - emit_rr(as, XO_TEST, leftlo, leftlo); - else - emit_gmrmi(as, XG_ARITHi(XOg_CMP), leftlo, imm); - } else { - emit_mrm(as, XO_CMP, leftlo, rightlo); - } - - /* Hiword comparison and branches. */ - if ((cc & 15) != CC_NE) - emit_sjcc(as, CC_NE, l_around); /* Hiword unequal: skip loword compare. */ - if ((cc & 15) != CC_E) - asm_guardcc(as, cc >> 8); /* Hiword compare without equality check. */ - as->mrm = mrm; /* Restore state. */ - if (ra_noreg(righthi)) { - int32_t imm = IR(ir->op2)->i; - if (imm == 0 && (cc & 0xa) != 0x2 && lefthi != RID_MRM) - emit_rr(as, XO_TEST, lefthi, lefthi); - else - emit_gmrmi(as, XG_ARITHi(XOg_CMP), lefthi, imm); - } else { - emit_mrm(as, XO_CMP, lefthi, righthi); - } -} -#endif - -/* -- Support for 64 bit ops in 32 bit mode ------------------------------- */ - -/* Hiword op of a split 64 bit op. Previous op must be the loword op. */ -static void asm_hiop(ASMState *as, IRIns *ir) -{ -#if LJ_32 && LJ_HASFFI - /* HIOP is marked as a store because it needs its own DCE logic. */ - int uselo = ra_used(ir-1), usehi = ra_used(ir); /* Loword/hiword used? */ - if (LJ_UNLIKELY(!(as->flags & JIT_F_OPT_DCE))) uselo = usehi = 1; - if ((ir-1)->o == IR_CONV) { /* Conversions to/from 64 bit. */ - as->curins--; /* Always skip the CONV. */ - if (usehi || uselo) - asm_conv64(as, ir); - return; - } else if ((ir-1)->o <= IR_NE) { /* 64 bit integer comparisons. ORDER IR. */ - asm_comp_int64(as, ir); - return; - } else if ((ir-1)->o == IR_XSTORE) { - if ((ir-1)->r != RID_SINK) - asm_fxstore(as, ir); - return; - } - if (!usehi) return; /* Skip unused hiword op for all remaining ops. */ - switch ((ir-1)->o) { - case IR_ADD: - as->flagmcp = NULL; - as->curins--; - asm_intarith(as, ir, XOg_ADC); - asm_intarith(as, ir-1, XOg_ADD); - break; - case IR_SUB: - as->flagmcp = NULL; - as->curins--; - asm_intarith(as, ir, XOg_SBB); - asm_intarith(as, ir-1, XOg_SUB); - break; - case IR_NEG: { - Reg dest = ra_dest(as, ir, RSET_GPR); - emit_rr(as, XO_GROUP3, XOg_NEG, dest); - emit_i8(as, 0); - emit_rr(as, XO_ARITHi8, XOg_ADC, dest); - ra_left(as, dest, ir->op1); - as->curins--; - asm_neg_not(as, ir-1, XOg_NEG); - break; - } - case IR_CALLN: - case IR_CALLXS: - if (!uselo) - ra_allocref(as, ir->op1, RID2RSET(RID_RETLO)); /* Mark lo op as used. */ - break; - case IR_CNEWI: - /* Nothing to do here. Handled by CNEWI itself. */ - break; - default: lua_assert(0); break; - } -#else - UNUSED(as); UNUSED(ir); lua_assert(0); /* Unused on x64 or without FFI. */ -#endif -} - -/* -- Profiling ----------------------------------------------------------- */ - -static void asm_prof(ASMState *as, IRIns *ir) -{ - UNUSED(ir); - asm_guardcc(as, CC_NE); - emit_i8(as, HOOK_PROFILE); - emit_rma(as, XO_GROUP3b, XOg_TEST, &J2G(as->J)->hookmask); -} - -/* -- Stack handling ------------------------------------------------------ */ - -/* Check Lua stack size for overflow. Use exit handler as fallback. */ -static void asm_stack_check(ASMState *as, BCReg topslot, - IRIns *irp, RegSet allow, ExitNo exitno) -{ - /* Try to get an unused temp. register, otherwise spill/restore eax. */ - Reg pbase = irp ? irp->r : RID_BASE; - Reg r = allow ? rset_pickbot(allow) : RID_EAX; - emit_jcc(as, CC_B, exitstub_addr(as->J, exitno)); - if (allow == RSET_EMPTY) /* Restore temp. register. */ - emit_rmro(as, XO_MOV, r|REX_64, RID_ESP, 0); - else - ra_modified(as, r); - emit_gri(as, XG_ARITHi(XOg_CMP), r|REX_GC64, (int32_t)(8*topslot)); - if (ra_hasreg(pbase) && pbase != r) - emit_rr(as, XO_ARITH(XOg_SUB), r|REX_GC64, pbase); - else -#if LJ_GC64 - emit_rmro(as, XO_ARITH(XOg_SUB), r|REX_64, RID_DISPATCH, - (int32_t)dispofs(as, &J2G(as->J)->jit_base)); -#else - emit_rmro(as, XO_ARITH(XOg_SUB), r, RID_NONE, - ptr2addr(&J2G(as->J)->jit_base)); -#endif - emit_rmro(as, XO_MOV, r|REX_GC64, r, offsetof(lua_State, maxstack)); - emit_getgl(as, r, cur_L); - if (allow == RSET_EMPTY) /* Spill temp. register. */ - emit_rmro(as, XO_MOVto, r|REX_64, RID_ESP, 0); -} - -/* Restore Lua stack from on-trace state. */ -static void asm_stack_restore(ASMState *as, SnapShot *snap) -{ - SnapEntry *map = &as->T->snapmap[snap->mapofs]; -#if !LJ_FR2 || defined(LUA_USE_ASSERT) - SnapEntry *flinks = &as->T->snapmap[snap_nextofs(as->T, snap)-1-LJ_FR2]; -#endif - MSize n, nent = snap->nent; - /* Store the value of all modified slots to the Lua stack. */ - for (n = 0; n < nent; n++) { - SnapEntry sn = map[n]; - BCReg s = snap_slot(sn); - int32_t ofs = 8*((int32_t)s-1-LJ_FR2); - IRRef ref = snap_ref(sn); - IRIns *ir = IR(ref); - if ((sn & SNAP_NORESTORE)) - continue; - if (irt_isnum(ir->t)) { - Reg src = ra_alloc1(as, ref, RSET_FPR); - emit_rmro(as, XO_MOVSDto, src, RID_BASE, ofs); - } else { - lua_assert(irt_ispri(ir->t) || irt_isaddr(ir->t) || - (LJ_DUALNUM && irt_isinteger(ir->t))); - if (!irref_isk(ref)) { - Reg src = ra_alloc1(as, ref, rset_exclude(RSET_GPR, RID_BASE)); -#if LJ_GC64 - if (irt_is64(ir->t)) { - /* TODO: 64 bit store + 32 bit load-modify-store is suboptimal. */ - emit_u32(as, irt_toitype(ir->t) << 15); - emit_rmro(as, XO_ARITHi, XOg_OR, RID_BASE, ofs+4); - } else if (LJ_DUALNUM && irt_isinteger(ir->t)) { - emit_movmroi(as, RID_BASE, ofs+4, LJ_TISNUM << 15); - } else { - emit_movmroi(as, RID_BASE, ofs+4, (irt_toitype(ir->t)<<15)|0x7fff); - } -#endif - emit_movtomro(as, REX_64IR(ir, src), RID_BASE, ofs); -#if LJ_GC64 - } else { - TValue k; - lj_ir_kvalue(as->J->L, &k, ir); - if (tvisnil(&k)) { - emit_i32(as, -1); - emit_rmro(as, XO_MOVmi, REX_64, RID_BASE, ofs); - } else { - emit_movmroi(as, RID_BASE, ofs+4, k.u32.hi); - emit_movmroi(as, RID_BASE, ofs, k.u32.lo); - } -#else - } else if (!irt_ispri(ir->t)) { - emit_movmroi(as, RID_BASE, ofs, ir->i); -#endif - } - if ((sn & (SNAP_CONT|SNAP_FRAME))) { -#if !LJ_FR2 - if (s != 0) /* Do not overwrite link to previous frame. */ - emit_movmroi(as, RID_BASE, ofs+4, (int32_t)(*flinks--)); -#endif -#if !LJ_GC64 - } else { - if (!(LJ_64 && irt_islightud(ir->t))) - emit_movmroi(as, RID_BASE, ofs+4, irt_toitype(ir->t)); -#endif - } - } - checkmclim(as); - } - lua_assert(map + nent == flinks); -} - -/* -- GC handling --------------------------------------------------------- */ - -/* Check GC threshold and do one or more GC steps. */ -static void asm_gc_check(ASMState *as) -{ - const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_gc_step_jit]; - IRRef args[2]; - MCLabel l_end; - Reg tmp; - ra_evictset(as, RSET_SCRATCH); - l_end = emit_label(as); - /* Exit trace if in GCSatomic or GCSfinalize. Avoids syncing GC objects. */ - asm_guardcc(as, CC_NE); /* Assumes asm_snap_prep() already done. */ - emit_rr(as, XO_TEST, RID_RET, RID_RET); - args[0] = ASMREF_TMP1; /* global_State *g */ - args[1] = ASMREF_TMP2; /* MSize steps */ - asm_gencall(as, ci, args); - tmp = ra_releasetmp(as, ASMREF_TMP1); -#if LJ_GC64 - emit_rmro(as, XO_LEA, tmp|REX_64, RID_DISPATCH, GG_DISP2G); -#else - emit_loada(as, tmp, J2G(as->J)); -#endif - emit_loadi(as, ra_releasetmp(as, ASMREF_TMP2), as->gcsteps); - /* Jump around GC step if GC total < GC threshold. */ - emit_sjcc(as, CC_B, l_end); - emit_opgl(as, XO_ARITH(XOg_CMP), tmp|REX_GC64, gc.threshold); - emit_getgl(as, tmp, gc.total); - as->gcsteps = 0; - checkmclim(as); -} - -/* -- Loop handling ------------------------------------------------------- */ - -/* Fixup the loop branch. */ -static void asm_loop_fixup(ASMState *as) -{ - MCode *p = as->mctop; - MCode *target = as->mcp; - if (as->realign) { /* Realigned loops use short jumps. */ - as->realign = NULL; /* Stop another retry. */ - lua_assert(((intptr_t)target & 15) == 0); - if (as->loopinv) { /* Inverted loop branch? */ - p -= 5; - p[0] = XI_JMP; - lua_assert(target - p >= -128); - p[-1] = (MCode)(target - p); /* Patch sjcc. */ - if (as->loopinv == 2) - p[-3] = (MCode)(target - p + 2); /* Patch opt. short jp. */ - } else { - lua_assert(target - p >= -128); - p[-1] = (MCode)(int8_t)(target - p); /* Patch short jmp. */ - p[-2] = XI_JMPs; - } - } else { - MCode *newloop; - p[-5] = XI_JMP; - if (as->loopinv) { /* Inverted loop branch? */ - /* asm_guardcc already inverted the jcc and patched the jmp. */ - p -= 5; - newloop = target+4; - *(int32_t *)(p-4) = (int32_t)(target - p); /* Patch jcc. */ - if (as->loopinv == 2) { - *(int32_t *)(p-10) = (int32_t)(target - p + 6); /* Patch opt. jp. */ - newloop = target+8; - } - } else { /* Otherwise just patch jmp. */ - *(int32_t *)(p-4) = (int32_t)(target - p); - newloop = target+3; - } - /* Realign small loops and shorten the loop branch. */ - if (newloop >= p - 128) { - as->realign = newloop; /* Force a retry and remember alignment. */ - as->curins = as->stopins; /* Abort asm_trace now. */ - as->T->nins = as->orignins; /* Remove any added renames. */ - } - } -} - -/* -- Head of trace ------------------------------------------------------- */ - -/* Coalesce BASE register for a root trace. */ -static void asm_head_root_base(ASMState *as) -{ - IRIns *ir = IR(REF_BASE); - Reg r = ir->r; - if (ra_hasreg(r)) { - ra_free(as, r); - if (rset_test(as->modset, r) || irt_ismarked(ir->t)) - ir->r = RID_INIT; /* No inheritance for modified BASE register. */ - if (r != RID_BASE) - emit_rr(as, XO_MOV, r|REX_GC64, RID_BASE); - } -} - -/* Coalesce or reload BASE register for a side trace. */ -static RegSet asm_head_side_base(ASMState *as, IRIns *irp, RegSet allow) -{ - IRIns *ir = IR(REF_BASE); - Reg r = ir->r; - if (ra_hasreg(r)) { - ra_free(as, r); - if (rset_test(as->modset, r) || irt_ismarked(ir->t)) - ir->r = RID_INIT; /* No inheritance for modified BASE register. */ - if (irp->r == r) { - rset_clear(allow, r); /* Mark same BASE register as coalesced. */ - } else if (ra_hasreg(irp->r) && rset_test(as->freeset, irp->r)) { - /* Move from coalesced parent reg. */ - rset_clear(allow, irp->r); - emit_rr(as, XO_MOV, r|REX_GC64, irp->r); - } else { - emit_getgl(as, r, jit_base); /* Otherwise reload BASE. */ - } - } - return allow; -} - -/* -- Tail of trace ------------------------------------------------------- */ - -/* Fixup the tail code. */ -static void asm_tail_fixup(ASMState *as, TraceNo lnk) -{ - /* Note: don't use as->mcp swap + emit_*: emit_op overwrites more bytes. */ - MCode *p = as->mctop; - MCode *target, *q; - int32_t spadj = as->T->spadjust; - if (spadj == 0) { - p -= ((as->flags & JIT_F_LEA_AGU) ? 7 : 6) + (LJ_64 ? 1 : 0); - } else { - MCode *p1; - /* Patch stack adjustment. */ - if (checki8(spadj)) { - p -= 3; - p1 = p-6; - *p1 = (MCode)spadj; - } else { - p1 = p-9; - *(int32_t *)p1 = spadj; - } - if ((as->flags & JIT_F_LEA_AGU)) { -#if LJ_64 - p1[-4] = 0x48; -#endif - p1[-3] = (MCode)XI_LEA; - p1[-2] = MODRM(checki8(spadj) ? XM_OFS8 : XM_OFS32, RID_ESP, RID_ESP); - p1[-1] = MODRM(XM_SCALE1, RID_ESP, RID_ESP); - } else { -#if LJ_64 - p1[-3] = 0x48; -#endif - p1[-2] = (MCode)(checki8(spadj) ? XI_ARITHi8 : XI_ARITHi); - p1[-1] = MODRM(XM_REG, XOg_ADD, RID_ESP); - } - } - /* Patch exit branch. */ - target = lnk ? traceref(as->J, lnk)->mcode : (MCode *)lj_vm_exit_interp; - *(int32_t *)(p-4) = jmprel(p, target); - p[-5] = XI_JMP; - /* Drop unused mcode tail. Fill with NOPs to make the prefetcher happy. */ - for (q = as->mctop-1; q >= p; q--) - *q = XI_NOP; - as->mctop = p; -} - -/* Prepare tail of code. */ -static void asm_tail_prep(ASMState *as) -{ - MCode *p = as->mctop; - /* Realign and leave room for backwards loop branch or exit branch. */ - if (as->realign) { - int i = ((int)(intptr_t)as->realign) & 15; - /* Fill unused mcode tail with NOPs to make the prefetcher happy. */ - while (i-- > 0) - *--p = XI_NOP; - as->mctop = p; - p -= (as->loopinv ? 5 : 2); /* Space for short/near jmp. */ - } else { - p -= 5; /* Space for exit branch (near jmp). */ - } - if (as->loopref) { - as->invmcp = as->mcp = p; - } else { - /* Leave room for ESP adjustment: add esp, imm or lea esp, [esp+imm] */ - as->mcp = p - (((as->flags & JIT_F_LEA_AGU) ? 7 : 6) + (LJ_64 ? 1 : 0)); - as->invmcp = NULL; - } -} - -/* -- Trace setup --------------------------------------------------------- */ - -/* Ensure there are enough stack slots for call arguments. */ -static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci) -{ - IRRef args[CCI_NARGS_MAX*2]; - int nslots; - asm_collectargs(as, ir, ci, args); - nslots = asm_count_call_slots(as, ci, args); - if (nslots > as->evenspill) /* Leave room for args in stack slots. */ - as->evenspill = nslots; -#if LJ_64 - return irt_isfp(ir->t) ? REGSP_HINT(RID_FPRET) : REGSP_HINT(RID_RET); -#else - return irt_isfp(ir->t) ? REGSP_INIT : REGSP_HINT(RID_RET); -#endif -} - -/* Target-specific setup. */ -static void asm_setup_target(ASMState *as) -{ - asm_exitstub_setup(as, as->T->nsnap); - as->mrm.base = 0; -} - -/* -- Trace patching ------------------------------------------------------ */ - -static const uint8_t map_op1[256] = { -0x92,0x92,0x92,0x92,0x52,0x45,0x51,0x51,0x92,0x92,0x92,0x92,0x52,0x45,0x51,0x20, -0x92,0x92,0x92,0x92,0x52,0x45,0x51,0x51,0x92,0x92,0x92,0x92,0x52,0x45,0x51,0x51, -0x92,0x92,0x92,0x92,0x52,0x45,0x10,0x51,0x92,0x92,0x92,0x92,0x52,0x45,0x10,0x51, -0x92,0x92,0x92,0x92,0x52,0x45,0x10,0x51,0x92,0x92,0x92,0x92,0x52,0x45,0x10,0x51, -#if LJ_64 -0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14, -#else -0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51, -#endif -0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51, -0x51,0x51,0x92,0x92,0x10,0x10,0x12,0x11,0x45,0x86,0x52,0x93,0x51,0x51,0x51,0x51, -0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52, -0x93,0x86,0x93,0x93,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92, -0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x47,0x51,0x51,0x51,0x51,0x51, -#if LJ_64 -0x59,0x59,0x59,0x59,0x51,0x51,0x51,0x51,0x52,0x45,0x51,0x51,0x51,0x51,0x51,0x51, -#else -0x55,0x55,0x55,0x55,0x51,0x51,0x51,0x51,0x52,0x45,0x51,0x51,0x51,0x51,0x51,0x51, -#endif -0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, -0x93,0x93,0x53,0x51,0x70,0x71,0x93,0x86,0x54,0x51,0x53,0x51,0x51,0x52,0x51,0x51, -0x92,0x92,0x92,0x92,0x52,0x52,0x51,0x51,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92, -0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x45,0x45,0x47,0x52,0x51,0x51,0x51,0x51, -0x10,0x51,0x10,0x10,0x51,0x51,0x63,0x66,0x51,0x51,0x51,0x51,0x51,0x51,0x92,0x92 -}; - -static const uint8_t map_op2[256] = { -0x93,0x93,0x93,0x93,0x52,0x52,0x52,0x52,0x52,0x52,0x51,0x52,0x51,0x93,0x52,0x94, -0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93, -0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93, -0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x34,0x51,0x35,0x51,0x51,0x51,0x51,0x51, -0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93, -0x53,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93, -0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93, -0x94,0x54,0x54,0x54,0x93,0x93,0x93,0x52,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93, -0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46, -0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93, -0x52,0x52,0x52,0x93,0x94,0x93,0x51,0x51,0x52,0x52,0x52,0x93,0x94,0x93,0x93,0x93, -0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x94,0x93,0x93,0x93,0x93,0x93, -0x93,0x93,0x94,0x93,0x94,0x94,0x94,0x93,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52, -0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93, -0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93, -0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x52 -}; - -static uint32_t asm_x86_inslen(const uint8_t* p) -{ - uint32_t result = 0; - uint32_t prefixes = 0; - uint32_t x = map_op1[*p]; - for (;;) { - switch (x >> 4) { - case 0: return result + x + (prefixes & 4); - case 1: prefixes |= x; x = map_op1[*++p]; result++; break; - case 2: x = map_op2[*++p]; break; - case 3: p++; goto mrm; - case 4: result -= (prefixes & 2); /* fallthrough */ - case 5: return result + (x & 15); - case 6: /* Group 3. */ - if (p[1] & 0x38) x = 2; - else if ((prefixes & 2) && (x == 0x66)) x = 4; - goto mrm; - case 7: /* VEX c4/c5. */ - if (LJ_32 && p[1] < 0xc0) { - x = 2; - goto mrm; - } - if (x == 0x70) { - x = *++p & 0x1f; - result++; - if (x >= 2) { - p += 2; - result += 2; - goto mrm; - } - } - p++; - result++; - x = map_op2[*++p]; - break; - case 8: result -= (prefixes & 2); /* fallthrough */ - case 9: mrm: /* ModR/M and possibly SIB. */ - result += (x & 15); - x = *++p; - switch (x >> 6) { - case 0: if ((x & 7) == 5) return result + 4; break; - case 1: result++; break; - case 2: result += 4; break; - case 3: return result; - } - if ((x & 7) == 4) { - result++; - if (x < 0x40 && (p[1] & 7) == 5) result += 4; - } - return result; - } - } -} - -/* Patch exit jumps of existing machine code to a new target. */ -void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, MCode *target) -{ - MCode *p = T->mcode; - MCode *mcarea = lj_mcode_patch(J, p, 0); - MSize len = T->szmcode; - MCode *px = exitstub_addr(J, exitno) - 6; - MCode *pe = p+len-6; -#if LJ_GC64 - uint32_t statei = (uint32_t)(GG_OFS(g.vmstate) - GG_OFS(dispatch)); -#else - uint32_t statei = u32ptr(&J2G(J)->vmstate); -#endif - if (len > 5 && p[len-5] == XI_JMP && p+len-6 + *(int32_t *)(p+len-4) == px) - *(int32_t *)(p+len-4) = jmprel(p+len, target); - /* Do not patch parent exit for a stack check. Skip beyond vmstate update. */ - for (; p < pe; p += asm_x86_inslen(p)) { - intptr_t ofs = LJ_GC64 ? (p[0] & 0xf0) == 0x40 : LJ_64; - if (*(uint32_t *)(p+2+ofs) == statei && p[ofs+LJ_GC64-LJ_64] == XI_MOVmi) - break; - } - lua_assert(p < pe); - for (; p < pe; p += asm_x86_inslen(p)) - if ((*(uint16_t *)p & 0xf0ff) == 0x800f && p + *(int32_t *)(p+2) == px) - *(int32_t *)(p+2) = jmprel(p+6, target); - lj_mcode_sync(T->mcode, T->mcode + T->szmcode); - lj_mcode_patch(J, mcarea, 1); -} - diff --git a/lib/LuaJIT/src/lj_bc.c b/lib/LuaJIT/src/lj_bc.c deleted file mode 100644 index a597692..0000000 --- a/lib/LuaJIT/src/lj_bc.c +++ /dev/null @@ -1,14 +0,0 @@ -/* -** Bytecode instruction modes. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_bc_c -#define LUA_CORE - -#include "lj_obj.h" -#include "lj_bc.h" - -/* Bytecode offsets and bytecode instruction modes. */ -#include "lj_bcdef.h" - diff --git a/lib/LuaJIT/src/lj_bc.h b/lib/LuaJIT/src/lj_bc.h deleted file mode 100644 index 69a45f2..0000000 --- a/lib/LuaJIT/src/lj_bc.h +++ /dev/null @@ -1,265 +0,0 @@ -/* -** Bytecode instruction format. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_BC_H -#define _LJ_BC_H - -#include "lj_def.h" -#include "lj_arch.h" - -/* Bytecode instruction format, 32 bit wide, fields of 8 or 16 bit: -** -** +----+----+----+----+ -** | B | C | A | OP | Format ABC -** +----+----+----+----+ -** | D | A | OP | Format AD -** +-------------------- -** MSB LSB -** -** In-memory instructions are always stored in host byte order. -*/ - -/* Operand ranges and related constants. */ -#define BCMAX_A 0xff -#define BCMAX_B 0xff -#define BCMAX_C 0xff -#define BCMAX_D 0xffff -#define BCBIAS_J 0x8000 -#define NO_REG BCMAX_A -#define NO_JMP (~(BCPos)0) - -/* Macros to get instruction fields. */ -#define bc_op(i) ((BCOp)((i)&0xff)) -#define bc_a(i) ((BCReg)(((i)>>8)&0xff)) -#define bc_b(i) ((BCReg)((i)>>24)) -#define bc_c(i) ((BCReg)(((i)>>16)&0xff)) -#define bc_d(i) ((BCReg)((i)>>16)) -#define bc_j(i) ((ptrdiff_t)bc_d(i)-BCBIAS_J) - -/* Macros to set instruction fields. */ -#define setbc_byte(p, x, ofs) \ - ((uint8_t *)(p))[LJ_ENDIAN_SELECT(ofs, 3-ofs)] = (uint8_t)(x) -#define setbc_op(p, x) setbc_byte(p, (x), 0) -#define setbc_a(p, x) setbc_byte(p, (x), 1) -#define setbc_b(p, x) setbc_byte(p, (x), 3) -#define setbc_c(p, x) setbc_byte(p, (x), 2) -#define setbc_d(p, x) \ - ((uint16_t *)(p))[LJ_ENDIAN_SELECT(1, 0)] = (uint16_t)(x) -#define setbc_j(p, x) setbc_d(p, (BCPos)((int32_t)(x)+BCBIAS_J)) - -/* Macros to compose instructions. */ -#define BCINS_ABC(o, a, b, c) \ - (((BCIns)(o))|((BCIns)(a)<<8)|((BCIns)(b)<<24)|((BCIns)(c)<<16)) -#define BCINS_AD(o, a, d) \ - (((BCIns)(o))|((BCIns)(a)<<8)|((BCIns)(d)<<16)) -#define BCINS_AJ(o, a, j) BCINS_AD(o, a, (BCPos)((int32_t)(j)+BCBIAS_J)) - -/* Bytecode instruction definition. Order matters, see below. -** -** (name, filler, Amode, Bmode, Cmode or Dmode, metamethod) -** -** The opcode name suffixes specify the type for RB/RC or RD: -** V = variable slot -** S = string const -** N = number const -** P = primitive type (~itype) -** B = unsigned byte literal -** M = multiple args/results -*/ -#define BCDEF(_) \ - /* Comparison ops. ORDER OPR. */ \ - _(ISLT, var, ___, var, lt) \ - _(ISGE, var, ___, var, lt) \ - _(ISLE, var, ___, var, le) \ - _(ISGT, var, ___, var, le) \ - \ - _(ISEQV, var, ___, var, eq) \ - _(ISNEV, var, ___, var, eq) \ - _(ISEQS, var, ___, str, eq) \ - _(ISNES, var, ___, str, eq) \ - _(ISEQN, var, ___, num, eq) \ - _(ISNEN, var, ___, num, eq) \ - _(ISEQP, var, ___, pri, eq) \ - _(ISNEP, var, ___, pri, eq) \ - \ - /* Unary test and copy ops. */ \ - _(ISTC, dst, ___, var, ___) \ - _(ISFC, dst, ___, var, ___) \ - _(IST, ___, ___, var, ___) \ - _(ISF, ___, ___, var, ___) \ - _(ISTYPE, var, ___, lit, ___) \ - _(ISNUM, var, ___, lit, ___) \ - \ - /* Unary ops. */ \ - _(MOV, dst, ___, var, ___) \ - _(NOT, dst, ___, var, ___) \ - _(UNM, dst, ___, var, unm) \ - _(LEN, dst, ___, var, len) \ - \ - /* Binary ops. ORDER OPR. VV last, POW must be next. */ \ - _(ADDVN, dst, var, num, add) \ - _(SUBVN, dst, var, num, sub) \ - _(MULVN, dst, var, num, mul) \ - _(DIVVN, dst, var, num, div) \ - _(MODVN, dst, var, num, mod) \ - \ - _(ADDNV, dst, var, num, add) \ - _(SUBNV, dst, var, num, sub) \ - _(MULNV, dst, var, num, mul) \ - _(DIVNV, dst, var, num, div) \ - _(MODNV, dst, var, num, mod) \ - \ - _(ADDVV, dst, var, var, add) \ - _(SUBVV, dst, var, var, sub) \ - _(MULVV, dst, var, var, mul) \ - _(DIVVV, dst, var, var, div) \ - _(MODVV, dst, var, var, mod) \ - \ - _(POW, dst, var, var, pow) \ - _(CAT, dst, rbase, rbase, concat) \ - \ - /* Constant ops. */ \ - _(KSTR, dst, ___, str, ___) \ - _(KCDATA, dst, ___, cdata, ___) \ - _(KSHORT, dst, ___, lits, ___) \ - _(KNUM, dst, ___, num, ___) \ - _(KPRI, dst, ___, pri, ___) \ - _(KNIL, base, ___, base, ___) \ - \ - /* Upvalue and function ops. */ \ - _(UGET, dst, ___, uv, ___) \ - _(USETV, uv, ___, var, ___) \ - _(USETS, uv, ___, str, ___) \ - _(USETN, uv, ___, num, ___) \ - _(USETP, uv, ___, pri, ___) \ - _(UCLO, rbase, ___, jump, ___) \ - _(FNEW, dst, ___, func, gc) \ - \ - /* Table ops. */ \ - _(TNEW, dst, ___, lit, gc) \ - _(TDUP, dst, ___, tab, gc) \ - _(GGET, dst, ___, str, index) \ - _(GSET, var, ___, str, newindex) \ - _(TGETV, dst, var, var, index) \ - _(TGETS, dst, var, str, index) \ - _(TGETB, dst, var, lit, index) \ - _(TGETR, dst, var, var, index) \ - _(TSETV, var, var, var, newindex) \ - _(TSETS, var, var, str, newindex) \ - _(TSETB, var, var, lit, newindex) \ - _(TSETM, base, ___, num, newindex) \ - _(TSETR, var, var, var, newindex) \ - \ - /* Calls and vararg handling. T = tail call. */ \ - _(CALLM, base, lit, lit, call) \ - _(CALL, base, lit, lit, call) \ - _(CALLMT, base, ___, lit, call) \ - _(CALLT, base, ___, lit, call) \ - _(ITERC, base, lit, lit, call) \ - _(ITERN, base, lit, lit, call) \ - _(VARG, base, lit, lit, ___) \ - _(ISNEXT, base, ___, jump, ___) \ - \ - /* Returns. */ \ - _(RETM, base, ___, lit, ___) \ - _(RET, rbase, ___, lit, ___) \ - _(RET0, rbase, ___, lit, ___) \ - _(RET1, rbase, ___, lit, ___) \ - \ - /* Loops and branches. I/J = interp/JIT, I/C/L = init/call/loop. */ \ - _(FORI, base, ___, jump, ___) \ - _(JFORI, base, ___, jump, ___) \ - \ - _(FORL, base, ___, jump, ___) \ - _(IFORL, base, ___, jump, ___) \ - _(JFORL, base, ___, lit, ___) \ - \ - _(ITERL, base, ___, jump, ___) \ - _(IITERL, base, ___, jump, ___) \ - _(JITERL, base, ___, lit, ___) \ - \ - _(LOOP, rbase, ___, jump, ___) \ - _(ILOOP, rbase, ___, jump, ___) \ - _(JLOOP, rbase, ___, lit, ___) \ - \ - _(JMP, rbase, ___, jump, ___) \ - \ - /* Function headers. I/J = interp/JIT, F/V/C = fixarg/vararg/C func. */ \ - _(FUNCF, rbase, ___, ___, ___) \ - _(IFUNCF, rbase, ___, ___, ___) \ - _(JFUNCF, rbase, ___, lit, ___) \ - _(FUNCV, rbase, ___, ___, ___) \ - _(IFUNCV, rbase, ___, ___, ___) \ - _(JFUNCV, rbase, ___, lit, ___) \ - _(FUNCC, rbase, ___, ___, ___) \ - _(FUNCCW, rbase, ___, ___, ___) - -/* Bytecode opcode numbers. */ -typedef enum { -#define BCENUM(name, ma, mb, mc, mt) BC_##name, -BCDEF(BCENUM) -#undef BCENUM - BC__MAX -} BCOp; - -LJ_STATIC_ASSERT((int)BC_ISEQV+1 == (int)BC_ISNEV); -LJ_STATIC_ASSERT(((int)BC_ISEQV^1) == (int)BC_ISNEV); -LJ_STATIC_ASSERT(((int)BC_ISEQS^1) == (int)BC_ISNES); -LJ_STATIC_ASSERT(((int)BC_ISEQN^1) == (int)BC_ISNEN); -LJ_STATIC_ASSERT(((int)BC_ISEQP^1) == (int)BC_ISNEP); -LJ_STATIC_ASSERT(((int)BC_ISLT^1) == (int)BC_ISGE); -LJ_STATIC_ASSERT(((int)BC_ISLE^1) == (int)BC_ISGT); -LJ_STATIC_ASSERT(((int)BC_ISLT^3) == (int)BC_ISGT); -LJ_STATIC_ASSERT((int)BC_IST-(int)BC_ISTC == (int)BC_ISF-(int)BC_ISFC); -LJ_STATIC_ASSERT((int)BC_CALLT-(int)BC_CALL == (int)BC_CALLMT-(int)BC_CALLM); -LJ_STATIC_ASSERT((int)BC_CALLMT + 1 == (int)BC_CALLT); -LJ_STATIC_ASSERT((int)BC_RETM + 1 == (int)BC_RET); -LJ_STATIC_ASSERT((int)BC_FORL + 1 == (int)BC_IFORL); -LJ_STATIC_ASSERT((int)BC_FORL + 2 == (int)BC_JFORL); -LJ_STATIC_ASSERT((int)BC_ITERL + 1 == (int)BC_IITERL); -LJ_STATIC_ASSERT((int)BC_ITERL + 2 == (int)BC_JITERL); -LJ_STATIC_ASSERT((int)BC_LOOP + 1 == (int)BC_ILOOP); -LJ_STATIC_ASSERT((int)BC_LOOP + 2 == (int)BC_JLOOP); -LJ_STATIC_ASSERT((int)BC_FUNCF + 1 == (int)BC_IFUNCF); -LJ_STATIC_ASSERT((int)BC_FUNCF + 2 == (int)BC_JFUNCF); -LJ_STATIC_ASSERT((int)BC_FUNCV + 1 == (int)BC_IFUNCV); -LJ_STATIC_ASSERT((int)BC_FUNCV + 2 == (int)BC_JFUNCV); - -/* This solves a circular dependency problem, change as needed. */ -#define FF_next_N 4 - -/* Stack slots used by FORI/FORL, relative to operand A. */ -enum { - FORL_IDX, FORL_STOP, FORL_STEP, FORL_EXT -}; - -/* Bytecode operand modes. ORDER BCMode */ -typedef enum { - BCMnone, BCMdst, BCMbase, BCMvar, BCMrbase, BCMuv, /* Mode A must be <= 7 */ - BCMlit, BCMlits, BCMpri, BCMnum, BCMstr, BCMtab, BCMfunc, BCMjump, BCMcdata, - BCM_max -} BCMode; -#define BCM___ BCMnone - -#define bcmode_a(op) ((BCMode)(lj_bc_mode[op] & 7)) -#define bcmode_b(op) ((BCMode)((lj_bc_mode[op]>>3) & 15)) -#define bcmode_c(op) ((BCMode)((lj_bc_mode[op]>>7) & 15)) -#define bcmode_d(op) bcmode_c(op) -#define bcmode_hasd(op) ((lj_bc_mode[op] & (15<<3)) == (BCMnone<<3)) -#define bcmode_mm(op) ((MMS)(lj_bc_mode[op]>>11)) - -#define BCMODE(name, ma, mb, mc, mm) \ - (BCM##ma|(BCM##mb<<3)|(BCM##mc<<7)|(MM_##mm<<11)), -#define BCMODE_FF 0 - -static LJ_AINLINE int bc_isret(BCOp op) -{ - return (op == BC_RETM || op == BC_RET || op == BC_RET0 || op == BC_RET1); -} - -LJ_DATA const uint16_t lj_bc_mode[]; -LJ_DATA const uint16_t lj_bc_ofs[]; - -#endif diff --git a/lib/LuaJIT/src/lj_bcdump.h b/lib/LuaJIT/src/lj_bcdump.h deleted file mode 100644 index fdfc6ec..0000000 --- a/lib/LuaJIT/src/lj_bcdump.h +++ /dev/null @@ -1,68 +0,0 @@ -/* -** Bytecode dump definitions. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_BCDUMP_H -#define _LJ_BCDUMP_H - -#include "lj_obj.h" -#include "lj_lex.h" - -/* -- Bytecode dump format ------------------------------------------------ */ - -/* -** dump = header proto+ 0U -** header = ESC 'L' 'J' versionB flagsU [namelenU nameB*] -** proto = lengthU pdata -** pdata = phead bcinsW* uvdataH* kgc* knum* [debugB*] -** phead = flagsB numparamsB framesizeB numuvB numkgcU numknU numbcU -** [debuglenU [firstlineU numlineU]] -** kgc = kgctypeU { ktab | (loU hiU) | (rloU rhiU iloU ihiU) | strB* } -** knum = intU0 | (loU1 hiU) -** ktab = narrayU nhashU karray* khash* -** karray = ktabk -** khash = ktabk ktabk -** ktabk = ktabtypeU { intU | (loU hiU) | strB* } -** -** B = 8 bit, H = 16 bit, W = 32 bit, U = ULEB128 of W, U0/U1 = ULEB128 of W+1 -*/ - -/* Bytecode dump header. */ -#define BCDUMP_HEAD1 0x1b -#define BCDUMP_HEAD2 0x4c -#define BCDUMP_HEAD3 0x4a - -/* If you perform *any* kind of private modifications to the bytecode itself -** or to the dump format, you *must* set BCDUMP_VERSION to 0x80 or higher. -*/ -#define BCDUMP_VERSION 2 - -/* Compatibility flags. */ -#define BCDUMP_F_BE 0x01 -#define BCDUMP_F_STRIP 0x02 -#define BCDUMP_F_FFI 0x04 -#define BCDUMP_F_FR2 0x08 - -#define BCDUMP_F_KNOWN (BCDUMP_F_FR2*2-1) - -/* Type codes for the GC constants of a prototype. Plus length for strings. */ -enum { - BCDUMP_KGC_CHILD, BCDUMP_KGC_TAB, BCDUMP_KGC_I64, BCDUMP_KGC_U64, - BCDUMP_KGC_COMPLEX, BCDUMP_KGC_STR -}; - -/* Type codes for the keys/values of a constant table. */ -enum { - BCDUMP_KTAB_NIL, BCDUMP_KTAB_FALSE, BCDUMP_KTAB_TRUE, - BCDUMP_KTAB_INT, BCDUMP_KTAB_NUM, BCDUMP_KTAB_STR -}; - -/* -- Bytecode reader/writer ---------------------------------------------- */ - -LJ_FUNC int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, - void *data, int strip); -LJ_FUNC GCproto *lj_bcread_proto(LexState *ls); -LJ_FUNC GCproto *lj_bcread(LexState *ls); - -#endif diff --git a/lib/LuaJIT/src/lj_bcread.c b/lib/LuaJIT/src/lj_bcread.c deleted file mode 100644 index 48c5e7c..0000000 --- a/lib/LuaJIT/src/lj_bcread.c +++ /dev/null @@ -1,457 +0,0 @@ -/* -** Bytecode reader. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_bcread_c -#define LUA_CORE - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_buf.h" -#include "lj_str.h" -#include "lj_tab.h" -#include "lj_bc.h" -#if LJ_HASFFI -#include "lj_ctype.h" -#include "lj_cdata.h" -#include "lualib.h" -#endif -#include "lj_lex.h" -#include "lj_bcdump.h" -#include "lj_state.h" -#include "lj_strfmt.h" - -/* Reuse some lexer fields for our own purposes. */ -#define bcread_flags(ls) ls->level -#define bcread_swap(ls) \ - ((bcread_flags(ls) & BCDUMP_F_BE) != LJ_BE*BCDUMP_F_BE) -#define bcread_oldtop(L, ls) restorestack(L, ls->lastline) -#define bcread_savetop(L, ls, top) \ - ls->lastline = (BCLine)savestack(L, (top)) - -/* -- Input buffer handling ----------------------------------------------- */ - -/* Throw reader error. */ -static LJ_NOINLINE void bcread_error(LexState *ls, ErrMsg em) -{ - lua_State *L = ls->L; - const char *name = ls->chunkarg; - if (*name == BCDUMP_HEAD1) name = "(binary)"; - else if (*name == '@' || *name == '=') name++; - lj_strfmt_pushf(L, "%s: %s", name, err2msg(em)); - lj_err_throw(L, LUA_ERRSYNTAX); -} - -/* Refill buffer. */ -static LJ_NOINLINE void bcread_fill(LexState *ls, MSize len, int need) -{ - lua_assert(len != 0); - if (len > LJ_MAX_BUF || ls->c < 0) - bcread_error(ls, LJ_ERR_BCBAD); - do { - const char *buf; - size_t sz; - char *p = sbufB(&ls->sb); - MSize n = (MSize)(ls->pe - ls->p); - if (n) { /* Copy remainder to buffer. */ - if (sbuflen(&ls->sb)) { /* Move down in buffer. */ - lua_assert(ls->pe == sbufP(&ls->sb)); - if (ls->p != p) memmove(p, ls->p, n); - } else { /* Copy from buffer provided by reader. */ - p = lj_buf_need(&ls->sb, len); - memcpy(p, ls->p, n); - } - ls->p = p; - ls->pe = p + n; - } - setsbufP(&ls->sb, p + n); - buf = ls->rfunc(ls->L, ls->rdata, &sz); /* Get more data from reader. */ - if (buf == NULL || sz == 0) { /* EOF? */ - if (need) bcread_error(ls, LJ_ERR_BCBAD); - ls->c = -1; /* Only bad if we get called again. */ - break; - } - if (n) { /* Append to buffer. */ - n += (MSize)sz; - p = lj_buf_need(&ls->sb, n < len ? len : n); - memcpy(sbufP(&ls->sb), buf, sz); - setsbufP(&ls->sb, p + n); - ls->p = p; - ls->pe = p + n; - } else { /* Return buffer provided by reader. */ - ls->p = buf; - ls->pe = buf + sz; - } - } while (ls->p + len > ls->pe); -} - -/* Need a certain number of bytes. */ -static LJ_AINLINE void bcread_need(LexState *ls, MSize len) -{ - if (LJ_UNLIKELY(ls->p + len > ls->pe)) - bcread_fill(ls, len, 1); -} - -/* Want to read up to a certain number of bytes, but may need less. */ -static LJ_AINLINE void bcread_want(LexState *ls, MSize len) -{ - if (LJ_UNLIKELY(ls->p + len > ls->pe)) - bcread_fill(ls, len, 0); -} - -/* Return memory block from buffer. */ -static LJ_AINLINE uint8_t *bcread_mem(LexState *ls, MSize len) -{ - uint8_t *p = (uint8_t *)ls->p; - ls->p += len; - lua_assert(ls->p <= ls->pe); - return p; -} - -/* Copy memory block from buffer. */ -static void bcread_block(LexState *ls, void *q, MSize len) -{ - memcpy(q, bcread_mem(ls, len), len); -} - -/* Read byte from buffer. */ -static LJ_AINLINE uint32_t bcread_byte(LexState *ls) -{ - lua_assert(ls->p < ls->pe); - return (uint32_t)(uint8_t)*ls->p++; -} - -/* Read ULEB128 value from buffer. */ -static LJ_AINLINE uint32_t bcread_uleb128(LexState *ls) -{ - uint32_t v = lj_buf_ruleb128(&ls->p); - lua_assert(ls->p <= ls->pe); - return v; -} - -/* Read top 32 bits of 33 bit ULEB128 value from buffer. */ -static uint32_t bcread_uleb128_33(LexState *ls) -{ - const uint8_t *p = (const uint8_t *)ls->p; - uint32_t v = (*p++ >> 1); - if (LJ_UNLIKELY(v >= 0x40)) { - int sh = -1; - v &= 0x3f; - do { - v |= ((*p & 0x7f) << (sh += 7)); - } while (*p++ >= 0x80); - } - ls->p = (char *)p; - lua_assert(ls->p <= ls->pe); - return v; -} - -/* -- Bytecode reader ----------------------------------------------------- */ - -/* Read debug info of a prototype. */ -static void bcread_dbg(LexState *ls, GCproto *pt, MSize sizedbg) -{ - void *lineinfo = (void *)proto_lineinfo(pt); - bcread_block(ls, lineinfo, sizedbg); - /* Swap lineinfo if the endianess differs. */ - if (bcread_swap(ls) && pt->numline >= 256) { - MSize i, n = pt->sizebc-1; - if (pt->numline < 65536) { - uint16_t *p = (uint16_t *)lineinfo; - for (i = 0; i < n; i++) p[i] = (uint16_t)((p[i] >> 8)|(p[i] << 8)); - } else { - uint32_t *p = (uint32_t *)lineinfo; - for (i = 0; i < n; i++) p[i] = lj_bswap(p[i]); - } - } -} - -/* Find pointer to varinfo. */ -static const void *bcread_varinfo(GCproto *pt) -{ - const uint8_t *p = proto_uvinfo(pt); - MSize n = pt->sizeuv; - if (n) while (*p++ || --n) ; - return p; -} - -/* Read a single constant key/value of a template table. */ -static void bcread_ktabk(LexState *ls, TValue *o) -{ - MSize tp = bcread_uleb128(ls); - if (tp >= BCDUMP_KTAB_STR) { - MSize len = tp - BCDUMP_KTAB_STR; - const char *p = (const char *)bcread_mem(ls, len); - setstrV(ls->L, o, lj_str_new(ls->L, p, len)); - } else if (tp == BCDUMP_KTAB_INT) { - setintV(o, (int32_t)bcread_uleb128(ls)); - } else if (tp == BCDUMP_KTAB_NUM) { - o->u32.lo = bcread_uleb128(ls); - o->u32.hi = bcread_uleb128(ls); - } else { - lua_assert(tp <= BCDUMP_KTAB_TRUE); - setpriV(o, ~tp); - } -} - -/* Read a template table. */ -static GCtab *bcread_ktab(LexState *ls) -{ - MSize narray = bcread_uleb128(ls); - MSize nhash = bcread_uleb128(ls); - GCtab *t = lj_tab_new(ls->L, narray, hsize2hbits(nhash)); - if (narray) { /* Read array entries. */ - MSize i; - TValue *o = tvref(t->array); - for (i = 0; i < narray; i++, o++) - bcread_ktabk(ls, o); - } - if (nhash) { /* Read hash entries. */ - MSize i; - for (i = 0; i < nhash; i++) { - TValue key; - bcread_ktabk(ls, &key); - lua_assert(!tvisnil(&key)); - bcread_ktabk(ls, lj_tab_set(ls->L, t, &key)); - } - } - return t; -} - -/* Read GC constants of a prototype. */ -static void bcread_kgc(LexState *ls, GCproto *pt, MSize sizekgc) -{ - MSize i; - GCRef *kr = mref(pt->k, GCRef) - (ptrdiff_t)sizekgc; - for (i = 0; i < sizekgc; i++, kr++) { - MSize tp = bcread_uleb128(ls); - if (tp >= BCDUMP_KGC_STR) { - MSize len = tp - BCDUMP_KGC_STR; - const char *p = (const char *)bcread_mem(ls, len); - setgcref(*kr, obj2gco(lj_str_new(ls->L, p, len))); - } else if (tp == BCDUMP_KGC_TAB) { - setgcref(*kr, obj2gco(bcread_ktab(ls))); -#if LJ_HASFFI - } else if (tp != BCDUMP_KGC_CHILD) { - CTypeID id = tp == BCDUMP_KGC_COMPLEX ? CTID_COMPLEX_DOUBLE : - tp == BCDUMP_KGC_I64 ? CTID_INT64 : CTID_UINT64; - CTSize sz = tp == BCDUMP_KGC_COMPLEX ? 16 : 8; - GCcdata *cd = lj_cdata_new_(ls->L, id, sz); - TValue *p = (TValue *)cdataptr(cd); - setgcref(*kr, obj2gco(cd)); - p[0].u32.lo = bcread_uleb128(ls); - p[0].u32.hi = bcread_uleb128(ls); - if (tp == BCDUMP_KGC_COMPLEX) { - p[1].u32.lo = bcread_uleb128(ls); - p[1].u32.hi = bcread_uleb128(ls); - } -#endif - } else { - lua_State *L = ls->L; - lua_assert(tp == BCDUMP_KGC_CHILD); - if (L->top <= bcread_oldtop(L, ls)) /* Stack underflow? */ - bcread_error(ls, LJ_ERR_BCBAD); - L->top--; - setgcref(*kr, obj2gco(protoV(L->top))); - } - } -} - -/* Read number constants of a prototype. */ -static void bcread_knum(LexState *ls, GCproto *pt, MSize sizekn) -{ - MSize i; - TValue *o = mref(pt->k, TValue); - for (i = 0; i < sizekn; i++, o++) { - int isnum = (ls->p[0] & 1); - uint32_t lo = bcread_uleb128_33(ls); - if (isnum) { - o->u32.lo = lo; - o->u32.hi = bcread_uleb128(ls); - } else { - setintV(o, lo); - } - } -} - -/* Read bytecode instructions. */ -static void bcread_bytecode(LexState *ls, GCproto *pt, MSize sizebc) -{ - BCIns *bc = proto_bc(pt); - bc[0] = BCINS_AD((pt->flags & PROTO_VARARG) ? BC_FUNCV : BC_FUNCF, - pt->framesize, 0); - bcread_block(ls, bc+1, (sizebc-1)*(MSize)sizeof(BCIns)); - /* Swap bytecode instructions if the endianess differs. */ - if (bcread_swap(ls)) { - MSize i; - for (i = 1; i < sizebc; i++) bc[i] = lj_bswap(bc[i]); - } -} - -/* Read upvalue refs. */ -static void bcread_uv(LexState *ls, GCproto *pt, MSize sizeuv) -{ - if (sizeuv) { - uint16_t *uv = proto_uv(pt); - bcread_block(ls, uv, sizeuv*2); - /* Swap upvalue refs if the endianess differs. */ - if (bcread_swap(ls)) { - MSize i; - for (i = 0; i < sizeuv; i++) - uv[i] = (uint16_t)((uv[i] >> 8)|(uv[i] << 8)); - } - } -} - -/* Read a prototype. */ -GCproto *lj_bcread_proto(LexState *ls) -{ - GCproto *pt; - MSize framesize, numparams, flags, sizeuv, sizekgc, sizekn, sizebc, sizept; - MSize ofsk, ofsuv, ofsdbg; - MSize sizedbg = 0; - BCLine firstline = 0, numline = 0; - - /* Read prototype header. */ - flags = bcread_byte(ls); - numparams = bcread_byte(ls); - framesize = bcread_byte(ls); - sizeuv = bcread_byte(ls); - sizekgc = bcread_uleb128(ls); - sizekn = bcread_uleb128(ls); - sizebc = bcread_uleb128(ls) + 1; - if (!(bcread_flags(ls) & BCDUMP_F_STRIP)) { - sizedbg = bcread_uleb128(ls); - if (sizedbg) { - firstline = bcread_uleb128(ls); - numline = bcread_uleb128(ls); - } - } - - /* Calculate total size of prototype including all colocated arrays. */ - sizept = (MSize)sizeof(GCproto) + - sizebc*(MSize)sizeof(BCIns) + - sizekgc*(MSize)sizeof(GCRef); - sizept = (sizept + (MSize)sizeof(TValue)-1) & ~((MSize)sizeof(TValue)-1); - ofsk = sizept; sizept += sizekn*(MSize)sizeof(TValue); - ofsuv = sizept; sizept += ((sizeuv+1)&~1)*2; - ofsdbg = sizept; sizept += sizedbg; - - /* Allocate prototype object and initialize its fields. */ - pt = (GCproto *)lj_mem_newgco(ls->L, (MSize)sizept); - pt->gct = ~LJ_TPROTO; - pt->numparams = (uint8_t)numparams; - pt->framesize = (uint8_t)framesize; - pt->sizebc = sizebc; - setmref(pt->k, (char *)pt + ofsk); - setmref(pt->uv, (char *)pt + ofsuv); - pt->sizekgc = 0; /* Set to zero until fully initialized. */ - pt->sizekn = sizekn; - pt->sizept = sizept; - pt->sizeuv = (uint8_t)sizeuv; - pt->flags = (uint8_t)flags; - pt->trace = 0; - setgcref(pt->chunkname, obj2gco(ls->chunkname)); - - /* Close potentially uninitialized gap between bc and kgc. */ - *(uint32_t *)((char *)pt + ofsk - sizeof(GCRef)*(sizekgc+1)) = 0; - - /* Read bytecode instructions and upvalue refs. */ - bcread_bytecode(ls, pt, sizebc); - bcread_uv(ls, pt, sizeuv); - - /* Read constants. */ - bcread_kgc(ls, pt, sizekgc); - pt->sizekgc = sizekgc; - bcread_knum(ls, pt, sizekn); - - /* Read and initialize debug info. */ - pt->firstline = firstline; - pt->numline = numline; - if (sizedbg) { - MSize sizeli = (sizebc-1) << (numline < 256 ? 0 : numline < 65536 ? 1 : 2); - setmref(pt->lineinfo, (char *)pt + ofsdbg); - setmref(pt->uvinfo, (char *)pt + ofsdbg + sizeli); - bcread_dbg(ls, pt, sizedbg); - setmref(pt->varinfo, bcread_varinfo(pt)); - } else { - setmref(pt->lineinfo, NULL); - setmref(pt->uvinfo, NULL); - setmref(pt->varinfo, NULL); - } - return pt; -} - -/* Read and check header of bytecode dump. */ -static int bcread_header(LexState *ls) -{ - uint32_t flags; - bcread_want(ls, 3+5+5); - if (bcread_byte(ls) != BCDUMP_HEAD2 || - bcread_byte(ls) != BCDUMP_HEAD3 || - bcread_byte(ls) != BCDUMP_VERSION) return 0; - bcread_flags(ls) = flags = bcread_uleb128(ls); - if ((flags & ~(BCDUMP_F_KNOWN)) != 0) return 0; - if ((flags & BCDUMP_F_FR2) != LJ_FR2*BCDUMP_F_FR2) return 0; - if ((flags & BCDUMP_F_FFI)) { -#if LJ_HASFFI - lua_State *L = ls->L; - if (!ctype_ctsG(G(L))) { - ptrdiff_t oldtop = savestack(L, L->top); - luaopen_ffi(L); /* Load FFI library on-demand. */ - L->top = restorestack(L, oldtop); - } -#else - return 0; -#endif - } - if ((flags & BCDUMP_F_STRIP)) { - ls->chunkname = lj_str_newz(ls->L, ls->chunkarg); - } else { - MSize len = bcread_uleb128(ls); - bcread_need(ls, len); - ls->chunkname = lj_str_new(ls->L, (const char *)bcread_mem(ls, len), len); - } - return 1; /* Ok. */ -} - -/* Read a bytecode dump. */ -GCproto *lj_bcread(LexState *ls) -{ - lua_State *L = ls->L; - lua_assert(ls->c == BCDUMP_HEAD1); - bcread_savetop(L, ls, L->top); - lj_buf_reset(&ls->sb); - /* Check for a valid bytecode dump header. */ - if (!bcread_header(ls)) - bcread_error(ls, LJ_ERR_BCFMT); - for (;;) { /* Process all prototypes in the bytecode dump. */ - GCproto *pt; - MSize len; - const char *startp; - /* Read length. */ - if (ls->p < ls->pe && ls->p[0] == 0) { /* Shortcut EOF. */ - ls->p++; - break; - } - bcread_want(ls, 5); - len = bcread_uleb128(ls); - if (!len) break; /* EOF */ - bcread_need(ls, len); - startp = ls->p; - pt = lj_bcread_proto(ls); - if (ls->p != startp + len) - bcread_error(ls, LJ_ERR_BCBAD); - setprotoV(L, L->top, pt); - incr_top(L); - } - if ((int32_t)(2*(uint32_t)(ls->pe - ls->p)) > 0 || - L->top-1 != bcread_oldtop(L, ls)) - bcread_error(ls, LJ_ERR_BCBAD); - /* Pop off last prototype. */ - L->top--; - return protoV(L->top); -} - diff --git a/lib/LuaJIT/src/lj_bcwrite.c b/lib/LuaJIT/src/lj_bcwrite.c deleted file mode 100644 index 5e05cae..0000000 --- a/lib/LuaJIT/src/lj_bcwrite.c +++ /dev/null @@ -1,361 +0,0 @@ -/* -** Bytecode writer. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_bcwrite_c -#define LUA_CORE - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_buf.h" -#include "lj_bc.h" -#if LJ_HASFFI -#include "lj_ctype.h" -#endif -#if LJ_HASJIT -#include "lj_dispatch.h" -#include "lj_jit.h" -#endif -#include "lj_strfmt.h" -#include "lj_bcdump.h" -#include "lj_vm.h" - -/* Context for bytecode writer. */ -typedef struct BCWriteCtx { - SBuf sb; /* Output buffer. */ - GCproto *pt; /* Root prototype. */ - lua_Writer wfunc; /* Writer callback. */ - void *wdata; /* Writer callback data. */ - int strip; /* Strip debug info. */ - int status; /* Status from writer callback. */ -} BCWriteCtx; - -/* -- Bytecode writer ----------------------------------------------------- */ - -/* Write a single constant key/value of a template table. */ -static void bcwrite_ktabk(BCWriteCtx *ctx, cTValue *o, int narrow) -{ - char *p = lj_buf_more(&ctx->sb, 1+10); - if (tvisstr(o)) { - const GCstr *str = strV(o); - MSize len = str->len; - p = lj_buf_more(&ctx->sb, 5+len); - p = lj_strfmt_wuleb128(p, BCDUMP_KTAB_STR+len); - p = lj_buf_wmem(p, strdata(str), len); - } else if (tvisint(o)) { - *p++ = BCDUMP_KTAB_INT; - p = lj_strfmt_wuleb128(p, intV(o)); - } else if (tvisnum(o)) { - if (!LJ_DUALNUM && narrow) { /* Narrow number constants to integers. */ - lua_Number num = numV(o); - int32_t k = lj_num2int(num); - if (num == (lua_Number)k) { /* -0 is never a constant. */ - *p++ = BCDUMP_KTAB_INT; - p = lj_strfmt_wuleb128(p, k); - setsbufP(&ctx->sb, p); - return; - } - } - *p++ = BCDUMP_KTAB_NUM; - p = lj_strfmt_wuleb128(p, o->u32.lo); - p = lj_strfmt_wuleb128(p, o->u32.hi); - } else { - lua_assert(tvispri(o)); - *p++ = BCDUMP_KTAB_NIL+~itype(o); - } - setsbufP(&ctx->sb, p); -} - -/* Write a template table. */ -static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const GCtab *t) -{ - MSize narray = 0, nhash = 0; - if (t->asize > 0) { /* Determine max. length of array part. */ - ptrdiff_t i; - TValue *array = tvref(t->array); - for (i = (ptrdiff_t)t->asize-1; i >= 0; i--) - if (!tvisnil(&array[i])) - break; - narray = (MSize)(i+1); - } - if (t->hmask > 0) { /* Count number of used hash slots. */ - MSize i, hmask = t->hmask; - Node *node = noderef(t->node); - for (i = 0; i <= hmask; i++) - nhash += !tvisnil(&node[i].val); - } - /* Write number of array slots and hash slots. */ - p = lj_strfmt_wuleb128(p, narray); - p = lj_strfmt_wuleb128(p, nhash); - setsbufP(&ctx->sb, p); - if (narray) { /* Write array entries (may contain nil). */ - MSize i; - TValue *o = tvref(t->array); - for (i = 0; i < narray; i++, o++) - bcwrite_ktabk(ctx, o, 1); - } - if (nhash) { /* Write hash entries. */ - MSize i = nhash; - Node *node = noderef(t->node) + t->hmask; - for (;; node--) - if (!tvisnil(&node->val)) { - bcwrite_ktabk(ctx, &node->key, 0); - bcwrite_ktabk(ctx, &node->val, 1); - if (--i == 0) break; - } - } -} - -/* Write GC constants of a prototype. */ -static void bcwrite_kgc(BCWriteCtx *ctx, GCproto *pt) -{ - MSize i, sizekgc = pt->sizekgc; - GCRef *kr = mref(pt->k, GCRef) - (ptrdiff_t)sizekgc; - for (i = 0; i < sizekgc; i++, kr++) { - GCobj *o = gcref(*kr); - MSize tp, need = 1; - char *p; - /* Determine constant type and needed size. */ - if (o->gch.gct == ~LJ_TSTR) { - tp = BCDUMP_KGC_STR + gco2str(o)->len; - need = 5+gco2str(o)->len; - } else if (o->gch.gct == ~LJ_TPROTO) { - lua_assert((pt->flags & PROTO_CHILD)); - tp = BCDUMP_KGC_CHILD; -#if LJ_HASFFI - } else if (o->gch.gct == ~LJ_TCDATA) { - CTypeID id = gco2cd(o)->ctypeid; - need = 1+4*5; - if (id == CTID_INT64) { - tp = BCDUMP_KGC_I64; - } else if (id == CTID_UINT64) { - tp = BCDUMP_KGC_U64; - } else { - lua_assert(id == CTID_COMPLEX_DOUBLE); - tp = BCDUMP_KGC_COMPLEX; - } -#endif - } else { - lua_assert(o->gch.gct == ~LJ_TTAB); - tp = BCDUMP_KGC_TAB; - need = 1+2*5; - } - /* Write constant type. */ - p = lj_buf_more(&ctx->sb, need); - p = lj_strfmt_wuleb128(p, tp); - /* Write constant data (if any). */ - if (tp >= BCDUMP_KGC_STR) { - p = lj_buf_wmem(p, strdata(gco2str(o)), gco2str(o)->len); - } else if (tp == BCDUMP_KGC_TAB) { - bcwrite_ktab(ctx, p, gco2tab(o)); - continue; -#if LJ_HASFFI - } else if (tp != BCDUMP_KGC_CHILD) { - cTValue *q = (TValue *)cdataptr(gco2cd(o)); - p = lj_strfmt_wuleb128(p, q[0].u32.lo); - p = lj_strfmt_wuleb128(p, q[0].u32.hi); - if (tp == BCDUMP_KGC_COMPLEX) { - p = lj_strfmt_wuleb128(p, q[1].u32.lo); - p = lj_strfmt_wuleb128(p, q[1].u32.hi); - } -#endif - } - setsbufP(&ctx->sb, p); - } -} - -/* Write number constants of a prototype. */ -static void bcwrite_knum(BCWriteCtx *ctx, GCproto *pt) -{ - MSize i, sizekn = pt->sizekn; - cTValue *o = mref(pt->k, TValue); - char *p = lj_buf_more(&ctx->sb, 10*sizekn); - for (i = 0; i < sizekn; i++, o++) { - int32_t k; - if (tvisint(o)) { - k = intV(o); - goto save_int; - } else { - /* Write a 33 bit ULEB128 for the int (lsb=0) or loword (lsb=1). */ - if (!LJ_DUALNUM) { /* Narrow number constants to integers. */ - lua_Number num = numV(o); - k = lj_num2int(num); - if (num == (lua_Number)k) { /* -0 is never a constant. */ - save_int: - p = lj_strfmt_wuleb128(p, 2*(uint32_t)k | ((uint32_t)k&0x80000000u)); - if (k < 0) - p[-1] = (p[-1] & 7) | ((k>>27) & 0x18); - continue; - } - } - p = lj_strfmt_wuleb128(p, 1+(2*o->u32.lo | (o->u32.lo & 0x80000000u))); - if (o->u32.lo >= 0x80000000u) - p[-1] = (p[-1] & 7) | ((o->u32.lo>>27) & 0x18); - p = lj_strfmt_wuleb128(p, o->u32.hi); - } - } - setsbufP(&ctx->sb, p); -} - -/* Write bytecode instructions. */ -static char *bcwrite_bytecode(BCWriteCtx *ctx, char *p, GCproto *pt) -{ - MSize nbc = pt->sizebc-1; /* Omit the [JI]FUNC* header. */ -#if LJ_HASJIT - uint8_t *q = (uint8_t *)p; -#endif - p = lj_buf_wmem(p, proto_bc(pt)+1, nbc*(MSize)sizeof(BCIns)); - UNUSED(ctx); -#if LJ_HASJIT - /* Unpatch modified bytecode containing ILOOP/JLOOP etc. */ - if ((pt->flags & PROTO_ILOOP) || pt->trace) { - jit_State *J = L2J(sbufL(&ctx->sb)); - MSize i; - for (i = 0; i < nbc; i++, q += sizeof(BCIns)) { - BCOp op = (BCOp)q[LJ_ENDIAN_SELECT(0, 3)]; - if (op == BC_IFORL || op == BC_IITERL || op == BC_ILOOP || - op == BC_JFORI) { - q[LJ_ENDIAN_SELECT(0, 3)] = (uint8_t)(op-BC_IFORL+BC_FORL); - } else if (op == BC_JFORL || op == BC_JITERL || op == BC_JLOOP) { - BCReg rd = q[LJ_ENDIAN_SELECT(2, 1)] + (q[LJ_ENDIAN_SELECT(3, 0)] << 8); - BCIns ins = traceref(J, rd)->startins; - q[LJ_ENDIAN_SELECT(0, 3)] = (uint8_t)(op-BC_JFORL+BC_FORL); - q[LJ_ENDIAN_SELECT(2, 1)] = bc_c(ins); - q[LJ_ENDIAN_SELECT(3, 0)] = bc_b(ins); - } - } - } -#endif - return p; -} - -/* Write prototype. */ -static void bcwrite_proto(BCWriteCtx *ctx, GCproto *pt) -{ - MSize sizedbg = 0; - char *p; - - /* Recursively write children of prototype. */ - if ((pt->flags & PROTO_CHILD)) { - ptrdiff_t i, n = pt->sizekgc; - GCRef *kr = mref(pt->k, GCRef) - 1; - for (i = 0; i < n; i++, kr--) { - GCobj *o = gcref(*kr); - if (o->gch.gct == ~LJ_TPROTO) - bcwrite_proto(ctx, gco2pt(o)); - } - } - - /* Start writing the prototype info to a buffer. */ - p = lj_buf_need(&ctx->sb, - 5+4+6*5+(pt->sizebc-1)*(MSize)sizeof(BCIns)+pt->sizeuv*2); - p += 5; /* Leave room for final size. */ - - /* Write prototype header. */ - *p++ = (pt->flags & (PROTO_CHILD|PROTO_VARARG|PROTO_FFI)); - *p++ = pt->numparams; - *p++ = pt->framesize; - *p++ = pt->sizeuv; - p = lj_strfmt_wuleb128(p, pt->sizekgc); - p = lj_strfmt_wuleb128(p, pt->sizekn); - p = lj_strfmt_wuleb128(p, pt->sizebc-1); - if (!ctx->strip) { - if (proto_lineinfo(pt)) - sizedbg = pt->sizept - (MSize)((char *)proto_lineinfo(pt) - (char *)pt); - p = lj_strfmt_wuleb128(p, sizedbg); - if (sizedbg) { - p = lj_strfmt_wuleb128(p, pt->firstline); - p = lj_strfmt_wuleb128(p, pt->numline); - } - } - - /* Write bytecode instructions and upvalue refs. */ - p = bcwrite_bytecode(ctx, p, pt); - p = lj_buf_wmem(p, proto_uv(pt), pt->sizeuv*2); - setsbufP(&ctx->sb, p); - - /* Write constants. */ - bcwrite_kgc(ctx, pt); - bcwrite_knum(ctx, pt); - - /* Write debug info, if not stripped. */ - if (sizedbg) { - p = lj_buf_more(&ctx->sb, sizedbg); - p = lj_buf_wmem(p, proto_lineinfo(pt), sizedbg); - setsbufP(&ctx->sb, p); - } - - /* Pass buffer to writer function. */ - if (ctx->status == 0) { - MSize n = sbuflen(&ctx->sb) - 5; - MSize nn = (lj_fls(n)+8)*9 >> 6; - char *q = sbufB(&ctx->sb) + (5 - nn); - p = lj_strfmt_wuleb128(q, n); /* Fill in final size. */ - lua_assert(p == sbufB(&ctx->sb) + 5); - ctx->status = ctx->wfunc(sbufL(&ctx->sb), q, nn+n, ctx->wdata); - } -} - -/* Write header of bytecode dump. */ -static void bcwrite_header(BCWriteCtx *ctx) -{ - GCstr *chunkname = proto_chunkname(ctx->pt); - const char *name = strdata(chunkname); - MSize len = chunkname->len; - char *p = lj_buf_need(&ctx->sb, 5+5+len); - *p++ = BCDUMP_HEAD1; - *p++ = BCDUMP_HEAD2; - *p++ = BCDUMP_HEAD3; - *p++ = BCDUMP_VERSION; - *p++ = (ctx->strip ? BCDUMP_F_STRIP : 0) + - LJ_BE*BCDUMP_F_BE + - ((ctx->pt->flags & PROTO_FFI) ? BCDUMP_F_FFI : 0) + - LJ_FR2*BCDUMP_F_FR2; - if (!ctx->strip) { - p = lj_strfmt_wuleb128(p, len); - p = lj_buf_wmem(p, name, len); - } - ctx->status = ctx->wfunc(sbufL(&ctx->sb), sbufB(&ctx->sb), - (MSize)(p - sbufB(&ctx->sb)), ctx->wdata); -} - -/* Write footer of bytecode dump. */ -static void bcwrite_footer(BCWriteCtx *ctx) -{ - if (ctx->status == 0) { - uint8_t zero = 0; - ctx->status = ctx->wfunc(sbufL(&ctx->sb), &zero, 1, ctx->wdata); - } -} - -/* Protected callback for bytecode writer. */ -static TValue *cpwriter(lua_State *L, lua_CFunction dummy, void *ud) -{ - BCWriteCtx *ctx = (BCWriteCtx *)ud; - UNUSED(L); UNUSED(dummy); - lj_buf_need(&ctx->sb, 1024); /* Avoids resize for most prototypes. */ - bcwrite_header(ctx); - bcwrite_proto(ctx, ctx->pt); - bcwrite_footer(ctx); - return NULL; -} - -/* Write bytecode for a prototype. */ -int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, void *data, - int strip) -{ - BCWriteCtx ctx; - int status; - ctx.pt = pt; - ctx.wfunc = writer; - ctx.wdata = data; - ctx.strip = strip; - ctx.status = 0; - lj_buf_init(L, &ctx.sb); - status = lj_vm_cpcall(L, NULL, &ctx, cpwriter); - if (status == 0) status = ctx.status; - lj_buf_free(G(sbufL(&ctx.sb)), &ctx.sb); - return status; -} - diff --git a/lib/LuaJIT/src/lj_buf.c b/lib/LuaJIT/src/lj_buf.c deleted file mode 100644 index 0dfe7f9..0000000 --- a/lib/LuaJIT/src/lj_buf.c +++ /dev/null @@ -1,232 +0,0 @@ -/* -** Buffer handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_buf_c -#define LUA_CORE - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_buf.h" -#include "lj_str.h" -#include "lj_tab.h" -#include "lj_strfmt.h" - -/* -- Buffer management --------------------------------------------------- */ - -static void buf_grow(SBuf *sb, MSize sz) -{ - MSize osz = sbufsz(sb), len = sbuflen(sb), nsz = osz; - char *b; - if (nsz < LJ_MIN_SBUF) nsz = LJ_MIN_SBUF; - while (nsz < sz) nsz += nsz; - b = (char *)lj_mem_realloc(sbufL(sb), sbufB(sb), osz, nsz); - setmref(sb->b, b); - setmref(sb->p, b + len); - setmref(sb->e, b + nsz); -} - -LJ_NOINLINE char *LJ_FASTCALL lj_buf_need2(SBuf *sb, MSize sz) -{ - lua_assert(sz > sbufsz(sb)); - if (LJ_UNLIKELY(sz > LJ_MAX_BUF)) - lj_err_mem(sbufL(sb)); - buf_grow(sb, sz); - return sbufB(sb); -} - -LJ_NOINLINE char *LJ_FASTCALL lj_buf_more2(SBuf *sb, MSize sz) -{ - MSize len = sbuflen(sb); - lua_assert(sz > sbufleft(sb)); - if (LJ_UNLIKELY(sz > LJ_MAX_BUF || len + sz > LJ_MAX_BUF)) - lj_err_mem(sbufL(sb)); - buf_grow(sb, len + sz); - return sbufP(sb); -} - -void LJ_FASTCALL lj_buf_shrink(lua_State *L, SBuf *sb) -{ - char *b = sbufB(sb); - MSize osz = (MSize)(sbufE(sb) - b); - if (osz > 2*LJ_MIN_SBUF) { - MSize n = (MSize)(sbufP(sb) - b); - b = lj_mem_realloc(L, b, osz, (osz >> 1)); - setmref(sb->b, b); - setmref(sb->p, b + n); - setmref(sb->e, b + (osz >> 1)); - } -} - -char * LJ_FASTCALL lj_buf_tmp(lua_State *L, MSize sz) -{ - SBuf *sb = &G(L)->tmpbuf; - setsbufL(sb, L); - return lj_buf_need(sb, sz); -} - -/* -- Low-level buffer put operations ------------------------------------- */ - -SBuf *lj_buf_putmem(SBuf *sb, const void *q, MSize len) -{ - char *p = lj_buf_more(sb, len); - p = lj_buf_wmem(p, q, len); - setsbufP(sb, p); - return sb; -} - -SBuf * LJ_FASTCALL lj_buf_putchar(SBuf *sb, int c) -{ - char *p = lj_buf_more(sb, 1); - *p++ = (char)c; - setsbufP(sb, p); - return sb; -} - -SBuf * LJ_FASTCALL lj_buf_putstr(SBuf *sb, GCstr *s) -{ - MSize len = s->len; - char *p = lj_buf_more(sb, len); - p = lj_buf_wmem(p, strdata(s), len); - setsbufP(sb, p); - return sb; -} - -/* -- High-level buffer put operations ------------------------------------ */ - -SBuf * LJ_FASTCALL lj_buf_putstr_reverse(SBuf *sb, GCstr *s) -{ - MSize len = s->len; - char *p = lj_buf_more(sb, len), *e = p+len; - const char *q = strdata(s)+len-1; - while (p < e) - *p++ = *q--; - setsbufP(sb, p); - return sb; -} - -SBuf * LJ_FASTCALL lj_buf_putstr_lower(SBuf *sb, GCstr *s) -{ - MSize len = s->len; - char *p = lj_buf_more(sb, len), *e = p+len; - const char *q = strdata(s); - for (; p < e; p++, q++) { - uint32_t c = *(unsigned char *)q; -#if LJ_TARGET_PPC - *p = c + ((c >= 'A' && c <= 'Z') << 5); -#else - if (c >= 'A' && c <= 'Z') c += 0x20; - *p = c; -#endif - } - setsbufP(sb, p); - return sb; -} - -SBuf * LJ_FASTCALL lj_buf_putstr_upper(SBuf *sb, GCstr *s) -{ - MSize len = s->len; - char *p = lj_buf_more(sb, len), *e = p+len; - const char *q = strdata(s); - for (; p < e; p++, q++) { - uint32_t c = *(unsigned char *)q; -#if LJ_TARGET_PPC - *p = c - ((c >= 'a' && c <= 'z') << 5); -#else - if (c >= 'a' && c <= 'z') c -= 0x20; - *p = c; -#endif - } - setsbufP(sb, p); - return sb; -} - -SBuf *lj_buf_putstr_rep(SBuf *sb, GCstr *s, int32_t rep) -{ - MSize len = s->len; - if (rep > 0 && len) { - uint64_t tlen = (uint64_t)rep * len; - char *p; - if (LJ_UNLIKELY(tlen > LJ_MAX_STR)) - lj_err_mem(sbufL(sb)); - p = lj_buf_more(sb, (MSize)tlen); - if (len == 1) { /* Optimize a common case. */ - uint32_t c = strdata(s)[0]; - do { *p++ = c; } while (--rep > 0); - } else { - const char *e = strdata(s) + len; - do { - const char *q = strdata(s); - do { *p++ = *q++; } while (q < e); - } while (--rep > 0); - } - setsbufP(sb, p); - } - return sb; -} - -SBuf *lj_buf_puttab(SBuf *sb, GCtab *t, GCstr *sep, int32_t i, int32_t e) -{ - MSize seplen = sep ? sep->len : 0; - if (i <= e) { - for (;;) { - cTValue *o = lj_tab_getint(t, i); - char *p; - if (!o) { - badtype: /* Error: bad element type. */ - setsbufP(sb, (void *)(intptr_t)i); /* Store failing index. */ - return NULL; - } else if (tvisstr(o)) { - MSize len = strV(o)->len; - p = lj_buf_wmem(lj_buf_more(sb, len + seplen), strVdata(o), len); - } else if (tvisint(o)) { - p = lj_strfmt_wint(lj_buf_more(sb, STRFMT_MAXBUF_INT+seplen), intV(o)); - } else if (tvisnum(o)) { - p = lj_buf_more(lj_strfmt_putfnum(sb, STRFMT_G14, numV(o)), seplen); - } else { - goto badtype; - } - if (i++ == e) { - setsbufP(sb, p); - break; - } - if (seplen) p = lj_buf_wmem(p, strdata(sep), seplen); - setsbufP(sb, p); - } - } - return sb; -} - -/* -- Miscellaneous buffer operations ------------------------------------- */ - -GCstr * LJ_FASTCALL lj_buf_tostr(SBuf *sb) -{ - return lj_str_new(sbufL(sb), sbufB(sb), sbuflen(sb)); -} - -/* Concatenate two strings. */ -GCstr *lj_buf_cat2str(lua_State *L, GCstr *s1, GCstr *s2) -{ - MSize len1 = s1->len, len2 = s2->len; - char *buf = lj_buf_tmp(L, len1 + len2); - memcpy(buf, strdata(s1), len1); - memcpy(buf+len1, strdata(s2), len2); - return lj_str_new(L, buf, len1 + len2); -} - -/* Read ULEB128 from buffer. */ -uint32_t LJ_FASTCALL lj_buf_ruleb128(const char **pp) -{ - const uint8_t *p = (const uint8_t *)*pp; - uint32_t v = *p++; - if (LJ_UNLIKELY(v >= 0x80)) { - int sh = 0; - v &= 0x7f; - do { v |= ((*p & 0x7f) << (sh += 7)); } while (*p++ >= 0x80); - } - *pp = (const char *)p; - return v; -} - diff --git a/lib/LuaJIT/src/lj_buf.h b/lib/LuaJIT/src/lj_buf.h deleted file mode 100644 index a405169..0000000 --- a/lib/LuaJIT/src/lj_buf.h +++ /dev/null @@ -1,103 +0,0 @@ -/* -** Buffer handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_BUF_H -#define _LJ_BUF_H - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_str.h" - -/* Resizable string buffers. Struct definition in lj_obj.h. */ -#define sbufB(sb) (mref((sb)->b, char)) -#define sbufP(sb) (mref((sb)->p, char)) -#define sbufE(sb) (mref((sb)->e, char)) -#define sbufL(sb) (mref((sb)->L, lua_State)) -#define sbufsz(sb) ((MSize)(sbufE((sb)) - sbufB((sb)))) -#define sbuflen(sb) ((MSize)(sbufP((sb)) - sbufB((sb)))) -#define sbufleft(sb) ((MSize)(sbufE((sb)) - sbufP((sb)))) -#define setsbufP(sb, q) (setmref((sb)->p, (q))) -#define setsbufL(sb, l) (setmref((sb)->L, (l))) - -/* Buffer management */ -LJ_FUNC char *LJ_FASTCALL lj_buf_need2(SBuf *sb, MSize sz); -LJ_FUNC char *LJ_FASTCALL lj_buf_more2(SBuf *sb, MSize sz); -LJ_FUNC void LJ_FASTCALL lj_buf_shrink(lua_State *L, SBuf *sb); -LJ_FUNC char * LJ_FASTCALL lj_buf_tmp(lua_State *L, MSize sz); - -static LJ_AINLINE void lj_buf_init(lua_State *L, SBuf *sb) -{ - setsbufL(sb, L); - setmref(sb->p, NULL); setmref(sb->e, NULL); setmref(sb->b, NULL); -} - -static LJ_AINLINE void lj_buf_reset(SBuf *sb) -{ - setmrefr(sb->p, sb->b); -} - -static LJ_AINLINE SBuf *lj_buf_tmp_(lua_State *L) -{ - SBuf *sb = &G(L)->tmpbuf; - setsbufL(sb, L); - lj_buf_reset(sb); - return sb; -} - -static LJ_AINLINE void lj_buf_free(global_State *g, SBuf *sb) -{ - lj_mem_free(g, sbufB(sb), sbufsz(sb)); -} - -static LJ_AINLINE char *lj_buf_need(SBuf *sb, MSize sz) -{ - if (LJ_UNLIKELY(sz > sbufsz(sb))) - return lj_buf_need2(sb, sz); - return sbufB(sb); -} - -static LJ_AINLINE char *lj_buf_more(SBuf *sb, MSize sz) -{ - if (LJ_UNLIKELY(sz > sbufleft(sb))) - return lj_buf_more2(sb, sz); - return sbufP(sb); -} - -/* Low-level buffer put operations */ -LJ_FUNC SBuf *lj_buf_putmem(SBuf *sb, const void *q, MSize len); -LJ_FUNC SBuf * LJ_FASTCALL lj_buf_putchar(SBuf *sb, int c); -LJ_FUNC SBuf * LJ_FASTCALL lj_buf_putstr(SBuf *sb, GCstr *s); - -static LJ_AINLINE char *lj_buf_wmem(char *p, const void *q, MSize len) -{ - return (char *)memcpy(p, q, len) + len; -} - -static LJ_AINLINE void lj_buf_putb(SBuf *sb, int c) -{ - char *p = lj_buf_more(sb, 1); - *p++ = (char)c; - setsbufP(sb, p); -} - -/* High-level buffer put operations */ -LJ_FUNCA SBuf * LJ_FASTCALL lj_buf_putstr_reverse(SBuf *sb, GCstr *s); -LJ_FUNCA SBuf * LJ_FASTCALL lj_buf_putstr_lower(SBuf *sb, GCstr *s); -LJ_FUNCA SBuf * LJ_FASTCALL lj_buf_putstr_upper(SBuf *sb, GCstr *s); -LJ_FUNC SBuf *lj_buf_putstr_rep(SBuf *sb, GCstr *s, int32_t rep); -LJ_FUNC SBuf *lj_buf_puttab(SBuf *sb, GCtab *t, GCstr *sep, - int32_t i, int32_t e); - -/* Miscellaneous buffer operations */ -LJ_FUNCA GCstr * LJ_FASTCALL lj_buf_tostr(SBuf *sb); -LJ_FUNC GCstr *lj_buf_cat2str(lua_State *L, GCstr *s1, GCstr *s2); -LJ_FUNC uint32_t LJ_FASTCALL lj_buf_ruleb128(const char **pp); - -static LJ_AINLINE GCstr *lj_buf_str(lua_State *L, SBuf *sb) -{ - return lj_str_new(L, sbufB(sb), sbuflen(sb)); -} - -#endif diff --git a/lib/LuaJIT/src/lj_carith.c b/lib/LuaJIT/src/lj_carith.c deleted file mode 100644 index 1c050eb..0000000 --- a/lib/LuaJIT/src/lj_carith.c +++ /dev/null @@ -1,437 +0,0 @@ -/* -** C data arithmetic. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#include "lj_obj.h" - -#if LJ_HASFFI - -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_tab.h" -#include "lj_meta.h" -#include "lj_ir.h" -#include "lj_ctype.h" -#include "lj_cconv.h" -#include "lj_cdata.h" -#include "lj_carith.h" -#include "lj_strscan.h" - -/* -- C data arithmetic --------------------------------------------------- */ - -/* Binary operands of an operator converted to ctypes. */ -typedef struct CDArith { - uint8_t *p[2]; - CType *ct[2]; -} CDArith; - -/* Check arguments for arithmetic metamethods. */ -static int carith_checkarg(lua_State *L, CTState *cts, CDArith *ca) -{ - TValue *o = L->base; - int ok = 1; - MSize i; - if (o+1 >= L->top) - lj_err_argt(L, 1, LUA_TCDATA); - for (i = 0; i < 2; i++, o++) { - if (tviscdata(o)) { - GCcdata *cd = cdataV(o); - CTypeID id = (CTypeID)cd->ctypeid; - CType *ct = ctype_raw(cts, id); - uint8_t *p = (uint8_t *)cdataptr(cd); - if (ctype_isptr(ct->info)) { - p = (uint8_t *)cdata_getptr(p, ct->size); - if (ctype_isref(ct->info)) ct = ctype_rawchild(cts, ct); - } else if (ctype_isfunc(ct->info)) { - p = (uint8_t *)*(void **)p; - ct = ctype_get(cts, - lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|id), CTSIZE_PTR)); - } - if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct); - ca->ct[i] = ct; - ca->p[i] = p; - } else if (tvisint(o)) { - ca->ct[i] = ctype_get(cts, CTID_INT32); - ca->p[i] = (uint8_t *)&o->i; - } else if (tvisnum(o)) { - ca->ct[i] = ctype_get(cts, CTID_DOUBLE); - ca->p[i] = (uint8_t *)&o->n; - } else if (tvisnil(o)) { - ca->ct[i] = ctype_get(cts, CTID_P_VOID); - ca->p[i] = (uint8_t *)0; - } else if (tvisstr(o)) { - TValue *o2 = i == 0 ? o+1 : o-1; - CType *ct = ctype_raw(cts, cdataV(o2)->ctypeid); - ca->ct[i] = NULL; - ca->p[i] = (uint8_t *)strVdata(o); - ok = 0; - if (ctype_isenum(ct->info)) { - CTSize ofs; - CType *cct = lj_ctype_getfield(cts, ct, strV(o), &ofs); - if (cct && ctype_isconstval(cct->info)) { - ca->ct[i] = ctype_child(cts, cct); - ca->p[i] = (uint8_t *)&cct->size; /* Assumes ct does not grow. */ - ok = 1; - } else { - ca->ct[1-i] = ct; /* Use enum to improve error message. */ - ca->p[1-i] = NULL; - break; - } - } - } else { - ca->ct[i] = NULL; - ca->p[i] = (void *)(intptr_t)1; /* To make it unequal. */ - ok = 0; - } - } - return ok; -} - -/* Pointer arithmetic. */ -static int carith_ptr(lua_State *L, CTState *cts, CDArith *ca, MMS mm) -{ - CType *ctp = ca->ct[0]; - uint8_t *pp = ca->p[0]; - ptrdiff_t idx; - CTSize sz; - CTypeID id; - GCcdata *cd; - if (ctype_isptr(ctp->info) || ctype_isrefarray(ctp->info)) { - if ((mm == MM_sub || mm == MM_eq || mm == MM_lt || mm == MM_le) && - (ctype_isptr(ca->ct[1]->info) || ctype_isrefarray(ca->ct[1]->info))) { - uint8_t *pp2 = ca->p[1]; - if (mm == MM_eq) { /* Pointer equality. Incompatible pointers are ok. */ - setboolV(L->top-1, (pp == pp2)); - return 1; - } - if (!lj_cconv_compatptr(cts, ctp, ca->ct[1], CCF_IGNQUAL)) - return 0; - if (mm == MM_sub) { /* Pointer difference. */ - intptr_t diff; - sz = lj_ctype_size(cts, ctype_cid(ctp->info)); /* Element size. */ - if (sz == 0 || sz == CTSIZE_INVALID) - return 0; - diff = ((intptr_t)pp - (intptr_t)pp2) / (int32_t)sz; - /* All valid pointer differences on x64 are in (-2^47, +2^47), - ** which fits into a double without loss of precision. - */ - setintptrV(L->top-1, (int32_t)diff); - return 1; - } else if (mm == MM_lt) { /* Pointer comparison (unsigned). */ - setboolV(L->top-1, ((uintptr_t)pp < (uintptr_t)pp2)); - return 1; - } else { - lua_assert(mm == MM_le); - setboolV(L->top-1, ((uintptr_t)pp <= (uintptr_t)pp2)); - return 1; - } - } - if (!((mm == MM_add || mm == MM_sub) && ctype_isnum(ca->ct[1]->info))) - return 0; - lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), ca->ct[1], - (uint8_t *)&idx, ca->p[1], 0); - if (mm == MM_sub) idx = -idx; - } else if (mm == MM_add && ctype_isnum(ctp->info) && - (ctype_isptr(ca->ct[1]->info) || ctype_isrefarray(ca->ct[1]->info))) { - /* Swap pointer and index. */ - ctp = ca->ct[1]; pp = ca->p[1]; - lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), ca->ct[0], - (uint8_t *)&idx, ca->p[0], 0); - } else { - return 0; - } - sz = lj_ctype_size(cts, ctype_cid(ctp->info)); /* Element size. */ - if (sz == CTSIZE_INVALID) - return 0; - pp += idx*(int32_t)sz; /* Compute pointer + index. */ - id = lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|ctype_cid(ctp->info)), - CTSIZE_PTR); - cd = lj_cdata_new(cts, id, CTSIZE_PTR); - *(uint8_t **)cdataptr(cd) = pp; - setcdataV(L, L->top-1, cd); - lj_gc_check(L); - return 1; -} - -/* 64 bit integer arithmetic. */ -static int carith_int64(lua_State *L, CTState *cts, CDArith *ca, MMS mm) -{ - if (ctype_isnum(ca->ct[0]->info) && ca->ct[0]->size <= 8 && - ctype_isnum(ca->ct[1]->info) && ca->ct[1]->size <= 8) { - CTypeID id = (((ca->ct[0]->info & CTF_UNSIGNED) && ca->ct[0]->size == 8) || - ((ca->ct[1]->info & CTF_UNSIGNED) && ca->ct[1]->size == 8)) ? - CTID_UINT64 : CTID_INT64; - CType *ct = ctype_get(cts, id); - GCcdata *cd; - uint64_t u0, u1, *up; - lj_cconv_ct_ct(cts, ct, ca->ct[0], (uint8_t *)&u0, ca->p[0], 0); - if (mm != MM_unm) - lj_cconv_ct_ct(cts, ct, ca->ct[1], (uint8_t *)&u1, ca->p[1], 0); - switch (mm) { - case MM_eq: - setboolV(L->top-1, (u0 == u1)); - return 1; - case MM_lt: - setboolV(L->top-1, - id == CTID_INT64 ? ((int64_t)u0 < (int64_t)u1) : (u0 < u1)); - return 1; - case MM_le: - setboolV(L->top-1, - id == CTID_INT64 ? ((int64_t)u0 <= (int64_t)u1) : (u0 <= u1)); - return 1; - default: break; - } - cd = lj_cdata_new(cts, id, 8); - up = (uint64_t *)cdataptr(cd); - setcdataV(L, L->top-1, cd); - switch (mm) { - case MM_add: *up = u0 + u1; break; - case MM_sub: *up = u0 - u1; break; - case MM_mul: *up = u0 * u1; break; - case MM_div: - if (id == CTID_INT64) - *up = (uint64_t)lj_carith_divi64((int64_t)u0, (int64_t)u1); - else - *up = lj_carith_divu64(u0, u1); - break; - case MM_mod: - if (id == CTID_INT64) - *up = (uint64_t)lj_carith_modi64((int64_t)u0, (int64_t)u1); - else - *up = lj_carith_modu64(u0, u1); - break; - case MM_pow: - if (id == CTID_INT64) - *up = (uint64_t)lj_carith_powi64((int64_t)u0, (int64_t)u1); - else - *up = lj_carith_powu64(u0, u1); - break; - case MM_unm: *up = (uint64_t)-(int64_t)u0; break; - default: lua_assert(0); break; - } - lj_gc_check(L); - return 1; - } - return 0; -} - -/* Handle ctype arithmetic metamethods. */ -static int lj_carith_meta(lua_State *L, CTState *cts, CDArith *ca, MMS mm) -{ - cTValue *tv = NULL; - if (tviscdata(L->base)) { - CTypeID id = cdataV(L->base)->ctypeid; - CType *ct = ctype_raw(cts, id); - if (ctype_isptr(ct->info)) id = ctype_cid(ct->info); - tv = lj_ctype_meta(cts, id, mm); - } - if (!tv && L->base+1 < L->top && tviscdata(L->base+1)) { - CTypeID id = cdataV(L->base+1)->ctypeid; - CType *ct = ctype_raw(cts, id); - if (ctype_isptr(ct->info)) id = ctype_cid(ct->info); - tv = lj_ctype_meta(cts, id, mm); - } - if (!tv) { - const char *repr[2]; - int i, isenum = -1, isstr = -1; - if (mm == MM_eq) { /* Equality checks never raise an error. */ - int eq = ca->p[0] == ca->p[1]; - setboolV(L->top-1, eq); - setboolV(&G(L)->tmptv2, eq); /* Remember for trace recorder. */ - return 1; - } - for (i = 0; i < 2; i++) { - if (ca->ct[i] && tviscdata(L->base+i)) { - if (ctype_isenum(ca->ct[i]->info)) isenum = i; - repr[i] = strdata(lj_ctype_repr(L, ctype_typeid(cts, ca->ct[i]), NULL)); - } else { - if (tvisstr(&L->base[i])) isstr = i; - repr[i] = lj_typename(&L->base[i]); - } - } - if ((isenum ^ isstr) == 1) - lj_err_callerv(L, LJ_ERR_FFI_BADCONV, repr[isstr], repr[isenum]); - lj_err_callerv(L, mm == MM_len ? LJ_ERR_FFI_BADLEN : - mm == MM_concat ? LJ_ERR_FFI_BADCONCAT : - mm < MM_add ? LJ_ERR_FFI_BADCOMP : LJ_ERR_FFI_BADARITH, - repr[0], repr[1]); - } - return lj_meta_tailcall(L, tv); -} - -/* Arithmetic operators for cdata. */ -int lj_carith_op(lua_State *L, MMS mm) -{ - CTState *cts = ctype_cts(L); - CDArith ca; - if (carith_checkarg(L, cts, &ca)) { - if (carith_int64(L, cts, &ca, mm) || carith_ptr(L, cts, &ca, mm)) { - copyTV(L, &G(L)->tmptv2, L->top-1); /* Remember for trace recorder. */ - return 1; - } - } - return lj_carith_meta(L, cts, &ca, mm); -} - -/* No built-in functionality for length of cdata. */ -int lj_carith_len(lua_State *L) -{ - CTState *cts = ctype_cts(L); - CDArith ca; - carith_checkarg(L, cts, &ca); - return lj_carith_meta(L, cts, &ca, MM_len); -} - -/* -- 64 bit bit operations helpers --------------------------------------- */ - -#if LJ_64 -#define B64DEF(name) \ - static LJ_AINLINE uint64_t lj_carith_##name(uint64_t x, int32_t sh) -#else -/* Not inlined on 32 bit archs, since some of these are quite lengthy. */ -#define B64DEF(name) \ - uint64_t LJ_NOINLINE lj_carith_##name(uint64_t x, int32_t sh) -#endif - -B64DEF(shl64) { return x << (sh&63); } -B64DEF(shr64) { return x >> (sh&63); } -B64DEF(sar64) { return (uint64_t)((int64_t)x >> (sh&63)); } -B64DEF(rol64) { return lj_rol(x, (sh&63)); } -B64DEF(ror64) { return lj_ror(x, (sh&63)); } - -#undef B64DEF - -uint64_t lj_carith_shift64(uint64_t x, int32_t sh, int op) -{ - switch (op) { - case IR_BSHL-IR_BSHL: x = lj_carith_shl64(x, sh); break; - case IR_BSHR-IR_BSHL: x = lj_carith_shr64(x, sh); break; - case IR_BSAR-IR_BSHL: x = lj_carith_sar64(x, sh); break; - case IR_BROL-IR_BSHL: x = lj_carith_rol64(x, sh); break; - case IR_BROR-IR_BSHL: x = lj_carith_ror64(x, sh); break; - default: lua_assert(0); break; - } - return x; -} - -/* Equivalent to lj_lib_checkbit(), but handles cdata. */ -uint64_t lj_carith_check64(lua_State *L, int narg, CTypeID *id) -{ - TValue *o = L->base + narg-1; - if (o >= L->top) { - err: - lj_err_argt(L, narg, LUA_TNUMBER); - } else if (LJ_LIKELY(tvisnumber(o))) { - /* Handled below. */ - } else if (tviscdata(o)) { - CTState *cts = ctype_cts(L); - uint8_t *sp = (uint8_t *)cdataptr(cdataV(o)); - CTypeID sid = cdataV(o)->ctypeid; - CType *s = ctype_get(cts, sid); - uint64_t x; - if (ctype_isref(s->info)) { - sp = *(void **)sp; - sid = ctype_cid(s->info); - } - s = ctype_raw(cts, sid); - if (ctype_isenum(s->info)) s = ctype_child(cts, s); - if ((s->info & (CTMASK_NUM|CTF_BOOL|CTF_FP|CTF_UNSIGNED)) == - CTINFO(CT_NUM, CTF_UNSIGNED) && s->size == 8) - *id = CTID_UINT64; /* Use uint64_t, since it has the highest rank. */ - else if (!*id) - *id = CTID_INT64; /* Use int64_t, unless already set. */ - lj_cconv_ct_ct(cts, ctype_get(cts, *id), s, - (uint8_t *)&x, sp, CCF_ARG(narg)); - return x; - } else if (!(tvisstr(o) && lj_strscan_number(strV(o), o))) { - goto err; - } - if (LJ_LIKELY(tvisint(o))) { - return (uint32_t)intV(o); - } else { - int32_t i = lj_num2bit(numV(o)); - if (LJ_DUALNUM) setintV(o, i); - return (uint32_t)i; - } -} - -/* -- 64 bit integer arithmetic helpers ----------------------------------- */ - -#if LJ_32 && LJ_HASJIT -/* Signed/unsigned 64 bit multiplication. */ -int64_t lj_carith_mul64(int64_t a, int64_t b) -{ - return a * b; -} -#endif - -/* Unsigned 64 bit division. */ -uint64_t lj_carith_divu64(uint64_t a, uint64_t b) -{ - if (b == 0) return U64x(80000000,00000000); - return a / b; -} - -/* Signed 64 bit division. */ -int64_t lj_carith_divi64(int64_t a, int64_t b) -{ - if (b == 0 || (a == (int64_t)U64x(80000000,00000000) && b == -1)) - return U64x(80000000,00000000); - return a / b; -} - -/* Unsigned 64 bit modulo. */ -uint64_t lj_carith_modu64(uint64_t a, uint64_t b) -{ - if (b == 0) return U64x(80000000,00000000); - return a % b; -} - -/* Signed 64 bit modulo. */ -int64_t lj_carith_modi64(int64_t a, int64_t b) -{ - if (b == 0) return U64x(80000000,00000000); - if (a == (int64_t)U64x(80000000,00000000) && b == -1) return 0; - return a % b; -} - -/* Unsigned 64 bit x^k. */ -uint64_t lj_carith_powu64(uint64_t x, uint64_t k) -{ - uint64_t y; - if (k == 0) - return 1; - for (; (k & 1) == 0; k >>= 1) x *= x; - y = x; - if ((k >>= 1) != 0) { - for (;;) { - x *= x; - if (k == 1) break; - if (k & 1) y *= x; - k >>= 1; - } - y *= x; - } - return y; -} - -/* Signed 64 bit x^k. */ -int64_t lj_carith_powi64(int64_t x, int64_t k) -{ - if (k == 0) - return 1; - if (k < 0) { - if (x == 0) - return U64x(7fffffff,ffffffff); - else if (x == 1) - return 1; - else if (x == -1) - return (k & 1) ? -1 : 1; - else - return 0; - } - return (int64_t)lj_carith_powu64((uint64_t)x, (uint64_t)k); -} - -#endif diff --git a/lib/LuaJIT/src/lj_carith.h b/lib/LuaJIT/src/lj_carith.h deleted file mode 100644 index 3b0a5dd..0000000 --- a/lib/LuaJIT/src/lj_carith.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -** C data arithmetic. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_CARITH_H -#define _LJ_CARITH_H - -#include "lj_obj.h" - -#if LJ_HASFFI - -LJ_FUNC int lj_carith_op(lua_State *L, MMS mm); -LJ_FUNC int lj_carith_len(lua_State *L); - -#if LJ_32 -LJ_FUNC uint64_t lj_carith_shl64(uint64_t x, int32_t sh); -LJ_FUNC uint64_t lj_carith_shr64(uint64_t x, int32_t sh); -LJ_FUNC uint64_t lj_carith_sar64(uint64_t x, int32_t sh); -LJ_FUNC uint64_t lj_carith_rol64(uint64_t x, int32_t sh); -LJ_FUNC uint64_t lj_carith_ror64(uint64_t x, int32_t sh); -#endif -LJ_FUNC uint64_t lj_carith_shift64(uint64_t x, int32_t sh, int op); -LJ_FUNC uint64_t lj_carith_check64(lua_State *L, int narg, CTypeID *id); - -#if LJ_32 && LJ_HASJIT -LJ_FUNC int64_t lj_carith_mul64(int64_t x, int64_t k); -#endif -LJ_FUNC uint64_t lj_carith_divu64(uint64_t a, uint64_t b); -LJ_FUNC int64_t lj_carith_divi64(int64_t a, int64_t b); -LJ_FUNC uint64_t lj_carith_modu64(uint64_t a, uint64_t b); -LJ_FUNC int64_t lj_carith_modi64(int64_t a, int64_t b); -LJ_FUNC uint64_t lj_carith_powu64(uint64_t x, uint64_t k); -LJ_FUNC int64_t lj_carith_powi64(int64_t x, int64_t k); - -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_ccall.c b/lib/LuaJIT/src/lj_ccall.c deleted file mode 100644 index 25e938c..0000000 --- a/lib/LuaJIT/src/lj_ccall.c +++ /dev/null @@ -1,1183 +0,0 @@ -/* -** FFI C call handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#include "lj_obj.h" - -#if LJ_HASFFI - -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_tab.h" -#include "lj_ctype.h" -#include "lj_cconv.h" -#include "lj_cdata.h" -#include "lj_ccall.h" -#include "lj_trace.h" - -/* Target-specific handling of register arguments. */ -#if LJ_TARGET_X86 -/* -- x86 calling conventions --------------------------------------------- */ - -#if LJ_ABI_WIN - -#define CCALL_HANDLE_STRUCTRET \ - /* Return structs bigger than 8 by reference (on stack only). */ \ - cc->retref = (sz > 8); \ - if (cc->retref) cc->stack[nsp++] = (GPRArg)dp; - -#define CCALL_HANDLE_COMPLEXRET CCALL_HANDLE_STRUCTRET - -#else - -#if LJ_TARGET_OSX - -#define CCALL_HANDLE_STRUCTRET \ - /* Return structs of size 1, 2, 4 or 8 in registers. */ \ - cc->retref = !(sz == 1 || sz == 2 || sz == 4 || sz == 8); \ - if (cc->retref) { \ - if (ngpr < maxgpr) \ - cc->gpr[ngpr++] = (GPRArg)dp; \ - else \ - cc->stack[nsp++] = (GPRArg)dp; \ - } else { /* Struct with single FP field ends up in FPR. */ \ - cc->resx87 = ccall_classify_struct(cts, ctr); \ - } - -#define CCALL_HANDLE_STRUCTRET2 \ - if (cc->resx87) sp = (uint8_t *)&cc->fpr[0]; \ - memcpy(dp, sp, ctr->size); - -#else - -#define CCALL_HANDLE_STRUCTRET \ - cc->retref = 1; /* Return all structs by reference (in reg or on stack). */ \ - if (ngpr < maxgpr) \ - cc->gpr[ngpr++] = (GPRArg)dp; \ - else \ - cc->stack[nsp++] = (GPRArg)dp; - -#endif - -#define CCALL_HANDLE_COMPLEXRET \ - /* Return complex float in GPRs and complex double by reference. */ \ - cc->retref = (sz > 8); \ - if (cc->retref) { \ - if (ngpr < maxgpr) \ - cc->gpr[ngpr++] = (GPRArg)dp; \ - else \ - cc->stack[nsp++] = (GPRArg)dp; \ - } - -#endif - -#define CCALL_HANDLE_COMPLEXRET2 \ - if (!cc->retref) \ - *(int64_t *)dp = *(int64_t *)sp; /* Copy complex float from GPRs. */ - -#define CCALL_HANDLE_STRUCTARG \ - ngpr = maxgpr; /* Pass all structs by value on the stack. */ - -#define CCALL_HANDLE_COMPLEXARG \ - isfp = 1; /* Pass complex by value on stack. */ - -#define CCALL_HANDLE_REGARG \ - if (!isfp) { /* Only non-FP values may be passed in registers. */ \ - if (n > 1) { /* Anything > 32 bit is passed on the stack. */ \ - if (!LJ_ABI_WIN) ngpr = maxgpr; /* Prevent reordering. */ \ - } else if (ngpr + 1 <= maxgpr) { \ - dp = &cc->gpr[ngpr]; \ - ngpr += n; \ - goto done; \ - } \ - } - -#elif LJ_TARGET_X64 && LJ_ABI_WIN -/* -- Windows/x64 calling conventions ------------------------------------- */ - -#define CCALL_HANDLE_STRUCTRET \ - /* Return structs of size 1, 2, 4 or 8 in a GPR. */ \ - cc->retref = !(sz == 1 || sz == 2 || sz == 4 || sz == 8); \ - if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp; - -#define CCALL_HANDLE_COMPLEXRET CCALL_HANDLE_STRUCTRET - -#define CCALL_HANDLE_COMPLEXRET2 \ - if (!cc->retref) \ - *(int64_t *)dp = *(int64_t *)sp; /* Copy complex float from GPRs. */ - -#define CCALL_HANDLE_STRUCTARG \ - /* Pass structs of size 1, 2, 4 or 8 in a GPR by value. */ \ - if (!(sz == 1 || sz == 2 || sz == 4 || sz == 8)) { \ - rp = cdataptr(lj_cdata_new(cts, did, sz)); \ - sz = CTSIZE_PTR; /* Pass all other structs by reference. */ \ - } - -#define CCALL_HANDLE_COMPLEXARG \ - /* Pass complex float in a GPR and complex double by reference. */ \ - if (sz != 2*sizeof(float)) { \ - rp = cdataptr(lj_cdata_new(cts, did, sz)); \ - sz = CTSIZE_PTR; \ - } - -/* Windows/x64 argument registers are strictly positional (use ngpr). */ -#define CCALL_HANDLE_REGARG \ - if (isfp) { \ - if (ngpr < maxgpr) { dp = &cc->fpr[ngpr++]; nfpr = ngpr; goto done; } \ - } else { \ - if (ngpr < maxgpr) { dp = &cc->gpr[ngpr++]; goto done; } \ - } - -#elif LJ_TARGET_X64 -/* -- POSIX/x64 calling conventions --------------------------------------- */ - -#define CCALL_HANDLE_STRUCTRET \ - int rcl[2]; rcl[0] = rcl[1] = 0; \ - if (ccall_classify_struct(cts, ctr, rcl, 0)) { \ - cc->retref = 1; /* Return struct by reference. */ \ - cc->gpr[ngpr++] = (GPRArg)dp; \ - } else { \ - cc->retref = 0; /* Return small structs in registers. */ \ - } - -#define CCALL_HANDLE_STRUCTRET2 \ - int rcl[2]; rcl[0] = rcl[1] = 0; \ - ccall_classify_struct(cts, ctr, rcl, 0); \ - ccall_struct_ret(cc, rcl, dp, ctr->size); - -#define CCALL_HANDLE_COMPLEXRET \ - /* Complex values are returned in one or two FPRs. */ \ - cc->retref = 0; - -#define CCALL_HANDLE_COMPLEXRET2 \ - if (ctr->size == 2*sizeof(float)) { /* Copy complex float from FPR. */ \ - *(int64_t *)dp = cc->fpr[0].l[0]; \ - } else { /* Copy non-contiguous complex double from FPRs. */ \ - ((int64_t *)dp)[0] = cc->fpr[0].l[0]; \ - ((int64_t *)dp)[1] = cc->fpr[1].l[0]; \ - } - -#define CCALL_HANDLE_STRUCTARG \ - int rcl[2]; rcl[0] = rcl[1] = 0; \ - if (!ccall_classify_struct(cts, d, rcl, 0)) { \ - cc->nsp = nsp; cc->ngpr = ngpr; cc->nfpr = nfpr; \ - if (ccall_struct_arg(cc, cts, d, rcl, o, narg)) goto err_nyi; \ - nsp = cc->nsp; ngpr = cc->ngpr; nfpr = cc->nfpr; \ - continue; \ - } /* Pass all other structs by value on stack. */ - -#define CCALL_HANDLE_COMPLEXARG \ - isfp = 2; /* Pass complex in FPRs or on stack. Needs postprocessing. */ - -#define CCALL_HANDLE_REGARG \ - if (isfp) { /* Try to pass argument in FPRs. */ \ - int n2 = ctype_isvector(d->info) ? 1 : n; \ - if (nfpr + n2 <= CCALL_NARG_FPR) { \ - dp = &cc->fpr[nfpr]; \ - nfpr += n2; \ - goto done; \ - } \ - } else { /* Try to pass argument in GPRs. */ \ - /* Note that reordering is explicitly allowed in the x64 ABI. */ \ - if (n <= 2 && ngpr + n <= maxgpr) { \ - dp = &cc->gpr[ngpr]; \ - ngpr += n; \ - goto done; \ - } \ - } - -#elif LJ_TARGET_ARM -/* -- ARM calling conventions --------------------------------------------- */ - -#if LJ_ABI_SOFTFP - -#define CCALL_HANDLE_STRUCTRET \ - /* Return structs of size <= 4 in a GPR. */ \ - cc->retref = !(sz <= 4); \ - if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp; - -#define CCALL_HANDLE_COMPLEXRET \ - cc->retref = 1; /* Return all complex values by reference. */ \ - cc->gpr[ngpr++] = (GPRArg)dp; - -#define CCALL_HANDLE_COMPLEXRET2 \ - UNUSED(dp); /* Nothing to do. */ - -#define CCALL_HANDLE_STRUCTARG \ - /* Pass all structs by value in registers and/or on the stack. */ - -#define CCALL_HANDLE_COMPLEXARG \ - /* Pass complex by value in 2 or 4 GPRs. */ - -#define CCALL_HANDLE_REGARG_FP1 -#define CCALL_HANDLE_REGARG_FP2 - -#else - -#define CCALL_HANDLE_STRUCTRET \ - cc->retref = !ccall_classify_struct(cts, ctr, ct); \ - if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp; - -#define CCALL_HANDLE_STRUCTRET2 \ - if (ccall_classify_struct(cts, ctr, ct) > 1) sp = (uint8_t *)&cc->fpr[0]; \ - memcpy(dp, sp, ctr->size); - -#define CCALL_HANDLE_COMPLEXRET \ - if (!(ct->info & CTF_VARARG)) cc->retref = 0; /* Return complex in FPRs. */ - -#define CCALL_HANDLE_COMPLEXRET2 \ - if (!(ct->info & CTF_VARARG)) memcpy(dp, &cc->fpr[0], ctr->size); - -#define CCALL_HANDLE_STRUCTARG \ - isfp = (ccall_classify_struct(cts, d, ct) > 1); - /* Pass all structs by value in registers and/or on the stack. */ - -#define CCALL_HANDLE_COMPLEXARG \ - isfp = 1; /* Pass complex by value in FPRs or on stack. */ - -#define CCALL_HANDLE_REGARG_FP1 \ - if (isfp && !(ct->info & CTF_VARARG)) { \ - if ((d->info & CTF_ALIGN) > CTALIGN_PTR) { \ - if (nfpr + (n >> 1) <= CCALL_NARG_FPR) { \ - dp = &cc->fpr[nfpr]; \ - nfpr += (n >> 1); \ - goto done; \ - } \ - } else { \ - if (sz > 1 && fprodd != nfpr) fprodd = 0; \ - if (fprodd) { \ - if (2*nfpr+n <= 2*CCALL_NARG_FPR+1) { \ - dp = (void *)&cc->fpr[fprodd-1].f[1]; \ - nfpr += (n >> 1); \ - if ((n & 1)) fprodd = 0; else fprodd = nfpr-1; \ - goto done; \ - } \ - } else { \ - if (2*nfpr+n <= 2*CCALL_NARG_FPR) { \ - dp = (void *)&cc->fpr[nfpr]; \ - nfpr += (n >> 1); \ - if ((n & 1)) fprodd = ++nfpr; else fprodd = 0; \ - goto done; \ - } \ - } \ - } \ - fprodd = 0; /* No reordering after the first FP value is on stack. */ \ - } else { - -#define CCALL_HANDLE_REGARG_FP2 } - -#endif - -#define CCALL_HANDLE_REGARG \ - CCALL_HANDLE_REGARG_FP1 \ - if ((d->info & CTF_ALIGN) > CTALIGN_PTR) { \ - if (ngpr < maxgpr) \ - ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \ - } \ - if (ngpr < maxgpr) { \ - dp = &cc->gpr[ngpr]; \ - if (ngpr + n > maxgpr) { \ - nsp += ngpr + n - maxgpr; /* Assumes contiguous gpr/stack fields. */ \ - if (nsp > CCALL_MAXSTACK) goto err_nyi; /* Too many arguments. */ \ - ngpr = maxgpr; \ - } else { \ - ngpr += n; \ - } \ - goto done; \ - } CCALL_HANDLE_REGARG_FP2 - -#define CCALL_HANDLE_RET \ - if ((ct->info & CTF_VARARG)) sp = (uint8_t *)&cc->gpr[0]; - -#elif LJ_TARGET_ARM64 -/* -- ARM64 calling conventions ------------------------------------------- */ - -#define CCALL_HANDLE_STRUCTRET \ - cc->retref = !ccall_classify_struct(cts, ctr); \ - if (cc->retref) cc->retp = dp; - -#define CCALL_HANDLE_STRUCTRET2 \ - unsigned int cl = ccall_classify_struct(cts, ctr); \ - if ((cl & 4)) { /* Combine float HFA from separate registers. */ \ - CTSize i = (cl >> 8) - 1; \ - do { ((uint32_t *)dp)[i] = cc->fpr[i].lo; } while (i--); \ - } else { \ - if (cl > 1) sp = (uint8_t *)&cc->fpr[0]; \ - memcpy(dp, sp, ctr->size); \ - } - -#define CCALL_HANDLE_COMPLEXRET \ - /* Complex values are returned in one or two FPRs. */ \ - cc->retref = 0; - -#define CCALL_HANDLE_COMPLEXRET2 \ - if (ctr->size == 2*sizeof(float)) { /* Copy complex float from FPRs. */ \ - ((float *)dp)[0] = cc->fpr[0].f; \ - ((float *)dp)[1] = cc->fpr[1].f; \ - } else { /* Copy complex double from FPRs. */ \ - ((double *)dp)[0] = cc->fpr[0].d; \ - ((double *)dp)[1] = cc->fpr[1].d; \ - } - -#define CCALL_HANDLE_STRUCTARG \ - unsigned int cl = ccall_classify_struct(cts, d); \ - if (cl == 0) { /* Pass struct by reference. */ \ - rp = cdataptr(lj_cdata_new(cts, did, sz)); \ - sz = CTSIZE_PTR; \ - } else if (cl > 1) { /* Pass struct in FPRs or on stack. */ \ - isfp = (cl & 4) ? 2 : 1; \ - } /* else: Pass struct in GPRs or on stack. */ - -#define CCALL_HANDLE_COMPLEXARG \ - /* Pass complex by value in separate (!) FPRs or on stack. */ \ - isfp = sz == 2*sizeof(float) ? 2 : 1; - -#define CCALL_HANDLE_REGARG \ - if (LJ_TARGET_IOS && isva) { \ - /* IOS: All variadic arguments are on the stack. */ \ - } else if (isfp) { /* Try to pass argument in FPRs. */ \ - int n2 = ctype_isvector(d->info) ? 1 : n*isfp; \ - if (nfpr + n2 <= CCALL_NARG_FPR) { \ - dp = &cc->fpr[nfpr]; \ - nfpr += n2; \ - goto done; \ - } else { \ - nfpr = CCALL_NARG_FPR; /* Prevent reordering. */ \ - if (LJ_TARGET_IOS && d->size < 8) goto err_nyi; \ - } \ - } else { /* Try to pass argument in GPRs. */ \ - if (!LJ_TARGET_IOS && (d->info & CTF_ALIGN) > CTALIGN_PTR) \ - ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \ - if (ngpr + n <= maxgpr) { \ - dp = &cc->gpr[ngpr]; \ - ngpr += n; \ - goto done; \ - } else { \ - ngpr = maxgpr; /* Prevent reordering. */ \ - if (LJ_TARGET_IOS && d->size < 8) goto err_nyi; \ - } \ - } - -#if LJ_BE -#define CCALL_HANDLE_RET \ - if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ - sp = (uint8_t *)&cc->fpr[0].f; -#endif - - -#elif LJ_TARGET_PPC -/* -- PPC calling conventions --------------------------------------------- */ - -#define CCALL_HANDLE_STRUCTRET \ - cc->retref = 1; /* Return all structs by reference. */ \ - cc->gpr[ngpr++] = (GPRArg)dp; - -#define CCALL_HANDLE_COMPLEXRET \ - /* Complex values are returned in 2 or 4 GPRs. */ \ - cc->retref = 0; - -#define CCALL_HANDLE_COMPLEXRET2 \ - memcpy(dp, sp, ctr->size); /* Copy complex from GPRs. */ - -#define CCALL_HANDLE_STRUCTARG \ - rp = cdataptr(lj_cdata_new(cts, did, sz)); \ - sz = CTSIZE_PTR; /* Pass all structs by reference. */ - -#define CCALL_HANDLE_COMPLEXARG \ - /* Pass complex by value in 2 or 4 GPRs. */ - -#define CCALL_HANDLE_GPR \ - /* Try to pass argument in GPRs. */ \ - if (n > 1) { \ - lua_assert(n == 2 || n == 4); /* int64_t or complex (float). */ \ - if (ctype_isinteger(d->info) || ctype_isfp(d->info)) \ - ngpr = (ngpr + 1u) & ~1u; /* Align int64_t to regpair. */ \ - else if (ngpr + n > maxgpr) \ - ngpr = maxgpr; /* Prevent reordering. */ \ - } \ - if (ngpr + n <= maxgpr) { \ - dp = &cc->gpr[ngpr]; \ - ngpr += n; \ - goto done; \ - } \ - -#if LJ_ABI_SOFTFP -#define CCALL_HANDLE_REGARG CCALL_HANDLE_GPR -#else -#define CCALL_HANDLE_REGARG \ - if (isfp) { /* Try to pass argument in FPRs. */ \ - if (nfpr + 1 <= CCALL_NARG_FPR) { \ - dp = &cc->fpr[nfpr]; \ - nfpr += 1; \ - d = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */ \ - goto done; \ - } \ - } else { \ - CCALL_HANDLE_GPR \ - } -#endif - -#if !LJ_ABI_SOFTFP -#define CCALL_HANDLE_RET \ - if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ - ctr = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */ -#endif - -#elif LJ_TARGET_MIPS32 -/* -- MIPS o32 calling conventions ---------------------------------------- */ - -#define CCALL_HANDLE_STRUCTRET \ - cc->retref = 1; /* Return all structs by reference. */ \ - cc->gpr[ngpr++] = (GPRArg)dp; - -#define CCALL_HANDLE_COMPLEXRET \ - /* Complex values are returned in 1 or 2 FPRs. */ \ - cc->retref = 0; - -#if LJ_ABI_SOFTFP -#define CCALL_HANDLE_COMPLEXRET2 \ - if (ctr->size == 2*sizeof(float)) { /* Copy complex float from GPRs. */ \ - ((intptr_t *)dp)[0] = cc->gpr[0]; \ - ((intptr_t *)dp)[1] = cc->gpr[1]; \ - } else { /* Copy complex double from GPRs. */ \ - ((intptr_t *)dp)[0] = cc->gpr[0]; \ - ((intptr_t *)dp)[1] = cc->gpr[1]; \ - ((intptr_t *)dp)[2] = cc->gpr[2]; \ - ((intptr_t *)dp)[3] = cc->gpr[3]; \ - } -#else -#define CCALL_HANDLE_COMPLEXRET2 \ - if (ctr->size == 2*sizeof(float)) { /* Copy complex float from FPRs. */ \ - ((float *)dp)[0] = cc->fpr[0].f; \ - ((float *)dp)[1] = cc->fpr[1].f; \ - } else { /* Copy complex double from FPRs. */ \ - ((double *)dp)[0] = cc->fpr[0].d; \ - ((double *)dp)[1] = cc->fpr[1].d; \ - } -#endif - -#define CCALL_HANDLE_STRUCTARG \ - /* Pass all structs by value in registers and/or on the stack. */ - -#define CCALL_HANDLE_COMPLEXARG \ - /* Pass complex by value in 2 or 4 GPRs. */ - -#define CCALL_HANDLE_GPR \ - if ((d->info & CTF_ALIGN) > CTALIGN_PTR) \ - ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \ - if (ngpr < maxgpr) { \ - dp = &cc->gpr[ngpr]; \ - if (ngpr + n > maxgpr) { \ - nsp += ngpr + n - maxgpr; /* Assumes contiguous gpr/stack fields. */ \ - if (nsp > CCALL_MAXSTACK) goto err_nyi; /* Too many arguments. */ \ - ngpr = maxgpr; \ - } else { \ - ngpr += n; \ - } \ - goto done; \ - } - -#if !LJ_ABI_SOFTFP /* MIPS32 hard-float */ -#define CCALL_HANDLE_REGARG \ - if (isfp && nfpr < CCALL_NARG_FPR && !(ct->info & CTF_VARARG)) { \ - /* Try to pass argument in FPRs. */ \ - dp = n == 1 ? (void *)&cc->fpr[nfpr].f : (void *)&cc->fpr[nfpr].d; \ - nfpr++; ngpr += n; \ - goto done; \ - } else { /* Try to pass argument in GPRs. */ \ - nfpr = CCALL_NARG_FPR; \ - CCALL_HANDLE_GPR \ - } -#else /* MIPS32 soft-float */ -#define CCALL_HANDLE_REGARG CCALL_HANDLE_GPR -#endif - -#if !LJ_ABI_SOFTFP -/* On MIPS64 soft-float, position of float return values is endian-dependant. */ -#define CCALL_HANDLE_RET \ - if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ - sp = (uint8_t *)&cc->fpr[0].f; -#endif - -#elif LJ_TARGET_MIPS64 -/* -- MIPS n64 calling conventions ---------------------------------------- */ - -#define CCALL_HANDLE_STRUCTRET \ - cc->retref = !(sz <= 16); \ - if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp; - -#define CCALL_HANDLE_STRUCTRET2 \ - ccall_copy_struct(cc, ctr, dp, sp, ccall_classify_struct(cts, ctr, ct)); - -#define CCALL_HANDLE_COMPLEXRET \ - /* Complex values are returned in 1 or 2 FPRs. */ \ - cc->retref = 0; - -#if LJ_ABI_SOFTFP /* MIPS64 soft-float */ - -#define CCALL_HANDLE_COMPLEXRET2 \ - if (ctr->size == 2*sizeof(float)) { /* Copy complex float from GPRs. */ \ - ((intptr_t *)dp)[0] = cc->gpr[0]; \ - } else { /* Copy complex double from GPRs. */ \ - ((intptr_t *)dp)[0] = cc->gpr[0]; \ - ((intptr_t *)dp)[1] = cc->gpr[1]; \ - } - -#define CCALL_HANDLE_COMPLEXARG \ - /* Pass complex by value in 2 or 4 GPRs. */ - -/* Position of soft-float 'float' return value depends on endianess. */ -#define CCALL_HANDLE_RET \ - if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ - sp = (uint8_t *)cc->gpr + LJ_ENDIAN_SELECT(0, 4); - -#else /* MIPS64 hard-float */ - -#define CCALL_HANDLE_COMPLEXRET2 \ - if (ctr->size == 2*sizeof(float)) { /* Copy complex float from FPRs. */ \ - ((float *)dp)[0] = cc->fpr[0].f; \ - ((float *)dp)[1] = cc->fpr[1].f; \ - } else { /* Copy complex double from FPRs. */ \ - ((double *)dp)[0] = cc->fpr[0].d; \ - ((double *)dp)[1] = cc->fpr[1].d; \ - } - -#define CCALL_HANDLE_COMPLEXARG \ - if (sz == 2*sizeof(float)) { \ - isfp = 2; \ - if (ngpr < maxgpr) \ - sz *= 2; \ - } - -#define CCALL_HANDLE_RET \ - if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ - sp = (uint8_t *)&cc->fpr[0].f; - -#endif - -#define CCALL_HANDLE_STRUCTARG \ - /* Pass all structs by value in registers and/or on the stack. */ - -#define CCALL_HANDLE_REGARG \ - if (ngpr < maxgpr) { \ - dp = &cc->gpr[ngpr]; \ - if (ngpr + n > maxgpr) { \ - nsp += ngpr + n - maxgpr; /* Assumes contiguous gpr/stack fields. */ \ - if (nsp > CCALL_MAXSTACK) goto err_nyi; /* Too many arguments. */ \ - ngpr = maxgpr; \ - } else { \ - ngpr += n; \ - } \ - goto done; \ - } - -#else -#error "Missing calling convention definitions for this architecture" -#endif - -#ifndef CCALL_HANDLE_STRUCTRET2 -#define CCALL_HANDLE_STRUCTRET2 \ - memcpy(dp, sp, ctr->size); /* Copy struct return value from GPRs. */ -#endif - -/* -- x86 OSX ABI struct classification ----------------------------------- */ - -#if LJ_TARGET_X86 && LJ_TARGET_OSX - -/* Check for struct with single FP field. */ -static int ccall_classify_struct(CTState *cts, CType *ct) -{ - CTSize sz = ct->size; - if (!(sz == sizeof(float) || sz == sizeof(double))) return 0; - if ((ct->info & CTF_UNION)) return 0; - while (ct->sib) { - ct = ctype_get(cts, ct->sib); - if (ctype_isfield(ct->info)) { - CType *sct = ctype_rawchild(cts, ct); - if (ctype_isfp(sct->info)) { - if (sct->size == sz) - return (sz >> 2); /* Return 1 for float or 2 for double. */ - } else if (ctype_isstruct(sct->info)) { - if (sct->size) - return ccall_classify_struct(cts, sct); - } else { - break; - } - } else if (ctype_isbitfield(ct->info)) { - break; - } else if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) { - CType *sct = ctype_rawchild(cts, ct); - if (sct->size) - return ccall_classify_struct(cts, sct); - } - } - return 0; -} - -#endif - -/* -- x64 struct classification ------------------------------------------- */ - -#if LJ_TARGET_X64 && !LJ_ABI_WIN - -/* Register classes for x64 struct classification. */ -#define CCALL_RCL_INT 1 -#define CCALL_RCL_SSE 2 -#define CCALL_RCL_MEM 4 -/* NYI: classify vectors. */ - -static int ccall_classify_struct(CTState *cts, CType *ct, int *rcl, CTSize ofs); - -/* Classify a C type. */ -static void ccall_classify_ct(CTState *cts, CType *ct, int *rcl, CTSize ofs) -{ - if (ctype_isarray(ct->info)) { - CType *cct = ctype_rawchild(cts, ct); - CTSize eofs, esz = cct->size, asz = ct->size; - for (eofs = 0; eofs < asz; eofs += esz) - ccall_classify_ct(cts, cct, rcl, ofs+eofs); - } else if (ctype_isstruct(ct->info)) { - ccall_classify_struct(cts, ct, rcl, ofs); - } else { - int cl = ctype_isfp(ct->info) ? CCALL_RCL_SSE : CCALL_RCL_INT; - lua_assert(ctype_hassize(ct->info)); - if ((ofs & (ct->size-1))) cl = CCALL_RCL_MEM; /* Unaligned. */ - rcl[(ofs >= 8)] |= cl; - } -} - -/* Recursively classify a struct based on its fields. */ -static int ccall_classify_struct(CTState *cts, CType *ct, int *rcl, CTSize ofs) -{ - if (ct->size > 16) return CCALL_RCL_MEM; /* Too big, gets memory class. */ - while (ct->sib) { - CTSize fofs; - ct = ctype_get(cts, ct->sib); - fofs = ofs+ct->size; - if (ctype_isfield(ct->info)) - ccall_classify_ct(cts, ctype_rawchild(cts, ct), rcl, fofs); - else if (ctype_isbitfield(ct->info)) - rcl[(fofs >= 8)] |= CCALL_RCL_INT; /* NYI: unaligned bitfields? */ - else if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) - ccall_classify_struct(cts, ctype_rawchild(cts, ct), rcl, fofs); - } - return ((rcl[0]|rcl[1]) & CCALL_RCL_MEM); /* Memory class? */ -} - -/* Try to split up a small struct into registers. */ -static int ccall_struct_reg(CCallState *cc, GPRArg *dp, int *rcl) -{ - MSize ngpr = cc->ngpr, nfpr = cc->nfpr; - uint32_t i; - for (i = 0; i < 2; i++) { - lua_assert(!(rcl[i] & CCALL_RCL_MEM)); - if ((rcl[i] & CCALL_RCL_INT)) { /* Integer class takes precedence. */ - if (ngpr >= CCALL_NARG_GPR) return 1; /* Register overflow. */ - cc->gpr[ngpr++] = dp[i]; - } else if ((rcl[i] & CCALL_RCL_SSE)) { - if (nfpr >= CCALL_NARG_FPR) return 1; /* Register overflow. */ - cc->fpr[nfpr++].l[0] = dp[i]; - } - } - cc->ngpr = ngpr; cc->nfpr = nfpr; - return 0; /* Ok. */ -} - -/* Pass a small struct argument. */ -static int ccall_struct_arg(CCallState *cc, CTState *cts, CType *d, int *rcl, - TValue *o, int narg) -{ - GPRArg dp[2]; - dp[0] = dp[1] = 0; - /* Convert to temp. struct. */ - lj_cconv_ct_tv(cts, d, (uint8_t *)dp, o, CCF_ARG(narg)); - if (ccall_struct_reg(cc, dp, rcl)) { /* Register overflow? Pass on stack. */ - MSize nsp = cc->nsp, n = rcl[1] ? 2 : 1; - if (nsp + n > CCALL_MAXSTACK) return 1; /* Too many arguments. */ - cc->nsp = nsp + n; - memcpy(&cc->stack[nsp], dp, n*CTSIZE_PTR); - } - return 0; /* Ok. */ -} - -/* Combine returned small struct. */ -static void ccall_struct_ret(CCallState *cc, int *rcl, uint8_t *dp, CTSize sz) -{ - GPRArg sp[2]; - MSize ngpr = 0, nfpr = 0; - uint32_t i; - for (i = 0; i < 2; i++) { - if ((rcl[i] & CCALL_RCL_INT)) { /* Integer class takes precedence. */ - sp[i] = cc->gpr[ngpr++]; - } else if ((rcl[i] & CCALL_RCL_SSE)) { - sp[i] = cc->fpr[nfpr++].l[0]; - } - } - memcpy(dp, sp, sz); -} -#endif - -/* -- ARM hard-float ABI struct classification ---------------------------- */ - -#if LJ_TARGET_ARM && !LJ_ABI_SOFTFP - -/* Classify a struct based on its fields. */ -static unsigned int ccall_classify_struct(CTState *cts, CType *ct, CType *ctf) -{ - CTSize sz = ct->size; - unsigned int r = 0, n = 0, isu = (ct->info & CTF_UNION); - if ((ctf->info & CTF_VARARG)) goto noth; - while (ct->sib) { - CType *sct; - ct = ctype_get(cts, ct->sib); - if (ctype_isfield(ct->info)) { - sct = ctype_rawchild(cts, ct); - if (ctype_isfp(sct->info)) { - r |= sct->size; - if (!isu) n++; else if (n == 0) n = 1; - } else if (ctype_iscomplex(sct->info)) { - r |= (sct->size >> 1); - if (!isu) n += 2; else if (n < 2) n = 2; - } else if (ctype_isstruct(sct->info)) { - goto substruct; - } else { - goto noth; - } - } else if (ctype_isbitfield(ct->info)) { - goto noth; - } else if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) { - sct = ctype_rawchild(cts, ct); - substruct: - if (sct->size > 0) { - unsigned int s = ccall_classify_struct(cts, sct, ctf); - if (s <= 1) goto noth; - r |= (s & 255); - if (!isu) n += (s >> 8); else if (n < (s >>8)) n = (s >> 8); - } - } - } - if ((r == 4 || r == 8) && n <= 4) - return r + (n << 8); -noth: /* Not a homogeneous float/double aggregate. */ - return (sz <= 4); /* Return structs of size <= 4 in a GPR. */ -} - -#endif - -/* -- ARM64 ABI struct classification ------------------------------------- */ - -#if LJ_TARGET_ARM64 - -/* Classify a struct based on its fields. */ -static unsigned int ccall_classify_struct(CTState *cts, CType *ct) -{ - CTSize sz = ct->size; - unsigned int r = 0, n = 0, isu = (ct->info & CTF_UNION); - while (ct->sib) { - CType *sct; - ct = ctype_get(cts, ct->sib); - if (ctype_isfield(ct->info)) { - sct = ctype_rawchild(cts, ct); - if (ctype_isfp(sct->info)) { - r |= sct->size; - if (!isu) n++; else if (n == 0) n = 1; - } else if (ctype_iscomplex(sct->info)) { - r |= (sct->size >> 1); - if (!isu) n += 2; else if (n < 2) n = 2; - } else if (ctype_isstruct(sct->info)) { - goto substruct; - } else { - goto noth; - } - } else if (ctype_isbitfield(ct->info)) { - goto noth; - } else if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) { - sct = ctype_rawchild(cts, ct); - substruct: - if (sct->size > 0) { - unsigned int s = ccall_classify_struct(cts, sct); - if (s <= 1) goto noth; - r |= (s & 255); - if (!isu) n += (s >> 8); else if (n < (s >>8)) n = (s >> 8); - } - } - } - if ((r == 4 || r == 8) && n <= 4) - return r + (n << 8); -noth: /* Not a homogeneous float/double aggregate. */ - return (sz <= 16); /* Return structs of size <= 16 in GPRs. */ -} - -#endif - -/* -- MIPS64 ABI struct classification ---------------------------- */ - -#if LJ_TARGET_MIPS64 - -#define FTYPE_FLOAT 1 -#define FTYPE_DOUBLE 2 - -/* Classify FP fields (max. 2) and their types. */ -static unsigned int ccall_classify_struct(CTState *cts, CType *ct, CType *ctf) -{ - int n = 0, ft = 0; - if ((ctf->info & CTF_VARARG) || (ct->info & CTF_UNION)) - goto noth; - while (ct->sib) { - CType *sct; - ct = ctype_get(cts, ct->sib); - if (n == 2) { - goto noth; - } else if (ctype_isfield(ct->info)) { - sct = ctype_rawchild(cts, ct); - if (ctype_isfp(sct->info)) { - ft |= (sct->size == 4 ? FTYPE_FLOAT : FTYPE_DOUBLE) << 2*n; - n++; - } else { - goto noth; - } - } else if (ctype_isbitfield(ct->info) || - ctype_isxattrib(ct->info, CTA_SUBTYPE)) { - goto noth; - } - } - if (n <= 2) - return ft; -noth: /* Not a homogeneous float/double aggregate. */ - return 0; /* Struct is in GPRs. */ -} - -static void ccall_copy_struct(CCallState *cc, CType *ctr, void *dp, void *sp, - int ft) -{ - if (LJ_ABI_SOFTFP ? ft : - ((ft & 3) == FTYPE_FLOAT || (ft >> 2) == FTYPE_FLOAT)) { - int i, ofs = 0; - for (i = 0; ft != 0; i++, ft >>= 2) { - if ((ft & 3) == FTYPE_FLOAT) { -#if LJ_ABI_SOFTFP - /* The 2nd FP struct result is in CARG1 (gpr[2]) and not CRET2. */ - memcpy((uint8_t *)dp + ofs, - (uint8_t *)&cc->gpr[2*i] + LJ_ENDIAN_SELECT(0, 4), 4); -#else - *(float *)((uint8_t *)dp + ofs) = cc->fpr[i].f; -#endif - ofs += 4; - } else { - ofs = (ofs + 7) & ~7; /* 64 bit alignment. */ -#if LJ_ABI_SOFTFP - *(intptr_t *)((uint8_t *)dp + ofs) = cc->gpr[2*i]; -#else - *(double *)((uint8_t *)dp + ofs) = cc->fpr[i].d; -#endif - ofs += 8; - } - } - } else { -#if !LJ_ABI_SOFTFP - if (ft) sp = (uint8_t *)&cc->fpr[0]; -#endif - memcpy(dp, sp, ctr->size); - } -} - -#endif - -/* -- Common C call handling ---------------------------------------------- */ - -/* Infer the destination CTypeID for a vararg argument. */ -CTypeID lj_ccall_ctid_vararg(CTState *cts, cTValue *o) -{ - if (tvisnumber(o)) { - return CTID_DOUBLE; - } else if (tviscdata(o)) { - CTypeID id = cdataV(o)->ctypeid; - CType *s = ctype_get(cts, id); - if (ctype_isrefarray(s->info)) { - return lj_ctype_intern(cts, - CTINFO(CT_PTR, CTALIGN_PTR|ctype_cid(s->info)), CTSIZE_PTR); - } else if (ctype_isstruct(s->info) || ctype_isfunc(s->info)) { - /* NYI: how to pass a struct by value in a vararg argument? */ - return lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|id), CTSIZE_PTR); - } else if (ctype_isfp(s->info) && s->size == sizeof(float)) { - return CTID_DOUBLE; - } else { - return id; - } - } else if (tvisstr(o)) { - return CTID_P_CCHAR; - } else if (tvisbool(o)) { - return CTID_BOOL; - } else { - return CTID_P_VOID; - } -} - -/* Setup arguments for C call. */ -static int ccall_set_args(lua_State *L, CTState *cts, CType *ct, - CCallState *cc) -{ - int gcsteps = 0; - TValue *o, *top = L->top; - CTypeID fid; - CType *ctr; - MSize maxgpr, ngpr = 0, nsp = 0, narg; -#if CCALL_NARG_FPR - MSize nfpr = 0; -#if LJ_TARGET_ARM - MSize fprodd = 0; -#endif -#endif - - /* Clear unused regs to get some determinism in case of misdeclaration. */ - memset(cc->gpr, 0, sizeof(cc->gpr)); -#if CCALL_NUM_FPR - memset(cc->fpr, 0, sizeof(cc->fpr)); -#endif - -#if LJ_TARGET_X86 - /* x86 has several different calling conventions. */ - cc->resx87 = 0; - switch (ctype_cconv(ct->info)) { - case CTCC_FASTCALL: maxgpr = 2; break; - case CTCC_THISCALL: maxgpr = 1; break; - default: maxgpr = 0; break; - } -#else - maxgpr = CCALL_NARG_GPR; -#endif - - /* Perform required setup for some result types. */ - ctr = ctype_rawchild(cts, ct); - if (ctype_isvector(ctr->info)) { - if (!(CCALL_VECTOR_REG && (ctr->size == 8 || ctr->size == 16))) - goto err_nyi; - } else if (ctype_iscomplex(ctr->info) || ctype_isstruct(ctr->info)) { - /* Preallocate cdata object and anchor it after arguments. */ - CTSize sz = ctr->size; - GCcdata *cd = lj_cdata_new(cts, ctype_cid(ct->info), sz); - void *dp = cdataptr(cd); - setcdataV(L, L->top++, cd); - if (ctype_isstruct(ctr->info)) { - CCALL_HANDLE_STRUCTRET - } else { - CCALL_HANDLE_COMPLEXRET - } -#if LJ_TARGET_X86 - } else if (ctype_isfp(ctr->info)) { - cc->resx87 = ctr->size == sizeof(float) ? 1 : 2; -#endif - } - - /* Skip initial attributes. */ - fid = ct->sib; - while (fid) { - CType *ctf = ctype_get(cts, fid); - if (!ctype_isattrib(ctf->info)) break; - fid = ctf->sib; - } - - /* Walk through all passed arguments. */ - for (o = L->base+1, narg = 1; o < top; o++, narg++) { - CTypeID did; - CType *d; - CTSize sz; - MSize n, isfp = 0, isva = 0; - void *dp, *rp = NULL; - - if (fid) { /* Get argument type from field. */ - CType *ctf = ctype_get(cts, fid); - fid = ctf->sib; - lua_assert(ctype_isfield(ctf->info)); - did = ctype_cid(ctf->info); - } else { - if (!(ct->info & CTF_VARARG)) - lj_err_caller(L, LJ_ERR_FFI_NUMARG); /* Too many arguments. */ - did = lj_ccall_ctid_vararg(cts, o); /* Infer vararg type. */ - isva = 1; - } - d = ctype_raw(cts, did); - sz = d->size; - - /* Find out how (by value/ref) and where (GPR/FPR) to pass an argument. */ - if (ctype_isnum(d->info)) { - if (sz > 8) goto err_nyi; - if ((d->info & CTF_FP)) - isfp = 1; - } else if (ctype_isvector(d->info)) { - if (CCALL_VECTOR_REG && (sz == 8 || sz == 16)) - isfp = 1; - else - goto err_nyi; - } else if (ctype_isstruct(d->info)) { - CCALL_HANDLE_STRUCTARG - } else if (ctype_iscomplex(d->info)) { - CCALL_HANDLE_COMPLEXARG - } else { - sz = CTSIZE_PTR; - } - sz = (sz + CTSIZE_PTR-1) & ~(CTSIZE_PTR-1); - n = sz / CTSIZE_PTR; /* Number of GPRs or stack slots needed. */ - - CCALL_HANDLE_REGARG /* Handle register arguments. */ - - /* Otherwise pass argument on stack. */ - if (CCALL_ALIGN_STACKARG && !rp && (d->info & CTF_ALIGN) > CTALIGN_PTR) { - MSize align = (1u << ctype_align(d->info-CTALIGN_PTR)) -1; - nsp = (nsp + align) & ~align; /* Align argument on stack. */ - } - if (nsp + n > CCALL_MAXSTACK) { /* Too many arguments. */ - err_nyi: - lj_err_caller(L, LJ_ERR_FFI_NYICALL); - } - dp = &cc->stack[nsp]; - nsp += n; - isva = 0; - - done: - if (rp) { /* Pass by reference. */ - gcsteps++; - *(void **)dp = rp; - dp = rp; - } - lj_cconv_ct_tv(cts, d, (uint8_t *)dp, o, CCF_ARG(narg)); - /* Extend passed integers to 32 bits at least. */ - if (ctype_isinteger_or_bool(d->info) && d->size < 4) { - if (d->info & CTF_UNSIGNED) - *(uint32_t *)dp = d->size == 1 ? (uint32_t)*(uint8_t *)dp : - (uint32_t)*(uint16_t *)dp; - else - *(int32_t *)dp = d->size == 1 ? (int32_t)*(int8_t *)dp : - (int32_t)*(int16_t *)dp; - } -#if LJ_TARGET_ARM64 && LJ_BE - if (isfp && d->size == sizeof(float)) - ((float *)dp)[1] = ((float *)dp)[0]; /* Floats occupy high slot. */ -#endif -#if LJ_TARGET_MIPS64 || (LJ_TARGET_ARM64 && LJ_BE) - if ((ctype_isinteger_or_bool(d->info) || ctype_isenum(d->info) -#if LJ_TARGET_MIPS64 - || (isfp && nsp == 0) -#endif - ) && d->size <= 4) { - *(int64_t *)dp = (int64_t)*(int32_t *)dp; /* Sign-extend to 64 bit. */ - } -#endif -#if LJ_TARGET_X64 && LJ_ABI_WIN - if (isva) { /* Windows/x64 mirrors varargs in both register sets. */ - if (nfpr == ngpr) - cc->gpr[ngpr-1] = cc->fpr[ngpr-1].l[0]; - else - cc->fpr[ngpr-1].l[0] = cc->gpr[ngpr-1]; - } -#else - UNUSED(isva); -#endif -#if LJ_TARGET_X64 && !LJ_ABI_WIN - if (isfp == 2 && n == 2 && (uint8_t *)dp == (uint8_t *)&cc->fpr[nfpr-2]) { - cc->fpr[nfpr-1].d[0] = cc->fpr[nfpr-2].d[1]; /* Split complex double. */ - cc->fpr[nfpr-2].d[1] = 0; - } -#elif LJ_TARGET_ARM64 || (LJ_TARGET_MIPS64 && !LJ_ABI_SOFTFP) - if (isfp == 2 && (uint8_t *)dp < (uint8_t *)cc->stack) { - /* Split float HFA or complex float into separate registers. */ - CTSize i = (sz >> 2) - 1; - do { ((uint64_t *)dp)[i] = ((uint32_t *)dp)[i]; } while (i--); - } -#else - UNUSED(isfp); -#endif - } - if (fid) lj_err_caller(L, LJ_ERR_FFI_NUMARG); /* Too few arguments. */ - -#if LJ_TARGET_X64 || (LJ_TARGET_PPC && !LJ_ABI_SOFTFP) - cc->nfpr = nfpr; /* Required for vararg functions. */ -#endif - cc->nsp = nsp; - cc->spadj = (CCALL_SPS_FREE + CCALL_SPS_EXTRA)*CTSIZE_PTR; - if (nsp > CCALL_SPS_FREE) - cc->spadj += (((nsp-CCALL_SPS_FREE)*CTSIZE_PTR + 15u) & ~15u); - return gcsteps; -} - -/* Get results from C call. */ -static int ccall_get_results(lua_State *L, CTState *cts, CType *ct, - CCallState *cc, int *ret) -{ - CType *ctr = ctype_rawchild(cts, ct); - uint8_t *sp = (uint8_t *)&cc->gpr[0]; - if (ctype_isvoid(ctr->info)) { - *ret = 0; /* Zero results. */ - return 0; /* No additional GC step. */ - } - *ret = 1; /* One result. */ - if (ctype_isstruct(ctr->info)) { - /* Return cdata object which is already on top of stack. */ - if (!cc->retref) { - void *dp = cdataptr(cdataV(L->top-1)); /* Use preallocated object. */ - CCALL_HANDLE_STRUCTRET2 - } - return 1; /* One GC step. */ - } - if (ctype_iscomplex(ctr->info)) { - /* Return cdata object which is already on top of stack. */ - void *dp = cdataptr(cdataV(L->top-1)); /* Use preallocated object. */ - CCALL_HANDLE_COMPLEXRET2 - return 1; /* One GC step. */ - } - if (LJ_BE && ctr->size < CTSIZE_PTR && - (ctype_isinteger_or_bool(ctr->info) || ctype_isenum(ctr->info))) - sp += (CTSIZE_PTR - ctr->size); -#if CCALL_NUM_FPR - if (ctype_isfp(ctr->info) || ctype_isvector(ctr->info)) - sp = (uint8_t *)&cc->fpr[0]; -#endif -#ifdef CCALL_HANDLE_RET - CCALL_HANDLE_RET -#endif - /* No reference types end up here, so there's no need for the CTypeID. */ - lua_assert(!(ctype_isrefarray(ctr->info) || ctype_isstruct(ctr->info))); - return lj_cconv_tv_ct(cts, ctr, 0, L->top-1, sp); -} - -/* Call C function. */ -int lj_ccall_func(lua_State *L, GCcdata *cd) -{ - CTState *cts = ctype_cts(L); - CType *ct = ctype_raw(cts, cd->ctypeid); - CTSize sz = CTSIZE_PTR; - if (ctype_isptr(ct->info)) { - sz = ct->size; - ct = ctype_rawchild(cts, ct); - } - if (ctype_isfunc(ct->info)) { - CCallState cc; - int gcsteps, ret; - cc.func = (void (*)(void))cdata_getptr(cdataptr(cd), sz); - gcsteps = ccall_set_args(L, cts, ct, &cc); - ct = (CType *)((intptr_t)ct-(intptr_t)cts->tab); - cts->cb.slot = ~0u; - lj_vm_ffi_call(&cc); - if (cts->cb.slot != ~0u) { /* Blacklist function that called a callback. */ - TValue tv; - setlightudV(&tv, (void *)cc.func); - setboolV(lj_tab_set(L, cts->miscmap, &tv), 1); - } - ct = (CType *)((intptr_t)ct+(intptr_t)cts->tab); /* May be reallocated. */ - gcsteps += ccall_get_results(L, cts, ct, &cc, &ret); -#if LJ_TARGET_X86 && LJ_ABI_WIN - /* Automatically detect __stdcall and fix up C function declaration. */ - if (cc.spadj && ctype_cconv(ct->info) == CTCC_CDECL) { - CTF_INSERT(ct->info, CCONV, CTCC_STDCALL); - lj_trace_abort(G(L)); - } -#endif - while (gcsteps-- > 0) - lj_gc_check(L); - return ret; - } - return -1; /* Not a function. */ -} - -#endif diff --git a/lib/LuaJIT/src/lj_ccall.h b/lib/LuaJIT/src/lj_ccall.h deleted file mode 100644 index 6efa48c..0000000 --- a/lib/LuaJIT/src/lj_ccall.h +++ /dev/null @@ -1,194 +0,0 @@ -/* -** FFI C call handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_CCALL_H -#define _LJ_CCALL_H - -#include "lj_obj.h" -#include "lj_ctype.h" - -#if LJ_HASFFI - -/* -- C calling conventions ----------------------------------------------- */ - -#if LJ_TARGET_X86ORX64 - -#if LJ_TARGET_X86 -#define CCALL_NARG_GPR 2 /* For fastcall arguments. */ -#define CCALL_NARG_FPR 0 -#define CCALL_NRET_GPR 2 -#define CCALL_NRET_FPR 1 /* For FP results on x87 stack. */ -#define CCALL_ALIGN_STACKARG 0 /* Don't align argument on stack. */ -#elif LJ_ABI_WIN -#define CCALL_NARG_GPR 4 -#define CCALL_NARG_FPR 4 -#define CCALL_NRET_GPR 1 -#define CCALL_NRET_FPR 1 -#define CCALL_SPS_EXTRA 4 -#else -#define CCALL_NARG_GPR 6 -#define CCALL_NARG_FPR 8 -#define CCALL_NRET_GPR 2 -#define CCALL_NRET_FPR 2 -#define CCALL_VECTOR_REG 1 /* Pass vectors in registers. */ -#endif - -#define CCALL_SPS_FREE 1 -#define CCALL_ALIGN_CALLSTATE 16 - -typedef LJ_ALIGN(16) union FPRArg { - double d[2]; - float f[4]; - uint8_t b[16]; - uint16_t s[8]; - int i[4]; - int64_t l[2]; -} FPRArg; - -typedef intptr_t GPRArg; - -#elif LJ_TARGET_ARM - -#define CCALL_NARG_GPR 4 -#define CCALL_NRET_GPR 2 /* For softfp double. */ -#if LJ_ABI_SOFTFP -#define CCALL_NARG_FPR 0 -#define CCALL_NRET_FPR 0 -#else -#define CCALL_NARG_FPR 8 -#define CCALL_NRET_FPR 4 -#endif -#define CCALL_SPS_FREE 0 - -typedef intptr_t GPRArg; -typedef union FPRArg { - double d; - float f[2]; -} FPRArg; - -#elif LJ_TARGET_ARM64 - -#define CCALL_NARG_GPR 8 -#define CCALL_NRET_GPR 2 -#define CCALL_NARG_FPR 8 -#define CCALL_NRET_FPR 4 -#define CCALL_SPS_FREE 0 - -typedef intptr_t GPRArg; -typedef union FPRArg { - double d; - struct { LJ_ENDIAN_LOHI(float f; , float g;) }; - struct { LJ_ENDIAN_LOHI(uint32_t lo; , uint32_t hi;) }; -} FPRArg; - -#elif LJ_TARGET_PPC - -#define CCALL_NARG_GPR 8 -#define CCALL_NARG_FPR (LJ_ABI_SOFTFP ? 0 : 8) -#define CCALL_NRET_GPR 4 /* For complex double. */ -#define CCALL_NRET_FPR (LJ_ABI_SOFTFP ? 0 : 1) -#define CCALL_SPS_EXTRA 4 -#define CCALL_SPS_FREE 0 - -typedef intptr_t GPRArg; -typedef double FPRArg; - -#elif LJ_TARGET_MIPS32 - -#define CCALL_NARG_GPR 4 -#define CCALL_NARG_FPR (LJ_ABI_SOFTFP ? 0 : 2) -#define CCALL_NRET_GPR (LJ_ABI_SOFTFP ? 4 : 2) -#define CCALL_NRET_FPR (LJ_ABI_SOFTFP ? 0 : 2) -#define CCALL_SPS_EXTRA 7 -#define CCALL_SPS_FREE 1 - -typedef intptr_t GPRArg; -typedef union FPRArg { - double d; - struct { LJ_ENDIAN_LOHI(float f; , float g;) }; -} FPRArg; - -#elif LJ_TARGET_MIPS64 - -/* FP args are positional and overlay the GPR array. */ -#define CCALL_NARG_GPR 8 -#define CCALL_NARG_FPR 0 -#define CCALL_NRET_GPR 2 -#define CCALL_NRET_FPR (LJ_ABI_SOFTFP ? 0 : 2) -#define CCALL_SPS_EXTRA 3 -#define CCALL_SPS_FREE 1 - -typedef intptr_t GPRArg; -typedef union FPRArg { - double d; - struct { LJ_ENDIAN_LOHI(float f; , float g;) }; -} FPRArg; - -#else -#error "Missing calling convention definitions for this architecture" -#endif - -#ifndef CCALL_SPS_EXTRA -#define CCALL_SPS_EXTRA 0 -#endif -#ifndef CCALL_VECTOR_REG -#define CCALL_VECTOR_REG 0 -#endif -#ifndef CCALL_ALIGN_STACKARG -#define CCALL_ALIGN_STACKARG 1 -#endif -#ifndef CCALL_ALIGN_CALLSTATE -#define CCALL_ALIGN_CALLSTATE 8 -#endif - -#define CCALL_NUM_GPR \ - (CCALL_NARG_GPR > CCALL_NRET_GPR ? CCALL_NARG_GPR : CCALL_NRET_GPR) -#define CCALL_NUM_FPR \ - (CCALL_NARG_FPR > CCALL_NRET_FPR ? CCALL_NARG_FPR : CCALL_NRET_FPR) - -/* Check against constants in lj_ctype.h. */ -LJ_STATIC_ASSERT(CCALL_NUM_GPR <= CCALL_MAX_GPR); -LJ_STATIC_ASSERT(CCALL_NUM_FPR <= CCALL_MAX_FPR); - -#define CCALL_MAXSTACK 32 - -/* -- C call state -------------------------------------------------------- */ - -typedef LJ_ALIGN(CCALL_ALIGN_CALLSTATE) struct CCallState { - void (*func)(void); /* Pointer to called function. */ - uint32_t spadj; /* Stack pointer adjustment. */ - uint8_t nsp; /* Number of stack slots. */ - uint8_t retref; /* Return value by reference. */ -#if LJ_TARGET_X64 - uint8_t ngpr; /* Number of arguments in GPRs. */ - uint8_t nfpr; /* Number of arguments in FPRs. */ -#elif LJ_TARGET_X86 - uint8_t resx87; /* Result on x87 stack: 1:float, 2:double. */ -#elif LJ_TARGET_ARM64 - void *retp; /* Aggregate return pointer in x8. */ -#elif LJ_TARGET_PPC - uint8_t nfpr; /* Number of arguments in FPRs. */ -#endif -#if LJ_32 - int32_t align1; -#endif -#if CCALL_NUM_FPR - FPRArg fpr[CCALL_NUM_FPR]; /* Arguments/results in FPRs. */ -#endif - GPRArg gpr[CCALL_NUM_GPR]; /* Arguments/results in GPRs. */ - GPRArg stack[CCALL_MAXSTACK]; /* Stack slots. */ -} CCallState; - -/* -- C call handling ----------------------------------------------------- */ - -/* Really belongs to lj_vm.h. */ -LJ_ASMF void LJ_FASTCALL lj_vm_ffi_call(CCallState *cc); - -LJ_FUNC CTypeID lj_ccall_ctid_vararg(CTState *cts, cTValue *o); -LJ_FUNC int lj_ccall_func(lua_State *L, GCcdata *cd); - -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_ccallback.c b/lib/LuaJIT/src/lj_ccallback.c deleted file mode 100644 index 412dbf8..0000000 --- a/lib/LuaJIT/src/lj_ccallback.c +++ /dev/null @@ -1,787 +0,0 @@ -/* -** FFI C callback handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#include "lj_obj.h" - -#if LJ_HASFFI - -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_tab.h" -#include "lj_state.h" -#include "lj_frame.h" -#include "lj_ctype.h" -#include "lj_cconv.h" -#include "lj_ccall.h" -#include "lj_ccallback.h" -#include "lj_target.h" -#include "lj_mcode.h" -#include "lj_trace.h" -#include "lj_vm.h" - -/* -- Target-specific handling of callback slots -------------------------- */ - -#define CALLBACK_MCODE_SIZE (LJ_PAGESIZE * LJ_NUM_CBPAGE) - -#if LJ_OS_NOJIT - -/* Callbacks disabled. */ -#define CALLBACK_SLOT2OFS(slot) (0*(slot)) -#define CALLBACK_OFS2SLOT(ofs) (0*(ofs)) -#define CALLBACK_MAX_SLOT 0 - -#elif LJ_TARGET_X86ORX64 - -#define CALLBACK_MCODE_HEAD (LJ_64 ? 8 : 0) -#define CALLBACK_MCODE_GROUP (-2+1+2+(LJ_GC64 ? 10 : 5)+(LJ_64 ? 6 : 5)) - -#define CALLBACK_SLOT2OFS(slot) \ - (CALLBACK_MCODE_HEAD + CALLBACK_MCODE_GROUP*((slot)/32) + 4*(slot)) - -static MSize CALLBACK_OFS2SLOT(MSize ofs) -{ - MSize group; - ofs -= CALLBACK_MCODE_HEAD; - group = ofs / (32*4 + CALLBACK_MCODE_GROUP); - return (ofs % (32*4 + CALLBACK_MCODE_GROUP))/4 + group*32; -} - -#define CALLBACK_MAX_SLOT \ - (((CALLBACK_MCODE_SIZE-CALLBACK_MCODE_HEAD)/(CALLBACK_MCODE_GROUP+4*32))*32) - -#elif LJ_TARGET_ARM - -#define CALLBACK_MCODE_HEAD 32 - -#elif LJ_TARGET_ARM64 - -#define CALLBACK_MCODE_HEAD 32 - -#elif LJ_TARGET_PPC - -#define CALLBACK_MCODE_HEAD 24 - -#elif LJ_TARGET_MIPS32 - -#define CALLBACK_MCODE_HEAD 20 - -#elif LJ_TARGET_MIPS64 - -#define CALLBACK_MCODE_HEAD 52 - -#else - -/* Missing support for this architecture. */ -#define CALLBACK_SLOT2OFS(slot) (0*(slot)) -#define CALLBACK_OFS2SLOT(ofs) (0*(ofs)) -#define CALLBACK_MAX_SLOT 0 - -#endif - -#ifndef CALLBACK_SLOT2OFS -#define CALLBACK_SLOT2OFS(slot) (CALLBACK_MCODE_HEAD + 8*(slot)) -#define CALLBACK_OFS2SLOT(ofs) (((ofs)-CALLBACK_MCODE_HEAD)/8) -#define CALLBACK_MAX_SLOT (CALLBACK_OFS2SLOT(CALLBACK_MCODE_SIZE)) -#endif - -/* Convert callback slot number to callback function pointer. */ -static void *callback_slot2ptr(CTState *cts, MSize slot) -{ - return (uint8_t *)cts->cb.mcode + CALLBACK_SLOT2OFS(slot); -} - -/* Convert callback function pointer to slot number. */ -MSize lj_ccallback_ptr2slot(CTState *cts, void *p) -{ - uintptr_t ofs = (uintptr_t)((uint8_t *)p -(uint8_t *)cts->cb.mcode); - if (ofs < CALLBACK_MCODE_SIZE) { - MSize slot = CALLBACK_OFS2SLOT((MSize)ofs); - if (CALLBACK_SLOT2OFS(slot) == (MSize)ofs) - return slot; - } - return ~0u; /* Not a known callback function pointer. */ -} - -/* Initialize machine code for callback function pointers. */ -#if LJ_OS_NOJIT -/* Disabled callback support. */ -#define callback_mcode_init(g, p) UNUSED(p) -#elif LJ_TARGET_X86ORX64 -static void callback_mcode_init(global_State *g, uint8_t *page) -{ - uint8_t *p = page; - uint8_t *target = (uint8_t *)(void *)lj_vm_ffi_callback; - MSize slot; -#if LJ_64 - *(void **)p = target; p += 8; -#endif - for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) { - /* mov al, slot; jmp group */ - *p++ = XI_MOVrib | RID_EAX; *p++ = (uint8_t)slot; - if ((slot & 31) == 31 || slot == CALLBACK_MAX_SLOT-1) { - /* push ebp/rbp; mov ah, slot>>8; mov ebp, &g. */ - *p++ = XI_PUSH + RID_EBP; - *p++ = XI_MOVrib | (RID_EAX+4); *p++ = (uint8_t)(slot >> 8); -#if LJ_GC64 - *p++ = 0x48; *p++ = XI_MOVri | RID_EBP; - *(uint64_t *)p = (uint64_t)(g); p += 8; -#else - *p++ = XI_MOVri | RID_EBP; - *(int32_t *)p = i32ptr(g); p += 4; -#endif -#if LJ_64 - /* jmp [rip-pageofs] where lj_vm_ffi_callback is stored. */ - *p++ = XI_GROUP5; *p++ = XM_OFS0 + (XOg_JMP<<3) + RID_EBP; - *(int32_t *)p = (int32_t)(page-(p+4)); p += 4; -#else - /* jmp lj_vm_ffi_callback. */ - *p++ = XI_JMP; *(int32_t *)p = target-(p+4); p += 4; -#endif - } else { - *p++ = XI_JMPs; *p++ = (uint8_t)((2+2)*(31-(slot&31)) - 2); - } - } - lua_assert(p - page <= CALLBACK_MCODE_SIZE); -} -#elif LJ_TARGET_ARM -static void callback_mcode_init(global_State *g, uint32_t *page) -{ - uint32_t *p = page; - void *target = (void *)lj_vm_ffi_callback; - MSize slot; - /* This must match with the saveregs macro in buildvm_arm.dasc. */ - *p++ = ARMI_SUB|ARMF_D(RID_R12)|ARMF_N(RID_R12)|ARMF_M(RID_PC); - *p++ = ARMI_PUSH|ARMF_N(RID_SP)|RSET_RANGE(RID_R4,RID_R11+1)|RID2RSET(RID_LR); - *p++ = ARMI_SUB|ARMI_K12|ARMF_D(RID_R12)|ARMF_N(RID_R12)|CALLBACK_MCODE_HEAD; - *p++ = ARMI_STR|ARMI_LS_P|ARMI_LS_W|ARMF_D(RID_R12)|ARMF_N(RID_SP)|(CFRAME_SIZE-4*9); - *p++ = ARMI_LDR|ARMI_LS_P|ARMI_LS_U|ARMF_D(RID_R12)|ARMF_N(RID_PC); - *p++ = ARMI_LDR|ARMI_LS_P|ARMI_LS_U|ARMF_D(RID_PC)|ARMF_N(RID_PC); - *p++ = u32ptr(g); - *p++ = u32ptr(target); - for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) { - *p++ = ARMI_MOV|ARMF_D(RID_R12)|ARMF_M(RID_PC); - *p = ARMI_B | ((page-p-2) & 0x00ffffffu); - p++; - } - lua_assert(p - page <= CALLBACK_MCODE_SIZE); -} -#elif LJ_TARGET_ARM64 -static void callback_mcode_init(global_State *g, uint32_t *page) -{ - uint32_t *p = page; - void *target = (void *)lj_vm_ffi_callback; - MSize slot; - *p++ = A64I_LE(A64I_LDRLx | A64F_D(RID_X11) | A64F_S19(4)); - *p++ = A64I_LE(A64I_LDRLx | A64F_D(RID_X10) | A64F_S19(5)); - *p++ = A64I_LE(A64I_BR | A64F_N(RID_X11)); - *p++ = A64I_LE(A64I_NOP); - ((void **)p)[0] = target; - ((void **)p)[1] = g; - p += 4; - for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) { - *p++ = A64I_LE(A64I_MOVZw | A64F_D(RID_X9) | A64F_U16(slot)); - *p = A64I_LE(A64I_B | A64F_S26((page-p) & 0x03ffffffu)); - p++; - } - lua_assert(p - page <= CALLBACK_MCODE_SIZE); -} -#elif LJ_TARGET_PPC -static void callback_mcode_init(global_State *g, uint32_t *page) -{ - uint32_t *p = page; - void *target = (void *)lj_vm_ffi_callback; - MSize slot; - *p++ = PPCI_LIS | PPCF_T(RID_TMP) | (u32ptr(target) >> 16); - *p++ = PPCI_LIS | PPCF_T(RID_R12) | (u32ptr(g) >> 16); - *p++ = PPCI_ORI | PPCF_A(RID_TMP)|PPCF_T(RID_TMP) | (u32ptr(target) & 0xffff); - *p++ = PPCI_ORI | PPCF_A(RID_R12)|PPCF_T(RID_R12) | (u32ptr(g) & 0xffff); - *p++ = PPCI_MTCTR | PPCF_T(RID_TMP); - *p++ = PPCI_BCTR; - for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) { - *p++ = PPCI_LI | PPCF_T(RID_R11) | slot; - *p = PPCI_B | (((page-p) & 0x00ffffffu) << 2); - p++; - } - lua_assert(p - page <= CALLBACK_MCODE_SIZE); -} -#elif LJ_TARGET_MIPS -static void callback_mcode_init(global_State *g, uint32_t *page) -{ - uint32_t *p = page; - uintptr_t target = (uintptr_t)(void *)lj_vm_ffi_callback; - uintptr_t ug = (uintptr_t)(void *)g; - MSize slot; -#if LJ_TARGET_MIPS32 - *p++ = MIPSI_LUI | MIPSF_T(RID_R3) | (target >> 16); - *p++ = MIPSI_LUI | MIPSF_T(RID_R2) | (ug >> 16); -#else - *p++ = MIPSI_LUI | MIPSF_T(RID_R3) | (target >> 48); - *p++ = MIPSI_LUI | MIPSF_T(RID_R2) | (ug >> 48); - *p++ = MIPSI_ORI | MIPSF_T(RID_R3)|MIPSF_S(RID_R3) | ((target >> 32) & 0xffff); - *p++ = MIPSI_ORI | MIPSF_T(RID_R2)|MIPSF_S(RID_R2) | ((ug >> 32) & 0xffff); - *p++ = MIPSI_DSLL | MIPSF_D(RID_R3)|MIPSF_T(RID_R3) | MIPSF_A(16); - *p++ = MIPSI_DSLL | MIPSF_D(RID_R2)|MIPSF_T(RID_R2) | MIPSF_A(16); - *p++ = MIPSI_ORI | MIPSF_T(RID_R3)|MIPSF_S(RID_R3) | ((target >> 16) & 0xffff); - *p++ = MIPSI_ORI | MIPSF_T(RID_R2)|MIPSF_S(RID_R2) | ((ug >> 16) & 0xffff); - *p++ = MIPSI_DSLL | MIPSF_D(RID_R3)|MIPSF_T(RID_R3) | MIPSF_A(16); - *p++ = MIPSI_DSLL | MIPSF_D(RID_R2)|MIPSF_T(RID_R2) | MIPSF_A(16); -#endif - *p++ = MIPSI_ORI | MIPSF_T(RID_R3)|MIPSF_S(RID_R3) | (target & 0xffff); - *p++ = MIPSI_JR | MIPSF_S(RID_R3); - *p++ = MIPSI_ORI | MIPSF_T(RID_R2)|MIPSF_S(RID_R2) | (ug & 0xffff); - for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) { - *p = MIPSI_B | ((page-p-1) & 0x0000ffffu); - p++; - *p++ = MIPSI_LI | MIPSF_T(RID_R1) | slot; - } - lua_assert(p - page <= CALLBACK_MCODE_SIZE); -} -#else -/* Missing support for this architecture. */ -#define callback_mcode_init(g, p) UNUSED(p) -#endif - -/* -- Machine code management --------------------------------------------- */ - -#if LJ_TARGET_WINDOWS - -#define WIN32_LEAN_AND_MEAN -#include - -#elif LJ_TARGET_POSIX - -#include -#ifndef MAP_ANONYMOUS -#define MAP_ANONYMOUS MAP_ANON -#endif - -#endif - -/* Allocate and initialize area for callback function pointers. */ -static void callback_mcode_new(CTState *cts) -{ - size_t sz = (size_t)CALLBACK_MCODE_SIZE; - void *p; - if (CALLBACK_MAX_SLOT == 0) - lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV); -#if LJ_TARGET_WINDOWS - p = LJ_WIN_VALLOC(NULL, sz, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); - if (!p) - lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV); -#elif LJ_TARGET_POSIX - p = mmap(NULL, sz, (PROT_READ|PROT_WRITE), MAP_PRIVATE|MAP_ANONYMOUS, - -1, 0); - if (p == MAP_FAILED) - lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV); -#else - /* Fallback allocator. Fails if memory is not executable by default. */ - p = lj_mem_new(cts->L, sz); -#endif - cts->cb.mcode = p; - callback_mcode_init(cts->g, p); - lj_mcode_sync(p, (char *)p + sz); -#if LJ_TARGET_WINDOWS - { - DWORD oprot; - LJ_WIN_VPROTECT(p, sz, PAGE_EXECUTE_READ, &oprot); - } -#elif LJ_TARGET_POSIX - mprotect(p, sz, (PROT_READ|PROT_EXEC)); -#endif -} - -/* Free area for callback function pointers. */ -void lj_ccallback_mcode_free(CTState *cts) -{ - size_t sz = (size_t)CALLBACK_MCODE_SIZE; - void *p = cts->cb.mcode; - if (p == NULL) return; -#if LJ_TARGET_WINDOWS - VirtualFree(p, 0, MEM_RELEASE); - UNUSED(sz); -#elif LJ_TARGET_POSIX - munmap(p, sz); -#else - lj_mem_free(cts->g, p, sz); -#endif -} - -/* -- C callback entry ---------------------------------------------------- */ - -/* Target-specific handling of register arguments. Similar to lj_ccall.c. */ -#if LJ_TARGET_X86 - -#define CALLBACK_HANDLE_REGARG \ - if (!isfp) { /* Only non-FP values may be passed in registers. */ \ - if (n > 1) { /* Anything > 32 bit is passed on the stack. */ \ - if (!LJ_ABI_WIN) ngpr = maxgpr; /* Prevent reordering. */ \ - } else if (ngpr + 1 <= maxgpr) { \ - sp = &cts->cb.gpr[ngpr]; \ - ngpr += n; \ - goto done; \ - } \ - } - -#elif LJ_TARGET_X64 && LJ_ABI_WIN - -/* Windows/x64 argument registers are strictly positional (use ngpr). */ -#define CALLBACK_HANDLE_REGARG \ - if (isfp) { \ - if (ngpr < maxgpr) { sp = &cts->cb.fpr[ngpr++]; UNUSED(nfpr); goto done; } \ - } else { \ - if (ngpr < maxgpr) { sp = &cts->cb.gpr[ngpr++]; goto done; } \ - } - -#elif LJ_TARGET_X64 - -#define CALLBACK_HANDLE_REGARG \ - if (isfp) { \ - if (nfpr + n <= CCALL_NARG_FPR) { \ - sp = &cts->cb.fpr[nfpr]; \ - nfpr += n; \ - goto done; \ - } \ - } else { \ - if (ngpr + n <= maxgpr) { \ - sp = &cts->cb.gpr[ngpr]; \ - ngpr += n; \ - goto done; \ - } \ - } - -#elif LJ_TARGET_ARM - -#if LJ_ABI_SOFTFP - -#define CALLBACK_HANDLE_REGARG_FP1 UNUSED(isfp); -#define CALLBACK_HANDLE_REGARG_FP2 - -#else - -#define CALLBACK_HANDLE_REGARG_FP1 \ - if (isfp) { \ - if (n == 1) { \ - if (fprodd) { \ - sp = &cts->cb.fpr[fprodd-1]; \ - fprodd = 0; \ - goto done; \ - } else if (nfpr + 1 <= CCALL_NARG_FPR) { \ - sp = &cts->cb.fpr[nfpr++]; \ - fprodd = nfpr; \ - goto done; \ - } \ - } else { \ - if (nfpr + 1 <= CCALL_NARG_FPR) { \ - sp = &cts->cb.fpr[nfpr++]; \ - goto done; \ - } \ - } \ - fprodd = 0; /* No reordering after the first FP value is on stack. */ \ - } else { - -#define CALLBACK_HANDLE_REGARG_FP2 } - -#endif - -#define CALLBACK_HANDLE_REGARG \ - CALLBACK_HANDLE_REGARG_FP1 \ - if (n > 1) ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \ - if (ngpr + n <= maxgpr) { \ - sp = &cts->cb.gpr[ngpr]; \ - ngpr += n; \ - goto done; \ - } CALLBACK_HANDLE_REGARG_FP2 - -#elif LJ_TARGET_ARM64 - -#define CALLBACK_HANDLE_REGARG \ - if (isfp) { \ - if (nfpr + n <= CCALL_NARG_FPR) { \ - sp = &cts->cb.fpr[nfpr]; \ - nfpr += n; \ - goto done; \ - } else { \ - nfpr = CCALL_NARG_FPR; /* Prevent reordering. */ \ - } \ - } else { \ - if (!LJ_TARGET_IOS && n > 1) \ - ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \ - if (ngpr + n <= maxgpr) { \ - sp = &cts->cb.gpr[ngpr]; \ - ngpr += n; \ - goto done; \ - } else { \ - ngpr = CCALL_NARG_GPR; /* Prevent reordering. */ \ - } \ - } - -#elif LJ_TARGET_PPC - -#define CALLBACK_HANDLE_GPR \ - if (n > 1) { \ - lua_assert(((LJ_ABI_SOFTFP && ctype_isnum(cta->info)) || /* double. */ \ - ctype_isinteger(cta->info)) && n == 2); /* int64_t. */ \ - ngpr = (ngpr + 1u) & ~1u; /* Align int64_t to regpair. */ \ - } \ - if (ngpr + n <= maxgpr) { \ - sp = &cts->cb.gpr[ngpr]; \ - ngpr += n; \ - goto done; \ - } - -#if LJ_ABI_SOFTFP -#define CALLBACK_HANDLE_REGARG \ - CALLBACK_HANDLE_GPR \ - UNUSED(isfp); -#else -#define CALLBACK_HANDLE_REGARG \ - if (isfp) { \ - if (nfpr + 1 <= CCALL_NARG_FPR) { \ - sp = &cts->cb.fpr[nfpr++]; \ - cta = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */ \ - goto done; \ - } \ - } else { /* Try to pass argument in GPRs. */ \ - CALLBACK_HANDLE_GPR \ - } -#endif - -#if !LJ_ABI_SOFTFP -#define CALLBACK_HANDLE_RET \ - if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ - *(double *)dp = *(float *)dp; /* FPRs always hold doubles. */ -#endif - -#elif LJ_TARGET_MIPS32 - -#define CALLBACK_HANDLE_GPR \ - if (n > 1) ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \ - if (ngpr + n <= maxgpr) { \ - sp = &cts->cb.gpr[ngpr]; \ - ngpr += n; \ - goto done; \ - } - -#if !LJ_ABI_SOFTFP /* MIPS32 hard-float */ -#define CALLBACK_HANDLE_REGARG \ - if (isfp && nfpr < CCALL_NARG_FPR) { /* Try to pass argument in FPRs. */ \ - sp = (void *)((uint8_t *)&cts->cb.fpr[nfpr] + ((LJ_BE && n==1) ? 4 : 0)); \ - nfpr++; ngpr += n; \ - goto done; \ - } else { /* Try to pass argument in GPRs. */ \ - nfpr = CCALL_NARG_FPR; \ - CALLBACK_HANDLE_GPR \ - } -#else /* MIPS32 soft-float */ -#define CALLBACK_HANDLE_REGARG \ - CALLBACK_HANDLE_GPR \ - UNUSED(isfp); -#endif - -#define CALLBACK_HANDLE_RET \ - if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ - ((float *)dp)[1] = *(float *)dp; - -#elif LJ_TARGET_MIPS64 - -#if !LJ_ABI_SOFTFP /* MIPS64 hard-float */ -#define CALLBACK_HANDLE_REGARG \ - if (ngpr + n <= maxgpr) { \ - sp = isfp ? (void*) &cts->cb.fpr[ngpr] : (void*) &cts->cb.gpr[ngpr]; \ - ngpr += n; \ - goto done; \ - } -#else /* MIPS64 soft-float */ -#define CALLBACK_HANDLE_REGARG \ - if (ngpr + n <= maxgpr) { \ - UNUSED(isfp); \ - sp = (void*) &cts->cb.gpr[ngpr]; \ - ngpr += n; \ - goto done; \ - } -#endif - -#define CALLBACK_HANDLE_RET \ - if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ - ((float *)dp)[1] = *(float *)dp; - -#else -#error "Missing calling convention definitions for this architecture" -#endif - -/* Convert and push callback arguments to Lua stack. */ -static void callback_conv_args(CTState *cts, lua_State *L) -{ - TValue *o = L->top; - intptr_t *stack = cts->cb.stack; - MSize slot = cts->cb.slot; - CTypeID id = 0, rid, fid; - int gcsteps = 0; - CType *ct; - GCfunc *fn; - int fntp; - MSize ngpr = 0, nsp = 0, maxgpr = CCALL_NARG_GPR; -#if CCALL_NARG_FPR - MSize nfpr = 0; -#if LJ_TARGET_ARM - MSize fprodd = 0; -#endif -#endif - - if (slot < cts->cb.sizeid && (id = cts->cb.cbid[slot]) != 0) { - ct = ctype_get(cts, id); - rid = ctype_cid(ct->info); /* Return type. x86: +(spadj<<16). */ - fn = funcV(lj_tab_getint(cts->miscmap, (int32_t)slot)); - fntp = LJ_TFUNC; - } else { /* Must set up frame first, before throwing the error. */ - ct = NULL; - rid = 0; - fn = (GCfunc *)L; - fntp = LJ_TTHREAD; - } - /* Continuation returns from callback. */ - if (LJ_FR2) { - (o++)->u64 = LJ_CONT_FFI_CALLBACK; - (o++)->u64 = rid; - o++; - } else { - o->u32.lo = LJ_CONT_FFI_CALLBACK; - o->u32.hi = rid; - o++; - } - setframe_gc(o, obj2gco(fn), fntp); - setframe_ftsz(o, ((char *)(o+1) - (char *)L->base) + FRAME_CONT); - L->top = L->base = ++o; - if (!ct) - lj_err_caller(cts->L, LJ_ERR_FFI_BADCBACK); - if (isluafunc(fn)) - setcframe_pc(L->cframe, proto_bc(funcproto(fn))+1); - lj_state_checkstack(L, LUA_MINSTACK); /* May throw. */ - o = L->base; /* Might have been reallocated. */ - -#if LJ_TARGET_X86 - /* x86 has several different calling conventions. */ - switch (ctype_cconv(ct->info)) { - case CTCC_FASTCALL: maxgpr = 2; break; - case CTCC_THISCALL: maxgpr = 1; break; - default: maxgpr = 0; break; - } -#endif - - fid = ct->sib; - while (fid) { - CType *ctf = ctype_get(cts, fid); - if (!ctype_isattrib(ctf->info)) { - CType *cta; - void *sp; - CTSize sz; - int isfp; - MSize n; - lua_assert(ctype_isfield(ctf->info)); - cta = ctype_rawchild(cts, ctf); - isfp = ctype_isfp(cta->info); - sz = (cta->size + CTSIZE_PTR-1) & ~(CTSIZE_PTR-1); - n = sz / CTSIZE_PTR; /* Number of GPRs or stack slots needed. */ - - CALLBACK_HANDLE_REGARG /* Handle register arguments. */ - - /* Otherwise pass argument on stack. */ - if (CCALL_ALIGN_STACKARG && LJ_32 && sz == 8) - nsp = (nsp + 1) & ~1u; /* Align 64 bit argument on stack. */ - sp = &stack[nsp]; - nsp += n; - - done: - if (LJ_BE && cta->size < CTSIZE_PTR -#if LJ_TARGET_MIPS64 - && !(isfp && nsp) -#endif - ) - sp = (void *)((uint8_t *)sp + CTSIZE_PTR-cta->size); - gcsteps += lj_cconv_tv_ct(cts, cta, 0, o++, sp); - } - fid = ctf->sib; - } - L->top = o; -#if LJ_TARGET_X86 - /* Store stack adjustment for returns from non-cdecl callbacks. */ - if (ctype_cconv(ct->info) != CTCC_CDECL) { -#if LJ_FR2 - (L->base-3)->u64 |= (nsp << (16+2)); -#else - (L->base-2)->u32.hi |= (nsp << (16+2)); -#endif - } -#endif - while (gcsteps-- > 0) - lj_gc_check(L); -} - -/* Convert Lua object to callback result. */ -static void callback_conv_result(CTState *cts, lua_State *L, TValue *o) -{ -#if LJ_FR2 - CType *ctr = ctype_raw(cts, (uint16_t)(L->base-3)->u64); -#else - CType *ctr = ctype_raw(cts, (uint16_t)(L->base-2)->u32.hi); -#endif -#if LJ_TARGET_X86 - cts->cb.gpr[2] = 0; -#endif - if (!ctype_isvoid(ctr->info)) { - uint8_t *dp = (uint8_t *)&cts->cb.gpr[0]; -#if CCALL_NUM_FPR - if (ctype_isfp(ctr->info)) - dp = (uint8_t *)&cts->cb.fpr[0]; -#endif -#if LJ_TARGET_ARM64 && LJ_BE - if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) - dp = (uint8_t *)&cts->cb.fpr[0].f[1]; -#endif - lj_cconv_ct_tv(cts, ctr, dp, o, 0); -#ifdef CALLBACK_HANDLE_RET - CALLBACK_HANDLE_RET -#endif - /* Extend returned integers to (at least) 32 bits. */ - if (ctype_isinteger_or_bool(ctr->info) && ctr->size < 4) { - if (ctr->info & CTF_UNSIGNED) - *(uint32_t *)dp = ctr->size == 1 ? (uint32_t)*(uint8_t *)dp : - (uint32_t)*(uint16_t *)dp; - else - *(int32_t *)dp = ctr->size == 1 ? (int32_t)*(int8_t *)dp : - (int32_t)*(int16_t *)dp; - } -#if LJ_TARGET_MIPS64 || (LJ_TARGET_ARM64 && LJ_BE) - /* Always sign-extend results to 64 bits. Even a soft-fp 'float'. */ - if (ctr->size <= 4 && - (LJ_ABI_SOFTFP || ctype_isinteger_or_bool(ctr->info))) - *(int64_t *)dp = (int64_t)*(int32_t *)dp; -#endif -#if LJ_TARGET_X86 - if (ctype_isfp(ctr->info)) - cts->cb.gpr[2] = ctr->size == sizeof(float) ? 1 : 2; -#endif - } -} - -/* Enter callback. */ -lua_State * LJ_FASTCALL lj_ccallback_enter(CTState *cts, void *cf) -{ - lua_State *L = cts->L; - global_State *g = cts->g; - lua_assert(L != NULL); - if (tvref(g->jit_base)) { - setstrV(L, L->top++, lj_err_str(L, LJ_ERR_FFI_BADCBACK)); - if (g->panic) g->panic(L); - exit(EXIT_FAILURE); - } - lj_trace_abort(g); /* Never record across callback. */ - /* Setup C frame. */ - cframe_prev(cf) = L->cframe; - setcframe_L(cf, L); - cframe_errfunc(cf) = -1; - cframe_nres(cf) = 0; - L->cframe = cf; - callback_conv_args(cts, L); - return L; /* Now call the function on this stack. */ -} - -/* Leave callback. */ -void LJ_FASTCALL lj_ccallback_leave(CTState *cts, TValue *o) -{ - lua_State *L = cts->L; - GCfunc *fn; - TValue *obase = L->base; - L->base = L->top; /* Keep continuation frame for throwing errors. */ - if (o >= L->base) { - /* PC of RET* is lost. Point to last line for result conv. errors. */ - fn = curr_func(L); - if (isluafunc(fn)) { - GCproto *pt = funcproto(fn); - setcframe_pc(L->cframe, proto_bc(pt)+pt->sizebc+1); - } - } - callback_conv_result(cts, L, o); - /* Finally drop C frame and continuation frame. */ - L->top -= 2+2*LJ_FR2; - L->base = obase; - L->cframe = cframe_prev(L->cframe); - cts->cb.slot = 0; /* Blacklist C function that called the callback. */ -} - -/* -- C callback management ----------------------------------------------- */ - -/* Get an unused slot in the callback slot table. */ -static MSize callback_slot_new(CTState *cts, CType *ct) -{ - CTypeID id = ctype_typeid(cts, ct); - CTypeID1 *cbid = cts->cb.cbid; - MSize top; - for (top = cts->cb.topid; top < cts->cb.sizeid; top++) - if (LJ_LIKELY(cbid[top] == 0)) - goto found; -#if CALLBACK_MAX_SLOT - if (top >= CALLBACK_MAX_SLOT) -#endif - lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV); - if (!cts->cb.mcode) - callback_mcode_new(cts); - lj_mem_growvec(cts->L, cbid, cts->cb.sizeid, CALLBACK_MAX_SLOT, CTypeID1); - cts->cb.cbid = cbid; - memset(cbid+top, 0, (cts->cb.sizeid-top)*sizeof(CTypeID1)); -found: - cbid[top] = id; - cts->cb.topid = top+1; - return top; -} - -/* Check for function pointer and supported argument/result types. */ -static CType *callback_checkfunc(CTState *cts, CType *ct) -{ - int narg = 0; - if (!ctype_isptr(ct->info) || (LJ_64 && ct->size != CTSIZE_PTR)) - return NULL; - ct = ctype_rawchild(cts, ct); - if (ctype_isfunc(ct->info)) { - CType *ctr = ctype_rawchild(cts, ct); - CTypeID fid = ct->sib; - if (!(ctype_isvoid(ctr->info) || ctype_isenum(ctr->info) || - ctype_isptr(ctr->info) || (ctype_isnum(ctr->info) && ctr->size <= 8))) - return NULL; - if ((ct->info & CTF_VARARG)) - return NULL; - while (fid) { - CType *ctf = ctype_get(cts, fid); - if (!ctype_isattrib(ctf->info)) { - CType *cta; - lua_assert(ctype_isfield(ctf->info)); - cta = ctype_rawchild(cts, ctf); - if (!(ctype_isenum(cta->info) || ctype_isptr(cta->info) || - (ctype_isnum(cta->info) && cta->size <= 8)) || - ++narg >= LUA_MINSTACK-3) - return NULL; - } - fid = ctf->sib; - } - return ct; - } - return NULL; -} - -/* Create a new callback and return the callback function pointer. */ -void *lj_ccallback_new(CTState *cts, CType *ct, GCfunc *fn) -{ - ct = callback_checkfunc(cts, ct); - if (ct) { - MSize slot = callback_slot_new(cts, ct); - GCtab *t = cts->miscmap; - setfuncV(cts->L, lj_tab_setint(cts->L, t, (int32_t)slot), fn); - lj_gc_anybarriert(cts->L, t); - return callback_slot2ptr(cts, slot); - } - return NULL; /* Bad conversion. */ -} - -#endif diff --git a/lib/LuaJIT/src/lj_ccallback.h b/lib/LuaJIT/src/lj_ccallback.h deleted file mode 100644 index a8cdad3..0000000 --- a/lib/LuaJIT/src/lj_ccallback.h +++ /dev/null @@ -1,25 +0,0 @@ -/* -** FFI C callback handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_CCALLBACK_H -#define _LJ_CCALLBACK_H - -#include "lj_obj.h" -#include "lj_ctype.h" - -#if LJ_HASFFI - -/* Really belongs to lj_vm.h. */ -LJ_ASMF void lj_vm_ffi_callback(void); - -LJ_FUNC MSize lj_ccallback_ptr2slot(CTState *cts, void *p); -LJ_FUNCA lua_State * LJ_FASTCALL lj_ccallback_enter(CTState *cts, void *cf); -LJ_FUNCA void LJ_FASTCALL lj_ccallback_leave(CTState *cts, TValue *o); -LJ_FUNC void *lj_ccallback_new(CTState *cts, CType *ct, GCfunc *fn); -LJ_FUNC void lj_ccallback_mcode_free(CTState *cts); - -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_cconv.c b/lib/LuaJIT/src/lj_cconv.c deleted file mode 100644 index 13b8230..0000000 --- a/lib/LuaJIT/src/lj_cconv.c +++ /dev/null @@ -1,754 +0,0 @@ -/* -** C type conversions. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#include "lj_obj.h" - -#if LJ_HASFFI - -#include "lj_err.h" -#include "lj_tab.h" -#include "lj_ctype.h" -#include "lj_cdata.h" -#include "lj_cconv.h" -#include "lj_ccallback.h" - -/* -- Conversion errors --------------------------------------------------- */ - -/* Bad conversion. */ -LJ_NORET static void cconv_err_conv(CTState *cts, CType *d, CType *s, - CTInfo flags) -{ - const char *dst = strdata(lj_ctype_repr(cts->L, ctype_typeid(cts, d), NULL)); - const char *src; - if ((flags & CCF_FROMTV)) - src = lj_obj_typename[1+(ctype_isnum(s->info) ? LUA_TNUMBER : - ctype_isarray(s->info) ? LUA_TSTRING : LUA_TNIL)]; - else - src = strdata(lj_ctype_repr(cts->L, ctype_typeid(cts, s), NULL)); - if (CCF_GETARG(flags)) - lj_err_argv(cts->L, CCF_GETARG(flags), LJ_ERR_FFI_BADCONV, src, dst); - else - lj_err_callerv(cts->L, LJ_ERR_FFI_BADCONV, src, dst); -} - -/* Bad conversion from TValue. */ -LJ_NORET static void cconv_err_convtv(CTState *cts, CType *d, TValue *o, - CTInfo flags) -{ - const char *dst = strdata(lj_ctype_repr(cts->L, ctype_typeid(cts, d), NULL)); - const char *src = lj_typename(o); - if (CCF_GETARG(flags)) - lj_err_argv(cts->L, CCF_GETARG(flags), LJ_ERR_FFI_BADCONV, src, dst); - else - lj_err_callerv(cts->L, LJ_ERR_FFI_BADCONV, src, dst); -} - -/* Initializer overflow. */ -LJ_NORET static void cconv_err_initov(CTState *cts, CType *d) -{ - const char *dst = strdata(lj_ctype_repr(cts->L, ctype_typeid(cts, d), NULL)); - lj_err_callerv(cts->L, LJ_ERR_FFI_INITOV, dst); -} - -/* -- C type compatibility checks ----------------------------------------- */ - -/* Get raw type and qualifiers for a child type. Resolves enums, too. */ -static CType *cconv_childqual(CTState *cts, CType *ct, CTInfo *qual) -{ - ct = ctype_child(cts, ct); - for (;;) { - if (ctype_isattrib(ct->info)) { - if (ctype_attrib(ct->info) == CTA_QUAL) *qual |= ct->size; - } else if (!ctype_isenum(ct->info)) { - break; - } - ct = ctype_child(cts, ct); - } - *qual |= (ct->info & CTF_QUAL); - return ct; -} - -/* Check for compatible types when converting to a pointer. -** Note: these checks are more relaxed than what C99 mandates. -*/ -int lj_cconv_compatptr(CTState *cts, CType *d, CType *s, CTInfo flags) -{ - if (!((flags & CCF_CAST) || d == s)) { - CTInfo dqual = 0, squal = 0; - d = cconv_childqual(cts, d, &dqual); - if (!ctype_isstruct(s->info)) - s = cconv_childqual(cts, s, &squal); - if ((flags & CCF_SAME)) { - if (dqual != squal) - return 0; /* Different qualifiers. */ - } else if (!(flags & CCF_IGNQUAL)) { - if ((dqual & squal) != squal) - return 0; /* Discarded qualifiers. */ - if (ctype_isvoid(d->info) || ctype_isvoid(s->info)) - return 1; /* Converting to/from void * is always ok. */ - } - if (ctype_type(d->info) != ctype_type(s->info) || - d->size != s->size) - return 0; /* Different type or different size. */ - if (ctype_isnum(d->info)) { - if (((d->info ^ s->info) & (CTF_BOOL|CTF_FP))) - return 0; /* Different numeric types. */ - } else if (ctype_ispointer(d->info)) { - /* Check child types for compatibility. */ - return lj_cconv_compatptr(cts, d, s, flags|CCF_SAME); - } else if (ctype_isstruct(d->info)) { - if (d != s) - return 0; /* Must be exact same type for struct/union. */ - } else if (ctype_isfunc(d->info)) { - /* NYI: structural equality of functions. */ - } - } - return 1; /* Types are compatible. */ -} - -/* -- C type to C type conversion ----------------------------------------- */ - -/* Convert C type to C type. Caveat: expects to get the raw CType! -** -** Note: This is only used by the interpreter and not optimized at all. -** The JIT compiler will do a much better job specializing for each case. -*/ -void lj_cconv_ct_ct(CTState *cts, CType *d, CType *s, - uint8_t *dp, uint8_t *sp, CTInfo flags) -{ - CTSize dsize = d->size, ssize = s->size; - CTInfo dinfo = d->info, sinfo = s->info; - void *tmpptr; - - lua_assert(!ctype_isenum(dinfo) && !ctype_isenum(sinfo)); - lua_assert(!ctype_isattrib(dinfo) && !ctype_isattrib(sinfo)); - - if (ctype_type(dinfo) > CT_MAYCONVERT || ctype_type(sinfo) > CT_MAYCONVERT) - goto err_conv; - - /* Some basic sanity checks. */ - lua_assert(!ctype_isnum(dinfo) || dsize > 0); - lua_assert(!ctype_isnum(sinfo) || ssize > 0); - lua_assert(!ctype_isbool(dinfo) || dsize == 1 || dsize == 4); - lua_assert(!ctype_isbool(sinfo) || ssize == 1 || ssize == 4); - lua_assert(!ctype_isinteger(dinfo) || (1u< ssize) { /* Zero-extend or sign-extend LSB. */ -#if LJ_LE - uint8_t fill = (!(sinfo & CTF_UNSIGNED) && (sp[ssize-1]&0x80)) ? 0xff : 0; - memcpy(dp, sp, ssize); - memset(dp + ssize, fill, dsize-ssize); -#else - uint8_t fill = (!(sinfo & CTF_UNSIGNED) && (sp[0]&0x80)) ? 0xff : 0; - memset(dp, fill, dsize-ssize); - memcpy(dp + (dsize-ssize), sp, ssize); -#endif - } else { /* Copy LSB. */ -#if LJ_LE - memcpy(dp, sp, dsize); -#else - memcpy(dp, sp + (ssize-dsize), dsize); -#endif - } - break; - case CCX(I, F): { - double n; /* Always convert via double. */ - conv_I_F: - /* Convert source to double. */ - if (ssize == sizeof(double)) n = *(double *)sp; - else if (ssize == sizeof(float)) n = (double)*(float *)sp; - else goto err_conv; /* NYI: long double. */ - /* Then convert double to integer. */ - /* The conversion must exactly match the semantics of JIT-compiled code! */ - if (dsize < 4 || (dsize == 4 && !(dinfo & CTF_UNSIGNED))) { - int32_t i = (int32_t)n; - if (dsize == 4) *(int32_t *)dp = i; - else if (dsize == 2) *(int16_t *)dp = (int16_t)i; - else *(int8_t *)dp = (int8_t)i; - } else if (dsize == 4) { - *(uint32_t *)dp = (uint32_t)n; - } else if (dsize == 8) { - if (!(dinfo & CTF_UNSIGNED)) - *(int64_t *)dp = (int64_t)n; - else - *(uint64_t *)dp = lj_num2u64(n); - } else { - goto err_conv; /* NYI: conversion to >64 bit integers. */ - } - break; - } - case CCX(I, C): - s = ctype_child(cts, s); - sinfo = s->info; - ssize = s->size; - goto conv_I_F; /* Just convert re. */ - case CCX(I, P): - if (!(flags & CCF_CAST)) goto err_conv; - sinfo = CTINFO(CT_NUM, CTF_UNSIGNED); - goto conv_I_I; - case CCX(I, A): - if (!(flags & CCF_CAST)) goto err_conv; - sinfo = CTINFO(CT_NUM, CTF_UNSIGNED); - ssize = CTSIZE_PTR; - tmpptr = sp; - sp = (uint8_t *)&tmpptr; - goto conv_I_I; - - /* Destination is a floating-point number. */ - case CCX(F, B): - case CCX(F, I): { - double n; /* Always convert via double. */ - conv_F_I: - /* First convert source to double. */ - /* The conversion must exactly match the semantics of JIT-compiled code! */ - if (ssize < 4 || (ssize == 4 && !(sinfo & CTF_UNSIGNED))) { - int32_t i; - if (ssize == 4) { - i = *(int32_t *)sp; - } else if (!(sinfo & CTF_UNSIGNED)) { - if (ssize == 2) i = *(int16_t *)sp; - else i = *(int8_t *)sp; - } else { - if (ssize == 2) i = *(uint16_t *)sp; - else i = *(uint8_t *)sp; - } - n = (double)i; - } else if (ssize == 4) { - n = (double)*(uint32_t *)sp; - } else if (ssize == 8) { - if (!(sinfo & CTF_UNSIGNED)) n = (double)*(int64_t *)sp; - else n = (double)*(uint64_t *)sp; - } else { - goto err_conv; /* NYI: conversion from >64 bit integers. */ - } - /* Convert double to destination. */ - if (dsize == sizeof(double)) *(double *)dp = n; - else if (dsize == sizeof(float)) *(float *)dp = (float)n; - else goto err_conv; /* NYI: long double. */ - break; - } - case CCX(F, F): { - double n; /* Always convert via double. */ - conv_F_F: - if (ssize == dsize) goto copyval; - /* Convert source to double. */ - if (ssize == sizeof(double)) n = *(double *)sp; - else if (ssize == sizeof(float)) n = (double)*(float *)sp; - else goto err_conv; /* NYI: long double. */ - /* Convert double to destination. */ - if (dsize == sizeof(double)) *(double *)dp = n; - else if (dsize == sizeof(float)) *(float *)dp = (float)n; - else goto err_conv; /* NYI: long double. */ - break; - } - case CCX(F, C): - s = ctype_child(cts, s); - sinfo = s->info; - ssize = s->size; - goto conv_F_F; /* Ignore im, and convert from re. */ - - /* Destination is a complex number. */ - case CCX(C, I): - d = ctype_child(cts, d); - dinfo = d->info; - dsize = d->size; - memset(dp + dsize, 0, dsize); /* Clear im. */ - goto conv_F_I; /* Convert to re. */ - case CCX(C, F): - d = ctype_child(cts, d); - dinfo = d->info; - dsize = d->size; - memset(dp + dsize, 0, dsize); /* Clear im. */ - goto conv_F_F; /* Convert to re. */ - - case CCX(C, C): - if (dsize != ssize) { /* Different types: convert re/im separately. */ - CType *dc = ctype_child(cts, d); - CType *sc = ctype_child(cts, s); - lj_cconv_ct_ct(cts, dc, sc, dp, sp, flags); - lj_cconv_ct_ct(cts, dc, sc, dp + dc->size, sp + sc->size, flags); - return; - } - goto copyval; /* Otherwise this is easy. */ - - /* Destination is a vector. */ - case CCX(V, I): - case CCX(V, F): - case CCX(V, C): { - CType *dc = ctype_child(cts, d); - CTSize esize; - /* First convert the scalar to the first element. */ - lj_cconv_ct_ct(cts, dc, s, dp, sp, flags); - /* Then replicate it to the other elements (splat). */ - for (sp = dp, esize = dc->size; dsize > esize; dsize -= esize) { - dp += esize; - memcpy(dp, sp, esize); - } - break; - } - - case CCX(V, V): - /* Copy same-sized vectors, even for different lengths/element-types. */ - if (dsize != ssize) goto err_conv; - goto copyval; - - /* Destination is a pointer. */ - case CCX(P, I): - if (!(flags & CCF_CAST)) goto err_conv; - dinfo = CTINFO(CT_NUM, CTF_UNSIGNED); - goto conv_I_I; - - case CCX(P, F): - if (!(flags & CCF_CAST) || !(flags & CCF_FROMTV)) goto err_conv; - /* The signed conversion is cheaper. x64 really has 47 bit pointers. */ - dinfo = CTINFO(CT_NUM, (LJ_64 && dsize == 8) ? 0 : CTF_UNSIGNED); - goto conv_I_F; - - case CCX(P, P): - if (!lj_cconv_compatptr(cts, d, s, flags)) goto err_conv; - cdata_setptr(dp, dsize, cdata_getptr(sp, ssize)); - break; - - case CCX(P, A): - case CCX(P, S): - if (!lj_cconv_compatptr(cts, d, s, flags)) goto err_conv; - cdata_setptr(dp, dsize, sp); - break; - - /* Destination is an array. */ - case CCX(A, A): - if ((flags & CCF_CAST) || (d->info & CTF_VLA) || dsize != ssize || - d->size == CTSIZE_INVALID || !lj_cconv_compatptr(cts, d, s, flags)) - goto err_conv; - goto copyval; - - /* Destination is a struct/union. */ - case CCX(S, S): - if ((flags & CCF_CAST) || (d->info & CTF_VLA) || d != s) - goto err_conv; /* Must be exact same type. */ -copyval: /* Copy value. */ - lua_assert(dsize == ssize); - memcpy(dp, sp, dsize); - break; - - default: - err_conv: - cconv_err_conv(cts, d, s, flags); - } -} - -/* -- C type to TValue conversion ----------------------------------------- */ - -/* Convert C type to TValue. Caveat: expects to get the raw CType! */ -int lj_cconv_tv_ct(CTState *cts, CType *s, CTypeID sid, - TValue *o, uint8_t *sp) -{ - CTInfo sinfo = s->info; - if (ctype_isnum(sinfo)) { - if (!ctype_isbool(sinfo)) { - if (ctype_isinteger(sinfo) && s->size > 4) goto copyval; - if (LJ_DUALNUM && ctype_isinteger(sinfo)) { - int32_t i; - lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT32), s, - (uint8_t *)&i, sp, 0); - if ((sinfo & CTF_UNSIGNED) && i < 0) - setnumV(o, (lua_Number)(uint32_t)i); - else - setintV(o, i); - } else { - lj_cconv_ct_ct(cts, ctype_get(cts, CTID_DOUBLE), s, - (uint8_t *)&o->n, sp, 0); - /* Numbers are NOT canonicalized here! Beware of uninitialized data. */ - lua_assert(tvisnum(o)); - } - } else { - uint32_t b = s->size == 1 ? (*sp != 0) : (*(int *)sp != 0); - setboolV(o, b); - setboolV(&cts->g->tmptv2, b); /* Remember for trace recorder. */ - } - return 0; - } else if (ctype_isrefarray(sinfo) || ctype_isstruct(sinfo)) { - /* Create reference. */ - setcdataV(cts->L, o, lj_cdata_newref(cts, sp, sid)); - return 1; /* Need GC step. */ - } else { - GCcdata *cd; - CTSize sz; - copyval: /* Copy value. */ - sz = s->size; - lua_assert(sz != CTSIZE_INVALID); - /* Attributes are stripped, qualifiers are kept (but mostly ignored). */ - cd = lj_cdata_new(cts, ctype_typeid(cts, s), sz); - setcdataV(cts->L, o, cd); - memcpy(cdataptr(cd), sp, sz); - return 1; /* Need GC step. */ - } -} - -/* Convert bitfield to TValue. */ -int lj_cconv_tv_bf(CTState *cts, CType *s, TValue *o, uint8_t *sp) -{ - CTInfo info = s->info; - CTSize pos, bsz; - uint32_t val; - lua_assert(ctype_isbitfield(info)); - /* NYI: packed bitfields may cause misaligned reads. */ - switch (ctype_bitcsz(info)) { - case 4: val = *(uint32_t *)sp; break; - case 2: val = *(uint16_t *)sp; break; - case 1: val = *(uint8_t *)sp; break; - default: lua_assert(0); val = 0; break; - } - /* Check if a packed bitfield crosses a container boundary. */ - pos = ctype_bitpos(info); - bsz = ctype_bitbsz(info); - lua_assert(pos < 8*ctype_bitcsz(info)); - lua_assert(bsz > 0 && bsz <= 8*ctype_bitcsz(info)); - if (pos + bsz > 8*ctype_bitcsz(info)) - lj_err_caller(cts->L, LJ_ERR_FFI_NYIPACKBIT); - if (!(info & CTF_BOOL)) { - CTSize shift = 32 - bsz; - if (!(info & CTF_UNSIGNED)) { - setintV(o, (int32_t)(val << (shift-pos)) >> shift); - } else { - val = (val << (shift-pos)) >> shift; - if (!LJ_DUALNUM || (int32_t)val < 0) - setnumV(o, (lua_Number)(uint32_t)val); - else - setintV(o, (int32_t)val); - } - } else { - uint32_t b = (val >> pos) & 1; - lua_assert(bsz == 1); - setboolV(o, b); - setboolV(&cts->g->tmptv2, b); /* Remember for trace recorder. */ - } - return 0; /* No GC step needed. */ -} - -/* -- TValue to C type conversion ----------------------------------------- */ - -/* Convert table to array. */ -static void cconv_array_tab(CTState *cts, CType *d, - uint8_t *dp, GCtab *t, CTInfo flags) -{ - int32_t i; - CType *dc = ctype_rawchild(cts, d); /* Array element type. */ - CTSize size = d->size, esize = dc->size, ofs = 0; - for (i = 0; ; i++) { - TValue *tv = (TValue *)lj_tab_getint(t, i); - if (!tv || tvisnil(tv)) { - if (i == 0) continue; /* Try again for 1-based tables. */ - break; /* Stop at first nil. */ - } - if (ofs >= size) - cconv_err_initov(cts, d); - lj_cconv_ct_tv(cts, dc, dp + ofs, tv, flags); - ofs += esize; - } - if (size != CTSIZE_INVALID) { /* Only fill up arrays with known size. */ - if (ofs == esize) { /* Replicate a single element. */ - for (; ofs < size; ofs += esize) memcpy(dp + ofs, dp, esize); - } else { /* Otherwise fill the remainder with zero. */ - memset(dp + ofs, 0, size - ofs); - } - } -} - -/* Convert table to sub-struct/union. */ -static void cconv_substruct_tab(CTState *cts, CType *d, uint8_t *dp, - GCtab *t, int32_t *ip, CTInfo flags) -{ - CTypeID id = d->sib; - while (id) { - CType *df = ctype_get(cts, id); - id = df->sib; - if (ctype_isfield(df->info) || ctype_isbitfield(df->info)) { - TValue *tv; - int32_t i = *ip, iz = i; - if (!gcref(df->name)) continue; /* Ignore unnamed fields. */ - if (i >= 0) { - retry: - tv = (TValue *)lj_tab_getint(t, i); - if (!tv || tvisnil(tv)) { - if (i == 0) { i = 1; goto retry; } /* 1-based tables. */ - if (iz == 0) { *ip = i = -1; goto tryname; } /* Init named fields. */ - break; /* Stop at first nil. */ - } - *ip = i + 1; - } else { - tryname: - tv = (TValue *)lj_tab_getstr(t, gco2str(gcref(df->name))); - if (!tv || tvisnil(tv)) continue; - } - if (ctype_isfield(df->info)) - lj_cconv_ct_tv(cts, ctype_rawchild(cts, df), dp+df->size, tv, flags); - else - lj_cconv_bf_tv(cts, df, dp+df->size, tv); - if ((d->info & CTF_UNION)) break; - } else if (ctype_isxattrib(df->info, CTA_SUBTYPE)) { - cconv_substruct_tab(cts, ctype_rawchild(cts, df), - dp+df->size, t, ip, flags); - } /* Ignore all other entries in the chain. */ - } -} - -/* Convert table to struct/union. */ -static void cconv_struct_tab(CTState *cts, CType *d, - uint8_t *dp, GCtab *t, CTInfo flags) -{ - int32_t i = 0; - memset(dp, 0, d->size); /* Much simpler to clear the struct first. */ - cconv_substruct_tab(cts, d, dp, t, &i, flags); -} - -/* Convert TValue to C type. Caveat: expects to get the raw CType! */ -void lj_cconv_ct_tv(CTState *cts, CType *d, - uint8_t *dp, TValue *o, CTInfo flags) -{ - CTypeID sid = CTID_P_VOID; - CType *s; - void *tmpptr; - uint8_t tmpbool, *sp = (uint8_t *)&tmpptr; - if (LJ_LIKELY(tvisint(o))) { - sp = (uint8_t *)&o->i; - sid = CTID_INT32; - flags |= CCF_FROMTV; - } else if (LJ_LIKELY(tvisnum(o))) { - sp = (uint8_t *)&o->n; - sid = CTID_DOUBLE; - flags |= CCF_FROMTV; - } else if (tviscdata(o)) { - sp = cdataptr(cdataV(o)); - sid = cdataV(o)->ctypeid; - s = ctype_get(cts, sid); - if (ctype_isref(s->info)) { /* Resolve reference for value. */ - lua_assert(s->size == CTSIZE_PTR); - sp = *(void **)sp; - sid = ctype_cid(s->info); - } - s = ctype_raw(cts, sid); - if (ctype_isfunc(s->info)) { - sid = lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|sid), CTSIZE_PTR); - } else { - if (ctype_isenum(s->info)) s = ctype_child(cts, s); - goto doconv; - } - } else if (tvisstr(o)) { - GCstr *str = strV(o); - if (ctype_isenum(d->info)) { /* Match string against enum constant. */ - CTSize ofs; - CType *cct = lj_ctype_getfield(cts, d, str, &ofs); - if (!cct || !ctype_isconstval(cct->info)) - goto err_conv; - lua_assert(d->size == 4); - sp = (uint8_t *)&cct->size; - sid = ctype_cid(cct->info); - } else if (ctype_isrefarray(d->info)) { /* Copy string to array. */ - CType *dc = ctype_rawchild(cts, d); - CTSize sz = str->len+1; - if (!ctype_isinteger(dc->info) || dc->size != 1) - goto err_conv; - if (d->size != 0 && d->size < sz) - sz = d->size; - memcpy(dp, strdata(str), sz); - return; - } else { /* Otherwise pass it as a const char[]. */ - sp = (uint8_t *)strdata(str); - sid = CTID_A_CCHAR; - flags |= CCF_FROMTV; - } - } else if (tvistab(o)) { - if (ctype_isarray(d->info)) { - cconv_array_tab(cts, d, dp, tabV(o), flags); - return; - } else if (ctype_isstruct(d->info)) { - cconv_struct_tab(cts, d, dp, tabV(o), flags); - return; - } else { - goto err_conv; - } - } else if (tvisbool(o)) { - tmpbool = boolV(o); - sp = &tmpbool; - sid = CTID_BOOL; - } else if (tvisnil(o)) { - tmpptr = (void *)0; - flags |= CCF_FROMTV; - } else if (tvisudata(o)) { - GCudata *ud = udataV(o); - tmpptr = uddata(ud); - if (ud->udtype == UDTYPE_IO_FILE) - tmpptr = *(void **)tmpptr; - } else if (tvislightud(o)) { - tmpptr = lightudV(o); - } else if (tvisfunc(o)) { - void *p = lj_ccallback_new(cts, d, funcV(o)); - if (p) { - *(void **)dp = p; - return; - } - goto err_conv; - } else { - err_conv: - cconv_err_convtv(cts, d, o, flags); - } - s = ctype_get(cts, sid); -doconv: - if (ctype_isenum(d->info)) d = ctype_child(cts, d); - lj_cconv_ct_ct(cts, d, s, dp, sp, flags); -} - -/* Convert TValue to bitfield. */ -void lj_cconv_bf_tv(CTState *cts, CType *d, uint8_t *dp, TValue *o) -{ - CTInfo info = d->info; - CTSize pos, bsz; - uint32_t val, mask; - lua_assert(ctype_isbitfield(info)); - if ((info & CTF_BOOL)) { - uint8_t tmpbool; - lua_assert(ctype_bitbsz(info) == 1); - lj_cconv_ct_tv(cts, ctype_get(cts, CTID_BOOL), &tmpbool, o, 0); - val = tmpbool; - } else { - CTypeID did = (info & CTF_UNSIGNED) ? CTID_UINT32 : CTID_INT32; - lj_cconv_ct_tv(cts, ctype_get(cts, did), (uint8_t *)&val, o, 0); - } - pos = ctype_bitpos(info); - bsz = ctype_bitbsz(info); - lua_assert(pos < 8*ctype_bitcsz(info)); - lua_assert(bsz > 0 && bsz <= 8*ctype_bitcsz(info)); - /* Check if a packed bitfield crosses a container boundary. */ - if (pos + bsz > 8*ctype_bitcsz(info)) - lj_err_caller(cts->L, LJ_ERR_FFI_NYIPACKBIT); - mask = ((1u << bsz) - 1u) << pos; - val = (val << pos) & mask; - /* NYI: packed bitfields may cause misaligned reads/writes. */ - switch (ctype_bitcsz(info)) { - case 4: *(uint32_t *)dp = (*(uint32_t *)dp & ~mask) | (uint32_t)val; break; - case 2: *(uint16_t *)dp = (*(uint16_t *)dp & ~mask) | (uint16_t)val; break; - case 1: *(uint8_t *)dp = (*(uint8_t *)dp & ~mask) | (uint8_t)val; break; - default: lua_assert(0); break; - } -} - -/* -- Initialize C type with TValues -------------------------------------- */ - -/* Initialize an array with TValues. */ -static void cconv_array_init(CTState *cts, CType *d, CTSize sz, uint8_t *dp, - TValue *o, MSize len) -{ - CType *dc = ctype_rawchild(cts, d); /* Array element type. */ - CTSize ofs, esize = dc->size; - MSize i; - if (len*esize > sz) - cconv_err_initov(cts, d); - for (i = 0, ofs = 0; i < len; i++, ofs += esize) - lj_cconv_ct_tv(cts, dc, dp + ofs, o + i, 0); - if (ofs == esize) { /* Replicate a single element. */ - for (; ofs < sz; ofs += esize) memcpy(dp + ofs, dp, esize); - } else { /* Otherwise fill the remainder with zero. */ - memset(dp + ofs, 0, sz - ofs); - } -} - -/* Initialize a sub-struct/union with TValues. */ -static void cconv_substruct_init(CTState *cts, CType *d, uint8_t *dp, - TValue *o, MSize len, MSize *ip) -{ - CTypeID id = d->sib; - while (id) { - CType *df = ctype_get(cts, id); - id = df->sib; - if (ctype_isfield(df->info) || ctype_isbitfield(df->info)) { - MSize i = *ip; - if (!gcref(df->name)) continue; /* Ignore unnamed fields. */ - if (i >= len) break; - *ip = i + 1; - if (ctype_isfield(df->info)) - lj_cconv_ct_tv(cts, ctype_rawchild(cts, df), dp+df->size, o + i, 0); - else - lj_cconv_bf_tv(cts, df, dp+df->size, o + i); - if ((d->info & CTF_UNION)) break; - } else if (ctype_isxattrib(df->info, CTA_SUBTYPE)) { - cconv_substruct_init(cts, ctype_rawchild(cts, df), - dp+df->size, o, len, ip); - if ((d->info & CTF_UNION)) break; - } /* Ignore all other entries in the chain. */ - } -} - -/* Initialize a struct/union with TValues. */ -static void cconv_struct_init(CTState *cts, CType *d, CTSize sz, uint8_t *dp, - TValue *o, MSize len) -{ - MSize i = 0; - memset(dp, 0, sz); /* Much simpler to clear the struct first. */ - cconv_substruct_init(cts, d, dp, o, len, &i); - if (i < len) - cconv_err_initov(cts, d); -} - -/* Check whether to use a multi-value initializer. -** This is true if an aggregate is to be initialized with a value. -** Valarrays are treated as values here so ct_tv handles (V|C, I|F). -*/ -int lj_cconv_multi_init(CTState *cts, CType *d, TValue *o) -{ - if (!(ctype_isrefarray(d->info) || ctype_isstruct(d->info))) - return 0; /* Destination is not an aggregate. */ - if (tvistab(o) || (tvisstr(o) && !ctype_isstruct(d->info))) - return 0; /* Initializer is not a value. */ - if (tviscdata(o) && lj_ctype_rawref(cts, cdataV(o)->ctypeid) == d) - return 0; /* Source and destination are identical aggregates. */ - return 1; /* Otherwise the initializer is a value. */ -} - -/* Initialize C type with TValues. Caveat: expects to get the raw CType! */ -void lj_cconv_ct_init(CTState *cts, CType *d, CTSize sz, - uint8_t *dp, TValue *o, MSize len) -{ - if (len == 0) - memset(dp, 0, sz); - else if (len == 1 && !lj_cconv_multi_init(cts, d, o)) - lj_cconv_ct_tv(cts, d, dp, o, 0); - else if (ctype_isarray(d->info)) /* Also handles valarray init with len>1. */ - cconv_array_init(cts, d, sz, dp, o, len); - else if (ctype_isstruct(d->info)) - cconv_struct_init(cts, d, sz, dp, o, len); - else - cconv_err_initov(cts, d); -} - -#endif diff --git a/lib/LuaJIT/src/lj_cconv.h b/lib/LuaJIT/src/lj_cconv.h deleted file mode 100644 index 0a0b66c..0000000 --- a/lib/LuaJIT/src/lj_cconv.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -** C type conversions. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_CCONV_H -#define _LJ_CCONV_H - -#include "lj_obj.h" -#include "lj_ctype.h" - -#if LJ_HASFFI - -/* Compressed C type index. ORDER CCX. */ -enum { - CCX_B, /* Bool. */ - CCX_I, /* Integer. */ - CCX_F, /* Floating-point number. */ - CCX_C, /* Complex. */ - CCX_V, /* Vector. */ - CCX_P, /* Pointer. */ - CCX_A, /* Refarray. */ - CCX_S /* Struct/union. */ -}; - -/* Convert C type info to compressed C type index. ORDER CT. ORDER CCX. */ -static LJ_AINLINE uint32_t cconv_idx(CTInfo info) -{ - uint32_t idx = ((info >> 26) & 15u); /* Dispatch bits. */ - lua_assert(ctype_type(info) <= CT_MAYCONVERT); -#if LJ_64 - idx = ((uint32_t)(U64x(f436fff5,fff7f021) >> 4*idx) & 15u); -#else - idx = (((idx < 8 ? 0xfff7f021u : 0xf436fff5) >> 4*(idx & 7u)) & 15u); -#endif - lua_assert(idx < 8); - return idx; -} - -#define cconv_idx2(dinfo, sinfo) \ - ((cconv_idx((dinfo)) << 3) + cconv_idx((sinfo))) - -#define CCX(dst, src) ((CCX_##dst << 3) + CCX_##src) - -/* Conversion flags. */ -#define CCF_CAST 0x00000001u -#define CCF_FROMTV 0x00000002u -#define CCF_SAME 0x00000004u -#define CCF_IGNQUAL 0x00000008u - -#define CCF_ARG_SHIFT 8 -#define CCF_ARG(n) ((n) << CCF_ARG_SHIFT) -#define CCF_GETARG(f) ((f) >> CCF_ARG_SHIFT) - -LJ_FUNC int lj_cconv_compatptr(CTState *cts, CType *d, CType *s, CTInfo flags); -LJ_FUNC void lj_cconv_ct_ct(CTState *cts, CType *d, CType *s, - uint8_t *dp, uint8_t *sp, CTInfo flags); -LJ_FUNC int lj_cconv_tv_ct(CTState *cts, CType *s, CTypeID sid, - TValue *o, uint8_t *sp); -LJ_FUNC int lj_cconv_tv_bf(CTState *cts, CType *s, TValue *o, uint8_t *sp); -LJ_FUNC void lj_cconv_ct_tv(CTState *cts, CType *d, - uint8_t *dp, TValue *o, CTInfo flags); -LJ_FUNC void lj_cconv_bf_tv(CTState *cts, CType *d, uint8_t *dp, TValue *o); -LJ_FUNC int lj_cconv_multi_init(CTState *cts, CType *d, TValue *o); -LJ_FUNC void lj_cconv_ct_init(CTState *cts, CType *d, CTSize sz, - uint8_t *dp, TValue *o, MSize len); - -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_cdata.c b/lib/LuaJIT/src/lj_cdata.c deleted file mode 100644 index 68e16d7..0000000 --- a/lib/LuaJIT/src/lj_cdata.c +++ /dev/null @@ -1,299 +0,0 @@ -/* -** C data management. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#include "lj_obj.h" - -#if LJ_HASFFI - -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_tab.h" -#include "lj_ctype.h" -#include "lj_cconv.h" -#include "lj_cdata.h" - -/* -- C data allocation --------------------------------------------------- */ - -/* Allocate a new C data object holding a reference to another object. */ -GCcdata *lj_cdata_newref(CTState *cts, const void *p, CTypeID id) -{ - CTypeID refid = lj_ctype_intern(cts, CTINFO_REF(id), CTSIZE_PTR); - GCcdata *cd = lj_cdata_new(cts, refid, CTSIZE_PTR); - *(const void **)cdataptr(cd) = p; - return cd; -} - -/* Allocate variable-sized or specially aligned C data object. */ -GCcdata *lj_cdata_newv(lua_State *L, CTypeID id, CTSize sz, CTSize align) -{ - global_State *g; - MSize extra = sizeof(GCcdataVar) + sizeof(GCcdata) + - (align > CT_MEMALIGN ? (1u<offset = (uint16_t)((char *)cd - p); - cdatav(cd)->extra = extra; - cdatav(cd)->len = sz; - g = G(L); - setgcrefr(cd->nextgc, g->gc.root); - setgcref(g->gc.root, obj2gco(cd)); - newwhite(g, obj2gco(cd)); - cd->marked |= 0x80; - cd->gct = ~LJ_TCDATA; - cd->ctypeid = id; - return cd; -} - -/* Allocate arbitrary C data object. */ -GCcdata *lj_cdata_newx(CTState *cts, CTypeID id, CTSize sz, CTInfo info) -{ - if (!(info & CTF_VLA) && ctype_align(info) <= CT_MEMALIGN) - return lj_cdata_new(cts, id, sz); - else - return lj_cdata_newv(cts->L, id, sz, ctype_align(info)); -} - -/* Free a C data object. */ -void LJ_FASTCALL lj_cdata_free(global_State *g, GCcdata *cd) -{ - if (LJ_UNLIKELY(cd->marked & LJ_GC_CDATA_FIN)) { - GCobj *root; - makewhite(g, obj2gco(cd)); - markfinalized(obj2gco(cd)); - if ((root = gcref(g->gc.mmudata)) != NULL) { - setgcrefr(cd->nextgc, root->gch.nextgc); - setgcref(root->gch.nextgc, obj2gco(cd)); - setgcref(g->gc.mmudata, obj2gco(cd)); - } else { - setgcref(cd->nextgc, obj2gco(cd)); - setgcref(g->gc.mmudata, obj2gco(cd)); - } - } else if (LJ_LIKELY(!cdataisv(cd))) { - CType *ct = ctype_raw(ctype_ctsG(g), cd->ctypeid); - CTSize sz = ctype_hassize(ct->info) ? ct->size : CTSIZE_PTR; - lua_assert(ctype_hassize(ct->info) || ctype_isfunc(ct->info) || - ctype_isextern(ct->info)); - lj_mem_free(g, cd, sizeof(GCcdata) + sz); - } else { - lj_mem_free(g, memcdatav(cd), sizecdatav(cd)); - } -} - -void lj_cdata_setfin(lua_State *L, GCcdata *cd, GCobj *obj, uint32_t it) -{ - GCtab *t = ctype_ctsG(G(L))->finalizer; - if (gcref(t->metatable)) { - /* Add cdata to finalizer table, if still enabled. */ - TValue *tv, tmp; - setcdataV(L, &tmp, cd); - lj_gc_anybarriert(L, t); - tv = lj_tab_set(L, t, &tmp); - if (it == LJ_TNIL) { - setnilV(tv); - cd->marked &= ~LJ_GC_CDATA_FIN; - } else { - setgcV(L, tv, obj, it); - cd->marked |= LJ_GC_CDATA_FIN; - } - } -} - -/* -- C data indexing ----------------------------------------------------- */ - -/* Index C data by a TValue. Return CType and pointer. */ -CType *lj_cdata_index(CTState *cts, GCcdata *cd, cTValue *key, uint8_t **pp, - CTInfo *qual) -{ - uint8_t *p = (uint8_t *)cdataptr(cd); - CType *ct = ctype_get(cts, cd->ctypeid); - ptrdiff_t idx; - - /* Resolve reference for cdata object. */ - if (ctype_isref(ct->info)) { - lua_assert(ct->size == CTSIZE_PTR); - p = *(uint8_t **)p; - ct = ctype_child(cts, ct); - } - -collect_attrib: - /* Skip attributes and collect qualifiers. */ - while (ctype_isattrib(ct->info)) { - if (ctype_attrib(ct->info) == CTA_QUAL) *qual |= ct->size; - ct = ctype_child(cts, ct); - } - lua_assert(!ctype_isref(ct->info)); /* Interning rejects refs to refs. */ - - if (tvisint(key)) { - idx = (ptrdiff_t)intV(key); - goto integer_key; - } else if (tvisnum(key)) { /* Numeric key. */ -#ifdef _MSC_VER - /* Workaround for MSVC bug. */ - volatile -#endif - lua_Number n = numV(key); - idx = LJ_64 ? (ptrdiff_t)n : (ptrdiff_t)lj_num2int(n); - integer_key: - if (ctype_ispointer(ct->info)) { - CTSize sz = lj_ctype_size(cts, ctype_cid(ct->info)); /* Element size. */ - if (sz == CTSIZE_INVALID) - lj_err_caller(cts->L, LJ_ERR_FFI_INVSIZE); - if (ctype_isptr(ct->info)) { - p = (uint8_t *)cdata_getptr(p, ct->size); - } else if ((ct->info & (CTF_VECTOR|CTF_COMPLEX))) { - if ((ct->info & CTF_COMPLEX)) idx &= 1; - *qual |= CTF_CONST; /* Valarray elements are constant. */ - } - *pp = p + idx*(int32_t)sz; - return ct; - } - } else if (tviscdata(key)) { /* Integer cdata key. */ - GCcdata *cdk = cdataV(key); - CType *ctk = ctype_raw(cts, cdk->ctypeid); - if (ctype_isenum(ctk->info)) ctk = ctype_child(cts, ctk); - if (ctype_isinteger(ctk->info)) { - lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), ctk, - (uint8_t *)&idx, cdataptr(cdk), 0); - goto integer_key; - } - } else if (tvisstr(key)) { /* String key. */ - GCstr *name = strV(key); - if (ctype_isstruct(ct->info)) { - CTSize ofs; - CType *fct = lj_ctype_getfieldq(cts, ct, name, &ofs, qual); - if (fct) { - *pp = p + ofs; - return fct; - } - } else if (ctype_iscomplex(ct->info)) { - if (name->len == 2) { - *qual |= CTF_CONST; /* Complex fields are constant. */ - if (strdata(name)[0] == 'r' && strdata(name)[1] == 'e') { - *pp = p; - return ct; - } else if (strdata(name)[0] == 'i' && strdata(name)[1] == 'm') { - *pp = p + (ct->size >> 1); - return ct; - } - } - } else if (cd->ctypeid == CTID_CTYPEID) { - /* Allow indexing a (pointer to) struct constructor to get constants. */ - CType *sct = ctype_raw(cts, *(CTypeID *)p); - if (ctype_isptr(sct->info)) - sct = ctype_rawchild(cts, sct); - if (ctype_isstruct(sct->info)) { - CTSize ofs; - CType *fct = lj_ctype_getfield(cts, sct, name, &ofs); - if (fct && ctype_isconstval(fct->info)) - return fct; - } - ct = sct; /* Allow resolving metamethods for constructors, too. */ - } - } - if (ctype_isptr(ct->info)) { /* Automatically perform '->'. */ - if (ctype_isstruct(ctype_rawchild(cts, ct)->info)) { - p = (uint8_t *)cdata_getptr(p, ct->size); - ct = ctype_child(cts, ct); - goto collect_attrib; - } - } - *qual |= 1; /* Lookup failed. */ - return ct; /* But return the resolved raw type. */ -} - -/* -- C data getters ------------------------------------------------------ */ - -/* Get constant value and convert to TValue. */ -static void cdata_getconst(CTState *cts, TValue *o, CType *ct) -{ - CType *ctt = ctype_child(cts, ct); - lua_assert(ctype_isinteger(ctt->info) && ctt->size <= 4); - /* Constants are already zero-extended/sign-extended to 32 bits. */ - if ((ctt->info & CTF_UNSIGNED) && (int32_t)ct->size < 0) - setnumV(o, (lua_Number)(uint32_t)ct->size); - else - setintV(o, (int32_t)ct->size); -} - -/* Get C data value and convert to TValue. */ -int lj_cdata_get(CTState *cts, CType *s, TValue *o, uint8_t *sp) -{ - CTypeID sid; - - if (ctype_isconstval(s->info)) { - cdata_getconst(cts, o, s); - return 0; /* No GC step needed. */ - } else if (ctype_isbitfield(s->info)) { - return lj_cconv_tv_bf(cts, s, o, sp); - } - - /* Get child type of pointer/array/field. */ - lua_assert(ctype_ispointer(s->info) || ctype_isfield(s->info)); - sid = ctype_cid(s->info); - s = ctype_get(cts, sid); - - /* Resolve reference for field. */ - if (ctype_isref(s->info)) { - lua_assert(s->size == CTSIZE_PTR); - sp = *(uint8_t **)sp; - sid = ctype_cid(s->info); - s = ctype_get(cts, sid); - } - - /* Skip attributes. */ - while (ctype_isattrib(s->info)) - s = ctype_child(cts, s); - - return lj_cconv_tv_ct(cts, s, sid, o, sp); -} - -/* -- C data setters ------------------------------------------------------ */ - -/* Convert TValue and set C data value. */ -void lj_cdata_set(CTState *cts, CType *d, uint8_t *dp, TValue *o, CTInfo qual) -{ - if (ctype_isconstval(d->info)) { - goto err_const; - } else if (ctype_isbitfield(d->info)) { - if (((d->info|qual) & CTF_CONST)) goto err_const; - lj_cconv_bf_tv(cts, d, dp, o); - return; - } - - /* Get child type of pointer/array/field. */ - lua_assert(ctype_ispointer(d->info) || ctype_isfield(d->info)); - d = ctype_child(cts, d); - - /* Resolve reference for field. */ - if (ctype_isref(d->info)) { - lua_assert(d->size == CTSIZE_PTR); - dp = *(uint8_t **)dp; - d = ctype_child(cts, d); - } - - /* Skip attributes and collect qualifiers. */ - for (;;) { - if (ctype_isattrib(d->info)) { - if (ctype_attrib(d->info) == CTA_QUAL) qual |= d->size; - } else { - break; - } - d = ctype_child(cts, d); - } - - lua_assert(ctype_hassize(d->info) && !ctype_isvoid(d->info)); - - if (((d->info|qual) & CTF_CONST)) { - err_const: - lj_err_caller(cts->L, LJ_ERR_FFI_WRCONST); - } - - lj_cconv_ct_tv(cts, d, dp, o, 0); -} - -#endif diff --git a/lib/LuaJIT/src/lj_cdata.h b/lib/LuaJIT/src/lj_cdata.h deleted file mode 100644 index 5bb0f5d..0000000 --- a/lib/LuaJIT/src/lj_cdata.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -** C data management. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_CDATA_H -#define _LJ_CDATA_H - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_ctype.h" - -#if LJ_HASFFI - -/* Get C data pointer. */ -static LJ_AINLINE void *cdata_getptr(void *p, CTSize sz) -{ - if (LJ_64 && sz == 4) { /* Support 32 bit pointers on 64 bit targets. */ - return ((void *)(uintptr_t)*(uint32_t *)p); - } else { - lua_assert(sz == CTSIZE_PTR); - return *(void **)p; - } -} - -/* Set C data pointer. */ -static LJ_AINLINE void cdata_setptr(void *p, CTSize sz, const void *v) -{ - if (LJ_64 && sz == 4) { /* Support 32 bit pointers on 64 bit targets. */ - *(uint32_t *)p = (uint32_t)(uintptr_t)v; - } else { - lua_assert(sz == CTSIZE_PTR); - *(void **)p = (void *)v; - } -} - -/* Allocate fixed-size C data object. */ -static LJ_AINLINE GCcdata *lj_cdata_new(CTState *cts, CTypeID id, CTSize sz) -{ - GCcdata *cd; -#ifdef LUA_USE_ASSERT - CType *ct = ctype_raw(cts, id); - lua_assert((ctype_hassize(ct->info) ? ct->size : CTSIZE_PTR) == sz); -#endif - cd = (GCcdata *)lj_mem_newgco(cts->L, sizeof(GCcdata) + sz); - cd->gct = ~LJ_TCDATA; - cd->ctypeid = ctype_check(cts, id); - return cd; -} - -/* Variant which works without a valid CTState. */ -static LJ_AINLINE GCcdata *lj_cdata_new_(lua_State *L, CTypeID id, CTSize sz) -{ - GCcdata *cd = (GCcdata *)lj_mem_newgco(L, sizeof(GCcdata) + sz); - cd->gct = ~LJ_TCDATA; - cd->ctypeid = id; - return cd; -} - -LJ_FUNC GCcdata *lj_cdata_newref(CTState *cts, const void *pp, CTypeID id); -LJ_FUNC GCcdata *lj_cdata_newv(lua_State *L, CTypeID id, CTSize sz, - CTSize align); -LJ_FUNC GCcdata *lj_cdata_newx(CTState *cts, CTypeID id, CTSize sz, - CTInfo info); - -LJ_FUNC void LJ_FASTCALL lj_cdata_free(global_State *g, GCcdata *cd); -LJ_FUNC void lj_cdata_setfin(lua_State *L, GCcdata *cd, GCobj *obj, - uint32_t it); - -LJ_FUNC CType *lj_cdata_index(CTState *cts, GCcdata *cd, cTValue *key, - uint8_t **pp, CTInfo *qual); -LJ_FUNC int lj_cdata_get(CTState *cts, CType *s, TValue *o, uint8_t *sp); -LJ_FUNC void lj_cdata_set(CTState *cts, CType *d, uint8_t *dp, TValue *o, - CTInfo qual); - -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_char.c b/lib/LuaJIT/src/lj_char.c deleted file mode 100644 index 11f23ef..0000000 --- a/lib/LuaJIT/src/lj_char.c +++ /dev/null @@ -1,43 +0,0 @@ -/* -** Character types. -** Donated to the public domain. -** -** This is intended to replace the problematic libc single-byte NLS functions. -** These just don't make sense anymore with UTF-8 locales becoming the norm -** on POSIX systems. It never worked too well on Windows systems since hardly -** anyone bothered to call setlocale(). -** -** This table is hardcoded for ASCII. Identifiers include the characters -** 128-255, too. This allows for the use of all non-ASCII chars as identifiers -** in the lexer. This is a broad definition, but works well in practice -** for both UTF-8 locales and most single-byte locales (such as ISO-8859-*). -** -** If you really need proper character types for UTF-8 strings, please use -** an add-on library such as slnunicode: http://luaforge.net/projects/sln/ -*/ - -#define lj_char_c -#define LUA_CORE - -#include "lj_char.h" - -LJ_DATADEF const uint8_t lj_char_bits[257] = { - 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 152,152,152,152,152,152,152,152,152,152, 4, 4, 4, 4, 4, 4, - 4,176,176,176,176,176,176,160,160,160,160,160,160,160,160,160, - 160,160,160,160,160,160,160,160,160,160,160, 4, 4, 4, 4,132, - 4,208,208,208,208,208,208,192,192,192,192,192,192,192,192,192, - 192,192,192,192,192,192,192,192,192,192,192, 4, 4, 4, 4, 1, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128 -}; - diff --git a/lib/LuaJIT/src/lj_char.h b/lib/LuaJIT/src/lj_char.h deleted file mode 100644 index c3c86d3..0000000 --- a/lib/LuaJIT/src/lj_char.h +++ /dev/null @@ -1,42 +0,0 @@ -/* -** Character types. -** Donated to the public domain. -*/ - -#ifndef _LJ_CHAR_H -#define _LJ_CHAR_H - -#include "lj_def.h" - -#define LJ_CHAR_CNTRL 0x01 -#define LJ_CHAR_SPACE 0x02 -#define LJ_CHAR_PUNCT 0x04 -#define LJ_CHAR_DIGIT 0x08 -#define LJ_CHAR_XDIGIT 0x10 -#define LJ_CHAR_UPPER 0x20 -#define LJ_CHAR_LOWER 0x40 -#define LJ_CHAR_IDENT 0x80 -#define LJ_CHAR_ALPHA (LJ_CHAR_LOWER|LJ_CHAR_UPPER) -#define LJ_CHAR_ALNUM (LJ_CHAR_ALPHA|LJ_CHAR_DIGIT) -#define LJ_CHAR_GRAPH (LJ_CHAR_ALNUM|LJ_CHAR_PUNCT) - -/* Only pass -1 or 0..255 to these macros. Never pass a signed char! */ -#define lj_char_isa(c, t) ((lj_char_bits+1)[(c)] & t) -#define lj_char_iscntrl(c) lj_char_isa((c), LJ_CHAR_CNTRL) -#define lj_char_isspace(c) lj_char_isa((c), LJ_CHAR_SPACE) -#define lj_char_ispunct(c) lj_char_isa((c), LJ_CHAR_PUNCT) -#define lj_char_isdigit(c) lj_char_isa((c), LJ_CHAR_DIGIT) -#define lj_char_isxdigit(c) lj_char_isa((c), LJ_CHAR_XDIGIT) -#define lj_char_isupper(c) lj_char_isa((c), LJ_CHAR_UPPER) -#define lj_char_islower(c) lj_char_isa((c), LJ_CHAR_LOWER) -#define lj_char_isident(c) lj_char_isa((c), LJ_CHAR_IDENT) -#define lj_char_isalpha(c) lj_char_isa((c), LJ_CHAR_ALPHA) -#define lj_char_isalnum(c) lj_char_isa((c), LJ_CHAR_ALNUM) -#define lj_char_isgraph(c) lj_char_isa((c), LJ_CHAR_GRAPH) - -#define lj_char_toupper(c) ((c) - (lj_char_islower(c) >> 1)) -#define lj_char_tolower(c) ((c) + lj_char_isupper(c)) - -LJ_DATA const uint8_t lj_char_bits[257]; - -#endif diff --git a/lib/LuaJIT/src/lj_clib.c b/lib/LuaJIT/src/lj_clib.c deleted file mode 100644 index f016b06..0000000 --- a/lib/LuaJIT/src/lj_clib.c +++ /dev/null @@ -1,430 +0,0 @@ -/* -** FFI C library loader. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#include "lj_obj.h" - -#if LJ_HASFFI - -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_tab.h" -#include "lj_str.h" -#include "lj_udata.h" -#include "lj_ctype.h" -#include "lj_cconv.h" -#include "lj_cdata.h" -#include "lj_clib.h" -#include "lj_strfmt.h" - -/* -- OS-specific functions ----------------------------------------------- */ - -#if LJ_TARGET_DLOPEN - -#include -#include - -#if defined(RTLD_DEFAULT) -#define CLIB_DEFHANDLE RTLD_DEFAULT -#elif LJ_TARGET_OSX || LJ_TARGET_BSD -#define CLIB_DEFHANDLE ((void *)(intptr_t)-2) -#else -#define CLIB_DEFHANDLE NULL -#endif - -LJ_NORET LJ_NOINLINE static void clib_error_(lua_State *L) -{ - lj_err_callermsg(L, dlerror()); -} - -#define clib_error(L, fmt, name) clib_error_(L) - -#if LJ_TARGET_CYGWIN -#define CLIB_SOPREFIX "cyg" -#else -#define CLIB_SOPREFIX "lib" -#endif - -#if LJ_TARGET_OSX -#define CLIB_SOEXT "%s.dylib" -#elif LJ_TARGET_CYGWIN -#define CLIB_SOEXT "%s.dll" -#else -#define CLIB_SOEXT "%s.so" -#endif - -static const char *clib_extname(lua_State *L, const char *name) -{ - if (!strchr(name, '/') -#if LJ_TARGET_CYGWIN - && !strchr(name, '\\') -#endif - ) { - if (!strchr(name, '.')) { - name = lj_strfmt_pushf(L, CLIB_SOEXT, name); - L->top--; -#if LJ_TARGET_CYGWIN - } else { - return name; -#endif - } - if (!(name[0] == CLIB_SOPREFIX[0] && name[1] == CLIB_SOPREFIX[1] && - name[2] == CLIB_SOPREFIX[2])) { - name = lj_strfmt_pushf(L, CLIB_SOPREFIX "%s", name); - L->top--; - } - } - return name; -} - -/* Check for a recognized ld script line. */ -static const char *clib_check_lds(lua_State *L, const char *buf) -{ - char *p, *e; - if ((!strncmp(buf, "GROUP", 5) || !strncmp(buf, "INPUT", 5)) && - (p = strchr(buf, '('))) { - while (*++p == ' ') ; - for (e = p; *e && *e != ' ' && *e != ')'; e++) ; - return strdata(lj_str_new(L, p, e-p)); - } - return NULL; -} - -/* Quick and dirty solution to resolve shared library name from ld script. */ -static const char *clib_resolve_lds(lua_State *L, const char *name) -{ - FILE *fp = fopen(name, "r"); - const char *p = NULL; - if (fp) { - char buf[256]; - if (fgets(buf, sizeof(buf), fp)) { - if (!strncmp(buf, "/* GNU ld script", 16)) { /* ld script magic? */ - while (fgets(buf, sizeof(buf), fp)) { /* Check all lines. */ - p = clib_check_lds(L, buf); - if (p) break; - } - } else { /* Otherwise check only the first line. */ - p = clib_check_lds(L, buf); - } - } - fclose(fp); - } - return p; -} - -static void *clib_loadlib(lua_State *L, const char *name, int global) -{ - void *h = dlopen(clib_extname(L, name), - RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL)); - if (!h) { - const char *e, *err = dlerror(); - if (*err == '/' && (e = strchr(err, ':')) && - (name = clib_resolve_lds(L, strdata(lj_str_new(L, err, e-err))))) { - h = dlopen(name, RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL)); - if (h) return h; - err = dlerror(); - } - lj_err_callermsg(L, err); - } - return h; -} - -static void clib_unloadlib(CLibrary *cl) -{ - if (cl->handle && cl->handle != CLIB_DEFHANDLE) - dlclose(cl->handle); -} - -static void *clib_getsym(CLibrary *cl, const char *name) -{ - void *p = dlsym(cl->handle, name); - return p; -} - -#elif LJ_TARGET_WINDOWS - -#define WIN32_LEAN_AND_MEAN -#include - -#ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS -#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4 -#define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2 -BOOL WINAPI GetModuleHandleExA(DWORD, LPCSTR, HMODULE*); -#endif - -#define CLIB_DEFHANDLE ((void *)-1) - -/* Default libraries. */ -enum { - CLIB_HANDLE_EXE, -#if !LJ_TARGET_UWP - CLIB_HANDLE_DLL, - CLIB_HANDLE_CRT, - CLIB_HANDLE_KERNEL32, - CLIB_HANDLE_USER32, - CLIB_HANDLE_GDI32, -#endif - CLIB_HANDLE_MAX -}; - -static void *clib_def_handle[CLIB_HANDLE_MAX]; - -LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt, - const char *name) -{ - DWORD err = GetLastError(); -#if LJ_TARGET_XBOXONE - wchar_t wbuf[128]; - char buf[128*2]; - if (!FormatMessageW(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM, - NULL, err, 0, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL) || - !WideCharToMultiByte(CP_ACP, 0, wbuf, 128, buf, 128*2, NULL, NULL)) -#else - char buf[128]; - if (!FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM, - NULL, err, 0, buf, sizeof(buf), NULL)) -#endif - buf[0] = '\0'; - lj_err_callermsg(L, lj_strfmt_pushf(L, fmt, name, buf)); -} - -static int clib_needext(const char *s) -{ - while (*s) { - if (*s == '/' || *s == '\\' || *s == '.') return 0; - s++; - } - return 1; -} - -static const char *clib_extname(lua_State *L, const char *name) -{ - if (clib_needext(name)) { - name = lj_strfmt_pushf(L, "%s.dll", name); - L->top--; - } - return name; -} - -static void *clib_loadlib(lua_State *L, const char *name, int global) -{ - DWORD oldwerr = GetLastError(); - void *h = LJ_WIN_LOADLIBA(clib_extname(L, name)); - if (!h) clib_error(L, "cannot load module " LUA_QS ": %s", name); - SetLastError(oldwerr); - UNUSED(global); - return h; -} - -static void clib_unloadlib(CLibrary *cl) -{ - if (cl->handle == CLIB_DEFHANDLE) { -#if !LJ_TARGET_UWP - MSize i; - for (i = CLIB_HANDLE_KERNEL32; i < CLIB_HANDLE_MAX; i++) { - void *h = clib_def_handle[i]; - if (h) { - clib_def_handle[i] = NULL; - FreeLibrary((HINSTANCE)h); - } - } -#endif - } else if (cl->handle) { - FreeLibrary((HINSTANCE)cl->handle); - } -} - -#if LJ_TARGET_UWP -EXTERN_C IMAGE_DOS_HEADER __ImageBase; -#endif - -static void *clib_getsym(CLibrary *cl, const char *name) -{ - void *p = NULL; - if (cl->handle == CLIB_DEFHANDLE) { /* Search default libraries. */ - MSize i; - for (i = 0; i < CLIB_HANDLE_MAX; i++) { - HINSTANCE h = (HINSTANCE)clib_def_handle[i]; - if (!(void *)h) { /* Resolve default library handles (once). */ -#if LJ_TARGET_UWP - h = (HINSTANCE)&__ImageBase; -#else - switch (i) { - case CLIB_HANDLE_EXE: GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, NULL, &h); break; - case CLIB_HANDLE_DLL: - GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, - (const char *)clib_def_handle, &h); - break; - case CLIB_HANDLE_CRT: - GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, - (const char *)&_fmode, &h); - break; - case CLIB_HANDLE_KERNEL32: h = LJ_WIN_LOADLIBA("kernel32.dll"); break; - case CLIB_HANDLE_USER32: h = LJ_WIN_LOADLIBA("user32.dll"); break; - case CLIB_HANDLE_GDI32: h = LJ_WIN_LOADLIBA("gdi32.dll"); break; - } - if (!h) continue; -#endif - clib_def_handle[i] = (void *)h; - } - p = (void *)GetProcAddress(h, name); - if (p) break; - } - } else { - p = (void *)GetProcAddress((HINSTANCE)cl->handle, name); - } - return p; -} - -#else - -#define CLIB_DEFHANDLE NULL - -LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt, - const char *name) -{ - lj_err_callermsg(L, lj_strfmt_pushf(L, fmt, name, "no support for this OS")); -} - -static void *clib_loadlib(lua_State *L, const char *name, int global) -{ - lj_err_callermsg(L, "no support for loading dynamic libraries for this OS"); - UNUSED(name); UNUSED(global); - return NULL; -} - -static void clib_unloadlib(CLibrary *cl) -{ - UNUSED(cl); -} - -static void *clib_getsym(CLibrary *cl, const char *name) -{ - UNUSED(cl); UNUSED(name); - return NULL; -} - -#endif - -/* -- C library indexing -------------------------------------------------- */ - -#if LJ_TARGET_X86 && LJ_ABI_WIN -/* Compute argument size for fastcall/stdcall functions. */ -static CTSize clib_func_argsize(CTState *cts, CType *ct) -{ - CTSize n = 0; - while (ct->sib) { - CType *d; - ct = ctype_get(cts, ct->sib); - if (ctype_isfield(ct->info)) { - d = ctype_rawchild(cts, ct); - n += ((d->size + 3) & ~3); - } - } - return n; -} -#endif - -/* Get redirected or mangled external symbol. */ -static const char *clib_extsym(CTState *cts, CType *ct, GCstr *name) -{ - if (ct->sib) { - CType *ctf = ctype_get(cts, ct->sib); - if (ctype_isxattrib(ctf->info, CTA_REDIR)) - return strdata(gco2str(gcref(ctf->name))); - } - return strdata(name); -} - -/* Index a C library by name. */ -TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name) -{ - TValue *tv = lj_tab_setstr(L, cl->cache, name); - if (LJ_UNLIKELY(tvisnil(tv))) { - CTState *cts = ctype_cts(L); - CType *ct; - CTypeID id = lj_ctype_getname(cts, &ct, name, CLNS_INDEX); - if (!id) - lj_err_callerv(L, LJ_ERR_FFI_NODECL, strdata(name)); - if (ctype_isconstval(ct->info)) { - CType *ctt = ctype_child(cts, ct); - lua_assert(ctype_isinteger(ctt->info) && ctt->size <= 4); - if ((ctt->info & CTF_UNSIGNED) && (int32_t)ct->size < 0) - setnumV(tv, (lua_Number)(uint32_t)ct->size); - else - setintV(tv, (int32_t)ct->size); - } else { - const char *sym = clib_extsym(cts, ct, name); -#if LJ_TARGET_WINDOWS - DWORD oldwerr = GetLastError(); -#endif - void *p = clib_getsym(cl, sym); - GCcdata *cd; - lua_assert(ctype_isfunc(ct->info) || ctype_isextern(ct->info)); -#if LJ_TARGET_X86 && LJ_ABI_WIN - /* Retry with decorated name for fastcall/stdcall functions. */ - if (!p && ctype_isfunc(ct->info)) { - CTInfo cconv = ctype_cconv(ct->info); - if (cconv == CTCC_FASTCALL || cconv == CTCC_STDCALL) { - CTSize sz = clib_func_argsize(cts, ct); - const char *symd = lj_strfmt_pushf(L, - cconv == CTCC_FASTCALL ? "@%s@%d" : "_%s@%d", - sym, sz); - L->top--; - p = clib_getsym(cl, symd); - } - } -#endif - if (!p) - clib_error(L, "cannot resolve symbol " LUA_QS ": %s", sym); -#if LJ_TARGET_WINDOWS - SetLastError(oldwerr); -#endif - cd = lj_cdata_new(cts, id, CTSIZE_PTR); - *(void **)cdataptr(cd) = p; - setcdataV(L, tv, cd); - } - } - return tv; -} - -/* -- C library management ------------------------------------------------ */ - -/* Create a new CLibrary object and push it on the stack. */ -static CLibrary *clib_new(lua_State *L, GCtab *mt) -{ - GCtab *t = lj_tab_new(L, 0, 0); - GCudata *ud = lj_udata_new(L, sizeof(CLibrary), t); - CLibrary *cl = (CLibrary *)uddata(ud); - cl->cache = t; - ud->udtype = UDTYPE_FFI_CLIB; - /* NOBARRIER: The GCudata is new (marked white). */ - setgcref(ud->metatable, obj2gco(mt)); - setudataV(L, L->top++, ud); - return cl; -} - -/* Load a C library. */ -void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global) -{ - void *handle = clib_loadlib(L, strdata(name), global); - CLibrary *cl = clib_new(L, mt); - cl->handle = handle; -} - -/* Unload a C library. */ -void lj_clib_unload(CLibrary *cl) -{ - clib_unloadlib(cl); - cl->handle = NULL; -} - -/* Create the default C library object. */ -void lj_clib_default(lua_State *L, GCtab *mt) -{ - CLibrary *cl = clib_new(L, mt); - cl->handle = CLIB_DEFHANDLE; -} - -#endif diff --git a/lib/LuaJIT/src/lj_clib.h b/lib/LuaJIT/src/lj_clib.h deleted file mode 100644 index fcc9dac..0000000 --- a/lib/LuaJIT/src/lj_clib.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -** FFI C library loader. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_CLIB_H -#define _LJ_CLIB_H - -#include "lj_obj.h" - -#if LJ_HASFFI - -/* Namespace for C library indexing. */ -#define CLNS_INDEX ((1u<env. */ -} CLibrary; - -LJ_FUNC TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name); -LJ_FUNC void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global); -LJ_FUNC void lj_clib_unload(CLibrary *cl); -LJ_FUNC void lj_clib_default(lua_State *L, GCtab *mt); - -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_cparse.c b/lib/LuaJIT/src/lj_cparse.c deleted file mode 100644 index 19f632f..0000000 --- a/lib/LuaJIT/src/lj_cparse.c +++ /dev/null @@ -1,1898 +0,0 @@ -/* -** C declaration parser. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#include "lj_obj.h" - -#if LJ_HASFFI - -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_buf.h" -#include "lj_ctype.h" -#include "lj_cparse.h" -#include "lj_frame.h" -#include "lj_vm.h" -#include "lj_char.h" -#include "lj_strscan.h" -#include "lj_strfmt.h" - -/* -** Important note: this is NOT a validating C parser! This is a minimal -** C declaration parser, solely for use by the LuaJIT FFI. -** -** It ought to return correct results for properly formed C declarations, -** but it may accept some invalid declarations, too (and return nonsense). -** Also, it shows rather generic error messages to avoid unnecessary bloat. -** If in doubt, please check the input against your favorite C compiler. -*/ - -/* -- C lexer ------------------------------------------------------------- */ - -/* C lexer token names. */ -static const char *const ctoknames[] = { -#define CTOKSTR(name, str) str, -CTOKDEF(CTOKSTR) -#undef CTOKSTR - NULL -}; - -/* Forward declaration. */ -LJ_NORET static void cp_err(CPState *cp, ErrMsg em); - -static const char *cp_tok2str(CPState *cp, CPToken tok) -{ - lua_assert(tok < CTOK_FIRSTDECL); - if (tok > CTOK_OFS) - return ctoknames[tok-CTOK_OFS-1]; - else if (!lj_char_iscntrl(tok)) - return lj_strfmt_pushf(cp->L, "%c", tok); - else - return lj_strfmt_pushf(cp->L, "char(%d)", tok); -} - -/* End-of-line? */ -static LJ_AINLINE int cp_iseol(CPChar c) -{ - return (c == '\n' || c == '\r'); -} - -/* Peek next raw character. */ -static LJ_AINLINE CPChar cp_rawpeek(CPState *cp) -{ - return (CPChar)(uint8_t)(*cp->p); -} - -static LJ_NOINLINE CPChar cp_get_bs(CPState *cp); - -/* Get next character. */ -static LJ_AINLINE CPChar cp_get(CPState *cp) -{ - cp->c = (CPChar)(uint8_t)(*cp->p++); - if (LJ_LIKELY(cp->c != '\\')) return cp->c; - return cp_get_bs(cp); -} - -/* Transparently skip backslash-escaped line breaks. */ -static LJ_NOINLINE CPChar cp_get_bs(CPState *cp) -{ - CPChar c2, c = cp_rawpeek(cp); - if (!cp_iseol(c)) return cp->c; - cp->p++; - c2 = cp_rawpeek(cp); - if (cp_iseol(c2) && c2 != c) cp->p++; - cp->linenumber++; - return cp_get(cp); -} - -/* Save character in buffer. */ -static LJ_AINLINE void cp_save(CPState *cp, CPChar c) -{ - lj_buf_putb(&cp->sb, c); -} - -/* Skip line break. Handles "\n", "\r", "\r\n" or "\n\r". */ -static void cp_newline(CPState *cp) -{ - CPChar c = cp_rawpeek(cp); - if (cp_iseol(c) && c != cp->c) cp->p++; - cp->linenumber++; -} - -LJ_NORET static void cp_errmsg(CPState *cp, CPToken tok, ErrMsg em, ...) -{ - const char *msg, *tokstr; - lua_State *L; - va_list argp; - if (tok == 0) { - tokstr = NULL; - } else if (tok == CTOK_IDENT || tok == CTOK_INTEGER || tok == CTOK_STRING || - tok >= CTOK_FIRSTDECL) { - if (sbufP(&cp->sb) == sbufB(&cp->sb)) cp_save(cp, '$'); - cp_save(cp, '\0'); - tokstr = sbufB(&cp->sb); - } else { - tokstr = cp_tok2str(cp, tok); - } - L = cp->L; - va_start(argp, em); - msg = lj_strfmt_pushvf(L, err2msg(em), argp); - va_end(argp); - if (tokstr) - msg = lj_strfmt_pushf(L, err2msg(LJ_ERR_XNEAR), msg, tokstr); - if (cp->linenumber > 1) - msg = lj_strfmt_pushf(L, "%s at line %d", msg, cp->linenumber); - lj_err_callermsg(L, msg); -} - -LJ_NORET LJ_NOINLINE static void cp_err_token(CPState *cp, CPToken tok) -{ - cp_errmsg(cp, cp->tok, LJ_ERR_XTOKEN, cp_tok2str(cp, tok)); -} - -LJ_NORET LJ_NOINLINE static void cp_err_badidx(CPState *cp, CType *ct) -{ - GCstr *s = lj_ctype_repr(cp->cts->L, ctype_typeid(cp->cts, ct), NULL); - cp_errmsg(cp, 0, LJ_ERR_FFI_BADIDX, strdata(s)); -} - -LJ_NORET LJ_NOINLINE static void cp_err(CPState *cp, ErrMsg em) -{ - cp_errmsg(cp, 0, em); -} - -/* -- Main lexical scanner ------------------------------------------------ */ - -/* Parse number literal. Only handles int32_t/uint32_t right now. */ -static CPToken cp_number(CPState *cp) -{ - StrScanFmt fmt; - TValue o; - do { cp_save(cp, cp->c); } while (lj_char_isident(cp_get(cp))); - cp_save(cp, '\0'); - fmt = lj_strscan_scan((const uint8_t *)sbufB(&cp->sb), &o, STRSCAN_OPT_C); - if (fmt == STRSCAN_INT) cp->val.id = CTID_INT32; - else if (fmt == STRSCAN_U32) cp->val.id = CTID_UINT32; - else if (!(cp->mode & CPARSE_MODE_SKIP)) - cp_errmsg(cp, CTOK_INTEGER, LJ_ERR_XNUMBER); - cp->val.u32 = (uint32_t)o.i; - return CTOK_INTEGER; -} - -/* Parse identifier or keyword. */ -static CPToken cp_ident(CPState *cp) -{ - do { cp_save(cp, cp->c); } while (lj_char_isident(cp_get(cp))); - cp->str = lj_buf_str(cp->L, &cp->sb); - cp->val.id = lj_ctype_getname(cp->cts, &cp->ct, cp->str, cp->tmask); - if (ctype_type(cp->ct->info) == CT_KW) - return ctype_cid(cp->ct->info); - return CTOK_IDENT; -} - -/* Parse parameter. */ -static CPToken cp_param(CPState *cp) -{ - CPChar c = cp_get(cp); - TValue *o = cp->param; - if (lj_char_isident(c) || c == '$') /* Reserve $xyz for future extensions. */ - cp_errmsg(cp, c, LJ_ERR_XSYNTAX); - if (!o || o >= cp->L->top) - cp_err(cp, LJ_ERR_FFI_NUMPARAM); - cp->param = o+1; - if (tvisstr(o)) { - cp->str = strV(o); - cp->val.id = 0; - cp->ct = &cp->cts->tab[0]; - return CTOK_IDENT; - } else if (tvisnumber(o)) { - cp->val.i32 = numberVint(o); - cp->val.id = CTID_INT32; - return CTOK_INTEGER; - } else { - GCcdata *cd; - if (!tviscdata(o)) - lj_err_argtype(cp->L, (int)(o-cp->L->base)+1, "type parameter"); - cd = cdataV(o); - if (cd->ctypeid == CTID_CTYPEID) - cp->val.id = *(CTypeID *)cdataptr(cd); - else - cp->val.id = cd->ctypeid; - return '$'; - } -} - -/* Parse string or character constant. */ -static CPToken cp_string(CPState *cp) -{ - CPChar delim = cp->c; - cp_get(cp); - while (cp->c != delim) { - CPChar c = cp->c; - if (c == '\0') cp_errmsg(cp, CTOK_EOF, LJ_ERR_XSTR); - if (c == '\\') { - c = cp_get(cp); - switch (c) { - case '\0': cp_errmsg(cp, CTOK_EOF, LJ_ERR_XSTR); break; - case 'a': c = '\a'; break; - case 'b': c = '\b'; break; - case 'f': c = '\f'; break; - case 'n': c = '\n'; break; - case 'r': c = '\r'; break; - case 't': c = '\t'; break; - case 'v': c = '\v'; break; - case 'e': c = 27; break; - case 'x': - c = 0; - while (lj_char_isxdigit(cp_get(cp))) - c = (c<<4) + (lj_char_isdigit(cp->c) ? cp->c-'0' : (cp->c&15)+9); - cp_save(cp, (c & 0xff)); - continue; - default: - if (lj_char_isdigit(c)) { - c -= '0'; - if (lj_char_isdigit(cp_get(cp))) { - c = c*8 + (cp->c - '0'); - if (lj_char_isdigit(cp_get(cp))) { - c = c*8 + (cp->c - '0'); - cp_get(cp); - } - } - cp_save(cp, (c & 0xff)); - continue; - } - break; - } - } - cp_save(cp, c); - cp_get(cp); - } - cp_get(cp); - if (delim == '"') { - cp->str = lj_buf_str(cp->L, &cp->sb); - return CTOK_STRING; - } else { - if (sbuflen(&cp->sb) != 1) cp_err_token(cp, '\''); - cp->val.i32 = (int32_t)(char)*sbufB(&cp->sb); - cp->val.id = CTID_INT32; - return CTOK_INTEGER; - } -} - -/* Skip C comment. */ -static void cp_comment_c(CPState *cp) -{ - do { - if (cp_get(cp) == '*') { - do { - if (cp_get(cp) == '/') { cp_get(cp); return; } - } while (cp->c == '*'); - } - if (cp_iseol(cp->c)) cp_newline(cp); - } while (cp->c != '\0'); -} - -/* Skip C++ comment. */ -static void cp_comment_cpp(CPState *cp) -{ - while (!cp_iseol(cp_get(cp)) && cp->c != '\0') - ; -} - -/* Lexical scanner for C. Only a minimal subset is implemented. */ -static CPToken cp_next_(CPState *cp) -{ - lj_buf_reset(&cp->sb); - for (;;) { - if (lj_char_isident(cp->c)) - return lj_char_isdigit(cp->c) ? cp_number(cp) : cp_ident(cp); - switch (cp->c) { - case '\n': case '\r': cp_newline(cp); /* fallthrough. */ - case ' ': case '\t': case '\v': case '\f': cp_get(cp); break; - case '"': case '\'': return cp_string(cp); - case '/': - if (cp_get(cp) == '*') cp_comment_c(cp); - else if (cp->c == '/') cp_comment_cpp(cp); - else return '/'; - break; - case '|': - if (cp_get(cp) != '|') return '|'; - cp_get(cp); return CTOK_OROR; - case '&': - if (cp_get(cp) != '&') return '&'; - cp_get(cp); return CTOK_ANDAND; - case '=': - if (cp_get(cp) != '=') return '='; - cp_get(cp); return CTOK_EQ; - case '!': - if (cp_get(cp) != '=') return '!'; - cp_get(cp); return CTOK_NE; - case '<': - if (cp_get(cp) == '=') { cp_get(cp); return CTOK_LE; } - else if (cp->c == '<') { cp_get(cp); return CTOK_SHL; } - return '<'; - case '>': - if (cp_get(cp) == '=') { cp_get(cp); return CTOK_GE; } - else if (cp->c == '>') { cp_get(cp); return CTOK_SHR; } - return '>'; - case '-': - if (cp_get(cp) != '>') return '-'; - cp_get(cp); return CTOK_DEREF; - case '$': - return cp_param(cp); - case '\0': return CTOK_EOF; - default: { CPToken c = cp->c; cp_get(cp); return c; } - } - } -} - -static LJ_NOINLINE CPToken cp_next(CPState *cp) -{ - return (cp->tok = cp_next_(cp)); -} - -/* -- C parser ------------------------------------------------------------ */ - -/* Namespaces for resolving identifiers. */ -#define CPNS_DEFAULT \ - ((1u<linenumber = 1; - cp->depth = 0; - cp->curpack = 0; - cp->packstack[0] = 255; - lj_buf_init(cp->L, &cp->sb); - lua_assert(cp->p != NULL); - cp_get(cp); /* Read-ahead first char. */ - cp->tok = 0; - cp->tmask = CPNS_DEFAULT; - cp_next(cp); /* Read-ahead first token. */ -} - -/* Cleanup C parser state. */ -static void cp_cleanup(CPState *cp) -{ - global_State *g = G(cp->L); - lj_buf_free(g, &cp->sb); -} - -/* Check and consume optional token. */ -static int cp_opt(CPState *cp, CPToken tok) -{ - if (cp->tok == tok) { cp_next(cp); return 1; } - return 0; -} - -/* Check and consume token. */ -static void cp_check(CPState *cp, CPToken tok) -{ - if (cp->tok != tok) cp_err_token(cp, tok); - cp_next(cp); -} - -/* Check if the next token may start a type declaration. */ -static int cp_istypedecl(CPState *cp) -{ - if (cp->tok >= CTOK_FIRSTDECL && cp->tok <= CTOK_LASTDECL) return 1; - if (cp->tok == CTOK_IDENT && ctype_istypedef(cp->ct->info)) return 1; - if (cp->tok == '$') return 1; - return 0; -} - -/* -- Constant expression evaluator --------------------------------------- */ - -/* Forward declarations. */ -static void cp_expr_unary(CPState *cp, CPValue *k); -static void cp_expr_sub(CPState *cp, CPValue *k, int pri); - -/* Please note that type handling is very weak here. Most ops simply -** assume integer operands. Accessors are only needed to compute types and -** return synthetic values. The only purpose of the expression evaluator -** is to compute the values of constant expressions one would typically -** find in C header files. And again: this is NOT a validating C parser! -*/ - -/* Parse comma separated expression and return last result. */ -static void cp_expr_comma(CPState *cp, CPValue *k) -{ - do { cp_expr_sub(cp, k, 0); } while (cp_opt(cp, ',')); -} - -/* Parse sizeof/alignof operator. */ -static void cp_expr_sizeof(CPState *cp, CPValue *k, int wantsz) -{ - CTSize sz; - CTInfo info; - if (cp_opt(cp, '(')) { - if (cp_istypedecl(cp)) - k->id = cp_decl_abstract(cp); - else - cp_expr_comma(cp, k); - cp_check(cp, ')'); - } else { - cp_expr_unary(cp, k); - } - info = lj_ctype_info(cp->cts, k->id, &sz); - if (wantsz) { - if (sz != CTSIZE_INVALID) - k->u32 = sz; - else if (k->id != CTID_A_CCHAR) /* Special case for sizeof("string"). */ - cp_err(cp, LJ_ERR_FFI_INVSIZE); - } else { - k->u32 = 1u << ctype_align(info); - } - k->id = CTID_UINT32; /* Really size_t. */ -} - -/* Parse prefix operators. */ -static void cp_expr_prefix(CPState *cp, CPValue *k) -{ - if (cp->tok == CTOK_INTEGER) { - *k = cp->val; cp_next(cp); - } else if (cp_opt(cp, '+')) { - cp_expr_unary(cp, k); /* Nothing to do (well, integer promotion). */ - } else if (cp_opt(cp, '-')) { - cp_expr_unary(cp, k); k->i32 = -k->i32; - } else if (cp_opt(cp, '~')) { - cp_expr_unary(cp, k); k->i32 = ~k->i32; - } else if (cp_opt(cp, '!')) { - cp_expr_unary(cp, k); k->i32 = !k->i32; k->id = CTID_INT32; - } else if (cp_opt(cp, '(')) { - if (cp_istypedecl(cp)) { /* Cast operator. */ - CTypeID id = cp_decl_abstract(cp); - cp_check(cp, ')'); - cp_expr_unary(cp, k); - k->id = id; /* No conversion performed. */ - } else { /* Sub-expression. */ - cp_expr_comma(cp, k); - cp_check(cp, ')'); - } - } else if (cp_opt(cp, '*')) { /* Indirection. */ - CType *ct; - cp_expr_unary(cp, k); - ct = lj_ctype_rawref(cp->cts, k->id); - if (!ctype_ispointer(ct->info)) - cp_err_badidx(cp, ct); - k->u32 = 0; k->id = ctype_cid(ct->info); - } else if (cp_opt(cp, '&')) { /* Address operator. */ - cp_expr_unary(cp, k); - k->id = lj_ctype_intern(cp->cts, CTINFO(CT_PTR, CTALIGN_PTR+k->id), - CTSIZE_PTR); - } else if (cp_opt(cp, CTOK_SIZEOF)) { - cp_expr_sizeof(cp, k, 1); - } else if (cp_opt(cp, CTOK_ALIGNOF)) { - cp_expr_sizeof(cp, k, 0); - } else if (cp->tok == CTOK_IDENT) { - if (ctype_type(cp->ct->info) == CT_CONSTVAL) { - k->u32 = cp->ct->size; k->id = ctype_cid(cp->ct->info); - } else if (ctype_type(cp->ct->info) == CT_EXTERN) { - k->u32 = cp->val.id; k->id = ctype_cid(cp->ct->info); - } else if (ctype_type(cp->ct->info) == CT_FUNC) { - k->u32 = cp->val.id; k->id = cp->val.id; - } else { - goto err_expr; - } - cp_next(cp); - } else if (cp->tok == CTOK_STRING) { - CTSize sz = cp->str->len; - while (cp_next(cp) == CTOK_STRING) - sz += cp->str->len; - k->u32 = sz + 1; - k->id = CTID_A_CCHAR; - } else { - err_expr: - cp_errmsg(cp, cp->tok, LJ_ERR_XSYMBOL); - } -} - -/* Parse postfix operators. */ -static void cp_expr_postfix(CPState *cp, CPValue *k) -{ - for (;;) { - CType *ct; - if (cp_opt(cp, '[')) { /* Array/pointer index. */ - CPValue k2; - cp_expr_comma(cp, &k2); - ct = lj_ctype_rawref(cp->cts, k->id); - if (!ctype_ispointer(ct->info)) { - ct = lj_ctype_rawref(cp->cts, k2.id); - if (!ctype_ispointer(ct->info)) - cp_err_badidx(cp, ct); - } - cp_check(cp, ']'); - k->u32 = 0; - } else if (cp->tok == '.' || cp->tok == CTOK_DEREF) { /* Struct deref. */ - CTSize ofs; - CType *fct; - ct = lj_ctype_rawref(cp->cts, k->id); - if (cp->tok == CTOK_DEREF) { - if (!ctype_ispointer(ct->info)) - cp_err_badidx(cp, ct); - ct = lj_ctype_rawref(cp->cts, ctype_cid(ct->info)); - } - cp_next(cp); - if (cp->tok != CTOK_IDENT) cp_err_token(cp, CTOK_IDENT); - if (!ctype_isstruct(ct->info) || ct->size == CTSIZE_INVALID || - !(fct = lj_ctype_getfield(cp->cts, ct, cp->str, &ofs)) || - ctype_isbitfield(fct->info)) { - GCstr *s = lj_ctype_repr(cp->cts->L, ctype_typeid(cp->cts, ct), NULL); - cp_errmsg(cp, 0, LJ_ERR_FFI_BADMEMBER, strdata(s), strdata(cp->str)); - } - ct = fct; - k->u32 = ctype_isconstval(ct->info) ? ct->size : 0; - cp_next(cp); - } else { - return; - } - k->id = ctype_cid(ct->info); - } -} - -/* Parse infix operators. */ -static void cp_expr_infix(CPState *cp, CPValue *k, int pri) -{ - CPValue k2; - k2.u32 = 0; k2.id = 0; /* Silence the compiler. */ - for (;;) { - switch (pri) { - case 0: - if (cp_opt(cp, '?')) { - CPValue k3; - cp_expr_comma(cp, &k2); /* Right-associative. */ - cp_check(cp, ':'); - cp_expr_sub(cp, &k3, 0); - k->u32 = k->u32 ? k2.u32 : k3.u32; - k->id = k2.id > k3.id ? k2.id : k3.id; - continue; - } - /* fallthrough */ - case 1: - if (cp_opt(cp, CTOK_OROR)) { - cp_expr_sub(cp, &k2, 2); k->i32 = k->u32 || k2.u32; k->id = CTID_INT32; - continue; - } - /* fallthrough */ - case 2: - if (cp_opt(cp, CTOK_ANDAND)) { - cp_expr_sub(cp, &k2, 3); k->i32 = k->u32 && k2.u32; k->id = CTID_INT32; - continue; - } - /* fallthrough */ - case 3: - if (cp_opt(cp, '|')) { - cp_expr_sub(cp, &k2, 4); k->u32 = k->u32 | k2.u32; goto arith_result; - } - /* fallthrough */ - case 4: - if (cp_opt(cp, '^')) { - cp_expr_sub(cp, &k2, 5); k->u32 = k->u32 ^ k2.u32; goto arith_result; - } - /* fallthrough */ - case 5: - if (cp_opt(cp, '&')) { - cp_expr_sub(cp, &k2, 6); k->u32 = k->u32 & k2.u32; goto arith_result; - } - /* fallthrough */ - case 6: - if (cp_opt(cp, CTOK_EQ)) { - cp_expr_sub(cp, &k2, 7); k->i32 = k->u32 == k2.u32; k->id = CTID_INT32; - continue; - } else if (cp_opt(cp, CTOK_NE)) { - cp_expr_sub(cp, &k2, 7); k->i32 = k->u32 != k2.u32; k->id = CTID_INT32; - continue; - } - /* fallthrough */ - case 7: - if (cp_opt(cp, '<')) { - cp_expr_sub(cp, &k2, 8); - if (k->id == CTID_INT32 && k2.id == CTID_INT32) - k->i32 = k->i32 < k2.i32; - else - k->i32 = k->u32 < k2.u32; - k->id = CTID_INT32; - continue; - } else if (cp_opt(cp, '>')) { - cp_expr_sub(cp, &k2, 8); - if (k->id == CTID_INT32 && k2.id == CTID_INT32) - k->i32 = k->i32 > k2.i32; - else - k->i32 = k->u32 > k2.u32; - k->id = CTID_INT32; - continue; - } else if (cp_opt(cp, CTOK_LE)) { - cp_expr_sub(cp, &k2, 8); - if (k->id == CTID_INT32 && k2.id == CTID_INT32) - k->i32 = k->i32 <= k2.i32; - else - k->i32 = k->u32 <= k2.u32; - k->id = CTID_INT32; - continue; - } else if (cp_opt(cp, CTOK_GE)) { - cp_expr_sub(cp, &k2, 8); - if (k->id == CTID_INT32 && k2.id == CTID_INT32) - k->i32 = k->i32 >= k2.i32; - else - k->i32 = k->u32 >= k2.u32; - k->id = CTID_INT32; - continue; - } - /* fallthrough */ - case 8: - if (cp_opt(cp, CTOK_SHL)) { - cp_expr_sub(cp, &k2, 9); k->u32 = k->u32 << k2.u32; - continue; - } else if (cp_opt(cp, CTOK_SHR)) { - cp_expr_sub(cp, &k2, 9); - if (k->id == CTID_INT32) - k->i32 = k->i32 >> k2.i32; - else - k->u32 = k->u32 >> k2.u32; - continue; - } - /* fallthrough */ - case 9: - if (cp_opt(cp, '+')) { - cp_expr_sub(cp, &k2, 10); k->u32 = k->u32 + k2.u32; - arith_result: - if (k2.id > k->id) k->id = k2.id; /* Trivial promotion to unsigned. */ - continue; - } else if (cp_opt(cp, '-')) { - cp_expr_sub(cp, &k2, 10); k->u32 = k->u32 - k2.u32; goto arith_result; - } - /* fallthrough */ - case 10: - if (cp_opt(cp, '*')) { - cp_expr_unary(cp, &k2); k->u32 = k->u32 * k2.u32; goto arith_result; - } else if (cp_opt(cp, '/')) { - cp_expr_unary(cp, &k2); - if (k2.id > k->id) k->id = k2.id; /* Trivial promotion to unsigned. */ - if (k2.u32 == 0 || - (k->id == CTID_INT32 && k->u32 == 0x80000000u && k2.i32 == -1)) - cp_err(cp, LJ_ERR_BADVAL); - if (k->id == CTID_INT32) - k->i32 = k->i32 / k2.i32; - else - k->u32 = k->u32 / k2.u32; - continue; - } else if (cp_opt(cp, '%')) { - cp_expr_unary(cp, &k2); - if (k2.id > k->id) k->id = k2.id; /* Trivial promotion to unsigned. */ - if (k2.u32 == 0 || - (k->id == CTID_INT32 && k->u32 == 0x80000000u && k2.i32 == -1)) - cp_err(cp, LJ_ERR_BADVAL); - if (k->id == CTID_INT32) - k->i32 = k->i32 % k2.i32; - else - k->u32 = k->u32 % k2.u32; - continue; - } - default: - return; - } - } -} - -/* Parse and evaluate unary expression. */ -static void cp_expr_unary(CPState *cp, CPValue *k) -{ - if (++cp->depth > CPARSE_MAX_DECLDEPTH) cp_err(cp, LJ_ERR_XLEVELS); - cp_expr_prefix(cp, k); - cp_expr_postfix(cp, k); - cp->depth--; -} - -/* Parse and evaluate sub-expression. */ -static void cp_expr_sub(CPState *cp, CPValue *k, int pri) -{ - cp_expr_unary(cp, k); - cp_expr_infix(cp, k, pri); -} - -/* Parse constant integer expression. */ -static void cp_expr_kint(CPState *cp, CPValue *k) -{ - CType *ct; - cp_expr_sub(cp, k, 0); - ct = ctype_raw(cp->cts, k->id); - if (!ctype_isinteger(ct->info)) cp_err(cp, LJ_ERR_BADVAL); -} - -/* Parse (non-negative) size expression. */ -static CTSize cp_expr_ksize(CPState *cp) -{ - CPValue k; - cp_expr_kint(cp, &k); - if (k.u32 >= 0x80000000u) cp_err(cp, LJ_ERR_FFI_INVSIZE); - return k.u32; -} - -/* -- Type declaration stack management ----------------------------------- */ - -/* Add declaration element behind the insertion position. */ -static CPDeclIdx cp_add(CPDecl *decl, CTInfo info, CTSize size) -{ - CPDeclIdx top = decl->top; - if (top >= CPARSE_MAX_DECLSTACK) cp_err(decl->cp, LJ_ERR_XLEVELS); - decl->stack[top].info = info; - decl->stack[top].size = size; - decl->stack[top].sib = 0; - setgcrefnull(decl->stack[top].name); - decl->stack[top].next = decl->stack[decl->pos].next; - decl->stack[decl->pos].next = (CTypeID1)top; - decl->top = top+1; - return top; -} - -/* Push declaration element before the insertion position. */ -static CPDeclIdx cp_push(CPDecl *decl, CTInfo info, CTSize size) -{ - return (decl->pos = cp_add(decl, info, size)); -} - -/* Push or merge attributes. */ -static void cp_push_attributes(CPDecl *decl) -{ - CType *ct = &decl->stack[decl->pos]; - if (ctype_isfunc(ct->info)) { /* Ok to modify in-place. */ -#if LJ_TARGET_X86 - if ((decl->fattr & CTFP_CCONV)) - ct->info = (ct->info & (CTMASK_NUM|CTF_VARARG|CTMASK_CID)) + - (decl->fattr & ~CTMASK_CID); -#endif - } else { - if ((decl->attr & CTFP_ALIGNED) && !(decl->mode & CPARSE_MODE_FIELD)) - cp_push(decl, CTINFO(CT_ATTRIB, CTATTRIB(CTA_ALIGN)), - ctype_align(decl->attr)); - } -} - -/* Push unrolled type to declaration stack and merge qualifiers. */ -static void cp_push_type(CPDecl *decl, CTypeID id) -{ - CType *ct = ctype_get(decl->cp->cts, id); - CTInfo info = ct->info; - CTSize size = ct->size; - switch (ctype_type(info)) { - case CT_STRUCT: case CT_ENUM: - cp_push(decl, CTINFO(CT_TYPEDEF, id), 0); /* Don't copy unique types. */ - if ((decl->attr & CTF_QUAL)) { /* Push unmerged qualifiers. */ - cp_push(decl, CTINFO(CT_ATTRIB, CTATTRIB(CTA_QUAL)), - (decl->attr & CTF_QUAL)); - decl->attr &= ~CTF_QUAL; - } - break; - case CT_ATTRIB: - if (ctype_isxattrib(info, CTA_QUAL)) - decl->attr &= ~size; /* Remove redundant qualifiers. */ - cp_push_type(decl, ctype_cid(info)); /* Unroll. */ - cp_push(decl, info & ~CTMASK_CID, size); /* Copy type. */ - break; - case CT_ARRAY: - if ((ct->info & (CTF_VECTOR|CTF_COMPLEX))) { - info |= (decl->attr & CTF_QUAL); - decl->attr &= ~CTF_QUAL; - } - cp_push_type(decl, ctype_cid(info)); /* Unroll. */ - cp_push(decl, info & ~CTMASK_CID, size); /* Copy type. */ - decl->stack[decl->pos].sib = 1; /* Mark as already checked and sized. */ - /* Note: this is not copied to the ct->sib in the C type table. */ - break; - case CT_FUNC: - /* Copy type, link parameters (shared). */ - decl->stack[cp_push(decl, info, size)].sib = ct->sib; - break; - default: - /* Copy type, merge common qualifiers. */ - cp_push(decl, info|(decl->attr & CTF_QUAL), size); - decl->attr &= ~CTF_QUAL; - break; - } -} - -/* Consume the declaration element chain and intern the C type. */ -static CTypeID cp_decl_intern(CPState *cp, CPDecl *decl) -{ - CTypeID id = 0; - CPDeclIdx idx = 0; - CTSize csize = CTSIZE_INVALID; - CTSize cinfo = 0; - do { - CType *ct = &decl->stack[idx]; - CTInfo info = ct->info; - CTInfo size = ct->size; - /* The cid is already part of info for copies of pointers/functions. */ - idx = ct->next; - if (ctype_istypedef(info)) { - lua_assert(id == 0); - id = ctype_cid(info); - /* Always refetch info/size, since struct/enum may have been completed. */ - cinfo = ctype_get(cp->cts, id)->info; - csize = ctype_get(cp->cts, id)->size; - lua_assert(ctype_isstruct(cinfo) || ctype_isenum(cinfo)); - } else if (ctype_isfunc(info)) { /* Intern function. */ - CType *fct; - CTypeID fid; - CTypeID sib; - if (id) { - CType *refct = ctype_raw(cp->cts, id); - /* Reject function or refarray return types. */ - if (ctype_isfunc(refct->info) || ctype_isrefarray(refct->info)) - cp_err(cp, LJ_ERR_FFI_INVTYPE); - } - /* No intervening attributes allowed, skip forward. */ - while (idx) { - CType *ctn = &decl->stack[idx]; - if (!ctype_isattrib(ctn->info)) break; - idx = ctn->next; /* Skip attribute. */ - } - sib = ct->sib; /* Next line may reallocate the C type table. */ - fid = lj_ctype_new(cp->cts, &fct); - csize = CTSIZE_INVALID; - fct->info = cinfo = info + id; - fct->size = size; - fct->sib = sib; - id = fid; - } else if (ctype_isattrib(info)) { - if (ctype_isxattrib(info, CTA_QUAL)) - cinfo |= size; - else if (ctype_isxattrib(info, CTA_ALIGN)) - CTF_INSERT(cinfo, ALIGN, size); - id = lj_ctype_intern(cp->cts, info+id, size); - /* Inherit csize/cinfo from original type. */ - } else { - if (ctype_isnum(info)) { /* Handle mode/vector-size attributes. */ - lua_assert(id == 0); - if (!(info & CTF_BOOL)) { - CTSize msize = ctype_msizeP(decl->attr); - CTSize vsize = ctype_vsizeP(decl->attr); - if (msize && (!(info & CTF_FP) || (msize == 4 || msize == 8))) { - CTSize malign = lj_fls(msize); - if (malign > 4) malign = 4; /* Limit alignment. */ - CTF_INSERT(info, ALIGN, malign); - size = msize; /* Override size via mode. */ - } - if (vsize) { /* Vector size set? */ - CTSize esize = lj_fls(size); - if (vsize >= esize) { - /* Intern the element type first. */ - id = lj_ctype_intern(cp->cts, info, size); - /* Then create a vector (array) with vsize alignment. */ - size = (1u << vsize); - if (vsize > 4) vsize = 4; /* Limit alignment. */ - if (ctype_align(info) > vsize) vsize = ctype_align(info); - info = CTINFO(CT_ARRAY, (info & CTF_QUAL) + CTF_VECTOR + - CTALIGN(vsize)); - } - } - } - } else if (ctype_isptr(info)) { - /* Reject pointer/ref to ref. */ - if (id && ctype_isref(ctype_raw(cp->cts, id)->info)) - cp_err(cp, LJ_ERR_FFI_INVTYPE); - if (ctype_isref(info)) { - info &= ~CTF_VOLATILE; /* Refs are always const, never volatile. */ - /* No intervening attributes allowed, skip forward. */ - while (idx) { - CType *ctn = &decl->stack[idx]; - if (!ctype_isattrib(ctn->info)) break; - idx = ctn->next; /* Skip attribute. */ - } - } - } else if (ctype_isarray(info)) { /* Check for valid array size etc. */ - if (ct->sib == 0) { /* Only check/size arrays not copied by unroll. */ - if (ctype_isref(cinfo)) /* Reject arrays of refs. */ - cp_err(cp, LJ_ERR_FFI_INVTYPE); - /* Reject VLS or unknown-sized types. */ - if (ctype_isvltype(cinfo) || csize == CTSIZE_INVALID) - cp_err(cp, LJ_ERR_FFI_INVSIZE); - /* a[] and a[?] keep their invalid size. */ - if (size != CTSIZE_INVALID) { - uint64_t xsz = (uint64_t)size * csize; - if (xsz >= 0x80000000u) cp_err(cp, LJ_ERR_FFI_INVSIZE); - size = (CTSize)xsz; - } - } - if ((cinfo & CTF_ALIGN) > (info & CTF_ALIGN)) /* Find max. align. */ - info = (info & ~CTF_ALIGN) | (cinfo & CTF_ALIGN); - info |= (cinfo & CTF_QUAL); /* Inherit qual. */ - } else { - lua_assert(ctype_isvoid(info)); - } - csize = size; - cinfo = info+id; - id = lj_ctype_intern(cp->cts, info+id, size); - } - } while (idx); - return id; -} - -/* -- C declaration parser ------------------------------------------------ */ - -#define H_(le, be) LJ_ENDIAN_SELECT(0x##le, 0x##be) - -/* Reset declaration state to declaration specifier. */ -static void cp_decl_reset(CPDecl *decl) -{ - decl->pos = decl->specpos; - decl->top = decl->specpos+1; - decl->stack[decl->specpos].next = 0; - decl->attr = decl->specattr; - decl->fattr = decl->specfattr; - decl->name = NULL; - decl->redir = NULL; -} - -/* Parse constant initializer. */ -/* NYI: FP constants and strings as initializers. */ -static CTypeID cp_decl_constinit(CPState *cp, CType **ctp, CTypeID ctypeid) -{ - CType *ctt = ctype_get(cp->cts, ctypeid); - CTInfo info; - CTSize size; - CPValue k; - CTypeID constid; - while (ctype_isattrib(ctt->info)) { /* Skip attributes. */ - ctypeid = ctype_cid(ctt->info); /* Update ID, too. */ - ctt = ctype_get(cp->cts, ctypeid); - } - info = ctt->info; - size = ctt->size; - if (!ctype_isinteger(info) || !(info & CTF_CONST) || size > 4) - cp_err(cp, LJ_ERR_FFI_INVTYPE); - cp_check(cp, '='); - cp_expr_sub(cp, &k, 0); - constid = lj_ctype_new(cp->cts, ctp); - (*ctp)->info = CTINFO(CT_CONSTVAL, CTF_CONST|ctypeid); - k.u32 <<= 8*(4-size); - if ((info & CTF_UNSIGNED)) - k.u32 >>= 8*(4-size); - else - k.u32 = (uint32_t)((int32_t)k.u32 >> 8*(4-size)); - (*ctp)->size = k.u32; - return constid; -} - -/* Parse size in parentheses as part of attribute. */ -static CTSize cp_decl_sizeattr(CPState *cp) -{ - CTSize sz; - uint32_t oldtmask = cp->tmask; - cp->tmask = CPNS_DEFAULT; /* Required for expression evaluator. */ - cp_check(cp, '('); - sz = cp_expr_ksize(cp); - cp->tmask = oldtmask; - cp_check(cp, ')'); - return sz; -} - -/* Parse alignment attribute. */ -static void cp_decl_align(CPState *cp, CPDecl *decl) -{ - CTSize al = 4; /* Unspecified alignment is 16 bytes. */ - if (cp->tok == '(') { - al = cp_decl_sizeattr(cp); - al = al ? lj_fls(al) : 0; - } - CTF_INSERT(decl->attr, ALIGN, al); - decl->attr |= CTFP_ALIGNED; -} - -/* Parse GCC asm("name") redirect. */ -static void cp_decl_asm(CPState *cp, CPDecl *decl) -{ - UNUSED(decl); - cp_next(cp); - cp_check(cp, '('); - if (cp->tok == CTOK_STRING) { - GCstr *str = cp->str; - while (cp_next(cp) == CTOK_STRING) { - lj_strfmt_pushf(cp->L, "%s%s", strdata(str), strdata(cp->str)); - cp->L->top--; - str = strV(cp->L->top); - } - decl->redir = str; - } - cp_check(cp, ')'); -} - -/* Parse GCC __attribute__((mode(...))). */ -static void cp_decl_mode(CPState *cp, CPDecl *decl) -{ - cp_check(cp, '('); - if (cp->tok == CTOK_IDENT) { - const char *s = strdata(cp->str); - CTSize sz = 0, vlen = 0; - if (s[0] == '_' && s[1] == '_') s += 2; - if (*s == 'V') { - s++; - vlen = *s++ - '0'; - if (*s >= '0' && *s <= '9') - vlen = vlen*10 + (*s++ - '0'); - } - switch (*s++) { - case 'Q': sz = 1; break; - case 'H': sz = 2; break; - case 'S': sz = 4; break; - case 'D': sz = 8; break; - case 'T': sz = 16; break; - case 'O': sz = 32; break; - default: goto bad_size; - } - if (*s == 'I' || *s == 'F') { - CTF_INSERT(decl->attr, MSIZEP, sz); - if (vlen) CTF_INSERT(decl->attr, VSIZEP, lj_fls(vlen*sz)); - } - bad_size: - cp_next(cp); - } - cp_check(cp, ')'); -} - -/* Parse GCC __attribute__((...)). */ -static void cp_decl_gccattribute(CPState *cp, CPDecl *decl) -{ - cp_next(cp); - cp_check(cp, '('); - cp_check(cp, '('); - while (cp->tok != ')') { - if (cp->tok == CTOK_IDENT) { - GCstr *attrstr = cp->str; - cp_next(cp); - switch (attrstr->hash) { - case H_(64a9208e,8ce14319): case H_(8e6331b2,95a282af): /* aligned */ - cp_decl_align(cp, decl); - break; - case H_(42eb47de,f0ede26c): case H_(29f48a09,cf383e0c): /* packed */ - decl->attr |= CTFP_PACKED; - break; - case H_(0a84eef6,8dfab04c): case H_(995cf92c,d5696591): /* mode */ - cp_decl_mode(cp, decl); - break; - case H_(0ab31997,2d5213fa): case H_(bf875611,200e9990): /* vector_size */ - { - CTSize vsize = cp_decl_sizeattr(cp); - if (vsize) CTF_INSERT(decl->attr, VSIZEP, lj_fls(vsize)); - } - break; -#if LJ_TARGET_X86 - case H_(5ad22db8,c689b848): case H_(439150fa,65ea78cb): /* regparm */ - CTF_INSERT(decl->fattr, REGPARM, cp_decl_sizeattr(cp)); - decl->fattr |= CTFP_CCONV; - break; - case H_(18fc0b98,7ff4c074): case H_(4e62abed,0a747424): /* cdecl */ - CTF_INSERT(decl->fattr, CCONV, CTCC_CDECL); - decl->fattr |= CTFP_CCONV; - break; - case H_(72b2e41b,494c5a44): case H_(f2356d59,f25fc9bd): /* thiscall */ - CTF_INSERT(decl->fattr, CCONV, CTCC_THISCALL); - decl->fattr |= CTFP_CCONV; - break; - case H_(0d0ffc42,ab746f88): case H_(21c54ba1,7f0ca7e3): /* fastcall */ - CTF_INSERT(decl->fattr, CCONV, CTCC_FASTCALL); - decl->fattr |= CTFP_CCONV; - break; - case H_(ef76b040,9412e06a): case H_(de56697b,c750e6e1): /* stdcall */ - CTF_INSERT(decl->fattr, CCONV, CTCC_STDCALL); - decl->fattr |= CTFP_CCONV; - break; - case H_(ea78b622,f234bd8e): case H_(252ffb06,8d50f34b): /* sseregparm */ - decl->fattr |= CTF_SSEREGPARM; - decl->fattr |= CTFP_CCONV; - break; -#endif - default: /* Skip all other attributes. */ - goto skip_attr; - } - } else if (cp->tok >= CTOK_FIRSTDECL) { /* For __attribute((const)) etc. */ - cp_next(cp); - skip_attr: - if (cp_opt(cp, '(')) { - while (cp->tok != ')' && cp->tok != CTOK_EOF) cp_next(cp); - cp_check(cp, ')'); - } - } else { - break; - } - if (!cp_opt(cp, ',')) break; - } - cp_check(cp, ')'); - cp_check(cp, ')'); -} - -/* Parse MSVC __declspec(...). */ -static void cp_decl_msvcattribute(CPState *cp, CPDecl *decl) -{ - cp_next(cp); - cp_check(cp, '('); - while (cp->tok == CTOK_IDENT) { - GCstr *attrstr = cp->str; - cp_next(cp); - switch (attrstr->hash) { - case H_(bc2395fa,98f267f8): /* align */ - cp_decl_align(cp, decl); - break; - default: /* Ignore all other attributes. */ - if (cp_opt(cp, '(')) { - while (cp->tok != ')' && cp->tok != CTOK_EOF) cp_next(cp); - cp_check(cp, ')'); - } - break; - } - } - cp_check(cp, ')'); -} - -/* Parse declaration attributes (and common qualifiers). */ -static void cp_decl_attributes(CPState *cp, CPDecl *decl) -{ - for (;;) { - switch (cp->tok) { - case CTOK_CONST: decl->attr |= CTF_CONST; break; - case CTOK_VOLATILE: decl->attr |= CTF_VOLATILE; break; - case CTOK_RESTRICT: break; /* Ignore. */ - case CTOK_EXTENSION: break; /* Ignore. */ - case CTOK_ATTRIBUTE: cp_decl_gccattribute(cp, decl); continue; - case CTOK_ASM: cp_decl_asm(cp, decl); continue; - case CTOK_DECLSPEC: cp_decl_msvcattribute(cp, decl); continue; - case CTOK_CCDECL: -#if LJ_TARGET_X86 - CTF_INSERT(decl->fattr, CCONV, cp->ct->size); - decl->fattr |= CTFP_CCONV; -#endif - break; - case CTOK_PTRSZ: -#if LJ_64 - CTF_INSERT(decl->attr, MSIZEP, cp->ct->size); -#endif - break; - default: return; - } - cp_next(cp); - } -} - -/* Parse struct/union/enum name. */ -static CTypeID cp_struct_name(CPState *cp, CPDecl *sdecl, CTInfo info) -{ - CTypeID sid; - CType *ct; - cp->tmask = CPNS_STRUCT; - cp_next(cp); - cp_decl_attributes(cp, sdecl); - cp->tmask = CPNS_DEFAULT; - if (cp->tok != '{') { - if (cp->tok != CTOK_IDENT) cp_err_token(cp, CTOK_IDENT); - if (cp->val.id) { /* Name of existing struct/union/enum. */ - sid = cp->val.id; - ct = cp->ct; - if ((ct->info ^ info) & (CTMASK_NUM|CTF_UNION)) /* Wrong type. */ - cp_errmsg(cp, 0, LJ_ERR_FFI_REDEF, strdata(gco2str(gcref(ct->name)))); - } else { /* Create named, incomplete struct/union/enum. */ - if ((cp->mode & CPARSE_MODE_NOIMPLICIT)) - cp_errmsg(cp, 0, LJ_ERR_FFI_BADTAG, strdata(cp->str)); - sid = lj_ctype_new(cp->cts, &ct); - ct->info = info; - ct->size = CTSIZE_INVALID; - ctype_setname(ct, cp->str); - lj_ctype_addname(cp->cts, ct, sid); - } - cp_next(cp); - } else { /* Create anonymous, incomplete struct/union/enum. */ - sid = lj_ctype_new(cp->cts, &ct); - ct->info = info; - ct->size = CTSIZE_INVALID; - } - if (cp->tok == '{') { - if (ct->size != CTSIZE_INVALID || ct->sib) - cp_errmsg(cp, 0, LJ_ERR_FFI_REDEF, strdata(gco2str(gcref(ct->name)))); - ct->sib = 1; /* Indicate the type is currently being defined. */ - } - return sid; -} - -/* Determine field alignment. */ -static CTSize cp_field_align(CPState *cp, CType *ct, CTInfo info) -{ - CTSize align = ctype_align(info); - UNUSED(cp); UNUSED(ct); -#if (LJ_TARGET_X86 && !LJ_ABI_WIN) || (LJ_TARGET_ARM && __APPLE__) - /* The SYSV i386 and iOS ABIs limit alignment of non-vector fields to 2^2. */ - if (align > 2 && !(info & CTFP_ALIGNED)) { - if (ctype_isarray(info) && !(info & CTF_VECTOR)) { - do { - ct = ctype_rawchild(cp->cts, ct); - info = ct->info; - } while (ctype_isarray(info) && !(info & CTF_VECTOR)); - } - if (ctype_isnum(info) || ctype_isenum(info)) - align = 2; - } -#endif - return align; -} - -/* Layout struct/union fields. */ -static void cp_struct_layout(CPState *cp, CTypeID sid, CTInfo sattr) -{ - CTSize bofs = 0, bmaxofs = 0; /* Bit offset and max. bit offset. */ - CTSize maxalign = ctype_align(sattr); - CType *sct = ctype_get(cp->cts, sid); - CTInfo sinfo = sct->info; - CTypeID fieldid = sct->sib; - while (fieldid) { - CType *ct = ctype_get(cp->cts, fieldid); - CTInfo attr = ct->size; /* Field declaration attributes (temp.). */ - - if (ctype_isfield(ct->info) || - (ctype_isxattrib(ct->info, CTA_SUBTYPE) && attr)) { - CTSize align, amask; /* Alignment (pow2) and alignment mask (bits). */ - CTSize sz; - CTInfo info = lj_ctype_info(cp->cts, ctype_cid(ct->info), &sz); - CTSize bsz, csz = 8*sz; /* Field size and container size (in bits). */ - sinfo |= (info & (CTF_QUAL|CTF_VLA)); /* Merge pseudo-qualifiers. */ - - /* Check for size overflow and determine alignment. */ - if (sz >= 0x20000000u || bofs + csz < bofs || (info & CTF_VLA)) { - if (!(sz == CTSIZE_INVALID && ctype_isarray(info) && - !(sinfo & CTF_UNION))) - cp_err(cp, LJ_ERR_FFI_INVSIZE); - csz = sz = 0; /* Treat a[] and a[?] as zero-sized. */ - } - align = cp_field_align(cp, ct, info); - if (((attr|sattr) & CTFP_PACKED) || - ((attr & CTFP_ALIGNED) && ctype_align(attr) > align)) - align = ctype_align(attr); - if (cp->packstack[cp->curpack] < align) - align = cp->packstack[cp->curpack]; - if (align > maxalign) maxalign = align; - amask = (8u << align) - 1; - - bsz = ctype_bitcsz(ct->info); /* Bitfield size (temp.). */ - if (bsz == CTBSZ_FIELD || !ctype_isfield(ct->info)) { - bsz = csz; /* Regular fields or subtypes always fill the container. */ - bofs = (bofs + amask) & ~amask; /* Start new aligned field. */ - ct->size = (bofs >> 3); /* Store field offset. */ - } else { /* Bitfield. */ - if (bsz == 0 || (attr & CTFP_ALIGNED) || - (!((attr|sattr) & CTFP_PACKED) && (bofs & amask) + bsz > csz)) - bofs = (bofs + amask) & ~amask; /* Start new aligned field. */ - - /* Prefer regular field over bitfield. */ - if (bsz == csz && (bofs & amask) == 0) { - ct->info = CTINFO(CT_FIELD, ctype_cid(ct->info)); - ct->size = (bofs >> 3); /* Store field offset. */ - } else { - ct->info = CTINFO(CT_BITFIELD, - (info & (CTF_QUAL|CTF_UNSIGNED|CTF_BOOL)) + - (csz << (CTSHIFT_BITCSZ-3)) + (bsz << CTSHIFT_BITBSZ)); -#if LJ_BE - ct->info += ((csz - (bofs & (csz-1)) - bsz) << CTSHIFT_BITPOS); -#else - ct->info += ((bofs & (csz-1)) << CTSHIFT_BITPOS); -#endif - ct->size = ((bofs & ~(csz-1)) >> 3); /* Store container offset. */ - } - } - - /* Determine next offset or max. offset. */ - if ((sinfo & CTF_UNION)) { - if (bsz > bmaxofs) bmaxofs = bsz; - } else { - bofs += bsz; - } - } /* All other fields in the chain are already set up. */ - - fieldid = ct->sib; - } - - /* Complete struct/union. */ - sct->info = sinfo + CTALIGN(maxalign); - bofs = (sinfo & CTF_UNION) ? bmaxofs : bofs; - maxalign = (8u << maxalign) - 1; - sct->size = (((bofs + maxalign) & ~maxalign) >> 3); -} - -/* Parse struct/union declaration. */ -static CTypeID cp_decl_struct(CPState *cp, CPDecl *sdecl, CTInfo sinfo) -{ - CTypeID sid = cp_struct_name(cp, sdecl, sinfo); - if (cp_opt(cp, '{')) { /* Struct/union definition. */ - CTypeID lastid = sid; - int lastdecl = 0; - while (cp->tok != '}') { - CPDecl decl; - CPscl scl = cp_decl_spec(cp, &decl, CDF_STATIC); - decl.mode = scl ? CPARSE_MODE_DIRECT : - CPARSE_MODE_DIRECT|CPARSE_MODE_ABSTRACT|CPARSE_MODE_FIELD; - - for (;;) { - CTypeID ctypeid; - - if (lastdecl) cp_err_token(cp, '}'); - - /* Parse field declarator. */ - decl.bits = CTSIZE_INVALID; - cp_declarator(cp, &decl); - ctypeid = cp_decl_intern(cp, &decl); - - if ((scl & CDF_STATIC)) { /* Static constant in struct namespace. */ - CType *ct; - CTypeID fieldid = cp_decl_constinit(cp, &ct, ctypeid); - ctype_get(cp->cts, lastid)->sib = fieldid; - lastid = fieldid; - ctype_setname(ct, decl.name); - } else { - CTSize bsz = CTBSZ_FIELD; /* Temp. for layout phase. */ - CType *ct; - CTypeID fieldid = lj_ctype_new(cp->cts, &ct); /* Do this first. */ - CType *tct = ctype_raw(cp->cts, ctypeid); - - if (decl.bits == CTSIZE_INVALID) { /* Regular field. */ - if (ctype_isarray(tct->info) && tct->size == CTSIZE_INVALID) - lastdecl = 1; /* a[] or a[?] must be the last declared field. */ - - /* Accept transparent struct/union/enum. */ - if (!decl.name) { - if (!((ctype_isstruct(tct->info) && !(tct->info & CTF_VLA)) || - ctype_isenum(tct->info))) - cp_err_token(cp, CTOK_IDENT); - ct->info = CTINFO(CT_ATTRIB, CTATTRIB(CTA_SUBTYPE) + ctypeid); - ct->size = ctype_isstruct(tct->info) ? - (decl.attr|0x80000000u) : 0; /* For layout phase. */ - goto add_field; - } - } else { /* Bitfield. */ - bsz = decl.bits; - if (!ctype_isinteger_or_bool(tct->info) || - (bsz == 0 && decl.name) || 8*tct->size > CTBSZ_MAX || - bsz > ((tct->info & CTF_BOOL) ? 1 : 8*tct->size)) - cp_errmsg(cp, ':', LJ_ERR_BADVAL); - } - - /* Create temporary field for layout phase. */ - ct->info = CTINFO(CT_FIELD, ctypeid + (bsz << CTSHIFT_BITCSZ)); - ct->size = decl.attr; - if (decl.name) ctype_setname(ct, decl.name); - - add_field: - ctype_get(cp->cts, lastid)->sib = fieldid; - lastid = fieldid; - } - if (!cp_opt(cp, ',')) break; - cp_decl_reset(&decl); - } - cp_check(cp, ';'); - } - cp_check(cp, '}'); - ctype_get(cp->cts, lastid)->sib = 0; /* Drop sib = 1 for empty structs. */ - cp_decl_attributes(cp, sdecl); /* Layout phase needs postfix attributes. */ - cp_struct_layout(cp, sid, sdecl->attr); - } - return sid; -} - -/* Parse enum declaration. */ -static CTypeID cp_decl_enum(CPState *cp, CPDecl *sdecl) -{ - CTypeID eid = cp_struct_name(cp, sdecl, CTINFO(CT_ENUM, CTID_VOID)); - CTInfo einfo = CTINFO(CT_ENUM, CTALIGN(2) + CTID_UINT32); - CTSize esize = 4; /* Only 32 bit enums are supported. */ - if (cp_opt(cp, '{')) { /* Enum definition. */ - CPValue k; - CTypeID lastid = eid; - k.u32 = 0; - k.id = CTID_INT32; - do { - GCstr *name = cp->str; - if (cp->tok != CTOK_IDENT) cp_err_token(cp, CTOK_IDENT); - if (cp->val.id) cp_errmsg(cp, 0, LJ_ERR_FFI_REDEF, strdata(name)); - cp_next(cp); - if (cp_opt(cp, '=')) { - cp_expr_kint(cp, &k); - if (k.id == CTID_UINT32) { - /* C99 says that enum constants are always (signed) integers. - ** But since unsigned constants like 0x80000000 are quite common, - ** those are left as uint32_t. - */ - if (k.i32 >= 0) k.id = CTID_INT32; - } else { - /* OTOH it's common practice and even mandated by some ABIs - ** that the enum type itself is unsigned, unless there are any - ** negative constants. - */ - k.id = CTID_INT32; - if (k.i32 < 0) einfo = CTINFO(CT_ENUM, CTALIGN(2) + CTID_INT32); - } - } - /* Add named enum constant. */ - { - CType *ct; - CTypeID constid = lj_ctype_new(cp->cts, &ct); - ctype_get(cp->cts, lastid)->sib = constid; - lastid = constid; - ctype_setname(ct, name); - ct->info = CTINFO(CT_CONSTVAL, CTF_CONST|k.id); - ct->size = k.u32++; - if (k.u32 == 0x80000000u) k.id = CTID_UINT32; - lj_ctype_addname(cp->cts, ct, constid); - } - if (!cp_opt(cp, ',')) break; - } while (cp->tok != '}'); /* Trailing ',' is ok. */ - cp_check(cp, '}'); - /* Complete enum. */ - ctype_get(cp->cts, eid)->info = einfo; - ctype_get(cp->cts, eid)->size = esize; - } - return eid; -} - -/* Parse declaration specifiers. */ -static CPscl cp_decl_spec(CPState *cp, CPDecl *decl, CPscl scl) -{ - uint32_t cds = 0, sz = 0; - CTypeID tdef = 0; - - decl->cp = cp; - decl->mode = cp->mode; - decl->name = NULL; - decl->redir = NULL; - decl->attr = 0; - decl->fattr = 0; - decl->pos = decl->top = 0; - decl->stack[0].next = 0; - - for (;;) { /* Parse basic types. */ - cp_decl_attributes(cp, decl); - if (cp->tok >= CTOK_FIRSTDECL && cp->tok <= CTOK_LASTDECLFLAG) { - uint32_t cbit; - if (cp->ct->size) { - if (sz) goto end_decl; - sz = cp->ct->size; - } - cbit = (1u << (cp->tok - CTOK_FIRSTDECL)); - cds = cds | cbit | ((cbit & cds & CDF_LONG) << 1); - if (cp->tok >= CTOK_FIRSTSCL) { - if (!(scl & cbit)) cp_errmsg(cp, cp->tok, LJ_ERR_FFI_BADSCL); - } else if (tdef) { - goto end_decl; - } - cp_next(cp); - continue; - } - if (sz || tdef || - (cds & (CDF_SHORT|CDF_LONG|CDF_SIGNED|CDF_UNSIGNED|CDF_COMPLEX))) - break; - switch (cp->tok) { - case CTOK_STRUCT: - tdef = cp_decl_struct(cp, decl, CTINFO(CT_STRUCT, 0)); - continue; - case CTOK_UNION: - tdef = cp_decl_struct(cp, decl, CTINFO(CT_STRUCT, CTF_UNION)); - continue; - case CTOK_ENUM: - tdef = cp_decl_enum(cp, decl); - continue; - case CTOK_IDENT: - if (ctype_istypedef(cp->ct->info)) { - tdef = ctype_cid(cp->ct->info); /* Get typedef. */ - cp_next(cp); - continue; - } - break; - case '$': - tdef = cp->val.id; - cp_next(cp); - continue; - default: - break; - } - break; - } -end_decl: - - if ((cds & CDF_COMPLEX)) /* Use predefined complex types. */ - tdef = sz == 4 ? CTID_COMPLEX_FLOAT : CTID_COMPLEX_DOUBLE; - - if (tdef) { - cp_push_type(decl, tdef); - } else if ((cds & CDF_VOID)) { - cp_push(decl, CTINFO(CT_VOID, (decl->attr & CTF_QUAL)), CTSIZE_INVALID); - decl->attr &= ~CTF_QUAL; - } else { - /* Determine type info and size. */ - CTInfo info = CTINFO(CT_NUM, (cds & CDF_UNSIGNED) ? CTF_UNSIGNED : 0); - if ((cds & CDF_BOOL)) { - if ((cds & ~(CDF_SCL|CDF_BOOL|CDF_INT|CDF_SIGNED|CDF_UNSIGNED))) - cp_errmsg(cp, 0, LJ_ERR_FFI_INVTYPE); - info |= CTF_BOOL; - if (!(cds & CDF_SIGNED)) info |= CTF_UNSIGNED; - if (!sz) { - sz = 1; - } - } else if ((cds & CDF_FP)) { - info = CTINFO(CT_NUM, CTF_FP); - if ((cds & CDF_LONG)) sz = sizeof(long double); - } else if ((cds & CDF_CHAR)) { - if ((cds & (CDF_CHAR|CDF_SIGNED|CDF_UNSIGNED)) == CDF_CHAR) - info |= CTF_UCHAR; /* Handle platforms where char is unsigned. */ - } else if ((cds & CDF_SHORT)) { - sz = sizeof(short); - } else if ((cds & CDF_LONGLONG)) { - sz = 8; - } else if ((cds & CDF_LONG)) { - info |= CTF_LONG; - sz = sizeof(long); - } else if (!sz) { - if (!(cds & (CDF_SIGNED|CDF_UNSIGNED))) - cp_errmsg(cp, cp->tok, LJ_ERR_FFI_DECLSPEC); - sz = sizeof(int); - } - lua_assert(sz != 0); - info += CTALIGN(lj_fls(sz)); /* Use natural alignment. */ - info += (decl->attr & CTF_QUAL); /* Merge qualifiers. */ - cp_push(decl, info, sz); - decl->attr &= ~CTF_QUAL; - } - decl->specpos = decl->pos; - decl->specattr = decl->attr; - decl->specfattr = decl->fattr; - return (cds & CDF_SCL); /* Return storage class. */ -} - -/* Parse array declaration. */ -static void cp_decl_array(CPState *cp, CPDecl *decl) -{ - CTInfo info = CTINFO(CT_ARRAY, 0); - CTSize nelem = CTSIZE_INVALID; /* Default size for a[] or a[?]. */ - cp_decl_attributes(cp, decl); - if (cp_opt(cp, '?')) - info |= CTF_VLA; /* Create variable-length array a[?]. */ - else if (cp->tok != ']') - nelem = cp_expr_ksize(cp); - cp_check(cp, ']'); - cp_add(decl, info, nelem); -} - -/* Parse function declaration. */ -static void cp_decl_func(CPState *cp, CPDecl *fdecl) -{ - CTSize nargs = 0; - CTInfo info = CTINFO(CT_FUNC, 0); - CTypeID lastid = 0, anchor = 0; - if (cp->tok != ')') { - do { - CPDecl decl; - CTypeID ctypeid, fieldid; - CType *ct; - if (cp_opt(cp, '.')) { /* Vararg function. */ - cp_check(cp, '.'); /* Workaround for the minimalistic lexer. */ - cp_check(cp, '.'); - info |= CTF_VARARG; - break; - } - cp_decl_spec(cp, &decl, CDF_REGISTER); - decl.mode = CPARSE_MODE_DIRECT|CPARSE_MODE_ABSTRACT; - cp_declarator(cp, &decl); - ctypeid = cp_decl_intern(cp, &decl); - ct = ctype_raw(cp->cts, ctypeid); - if (ctype_isvoid(ct->info)) - break; - else if (ctype_isrefarray(ct->info)) - ctypeid = lj_ctype_intern(cp->cts, - CTINFO(CT_PTR, CTALIGN_PTR|ctype_cid(ct->info)), CTSIZE_PTR); - else if (ctype_isfunc(ct->info)) - ctypeid = lj_ctype_intern(cp->cts, - CTINFO(CT_PTR, CTALIGN_PTR|ctypeid), CTSIZE_PTR); - /* Add new parameter. */ - fieldid = lj_ctype_new(cp->cts, &ct); - if (anchor) - ctype_get(cp->cts, lastid)->sib = fieldid; - else - anchor = fieldid; - lastid = fieldid; - if (decl.name) ctype_setname(ct, decl.name); - ct->info = CTINFO(CT_FIELD, ctypeid); - ct->size = nargs++; - } while (cp_opt(cp, ',')); - } - cp_check(cp, ')'); - if (cp_opt(cp, '{')) { /* Skip function definition. */ - int level = 1; - cp->mode |= CPARSE_MODE_SKIP; - for (;;) { - if (cp->tok == '{') level++; - else if (cp->tok == '}' && --level == 0) break; - else if (cp->tok == CTOK_EOF) cp_err_token(cp, '}'); - cp_next(cp); - } - cp->mode &= ~CPARSE_MODE_SKIP; - cp->tok = ';'; /* Ok for cp_decl_multi(), error in cp_decl_single(). */ - } - info |= (fdecl->fattr & ~CTMASK_CID); - fdecl->fattr = 0; - fdecl->stack[cp_add(fdecl, info, nargs)].sib = anchor; -} - -/* Parse declarator. */ -static void cp_declarator(CPState *cp, CPDecl *decl) -{ - if (++cp->depth > CPARSE_MAX_DECLDEPTH) cp_err(cp, LJ_ERR_XLEVELS); - - for (;;) { /* Head of declarator. */ - if (cp_opt(cp, '*')) { /* Pointer. */ - CTSize sz; - CTInfo info; - cp_decl_attributes(cp, decl); - sz = CTSIZE_PTR; - info = CTINFO(CT_PTR, CTALIGN_PTR); -#if LJ_64 - if (ctype_msizeP(decl->attr) == 4) { - sz = 4; - info = CTINFO(CT_PTR, CTALIGN(2)); - } -#endif - info += (decl->attr & (CTF_QUAL|CTF_REF)); - decl->attr &= ~(CTF_QUAL|(CTMASK_MSIZEP<attr &= ~(CTF_QUAL|(CTMASK_MSIZEP<mode & CPARSE_MODE_ABSTRACT) && - (cp->tok == ')' || cp_istypedecl(cp))) goto func_decl; - pos = decl->pos; - cp_declarator(cp, decl); - cp_check(cp, ')'); - decl->pos = pos; - } else if (cp->tok == CTOK_IDENT) { /* Direct declarator. */ - if (!(decl->mode & CPARSE_MODE_DIRECT)) cp_err_token(cp, CTOK_EOF); - decl->name = cp->str; - decl->nameid = cp->val.id; - cp_next(cp); - } else { /* Abstract declarator. */ - if (!(decl->mode & CPARSE_MODE_ABSTRACT)) cp_err_token(cp, CTOK_IDENT); - } - - for (;;) { /* Tail of declarator. */ - if (cp_opt(cp, '[')) { /* Array. */ - cp_decl_array(cp, decl); - } else if (cp_opt(cp, '(')) { /* Function. */ - func_decl: - cp_decl_func(cp, decl); - } else { - break; - } - } - - if ((decl->mode & CPARSE_MODE_FIELD) && cp_opt(cp, ':')) /* Field width. */ - decl->bits = cp_expr_ksize(cp); - - /* Process postfix attributes. */ - cp_decl_attributes(cp, decl); - cp_push_attributes(decl); - - cp->depth--; -} - -/* Parse an abstract type declaration and return it's C type ID. */ -static CTypeID cp_decl_abstract(CPState *cp) -{ - CPDecl decl; - cp_decl_spec(cp, &decl, 0); - decl.mode = CPARSE_MODE_ABSTRACT; - cp_declarator(cp, &decl); - return cp_decl_intern(cp, &decl); -} - -/* Handle pragmas. */ -static void cp_pragma(CPState *cp, BCLine pragmaline) -{ - cp_next(cp); - if (cp->tok == CTOK_IDENT && - cp->str->hash == H_(e79b999f,42ca3e85)) { /* pack */ - cp_next(cp); - cp_check(cp, '('); - if (cp->tok == CTOK_IDENT) { - if (cp->str->hash == H_(738e923c,a1b65954)) { /* push */ - if (cp->curpack < CPARSE_MAX_PACKSTACK) { - cp->packstack[cp->curpack+1] = cp->packstack[cp->curpack]; - cp->curpack++; - } - } else if (cp->str->hash == H_(6c71cf27,6c71cf27)) { /* pop */ - if (cp->curpack > 0) cp->curpack--; - } else { - cp_errmsg(cp, cp->tok, LJ_ERR_XSYMBOL); - } - cp_next(cp); - if (!cp_opt(cp, ',')) goto end_pack; - } - if (cp->tok == CTOK_INTEGER) { - cp->packstack[cp->curpack] = cp->val.u32 ? lj_fls(cp->val.u32) : 0; - cp_next(cp); - } else { - cp->packstack[cp->curpack] = 255; - } - end_pack: - cp_check(cp, ')'); - } else { /* Ignore all other pragmas. */ - while (cp->tok != CTOK_EOF && cp->linenumber == pragmaline) - cp_next(cp); - } -} - -/* Handle line number. */ -static void cp_line(CPState *cp, BCLine hashline) -{ - BCLine newline = cp->val.u32; - /* TODO: Handle file name and include it in error messages. */ - while (cp->tok != CTOK_EOF && cp->linenumber == hashline) - cp_next(cp); - cp->linenumber = newline; -} - -/* Parse multiple C declarations of types or extern identifiers. */ -static void cp_decl_multi(CPState *cp) -{ - int first = 1; - while (cp->tok != CTOK_EOF) { - CPDecl decl; - CPscl scl; - if (cp_opt(cp, ';')) { /* Skip empty statements. */ - first = 0; - continue; - } - if (cp->tok == '#') { /* Workaround, since we have no preprocessor, yet. */ - BCLine hashline = cp->linenumber; - CPToken tok = cp_next(cp); - if (tok == CTOK_INTEGER) { - cp_line(cp, hashline); - continue; - } else if (tok == CTOK_IDENT && - cp->str->hash == H_(187aab88,fcb60b42)) { /* line */ - if (cp_next(cp) != CTOK_INTEGER) cp_err_token(cp, tok); - cp_line(cp, hashline); - continue; - } else if (tok == CTOK_IDENT && - cp->str->hash == H_(f5e6b4f8,1d509107)) { /* pragma */ - cp_pragma(cp, hashline); - continue; - } else { - cp_errmsg(cp, cp->tok, LJ_ERR_XSYMBOL); - } - } - scl = cp_decl_spec(cp, &decl, CDF_TYPEDEF|CDF_EXTERN|CDF_STATIC); - if ((cp->tok == ';' || cp->tok == CTOK_EOF) && - ctype_istypedef(decl.stack[0].info)) { - CTInfo info = ctype_rawchild(cp->cts, &decl.stack[0])->info; - if (ctype_isstruct(info) || ctype_isenum(info)) - goto decl_end; /* Accept empty declaration of struct/union/enum. */ - } - for (;;) { - CTypeID ctypeid; - cp_declarator(cp, &decl); - ctypeid = cp_decl_intern(cp, &decl); - if (decl.name && !decl.nameid) { /* NYI: redeclarations are ignored. */ - CType *ct; - CTypeID id; - if ((scl & CDF_TYPEDEF)) { /* Create new typedef. */ - id = lj_ctype_new(cp->cts, &ct); - ct->info = CTINFO(CT_TYPEDEF, ctypeid); - goto noredir; - } else if (ctype_isfunc(ctype_get(cp->cts, ctypeid)->info)) { - /* Treat both static and extern function declarations as extern. */ - ct = ctype_get(cp->cts, ctypeid); - /* We always get new anonymous functions (typedefs are copied). */ - lua_assert(gcref(ct->name) == NULL); - id = ctypeid; /* Just name it. */ - } else if ((scl & CDF_STATIC)) { /* Accept static constants. */ - id = cp_decl_constinit(cp, &ct, ctypeid); - goto noredir; - } else { /* External references have extern or no storage class. */ - id = lj_ctype_new(cp->cts, &ct); - ct->info = CTINFO(CT_EXTERN, ctypeid); - } - if (decl.redir) { /* Add attribute for redirected symbol name. */ - CType *cta; - CTypeID aid = lj_ctype_new(cp->cts, &cta); - ct = ctype_get(cp->cts, id); /* Table may have been reallocated. */ - cta->info = CTINFO(CT_ATTRIB, CTATTRIB(CTA_REDIR)); - cta->sib = ct->sib; - ct->sib = aid; - ctype_setname(cta, decl.redir); - } - noredir: - ctype_setname(ct, decl.name); - lj_ctype_addname(cp->cts, ct, id); - } - if (!cp_opt(cp, ',')) break; - cp_decl_reset(&decl); - } - decl_end: - if (cp->tok == CTOK_EOF && first) break; /* May omit ';' for 1 decl. */ - first = 0; - cp_check(cp, ';'); - } -} - -/* Parse a single C type declaration. */ -static void cp_decl_single(CPState *cp) -{ - CPDecl decl; - cp_decl_spec(cp, &decl, 0); - cp_declarator(cp, &decl); - cp->val.id = cp_decl_intern(cp, &decl); - if (cp->tok != CTOK_EOF) cp_err_token(cp, CTOK_EOF); -} - -#undef H_ - -/* ------------------------------------------------------------------------ */ - -/* Protected callback for C parser. */ -static TValue *cpcparser(lua_State *L, lua_CFunction dummy, void *ud) -{ - CPState *cp = (CPState *)ud; - UNUSED(dummy); - cframe_errfunc(L->cframe) = -1; /* Inherit error function. */ - cp_init(cp); - if ((cp->mode & CPARSE_MODE_MULTI)) - cp_decl_multi(cp); - else - cp_decl_single(cp); - if (cp->param && cp->param != cp->L->top) - cp_err(cp, LJ_ERR_FFI_NUMPARAM); - lua_assert(cp->depth == 0); - return NULL; -} - -/* C parser. */ -int lj_cparse(CPState *cp) -{ - LJ_CTYPE_SAVE(cp->cts); - int errcode = lj_vm_cpcall(cp->L, NULL, cp, cpcparser); - if (errcode) - LJ_CTYPE_RESTORE(cp->cts); - cp_cleanup(cp); - return errcode; -} - -#endif diff --git a/lib/LuaJIT/src/lj_cparse.h b/lib/LuaJIT/src/lj_cparse.h deleted file mode 100644 index bad1060..0000000 --- a/lib/LuaJIT/src/lj_cparse.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -** C declaration parser. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_CPARSE_H -#define _LJ_CPARSE_H - -#include "lj_obj.h" -#include "lj_ctype.h" - -#if LJ_HASFFI - -/* C parser limits. */ -#define CPARSE_MAX_BUF 32768 /* Max. token buffer size. */ -#define CPARSE_MAX_DECLSTACK 100 /* Max. declaration stack depth. */ -#define CPARSE_MAX_DECLDEPTH 20 /* Max. recursive declaration depth. */ -#define CPARSE_MAX_PACKSTACK 7 /* Max. pack pragma stack depth. */ - -/* Flags for C parser mode. */ -#define CPARSE_MODE_MULTI 1 /* Process multiple declarations. */ -#define CPARSE_MODE_ABSTRACT 2 /* Accept abstract declarators. */ -#define CPARSE_MODE_DIRECT 4 /* Accept direct declarators. */ -#define CPARSE_MODE_FIELD 8 /* Accept field width in bits, too. */ -#define CPARSE_MODE_NOIMPLICIT 16 /* Reject implicit declarations. */ -#define CPARSE_MODE_SKIP 32 /* Skip definitions, ignore errors. */ - -typedef int CPChar; /* C parser character. Unsigned ext. from char. */ -typedef int CPToken; /* C parser token. */ - -/* C parser internal value representation. */ -typedef struct CPValue { - union { - int32_t i32; /* Value for CTID_INT32. */ - uint32_t u32; /* Value for CTID_UINT32. */ - }; - CTypeID id; /* C Type ID of the value. */ -} CPValue; - -/* C parser state. */ -typedef struct CPState { - CPChar c; /* Current character. */ - CPToken tok; /* Current token. */ - CPValue val; /* Token value. */ - GCstr *str; /* Interned string of identifier/keyword. */ - CType *ct; /* C type table entry. */ - const char *p; /* Current position in input buffer. */ - SBuf sb; /* String buffer for tokens. */ - lua_State *L; /* Lua state. */ - CTState *cts; /* C type state. */ - TValue *param; /* C type parameters. */ - const char *srcname; /* Current source name. */ - BCLine linenumber; /* Input line counter. */ - int depth; /* Recursive declaration depth. */ - uint32_t tmask; /* Type mask for next identifier. */ - uint32_t mode; /* C parser mode. */ - uint8_t packstack[CPARSE_MAX_PACKSTACK]; /* Stack for pack pragmas. */ - uint8_t curpack; /* Current position in pack pragma stack. */ -} CPState; - -LJ_FUNC int lj_cparse(CPState *cp); - -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_crecord.c b/lib/LuaJIT/src/lj_crecord.c deleted file mode 100644 index d425686..0000000 --- a/lib/LuaJIT/src/lj_crecord.c +++ /dev/null @@ -1,1892 +0,0 @@ -/* -** Trace recorder for C data operations. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_ffrecord_c -#define LUA_CORE - -#include "lj_obj.h" - -#if LJ_HASJIT && LJ_HASFFI - -#include "lj_err.h" -#include "lj_tab.h" -#include "lj_frame.h" -#include "lj_ctype.h" -#include "lj_cdata.h" -#include "lj_cparse.h" -#include "lj_cconv.h" -#include "lj_carith.h" -#include "lj_clib.h" -#include "lj_ccall.h" -#include "lj_ff.h" -#include "lj_ir.h" -#include "lj_jit.h" -#include "lj_ircall.h" -#include "lj_iropt.h" -#include "lj_trace.h" -#include "lj_record.h" -#include "lj_ffrecord.h" -#include "lj_snap.h" -#include "lj_crecord.h" -#include "lj_dispatch.h" -#include "lj_strfmt.h" - -/* Some local macros to save typing. Undef'd at the end. */ -#define IR(ref) (&J->cur.ir[(ref)]) - -/* Pass IR on to next optimization in chain (FOLD). */ -#define emitir(ot, a, b) (lj_ir_set(J, (ot), (a), (b)), lj_opt_fold(J)) - -#define emitconv(a, dt, st, flags) \ - emitir(IRT(IR_CONV, (dt)), (a), (st)|((dt) << 5)|(flags)) - -/* -- C type checks ------------------------------------------------------- */ - -static GCcdata *argv2cdata(jit_State *J, TRef tr, cTValue *o) -{ - GCcdata *cd; - TRef trtypeid; - if (!tref_iscdata(tr)) - lj_trace_err(J, LJ_TRERR_BADTYPE); - cd = cdataV(o); - /* Specialize to the CTypeID. */ - trtypeid = emitir(IRT(IR_FLOAD, IRT_U16), tr, IRFL_CDATA_CTYPEID); - emitir(IRTG(IR_EQ, IRT_INT), trtypeid, lj_ir_kint(J, (int32_t)cd->ctypeid)); - return cd; -} - -/* Specialize to the CTypeID held by a cdata constructor. */ -static CTypeID crec_constructor(jit_State *J, GCcdata *cd, TRef tr) -{ - CTypeID id; - lua_assert(tref_iscdata(tr) && cd->ctypeid == CTID_CTYPEID); - id = *(CTypeID *)cdataptr(cd); - tr = emitir(IRT(IR_FLOAD, IRT_INT), tr, IRFL_CDATA_INT); - emitir(IRTG(IR_EQ, IRT_INT), tr, lj_ir_kint(J, (int32_t)id)); - return id; -} - -static CTypeID argv2ctype(jit_State *J, TRef tr, cTValue *o) -{ - if (tref_isstr(tr)) { - GCstr *s = strV(o); - CPState cp; - CTypeID oldtop; - /* Specialize to the string containing the C type declaration. */ - emitir(IRTG(IR_EQ, IRT_STR), tr, lj_ir_kstr(J, s)); - cp.L = J->L; - cp.cts = ctype_ctsG(J2G(J)); - oldtop = cp.cts->top; - cp.srcname = strdata(s); - cp.p = strdata(s); - cp.param = NULL; - cp.mode = CPARSE_MODE_ABSTRACT|CPARSE_MODE_NOIMPLICIT; - if (lj_cparse(&cp) || cp.cts->top > oldtop) /* Avoid new struct defs. */ - lj_trace_err(J, LJ_TRERR_BADTYPE); - return cp.val.id; - } else { - GCcdata *cd = argv2cdata(J, tr, o); - return cd->ctypeid == CTID_CTYPEID ? crec_constructor(J, cd, tr) : - cd->ctypeid; - } -} - -/* Convert CType to IRType (if possible). */ -static IRType crec_ct2irt(CTState *cts, CType *ct) -{ - if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct); - if (LJ_LIKELY(ctype_isnum(ct->info))) { - if ((ct->info & CTF_FP)) { - if (ct->size == sizeof(double)) - return IRT_NUM; - else if (ct->size == sizeof(float)) - return IRT_FLOAT; - } else { - uint32_t b = lj_fls(ct->size); - if (b <= 3) - return IRT_I8 + 2*b + ((ct->info & CTF_UNSIGNED) ? 1 : 0); - } - } else if (ctype_isptr(ct->info)) { - return (LJ_64 && ct->size == 8) ? IRT_P64 : IRT_P32; - } else if (ctype_iscomplex(ct->info)) { - if (ct->size == 2*sizeof(double)) - return IRT_NUM; - else if (ct->size == 2*sizeof(float)) - return IRT_FLOAT; - } - return IRT_CDATA; -} - -/* -- Optimized memory fill and copy -------------------------------------- */ - -/* Maximum length and unroll of inlined copy/fill. */ -#define CREC_COPY_MAXUNROLL 16 -#define CREC_COPY_MAXLEN 128 - -#define CREC_FILL_MAXUNROLL 16 - -/* Number of windowed registers used for optimized memory copy. */ -#if LJ_TARGET_X86 -#define CREC_COPY_REGWIN 2 -#elif LJ_TARGET_PPC || LJ_TARGET_MIPS -#define CREC_COPY_REGWIN 8 -#else -#define CREC_COPY_REGWIN 4 -#endif - -/* List of memory offsets for copy/fill. */ -typedef struct CRecMemList { - CTSize ofs; /* Offset in bytes. */ - IRType tp; /* Type of load/store. */ - TRef trofs; /* TRef of interned offset. */ - TRef trval; /* TRef of load value. */ -} CRecMemList; - -/* Generate copy list for element-wise struct copy. */ -static MSize crec_copy_struct(CRecMemList *ml, CTState *cts, CType *ct) -{ - CTypeID fid = ct->sib; - MSize mlp = 0; - while (fid) { - CType *df = ctype_get(cts, fid); - fid = df->sib; - if (ctype_isfield(df->info)) { - CType *cct; - IRType tp; - if (!gcref(df->name)) continue; /* Ignore unnamed fields. */ - cct = ctype_rawchild(cts, df); /* Field type. */ - tp = crec_ct2irt(cts, cct); - if (tp == IRT_CDATA) return 0; /* NYI: aggregates. */ - if (mlp >= CREC_COPY_MAXUNROLL) return 0; - ml[mlp].ofs = df->size; - ml[mlp].tp = tp; - mlp++; - if (ctype_iscomplex(cct->info)) { - if (mlp >= CREC_COPY_MAXUNROLL) return 0; - ml[mlp].ofs = df->size + (cct->size >> 1); - ml[mlp].tp = tp; - mlp++; - } - } else if (!ctype_isconstval(df->info)) { - /* NYI: bitfields and sub-structures. */ - return 0; - } - } - return mlp; -} - -/* Generate unrolled copy list, from highest to lowest step size/alignment. */ -static MSize crec_copy_unroll(CRecMemList *ml, CTSize len, CTSize step, - IRType tp) -{ - CTSize ofs = 0; - MSize mlp = 0; - if (tp == IRT_CDATA) tp = IRT_U8 + 2*lj_fls(step); - do { - while (ofs + step <= len) { - if (mlp >= CREC_COPY_MAXUNROLL) return 0; - ml[mlp].ofs = ofs; - ml[mlp].tp = tp; - mlp++; - ofs += step; - } - step >>= 1; - tp -= 2; - } while (ofs < len); - return mlp; -} - -/* -** Emit copy list with windowed loads/stores. -** LJ_TARGET_UNALIGNED: may emit unaligned loads/stores (not marked as such). -*/ -static void crec_copy_emit(jit_State *J, CRecMemList *ml, MSize mlp, - TRef trdst, TRef trsrc) -{ - MSize i, j, rwin = 0; - for (i = 0, j = 0; i < mlp; ) { - TRef trofs = lj_ir_kintp(J, ml[i].ofs); - TRef trsptr = emitir(IRT(IR_ADD, IRT_PTR), trsrc, trofs); - ml[i].trval = emitir(IRT(IR_XLOAD, ml[i].tp), trsptr, 0); - ml[i].trofs = trofs; - i++; - rwin += (LJ_SOFTFP32 && ml[i].tp == IRT_NUM) ? 2 : 1; - if (rwin >= CREC_COPY_REGWIN || i >= mlp) { /* Flush buffered stores. */ - rwin = 0; - for ( ; j < i; j++) { - TRef trdptr = emitir(IRT(IR_ADD, IRT_PTR), trdst, ml[j].trofs); - emitir(IRT(IR_XSTORE, ml[j].tp), trdptr, ml[j].trval); - } - } - } -} - -/* Optimized memory copy. */ -static void crec_copy(jit_State *J, TRef trdst, TRef trsrc, TRef trlen, - CType *ct) -{ - if (tref_isk(trlen)) { /* Length must be constant. */ - CRecMemList ml[CREC_COPY_MAXUNROLL]; - MSize mlp = 0; - CTSize step = 1, len = (CTSize)IR(tref_ref(trlen))->i; - IRType tp = IRT_CDATA; - int needxbar = 0; - if (len == 0) return; /* Shortcut. */ - if (len > CREC_COPY_MAXLEN) goto fallback; - if (ct) { - CTState *cts = ctype_ctsG(J2G(J)); - lua_assert(ctype_isarray(ct->info) || ctype_isstruct(ct->info)); - if (ctype_isarray(ct->info)) { - CType *cct = ctype_rawchild(cts, ct); - tp = crec_ct2irt(cts, cct); - if (tp == IRT_CDATA) goto rawcopy; - step = lj_ir_type_size[tp]; - lua_assert((len & (step-1)) == 0); - } else if ((ct->info & CTF_UNION)) { - step = (1u << ctype_align(ct->info)); - goto rawcopy; - } else { - mlp = crec_copy_struct(ml, cts, ct); - goto emitcopy; - } - } else { - rawcopy: - needxbar = 1; - if (LJ_TARGET_UNALIGNED || step >= CTSIZE_PTR) - step = CTSIZE_PTR; - } - mlp = crec_copy_unroll(ml, len, step, tp); - emitcopy: - if (mlp) { - crec_copy_emit(J, ml, mlp, trdst, trsrc); - if (needxbar) - emitir(IRT(IR_XBAR, IRT_NIL), 0, 0); - return; - } - } -fallback: - /* Call memcpy. Always needs a barrier to disable alias analysis. */ - lj_ir_call(J, IRCALL_memcpy, trdst, trsrc, trlen); - emitir(IRT(IR_XBAR, IRT_NIL), 0, 0); -} - -/* Generate unrolled fill list, from highest to lowest step size/alignment. */ -static MSize crec_fill_unroll(CRecMemList *ml, CTSize len, CTSize step) -{ - CTSize ofs = 0; - MSize mlp = 0; - IRType tp = IRT_U8 + 2*lj_fls(step); - do { - while (ofs + step <= len) { - if (mlp >= CREC_COPY_MAXUNROLL) return 0; - ml[mlp].ofs = ofs; - ml[mlp].tp = tp; - mlp++; - ofs += step; - } - step >>= 1; - tp -= 2; - } while (ofs < len); - return mlp; -} - -/* -** Emit stores for fill list. -** LJ_TARGET_UNALIGNED: may emit unaligned stores (not marked as such). -*/ -static void crec_fill_emit(jit_State *J, CRecMemList *ml, MSize mlp, - TRef trdst, TRef trfill) -{ - MSize i; - for (i = 0; i < mlp; i++) { - TRef trofs = lj_ir_kintp(J, ml[i].ofs); - TRef trdptr = emitir(IRT(IR_ADD, IRT_PTR), trdst, trofs); - emitir(IRT(IR_XSTORE, ml[i].tp), trdptr, trfill); - } -} - -/* Optimized memory fill. */ -static void crec_fill(jit_State *J, TRef trdst, TRef trlen, TRef trfill, - CTSize step) -{ - if (tref_isk(trlen)) { /* Length must be constant. */ - CRecMemList ml[CREC_FILL_MAXUNROLL]; - MSize mlp; - CTSize len = (CTSize)IR(tref_ref(trlen))->i; - if (len == 0) return; /* Shortcut. */ - if (LJ_TARGET_UNALIGNED || step >= CTSIZE_PTR) - step = CTSIZE_PTR; - if (step * CREC_FILL_MAXUNROLL < len) goto fallback; - mlp = crec_fill_unroll(ml, len, step); - if (!mlp) goto fallback; - if (tref_isk(trfill) || ml[0].tp != IRT_U8) - trfill = emitconv(trfill, IRT_INT, IRT_U8, 0); - if (ml[0].tp != IRT_U8) { /* Scatter U8 to U16/U32/U64. */ - if (CTSIZE_PTR == 8 && ml[0].tp == IRT_U64) { - if (tref_isk(trfill)) /* Pointless on x64 with zero-extended regs. */ - trfill = emitconv(trfill, IRT_U64, IRT_U32, 0); - trfill = emitir(IRT(IR_MUL, IRT_U64), trfill, - lj_ir_kint64(J, U64x(01010101,01010101))); - } else { - trfill = emitir(IRTI(IR_MUL), trfill, - lj_ir_kint(J, ml[0].tp == IRT_U16 ? 0x0101 : 0x01010101)); - } - } - crec_fill_emit(J, ml, mlp, trdst, trfill); - } else { -fallback: - /* Call memset. Always needs a barrier to disable alias analysis. */ - lj_ir_call(J, IRCALL_memset, trdst, trfill, trlen); /* Note: arg order! */ - } - emitir(IRT(IR_XBAR, IRT_NIL), 0, 0); -} - -/* -- Convert C type to C type -------------------------------------------- */ - -/* -** This code mirrors the code in lj_cconv.c. It performs the same steps -** for the trace recorder that lj_cconv.c does for the interpreter. -** -** One major difference is that we can get away with much fewer checks -** here. E.g. checks for casts, constness or correct types can often be -** omitted, even if they might fail. The interpreter subsequently throws -** an error, which aborts the trace. -** -** All operations are specialized to their C types, so the on-trace -** outcome must be the same as the outcome in the interpreter. If the -** interpreter doesn't throw an error, then the trace is correct, too. -** Care must be taken not to generate invalid (temporary) IR or to -** trigger asserts. -*/ - -/* Determine whether a passed number or cdata number is non-zero. */ -static int crec_isnonzero(CType *s, void *p) -{ - if (p == (void *)0) - return 0; - if (p == (void *)1) - return 1; - if ((s->info & CTF_FP)) { - if (s->size == sizeof(float)) - return (*(float *)p != 0); - else - return (*(double *)p != 0); - } else { - if (s->size == 1) - return (*(uint8_t *)p != 0); - else if (s->size == 2) - return (*(uint16_t *)p != 0); - else if (s->size == 4) - return (*(uint32_t *)p != 0); - else - return (*(uint64_t *)p != 0); - } -} - -static TRef crec_ct_ct(jit_State *J, CType *d, CType *s, TRef dp, TRef sp, - void *svisnz) -{ - IRType dt = crec_ct2irt(ctype_ctsG(J2G(J)), d); - IRType st = crec_ct2irt(ctype_ctsG(J2G(J)), s); - CTSize dsize = d->size, ssize = s->size; - CTInfo dinfo = d->info, sinfo = s->info; - - if (ctype_type(dinfo) > CT_MAYCONVERT || ctype_type(sinfo) > CT_MAYCONVERT) - goto err_conv; - - /* - ** Note: Unlike lj_cconv_ct_ct(), sp holds the _value_ of pointers and - ** numbers up to 8 bytes. Otherwise sp holds a pointer. - */ - - switch (cconv_idx2(dinfo, sinfo)) { - /* Destination is a bool. */ - case CCX(B, B): - goto xstore; /* Source operand is already normalized. */ - case CCX(B, I): - case CCX(B, F): - if (st != IRT_CDATA) { - /* Specialize to the result of a comparison against 0. */ - TRef zero = (st == IRT_NUM || st == IRT_FLOAT) ? lj_ir_knum(J, 0) : - (st == IRT_I64 || st == IRT_U64) ? lj_ir_kint64(J, 0) : - lj_ir_kint(J, 0); - int isnz = crec_isnonzero(s, svisnz); - emitir(IRTG(isnz ? IR_NE : IR_EQ, st), sp, zero); - sp = lj_ir_kint(J, isnz); - goto xstore; - } - goto err_nyi; - - /* Destination is an integer. */ - case CCX(I, B): - case CCX(I, I): - conv_I_I: - if (dt == IRT_CDATA || st == IRT_CDATA) goto err_nyi; - /* Extend 32 to 64 bit integer. */ - if (dsize == 8 && ssize < 8 && !(LJ_64 && (sinfo & CTF_UNSIGNED))) - sp = emitconv(sp, dt, ssize < 4 ? IRT_INT : st, - (sinfo & CTF_UNSIGNED) ? 0 : IRCONV_SEXT); - else if (dsize < 8 && ssize == 8) /* Truncate from 64 bit integer. */ - sp = emitconv(sp, dsize < 4 ? IRT_INT : dt, st, 0); - else if (st == IRT_INT) - sp = lj_opt_narrow_toint(J, sp); - xstore: - if (dt == IRT_I64 || dt == IRT_U64) lj_needsplit(J); - if (dp == 0) return sp; - emitir(IRT(IR_XSTORE, dt), dp, sp); - break; - case CCX(I, C): - sp = emitir(IRT(IR_XLOAD, st), sp, 0); /* Load re. */ - /* fallthrough */ - case CCX(I, F): - if (dt == IRT_CDATA || st == IRT_CDATA) goto err_nyi; - sp = emitconv(sp, dsize < 4 ? IRT_INT : dt, st, IRCONV_ANY); - goto xstore; - case CCX(I, P): - case CCX(I, A): - sinfo = CTINFO(CT_NUM, CTF_UNSIGNED); - ssize = CTSIZE_PTR; - st = IRT_UINTP; - if (((dsize ^ ssize) & 8) == 0) { /* Must insert no-op type conversion. */ - sp = emitconv(sp, dsize < 4 ? IRT_INT : dt, IRT_PTR, 0); - goto xstore; - } - goto conv_I_I; - - /* Destination is a floating-point number. */ - case CCX(F, B): - case CCX(F, I): - conv_F_I: - if (dt == IRT_CDATA || st == IRT_CDATA) goto err_nyi; - sp = emitconv(sp, dt, ssize < 4 ? IRT_INT : st, 0); - goto xstore; - case CCX(F, C): - sp = emitir(IRT(IR_XLOAD, st), sp, 0); /* Load re. */ - /* fallthrough */ - case CCX(F, F): - conv_F_F: - if (dt == IRT_CDATA || st == IRT_CDATA) goto err_nyi; - if (dt != st) sp = emitconv(sp, dt, st, 0); - goto xstore; - - /* Destination is a complex number. */ - case CCX(C, I): - case CCX(C, F): - { /* Clear im. */ - TRef ptr = emitir(IRT(IR_ADD, IRT_PTR), dp, lj_ir_kintp(J, (dsize >> 1))); - emitir(IRT(IR_XSTORE, dt), ptr, lj_ir_knum(J, 0)); - } - /* Convert to re. */ - if ((sinfo & CTF_FP)) goto conv_F_F; else goto conv_F_I; - - case CCX(C, C): - if (dt == IRT_CDATA || st == IRT_CDATA) goto err_nyi; - { - TRef re, im, ptr; - re = emitir(IRT(IR_XLOAD, st), sp, 0); - ptr = emitir(IRT(IR_ADD, IRT_PTR), sp, lj_ir_kintp(J, (ssize >> 1))); - im = emitir(IRT(IR_XLOAD, st), ptr, 0); - if (dt != st) { - re = emitconv(re, dt, st, 0); - im = emitconv(im, dt, st, 0); - } - emitir(IRT(IR_XSTORE, dt), dp, re); - ptr = emitir(IRT(IR_ADD, IRT_PTR), dp, lj_ir_kintp(J, (dsize >> 1))); - emitir(IRT(IR_XSTORE, dt), ptr, im); - } - break; - - /* Destination is a vector. */ - case CCX(V, I): - case CCX(V, F): - case CCX(V, C): - case CCX(V, V): - goto err_nyi; - - /* Destination is a pointer. */ - case CCX(P, P): - case CCX(P, A): - case CCX(P, S): - /* There are only 32 bit pointers/addresses on 32 bit machines. - ** Also ok on x64, since all 32 bit ops clear the upper part of the reg. - */ - goto xstore; - case CCX(P, I): - if (st == IRT_CDATA) goto err_nyi; - if (!LJ_64 && ssize == 8) /* Truncate from 64 bit integer. */ - sp = emitconv(sp, IRT_U32, st, 0); - goto xstore; - case CCX(P, F): - if (st == IRT_CDATA) goto err_nyi; - /* The signed conversion is cheaper. x64 really has 47 bit pointers. */ - sp = emitconv(sp, (LJ_64 && dsize == 8) ? IRT_I64 : IRT_U32, - st, IRCONV_ANY); - goto xstore; - - /* Destination is an array. */ - case CCX(A, A): - /* Destination is a struct/union. */ - case CCX(S, S): - if (dp == 0) goto err_conv; - crec_copy(J, dp, sp, lj_ir_kint(J, dsize), d); - break; - - default: - err_conv: - err_nyi: - lj_trace_err(J, LJ_TRERR_NYICONV); - break; - } - return 0; -} - -/* -- Convert C type to TValue (load) ------------------------------------- */ - -static TRef crec_tv_ct(jit_State *J, CType *s, CTypeID sid, TRef sp) -{ - CTState *cts = ctype_ctsG(J2G(J)); - IRType t = crec_ct2irt(cts, s); - CTInfo sinfo = s->info; - if (ctype_isnum(sinfo)) { - TRef tr; - if (t == IRT_CDATA) - goto err_nyi; /* NYI: copyval of >64 bit integers. */ - tr = emitir(IRT(IR_XLOAD, t), sp, 0); - if (t == IRT_FLOAT || t == IRT_U32) { /* Keep uint32_t/float as numbers. */ - return emitconv(tr, IRT_NUM, t, 0); - } else if (t == IRT_I64 || t == IRT_U64) { /* Box 64 bit integer. */ - sp = tr; - lj_needsplit(J); - } else if ((sinfo & CTF_BOOL)) { - /* Assume not equal to zero. Fixup and emit pending guard later. */ - lj_ir_set(J, IRTGI(IR_NE), tr, lj_ir_kint(J, 0)); - J->postproc = LJ_POST_FIXGUARD; - return TREF_TRUE; - } else { - return tr; - } - } else if (ctype_isptr(sinfo) || ctype_isenum(sinfo)) { - sp = emitir(IRT(IR_XLOAD, t), sp, 0); /* Box pointers and enums. */ - } else if (ctype_isrefarray(sinfo) || ctype_isstruct(sinfo)) { - cts->L = J->L; - sid = lj_ctype_intern(cts, CTINFO_REF(sid), CTSIZE_PTR); /* Create ref. */ - } else if (ctype_iscomplex(sinfo)) { /* Unbox/box complex. */ - ptrdiff_t esz = (ptrdiff_t)(s->size >> 1); - TRef ptr, tr1, tr2, dp; - dp = emitir(IRTG(IR_CNEW, IRT_CDATA), lj_ir_kint(J, sid), TREF_NIL); - tr1 = emitir(IRT(IR_XLOAD, t), sp, 0); - ptr = emitir(IRT(IR_ADD, IRT_PTR), sp, lj_ir_kintp(J, esz)); - tr2 = emitir(IRT(IR_XLOAD, t), ptr, 0); - ptr = emitir(IRT(IR_ADD, IRT_PTR), dp, lj_ir_kintp(J, sizeof(GCcdata))); - emitir(IRT(IR_XSTORE, t), ptr, tr1); - ptr = emitir(IRT(IR_ADD, IRT_PTR), dp, lj_ir_kintp(J, sizeof(GCcdata)+esz)); - emitir(IRT(IR_XSTORE, t), ptr, tr2); - return dp; - } else { - /* NYI: copyval of vectors. */ - err_nyi: - lj_trace_err(J, LJ_TRERR_NYICONV); - } - /* Box pointer, ref, enum or 64 bit integer. */ - return emitir(IRTG(IR_CNEWI, IRT_CDATA), lj_ir_kint(J, sid), sp); -} - -/* -- Convert TValue to C type (store) ------------------------------------ */ - -static TRef crec_ct_tv(jit_State *J, CType *d, TRef dp, TRef sp, cTValue *sval) -{ - CTState *cts = ctype_ctsG(J2G(J)); - CTypeID sid = CTID_P_VOID; - void *svisnz = 0; - CType *s; - if (LJ_LIKELY(tref_isinteger(sp))) { - sid = CTID_INT32; - svisnz = (void *)(intptr_t)(tvisint(sval)?(intV(sval)!=0):!tviszero(sval)); - } else if (tref_isnum(sp)) { - sid = CTID_DOUBLE; - svisnz = (void *)(intptr_t)(tvisint(sval)?(intV(sval)!=0):!tviszero(sval)); - } else if (tref_isbool(sp)) { - sp = lj_ir_kint(J, tref_istrue(sp) ? 1 : 0); - sid = CTID_BOOL; - } else if (tref_isnil(sp)) { - sp = lj_ir_kptr(J, NULL); - } else if (tref_isudata(sp)) { - GCudata *ud = udataV(sval); - if (ud->udtype == UDTYPE_IO_FILE) { - TRef tr = emitir(IRT(IR_FLOAD, IRT_U8), sp, IRFL_UDATA_UDTYPE); - emitir(IRTGI(IR_EQ), tr, lj_ir_kint(J, UDTYPE_IO_FILE)); - sp = emitir(IRT(IR_FLOAD, IRT_PTR), sp, IRFL_UDATA_FILE); - } else { - sp = emitir(IRT(IR_ADD, IRT_PTR), sp, lj_ir_kintp(J, sizeof(GCudata))); - } - } else if (tref_isstr(sp)) { - if (ctype_isenum(d->info)) { /* Match string against enum constant. */ - GCstr *str = strV(sval); - CTSize ofs; - CType *cct = lj_ctype_getfield(cts, d, str, &ofs); - /* Specialize to the name of the enum constant. */ - emitir(IRTG(IR_EQ, IRT_STR), sp, lj_ir_kstr(J, str)); - if (cct && ctype_isconstval(cct->info)) { - lua_assert(ctype_child(cts, cct)->size == 4); - svisnz = (void *)(intptr_t)(ofs != 0); - sp = lj_ir_kint(J, (int32_t)ofs); - sid = ctype_cid(cct->info); - } /* else: interpreter will throw. */ - } else if (ctype_isrefarray(d->info)) { /* Copy string to array. */ - lj_trace_err(J, LJ_TRERR_BADTYPE); /* NYI */ - } else { /* Otherwise pass the string data as a const char[]. */ - /* Don't use STRREF. It folds with SNEW, which loses the trailing NUL. */ - sp = emitir(IRT(IR_ADD, IRT_PTR), sp, lj_ir_kintp(J, sizeof(GCstr))); - sid = CTID_A_CCHAR; - } - } else if (tref_islightud(sp)) { -#if LJ_64 - sp = emitir(IRT(IR_BAND, IRT_P64), sp, - lj_ir_kint64(J, U64x(00007fff,ffffffff))); -#endif - } else { /* NYI: tref_istab(sp). */ - IRType t; - sid = argv2cdata(J, sp, sval)->ctypeid; - s = ctype_raw(cts, sid); - svisnz = cdataptr(cdataV(sval)); - if (ctype_isfunc(s->info)) { - sid = lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|sid), CTSIZE_PTR); - s = ctype_get(cts, sid); - t = IRT_PTR; - } else { - t = crec_ct2irt(cts, s); - } - if (ctype_isptr(s->info)) { - sp = emitir(IRT(IR_FLOAD, t), sp, IRFL_CDATA_PTR); - if (ctype_isref(s->info)) { - svisnz = *(void **)svisnz; - s = ctype_rawchild(cts, s); - if (ctype_isenum(s->info)) s = ctype_child(cts, s); - t = crec_ct2irt(cts, s); - } else { - goto doconv; - } - } else if (t == IRT_I64 || t == IRT_U64) { - sp = emitir(IRT(IR_FLOAD, t), sp, IRFL_CDATA_INT64); - lj_needsplit(J); - goto doconv; - } else if (t == IRT_INT || t == IRT_U32) { - if (ctype_isenum(s->info)) s = ctype_child(cts, s); - sp = emitir(IRT(IR_FLOAD, t), sp, IRFL_CDATA_INT); - goto doconv; - } else { - sp = emitir(IRT(IR_ADD, IRT_PTR), sp, lj_ir_kintp(J, sizeof(GCcdata))); - } - if (ctype_isnum(s->info) && t != IRT_CDATA) - sp = emitir(IRT(IR_XLOAD, t), sp, 0); /* Load number value. */ - goto doconv; - } - s = ctype_get(cts, sid); -doconv: - if (ctype_isenum(d->info)) d = ctype_child(cts, d); - return crec_ct_ct(J, d, s, dp, sp, svisnz); -} - -/* -- C data metamethods -------------------------------------------------- */ - -/* This would be rather difficult in FOLD, so do it here: -** (base+k)+(idx*sz)+ofs ==> (base+idx*sz)+(ofs+k) -** (base+(idx+k)*sz)+ofs ==> (base+idx*sz)+(ofs+k*sz) -*/ -static TRef crec_reassoc_ofs(jit_State *J, TRef tr, ptrdiff_t *ofsp, MSize sz) -{ - IRIns *ir = IR(tref_ref(tr)); - if (LJ_LIKELY(J->flags & JIT_F_OPT_FOLD) && irref_isk(ir->op2) && - (ir->o == IR_ADD || ir->o == IR_ADDOV || ir->o == IR_SUBOV)) { - IRIns *irk = IR(ir->op2); - ptrdiff_t k; - if (LJ_64 && irk->o == IR_KINT64) - k = (ptrdiff_t)ir_kint64(irk)->u64 * sz; - else - k = (ptrdiff_t)irk->i * sz; - if (ir->o == IR_SUBOV) *ofsp -= k; else *ofsp += k; - tr = ir->op1; /* Not a TRef, but the caller doesn't care. */ - } - return tr; -} - -/* Tailcall to function. */ -static void crec_tailcall(jit_State *J, RecordFFData *rd, cTValue *tv) -{ - TRef kfunc = lj_ir_kfunc(J, funcV(tv)); -#if LJ_FR2 - J->base[-2] = kfunc; - J->base[-1] = TREF_FRAME; -#else - J->base[-1] = kfunc | TREF_FRAME; -#endif - rd->nres = -1; /* Pending tailcall. */ -} - -/* Record ctype __index/__newindex metamethods. */ -static void crec_index_meta(jit_State *J, CTState *cts, CType *ct, - RecordFFData *rd) -{ - CTypeID id = ctype_typeid(cts, ct); - cTValue *tv = lj_ctype_meta(cts, id, rd->data ? MM_newindex : MM_index); - if (!tv) - lj_trace_err(J, LJ_TRERR_BADTYPE); - if (tvisfunc(tv)) { - crec_tailcall(J, rd, tv); - } else if (rd->data == 0 && tvistab(tv) && tref_isstr(J->base[1])) { - /* Specialize to result of __index lookup. */ - cTValue *o = lj_tab_get(J->L, tabV(tv), &rd->argv[1]); - J->base[0] = lj_record_constify(J, o); - if (!J->base[0]) - lj_trace_err(J, LJ_TRERR_BADTYPE); - /* Always specialize to the key. */ - emitir(IRTG(IR_EQ, IRT_STR), J->base[1], lj_ir_kstr(J, strV(&rd->argv[1]))); - } else { - /* NYI: resolving of non-function metamethods. */ - /* NYI: non-string keys for __index table. */ - /* NYI: stores to __newindex table. */ - lj_trace_err(J, LJ_TRERR_BADTYPE); - } -} - -/* Record bitfield load/store. */ -static void crec_index_bf(jit_State *J, RecordFFData *rd, TRef ptr, CTInfo info) -{ - IRType t = IRT_I8 + 2*lj_fls(ctype_bitcsz(info)) + ((info&CTF_UNSIGNED)?1:0); - TRef tr = emitir(IRT(IR_XLOAD, t), ptr, 0); - CTSize pos = ctype_bitpos(info), bsz = ctype_bitbsz(info), shift = 32 - bsz; - lua_assert(t <= IRT_U32); /* NYI: 64 bit bitfields. */ - if (rd->data == 0) { /* __index metamethod. */ - if ((info & CTF_BOOL)) { - tr = emitir(IRTI(IR_BAND), tr, lj_ir_kint(J, (int32_t)((1u << pos)))); - /* Assume not equal to zero. Fixup and emit pending guard later. */ - lj_ir_set(J, IRTGI(IR_NE), tr, lj_ir_kint(J, 0)); - J->postproc = LJ_POST_FIXGUARD; - tr = TREF_TRUE; - } else if (!(info & CTF_UNSIGNED)) { - tr = emitir(IRTI(IR_BSHL), tr, lj_ir_kint(J, shift - pos)); - tr = emitir(IRTI(IR_BSAR), tr, lj_ir_kint(J, shift)); - } else { - lua_assert(bsz < 32); /* Full-size fields cannot end up here. */ - tr = emitir(IRTI(IR_BSHR), tr, lj_ir_kint(J, pos)); - tr = emitir(IRTI(IR_BAND), tr, lj_ir_kint(J, (int32_t)((1u << bsz)-1))); - /* We can omit the U32 to NUM conversion, since bsz < 32. */ - } - J->base[0] = tr; - } else { /* __newindex metamethod. */ - CTState *cts = ctype_ctsG(J2G(J)); - CType *ct = ctype_get(cts, - (info & CTF_BOOL) ? CTID_BOOL : - (info & CTF_UNSIGNED) ? CTID_UINT32 : CTID_INT32); - int32_t mask = (int32_t)(((1u << bsz)-1) << pos); - TRef sp = crec_ct_tv(J, ct, 0, J->base[2], &rd->argv[2]); - sp = emitir(IRTI(IR_BSHL), sp, lj_ir_kint(J, pos)); - /* Use of the target type avoids forwarding conversions. */ - sp = emitir(IRT(IR_BAND, t), sp, lj_ir_kint(J, mask)); - tr = emitir(IRT(IR_BAND, t), tr, lj_ir_kint(J, (int32_t)~mask)); - tr = emitir(IRT(IR_BOR, t), tr, sp); - emitir(IRT(IR_XSTORE, t), ptr, tr); - rd->nres = 0; - J->needsnap = 1; - } -} - -void LJ_FASTCALL recff_cdata_index(jit_State *J, RecordFFData *rd) -{ - TRef idx, ptr = J->base[0]; - ptrdiff_t ofs = sizeof(GCcdata); - GCcdata *cd = argv2cdata(J, ptr, &rd->argv[0]); - CTState *cts = ctype_ctsG(J2G(J)); - CType *ct = ctype_raw(cts, cd->ctypeid); - CTypeID sid = 0; - - /* Resolve pointer or reference for cdata object. */ - if (ctype_isptr(ct->info)) { - IRType t = (LJ_64 && ct->size == 8) ? IRT_P64 : IRT_P32; - if (ctype_isref(ct->info)) ct = ctype_rawchild(cts, ct); - ptr = emitir(IRT(IR_FLOAD, t), ptr, IRFL_CDATA_PTR); - ofs = 0; - ptr = crec_reassoc_ofs(J, ptr, &ofs, 1); - } - -again: - idx = J->base[1]; - if (tref_isnumber(idx)) { - idx = lj_opt_narrow_cindex(J, idx); - if (ctype_ispointer(ct->info)) { - CTSize sz; - integer_key: - if ((ct->info & CTF_COMPLEX)) - idx = emitir(IRT(IR_BAND, IRT_INTP), idx, lj_ir_kintp(J, 1)); - sz = lj_ctype_size(cts, (sid = ctype_cid(ct->info))); - idx = crec_reassoc_ofs(J, idx, &ofs, sz); -#if LJ_TARGET_ARM || LJ_TARGET_PPC - /* Hoist base add to allow fusion of index/shift into operands. */ - if (LJ_LIKELY(J->flags & JIT_F_OPT_LOOP) && ofs -#if LJ_TARGET_ARM - && (sz == 1 || sz == 4) -#endif - ) { - ptr = emitir(IRT(IR_ADD, IRT_PTR), ptr, lj_ir_kintp(J, ofs)); - ofs = 0; - } -#endif - idx = emitir(IRT(IR_MUL, IRT_INTP), idx, lj_ir_kintp(J, sz)); - ptr = emitir(IRT(IR_ADD, IRT_PTR), idx, ptr); - } - } else if (tref_iscdata(idx)) { - GCcdata *cdk = cdataV(&rd->argv[1]); - CType *ctk = ctype_raw(cts, cdk->ctypeid); - IRType t = crec_ct2irt(cts, ctk); - if (ctype_ispointer(ct->info) && t >= IRT_I8 && t <= IRT_U64) { - if (ctk->size == 8) { - idx = emitir(IRT(IR_FLOAD, t), idx, IRFL_CDATA_INT64); - } else if (ctk->size == 4) { - idx = emitir(IRT(IR_FLOAD, t), idx, IRFL_CDATA_INT); - } else { - idx = emitir(IRT(IR_ADD, IRT_PTR), idx, - lj_ir_kintp(J, sizeof(GCcdata))); - idx = emitir(IRT(IR_XLOAD, t), idx, 0); - } - if (LJ_64 && ctk->size < sizeof(intptr_t) && !(ctk->info & CTF_UNSIGNED)) - idx = emitconv(idx, IRT_INTP, IRT_INT, IRCONV_SEXT); - if (!LJ_64 && ctk->size > sizeof(intptr_t)) { - idx = emitconv(idx, IRT_INTP, t, 0); - lj_needsplit(J); - } - goto integer_key; - } - } else if (tref_isstr(idx)) { - GCstr *name = strV(&rd->argv[1]); - if (cd && cd->ctypeid == CTID_CTYPEID) - ct = ctype_raw(cts, crec_constructor(J, cd, ptr)); - if (ctype_isstruct(ct->info)) { - CTSize fofs; - CType *fct; - fct = lj_ctype_getfield(cts, ct, name, &fofs); - if (fct) { - ofs += (ptrdiff_t)fofs; - /* Always specialize to the field name. */ - emitir(IRTG(IR_EQ, IRT_STR), idx, lj_ir_kstr(J, name)); - if (ctype_isconstval(fct->info)) { - if (fct->size >= 0x80000000u && - (ctype_child(cts, fct)->info & CTF_UNSIGNED)) { - J->base[0] = lj_ir_knum(J, (lua_Number)(uint32_t)fct->size); - return; - } - J->base[0] = lj_ir_kint(J, (int32_t)fct->size); - return; /* Interpreter will throw for newindex. */ - } else if (ctype_isbitfield(fct->info)) { - if (ofs) - ptr = emitir(IRT(IR_ADD, IRT_PTR), ptr, lj_ir_kintp(J, ofs)); - crec_index_bf(J, rd, ptr, fct->info); - return; - } else { - lua_assert(ctype_isfield(fct->info)); - sid = ctype_cid(fct->info); - } - } - } else if (ctype_iscomplex(ct->info)) { - if (name->len == 2 && - ((strdata(name)[0] == 'r' && strdata(name)[1] == 'e') || - (strdata(name)[0] == 'i' && strdata(name)[1] == 'm'))) { - /* Always specialize to the field name. */ - emitir(IRTG(IR_EQ, IRT_STR), idx, lj_ir_kstr(J, name)); - if (strdata(name)[0] == 'i') ofs += (ct->size >> 1); - sid = ctype_cid(ct->info); - } - } - } - if (!sid) { - if (ctype_isptr(ct->info)) { /* Automatically perform '->'. */ - CType *cct = ctype_rawchild(cts, ct); - if (ctype_isstruct(cct->info)) { - ct = cct; - cd = NULL; - if (tref_isstr(idx)) goto again; - } - } - crec_index_meta(J, cts, ct, rd); - return; - } - - if (ofs) - ptr = emitir(IRT(IR_ADD, IRT_PTR), ptr, lj_ir_kintp(J, ofs)); - - /* Resolve reference for field. */ - ct = ctype_get(cts, sid); - if (ctype_isref(ct->info)) { - ptr = emitir(IRT(IR_XLOAD, IRT_PTR), ptr, 0); - sid = ctype_cid(ct->info); - ct = ctype_get(cts, sid); - } - - while (ctype_isattrib(ct->info)) - ct = ctype_child(cts, ct); /* Skip attributes. */ - - if (rd->data == 0) { /* __index metamethod. */ - J->base[0] = crec_tv_ct(J, ct, sid, ptr); - } else { /* __newindex metamethod. */ - rd->nres = 0; - J->needsnap = 1; - crec_ct_tv(J, ct, ptr, J->base[2], &rd->argv[2]); - } -} - -/* Record setting a finalizer. */ -static void crec_finalizer(jit_State *J, TRef trcd, TRef trfin, cTValue *fin) -{ - if (tvisgcv(fin)) { - if (!trfin) trfin = lj_ir_kptr(J, gcval(fin)); - } else if (tvisnil(fin)) { - trfin = lj_ir_kptr(J, NULL); - } else { - lj_trace_err(J, LJ_TRERR_BADTYPE); - } - lj_ir_call(J, IRCALL_lj_cdata_setfin, trcd, - trfin, lj_ir_kint(J, (int32_t)itype(fin))); - J->needsnap = 1; -} - -/* Record cdata allocation. */ -static void crec_alloc(jit_State *J, RecordFFData *rd, CTypeID id) -{ - CTState *cts = ctype_ctsG(J2G(J)); - CTSize sz; - CTInfo info = lj_ctype_info(cts, id, &sz); - CType *d = ctype_raw(cts, id); - TRef trcd, trid = lj_ir_kint(J, id); - cTValue *fin; - /* Use special instruction to box pointer or 32/64 bit integer. */ - if (ctype_isptr(info) || (ctype_isinteger(info) && (sz == 4 || sz == 8))) { - TRef sp = J->base[1] ? crec_ct_tv(J, d, 0, J->base[1], &rd->argv[1]) : - ctype_isptr(info) ? lj_ir_kptr(J, NULL) : - sz == 4 ? lj_ir_kint(J, 0) : - (lj_needsplit(J), lj_ir_kint64(J, 0)); - J->base[0] = emitir(IRTG(IR_CNEWI, IRT_CDATA), trid, sp); - return; - } else { - TRef trsz = TREF_NIL; - if ((info & CTF_VLA)) { /* Calculate VLA/VLS size at runtime. */ - CTSize sz0, sz1; - if (!J->base[1] || J->base[2]) - lj_trace_err(J, LJ_TRERR_NYICONV); /* NYI: init VLA/VLS. */ - trsz = crec_ct_tv(J, ctype_get(cts, CTID_INT32), 0, - J->base[1], &rd->argv[1]); - sz0 = lj_ctype_vlsize(cts, d, 0); - sz1 = lj_ctype_vlsize(cts, d, 1); - trsz = emitir(IRTGI(IR_MULOV), trsz, lj_ir_kint(J, (int32_t)(sz1-sz0))); - trsz = emitir(IRTGI(IR_ADDOV), trsz, lj_ir_kint(J, (int32_t)sz0)); - J->base[1] = 0; /* Simplify logic below. */ - } else if (ctype_align(info) > CT_MEMALIGN) { - trsz = lj_ir_kint(J, sz); - } - trcd = emitir(IRTG(IR_CNEW, IRT_CDATA), trid, trsz); - if (sz > 128 || (info & CTF_VLA)) { - TRef dp; - CTSize align; - special: /* Only handle bulk zero-fill for large/VLA/VLS types. */ - if (J->base[1]) - lj_trace_err(J, LJ_TRERR_NYICONV); /* NYI: init large/VLA/VLS types. */ - dp = emitir(IRT(IR_ADD, IRT_PTR), trcd, lj_ir_kintp(J, sizeof(GCcdata))); - if (trsz == TREF_NIL) trsz = lj_ir_kint(J, sz); - align = ctype_align(info); - if (align < CT_MEMALIGN) align = CT_MEMALIGN; - crec_fill(J, dp, trsz, lj_ir_kint(J, 0), (1u << align)); - } else if (J->base[1] && !J->base[2] && - !lj_cconv_multi_init(cts, d, &rd->argv[1])) { - goto single_init; - } else if (ctype_isarray(d->info)) { - CType *dc = ctype_rawchild(cts, d); /* Array element type. */ - CTSize ofs, esize = dc->size; - TRef sp = 0; - TValue tv; - TValue *sval = &tv; - MSize i; - tv.u64 = 0; - if (!(ctype_isnum(dc->info) || ctype_isptr(dc->info)) || - esize * CREC_FILL_MAXUNROLL < sz) - goto special; - for (i = 1, ofs = 0; ofs < sz; ofs += esize) { - TRef dp = emitir(IRT(IR_ADD, IRT_PTR), trcd, - lj_ir_kintp(J, ofs + sizeof(GCcdata))); - if (J->base[i]) { - sp = J->base[i]; - sval = &rd->argv[i]; - i++; - } else if (i != 2) { - sp = ctype_isnum(dc->info) ? lj_ir_kint(J, 0) : TREF_NIL; - } - crec_ct_tv(J, dc, dp, sp, sval); - } - } else if (ctype_isstruct(d->info)) { - CTypeID fid = d->sib; - MSize i = 1; - while (fid) { - CType *df = ctype_get(cts, fid); - fid = df->sib; - if (ctype_isfield(df->info)) { - CType *dc; - TRef sp, dp; - TValue tv; - TValue *sval = &tv; - setintV(&tv, 0); - if (!gcref(df->name)) continue; /* Ignore unnamed fields. */ - dc = ctype_rawchild(cts, df); /* Field type. */ - if (!(ctype_isnum(dc->info) || ctype_isptr(dc->info) || - ctype_isenum(dc->info))) - lj_trace_err(J, LJ_TRERR_NYICONV); /* NYI: init aggregates. */ - if (J->base[i]) { - sp = J->base[i]; - sval = &rd->argv[i]; - i++; - } else { - sp = ctype_isptr(dc->info) ? TREF_NIL : lj_ir_kint(J, 0); - } - dp = emitir(IRT(IR_ADD, IRT_PTR), trcd, - lj_ir_kintp(J, df->size + sizeof(GCcdata))); - crec_ct_tv(J, dc, dp, sp, sval); - } else if (!ctype_isconstval(df->info)) { - /* NYI: init bitfields and sub-structures. */ - lj_trace_err(J, LJ_TRERR_NYICONV); - } - } - } else { - TRef dp; - single_init: - dp = emitir(IRT(IR_ADD, IRT_PTR), trcd, lj_ir_kintp(J, sizeof(GCcdata))); - if (J->base[1]) { - crec_ct_tv(J, d, dp, J->base[1], &rd->argv[1]); - } else { - TValue tv; - tv.u64 = 0; - crec_ct_tv(J, d, dp, lj_ir_kint(J, 0), &tv); - } - } - } - J->base[0] = trcd; - /* Handle __gc metamethod. */ - fin = lj_ctype_meta(cts, id, MM_gc); - if (fin) - crec_finalizer(J, trcd, 0, fin); -} - -/* Record argument conversions. */ -static TRef crec_call_args(jit_State *J, RecordFFData *rd, - CTState *cts, CType *ct) -{ - TRef args[CCI_NARGS_MAX]; - CTypeID fid; - MSize i, n; - TRef tr, *base; - cTValue *o; -#if LJ_TARGET_X86 -#if LJ_ABI_WIN - TRef *arg0 = NULL, *arg1 = NULL; -#endif - int ngpr = 0; - if (ctype_cconv(ct->info) == CTCC_THISCALL) - ngpr = 1; - else if (ctype_cconv(ct->info) == CTCC_FASTCALL) - ngpr = 2; -#endif - - /* Skip initial attributes. */ - fid = ct->sib; - while (fid) { - CType *ctf = ctype_get(cts, fid); - if (!ctype_isattrib(ctf->info)) break; - fid = ctf->sib; - } - args[0] = TREF_NIL; - for (n = 0, base = J->base+1, o = rd->argv+1; *base; n++, base++, o++) { - CTypeID did; - CType *d; - - if (n >= CCI_NARGS_MAX) - lj_trace_err(J, LJ_TRERR_NYICALL); - - if (fid) { /* Get argument type from field. */ - CType *ctf = ctype_get(cts, fid); - fid = ctf->sib; - lua_assert(ctype_isfield(ctf->info)); - did = ctype_cid(ctf->info); - } else { - if (!(ct->info & CTF_VARARG)) - lj_trace_err(J, LJ_TRERR_NYICALL); /* Too many arguments. */ - did = lj_ccall_ctid_vararg(cts, o); /* Infer vararg type. */ - } - d = ctype_raw(cts, did); - if (!(ctype_isnum(d->info) || ctype_isptr(d->info) || - ctype_isenum(d->info))) - lj_trace_err(J, LJ_TRERR_NYICALL); - tr = crec_ct_tv(J, d, 0, *base, o); - if (ctype_isinteger_or_bool(d->info)) { - if (d->size < 4) { - if ((d->info & CTF_UNSIGNED)) - tr = emitconv(tr, IRT_INT, d->size==1 ? IRT_U8 : IRT_U16, 0); - else - tr = emitconv(tr, IRT_INT, d->size==1 ? IRT_I8 : IRT_I16,IRCONV_SEXT); - } - } else if (LJ_SOFTFP32 && ctype_isfp(d->info) && d->size > 4) { - lj_needsplit(J); - } -#if LJ_TARGET_X86 - /* 64 bit args must not end up in registers for fastcall/thiscall. */ -#if LJ_ABI_WIN - if (!ctype_isfp(d->info)) { - /* Sigh, the Windows/x86 ABI allows reordering across 64 bit args. */ - if (tref_typerange(tr, IRT_I64, IRT_U64)) { - if (ngpr) { - arg0 = &args[n]; args[n++] = TREF_NIL; ngpr--; - if (ngpr) { - arg1 = &args[n]; args[n++] = TREF_NIL; ngpr--; - } - } - } else { - if (arg0) { *arg0 = tr; arg0 = NULL; n--; continue; } - if (arg1) { *arg1 = tr; arg1 = NULL; n--; continue; } - if (ngpr) ngpr--; - } - } -#else - if (!ctype_isfp(d->info) && ngpr) { - if (tref_typerange(tr, IRT_I64, IRT_U64)) { - /* No reordering for other x86 ABIs. Simply add alignment args. */ - do { args[n++] = TREF_NIL; } while (--ngpr); - } else { - ngpr--; - } - } -#endif -#endif - args[n] = tr; - } - tr = args[0]; - for (i = 1; i < n; i++) - tr = emitir(IRT(IR_CARG, IRT_NIL), tr, args[i]); - return tr; -} - -/* Create a snapshot for the caller, simulating a 'false' return value. */ -static void crec_snap_caller(jit_State *J) -{ - lua_State *L = J->L; - TValue *base = L->base, *top = L->top; - const BCIns *pc = J->pc; - TRef ftr = J->base[-1-LJ_FR2]; - ptrdiff_t delta; - if (!frame_islua(base-1) || J->framedepth <= 0) - lj_trace_err(J, LJ_TRERR_NYICALL); - J->pc = frame_pc(base-1); delta = 1+LJ_FR2+bc_a(J->pc[-1]); - L->top = base; L->base = base - delta; - J->base[-1-LJ_FR2] = TREF_FALSE; - J->base -= delta; J->baseslot -= (BCReg)delta; - J->maxslot = (BCReg)delta-LJ_FR2; J->framedepth--; - lj_snap_add(J); - L->base = base; L->top = top; - J->framedepth++; J->maxslot = 1; - J->base += delta; J->baseslot += (BCReg)delta; - J->base[-1-LJ_FR2] = ftr; J->pc = pc; -} - -/* Record function call. */ -static int crec_call(jit_State *J, RecordFFData *rd, GCcdata *cd) -{ - CTState *cts = ctype_ctsG(J2G(J)); - CType *ct = ctype_raw(cts, cd->ctypeid); - IRType tp = IRT_PTR; - if (ctype_isptr(ct->info)) { - tp = (LJ_64 && ct->size == 8) ? IRT_P64 : IRT_P32; - ct = ctype_rawchild(cts, ct); - } - if (ctype_isfunc(ct->info)) { - TRef func = emitir(IRT(IR_FLOAD, tp), J->base[0], IRFL_CDATA_PTR); - CType *ctr = ctype_rawchild(cts, ct); - IRType t = crec_ct2irt(cts, ctr); - TRef tr; - TValue tv; - /* Check for blacklisted C functions that might call a callback. */ - setlightudV(&tv, - cdata_getptr(cdataptr(cd), (LJ_64 && tp == IRT_P64) ? 8 : 4)); - if (tvistrue(lj_tab_get(J->L, cts->miscmap, &tv))) - lj_trace_err(J, LJ_TRERR_BLACKL); - if (ctype_isvoid(ctr->info)) { - t = IRT_NIL; - rd->nres = 0; - } else if (!(ctype_isnum(ctr->info) || ctype_isptr(ctr->info) || - ctype_isenum(ctr->info)) || t == IRT_CDATA) { - lj_trace_err(J, LJ_TRERR_NYICALL); - } - if ((ct->info & CTF_VARARG) -#if LJ_TARGET_X86 - || ctype_cconv(ct->info) != CTCC_CDECL -#endif - ) - func = emitir(IRT(IR_CARG, IRT_NIL), func, - lj_ir_kint(J, ctype_typeid(cts, ct))); - tr = emitir(IRT(IR_CALLXS, t), crec_call_args(J, rd, cts, ct), func); - if (ctype_isbool(ctr->info)) { - if (frame_islua(J->L->base-1) && bc_b(frame_pc(J->L->base-1)[-1]) == 1) { - /* Don't check result if ignored. */ - tr = TREF_NIL; - } else { - crec_snap_caller(J); -#if LJ_TARGET_X86ORX64 - /* Note: only the x86/x64 backend supports U8 and only for EQ(tr, 0). */ - lj_ir_set(J, IRTG(IR_NE, IRT_U8), tr, lj_ir_kint(J, 0)); -#else - lj_ir_set(J, IRTGI(IR_NE), tr, lj_ir_kint(J, 0)); -#endif - J->postproc = LJ_POST_FIXGUARDSNAP; - tr = TREF_TRUE; - } - } else if (t == IRT_PTR || (LJ_64 && t == IRT_P32) || - t == IRT_I64 || t == IRT_U64 || ctype_isenum(ctr->info)) { - TRef trid = lj_ir_kint(J, ctype_cid(ct->info)); - tr = emitir(IRTG(IR_CNEWI, IRT_CDATA), trid, tr); - if (t == IRT_I64 || t == IRT_U64) lj_needsplit(J); - } else if (t == IRT_FLOAT || t == IRT_U32) { - tr = emitconv(tr, IRT_NUM, t, 0); - } else if (t == IRT_I8 || t == IRT_I16) { - tr = emitconv(tr, IRT_INT, t, IRCONV_SEXT); - } else if (t == IRT_U8 || t == IRT_U16) { - tr = emitconv(tr, IRT_INT, t, 0); - } - J->base[0] = tr; - J->needsnap = 1; - return 1; - } - return 0; -} - -void LJ_FASTCALL recff_cdata_call(jit_State *J, RecordFFData *rd) -{ - CTState *cts = ctype_ctsG(J2G(J)); - GCcdata *cd = argv2cdata(J, J->base[0], &rd->argv[0]); - CTypeID id = cd->ctypeid; - CType *ct; - cTValue *tv; - MMS mm = MM_call; - if (id == CTID_CTYPEID) { - id = crec_constructor(J, cd, J->base[0]); - mm = MM_new; - } else if (crec_call(J, rd, cd)) { - return; - } - /* Record ctype __call/__new metamethod. */ - ct = ctype_raw(cts, id); - tv = lj_ctype_meta(cts, ctype_isptr(ct->info) ? ctype_cid(ct->info) : id, mm); - if (tv) { - if (tvisfunc(tv)) { - crec_tailcall(J, rd, tv); - return; - } - } else if (mm == MM_new) { - crec_alloc(J, rd, id); - return; - } - /* No metamethod or NYI: non-function metamethods. */ - lj_trace_err(J, LJ_TRERR_BADTYPE); -} - -static TRef crec_arith_int64(jit_State *J, TRef *sp, CType **s, MMS mm) -{ - if (sp[0] && sp[1] && ctype_isnum(s[0]->info) && ctype_isnum(s[1]->info)) { - IRType dt; - CTypeID id; - TRef tr; - MSize i; - IROp op; - lj_needsplit(J); - if (((s[0]->info & CTF_UNSIGNED) && s[0]->size == 8) || - ((s[1]->info & CTF_UNSIGNED) && s[1]->size == 8)) { - dt = IRT_U64; id = CTID_UINT64; - } else { - dt = IRT_I64; id = CTID_INT64; - if (mm < MM_add && - !((s[0]->info | s[1]->info) & CTF_FP) && - s[0]->size == 4 && s[1]->size == 4) { /* Try to narrow comparison. */ - if (!((s[0]->info ^ s[1]->info) & CTF_UNSIGNED) || - (tref_isk(sp[1]) && IR(tref_ref(sp[1]))->i >= 0)) { - dt = (s[0]->info & CTF_UNSIGNED) ? IRT_U32 : IRT_INT; - goto comp; - } else if (tref_isk(sp[0]) && IR(tref_ref(sp[0]))->i >= 0) { - dt = (s[1]->info & CTF_UNSIGNED) ? IRT_U32 : IRT_INT; - goto comp; - } - } - } - for (i = 0; i < 2; i++) { - IRType st = tref_type(sp[i]); - if (st == IRT_NUM || st == IRT_FLOAT) - sp[i] = emitconv(sp[i], dt, st, IRCONV_ANY); - else if (!(st == IRT_I64 || st == IRT_U64)) - sp[i] = emitconv(sp[i], dt, IRT_INT, - (s[i]->info & CTF_UNSIGNED) ? 0 : IRCONV_SEXT); - } - if (mm < MM_add) { - comp: - /* Assume true comparison. Fixup and emit pending guard later. */ - if (mm == MM_eq) { - op = IR_EQ; - } else { - op = mm == MM_lt ? IR_LT : IR_LE; - if (dt == IRT_U32 || dt == IRT_U64) - op += (IR_ULT-IR_LT); - } - lj_ir_set(J, IRTG(op, dt), sp[0], sp[1]); - J->postproc = LJ_POST_FIXGUARD; - return TREF_TRUE; - } else { - tr = emitir(IRT(mm+(int)IR_ADD-(int)MM_add, dt), sp[0], sp[1]); - } - return emitir(IRTG(IR_CNEWI, IRT_CDATA), lj_ir_kint(J, id), tr); - } - return 0; -} - -static TRef crec_arith_ptr(jit_State *J, TRef *sp, CType **s, MMS mm) -{ - CTState *cts = ctype_ctsG(J2G(J)); - CType *ctp = s[0]; - if (!(sp[0] && sp[1])) return 0; - if (ctype_isptr(ctp->info) || ctype_isrefarray(ctp->info)) { - if ((mm == MM_sub || mm == MM_eq || mm == MM_lt || mm == MM_le) && - (ctype_isptr(s[1]->info) || ctype_isrefarray(s[1]->info))) { - if (mm == MM_sub) { /* Pointer difference. */ - TRef tr; - CTSize sz = lj_ctype_size(cts, ctype_cid(ctp->info)); - if (sz == 0 || (sz & (sz-1)) != 0) - return 0; /* NYI: integer division. */ - tr = emitir(IRT(IR_SUB, IRT_INTP), sp[0], sp[1]); - tr = emitir(IRT(IR_BSAR, IRT_INTP), tr, lj_ir_kint(J, lj_fls(sz))); -#if LJ_64 - tr = emitconv(tr, IRT_NUM, IRT_INTP, 0); -#endif - return tr; - } else { /* Pointer comparison (unsigned). */ - /* Assume true comparison. Fixup and emit pending guard later. */ - IROp op = mm == MM_eq ? IR_EQ : mm == MM_lt ? IR_ULT : IR_ULE; - lj_ir_set(J, IRTG(op, IRT_PTR), sp[0], sp[1]); - J->postproc = LJ_POST_FIXGUARD; - return TREF_TRUE; - } - } - if (!((mm == MM_add || mm == MM_sub) && ctype_isnum(s[1]->info))) - return 0; - } else if (mm == MM_add && ctype_isnum(ctp->info) && - (ctype_isptr(s[1]->info) || ctype_isrefarray(s[1]->info))) { - TRef tr = sp[0]; sp[0] = sp[1]; sp[1] = tr; /* Swap pointer and index. */ - ctp = s[1]; - } else { - return 0; - } - { - TRef tr = sp[1]; - IRType t = tref_type(tr); - CTSize sz = lj_ctype_size(cts, ctype_cid(ctp->info)); - CTypeID id; -#if LJ_64 - if (t == IRT_NUM || t == IRT_FLOAT) - tr = emitconv(tr, IRT_INTP, t, IRCONV_ANY); - else if (!(t == IRT_I64 || t == IRT_U64)) - tr = emitconv(tr, IRT_INTP, IRT_INT, - ((t - IRT_I8) & 1) ? 0 : IRCONV_SEXT); -#else - if (!tref_typerange(sp[1], IRT_I8, IRT_U32)) { - tr = emitconv(tr, IRT_INTP, t, - (t == IRT_NUM || t == IRT_FLOAT) ? IRCONV_ANY : 0); - } -#endif - tr = emitir(IRT(IR_MUL, IRT_INTP), tr, lj_ir_kintp(J, sz)); - tr = emitir(IRT(mm+(int)IR_ADD-(int)MM_add, IRT_PTR), sp[0], tr); - id = lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|ctype_cid(ctp->info)), - CTSIZE_PTR); - return emitir(IRTG(IR_CNEWI, IRT_CDATA), lj_ir_kint(J, id), tr); - } -} - -/* Record ctype arithmetic metamethods. */ -static TRef crec_arith_meta(jit_State *J, TRef *sp, CType **s, CTState *cts, - RecordFFData *rd) -{ - cTValue *tv = NULL; - if (J->base[0]) { - if (tviscdata(&rd->argv[0])) { - CTypeID id = argv2cdata(J, J->base[0], &rd->argv[0])->ctypeid; - CType *ct = ctype_raw(cts, id); - if (ctype_isptr(ct->info)) id = ctype_cid(ct->info); - tv = lj_ctype_meta(cts, id, (MMS)rd->data); - } - if (!tv && J->base[1] && tviscdata(&rd->argv[1])) { - CTypeID id = argv2cdata(J, J->base[1], &rd->argv[1])->ctypeid; - CType *ct = ctype_raw(cts, id); - if (ctype_isptr(ct->info)) id = ctype_cid(ct->info); - tv = lj_ctype_meta(cts, id, (MMS)rd->data); - } - } - if (tv) { - if (tvisfunc(tv)) { - crec_tailcall(J, rd, tv); - return 0; - } /* NYI: non-function metamethods. */ - } else if ((MMS)rd->data == MM_eq) { /* Fallback cdata pointer comparison. */ - if (sp[0] && sp[1] && ctype_isnum(s[0]->info) == ctype_isnum(s[1]->info)) { - /* Assume true comparison. Fixup and emit pending guard later. */ - lj_ir_set(J, IRTG(IR_EQ, IRT_PTR), sp[0], sp[1]); - J->postproc = LJ_POST_FIXGUARD; - return TREF_TRUE; - } else { - return TREF_FALSE; - } - } - lj_trace_err(J, LJ_TRERR_BADTYPE); - return 0; -} - -void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd) -{ - CTState *cts = ctype_ctsG(J2G(J)); - TRef sp[2]; - CType *s[2]; - MSize i; - for (i = 0; i < 2; i++) { - TRef tr = J->base[i]; - CType *ct = ctype_get(cts, CTID_DOUBLE); - if (!tr) { - lj_trace_err(J, LJ_TRERR_BADTYPE); - } else if (tref_iscdata(tr)) { - CTypeID id = argv2cdata(J, tr, &rd->argv[i])->ctypeid; - IRType t; - ct = ctype_raw(cts, id); - t = crec_ct2irt(cts, ct); - if (ctype_isptr(ct->info)) { /* Resolve pointer or reference. */ - tr = emitir(IRT(IR_FLOAD, t), tr, IRFL_CDATA_PTR); - if (ctype_isref(ct->info)) { - ct = ctype_rawchild(cts, ct); - t = crec_ct2irt(cts, ct); - } - } else if (t == IRT_I64 || t == IRT_U64) { - tr = emitir(IRT(IR_FLOAD, t), tr, IRFL_CDATA_INT64); - lj_needsplit(J); - goto ok; - } else if (t == IRT_INT || t == IRT_U32) { - tr = emitir(IRT(IR_FLOAD, t), tr, IRFL_CDATA_INT); - if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct); - goto ok; - } else if (ctype_isfunc(ct->info)) { - tr = emitir(IRT(IR_FLOAD, IRT_PTR), tr, IRFL_CDATA_PTR); - ct = ctype_get(cts, - lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|id), CTSIZE_PTR)); - goto ok; - } else { - tr = emitir(IRT(IR_ADD, IRT_PTR), tr, lj_ir_kintp(J, sizeof(GCcdata))); - } - if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct); - if (ctype_isnum(ct->info)) { - if (t == IRT_CDATA) { - tr = 0; - } else { - if (t == IRT_I64 || t == IRT_U64) lj_needsplit(J); - tr = emitir(IRT(IR_XLOAD, t), tr, 0); - } - } - } else if (tref_isnil(tr)) { - tr = lj_ir_kptr(J, NULL); - ct = ctype_get(cts, CTID_P_VOID); - } else if (tref_isinteger(tr)) { - ct = ctype_get(cts, CTID_INT32); - } else if (tref_isstr(tr)) { - TRef tr2 = J->base[1-i]; - CTypeID id = argv2cdata(J, tr2, &rd->argv[1-i])->ctypeid; - ct = ctype_raw(cts, id); - if (ctype_isenum(ct->info)) { /* Match string against enum constant. */ - GCstr *str = strV(&rd->argv[i]); - CTSize ofs; - CType *cct = lj_ctype_getfield(cts, ct, str, &ofs); - if (cct && ctype_isconstval(cct->info)) { - /* Specialize to the name of the enum constant. */ - emitir(IRTG(IR_EQ, IRT_STR), tr, lj_ir_kstr(J, str)); - ct = ctype_child(cts, cct); - tr = lj_ir_kint(J, (int32_t)ofs); - } else { /* Interpreter will throw or return false. */ - ct = ctype_get(cts, CTID_P_VOID); - } - } else if (ctype_isptr(ct->info)) { - tr = emitir(IRT(IR_ADD, IRT_PTR), tr, lj_ir_kintp(J, sizeof(GCstr))); - } else { - ct = ctype_get(cts, CTID_P_VOID); - } - } else if (!tref_isnum(tr)) { - tr = 0; - ct = ctype_get(cts, CTID_P_VOID); - } - ok: - s[i] = ct; - sp[i] = tr; - } - { - TRef tr; - if (!(tr = crec_arith_int64(J, sp, s, (MMS)rd->data)) && - !(tr = crec_arith_ptr(J, sp, s, (MMS)rd->data)) && - !(tr = crec_arith_meta(J, sp, s, cts, rd))) - return; - J->base[0] = tr; - /* Fixup cdata comparisons, too. Avoids some cdata escapes. */ - if (J->postproc == LJ_POST_FIXGUARD && frame_iscont(J->L->base-1) && - !irt_isguard(J->guardemit)) { - const BCIns *pc = frame_contpc(J->L->base-1) - 1; - if (bc_op(*pc) <= BC_ISNEP) { - J2G(J)->tmptv.u64 = (uint64_t)(uintptr_t)pc; - J->postproc = LJ_POST_FIXCOMP; - } - } - } -} - -/* -- C library namespace metamethods ------------------------------------- */ - -void LJ_FASTCALL recff_clib_index(jit_State *J, RecordFFData *rd) -{ - CTState *cts = ctype_ctsG(J2G(J)); - if (tref_isudata(J->base[0]) && tref_isstr(J->base[1]) && - udataV(&rd->argv[0])->udtype == UDTYPE_FFI_CLIB) { - CLibrary *cl = (CLibrary *)uddata(udataV(&rd->argv[0])); - GCstr *name = strV(&rd->argv[1]); - CType *ct; - CTypeID id = lj_ctype_getname(cts, &ct, name, CLNS_INDEX); - cTValue *tv = lj_tab_getstr(cl->cache, name); - rd->nres = rd->data; - if (id && tv && !tvisnil(tv)) { - /* Specialize to the symbol name and make the result a constant. */ - emitir(IRTG(IR_EQ, IRT_STR), J->base[1], lj_ir_kstr(J, name)); - if (ctype_isconstval(ct->info)) { - if (ct->size >= 0x80000000u && - (ctype_child(cts, ct)->info & CTF_UNSIGNED)) - J->base[0] = lj_ir_knum(J, (lua_Number)(uint32_t)ct->size); - else - J->base[0] = lj_ir_kint(J, (int32_t)ct->size); - } else if (ctype_isextern(ct->info)) { - CTypeID sid = ctype_cid(ct->info); - void *sp = *(void **)cdataptr(cdataV(tv)); - TRef ptr; - ct = ctype_raw(cts, sid); - if (LJ_64 && !checkptr32(sp)) - ptr = lj_ir_kintp(J, (uintptr_t)sp); - else - ptr = lj_ir_kptr(J, sp); - if (rd->data) { - J->base[0] = crec_tv_ct(J, ct, sid, ptr); - } else { - J->needsnap = 1; - crec_ct_tv(J, ct, ptr, J->base[2], &rd->argv[2]); - } - } else { - J->base[0] = lj_ir_kgc(J, obj2gco(cdataV(tv)), IRT_CDATA); - } - } else { - lj_trace_err(J, LJ_TRERR_NOCACHE); - } - } /* else: interpreter will throw. */ -} - -/* -- FFI library functions ----------------------------------------------- */ - -static TRef crec_toint(jit_State *J, CTState *cts, TRef sp, TValue *sval) -{ - return crec_ct_tv(J, ctype_get(cts, CTID_INT32), 0, sp, sval); -} - -void LJ_FASTCALL recff_ffi_new(jit_State *J, RecordFFData *rd) -{ - crec_alloc(J, rd, argv2ctype(J, J->base[0], &rd->argv[0])); -} - -void LJ_FASTCALL recff_ffi_errno(jit_State *J, RecordFFData *rd) -{ - UNUSED(rd); - if (J->base[0]) - lj_trace_err(J, LJ_TRERR_NYICALL); - J->base[0] = lj_ir_call(J, IRCALL_lj_vm_errno); -} - -void LJ_FASTCALL recff_ffi_string(jit_State *J, RecordFFData *rd) -{ - CTState *cts = ctype_ctsG(J2G(J)); - TRef tr = J->base[0]; - if (tr) { - TRef trlen = J->base[1]; - if (!tref_isnil(trlen)) { - trlen = crec_toint(J, cts, trlen, &rd->argv[1]); - tr = crec_ct_tv(J, ctype_get(cts, CTID_P_CVOID), 0, tr, &rd->argv[0]); - } else { - tr = crec_ct_tv(J, ctype_get(cts, CTID_P_CCHAR), 0, tr, &rd->argv[0]); - trlen = lj_ir_call(J, IRCALL_strlen, tr); - } - J->base[0] = emitir(IRT(IR_XSNEW, IRT_STR), tr, trlen); - } /* else: interpreter will throw. */ -} - -void LJ_FASTCALL recff_ffi_copy(jit_State *J, RecordFFData *rd) -{ - CTState *cts = ctype_ctsG(J2G(J)); - TRef trdst = J->base[0], trsrc = J->base[1], trlen = J->base[2]; - if (trdst && trsrc && (trlen || tref_isstr(trsrc))) { - trdst = crec_ct_tv(J, ctype_get(cts, CTID_P_VOID), 0, trdst, &rd->argv[0]); - trsrc = crec_ct_tv(J, ctype_get(cts, CTID_P_CVOID), 0, trsrc, &rd->argv[1]); - if (trlen) { - trlen = crec_toint(J, cts, trlen, &rd->argv[2]); - } else { - trlen = emitir(IRTI(IR_FLOAD), J->base[1], IRFL_STR_LEN); - trlen = emitir(IRTI(IR_ADD), trlen, lj_ir_kint(J, 1)); - } - rd->nres = 0; - crec_copy(J, trdst, trsrc, trlen, NULL); - } /* else: interpreter will throw. */ -} - -void LJ_FASTCALL recff_ffi_fill(jit_State *J, RecordFFData *rd) -{ - CTState *cts = ctype_ctsG(J2G(J)); - TRef trdst = J->base[0], trlen = J->base[1], trfill = J->base[2]; - if (trdst && trlen) { - CTSize step = 1; - if (tviscdata(&rd->argv[0])) { /* Get alignment of original destination. */ - CTSize sz; - CType *ct = ctype_raw(cts, cdataV(&rd->argv[0])->ctypeid); - if (ctype_isptr(ct->info)) - ct = ctype_rawchild(cts, ct); - step = (1u<argv[0]); - trlen = crec_toint(J, cts, trlen, &rd->argv[1]); - if (trfill) - trfill = crec_toint(J, cts, trfill, &rd->argv[2]); - else - trfill = lj_ir_kint(J, 0); - rd->nres = 0; - crec_fill(J, trdst, trlen, trfill, step); - } /* else: interpreter will throw. */ -} - -void LJ_FASTCALL recff_ffi_typeof(jit_State *J, RecordFFData *rd) -{ - if (tref_iscdata(J->base[0])) { - TRef trid = lj_ir_kint(J, argv2ctype(J, J->base[0], &rd->argv[0])); - J->base[0] = emitir(IRTG(IR_CNEWI, IRT_CDATA), - lj_ir_kint(J, CTID_CTYPEID), trid); - } else { - setfuncV(J->L, &J->errinfo, J->fn); - lj_trace_err_info(J, LJ_TRERR_NYIFFU); - } -} - -void LJ_FASTCALL recff_ffi_istype(jit_State *J, RecordFFData *rd) -{ - argv2ctype(J, J->base[0], &rd->argv[0]); - if (tref_iscdata(J->base[1])) { - argv2ctype(J, J->base[1], &rd->argv[1]); - J->postproc = LJ_POST_FIXBOOL; - J->base[0] = TREF_TRUE; - } else { - J->base[0] = TREF_FALSE; - } -} - -void LJ_FASTCALL recff_ffi_abi(jit_State *J, RecordFFData *rd) -{ - if (tref_isstr(J->base[0])) { - /* Specialize to the ABI string to make the boolean result a constant. */ - emitir(IRTG(IR_EQ, IRT_STR), J->base[0], lj_ir_kstr(J, strV(&rd->argv[0]))); - J->postproc = LJ_POST_FIXBOOL; - J->base[0] = TREF_TRUE; - } else { - lj_trace_err(J, LJ_TRERR_BADTYPE); - } -} - -/* Record ffi.sizeof(), ffi.alignof(), ffi.offsetof(). */ -void LJ_FASTCALL recff_ffi_xof(jit_State *J, RecordFFData *rd) -{ - CTypeID id = argv2ctype(J, J->base[0], &rd->argv[0]); - if (rd->data == FF_ffi_sizeof) { - CType *ct = lj_ctype_rawref(ctype_ctsG(J2G(J)), id); - if (ctype_isvltype(ct->info)) - lj_trace_err(J, LJ_TRERR_BADTYPE); - } else if (rd->data == FF_ffi_offsetof) { /* Specialize to the field name. */ - if (!tref_isstr(J->base[1])) - lj_trace_err(J, LJ_TRERR_BADTYPE); - emitir(IRTG(IR_EQ, IRT_STR), J->base[1], lj_ir_kstr(J, strV(&rd->argv[1]))); - rd->nres = 3; /* Just in case. */ - } - J->postproc = LJ_POST_FIXCONST; - J->base[0] = J->base[1] = J->base[2] = TREF_NIL; -} - -void LJ_FASTCALL recff_ffi_gc(jit_State *J, RecordFFData *rd) -{ - argv2cdata(J, J->base[0], &rd->argv[0]); - if (!J->base[1]) - lj_trace_err(J, LJ_TRERR_BADTYPE); - crec_finalizer(J, J->base[0], J->base[1], &rd->argv[1]); -} - -/* -- 64 bit bit.* library functions -------------------------------------- */ - -/* Determine bit operation type from argument type. */ -static CTypeID crec_bit64_type(CTState *cts, cTValue *tv) -{ - if (tviscdata(tv)) { - CType *ct = lj_ctype_rawref(cts, cdataV(tv)->ctypeid); - if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct); - if ((ct->info & (CTMASK_NUM|CTF_BOOL|CTF_FP|CTF_UNSIGNED)) == - CTINFO(CT_NUM, CTF_UNSIGNED) && ct->size == 8) - return CTID_UINT64; /* Use uint64_t, since it has the highest rank. */ - return CTID_INT64; /* Otherwise use int64_t. */ - } - return 0; /* Use regular 32 bit ops. */ -} - -void LJ_FASTCALL recff_bit64_tobit(jit_State *J, RecordFFData *rd) -{ - CTState *cts = ctype_ctsG(J2G(J)); - TRef tr = crec_ct_tv(J, ctype_get(cts, CTID_INT64), 0, - J->base[0], &rd->argv[0]); - if (!tref_isinteger(tr)) - tr = emitconv(tr, IRT_INT, tref_type(tr), 0); - J->base[0] = tr; -} - -int LJ_FASTCALL recff_bit64_unary(jit_State *J, RecordFFData *rd) -{ - CTState *cts = ctype_ctsG(J2G(J)); - CTypeID id = crec_bit64_type(cts, &rd->argv[0]); - if (id) { - TRef tr = crec_ct_tv(J, ctype_get(cts, id), 0, J->base[0], &rd->argv[0]); - tr = emitir(IRT(rd->data, id-CTID_INT64+IRT_I64), tr, 0); - J->base[0] = emitir(IRTG(IR_CNEWI, IRT_CDATA), lj_ir_kint(J, id), tr); - return 1; - } - return 0; -} - -int LJ_FASTCALL recff_bit64_nary(jit_State *J, RecordFFData *rd) -{ - CTState *cts = ctype_ctsG(J2G(J)); - CTypeID id = 0; - MSize i; - for (i = 0; J->base[i] != 0; i++) { - CTypeID aid = crec_bit64_type(cts, &rd->argv[i]); - if (id < aid) id = aid; /* Determine highest type rank of all arguments. */ - } - if (id) { - CType *ct = ctype_get(cts, id); - uint32_t ot = IRT(rd->data, id-CTID_INT64+IRT_I64); - TRef tr = crec_ct_tv(J, ct, 0, J->base[0], &rd->argv[0]); - for (i = 1; J->base[i] != 0; i++) { - TRef tr2 = crec_ct_tv(J, ct, 0, J->base[i], &rd->argv[i]); - tr = emitir(ot, tr, tr2); - } - J->base[0] = emitir(IRTG(IR_CNEWI, IRT_CDATA), lj_ir_kint(J, id), tr); - return 1; - } - return 0; -} - -int LJ_FASTCALL recff_bit64_shift(jit_State *J, RecordFFData *rd) -{ - CTState *cts = ctype_ctsG(J2G(J)); - CTypeID id; - TRef tsh = 0; - if (J->base[0] && tref_iscdata(J->base[1])) { - tsh = crec_ct_tv(J, ctype_get(cts, CTID_INT64), 0, - J->base[1], &rd->argv[1]); - if (!tref_isinteger(tsh)) - tsh = emitconv(tsh, IRT_INT, tref_type(tsh), 0); - J->base[1] = tsh; - } - id = crec_bit64_type(cts, &rd->argv[0]); - if (id) { - TRef tr = crec_ct_tv(J, ctype_get(cts, id), 0, J->base[0], &rd->argv[0]); - uint32_t op = rd->data; - if (!tsh) tsh = lj_opt_narrow_tobit(J, J->base[1]); - if (!(op < IR_BROL ? LJ_TARGET_MASKSHIFT : LJ_TARGET_MASKROT) && - !tref_isk(tsh)) - tsh = emitir(IRTI(IR_BAND), tsh, lj_ir_kint(J, 63)); -#ifdef LJ_TARGET_UNIFYROT - if (op == (LJ_TARGET_UNIFYROT == 1 ? IR_BROR : IR_BROL)) { - op = LJ_TARGET_UNIFYROT == 1 ? IR_BROL : IR_BROR; - tsh = emitir(IRTI(IR_NEG), tsh, tsh); - } -#endif - tr = emitir(IRT(op, id-CTID_INT64+IRT_I64), tr, tsh); - J->base[0] = emitir(IRTG(IR_CNEWI, IRT_CDATA), lj_ir_kint(J, id), tr); - return 1; - } - return 0; -} - -TRef recff_bit64_tohex(jit_State *J, RecordFFData *rd, TRef hdr) -{ - CTState *cts = ctype_ctsG(J2G(J)); - CTypeID id = crec_bit64_type(cts, &rd->argv[0]); - TRef tr, trsf = J->base[1]; - SFormat sf = (STRFMT_UINT|STRFMT_T_HEX); - int32_t n; - if (trsf) { - CTypeID id2 = 0; - n = (int32_t)lj_carith_check64(J->L, 2, &id2); - if (id2) - trsf = crec_ct_tv(J, ctype_get(cts, CTID_INT32), 0, trsf, &rd->argv[1]); - else - trsf = lj_opt_narrow_tobit(J, trsf); - emitir(IRTGI(IR_EQ), trsf, lj_ir_kint(J, n)); /* Specialize to n. */ - } else { - n = id ? 16 : 8; - } - if (n < 0) { n = -n; sf |= STRFMT_F_UPPER; } - sf |= ((SFormat)((n+1)&255) << STRFMT_SH_PREC); - if (id) { - tr = crec_ct_tv(J, ctype_get(cts, id), 0, J->base[0], &rd->argv[0]); - if (n < 16) - tr = emitir(IRT(IR_BAND, IRT_U64), tr, - lj_ir_kint64(J, ((uint64_t)1 << 4*n)-1)); - } else { - tr = lj_opt_narrow_tobit(J, J->base[0]); - if (n < 8) - tr = emitir(IRTI(IR_BAND), tr, lj_ir_kint(J, (int32_t)((1u << 4*n)-1))); - tr = emitconv(tr, IRT_U64, IRT_INT, 0); /* No sign-extension. */ - lj_needsplit(J); - } - return lj_ir_call(J, IRCALL_lj_strfmt_putfxint, hdr, lj_ir_kint(J, sf), tr); -} - -/* -- Miscellaneous library functions ------------------------------------- */ - -void LJ_FASTCALL lj_crecord_tonumber(jit_State *J, RecordFFData *rd) -{ - CTState *cts = ctype_ctsG(J2G(J)); - CType *d, *ct = lj_ctype_rawref(cts, cdataV(&rd->argv[0])->ctypeid); - if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct); - if (ctype_isnum(ct->info) || ctype_iscomplex(ct->info)) { - if (ctype_isinteger_or_bool(ct->info) && ct->size <= 4 && - !(ct->size == 4 && (ct->info & CTF_UNSIGNED))) - d = ctype_get(cts, CTID_INT32); - else - d = ctype_get(cts, CTID_DOUBLE); - J->base[0] = crec_ct_tv(J, d, 0, J->base[0], &rd->argv[0]); - } else { - /* Specialize to the ctype that couldn't be converted. */ - argv2cdata(J, J->base[0], &rd->argv[0]); - J->base[0] = TREF_NIL; - } -} - -#undef IR -#undef emitir -#undef emitconv - -#endif diff --git a/lib/LuaJIT/src/lj_crecord.h b/lib/LuaJIT/src/lj_crecord.h deleted file mode 100644 index c165def..0000000 --- a/lib/LuaJIT/src/lj_crecord.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -** Trace recorder for C data operations. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_CRECORD_H -#define _LJ_CRECORD_H - -#include "lj_obj.h" -#include "lj_jit.h" -#include "lj_ffrecord.h" - -#if LJ_HASJIT && LJ_HASFFI -LJ_FUNC void LJ_FASTCALL recff_cdata_index(jit_State *J, RecordFFData *rd); -LJ_FUNC void LJ_FASTCALL recff_cdata_call(jit_State *J, RecordFFData *rd); -LJ_FUNC void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd); -LJ_FUNC void LJ_FASTCALL recff_clib_index(jit_State *J, RecordFFData *rd); -LJ_FUNC void LJ_FASTCALL recff_ffi_new(jit_State *J, RecordFFData *rd); -LJ_FUNC void LJ_FASTCALL recff_ffi_errno(jit_State *J, RecordFFData *rd); -LJ_FUNC void LJ_FASTCALL recff_ffi_string(jit_State *J, RecordFFData *rd); -LJ_FUNC void LJ_FASTCALL recff_ffi_copy(jit_State *J, RecordFFData *rd); -LJ_FUNC void LJ_FASTCALL recff_ffi_fill(jit_State *J, RecordFFData *rd); -LJ_FUNC void LJ_FASTCALL recff_ffi_typeof(jit_State *J, RecordFFData *rd); -LJ_FUNC void LJ_FASTCALL recff_ffi_istype(jit_State *J, RecordFFData *rd); -LJ_FUNC void LJ_FASTCALL recff_ffi_abi(jit_State *J, RecordFFData *rd); -LJ_FUNC void LJ_FASTCALL recff_ffi_xof(jit_State *J, RecordFFData *rd); -LJ_FUNC void LJ_FASTCALL recff_ffi_gc(jit_State *J, RecordFFData *rd); - -LJ_FUNC void LJ_FASTCALL recff_bit64_tobit(jit_State *J, RecordFFData *rd); -LJ_FUNC int LJ_FASTCALL recff_bit64_unary(jit_State *J, RecordFFData *rd); -LJ_FUNC int LJ_FASTCALL recff_bit64_nary(jit_State *J, RecordFFData *rd); -LJ_FUNC int LJ_FASTCALL recff_bit64_shift(jit_State *J, RecordFFData *rd); -LJ_FUNC TRef recff_bit64_tohex(jit_State *J, RecordFFData *rd, TRef hdr); - -LJ_FUNC void LJ_FASTCALL lj_crecord_tonumber(jit_State *J, RecordFFData *rd); -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_ctype.c b/lib/LuaJIT/src/lj_ctype.c deleted file mode 100644 index 0ea89c7..0000000 --- a/lib/LuaJIT/src/lj_ctype.c +++ /dev/null @@ -1,637 +0,0 @@ -/* -** C type management. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#include "lj_obj.h" - -#if LJ_HASFFI - -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_str.h" -#include "lj_tab.h" -#include "lj_strfmt.h" -#include "lj_ctype.h" -#include "lj_ccallback.h" -#include "lj_buf.h" - -/* -- C type definitions -------------------------------------------------- */ - -/* Predefined typedefs. */ -#define CTTDDEF(_) \ - /* Vararg handling. */ \ - _("va_list", P_VOID) \ - _("__builtin_va_list", P_VOID) \ - _("__gnuc_va_list", P_VOID) \ - /* From stddef.h. */ \ - _("ptrdiff_t", INT_PSZ) \ - _("size_t", UINT_PSZ) \ - _("wchar_t", WCHAR) \ - /* Subset of stdint.h. */ \ - _("int8_t", INT8) \ - _("int16_t", INT16) \ - _("int32_t", INT32) \ - _("int64_t", INT64) \ - _("uint8_t", UINT8) \ - _("uint16_t", UINT16) \ - _("uint32_t", UINT32) \ - _("uint64_t", UINT64) \ - _("intptr_t", INT_PSZ) \ - _("uintptr_t", UINT_PSZ) \ - /* From POSIX. */ \ - _("ssize_t", INT_PSZ) \ - /* End of typedef list. */ - -/* Keywords (only the ones we actually care for). */ -#define CTKWDEF(_) \ - /* Type specifiers. */ \ - _("void", -1, CTOK_VOID) \ - _("_Bool", 0, CTOK_BOOL) \ - _("bool", 1, CTOK_BOOL) \ - _("char", 1, CTOK_CHAR) \ - _("int", 4, CTOK_INT) \ - _("__int8", 1, CTOK_INT) \ - _("__int16", 2, CTOK_INT) \ - _("__int32", 4, CTOK_INT) \ - _("__int64", 8, CTOK_INT) \ - _("float", 4, CTOK_FP) \ - _("double", 8, CTOK_FP) \ - _("long", 0, CTOK_LONG) \ - _("short", 0, CTOK_SHORT) \ - _("_Complex", 0, CTOK_COMPLEX) \ - _("complex", 0, CTOK_COMPLEX) \ - _("__complex", 0, CTOK_COMPLEX) \ - _("__complex__", 0, CTOK_COMPLEX) \ - _("signed", 0, CTOK_SIGNED) \ - _("__signed", 0, CTOK_SIGNED) \ - _("__signed__", 0, CTOK_SIGNED) \ - _("unsigned", 0, CTOK_UNSIGNED) \ - /* Type qualifiers. */ \ - _("const", 0, CTOK_CONST) \ - _("__const", 0, CTOK_CONST) \ - _("__const__", 0, CTOK_CONST) \ - _("volatile", 0, CTOK_VOLATILE) \ - _("__volatile", 0, CTOK_VOLATILE) \ - _("__volatile__", 0, CTOK_VOLATILE) \ - _("restrict", 0, CTOK_RESTRICT) \ - _("__restrict", 0, CTOK_RESTRICT) \ - _("__restrict__", 0, CTOK_RESTRICT) \ - _("inline", 0, CTOK_INLINE) \ - _("__inline", 0, CTOK_INLINE) \ - _("__inline__", 0, CTOK_INLINE) \ - /* Storage class specifiers. */ \ - _("typedef", 0, CTOK_TYPEDEF) \ - _("extern", 0, CTOK_EXTERN) \ - _("static", 0, CTOK_STATIC) \ - _("auto", 0, CTOK_AUTO) \ - _("register", 0, CTOK_REGISTER) \ - /* GCC Attributes. */ \ - _("__extension__", 0, CTOK_EXTENSION) \ - _("__attribute", 0, CTOK_ATTRIBUTE) \ - _("__attribute__", 0, CTOK_ATTRIBUTE) \ - _("asm", 0, CTOK_ASM) \ - _("__asm", 0, CTOK_ASM) \ - _("__asm__", 0, CTOK_ASM) \ - /* MSVC Attributes. */ \ - _("__declspec", 0, CTOK_DECLSPEC) \ - _("__cdecl", CTCC_CDECL, CTOK_CCDECL) \ - _("__thiscall", CTCC_THISCALL, CTOK_CCDECL) \ - _("__fastcall", CTCC_FASTCALL, CTOK_CCDECL) \ - _("__stdcall", CTCC_STDCALL, CTOK_CCDECL) \ - _("__ptr32", 4, CTOK_PTRSZ) \ - _("__ptr64", 8, CTOK_PTRSZ) \ - /* Other type specifiers. */ \ - _("struct", 0, CTOK_STRUCT) \ - _("union", 0, CTOK_UNION) \ - _("enum", 0, CTOK_ENUM) \ - /* Operators. */ \ - _("sizeof", 0, CTOK_SIZEOF) \ - _("__alignof", 0, CTOK_ALIGNOF) \ - _("__alignof__", 0, CTOK_ALIGNOF) \ - /* End of keyword list. */ - -/* Type info for predefined types. Size merged in. */ -static CTInfo lj_ctype_typeinfo[] = { -#define CTTYINFODEF(id, sz, ct, info) CTINFO((ct),(((sz)&0x3fu)<<10)+(info)), -#define CTTDINFODEF(name, id) CTINFO(CT_TYPEDEF, CTID_##id), -#define CTKWINFODEF(name, sz, kw) CTINFO(CT_KW,(((sz)&0x3fu)<<10)+(kw)), -CTTYDEF(CTTYINFODEF) -CTTDDEF(CTTDINFODEF) -CTKWDEF(CTKWINFODEF) -#undef CTTYINFODEF -#undef CTTDINFODEF -#undef CTKWINFODEF - 0 -}; - -/* Predefined type names collected in a single string. */ -static const char * const lj_ctype_typenames = -#define CTTDNAMEDEF(name, id) name "\0" -#define CTKWNAMEDEF(name, sz, cds) name "\0" -CTTDDEF(CTTDNAMEDEF) -CTKWDEF(CTKWNAMEDEF) -#undef CTTDNAMEDEF -#undef CTKWNAMEDEF -; - -#define CTTYPEINFO_NUM (sizeof(lj_ctype_typeinfo)/sizeof(CTInfo)-1) -#ifdef LUAJIT_CTYPE_CHECK_ANCHOR -#define CTTYPETAB_MIN CTTYPEINFO_NUM -#else -#define CTTYPETAB_MIN 128 -#endif - -/* -- C type interning ---------------------------------------------------- */ - -#define ct_hashtype(info, size) (hashrot(info, size) & CTHASH_MASK) -#define ct_hashname(name) \ - (hashrot(u32ptr(name), u32ptr(name) + HASH_BIAS) & CTHASH_MASK) - -/* Create new type element. */ -CTypeID lj_ctype_new(CTState *cts, CType **ctp) -{ - CTypeID id = cts->top; - CType *ct; - lua_assert(cts->L); - if (LJ_UNLIKELY(id >= cts->sizetab)) { - if (id >= CTID_MAX) lj_err_msg(cts->L, LJ_ERR_TABOV); -#ifdef LUAJIT_CTYPE_CHECK_ANCHOR - ct = lj_mem_newvec(cts->L, id+1, CType); - memcpy(ct, cts->tab, id*sizeof(CType)); - memset(cts->tab, 0, id*sizeof(CType)); - lj_mem_freevec(cts->g, cts->tab, cts->sizetab, CType); - cts->tab = ct; - cts->sizetab = id+1; -#else - lj_mem_growvec(cts->L, cts->tab, cts->sizetab, CTID_MAX, CType); -#endif - } - cts->top = id+1; - *ctp = ct = &cts->tab[id]; - ct->info = 0; - ct->size = 0; - ct->sib = 0; - ct->next = 0; - setgcrefnull(ct->name); - return id; -} - -/* Intern a type element. */ -CTypeID lj_ctype_intern(CTState *cts, CTInfo info, CTSize size) -{ - uint32_t h = ct_hashtype(info, size); - CTypeID id = cts->hash[h]; - lua_assert(cts->L); - while (id) { - CType *ct = ctype_get(cts, id); - if (ct->info == info && ct->size == size) - return id; - id = ct->next; - } - id = cts->top; - if (LJ_UNLIKELY(id >= cts->sizetab)) { - if (id >= CTID_MAX) lj_err_msg(cts->L, LJ_ERR_TABOV); - lj_mem_growvec(cts->L, cts->tab, cts->sizetab, CTID_MAX, CType); - } - cts->top = id+1; - cts->tab[id].info = info; - cts->tab[id].size = size; - cts->tab[id].sib = 0; - cts->tab[id].next = cts->hash[h]; - setgcrefnull(cts->tab[id].name); - cts->hash[h] = (CTypeID1)id; - return id; -} - -/* Add type element to hash table. */ -static void ctype_addtype(CTState *cts, CType *ct, CTypeID id) -{ - uint32_t h = ct_hashtype(ct->info, ct->size); - ct->next = cts->hash[h]; - cts->hash[h] = (CTypeID1)id; -} - -/* Add named element to hash table. */ -void lj_ctype_addname(CTState *cts, CType *ct, CTypeID id) -{ - uint32_t h = ct_hashname(gcref(ct->name)); - ct->next = cts->hash[h]; - cts->hash[h] = (CTypeID1)id; -} - -/* Get a C type by name, matching the type mask. */ -CTypeID lj_ctype_getname(CTState *cts, CType **ctp, GCstr *name, uint32_t tmask) -{ - CTypeID id = cts->hash[ct_hashname(name)]; - while (id) { - CType *ct = ctype_get(cts, id); - if (gcref(ct->name) == obj2gco(name) && - ((tmask >> ctype_type(ct->info)) & 1)) { - *ctp = ct; - return id; - } - id = ct->next; - } - *ctp = &cts->tab[0]; /* Simplify caller logic. ctype_get() would assert. */ - return 0; -} - -/* Get a struct/union/enum/function field by name. */ -CType *lj_ctype_getfieldq(CTState *cts, CType *ct, GCstr *name, CTSize *ofs, - CTInfo *qual) -{ - while (ct->sib) { - ct = ctype_get(cts, ct->sib); - if (gcref(ct->name) == obj2gco(name)) { - *ofs = ct->size; - return ct; - } - if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) { - CType *fct, *cct = ctype_child(cts, ct); - CTInfo q = 0; - while (ctype_isattrib(cct->info)) { - if (ctype_attrib(cct->info) == CTA_QUAL) q |= cct->size; - cct = ctype_child(cts, cct); - } - fct = lj_ctype_getfieldq(cts, cct, name, ofs, qual); - if (fct) { - if (qual) *qual |= q; - *ofs += ct->size; - return fct; - } - } - } - return NULL; /* Not found. */ -} - -/* -- C type information -------------------------------------------------- */ - -/* Follow references and get raw type for a C type ID. */ -CType *lj_ctype_rawref(CTState *cts, CTypeID id) -{ - CType *ct = ctype_get(cts, id); - while (ctype_isattrib(ct->info) || ctype_isref(ct->info)) - ct = ctype_child(cts, ct); - return ct; -} - -/* Get size for a C type ID. Does NOT support VLA/VLS. */ -CTSize lj_ctype_size(CTState *cts, CTypeID id) -{ - CType *ct = ctype_raw(cts, id); - return ctype_hassize(ct->info) ? ct->size : CTSIZE_INVALID; -} - -/* Get size for a variable-length C type. Does NOT support other C types. */ -CTSize lj_ctype_vlsize(CTState *cts, CType *ct, CTSize nelem) -{ - uint64_t xsz = 0; - if (ctype_isstruct(ct->info)) { - CTypeID arrid = 0, fid = ct->sib; - xsz = ct->size; /* Add the struct size. */ - while (fid) { - CType *ctf = ctype_get(cts, fid); - if (ctype_type(ctf->info) == CT_FIELD) - arrid = ctype_cid(ctf->info); /* Remember last field of VLS. */ - fid = ctf->sib; - } - ct = ctype_raw(cts, arrid); - } - lua_assert(ctype_isvlarray(ct->info)); /* Must be a VLA. */ - ct = ctype_rawchild(cts, ct); /* Get array element. */ - lua_assert(ctype_hassize(ct->info)); - /* Calculate actual size of VLA and check for overflow. */ - xsz += (uint64_t)ct->size * nelem; - return xsz < 0x80000000u ? (CTSize)xsz : CTSIZE_INVALID; -} - -/* Get type, qualifiers, size and alignment for a C type ID. */ -CTInfo lj_ctype_info(CTState *cts, CTypeID id, CTSize *szp) -{ - CTInfo qual = 0; - CType *ct = ctype_get(cts, id); - for (;;) { - CTInfo info = ct->info; - if (ctype_isenum(info)) { - /* Follow child. Need to look at its attributes, too. */ - } else if (ctype_isattrib(info)) { - if (ctype_isxattrib(info, CTA_QUAL)) - qual |= ct->size; - else if (ctype_isxattrib(info, CTA_ALIGN) && !(qual & CTFP_ALIGNED)) - qual |= CTFP_ALIGNED + CTALIGN(ct->size); - } else { - if (!(qual & CTFP_ALIGNED)) qual |= (info & CTF_ALIGN); - qual |= (info & ~(CTF_ALIGN|CTMASK_CID)); - lua_assert(ctype_hassize(info) || ctype_isfunc(info)); - *szp = ctype_isfunc(info) ? CTSIZE_INVALID : ct->size; - break; - } - ct = ctype_get(cts, ctype_cid(info)); - } - return qual; -} - -/* Get ctype metamethod. */ -cTValue *lj_ctype_meta(CTState *cts, CTypeID id, MMS mm) -{ - CType *ct = ctype_get(cts, id); - cTValue *tv; - while (ctype_isattrib(ct->info) || ctype_isref(ct->info)) { - id = ctype_cid(ct->info); - ct = ctype_get(cts, id); - } - if (ctype_isptr(ct->info) && - ctype_isfunc(ctype_get(cts, ctype_cid(ct->info))->info)) - tv = lj_tab_getstr(cts->miscmap, &cts->g->strempty); - else - tv = lj_tab_getinth(cts->miscmap, -(int32_t)id); - if (tv && tvistab(tv) && - (tv = lj_tab_getstr(tabV(tv), mmname_str(cts->g, mm))) && !tvisnil(tv)) - return tv; - return NULL; -} - -/* -- C type representation ----------------------------------------------- */ - -/* Fixed max. length of a C type representation. */ -#define CTREPR_MAX 512 - -typedef struct CTRepr { - char *pb, *pe; - CTState *cts; - lua_State *L; - int needsp; - int ok; - char buf[CTREPR_MAX]; -} CTRepr; - -/* Prepend string. */ -static void ctype_prepstr(CTRepr *ctr, const char *str, MSize len) -{ - char *p = ctr->pb; - if (ctr->buf + len+1 > p) { ctr->ok = 0; return; } - if (ctr->needsp) *--p = ' '; - ctr->needsp = 1; - p -= len; - while (len-- > 0) p[len] = str[len]; - ctr->pb = p; -} - -#define ctype_preplit(ctr, str) ctype_prepstr((ctr), "" str, sizeof(str)-1) - -/* Prepend char. */ -static void ctype_prepc(CTRepr *ctr, int c) -{ - if (ctr->buf >= ctr->pb) { ctr->ok = 0; return; } - *--ctr->pb = c; -} - -/* Prepend number. */ -static void ctype_prepnum(CTRepr *ctr, uint32_t n) -{ - char *p = ctr->pb; - if (ctr->buf + 10+1 > p) { ctr->ok = 0; return; } - do { *--p = (char)('0' + n % 10); } while (n /= 10); - ctr->pb = p; - ctr->needsp = 0; -} - -/* Append char. */ -static void ctype_appc(CTRepr *ctr, int c) -{ - if (ctr->pe >= ctr->buf + CTREPR_MAX) { ctr->ok = 0; return; } - *ctr->pe++ = c; -} - -/* Append number. */ -static void ctype_appnum(CTRepr *ctr, uint32_t n) -{ - char buf[10]; - char *p = buf+sizeof(buf); - char *q = ctr->pe; - if (q > ctr->buf + CTREPR_MAX - 10) { ctr->ok = 0; return; } - do { *--p = (char)('0' + n % 10); } while (n /= 10); - do { *q++ = *p++; } while (p < buf+sizeof(buf)); - ctr->pe = q; -} - -/* Prepend qualifiers. */ -static void ctype_prepqual(CTRepr *ctr, CTInfo info) -{ - if ((info & CTF_VOLATILE)) ctype_preplit(ctr, "volatile"); - if ((info & CTF_CONST)) ctype_preplit(ctr, "const"); -} - -/* Prepend named type. */ -static void ctype_preptype(CTRepr *ctr, CType *ct, CTInfo qual, const char *t) -{ - if (gcref(ct->name)) { - GCstr *str = gco2str(gcref(ct->name)); - ctype_prepstr(ctr, strdata(str), str->len); - } else { - if (ctr->needsp) ctype_prepc(ctr, ' '); - ctype_prepnum(ctr, ctype_typeid(ctr->cts, ct)); - ctr->needsp = 1; - } - ctype_prepstr(ctr, t, (MSize)strlen(t)); - ctype_prepqual(ctr, qual); -} - -static void ctype_repr(CTRepr *ctr, CTypeID id) -{ - CType *ct = ctype_get(ctr->cts, id); - CTInfo qual = 0; - int ptrto = 0; - for (;;) { - CTInfo info = ct->info; - CTSize size = ct->size; - switch (ctype_type(info)) { - case CT_NUM: - if ((info & CTF_BOOL)) { - ctype_preplit(ctr, "bool"); - } else if ((info & CTF_FP)) { - if (size == sizeof(double)) ctype_preplit(ctr, "double"); - else if (size == sizeof(float)) ctype_preplit(ctr, "float"); - else ctype_preplit(ctr, "long double"); - } else if (size == 1) { - if (!((info ^ CTF_UCHAR) & CTF_UNSIGNED)) ctype_preplit(ctr, "char"); - else if (CTF_UCHAR) ctype_preplit(ctr, "signed char"); - else ctype_preplit(ctr, "unsigned char"); - } else if (size < 8) { - if (size == 4) ctype_preplit(ctr, "int"); - else ctype_preplit(ctr, "short"); - if ((info & CTF_UNSIGNED)) ctype_preplit(ctr, "unsigned"); - } else { - ctype_preplit(ctr, "_t"); - ctype_prepnum(ctr, size*8); - ctype_preplit(ctr, "int"); - if ((info & CTF_UNSIGNED)) ctype_prepc(ctr, 'u'); - } - ctype_prepqual(ctr, (qual|info)); - return; - case CT_VOID: - ctype_preplit(ctr, "void"); - ctype_prepqual(ctr, (qual|info)); - return; - case CT_STRUCT: - ctype_preptype(ctr, ct, qual, (info & CTF_UNION) ? "union" : "struct"); - return; - case CT_ENUM: - if (id == CTID_CTYPEID) { - ctype_preplit(ctr, "ctype"); - return; - } - ctype_preptype(ctr, ct, qual, "enum"); - return; - case CT_ATTRIB: - if (ctype_attrib(info) == CTA_QUAL) qual |= size; - break; - case CT_PTR: - if ((info & CTF_REF)) { - ctype_prepc(ctr, '&'); - } else { - ctype_prepqual(ctr, (qual|info)); - if (LJ_64 && size == 4) ctype_preplit(ctr, "__ptr32"); - ctype_prepc(ctr, '*'); - } - qual = 0; - ptrto = 1; - ctr->needsp = 1; - break; - case CT_ARRAY: - if (ctype_isrefarray(info)) { - ctr->needsp = 1; - if (ptrto) { ptrto = 0; ctype_prepc(ctr, '('); ctype_appc(ctr, ')'); } - ctype_appc(ctr, '['); - if (size != CTSIZE_INVALID) { - CTSize csize = ctype_child(ctr->cts, ct)->size; - ctype_appnum(ctr, csize ? size/csize : 0); - } else if ((info & CTF_VLA)) { - ctype_appc(ctr, '?'); - } - ctype_appc(ctr, ']'); - } else if ((info & CTF_COMPLEX)) { - if (size == 2*sizeof(float)) ctype_preplit(ctr, "float"); - ctype_preplit(ctr, "complex"); - return; - } else { - ctype_preplit(ctr, ")))"); - ctype_prepnum(ctr, size); - ctype_preplit(ctr, "__attribute__((vector_size("); - } - break; - case CT_FUNC: - ctr->needsp = 1; - if (ptrto) { ptrto = 0; ctype_prepc(ctr, '('); ctype_appc(ctr, ')'); } - ctype_appc(ctr, '('); - ctype_appc(ctr, ')'); - break; - default: - lua_assert(0); - break; - } - ct = ctype_get(ctr->cts, ctype_cid(info)); - } -} - -/* Return a printable representation of a C type. */ -GCstr *lj_ctype_repr(lua_State *L, CTypeID id, GCstr *name) -{ - global_State *g = G(L); - CTRepr ctr; - ctr.pb = ctr.pe = &ctr.buf[CTREPR_MAX/2]; - ctr.cts = ctype_ctsG(g); - ctr.L = L; - ctr.ok = 1; - ctr.needsp = 0; - if (name) ctype_prepstr(&ctr, strdata(name), name->len); - ctype_repr(&ctr, id); - if (LJ_UNLIKELY(!ctr.ok)) return lj_str_newlit(L, "?"); - return lj_str_new(L, ctr.pb, ctr.pe - ctr.pb); -} - -/* Convert int64_t/uint64_t to string with 'LL' or 'ULL' suffix. */ -GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned) -{ - char buf[1+20+3]; - char *p = buf+sizeof(buf); - int sign = 0; - *--p = 'L'; *--p = 'L'; - if (isunsigned) { - *--p = 'U'; - } else if ((int64_t)n < 0) { - n = (uint64_t)-(int64_t)n; - sign = 1; - } - do { *--p = (char)('0' + n % 10); } while (n /= 10); - if (sign) *--p = '-'; - return lj_str_new(L, p, (size_t)(buf+sizeof(buf)-p)); -} - -/* Convert complex to string with 'i' or 'I' suffix. */ -GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size) -{ - SBuf *sb = lj_buf_tmp_(L); - TValue re, im; - if (size == 2*sizeof(double)) { - re.n = *(double *)sp; im.n = ((double *)sp)[1]; - } else { - re.n = (double)*(float *)sp; im.n = (double)((float *)sp)[1]; - } - lj_strfmt_putfnum(sb, STRFMT_G14, re.n); - if (!(im.u32.hi & 0x80000000u) || im.n != im.n) lj_buf_putchar(sb, '+'); - lj_strfmt_putfnum(sb, STRFMT_G14, im.n); - lj_buf_putchar(sb, sbufP(sb)[-1] >= 'a' ? 'I' : 'i'); - return lj_buf_str(L, sb); -} - -/* -- C type state -------------------------------------------------------- */ - -/* Initialize C type table and state. */ -CTState *lj_ctype_init(lua_State *L) -{ - CTState *cts = lj_mem_newt(L, sizeof(CTState), CTState); - CType *ct = lj_mem_newvec(L, CTTYPETAB_MIN, CType); - const char *name = lj_ctype_typenames; - CTypeID id; - memset(cts, 0, sizeof(CTState)); - cts->tab = ct; - cts->sizetab = CTTYPETAB_MIN; - cts->top = CTTYPEINFO_NUM; - cts->L = NULL; - cts->g = G(L); - for (id = 0; id < CTTYPEINFO_NUM; id++, ct++) { - CTInfo info = lj_ctype_typeinfo[id]; - ct->size = (CTSize)((int32_t)(info << 16) >> 26); - ct->info = info & 0xffff03ffu; - ct->sib = 0; - if (ctype_type(info) == CT_KW || ctype_istypedef(info)) { - size_t len = strlen(name); - GCstr *str = lj_str_new(L, name, len); - ctype_setname(ct, str); - name += len+1; - lj_ctype_addname(cts, ct, id); - } else { - setgcrefnull(ct->name); - ct->next = 0; - if (!ctype_isenum(info)) ctype_addtype(cts, ct, id); - } - } - setmref(G(L)->ctype_state, cts); - return cts; -} - -/* Free C type table and state. */ -void lj_ctype_freestate(global_State *g) -{ - CTState *cts = ctype_ctsG(g); - if (cts) { - lj_ccallback_mcode_free(cts); - lj_mem_freevec(g, cts->tab, cts->sizetab, CType); - lj_mem_freevec(g, cts->cb.cbid, cts->cb.sizeid, CTypeID1); - lj_mem_freet(g, cts); - } -} - -#endif diff --git a/lib/LuaJIT/src/lj_ctype.h b/lib/LuaJIT/src/lj_ctype.h deleted file mode 100644 index 0c220a8..0000000 --- a/lib/LuaJIT/src/lj_ctype.h +++ /dev/null @@ -1,461 +0,0 @@ -/* -** C type management. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_CTYPE_H -#define _LJ_CTYPE_H - -#include "lj_obj.h" -#include "lj_gc.h" - -#if LJ_HASFFI - -/* -- C type definitions -------------------------------------------------- */ - -/* C type numbers. Highest 4 bits of C type info. ORDER CT. */ -enum { - /* Externally visible types. */ - CT_NUM, /* Integer or floating-point numbers. */ - CT_STRUCT, /* Struct or union. */ - CT_PTR, /* Pointer or reference. */ - CT_ARRAY, /* Array or complex type. */ - CT_MAYCONVERT = CT_ARRAY, - CT_VOID, /* Void type. */ - CT_ENUM, /* Enumeration. */ - CT_HASSIZE = CT_ENUM, /* Last type where ct->size holds the actual size. */ - CT_FUNC, /* Function. */ - CT_TYPEDEF, /* Typedef. */ - CT_ATTRIB, /* Miscellaneous attributes. */ - /* Internal element types. */ - CT_FIELD, /* Struct/union field or function parameter. */ - CT_BITFIELD, /* Struct/union bitfield. */ - CT_CONSTVAL, /* Constant value. */ - CT_EXTERN, /* External reference. */ - CT_KW /* Keyword. */ -}; - -LJ_STATIC_ASSERT(((int)CT_PTR & (int)CT_ARRAY) == CT_PTR); -LJ_STATIC_ASSERT(((int)CT_STRUCT & (int)CT_ARRAY) == CT_STRUCT); - -/* -** ---------- info ------------ -** |type flags... A cid | size | sib | next | name | -** +----------------------------+--------+-------+-------+-------+-- -** |NUM BFcvUL.. A | size | | type | | -** |STRUCT ..cvU..V A | size | field | name? | name? | -** |PTR ..cvR... A cid | size | | type | | -** |ARRAY VCcv...V A cid | size | | type | | -** |VOID ..cv.... A | size | | type | | -** |ENUM A cid | size | const | name? | name? | -** |FUNC ....VS.. cc cid | nargs | field | name? | name? | -** |TYPEDEF cid | | | name | name | -** |ATTRIB attrnum cid | attr | sib? | type? | | -** |FIELD cid | offset | field | | name? | -** |BITFIELD B.cvU csz bsz pos | offset | field | | name? | -** |CONSTVAL c cid | value | const | name | name | -** |EXTERN cid | | sib? | name | name | -** |KW tok | size | | name | name | -** +----------------------------+--------+-------+-------+-------+-- -** ^^ ^^--- bits used for C type conversion dispatch -*/ - -/* C type info flags. TFFArrrr */ -#define CTF_BOOL 0x08000000u /* Boolean: NUM, BITFIELD. */ -#define CTF_FP 0x04000000u /* Floating-point: NUM. */ -#define CTF_CONST 0x02000000u /* Const qualifier. */ -#define CTF_VOLATILE 0x01000000u /* Volatile qualifier. */ -#define CTF_UNSIGNED 0x00800000u /* Unsigned: NUM, BITFIELD. */ -#define CTF_LONG 0x00400000u /* Long: NUM. */ -#define CTF_VLA 0x00100000u /* Variable-length: ARRAY, STRUCT. */ -#define CTF_REF 0x00800000u /* Reference: PTR. */ -#define CTF_VECTOR 0x08000000u /* Vector: ARRAY. */ -#define CTF_COMPLEX 0x04000000u /* Complex: ARRAY. */ -#define CTF_UNION 0x00800000u /* Union: STRUCT. */ -#define CTF_VARARG 0x00800000u /* Vararg: FUNC. */ -#define CTF_SSEREGPARM 0x00400000u /* SSE register parameters: FUNC. */ - -#define CTF_QUAL (CTF_CONST|CTF_VOLATILE) -#define CTF_ALIGN (CTMASK_ALIGN< 0 ? CTF_UNSIGNED : 0) - -/* Flags used in parser. .F.Ammvf cp->attr */ -#define CTFP_ALIGNED 0x00000001u /* cp->attr + ALIGN */ -#define CTFP_PACKED 0x00000002u /* cp->attr */ -/* ...C...f cp->fattr */ -#define CTFP_CCONV 0x00000001u /* cp->fattr + CCONV/[SSE]REGPARM */ - -/* C type info bitfields. */ -#define CTMASK_CID 0x0000ffffu /* Max. 65536 type IDs. */ -#define CTMASK_NUM 0xf0000000u /* Max. 16 type numbers. */ -#define CTSHIFT_NUM 28 -#define CTMASK_ALIGN 15 /* Max. alignment is 2^15. */ -#define CTSHIFT_ALIGN 16 -#define CTMASK_ATTRIB 255 /* Max. 256 attributes. */ -#define CTSHIFT_ATTRIB 16 -#define CTMASK_CCONV 3 /* Max. 4 calling conventions. */ -#define CTSHIFT_CCONV 16 -#define CTMASK_REGPARM 3 /* Max. 0-3 regparms. */ -#define CTSHIFT_REGPARM 18 -/* Bitfields only used in parser. */ -#define CTMASK_VSIZEP 15 /* Max. vector size is 2^15. */ -#define CTSHIFT_VSIZEP 4 -#define CTMASK_MSIZEP 255 /* Max. type size (via mode) is 128. */ -#define CTSHIFT_MSIZEP 8 - -/* Info bits for BITFIELD. Max. size of bitfield is 64 bits. */ -#define CTBSZ_MAX 32 /* Max. size of bitfield is 32 bit. */ -#define CTBSZ_FIELD 127 /* Temp. marker for regular field. */ -#define CTMASK_BITPOS 127 -#define CTMASK_BITBSZ 127 -#define CTMASK_BITCSZ 127 -#define CTSHIFT_BITPOS 0 -#define CTSHIFT_BITBSZ 8 -#define CTSHIFT_BITCSZ 16 - -#define CTF_INSERT(info, field, val) \ - info = (info & ~(CTMASK_##field<> CTSHIFT_NUM) -#define ctype_cid(info) ((CTypeID)((info) & CTMASK_CID)) -#define ctype_align(info) (((info) >> CTSHIFT_ALIGN) & CTMASK_ALIGN) -#define ctype_attrib(info) (((info) >> CTSHIFT_ATTRIB) & CTMASK_ATTRIB) -#define ctype_bitpos(info) (((info) >> CTSHIFT_BITPOS) & CTMASK_BITPOS) -#define ctype_bitbsz(info) (((info) >> CTSHIFT_BITBSZ) & CTMASK_BITBSZ) -#define ctype_bitcsz(info) (((info) >> CTSHIFT_BITCSZ) & CTMASK_BITCSZ) -#define ctype_vsizeP(info) (((info) >> CTSHIFT_VSIZEP) & CTMASK_VSIZEP) -#define ctype_msizeP(info) (((info) >> CTSHIFT_MSIZEP) & CTMASK_MSIZEP) -#define ctype_cconv(info) (((info) >> CTSHIFT_CCONV) & CTMASK_CCONV) - -/* Simple type checks. */ -#define ctype_isnum(info) (ctype_type((info)) == CT_NUM) -#define ctype_isvoid(info) (ctype_type((info)) == CT_VOID) -#define ctype_isptr(info) (ctype_type((info)) == CT_PTR) -#define ctype_isarray(info) (ctype_type((info)) == CT_ARRAY) -#define ctype_isstruct(info) (ctype_type((info)) == CT_STRUCT) -#define ctype_isfunc(info) (ctype_type((info)) == CT_FUNC) -#define ctype_isenum(info) (ctype_type((info)) == CT_ENUM) -#define ctype_istypedef(info) (ctype_type((info)) == CT_TYPEDEF) -#define ctype_isattrib(info) (ctype_type((info)) == CT_ATTRIB) -#define ctype_isfield(info) (ctype_type((info)) == CT_FIELD) -#define ctype_isbitfield(info) (ctype_type((info)) == CT_BITFIELD) -#define ctype_isconstval(info) (ctype_type((info)) == CT_CONSTVAL) -#define ctype_isextern(info) (ctype_type((info)) == CT_EXTERN) -#define ctype_hassize(info) (ctype_type((info)) <= CT_HASSIZE) - -/* Combined type and flag checks. */ -#define ctype_isinteger(info) \ - (((info) & (CTMASK_NUM|CTF_BOOL|CTF_FP)) == CTINFO(CT_NUM, 0)) -#define ctype_isinteger_or_bool(info) \ - (((info) & (CTMASK_NUM|CTF_FP)) == CTINFO(CT_NUM, 0)) -#define ctype_isbool(info) \ - (((info) & (CTMASK_NUM|CTF_BOOL)) == CTINFO(CT_NUM, CTF_BOOL)) -#define ctype_isfp(info) \ - (((info) & (CTMASK_NUM|CTF_FP)) == CTINFO(CT_NUM, CTF_FP)) - -#define ctype_ispointer(info) \ - ((ctype_type(info) >> 1) == (CT_PTR >> 1)) /* Pointer or array. */ -#define ctype_isref(info) \ - (((info) & (CTMASK_NUM|CTF_REF)) == CTINFO(CT_PTR, CTF_REF)) - -#define ctype_isrefarray(info) \ - (((info) & (CTMASK_NUM|CTF_VECTOR|CTF_COMPLEX)) == CTINFO(CT_ARRAY, 0)) -#define ctype_isvector(info) \ - (((info) & (CTMASK_NUM|CTF_VECTOR)) == CTINFO(CT_ARRAY, CTF_VECTOR)) -#define ctype_iscomplex(info) \ - (((info) & (CTMASK_NUM|CTF_COMPLEX)) == CTINFO(CT_ARRAY, CTF_COMPLEX)) - -#define ctype_isvltype(info) \ - (((info) & ((CTMASK_NUM|CTF_VLA) - (2u<") _(STRING, "") \ - _(INTEGER, "") _(EOF, "") \ - _(OROR, "||") _(ANDAND, "&&") _(EQ, "==") _(NE, "!=") \ - _(LE, "<=") _(GE, ">=") _(SHL, "<<") _(SHR, ">>") _(DEREF, "->") - -/* Simple declaration specifiers. */ -#define CDSDEF(_) \ - _(VOID) _(BOOL) _(CHAR) _(INT) _(FP) \ - _(LONG) _(LONGLONG) _(SHORT) _(COMPLEX) _(SIGNED) _(UNSIGNED) \ - _(CONST) _(VOLATILE) _(RESTRICT) _(INLINE) \ - _(TYPEDEF) _(EXTERN) _(STATIC) _(AUTO) _(REGISTER) - -/* C keywords. */ -#define CKWDEF(_) \ - CDSDEF(_) _(EXTENSION) _(ASM) _(ATTRIBUTE) \ - _(DECLSPEC) _(CCDECL) _(PTRSZ) \ - _(STRUCT) _(UNION) _(ENUM) \ - _(SIZEOF) _(ALIGNOF) - -/* C token numbers. */ -enum { - CTOK_OFS = 255, -#define CTOKNUM(name, sym) CTOK_##name, -#define CKWNUM(name) CTOK_##name, -CTOKDEF(CTOKNUM) -CKWDEF(CKWNUM) -#undef CTOKNUM -#undef CKWNUM - CTOK_FIRSTDECL = CTOK_VOID, - CTOK_FIRSTSCL = CTOK_TYPEDEF, - CTOK_LASTDECLFLAG = CTOK_REGISTER, - CTOK_LASTDECL = CTOK_ENUM -}; - -/* Declaration specifier flags. */ -enum { -#define CDSFLAG(name) CDF_##name = (1u << (CTOK_##name - CTOK_FIRSTDECL)), -CDSDEF(CDSFLAG) -#undef CDSFLAG - CDF__END -}; - -#define CDF_SCL (CDF_TYPEDEF|CDF_EXTERN|CDF_STATIC|CDF_AUTO|CDF_REGISTER) - -/* -- C type management --------------------------------------------------- */ - -#define ctype_ctsG(g) (mref((g)->ctype_state, CTState)) - -/* Get C type state. */ -static LJ_AINLINE CTState *ctype_cts(lua_State *L) -{ - CTState *cts = ctype_ctsG(G(L)); - cts->L = L; /* Save L for errors and allocations. */ - return cts; -} - -/* Save and restore state of C type table. */ -#define LJ_CTYPE_SAVE(cts) CTState savects_ = *(cts) -#define LJ_CTYPE_RESTORE(cts) \ - ((cts)->top = savects_.top, \ - memcpy((cts)->hash, savects_.hash, sizeof(savects_.hash))) - -/* Check C type ID for validity when assertions are enabled. */ -static LJ_AINLINE CTypeID ctype_check(CTState *cts, CTypeID id) -{ - lua_assert(id > 0 && id < cts->top); UNUSED(cts); - return id; -} - -/* Get C type for C type ID. */ -static LJ_AINLINE CType *ctype_get(CTState *cts, CTypeID id) -{ - return &cts->tab[ctype_check(cts, id)]; -} - -/* Get C type ID for a C type. */ -#define ctype_typeid(cts, ct) ((CTypeID)((ct) - (cts)->tab)) - -/* Get child C type. */ -static LJ_AINLINE CType *ctype_child(CTState *cts, CType *ct) -{ - lua_assert(!(ctype_isvoid(ct->info) || ctype_isstruct(ct->info) || - ctype_isbitfield(ct->info))); /* These don't have children. */ - return ctype_get(cts, ctype_cid(ct->info)); -} - -/* Get raw type for a C type ID. */ -static LJ_AINLINE CType *ctype_raw(CTState *cts, CTypeID id) -{ - CType *ct = ctype_get(cts, id); - while (ctype_isattrib(ct->info)) ct = ctype_child(cts, ct); - return ct; -} - -/* Get raw type of the child of a C type. */ -static LJ_AINLINE CType *ctype_rawchild(CTState *cts, CType *ct) -{ - do { ct = ctype_child(cts, ct); } while (ctype_isattrib(ct->info)); - return ct; -} - -/* Set the name of a C type table element. */ -static LJ_AINLINE void ctype_setname(CType *ct, GCstr *s) -{ - /* NOBARRIER: mark string as fixed -- the C type table is never collected. */ - fixstring(s); - setgcref(ct->name, obj2gco(s)); -} - -LJ_FUNC CTypeID lj_ctype_new(CTState *cts, CType **ctp); -LJ_FUNC CTypeID lj_ctype_intern(CTState *cts, CTInfo info, CTSize size); -LJ_FUNC void lj_ctype_addname(CTState *cts, CType *ct, CTypeID id); -LJ_FUNC CTypeID lj_ctype_getname(CTState *cts, CType **ctp, GCstr *name, - uint32_t tmask); -LJ_FUNC CType *lj_ctype_getfieldq(CTState *cts, CType *ct, GCstr *name, - CTSize *ofs, CTInfo *qual); -#define lj_ctype_getfield(cts, ct, name, ofs) \ - lj_ctype_getfieldq((cts), (ct), (name), (ofs), NULL) -LJ_FUNC CType *lj_ctype_rawref(CTState *cts, CTypeID id); -LJ_FUNC CTSize lj_ctype_size(CTState *cts, CTypeID id); -LJ_FUNC CTSize lj_ctype_vlsize(CTState *cts, CType *ct, CTSize nelem); -LJ_FUNC CTInfo lj_ctype_info(CTState *cts, CTypeID id, CTSize *szp); -LJ_FUNC cTValue *lj_ctype_meta(CTState *cts, CTypeID id, MMS mm); -LJ_FUNC GCstr *lj_ctype_repr(lua_State *L, CTypeID id, GCstr *name); -LJ_FUNC GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned); -LJ_FUNC GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size); -LJ_FUNC CTState *lj_ctype_init(lua_State *L); -LJ_FUNC void lj_ctype_freestate(global_State *g); - -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_debug.c b/lib/LuaJIT/src/lj_debug.c deleted file mode 100644 index 959dc28..0000000 --- a/lib/LuaJIT/src/lj_debug.c +++ /dev/null @@ -1,699 +0,0 @@ -/* -** Debugging and introspection. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_debug_c -#define LUA_CORE - -#include "lj_obj.h" -#include "lj_err.h" -#include "lj_debug.h" -#include "lj_buf.h" -#include "lj_tab.h" -#include "lj_state.h" -#include "lj_frame.h" -#include "lj_bc.h" -#include "lj_strfmt.h" -#if LJ_HASJIT -#include "lj_jit.h" -#endif - -/* -- Frames -------------------------------------------------------------- */ - -/* Get frame corresponding to a level. */ -cTValue *lj_debug_frame(lua_State *L, int level, int *size) -{ - cTValue *frame, *nextframe, *bot = tvref(L->stack)+LJ_FR2; - /* Traverse frames backwards. */ - for (nextframe = frame = L->base-1; frame > bot; ) { - if (frame_gc(frame) == obj2gco(L)) - level++; /* Skip dummy frames. See lj_err_optype_call(). */ - if (level-- == 0) { - *size = (int)(nextframe - frame); - return frame; /* Level found. */ - } - nextframe = frame; - if (frame_islua(frame)) { - frame = frame_prevl(frame); - } else { - if (frame_isvarg(frame)) - level++; /* Skip vararg pseudo-frame. */ - frame = frame_prevd(frame); - } - } - *size = level; - return NULL; /* Level not found. */ -} - -/* Invalid bytecode position. */ -#define NO_BCPOS (~(BCPos)0) - -/* Return bytecode position for function/frame or NO_BCPOS. */ -static BCPos debug_framepc(lua_State *L, GCfunc *fn, cTValue *nextframe) -{ - const BCIns *ins; - GCproto *pt; - BCPos pos; - lua_assert(fn->c.gct == ~LJ_TFUNC || fn->c.gct == ~LJ_TTHREAD); - if (!isluafunc(fn)) { /* Cannot derive a PC for non-Lua functions. */ - return NO_BCPOS; - } else if (nextframe == NULL) { /* Lua function on top. */ - void *cf = cframe_raw(L->cframe); - if (cf == NULL || (char *)cframe_pc(cf) == (char *)cframe_L(cf)) - return NO_BCPOS; - ins = cframe_pc(cf); /* Only happens during error/hook handling. */ - } else { - if (frame_islua(nextframe)) { - ins = frame_pc(nextframe); - } else if (frame_iscont(nextframe)) { - ins = frame_contpc(nextframe); - } else { - /* Lua function below errfunc/gc/hook: find cframe to get the PC. */ - void *cf = cframe_raw(L->cframe); - TValue *f = L->base-1; - for (;;) { - if (cf == NULL) - return NO_BCPOS; - while (cframe_nres(cf) < 0) { - if (f >= restorestack(L, -cframe_nres(cf))) - break; - cf = cframe_raw(cframe_prev(cf)); - if (cf == NULL) - return NO_BCPOS; - } - if (f < nextframe) - break; - if (frame_islua(f)) { - f = frame_prevl(f); - } else { - if (frame_isc(f) || (frame_iscont(f) && frame_iscont_fficb(f))) - cf = cframe_raw(cframe_prev(cf)); - f = frame_prevd(f); - } - } - ins = cframe_pc(cf); - } - } - pt = funcproto(fn); - pos = proto_bcpos(pt, ins) - 1; -#if LJ_HASJIT - if (pos > pt->sizebc) { /* Undo the effects of lj_trace_exit for JLOOP. */ - GCtrace *T = (GCtrace *)((char *)(ins-1) - offsetof(GCtrace, startins)); - lua_assert(bc_isret(bc_op(ins[-1]))); - pos = proto_bcpos(pt, mref(T->startpc, const BCIns)); - } -#endif - return pos; -} - -/* -- Line numbers -------------------------------------------------------- */ - -/* Get line number for a bytecode position. */ -BCLine LJ_FASTCALL lj_debug_line(GCproto *pt, BCPos pc) -{ - const void *lineinfo = proto_lineinfo(pt); - if (pc <= pt->sizebc && lineinfo) { - BCLine first = pt->firstline; - if (pc == pt->sizebc) return first + pt->numline; - if (pc-- == 0) return first; - if (pt->numline < 256) - return first + (BCLine)((const uint8_t *)lineinfo)[pc]; - else if (pt->numline < 65536) - return first + (BCLine)((const uint16_t *)lineinfo)[pc]; - else - return first + (BCLine)((const uint32_t *)lineinfo)[pc]; - } - return 0; -} - -/* Get line number for function/frame. */ -static BCLine debug_frameline(lua_State *L, GCfunc *fn, cTValue *nextframe) -{ - BCPos pc = debug_framepc(L, fn, nextframe); - if (pc != NO_BCPOS) { - GCproto *pt = funcproto(fn); - lua_assert(pc <= pt->sizebc); - return lj_debug_line(pt, pc); - } - return -1; -} - -/* -- Variable names ------------------------------------------------------ */ - -/* Get name of a local variable from slot number and PC. */ -static const char *debug_varname(const GCproto *pt, BCPos pc, BCReg slot) -{ - const char *p = (const char *)proto_varinfo(pt); - if (p) { - BCPos lastpc = 0; - for (;;) { - const char *name = p; - uint32_t vn = *(const uint8_t *)p; - BCPos startpc, endpc; - if (vn < VARNAME__MAX) { - if (vn == VARNAME_END) break; /* End of varinfo. */ - } else { - do { p++; } while (*(const uint8_t *)p); /* Skip over variable name. */ - } - p++; - lastpc = startpc = lastpc + lj_buf_ruleb128(&p); - if (startpc > pc) break; - endpc = startpc + lj_buf_ruleb128(&p); - if (pc < endpc && slot-- == 0) { - if (vn < VARNAME__MAX) { -#define VARNAMESTR(name, str) str "\0" - name = VARNAMEDEF(VARNAMESTR); -#undef VARNAMESTR - if (--vn) while (*name++ || --vn) ; - } - return name; - } - } - } - return NULL; -} - -/* Get name of local variable from 1-based slot number and function/frame. */ -static TValue *debug_localname(lua_State *L, const lua_Debug *ar, - const char **name, BCReg slot1) -{ - uint32_t offset = (uint32_t)ar->i_ci & 0xffff; - uint32_t size = (uint32_t)ar->i_ci >> 16; - TValue *frame = tvref(L->stack) + offset; - TValue *nextframe = size ? frame + size : NULL; - GCfunc *fn = frame_func(frame); - BCPos pc = debug_framepc(L, fn, nextframe); - if (!nextframe) nextframe = L->top+LJ_FR2; - if ((int)slot1 < 0) { /* Negative slot number is for varargs. */ - if (pc != NO_BCPOS) { - GCproto *pt = funcproto(fn); - if ((pt->flags & PROTO_VARARG)) { - slot1 = pt->numparams + (BCReg)(-(int)slot1); - if (frame_isvarg(frame)) { /* Vararg frame has been set up? (pc!=0) */ - nextframe = frame; - frame = frame_prevd(frame); - } - if (frame + slot1+LJ_FR2 < nextframe) { - *name = "(*vararg)"; - return frame+slot1; - } - } - } - return NULL; - } - if (pc != NO_BCPOS && - (*name = debug_varname(funcproto(fn), pc, slot1-1)) != NULL) - ; - else if (slot1 > 0 && frame + slot1+LJ_FR2 < nextframe) - *name = "(*temporary)"; - return frame+slot1; -} - -/* Get name of upvalue. */ -const char *lj_debug_uvname(GCproto *pt, uint32_t idx) -{ - const uint8_t *p = proto_uvinfo(pt); - lua_assert(idx < pt->sizeuv); - if (!p) return ""; - if (idx) while (*p++ || --idx) ; - return (const char *)p; -} - -/* Get name and value of upvalue. */ -const char *lj_debug_uvnamev(cTValue *o, uint32_t idx, TValue **tvp) -{ - if (tvisfunc(o)) { - GCfunc *fn = funcV(o); - if (isluafunc(fn)) { - GCproto *pt = funcproto(fn); - if (idx < pt->sizeuv) { - *tvp = uvval(&gcref(fn->l.uvptr[idx])->uv); - return lj_debug_uvname(pt, idx); - } - } else { - if (idx < fn->c.nupvalues) { - *tvp = &fn->c.upvalue[idx]; - return ""; - } - } - } - return NULL; -} - -/* Deduce name of an object from slot number and PC. */ -const char *lj_debug_slotname(GCproto *pt, const BCIns *ip, BCReg slot, - const char **name) -{ - const char *lname; -restart: - lname = debug_varname(pt, proto_bcpos(pt, ip), slot); - if (lname != NULL) { *name = lname; return "local"; } - while (--ip > proto_bc(pt)) { - BCIns ins = *ip; - BCOp op = bc_op(ins); - BCReg ra = bc_a(ins); - if (bcmode_a(op) == BCMbase) { - if (slot >= ra && (op != BC_KNIL || slot <= bc_d(ins))) - return NULL; - } else if (bcmode_a(op) == BCMdst && ra == slot) { - switch (bc_op(ins)) { - case BC_MOV: - if (ra == slot) { slot = bc_d(ins); goto restart; } - break; - case BC_GGET: - *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_d(ins)))); - return "global"; - case BC_TGETS: - *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_c(ins)))); - if (ip > proto_bc(pt)) { - BCIns insp = ip[-1]; - if (bc_op(insp) == BC_MOV && bc_a(insp) == ra+1+LJ_FR2 && - bc_d(insp) == bc_b(ins)) - return "method"; - } - return "field"; - case BC_UGET: - *name = lj_debug_uvname(pt, bc_d(ins)); - return "upvalue"; - default: - return NULL; - } - } - } - return NULL; -} - -/* Deduce function name from caller of a frame. */ -const char *lj_debug_funcname(lua_State *L, cTValue *frame, const char **name) -{ - cTValue *pframe; - GCfunc *fn; - BCPos pc; - if (frame <= tvref(L->stack)+LJ_FR2) - return NULL; - if (frame_isvarg(frame)) - frame = frame_prevd(frame); - pframe = frame_prev(frame); - fn = frame_func(pframe); - pc = debug_framepc(L, fn, frame); - if (pc != NO_BCPOS) { - GCproto *pt = funcproto(fn); - const BCIns *ip = &proto_bc(pt)[check_exp(pc < pt->sizebc, pc)]; - MMS mm = bcmode_mm(bc_op(*ip)); - if (mm == MM_call) { - BCReg slot = bc_a(*ip); - if (bc_op(*ip) == BC_ITERC) slot -= 3; - return lj_debug_slotname(pt, ip, slot, name); - } else if (mm != MM__MAX) { - *name = strdata(mmname_str(G(L), mm)); - return "metamethod"; - } - } - return NULL; -} - -/* -- Source code locations ----------------------------------------------- */ - -/* Generate shortened source name. */ -void lj_debug_shortname(char *out, GCstr *str, BCLine line) -{ - const char *src = strdata(str); - if (*src == '=') { - strncpy(out, src+1, LUA_IDSIZE); /* Remove first char. */ - out[LUA_IDSIZE-1] = '\0'; /* Ensures null termination. */ - } else if (*src == '@') { /* Output "source", or "...source". */ - size_t len = str->len-1; - src++; /* Skip the `@' */ - if (len >= LUA_IDSIZE) { - src += len-(LUA_IDSIZE-4); /* Get last part of file name. */ - *out++ = '.'; *out++ = '.'; *out++ = '.'; - } - strcpy(out, src); - } else { /* Output [string "string"] or [builtin:name]. */ - size_t len; /* Length, up to first control char. */ - for (len = 0; len < LUA_IDSIZE-12; len++) - if (((const unsigned char *)src)[len] < ' ') break; - strcpy(out, line == ~(BCLine)0 ? "[builtin:" : "[string \""); out += 9; - if (src[len] != '\0') { /* Must truncate? */ - if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15; - strncpy(out, src, len); out += len; - strcpy(out, "..."); out += 3; - } else { - strcpy(out, src); out += len; - } - strcpy(out, line == ~(BCLine)0 ? "]" : "\"]"); - } -} - -/* Add current location of a frame to error message. */ -void lj_debug_addloc(lua_State *L, const char *msg, - cTValue *frame, cTValue *nextframe) -{ - if (frame) { - GCfunc *fn = frame_func(frame); - if (isluafunc(fn)) { - BCLine line = debug_frameline(L, fn, nextframe); - if (line >= 0) { - GCproto *pt = funcproto(fn); - char buf[LUA_IDSIZE]; - lj_debug_shortname(buf, proto_chunkname(pt), pt->firstline); - lj_strfmt_pushf(L, "%s:%d: %s", buf, line, msg); - return; - } - } - } - lj_strfmt_pushf(L, "%s", msg); -} - -/* Push location string for a bytecode position to Lua stack. */ -void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc) -{ - GCstr *name = proto_chunkname(pt); - const char *s = strdata(name); - MSize i, len = name->len; - BCLine line = lj_debug_line(pt, pc); - if (pt->firstline == ~(BCLine)0) { - lj_strfmt_pushf(L, "builtin:%s", s); - } else if (*s == '@') { - s++; len--; - for (i = len; i > 0; i--) - if (s[i] == '/' || s[i] == '\\') { - s += i+1; - break; - } - lj_strfmt_pushf(L, "%s:%d", s, line); - } else if (len > 40) { - lj_strfmt_pushf(L, "%p:%d", pt, line); - } else if (*s == '=') { - lj_strfmt_pushf(L, "%s:%d", s+1, line); - } else { - lj_strfmt_pushf(L, "\"%s\":%d", s, line); - } -} - -/* -- Public debug API ---------------------------------------------------- */ - -/* lua_getupvalue() and lua_setupvalue() are in lj_api.c. */ - -LUA_API const char *lua_getlocal(lua_State *L, const lua_Debug *ar, int n) -{ - const char *name = NULL; - if (ar) { - TValue *o = debug_localname(L, ar, &name, (BCReg)n); - if (name) { - copyTV(L, L->top, o); - incr_top(L); - } - } else if (tvisfunc(L->top-1) && isluafunc(funcV(L->top-1))) { - name = debug_varname(funcproto(funcV(L->top-1)), 0, (BCReg)n-1); - } - return name; -} - -LUA_API const char *lua_setlocal(lua_State *L, const lua_Debug *ar, int n) -{ - const char *name = NULL; - TValue *o = debug_localname(L, ar, &name, (BCReg)n); - if (name) - copyTV(L, o, L->top-1); - L->top--; - return name; -} - -int lj_debug_getinfo(lua_State *L, const char *what, lj_Debug *ar, int ext) -{ - int opt_f = 0, opt_L = 0; - TValue *frame = NULL; - TValue *nextframe = NULL; - GCfunc *fn; - if (*what == '>') { - TValue *func = L->top - 1; - api_check(L, tvisfunc(func)); - fn = funcV(func); - L->top--; - what++; - } else { - uint32_t offset = (uint32_t)ar->i_ci & 0xffff; - uint32_t size = (uint32_t)ar->i_ci >> 16; - lua_assert(offset != 0); - frame = tvref(L->stack) + offset; - if (size) nextframe = frame + size; - lua_assert(frame <= tvref(L->maxstack) && - (!nextframe || nextframe <= tvref(L->maxstack))); - fn = frame_func(frame); - lua_assert(fn->c.gct == ~LJ_TFUNC); - } - for (; *what; what++) { - if (*what == 'S') { - if (isluafunc(fn)) { - GCproto *pt = funcproto(fn); - BCLine firstline = pt->firstline; - GCstr *name = proto_chunkname(pt); - ar->source = strdata(name); - lj_debug_shortname(ar->short_src, name, pt->firstline); - ar->linedefined = (int)firstline; - ar->lastlinedefined = (int)(firstline + pt->numline); - ar->what = (firstline || !pt->numline) ? "Lua" : "main"; - } else { - ar->source = "=[C]"; - ar->short_src[0] = '['; - ar->short_src[1] = 'C'; - ar->short_src[2] = ']'; - ar->short_src[3] = '\0'; - ar->linedefined = -1; - ar->lastlinedefined = -1; - ar->what = "C"; - } - } else if (*what == 'l') { - ar->currentline = frame ? debug_frameline(L, fn, nextframe) : -1; - } else if (*what == 'u') { - ar->nups = fn->c.nupvalues; - if (ext) { - if (isluafunc(fn)) { - GCproto *pt = funcproto(fn); - ar->nparams = pt->numparams; - ar->isvararg = !!(pt->flags & PROTO_VARARG); - } else { - ar->nparams = 0; - ar->isvararg = 1; - } - } - } else if (*what == 'n') { - ar->namewhat = frame ? lj_debug_funcname(L, frame, &ar->name) : NULL; - if (ar->namewhat == NULL) { - ar->namewhat = ""; - ar->name = NULL; - } - } else if (*what == 'f') { - opt_f = 1; - } else if (*what == 'L') { - opt_L = 1; - } else { - return 0; /* Bad option. */ - } - } - if (opt_f) { - setfuncV(L, L->top, fn); - incr_top(L); - } - if (opt_L) { - if (isluafunc(fn)) { - GCtab *t = lj_tab_new(L, 0, 0); - GCproto *pt = funcproto(fn); - const void *lineinfo = proto_lineinfo(pt); - if (lineinfo) { - BCLine first = pt->firstline; - int sz = pt->numline < 256 ? 1 : pt->numline < 65536 ? 2 : 4; - MSize i, szl = pt->sizebc-1; - for (i = 0; i < szl; i++) { - BCLine line = first + - (sz == 1 ? (BCLine)((const uint8_t *)lineinfo)[i] : - sz == 2 ? (BCLine)((const uint16_t *)lineinfo)[i] : - (BCLine)((const uint32_t *)lineinfo)[i]); - setboolV(lj_tab_setint(L, t, line), 1); - } - } - settabV(L, L->top, t); - } else { - setnilV(L->top); - } - incr_top(L); - } - return 1; /* Ok. */ -} - -LUA_API int lua_getinfo(lua_State *L, const char *what, lua_Debug *ar) -{ - return lj_debug_getinfo(L, what, (lj_Debug *)ar, 0); -} - -LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar) -{ - int size; - cTValue *frame = lj_debug_frame(L, level, &size); - if (frame) { - ar->i_ci = (size << 16) + (int)(frame - tvref(L->stack)); - return 1; - } else { - ar->i_ci = level - size; - return 0; - } -} - -#if LJ_HASPROFILE -/* Put the chunkname into a buffer. */ -static int debug_putchunkname(SBuf *sb, GCproto *pt, int pathstrip) -{ - GCstr *name = proto_chunkname(pt); - const char *p = strdata(name); - if (pt->firstline == ~(BCLine)0) { - lj_buf_putmem(sb, "[builtin:", 9); - lj_buf_putstr(sb, name); - lj_buf_putb(sb, ']'); - return 0; - } - if (*p == '=' || *p == '@') { - MSize len = name->len-1; - p++; - if (pathstrip) { - int i; - for (i = len-1; i >= 0; i--) - if (p[i] == '/' || p[i] == '\\') { - len -= i+1; - p = p+i+1; - break; - } - } - lj_buf_putmem(sb, p, len); - } else { - lj_buf_putmem(sb, "[string]", 8); - } - return 1; -} - -/* Put a compact stack dump into a buffer. */ -void lj_debug_dumpstack(lua_State *L, SBuf *sb, const char *fmt, int depth) -{ - int level = 0, dir = 1, pathstrip = 1; - MSize lastlen = 0; - if (depth < 0) { level = ~depth; depth = dir = -1; } /* Reverse frames. */ - while (level != depth) { /* Loop through all frame. */ - int size; - cTValue *frame = lj_debug_frame(L, level, &size); - if (frame) { - cTValue *nextframe = size ? frame+size : NULL; - GCfunc *fn = frame_func(frame); - const uint8_t *p = (const uint8_t *)fmt; - int c; - while ((c = *p++)) { - switch (c) { - case 'p': /* Preserve full path. */ - pathstrip = 0; - break; - case 'F': case 'f': { /* Dump function name. */ - const char *name; - const char *what = lj_debug_funcname(L, frame, &name); - if (what) { - if (c == 'F' && isluafunc(fn)) { /* Dump module:name for 'F'. */ - GCproto *pt = funcproto(fn); - if (pt->firstline != ~(BCLine)0) { /* Not a bytecode builtin. */ - debug_putchunkname(sb, pt, pathstrip); - lj_buf_putb(sb, ':'); - } - } - lj_buf_putmem(sb, name, (MSize)strlen(name)); - break; - } /* else: can't derive a name, dump module:line. */ - } - /* fallthrough */ - case 'l': /* Dump module:line. */ - if (isluafunc(fn)) { - GCproto *pt = funcproto(fn); - if (debug_putchunkname(sb, pt, pathstrip)) { - /* Regular Lua function. */ - BCLine line = c == 'l' ? debug_frameline(L, fn, nextframe) : - pt->firstline; - lj_buf_putb(sb, ':'); - lj_strfmt_putint(sb, line >= 0 ? line : pt->firstline); - } - } else if (isffunc(fn)) { /* Dump numbered builtins. */ - lj_buf_putmem(sb, "[builtin#", 9); - lj_strfmt_putint(sb, fn->c.ffid); - lj_buf_putb(sb, ']'); - } else { /* Dump C function address. */ - lj_buf_putb(sb, '@'); - lj_strfmt_putptr(sb, fn->c.f); - } - break; - case 'Z': /* Zap trailing separator. */ - lastlen = sbuflen(sb); - break; - default: - lj_buf_putb(sb, c); - break; - } - } - } else if (dir == 1) { - break; - } else { - level -= size; /* Reverse frame order: quickly skip missing level. */ - } - level += dir; - } - if (lastlen) - setsbufP(sb, sbufB(sb) + lastlen); /* Zap trailing separator. */ -} -#endif - -/* Number of frames for the leading and trailing part of a traceback. */ -#define TRACEBACK_LEVELS1 12 -#define TRACEBACK_LEVELS2 10 - -LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, - int level) -{ - int top = (int)(L->top - L->base); - int lim = TRACEBACK_LEVELS1; - lua_Debug ar; - if (msg) lua_pushfstring(L, "%s\n", msg); - lua_pushliteral(L, "stack traceback:"); - while (lua_getstack(L1, level++, &ar)) { - GCfunc *fn; - if (level > lim) { - if (!lua_getstack(L1, level + TRACEBACK_LEVELS2, &ar)) { - level--; - } else { - lua_pushliteral(L, "\n\t..."); - lua_getstack(L1, -10, &ar); - level = ar.i_ci - TRACEBACK_LEVELS2; - } - lim = 2147483647; - continue; - } - lua_getinfo(L1, "Snlf", &ar); - fn = funcV(L1->top-1); L1->top--; - if (isffunc(fn) && !*ar.namewhat) - lua_pushfstring(L, "\n\t[builtin#%d]:", fn->c.ffid); - else - lua_pushfstring(L, "\n\t%s:", ar.short_src); - if (ar.currentline > 0) - lua_pushfstring(L, "%d:", ar.currentline); - if (*ar.namewhat) { - lua_pushfstring(L, " in function " LUA_QS, ar.name); - } else { - if (*ar.what == 'm') { - lua_pushliteral(L, " in main chunk"); - } else if (*ar.what == 'C') { - lua_pushfstring(L, " at %p", fn->c.f); - } else { - lua_pushfstring(L, " in function <%s:%d>", - ar.short_src, ar.linedefined); - } - } - if ((int)(L->top - L->base) - top >= 15) - lua_concat(L, (int)(L->top - L->base) - top); - } - lua_concat(L, (int)(L->top - L->base) - top); -} - diff --git a/lib/LuaJIT/src/lj_debug.h b/lib/LuaJIT/src/lj_debug.h deleted file mode 100644 index 5917c00..0000000 --- a/lib/LuaJIT/src/lj_debug.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -** Debugging and introspection. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_DEBUG_H -#define _LJ_DEBUG_H - -#include "lj_obj.h" - -typedef struct lj_Debug { - /* Common fields. Must be in the same order as in lua.h. */ - int event; - const char *name; - const char *namewhat; - const char *what; - const char *source; - int currentline; - int nups; - int linedefined; - int lastlinedefined; - char short_src[LUA_IDSIZE]; - int i_ci; - /* Extended fields. Only valid if lj_debug_getinfo() is called with ext = 1.*/ - int nparams; - int isvararg; -} lj_Debug; - -LJ_FUNC cTValue *lj_debug_frame(lua_State *L, int level, int *size); -LJ_FUNC BCLine LJ_FASTCALL lj_debug_line(GCproto *pt, BCPos pc); -LJ_FUNC const char *lj_debug_uvname(GCproto *pt, uint32_t idx); -LJ_FUNC const char *lj_debug_uvnamev(cTValue *o, uint32_t idx, TValue **tvp); -LJ_FUNC const char *lj_debug_slotname(GCproto *pt, const BCIns *pc, - BCReg slot, const char **name); -LJ_FUNC const char *lj_debug_funcname(lua_State *L, cTValue *frame, - const char **name); -LJ_FUNC void lj_debug_shortname(char *out, GCstr *str, BCLine line); -LJ_FUNC void lj_debug_addloc(lua_State *L, const char *msg, - cTValue *frame, cTValue *nextframe); -LJ_FUNC void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc); -LJ_FUNC int lj_debug_getinfo(lua_State *L, const char *what, lj_Debug *ar, - int ext); -#if LJ_HASPROFILE -LJ_FUNC void lj_debug_dumpstack(lua_State *L, SBuf *sb, const char *fmt, - int depth); -#endif - -/* Fixed internal variable names. */ -#define VARNAMEDEF(_) \ - _(FOR_IDX, "(for index)") \ - _(FOR_STOP, "(for limit)") \ - _(FOR_STEP, "(for step)") \ - _(FOR_GEN, "(for generator)") \ - _(FOR_STATE, "(for state)") \ - _(FOR_CTL, "(for control)") - -enum { - VARNAME_END, -#define VARNAMEENUM(name, str) VARNAME_##name, - VARNAMEDEF(VARNAMEENUM) -#undef VARNAMEENUM - VARNAME__MAX -}; - -#endif diff --git a/lib/LuaJIT/src/lj_def.h b/lib/LuaJIT/src/lj_def.h deleted file mode 100644 index e67bb24..0000000 --- a/lib/LuaJIT/src/lj_def.h +++ /dev/null @@ -1,361 +0,0 @@ -/* -** LuaJIT common internal definitions. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_DEF_H -#define _LJ_DEF_H - -#include "lua.h" - -#if defined(_MSC_VER) -/* MSVC is stuck in the last century and doesn't have C99's stdint.h. */ -typedef __int8 int8_t; -typedef __int16 int16_t; -typedef __int32 int32_t; -typedef __int64 int64_t; -typedef unsigned __int8 uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int32 uint32_t; -typedef unsigned __int64 uint64_t; -#ifdef _WIN64 -typedef __int64 intptr_t; -typedef unsigned __int64 uintptr_t; -#else -typedef __int32 intptr_t; -typedef unsigned __int32 uintptr_t; -#endif -#elif defined(__symbian__) -/* Cough. */ -typedef signed char int8_t; -typedef short int int16_t; -typedef int int32_t; -typedef long long int64_t; -typedef unsigned char uint8_t; -typedef unsigned short int uint16_t; -typedef unsigned int uint32_t; -typedef unsigned long long uint64_t; -typedef int intptr_t; -typedef unsigned int uintptr_t; -#else -#include -#endif - -/* Needed everywhere. */ -#include -#include - -/* Various VM limits. */ -#define LJ_MAX_MEM32 0x7fffff00 /* Max. 32 bit memory allocation. */ -#define LJ_MAX_MEM64 ((uint64_t)1<<47) /* Max. 64 bit memory allocation. */ -/* Max. total memory allocation. */ -#define LJ_MAX_MEM (LJ_GC64 ? LJ_MAX_MEM64 : LJ_MAX_MEM32) -#define LJ_MAX_ALLOC LJ_MAX_MEM /* Max. individual allocation length. */ -#define LJ_MAX_STR LJ_MAX_MEM32 /* Max. string length. */ -#define LJ_MAX_BUF LJ_MAX_MEM32 /* Max. buffer length. */ -#define LJ_MAX_UDATA LJ_MAX_MEM32 /* Max. userdata length. */ - -#define LJ_MAX_STRTAB (1<<26) /* Max. string table size. */ -#define LJ_MAX_HBITS 26 /* Max. hash bits. */ -#define LJ_MAX_ABITS 28 /* Max. bits of array key. */ -#define LJ_MAX_ASIZE ((1<<(LJ_MAX_ABITS-1))+1) /* Max. array part size. */ -#define LJ_MAX_COLOSIZE 16 /* Max. elems for colocated array. */ - -#define LJ_MAX_LINE LJ_MAX_MEM32 /* Max. source code line number. */ -#define LJ_MAX_XLEVEL 200 /* Max. syntactic nesting level. */ -#define LJ_MAX_BCINS (1<<26) /* Max. # of bytecode instructions. */ -#define LJ_MAX_SLOTS 250 /* Max. # of slots in a Lua func. */ -#define LJ_MAX_LOCVAR 200 /* Max. # of local variables. */ -#define LJ_MAX_UPVAL 60 /* Max. # of upvalues. */ - -#define LJ_MAX_IDXCHAIN 100 /* __index/__newindex chain limit. */ -#define LJ_STACK_EXTRA (5+2*LJ_FR2) /* Extra stack space (metamethods). */ - -#define LJ_NUM_CBPAGE 1 /* Number of FFI callback pages. */ - -/* Minimum table/buffer sizes. */ -#define LJ_MIN_GLOBAL 6 /* Min. global table size (hbits). */ -#define LJ_MIN_REGISTRY 2 /* Min. registry size (hbits). */ -#define LJ_MIN_STRTAB 256 /* Min. string table size (pow2). */ -#define LJ_MIN_SBUF 32 /* Min. string buffer length. */ -#define LJ_MIN_VECSZ 8 /* Min. size for growable vectors. */ -#define LJ_MIN_IRSZ 32 /* Min. size for growable IR. */ - -/* JIT compiler limits. */ -#define LJ_MAX_JSLOTS 250 /* Max. # of stack slots for a trace. */ -#define LJ_MAX_PHI 64 /* Max. # of PHIs for a loop. */ -#define LJ_MAX_EXITSTUBGR 16 /* Max. # of exit stub groups. */ - -/* Various macros. */ -#ifndef UNUSED -#define UNUSED(x) ((void)(x)) /* to avoid warnings */ -#endif - -#define U64x(hi, lo) (((uint64_t)0x##hi << 32) + (uint64_t)0x##lo) -#define i32ptr(p) ((int32_t)(intptr_t)(void *)(p)) -#define u32ptr(p) ((uint32_t)(intptr_t)(void *)(p)) -#define i64ptr(p) ((int64_t)(intptr_t)(void *)(p)) -#define u64ptr(p) ((uint64_t)(intptr_t)(void *)(p)) -#define igcptr(p) (LJ_GC64 ? i64ptr(p) : i32ptr(p)) - -#define checki8(x) ((x) == (int32_t)(int8_t)(x)) -#define checku8(x) ((x) == (int32_t)(uint8_t)(x)) -#define checki16(x) ((x) == (int32_t)(int16_t)(x)) -#define checku16(x) ((x) == (int32_t)(uint16_t)(x)) -#define checki32(x) ((x) == (int32_t)(x)) -#define checku32(x) ((x) == (uint32_t)(x)) -#define checkptr32(x) ((uintptr_t)(x) == (uint32_t)(uintptr_t)(x)) -#define checkptr47(x) (((uint64_t)(uintptr_t)(x) >> 47) == 0) -#define checkptrGC(x) (LJ_GC64 ? checkptr47((x)) : LJ_64 ? checkptr32((x)) :1) - -/* Every half-decent C compiler transforms this into a rotate instruction. */ -#define lj_rol(x, n) (((x)<<(n)) | ((x)>>(-(int)(n)&(8*sizeof(x)-1)))) -#define lj_ror(x, n) (((x)<<(-(int)(n)&(8*sizeof(x)-1))) | ((x)>>(n))) - -/* A really naive Bloom filter. But sufficient for our needs. */ -typedef uintptr_t BloomFilter; -#define BLOOM_MASK (8*sizeof(BloomFilter) - 1) -#define bloombit(x) ((uintptr_t)1 << ((x) & BLOOM_MASK)) -#define bloomset(b, x) ((b) |= bloombit((x))) -#define bloomtest(b, x) ((b) & bloombit((x))) - -#if defined(__GNUC__) || defined(__psp2__) - -#define LJ_NORET __attribute__((noreturn)) -#define LJ_ALIGN(n) __attribute__((aligned(n))) -#define LJ_INLINE inline -#define LJ_AINLINE inline __attribute__((always_inline)) -#define LJ_NOINLINE __attribute__((noinline)) - -#if defined(__ELF__) || defined(__MACH__) || defined(__psp2__) -#if !((defined(__sun__) && defined(__svr4__)) || defined(__CELLOS_LV2__)) -#define LJ_NOAPI extern __attribute__((visibility("hidden"))) -#endif -#endif - -/* Note: it's only beneficial to use fastcall on x86 and then only for up to -** two non-FP args. The amalgamated compile covers all LJ_FUNC cases. Only -** indirect calls and related tail-called C functions are marked as fastcall. -*/ -#if defined(__i386__) -#define LJ_FASTCALL __attribute__((fastcall)) -#endif - -#define LJ_LIKELY(x) __builtin_expect(!!(x), 1) -#define LJ_UNLIKELY(x) __builtin_expect(!!(x), 0) - -#define lj_ffs(x) ((uint32_t)__builtin_ctz(x)) -/* Don't ask ... */ -#if defined(__INTEL_COMPILER) && (defined(__i386__) || defined(__x86_64__)) -static LJ_AINLINE uint32_t lj_fls(uint32_t x) -{ - uint32_t r; __asm__("bsrl %1, %0" : "=r" (r) : "rm" (x) : "cc"); return r; -} -#else -#define lj_fls(x) ((uint32_t)(__builtin_clz(x)^31)) -#endif - -#if defined(__arm__) -static LJ_AINLINE uint32_t lj_bswap(uint32_t x) -{ -#if defined(__psp2__) - return __builtin_rev(x); -#else - uint32_t r; -#if __ARM_ARCH_6__ || __ARM_ARCH_6J__ || __ARM_ARCH_6T2__ || __ARM_ARCH_6Z__ ||\ - __ARM_ARCH_6ZK__ || __ARM_ARCH_7__ || __ARM_ARCH_7A__ || __ARM_ARCH_7R__ - __asm__("rev %0, %1" : "=r" (r) : "r" (x)); - return r; -#else -#ifdef __thumb__ - r = x ^ lj_ror(x, 16); -#else - __asm__("eor %0, %1, %1, ror #16" : "=r" (r) : "r" (x)); -#endif - return ((r & 0xff00ffffu) >> 8) ^ lj_ror(x, 8); -#endif -#endif -} - -static LJ_AINLINE uint64_t lj_bswap64(uint64_t x) -{ - return ((uint64_t)lj_bswap((uint32_t)x)<<32) | lj_bswap((uint32_t)(x>>32)); -} -#elif (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) -static LJ_AINLINE uint32_t lj_bswap(uint32_t x) -{ - return (uint32_t)__builtin_bswap32((int32_t)x); -} - -static LJ_AINLINE uint64_t lj_bswap64(uint64_t x) -{ - return (uint64_t)__builtin_bswap64((int64_t)x); -} -#elif defined(__i386__) || defined(__x86_64__) -static LJ_AINLINE uint32_t lj_bswap(uint32_t x) -{ - uint32_t r; __asm__("bswap %0" : "=r" (r) : "0" (x)); return r; -} - -#if defined(__i386__) -static LJ_AINLINE uint64_t lj_bswap64(uint64_t x) -{ - return ((uint64_t)lj_bswap((uint32_t)x)<<32) | lj_bswap((uint32_t)(x>>32)); -} -#else -static LJ_AINLINE uint64_t lj_bswap64(uint64_t x) -{ - uint64_t r; __asm__("bswap %0" : "=r" (r) : "0" (x)); return r; -} -#endif -#else -static LJ_AINLINE uint32_t lj_bswap(uint32_t x) -{ - return (x << 24) | ((x & 0xff00) << 8) | ((x >> 8) & 0xff00) | (x >> 24); -} - -static LJ_AINLINE uint64_t lj_bswap64(uint64_t x) -{ - return (uint64_t)lj_bswap((uint32_t)(x >> 32)) | - ((uint64_t)lj_bswap((uint32_t)x) << 32); -} -#endif - -typedef union __attribute__((packed)) Unaligned16 { - uint16_t u; - uint8_t b[2]; -} Unaligned16; - -typedef union __attribute__((packed)) Unaligned32 { - uint32_t u; - uint8_t b[4]; -} Unaligned32; - -/* Unaligned load of uint16_t. */ -static LJ_AINLINE uint16_t lj_getu16(const void *p) -{ - return ((const Unaligned16 *)p)->u; -} - -/* Unaligned load of uint32_t. */ -static LJ_AINLINE uint32_t lj_getu32(const void *p) -{ - return ((const Unaligned32 *)p)->u; -} - -#elif defined(_MSC_VER) - -#define LJ_NORET __declspec(noreturn) -#define LJ_ALIGN(n) __declspec(align(n)) -#define LJ_INLINE __inline -#define LJ_AINLINE __forceinline -#define LJ_NOINLINE __declspec(noinline) -#if defined(_M_IX86) -#define LJ_FASTCALL __fastcall -#endif - -#ifdef _M_PPC -unsigned int _CountLeadingZeros(long); -#pragma intrinsic(_CountLeadingZeros) -static LJ_AINLINE uint32_t lj_fls(uint32_t x) -{ - return _CountLeadingZeros(x) ^ 31; -} -#else -unsigned char _BitScanForward(uint32_t *, unsigned long); -unsigned char _BitScanReverse(uint32_t *, unsigned long); -#pragma intrinsic(_BitScanForward) -#pragma intrinsic(_BitScanReverse) - -static LJ_AINLINE uint32_t lj_ffs(uint32_t x) -{ - uint32_t r; _BitScanForward(&r, x); return r; -} - -static LJ_AINLINE uint32_t lj_fls(uint32_t x) -{ - uint32_t r; _BitScanReverse(&r, x); return r; -} -#endif - -unsigned long _byteswap_ulong(unsigned long); -uint64_t _byteswap_uint64(uint64_t); -#define lj_bswap(x) (_byteswap_ulong((x))) -#define lj_bswap64(x) (_byteswap_uint64((x))) - -#if defined(_M_PPC) && defined(LUAJIT_NO_UNALIGNED) -/* -** Replacement for unaligned loads on Xbox 360. Disabled by default since it's -** usually more costly than the occasional stall when crossing a cache-line. -*/ -static LJ_AINLINE uint16_t lj_getu16(const void *v) -{ - const uint8_t *p = (const uint8_t *)v; - return (uint16_t)((p[0]<<8) | p[1]); -} -static LJ_AINLINE uint32_t lj_getu32(const void *v) -{ - const uint8_t *p = (const uint8_t *)v; - return (uint32_t)((p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]); -} -#else -/* Unaligned loads are generally ok on x86/x64. */ -#define lj_getu16(p) (*(uint16_t *)(p)) -#define lj_getu32(p) (*(uint32_t *)(p)) -#endif - -#else -#error "missing defines for your compiler" -#endif - -/* Optional defines. */ -#ifndef LJ_FASTCALL -#define LJ_FASTCALL -#endif -#ifndef LJ_NORET -#define LJ_NORET -#endif -#ifndef LJ_NOAPI -#define LJ_NOAPI extern -#endif -#ifndef LJ_LIKELY -#define LJ_LIKELY(x) (x) -#define LJ_UNLIKELY(x) (x) -#endif - -/* Attributes for internal functions. */ -#define LJ_DATA LJ_NOAPI -#define LJ_DATADEF -#define LJ_ASMF LJ_NOAPI -#define LJ_FUNCA LJ_NOAPI -#if defined(ljamalg_c) -#define LJ_FUNC static -#else -#define LJ_FUNC LJ_NOAPI -#endif -#define LJ_FUNC_NORET LJ_FUNC LJ_NORET -#define LJ_FUNCA_NORET LJ_FUNCA LJ_NORET -#define LJ_ASMF_NORET LJ_ASMF LJ_NORET - -/* Runtime assertions. */ -#ifdef lua_assert -#define check_exp(c, e) (lua_assert(c), (e)) -#define api_check(l, e) lua_assert(e) -#else -#define lua_assert(c) ((void)0) -#define check_exp(c, e) (e) -#define api_check luai_apicheck -#endif - -/* Static assertions. */ -#define LJ_ASSERT_NAME2(name, line) name ## line -#define LJ_ASSERT_NAME(line) LJ_ASSERT_NAME2(lj_assert_, line) -#ifdef __COUNTER__ -#define LJ_STATIC_ASSERT(cond) \ - extern void LJ_ASSERT_NAME(__COUNTER__)(int STATIC_ASSERTION_FAILED[(cond)?1:-1]) -#else -#define LJ_STATIC_ASSERT(cond) \ - extern void LJ_ASSERT_NAME(__LINE__)(int STATIC_ASSERTION_FAILED[(cond)?1:-1]) -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_dispatch.c b/lib/LuaJIT/src/lj_dispatch.c deleted file mode 100644 index 5d6795f..0000000 --- a/lib/LuaJIT/src/lj_dispatch.c +++ /dev/null @@ -1,557 +0,0 @@ -/* -** Instruction dispatch handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_dispatch_c -#define LUA_CORE - -#include "lj_obj.h" -#include "lj_err.h" -#include "lj_buf.h" -#include "lj_func.h" -#include "lj_str.h" -#include "lj_tab.h" -#include "lj_meta.h" -#include "lj_debug.h" -#include "lj_state.h" -#include "lj_frame.h" -#include "lj_bc.h" -#include "lj_ff.h" -#include "lj_strfmt.h" -#if LJ_HASJIT -#include "lj_jit.h" -#endif -#if LJ_HASFFI -#include "lj_ccallback.h" -#endif -#include "lj_trace.h" -#include "lj_dispatch.h" -#if LJ_HASPROFILE -#include "lj_profile.h" -#endif -#include "lj_vm.h" -#include "luajit.h" - -/* Bump GG_NUM_ASMFF in lj_dispatch.h as needed. Ugly. */ -LJ_STATIC_ASSERT(GG_NUM_ASMFF == FF_NUM_ASMFUNC); - -/* -- Dispatch table management ------------------------------------------- */ - -#if LJ_TARGET_MIPS -#include -LJ_FUNCA_NORET void LJ_FASTCALL lj_ffh_coroutine_wrap_err(lua_State *L, - lua_State *co); -#if !LJ_HASJIT -#define lj_dispatch_stitch lj_dispatch_ins -#endif -#if !LJ_HASPROFILE -#define lj_dispatch_profile lj_dispatch_ins -#endif - -#define GOTFUNC(name) (ASMFunction)name, -static const ASMFunction dispatch_got[] = { - GOTDEF(GOTFUNC) -}; -#undef GOTFUNC -#endif - -/* Initialize instruction dispatch table and hot counters. */ -void lj_dispatch_init(GG_State *GG) -{ - uint32_t i; - ASMFunction *disp = GG->dispatch; - for (i = 0; i < GG_LEN_SDISP; i++) - disp[GG_LEN_DDISP+i] = disp[i] = makeasmfunc(lj_bc_ofs[i]); - for (i = GG_LEN_SDISP; i < GG_LEN_DDISP; i++) - disp[i] = makeasmfunc(lj_bc_ofs[i]); - /* The JIT engine is off by default. luaopen_jit() turns it on. */ - disp[BC_FORL] = disp[BC_IFORL]; - disp[BC_ITERL] = disp[BC_IITERL]; - disp[BC_LOOP] = disp[BC_ILOOP]; - disp[BC_FUNCF] = disp[BC_IFUNCF]; - disp[BC_FUNCV] = disp[BC_IFUNCV]; - GG->g.bc_cfunc_ext = GG->g.bc_cfunc_int = BCINS_AD(BC_FUNCC, LUA_MINSTACK, 0); - for (i = 0; i < GG_NUM_ASMFF; i++) - GG->bcff[i] = BCINS_AD(BC__MAX+i, 0, 0); -#if LJ_TARGET_MIPS - memcpy(GG->got, dispatch_got, LJ_GOT__MAX*sizeof(ASMFunction *)); -#endif -} - -#if LJ_HASJIT -/* Initialize hotcount table. */ -void lj_dispatch_init_hotcount(global_State *g) -{ - int32_t hotloop = G2J(g)->param[JIT_P_hotloop]; - HotCount start = (HotCount)(hotloop*HOTCOUNT_LOOP - 1); - HotCount *hotcount = G2GG(g)->hotcount; - uint32_t i; - for (i = 0; i < HOTCOUNT_SIZE; i++) - hotcount[i] = start; -} -#endif - -/* Internal dispatch mode bits. */ -#define DISPMODE_CALL 0x01 /* Override call dispatch. */ -#define DISPMODE_RET 0x02 /* Override return dispatch. */ -#define DISPMODE_INS 0x04 /* Override instruction dispatch. */ -#define DISPMODE_JIT 0x10 /* JIT compiler on. */ -#define DISPMODE_REC 0x20 /* Recording active. */ -#define DISPMODE_PROF 0x40 /* Profiling active. */ - -/* Update dispatch table depending on various flags. */ -void lj_dispatch_update(global_State *g) -{ - uint8_t oldmode = g->dispatchmode; - uint8_t mode = 0; -#if LJ_HASJIT - mode |= (G2J(g)->flags & JIT_F_ON) ? DISPMODE_JIT : 0; - mode |= G2J(g)->state != LJ_TRACE_IDLE ? - (DISPMODE_REC|DISPMODE_INS|DISPMODE_CALL) : 0; -#endif -#if LJ_HASPROFILE - mode |= (g->hookmask & HOOK_PROFILE) ? (DISPMODE_PROF|DISPMODE_INS) : 0; -#endif - mode |= (g->hookmask & (LUA_MASKLINE|LUA_MASKCOUNT)) ? DISPMODE_INS : 0; - mode |= (g->hookmask & LUA_MASKCALL) ? DISPMODE_CALL : 0; - mode |= (g->hookmask & LUA_MASKRET) ? DISPMODE_RET : 0; - if (oldmode != mode) { /* Mode changed? */ - ASMFunction *disp = G2GG(g)->dispatch; - ASMFunction f_forl, f_iterl, f_loop, f_funcf, f_funcv; - g->dispatchmode = mode; - - /* Hotcount if JIT is on, but not while recording. */ - if ((mode & (DISPMODE_JIT|DISPMODE_REC)) == DISPMODE_JIT) { - f_forl = makeasmfunc(lj_bc_ofs[BC_FORL]); - f_iterl = makeasmfunc(lj_bc_ofs[BC_ITERL]); - f_loop = makeasmfunc(lj_bc_ofs[BC_LOOP]); - f_funcf = makeasmfunc(lj_bc_ofs[BC_FUNCF]); - f_funcv = makeasmfunc(lj_bc_ofs[BC_FUNCV]); - } else { /* Otherwise use the non-hotcounting instructions. */ - f_forl = disp[GG_LEN_DDISP+BC_IFORL]; - f_iterl = disp[GG_LEN_DDISP+BC_IITERL]; - f_loop = disp[GG_LEN_DDISP+BC_ILOOP]; - f_funcf = makeasmfunc(lj_bc_ofs[BC_IFUNCF]); - f_funcv = makeasmfunc(lj_bc_ofs[BC_IFUNCV]); - } - /* Init static counting instruction dispatch first (may be copied below). */ - disp[GG_LEN_DDISP+BC_FORL] = f_forl; - disp[GG_LEN_DDISP+BC_ITERL] = f_iterl; - disp[GG_LEN_DDISP+BC_LOOP] = f_loop; - - /* Set dynamic instruction dispatch. */ - if ((oldmode ^ mode) & (DISPMODE_PROF|DISPMODE_REC|DISPMODE_INS)) { - /* Need to update the whole table. */ - if (!(mode & DISPMODE_INS)) { /* No ins dispatch? */ - /* Copy static dispatch table to dynamic dispatch table. */ - memcpy(&disp[0], &disp[GG_LEN_DDISP], GG_LEN_SDISP*sizeof(ASMFunction)); - /* Overwrite with dynamic return dispatch. */ - if ((mode & DISPMODE_RET)) { - disp[BC_RETM] = lj_vm_rethook; - disp[BC_RET] = lj_vm_rethook; - disp[BC_RET0] = lj_vm_rethook; - disp[BC_RET1] = lj_vm_rethook; - } - } else { - /* The recording dispatch also checks for hooks. */ - ASMFunction f = (mode & DISPMODE_PROF) ? lj_vm_profhook : - (mode & DISPMODE_REC) ? lj_vm_record : lj_vm_inshook; - uint32_t i; - for (i = 0; i < GG_LEN_SDISP; i++) - disp[i] = f; - } - } else if (!(mode & DISPMODE_INS)) { - /* Otherwise set dynamic counting ins. */ - disp[BC_FORL] = f_forl; - disp[BC_ITERL] = f_iterl; - disp[BC_LOOP] = f_loop; - /* Set dynamic return dispatch. */ - if ((mode & DISPMODE_RET)) { - disp[BC_RETM] = lj_vm_rethook; - disp[BC_RET] = lj_vm_rethook; - disp[BC_RET0] = lj_vm_rethook; - disp[BC_RET1] = lj_vm_rethook; - } else { - disp[BC_RETM] = disp[GG_LEN_DDISP+BC_RETM]; - disp[BC_RET] = disp[GG_LEN_DDISP+BC_RET]; - disp[BC_RET0] = disp[GG_LEN_DDISP+BC_RET0]; - disp[BC_RET1] = disp[GG_LEN_DDISP+BC_RET1]; - } - } - - /* Set dynamic call dispatch. */ - if ((oldmode ^ mode) & DISPMODE_CALL) { /* Update the whole table? */ - uint32_t i; - if ((mode & DISPMODE_CALL) == 0) { /* No call hooks? */ - for (i = GG_LEN_SDISP; i < GG_LEN_DDISP; i++) - disp[i] = makeasmfunc(lj_bc_ofs[i]); - } else { - for (i = GG_LEN_SDISP; i < GG_LEN_DDISP; i++) - disp[i] = lj_vm_callhook; - } - } - if (!(mode & DISPMODE_CALL)) { /* Overwrite dynamic counting ins. */ - disp[BC_FUNCF] = f_funcf; - disp[BC_FUNCV] = f_funcv; - } - -#if LJ_HASJIT - /* Reset hotcounts for JIT off to on transition. */ - if ((mode & DISPMODE_JIT) && !(oldmode & DISPMODE_JIT)) - lj_dispatch_init_hotcount(g); -#endif - } -} - -/* -- JIT mode setting ---------------------------------------------------- */ - -#if LJ_HASJIT -/* Set JIT mode for a single prototype. */ -static void setptmode(global_State *g, GCproto *pt, int mode) -{ - if ((mode & LUAJIT_MODE_ON)) { /* (Re-)enable JIT compilation. */ - pt->flags &= ~PROTO_NOJIT; - lj_trace_reenableproto(pt); /* Unpatch all ILOOP etc. bytecodes. */ - } else { /* Flush and/or disable JIT compilation. */ - if (!(mode & LUAJIT_MODE_FLUSH)) - pt->flags |= PROTO_NOJIT; - lj_trace_flushproto(g, pt); /* Flush all traces of prototype. */ - } -} - -/* Recursively set the JIT mode for all children of a prototype. */ -static void setptmode_all(global_State *g, GCproto *pt, int mode) -{ - ptrdiff_t i; - if (!(pt->flags & PROTO_CHILD)) return; - for (i = -(ptrdiff_t)pt->sizekgc; i < 0; i++) { - GCobj *o = proto_kgc(pt, i); - if (o->gch.gct == ~LJ_TPROTO) { - setptmode(g, gco2pt(o), mode); - setptmode_all(g, gco2pt(o), mode); - } - } -} -#endif - -/* Public API function: control the JIT engine. */ -int luaJIT_setmode(lua_State *L, int idx, int mode) -{ - global_State *g = G(L); - int mm = mode & LUAJIT_MODE_MASK; - lj_trace_abort(g); /* Abort recording on any state change. */ - /* Avoid pulling the rug from under our own feet. */ - if ((g->hookmask & HOOK_GC)) - lj_err_caller(L, LJ_ERR_NOGCMM); - switch (mm) { -#if LJ_HASJIT - case LUAJIT_MODE_ENGINE: - if ((mode & LUAJIT_MODE_FLUSH)) { - lj_trace_flushall(L); - } else { - if (!(mode & LUAJIT_MODE_ON)) - G2J(g)->flags &= ~(uint32_t)JIT_F_ON; -#if LJ_TARGET_X86ORX64 - else if ((G2J(g)->flags & JIT_F_SSE2)) - G2J(g)->flags |= (uint32_t)JIT_F_ON; - else - return 0; /* Don't turn on JIT compiler without SSE2 support. */ -#else - else - G2J(g)->flags |= (uint32_t)JIT_F_ON; -#endif - lj_dispatch_update(g); - } - break; - case LUAJIT_MODE_FUNC: - case LUAJIT_MODE_ALLFUNC: - case LUAJIT_MODE_ALLSUBFUNC: { - cTValue *tv = idx == 0 ? frame_prev(L->base-1)-LJ_FR2 : - idx > 0 ? L->base + (idx-1) : L->top + idx; - GCproto *pt; - if ((idx == 0 || tvisfunc(tv)) && isluafunc(&gcval(tv)->fn)) - pt = funcproto(&gcval(tv)->fn); /* Cannot use funcV() for frame slot. */ - else if (tvisproto(tv)) - pt = protoV(tv); - else - return 0; /* Failed. */ - if (mm != LUAJIT_MODE_ALLSUBFUNC) - setptmode(g, pt, mode); - if (mm != LUAJIT_MODE_FUNC) - setptmode_all(g, pt, mode); - break; - } - case LUAJIT_MODE_TRACE: - if (!(mode & LUAJIT_MODE_FLUSH)) - return 0; /* Failed. */ - lj_trace_flush(G2J(g), idx); - break; -#else - case LUAJIT_MODE_ENGINE: - case LUAJIT_MODE_FUNC: - case LUAJIT_MODE_ALLFUNC: - case LUAJIT_MODE_ALLSUBFUNC: - UNUSED(idx); - if ((mode & LUAJIT_MODE_ON)) - return 0; /* Failed. */ - break; -#endif - case LUAJIT_MODE_WRAPCFUNC: - if ((mode & LUAJIT_MODE_ON)) { - if (idx != 0) { - cTValue *tv = idx > 0 ? L->base + (idx-1) : L->top + idx; - if (tvislightud(tv)) - g->wrapf = (lua_CFunction)lightudV(tv); - else - return 0; /* Failed. */ - } else { - return 0; /* Failed. */ - } - g->bc_cfunc_ext = BCINS_AD(BC_FUNCCW, 0, 0); - } else { - g->bc_cfunc_ext = BCINS_AD(BC_FUNCC, 0, 0); - } - break; - default: - return 0; /* Failed. */ - } - return 1; /* OK. */ -} - -/* Enforce (dynamic) linker error for version mismatches. See luajit.c. */ -LUA_API void LUAJIT_VERSION_SYM(void) -{ -} - -/* -- Hooks --------------------------------------------------------------- */ - -/* This function can be called asynchronously (e.g. during a signal). */ -LUA_API int lua_sethook(lua_State *L, lua_Hook func, int mask, int count) -{ - global_State *g = G(L); - mask &= HOOK_EVENTMASK; - if (func == NULL || mask == 0) { mask = 0; func = NULL; } /* Consistency. */ - g->hookf = func; - g->hookcount = g->hookcstart = (int32_t)count; - g->hookmask = (uint8_t)((g->hookmask & ~HOOK_EVENTMASK) | mask); - lj_trace_abort(g); /* Abort recording on any hook change. */ - lj_dispatch_update(g); - return 1; -} - -LUA_API lua_Hook lua_gethook(lua_State *L) -{ - return G(L)->hookf; -} - -LUA_API int lua_gethookmask(lua_State *L) -{ - return G(L)->hookmask & HOOK_EVENTMASK; -} - -LUA_API int lua_gethookcount(lua_State *L) -{ - return (int)G(L)->hookcstart; -} - -/* Call a hook. */ -static void callhook(lua_State *L, int event, BCLine line) -{ - global_State *g = G(L); - lua_Hook hookf = g->hookf; - if (hookf && !hook_active(g)) { - lua_Debug ar; - lj_trace_abort(g); /* Abort recording on any hook call. */ - ar.event = event; - ar.currentline = line; - /* Top frame, nextframe = NULL. */ - ar.i_ci = (int)((L->base-1) - tvref(L->stack)); - lj_state_checkstack(L, 1+LUA_MINSTACK); -#if LJ_HASPROFILE && !LJ_PROFILE_SIGPROF - lj_profile_hook_enter(g); -#else - hook_enter(g); -#endif - hookf(L, &ar); - lua_assert(hook_active(g)); - setgcref(g->cur_L, obj2gco(L)); -#if LJ_HASPROFILE && !LJ_PROFILE_SIGPROF - lj_profile_hook_leave(g); -#else - hook_leave(g); -#endif - } -} - -/* -- Dispatch callbacks -------------------------------------------------- */ - -/* Calculate number of used stack slots in the current frame. */ -static BCReg cur_topslot(GCproto *pt, const BCIns *pc, uint32_t nres) -{ - BCIns ins = pc[-1]; - if (bc_op(ins) == BC_UCLO) - ins = pc[bc_j(ins)]; - switch (bc_op(ins)) { - case BC_CALLM: case BC_CALLMT: return bc_a(ins) + bc_c(ins) + nres-1+1+LJ_FR2; - case BC_RETM: return bc_a(ins) + bc_d(ins) + nres-1; - case BC_TSETM: return bc_a(ins) + nres-1; - default: return pt->framesize; - } -} - -/* Instruction dispatch. Used by instr/line/return hooks or when recording. */ -void LJ_FASTCALL lj_dispatch_ins(lua_State *L, const BCIns *pc) -{ - ERRNO_SAVE - GCfunc *fn = curr_func(L); - GCproto *pt = funcproto(fn); - void *cf = cframe_raw(L->cframe); - const BCIns *oldpc = cframe_pc(cf); - global_State *g = G(L); - BCReg slots; - setcframe_pc(cf, pc); - slots = cur_topslot(pt, pc, cframe_multres_n(cf)); - L->top = L->base + slots; /* Fix top. */ -#if LJ_HASJIT - { - jit_State *J = G2J(g); - if (J->state != LJ_TRACE_IDLE) { -#ifdef LUA_USE_ASSERT - ptrdiff_t delta = L->top - L->base; -#endif - J->L = L; - lj_trace_ins(J, pc-1); /* The interpreter bytecode PC is offset by 1. */ - lua_assert(L->top - L->base == delta); - } - } -#endif - if ((g->hookmask & LUA_MASKCOUNT) && g->hookcount == 0) { - g->hookcount = g->hookcstart; - callhook(L, LUA_HOOKCOUNT, -1); - L->top = L->base + slots; /* Fix top again. */ - } - if ((g->hookmask & LUA_MASKLINE)) { - BCPos npc = proto_bcpos(pt, pc) - 1; - BCPos opc = proto_bcpos(pt, oldpc) - 1; - BCLine line = lj_debug_line(pt, npc); - if (pc <= oldpc || opc >= pt->sizebc || line != lj_debug_line(pt, opc)) { - callhook(L, LUA_HOOKLINE, line); - L->top = L->base + slots; /* Fix top again. */ - } - } - if ((g->hookmask & LUA_MASKRET) && bc_isret(bc_op(pc[-1]))) - callhook(L, LUA_HOOKRET, -1); - ERRNO_RESTORE -} - -/* Initialize call. Ensure stack space and return # of missing parameters. */ -static int call_init(lua_State *L, GCfunc *fn) -{ - if (isluafunc(fn)) { - GCproto *pt = funcproto(fn); - int numparams = pt->numparams; - int gotparams = (int)(L->top - L->base); - int need = pt->framesize; - if ((pt->flags & PROTO_VARARG)) need += 1+gotparams; - lj_state_checkstack(L, (MSize)need); - numparams -= gotparams; - return numparams >= 0 ? numparams : 0; - } else { - lj_state_checkstack(L, LUA_MINSTACK); - return 0; - } -} - -/* Call dispatch. Used by call hooks, hot calls or when recording. */ -ASMFunction LJ_FASTCALL lj_dispatch_call(lua_State *L, const BCIns *pc) -{ - ERRNO_SAVE - GCfunc *fn = curr_func(L); - BCOp op; - global_State *g = G(L); -#if LJ_HASJIT - jit_State *J = G2J(g); -#endif - int missing = call_init(L, fn); -#if LJ_HASJIT - J->L = L; - if ((uintptr_t)pc & 1) { /* Marker for hot call. */ -#ifdef LUA_USE_ASSERT - ptrdiff_t delta = L->top - L->base; -#endif - pc = (const BCIns *)((uintptr_t)pc & ~(uintptr_t)1); - lj_trace_hot(J, pc); - lua_assert(L->top - L->base == delta); - goto out; - } else if (J->state != LJ_TRACE_IDLE && - !(g->hookmask & (HOOK_GC|HOOK_VMEVENT))) { -#ifdef LUA_USE_ASSERT - ptrdiff_t delta = L->top - L->base; -#endif - /* Record the FUNC* bytecodes, too. */ - lj_trace_ins(J, pc-1); /* The interpreter bytecode PC is offset by 1. */ - lua_assert(L->top - L->base == delta); - } -#endif - if ((g->hookmask & LUA_MASKCALL)) { - int i; - for (i = 0; i < missing; i++) /* Add missing parameters. */ - setnilV(L->top++); - callhook(L, LUA_HOOKCALL, -1); - /* Preserve modifications of missing parameters by lua_setlocal(). */ - while (missing-- > 0 && tvisnil(L->top - 1)) - L->top--; - } -#if LJ_HASJIT -out: -#endif - op = bc_op(pc[-1]); /* Get FUNC* op. */ -#if LJ_HASJIT - /* Use the non-hotcounting variants if JIT is off or while recording. */ - if ((!(J->flags & JIT_F_ON) || J->state != LJ_TRACE_IDLE) && - (op == BC_FUNCF || op == BC_FUNCV)) - op = (BCOp)((int)op+(int)BC_IFUNCF-(int)BC_FUNCF); -#endif - ERRNO_RESTORE - return makeasmfunc(lj_bc_ofs[op]); /* Return static dispatch target. */ -} - -#if LJ_HASJIT -/* Stitch a new trace. */ -void LJ_FASTCALL lj_dispatch_stitch(jit_State *J, const BCIns *pc) -{ - ERRNO_SAVE - lua_State *L = J->L; - void *cf = cframe_raw(L->cframe); - const BCIns *oldpc = cframe_pc(cf); - setcframe_pc(cf, pc); - /* Before dispatch, have to bias PC by 1. */ - L->top = L->base + cur_topslot(curr_proto(L), pc+1, cframe_multres_n(cf)); - lj_trace_stitch(J, pc-1); /* Point to the CALL instruction. */ - setcframe_pc(cf, oldpc); - ERRNO_RESTORE -} -#endif - -#if LJ_HASPROFILE -/* Profile dispatch. */ -void LJ_FASTCALL lj_dispatch_profile(lua_State *L, const BCIns *pc) -{ - ERRNO_SAVE - GCfunc *fn = curr_func(L); - GCproto *pt = funcproto(fn); - void *cf = cframe_raw(L->cframe); - const BCIns *oldpc = cframe_pc(cf); - global_State *g; - setcframe_pc(cf, pc); - L->top = L->base + cur_topslot(pt, pc, cframe_multres_n(cf)); - lj_profile_interpreter(L); - setcframe_pc(cf, oldpc); - g = G(L); - setgcref(g->cur_L, obj2gco(L)); - setvmstate(g, INTERP); - ERRNO_RESTORE -} -#endif - diff --git a/lib/LuaJIT/src/lj_dispatch.h b/lib/LuaJIT/src/lj_dispatch.h deleted file mode 100644 index 5bda51a..0000000 --- a/lib/LuaJIT/src/lj_dispatch.h +++ /dev/null @@ -1,156 +0,0 @@ -/* -** Instruction dispatch handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_DISPATCH_H -#define _LJ_DISPATCH_H - -#include "lj_obj.h" -#include "lj_bc.h" -#if LJ_HASJIT -#include "lj_jit.h" -#endif - -#if LJ_TARGET_MIPS -/* Need our own global offset table for the dreaded MIPS calling conventions. */ - -#ifndef _LJ_VM_H -LJ_ASMF int32_t LJ_FASTCALL lj_vm_modi(int32_t a, int32_t b); -#endif - -#if LJ_SOFTFP -#ifndef _LJ_IRCALL_H -extern double __adddf3(double a, double b); -extern double __subdf3(double a, double b); -extern double __muldf3(double a, double b); -extern double __divdf3(double a, double b); -#endif -#define SFGOTDEF(_) _(sqrt) _(__adddf3) _(__subdf3) _(__muldf3) _(__divdf3) -#else -#define SFGOTDEF(_) -#endif -#if LJ_HASJIT -#define JITGOTDEF(_) _(lj_trace_exit) _(lj_trace_hot) -#else -#define JITGOTDEF(_) -#endif -#if LJ_HASFFI -#define FFIGOTDEF(_) \ - _(lj_meta_equal_cd) _(lj_ccallback_enter) _(lj_ccallback_leave) -#else -#define FFIGOTDEF(_) -#endif -#define GOTDEF(_) \ - _(floor) _(ceil) _(trunc) _(log) _(log10) _(exp) _(sin) _(cos) _(tan) \ - _(asin) _(acos) _(atan) _(sinh) _(cosh) _(tanh) _(frexp) _(modf) _(atan2) \ - _(pow) _(fmod) _(ldexp) _(lj_vm_modi) \ - _(lj_dispatch_call) _(lj_dispatch_ins) _(lj_dispatch_stitch) \ - _(lj_dispatch_profile) _(lj_err_throw) \ - _(lj_ffh_coroutine_wrap_err) _(lj_func_closeuv) _(lj_func_newL_gc) \ - _(lj_gc_barrieruv) _(lj_gc_step) _(lj_gc_step_fixtop) _(lj_meta_arith) \ - _(lj_meta_call) _(lj_meta_cat) _(lj_meta_comp) _(lj_meta_equal) \ - _(lj_meta_for) _(lj_meta_istype) _(lj_meta_len) _(lj_meta_tget) \ - _(lj_meta_tset) _(lj_state_growstack) _(lj_strfmt_number) \ - _(lj_str_new) _(lj_tab_dup) _(lj_tab_get) _(lj_tab_getinth) _(lj_tab_len) \ - _(lj_tab_new) _(lj_tab_newkey) _(lj_tab_next) _(lj_tab_reasize) \ - _(lj_tab_setinth) _(lj_buf_putstr_reverse) _(lj_buf_putstr_lower) \ - _(lj_buf_putstr_upper) _(lj_buf_tostr) \ - JITGOTDEF(_) FFIGOTDEF(_) SFGOTDEF(_) - -enum { -#define GOTENUM(name) LJ_GOT_##name, -GOTDEF(GOTENUM) -#undef GOTENUM - LJ_GOT__MAX -}; -#endif - -/* Type of hot counter. Must match the code in the assembler VM. */ -/* 16 bits are sufficient. Only 0.0015% overhead with maximum slot penalty. */ -typedef uint16_t HotCount; - -/* Number of hot counter hash table entries (must be a power of two). */ -#define HOTCOUNT_SIZE 64 -#define HOTCOUNT_PCMASK ((HOTCOUNT_SIZE-1)*sizeof(HotCount)) - -/* Hotcount decrements. */ -#define HOTCOUNT_LOOP 2 -#define HOTCOUNT_CALL 1 - -/* This solves a circular dependency problem -- bump as needed. Sigh. */ -#define GG_NUM_ASMFF 57 - -#define GG_LEN_DDISP (BC__MAX + GG_NUM_ASMFF) -#define GG_LEN_SDISP BC_FUNCF -#define GG_LEN_DISP (GG_LEN_DDISP + GG_LEN_SDISP) - -/* Global state, main thread and extra fields are allocated together. */ -typedef struct GG_State { - lua_State L; /* Main thread. */ - global_State g; /* Global state. */ -#if LJ_TARGET_MIPS - ASMFunction got[LJ_GOT__MAX]; /* Global offset table. */ -#endif -#if LJ_HASJIT - jit_State J; /* JIT state. */ - HotCount hotcount[HOTCOUNT_SIZE]; /* Hot counters. */ -#endif - ASMFunction dispatch[GG_LEN_DISP]; /* Instruction dispatch tables. */ - BCIns bcff[GG_NUM_ASMFF]; /* Bytecode for ASM fast functions. */ -} GG_State; - -#define GG_OFS(field) ((int)offsetof(GG_State, field)) -#define G2GG(gl) ((GG_State *)((char *)(gl) - GG_OFS(g))) -#define J2GG(j) ((GG_State *)((char *)(j) - GG_OFS(J))) -#define L2GG(L) (G2GG(G(L))) -#define J2G(J) (&J2GG(J)->g) -#define G2J(gl) (&G2GG(gl)->J) -#define L2J(L) (&L2GG(L)->J) -#define GG_G2J (GG_OFS(J) - GG_OFS(g)) -#define GG_G2DISP (GG_OFS(dispatch) - GG_OFS(g)) -#define GG_DISP2G (GG_OFS(g) - GG_OFS(dispatch)) -#define GG_DISP2J (GG_OFS(J) - GG_OFS(dispatch)) -#define GG_DISP2HOT (GG_OFS(hotcount) - GG_OFS(dispatch)) -#define GG_DISP2STATIC (GG_LEN_DDISP*(int)sizeof(ASMFunction)) - -#define hotcount_get(gg, pc) \ - (gg)->hotcount[(u32ptr(pc)>>2) & (HOTCOUNT_SIZE-1)] -#define hotcount_set(gg, pc, val) \ - (hotcount_get((gg), (pc)) = (HotCount)(val)) - -/* Dispatch table management. */ -LJ_FUNC void lj_dispatch_init(GG_State *GG); -#if LJ_HASJIT -LJ_FUNC void lj_dispatch_init_hotcount(global_State *g); -#endif -LJ_FUNC void lj_dispatch_update(global_State *g); - -/* Instruction dispatch callback for hooks or when recording. */ -LJ_FUNCA void LJ_FASTCALL lj_dispatch_ins(lua_State *L, const BCIns *pc); -LJ_FUNCA ASMFunction LJ_FASTCALL lj_dispatch_call(lua_State *L, const BCIns*pc); -#if LJ_HASJIT -LJ_FUNCA void LJ_FASTCALL lj_dispatch_stitch(jit_State *J, const BCIns *pc); -#endif -#if LJ_HASPROFILE -LJ_FUNCA void LJ_FASTCALL lj_dispatch_profile(lua_State *L, const BCIns *pc); -#endif - -#if LJ_HASFFI && !defined(_BUILDVM_H) -/* Save/restore errno and GetLastError() around hooks, exits and recording. */ -#include -#if LJ_TARGET_WINDOWS -#define WIN32_LEAN_AND_MEAN -#include -#define ERRNO_SAVE int olderr = errno; DWORD oldwerr = GetLastError(); -#define ERRNO_RESTORE errno = olderr; SetLastError(oldwerr); -#else -#define ERRNO_SAVE int olderr = errno; -#define ERRNO_RESTORE errno = olderr; -#endif -#else -#define ERRNO_SAVE -#define ERRNO_RESTORE -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_emit_arm.h b/lib/LuaJIT/src/lj_emit_arm.h deleted file mode 100644 index dee8bdc..0000000 --- a/lib/LuaJIT/src/lj_emit_arm.h +++ /dev/null @@ -1,357 +0,0 @@ -/* -** ARM instruction emitter. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -/* -- Constant encoding --------------------------------------------------- */ - -static uint8_t emit_invai[16] = { - /* AND */ (ARMI_AND^ARMI_BIC) >> 21, - /* EOR */ 0, - /* SUB */ (ARMI_SUB^ARMI_ADD) >> 21, - /* RSB */ 0, - /* ADD */ (ARMI_ADD^ARMI_SUB) >> 21, - /* ADC */ (ARMI_ADC^ARMI_SBC) >> 21, - /* SBC */ (ARMI_SBC^ARMI_ADC) >> 21, - /* RSC */ 0, - /* TST */ 0, - /* TEQ */ 0, - /* CMP */ (ARMI_CMP^ARMI_CMN) >> 21, - /* CMN */ (ARMI_CMN^ARMI_CMP) >> 21, - /* ORR */ 0, - /* MOV */ (ARMI_MOV^ARMI_MVN) >> 21, - /* BIC */ (ARMI_BIC^ARMI_AND) >> 21, - /* MVN */ (ARMI_MVN^ARMI_MOV) >> 21 -}; - -/* Encode constant in K12 format for data processing instructions. */ -static uint32_t emit_isk12(ARMIns ai, int32_t n) -{ - uint32_t invai, i, m = (uint32_t)n; - /* K12: unsigned 8 bit value, rotated in steps of two bits. */ - for (i = 0; i < 4096; i += 256, m = lj_rol(m, 2)) - if (m <= 255) return ARMI_K12|m|i; - /* Otherwise try negation/complement with the inverse instruction. */ - invai = emit_invai[((ai >> 21) & 15)]; - if (!invai) return 0; /* Failed. No inverse instruction. */ - m = ~(uint32_t)n; - if (invai == ((ARMI_SUB^ARMI_ADD) >> 21) || - invai == (ARMI_CMP^ARMI_CMN) >> 21) m++; - for (i = 0; i < 4096; i += 256, m = lj_rol(m, 2)) - if (m <= 255) return ARMI_K12|(invai<<21)|m|i; - return 0; /* Failed. */ -} - -/* -- Emit basic instructions --------------------------------------------- */ - -static void emit_dnm(ASMState *as, ARMIns ai, Reg rd, Reg rn, Reg rm) -{ - *--as->mcp = ai | ARMF_D(rd) | ARMF_N(rn) | ARMF_M(rm); -} - -static void emit_dm(ASMState *as, ARMIns ai, Reg rd, Reg rm) -{ - *--as->mcp = ai | ARMF_D(rd) | ARMF_M(rm); -} - -static void emit_dn(ASMState *as, ARMIns ai, Reg rd, Reg rn) -{ - *--as->mcp = ai | ARMF_D(rd) | ARMF_N(rn); -} - -static void emit_nm(ASMState *as, ARMIns ai, Reg rn, Reg rm) -{ - *--as->mcp = ai | ARMF_N(rn) | ARMF_M(rm); -} - -static void emit_d(ASMState *as, ARMIns ai, Reg rd) -{ - *--as->mcp = ai | ARMF_D(rd); -} - -static void emit_n(ASMState *as, ARMIns ai, Reg rn) -{ - *--as->mcp = ai | ARMF_N(rn); -} - -static void emit_m(ASMState *as, ARMIns ai, Reg rm) -{ - *--as->mcp = ai | ARMF_M(rm); -} - -static void emit_lsox(ASMState *as, ARMIns ai, Reg rd, Reg rn, int32_t ofs) -{ - lua_assert(ofs >= -255 && ofs <= 255); - if (ofs < 0) ofs = -ofs; else ai |= ARMI_LS_U; - *--as->mcp = ai | ARMI_LS_P | ARMI_LSX_I | ARMF_D(rd) | ARMF_N(rn) | - ((ofs & 0xf0) << 4) | (ofs & 0x0f); -} - -static void emit_lso(ASMState *as, ARMIns ai, Reg rd, Reg rn, int32_t ofs) -{ - lua_assert(ofs >= -4095 && ofs <= 4095); - /* Combine LDR/STR pairs to LDRD/STRD. */ - if (*as->mcp == (ai|ARMI_LS_P|ARMI_LS_U|ARMF_D(rd^1)|ARMF_N(rn)|(ofs^4)) && - (ai & ~(ARMI_LDR^ARMI_STR)) == ARMI_STR && rd != rn && - (uint32_t)ofs <= 252 && !(ofs & 3) && !((rd ^ (ofs >>2)) & 1) && - as->mcp != as->mcloop) { - as->mcp++; - emit_lsox(as, ai == ARMI_LDR ? ARMI_LDRD : ARMI_STRD, rd&~1, rn, ofs&~4); - return; - } - if (ofs < 0) ofs = -ofs; else ai |= ARMI_LS_U; - *--as->mcp = ai | ARMI_LS_P | ARMF_D(rd) | ARMF_N(rn) | ofs; -} - -#if !LJ_SOFTFP -static void emit_vlso(ASMState *as, ARMIns ai, Reg rd, Reg rn, int32_t ofs) -{ - lua_assert(ofs >= -1020 && ofs <= 1020 && (ofs&3) == 0); - if (ofs < 0) ofs = -ofs; else ai |= ARMI_LS_U; - *--as->mcp = ai | ARMI_LS_P | ARMF_D(rd & 15) | ARMF_N(rn) | (ofs >> 2); -} -#endif - -/* -- Emit loads/stores --------------------------------------------------- */ - -/* Prefer spills of BASE/L. */ -#define emit_canremat(ref) ((ref) < ASMREF_L) - -/* Try to find a one step delta relative to another constant. */ -static int emit_kdelta1(ASMState *as, Reg d, int32_t i) -{ - RegSet work = ~as->freeset & RSET_GPR; - while (work) { - Reg r = rset_picktop(work); - IRRef ref = regcost_ref(as->cost[r]); - lua_assert(r != d); - if (emit_canremat(ref)) { - int32_t delta = i - (ra_iskref(ref) ? ra_krefk(as, ref) : IR(ref)->i); - uint32_t k = emit_isk12(ARMI_ADD, delta); - if (k) { - if (k == ARMI_K12) - emit_dm(as, ARMI_MOV, d, r); - else - emit_dn(as, ARMI_ADD^k, d, r); - return 1; - } - } - rset_clear(work, r); - } - return 0; /* Failed. */ -} - -/* Try to find a two step delta relative to another constant. */ -static int emit_kdelta2(ASMState *as, Reg d, int32_t i) -{ - RegSet work = ~as->freeset & RSET_GPR; - while (work) { - Reg r = rset_picktop(work); - IRRef ref = regcost_ref(as->cost[r]); - lua_assert(r != d); - if (emit_canremat(ref)) { - int32_t other = ra_iskref(ref) ? ra_krefk(as, ref) : IR(ref)->i; - if (other) { - int32_t delta = i - other; - uint32_t sh, inv = 0, k2, k; - if (delta < 0) { delta = -delta; inv = ARMI_ADD^ARMI_SUB; } - sh = lj_ffs(delta) & ~1; - k2 = emit_isk12(0, delta & (255 << sh)); - k = emit_isk12(0, delta & ~(255 << sh)); - if (k) { - emit_dn(as, ARMI_ADD^k2^inv, d, d); - emit_dn(as, ARMI_ADD^k^inv, d, r); - return 1; - } - } - } - rset_clear(work, r); - } - return 0; /* Failed. */ -} - -/* Load a 32 bit constant into a GPR. */ -static void emit_loadi(ASMState *as, Reg r, int32_t i) -{ - uint32_t k = emit_isk12(ARMI_MOV, i); - lua_assert(rset_test(as->freeset, r) || r == RID_TMP); - if (k) { - /* Standard K12 constant. */ - emit_d(as, ARMI_MOV^k, r); - } else if ((as->flags & JIT_F_ARMV6T2) && (uint32_t)i < 0x00010000u) { - /* 16 bit loword constant for ARMv6T2. */ - emit_d(as, ARMI_MOVW|(i & 0x0fff)|((i & 0xf000)<<4), r); - } else if (emit_kdelta1(as, r, i)) { - /* One step delta relative to another constant. */ - } else if ((as->flags & JIT_F_ARMV6T2)) { - /* 32 bit hiword/loword constant for ARMv6T2. */ - emit_d(as, ARMI_MOVT|((i>>16) & 0x0fff)|(((i>>16) & 0xf000)<<4), r); - emit_d(as, ARMI_MOVW|(i & 0x0fff)|((i & 0xf000)<<4), r); - } else if (emit_kdelta2(as, r, i)) { - /* Two step delta relative to another constant. */ - } else { - /* Otherwise construct the constant with up to 4 instructions. */ - /* NYI: use mvn+bic, use pc-relative loads. */ - for (;;) { - uint32_t sh = lj_ffs(i) & ~1; - int32_t m = i & (255 << sh); - i &= ~(255 << sh); - if (i == 0) { - emit_d(as, ARMI_MOV ^ emit_isk12(0, m), r); - break; - } - emit_dn(as, ARMI_ORR ^ emit_isk12(0, m), r, r); - } - } -} - -#define emit_loada(as, r, addr) emit_loadi(as, (r), i32ptr((addr))) - -static Reg ra_allock(ASMState *as, intptr_t k, RegSet allow); - -/* Get/set from constant pointer. */ -static void emit_lsptr(ASMState *as, ARMIns ai, Reg r, void *p) -{ - int32_t i = i32ptr(p); - emit_lso(as, ai, r, ra_allock(as, (i & ~4095), rset_exclude(RSET_GPR, r)), - (i & 4095)); -} - -#if !LJ_SOFTFP -/* Load a number constant into an FPR. */ -static void emit_loadk64(ASMState *as, Reg r, IRIns *ir) -{ - cTValue *tv = ir_knum(ir); - int32_t i; - if ((as->flags & JIT_F_VFPV3) && !tv->u32.lo) { - uint32_t hi = tv->u32.hi; - uint32_t b = ((hi >> 22) & 0x1ff); - if (!(hi & 0xffff) && (b == 0x100 || b == 0x0ff)) { - *--as->mcp = ARMI_VMOVI_D | ARMF_D(r & 15) | - ((tv->u32.hi >> 12) & 0x00080000) | - ((tv->u32.hi >> 4) & 0x00070000) | - ((tv->u32.hi >> 16) & 0x0000000f); - return; - } - } - i = i32ptr(tv); - emit_vlso(as, ARMI_VLDR_D, r, - ra_allock(as, (i & ~1020), RSET_GPR), (i & 1020)); -} -#endif - -/* Get/set global_State fields. */ -#define emit_getgl(as, r, field) \ - emit_lsptr(as, ARMI_LDR, (r), (void *)&J2G(as->J)->field) -#define emit_setgl(as, r, field) \ - emit_lsptr(as, ARMI_STR, (r), (void *)&J2G(as->J)->field) - -/* Trace number is determined from pc of exit instruction. */ -#define emit_setvmstate(as, i) UNUSED(i) - -/* -- Emit control-flow instructions -------------------------------------- */ - -/* Label for internal jumps. */ -typedef MCode *MCLabel; - -/* Return label pointing to current PC. */ -#define emit_label(as) ((as)->mcp) - -static void emit_branch(ASMState *as, ARMIns ai, MCode *target) -{ - MCode *p = as->mcp; - ptrdiff_t delta = (target - p) - 1; - lua_assert(((delta + 0x00800000) >> 24) == 0); - *--p = ai | ((uint32_t)delta & 0x00ffffffu); - as->mcp = p; -} - -#define emit_jmp(as, target) emit_branch(as, ARMI_B, (target)) - -static void emit_call(ASMState *as, void *target) -{ - MCode *p = --as->mcp; - ptrdiff_t delta = ((char *)target - (char *)p) - 8; - if ((((delta>>2) + 0x00800000) >> 24) == 0) { - if ((delta & 1)) - *p = ARMI_BLX | ((uint32_t)(delta>>2) & 0x00ffffffu) | ((delta&2) << 23); - else - *p = ARMI_BL | ((uint32_t)(delta>>2) & 0x00ffffffu); - } else { /* Target out of range: need indirect call. But don't use R0-R3. */ - Reg r = ra_allock(as, i32ptr(target), RSET_RANGE(RID_R4, RID_R12+1)); - *p = ARMI_BLXr | ARMF_M(r); - } -} - -/* -- Emit generic operations --------------------------------------------- */ - -/* Generic move between two regs. */ -static void emit_movrr(ASMState *as, IRIns *ir, Reg dst, Reg src) -{ -#if LJ_SOFTFP - lua_assert(!irt_isnum(ir->t)); UNUSED(ir); -#else - if (dst >= RID_MAX_GPR) { - emit_dm(as, irt_isnum(ir->t) ? ARMI_VMOV_D : ARMI_VMOV_S, - (dst & 15), (src & 15)); - return; - } -#endif - if (as->mcp != as->mcloop) { /* Swap early registers for loads/stores. */ - MCode ins = *as->mcp, swp = (src^dst); - if ((ins & 0x0c000000) == 0x04000000 && (ins & 0x02000010) != 0x02000010) { - if (!((ins ^ (dst << 16)) & 0x000f0000)) - *as->mcp = ins ^ (swp << 16); /* Swap N in load/store. */ - if (!(ins & 0x00100000) && !((ins ^ (dst << 12)) & 0x0000f000)) - *as->mcp = ins ^ (swp << 12); /* Swap D in store. */ - } - } - emit_dm(as, ARMI_MOV, dst, src); -} - -/* Generic load of register with base and (small) offset address. */ -static void emit_loadofs(ASMState *as, IRIns *ir, Reg r, Reg base, int32_t ofs) -{ -#if LJ_SOFTFP - lua_assert(!irt_isnum(ir->t)); UNUSED(ir); -#else - if (r >= RID_MAX_GPR) - emit_vlso(as, irt_isnum(ir->t) ? ARMI_VLDR_D : ARMI_VLDR_S, r, base, ofs); - else -#endif - emit_lso(as, ARMI_LDR, r, base, ofs); -} - -/* Generic store of register with base and (small) offset address. */ -static void emit_storeofs(ASMState *as, IRIns *ir, Reg r, Reg base, int32_t ofs) -{ -#if LJ_SOFTFP - lua_assert(!irt_isnum(ir->t)); UNUSED(ir); -#else - if (r >= RID_MAX_GPR) - emit_vlso(as, irt_isnum(ir->t) ? ARMI_VSTR_D : ARMI_VSTR_S, r, base, ofs); - else -#endif - emit_lso(as, ARMI_STR, r, base, ofs); -} - -/* Emit an arithmetic/logic operation with a constant operand. */ -static void emit_opk(ASMState *as, ARMIns ai, Reg dest, Reg src, - int32_t i, RegSet allow) -{ - uint32_t k = emit_isk12(ai, i); - if (k) - emit_dn(as, ai^k, dest, src); - else - emit_dnm(as, ai, dest, src, ra_allock(as, i, allow)); -} - -/* Add offset to pointer. */ -static void emit_addptr(ASMState *as, Reg r, int32_t ofs) -{ - if (ofs) - emit_opk(as, ARMI_ADD, r, r, ofs, rset_exclude(RSET_GPR, r)); -} - -#define emit_spsub(as, ofs) emit_addptr(as, RID_SP, -(ofs)) - diff --git a/lib/LuaJIT/src/lj_emit_arm64.h b/lib/LuaJIT/src/lj_emit_arm64.h deleted file mode 100644 index 1001b1d..0000000 --- a/lib/LuaJIT/src/lj_emit_arm64.h +++ /dev/null @@ -1,419 +0,0 @@ -/* -** ARM64 instruction emitter. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Contributed by Djordje Kovacevic and Stefan Pejic from RT-RK.com. -** Sponsored by Cisco Systems, Inc. -*/ - -/* -- Constant encoding --------------------------------------------------- */ - -static uint64_t get_k64val(IRIns *ir) -{ - if (ir->o == IR_KINT64) { - return ir_kint64(ir)->u64; - } else if (ir->o == IR_KGC) { - return (uint64_t)ir_kgc(ir); - } else if (ir->o == IR_KPTR || ir->o == IR_KKPTR) { - return (uint64_t)ir_kptr(ir); - } else { - lua_assert(ir->o == IR_KINT || ir->o == IR_KNULL); - return ir->i; /* Sign-extended. */ - } -} - -/* Encode constant in K12 format for data processing instructions. */ -static uint32_t emit_isk12(int64_t n) -{ - uint64_t k = (n < 0) ? -n : n; - uint32_t m = (n < 0) ? 0x40000000 : 0; - if (k < 0x1000) { - return A64I_K12|m|A64F_U12(k); - } else if ((k & 0xfff000) == k) { - return A64I_K12|m|0x400000|A64F_U12(k>>12); - } - return 0; -} - -#define emit_clz64(n) __builtin_clzll(n) -#define emit_ctz64(n) __builtin_ctzll(n) - -/* Encode constant in K13 format for logical data processing instructions. */ -static uint32_t emit_isk13(uint64_t n, int is64) -{ - int inv = 0, w = 128, lz, tz; - if (n & 1) { n = ~n; w = 64; inv = 1; } /* Avoid wrap-around of ones. */ - if (!n) return 0; /* Neither all-zero nor all-ones are allowed. */ - do { /* Find the repeat width. */ - if (is64 && (uint32_t)(n^(n>>32))) break; - n = (uint32_t)n; - if (!n) return 0; /* Ditto when passing n=0xffffffff and is64=0. */ - w = 32; if ((n^(n>>16)) & 0xffff) break; - n = n & 0xffff; w = 16; if ((n^(n>>8)) & 0xff) break; - n = n & 0xff; w = 8; if ((n^(n>>4)) & 0xf) break; - n = n & 0xf; w = 4; if ((n^(n>>2)) & 0x3) break; - n = n & 0x3; w = 2; - } while (0); - lz = emit_clz64(n); - tz = emit_ctz64(n); - if ((int64_t)(n << lz) >> (lz+tz) != -1ll) return 0; /* Non-contiguous? */ - if (inv) - return A64I_K13 | (((lz-w) & 127) << 16) | (((lz+tz-w-1) & 63) << 10); - else - return A64I_K13 | ((w-tz) << 16) | (((63-lz-tz-w-w) & 63) << 10); -} - -static uint32_t emit_isfpk64(uint64_t n) -{ - uint64_t etop9 = ((n >> 54) & 0x1ff); - if ((n << 16) == 0 && (etop9 == 0x100 || etop9 == 0x0ff)) { - return (uint32_t)(((n >> 48) & 0x7f) | ((n >> 56) & 0x80)); - } - return ~0u; -} - -/* -- Emit basic instructions --------------------------------------------- */ - -static void emit_dnma(ASMState *as, A64Ins ai, Reg rd, Reg rn, Reg rm, Reg ra) -{ - *--as->mcp = ai | A64F_D(rd) | A64F_N(rn) | A64F_M(rm) | A64F_A(ra); -} - -static void emit_dnm(ASMState *as, A64Ins ai, Reg rd, Reg rn, Reg rm) -{ - *--as->mcp = ai | A64F_D(rd) | A64F_N(rn) | A64F_M(rm); -} - -static void emit_dm(ASMState *as, A64Ins ai, Reg rd, Reg rm) -{ - *--as->mcp = ai | A64F_D(rd) | A64F_M(rm); -} - -static void emit_dn(ASMState *as, A64Ins ai, Reg rd, Reg rn) -{ - *--as->mcp = ai | A64F_D(rd) | A64F_N(rn); -} - -static void emit_nm(ASMState *as, A64Ins ai, Reg rn, Reg rm) -{ - *--as->mcp = ai | A64F_N(rn) | A64F_M(rm); -} - -static void emit_d(ASMState *as, A64Ins ai, Reg rd) -{ - *--as->mcp = ai | A64F_D(rd); -} - -static void emit_n(ASMState *as, A64Ins ai, Reg rn) -{ - *--as->mcp = ai | A64F_N(rn); -} - -static int emit_checkofs(A64Ins ai, int64_t ofs) -{ - int scale = (ai >> 30) & 3; - if (ofs < 0 || (ofs & ((1<= -256 && ofs <= 255) ? -1 : 0; - } else { - return (ofs < (4096<> 30) & 3; - lua_assert(ot); - /* Combine LDR/STR pairs to LDP/STP. */ - if ((sc == 2 || sc == 3) && - (!(ai & 0x400000) || rd != rn) && - as->mcp != as->mcloop) { - uint32_t prev = *as->mcp & ~A64F_D(31); - int ofsm = ofs - (1<>sc)) || - prev == ((ai^A64I_LS_U) | A64F_N(rn) | A64F_S9(ofsm&0x1ff))) { - aip = (A64F_A(rd) | A64F_D(*as->mcp & 31)); - } else if (prev == (ai | A64F_N(rn) | A64F_U12(ofsp>>sc)) || - prev == ((ai^A64I_LS_U) | A64F_N(rn) | A64F_S9(ofsp&0x1ff))) { - aip = (A64F_D(rd) | A64F_A(*as->mcp & 31)); - ofsm = ofs; - } else { - goto nopair; - } - if (ofsm >= (int)((unsigned int)-64<mcp = aip | A64F_N(rn) | ((ofsm >> sc) << 15) | - (ai ^ ((ai == A64I_LDRx || ai == A64I_STRx) ? 0x50000000 : 0x90000000)); - return; - } - } -nopair: - if (ot == 1) - *--as->mcp = ai | A64F_D(rd) | A64F_N(rn) | A64F_U12(ofs >> sc); - else - *--as->mcp = (ai^A64I_LS_U) | A64F_D(rd) | A64F_N(rn) | A64F_S9(ofs & 0x1ff); -} - -/* -- Emit loads/stores --------------------------------------------------- */ - -/* Prefer rematerialization of BASE/L from global_State over spills. */ -#define emit_canremat(ref) ((ref) <= ASMREF_L) - -/* Try to find an N-step delta relative to other consts with N < lim. */ -static int emit_kdelta(ASMState *as, Reg rd, uint64_t k, int lim) -{ - RegSet work = ~as->freeset & RSET_GPR; - if (lim <= 1) return 0; /* Can't beat that. */ - while (work) { - Reg r = rset_picktop(work); - IRRef ref = regcost_ref(as->cost[r]); - lua_assert(r != rd); - if (ref < REF_TRUE) { - uint64_t kx = ra_iskref(ref) ? (uint64_t)ra_krefk(as, ref) : - get_k64val(IR(ref)); - int64_t delta = (int64_t)(k - kx); - if (delta == 0) { - emit_dm(as, A64I_MOVx, rd, r); - return 1; - } else { - uint32_t k12 = emit_isk12(delta < 0 ? -delta : delta); - if (k12) { - emit_dn(as, (delta < 0 ? A64I_SUBx : A64I_ADDx)^k12, rd, r); - return 1; - } - /* Do other ops or multi-step deltas pay off? Probably not. - ** E.g. XOR rarely helps with pointer consts. - */ - } - } - rset_clear(work, r); - } - return 0; /* Failed. */ -} - -static void emit_loadk(ASMState *as, Reg rd, uint64_t u64, int is64) -{ - uint32_t k13 = emit_isk13(u64, is64); - if (k13) { /* Can the constant be represented as a bitmask immediate? */ - emit_dn(as, (is64|A64I_ORRw)^k13, rd, RID_ZERO); - } else { - int i, zeros = 0, ones = 0, neg; - if (!is64) u64 = (int64_t)(int32_t)u64; /* Sign-extend. */ - /* Count homogeneous 16 bit fragments. */ - for (i = 0; i < 4; i++) { - uint64_t frag = (u64 >> i*16) & 0xffff; - zeros += (frag == 0); - ones += (frag == 0xffff); - } - neg = ones > zeros; /* Use MOVN if it pays off. */ - if (!emit_kdelta(as, rd, u64, 4 - (neg ? ones : zeros))) { - int shift = 0, lshift = 0; - uint64_t n64 = neg ? ~u64 : u64; - if (n64 != 0) { - /* Find first/last fragment to be filled. */ - shift = (63-emit_clz64(n64)) & ~15; - lshift = emit_ctz64(n64) & ~15; - } - /* MOVK requires the original value (u64). */ - while (shift > lshift) { - uint32_t u16 = (u64 >> shift) & 0xffff; - /* Skip fragments that are correctly filled by MOVN/MOVZ. */ - if (u16 != (neg ? 0xffff : 0)) - emit_d(as, is64 | A64I_MOVKw | A64F_U16(u16) | A64F_LSL16(shift), rd); - shift -= 16; - } - /* But MOVN needs an inverted value (n64). */ - emit_d(as, (neg ? A64I_MOVNx : A64I_MOVZx) | - A64F_U16((n64 >> lshift) & 0xffff) | A64F_LSL16(lshift), rd); - } - } -} - -/* Load a 32 bit constant into a GPR. */ -#define emit_loadi(as, rd, i) emit_loadk(as, rd, i, 0) - -/* Load a 64 bit constant into a GPR. */ -#define emit_loadu64(as, rd, i) emit_loadk(as, rd, i, A64I_X) - -#define emit_loada(as, r, addr) emit_loadu64(as, (r), (uintptr_t)(addr)) - -#define glofs(as, k) \ - ((intptr_t)((uintptr_t)(k) - (uintptr_t)&J2GG(as->J)->g)) -#define mcpofs(as, k) \ - ((intptr_t)((uintptr_t)(k) - (uintptr_t)(as->mcp - 1))) -#define checkmcpofs(as, k) \ - (A64F_S_OK(mcpofs(as, k)>>2, 19)) - -static Reg ra_allock(ASMState *as, intptr_t k, RegSet allow); - -/* Get/set from constant pointer. */ -static void emit_lsptr(ASMState *as, A64Ins ai, Reg r, void *p) -{ - /* First, check if ip + offset is in range. */ - if ((ai & 0x00400000) && checkmcpofs(as, p)) { - emit_d(as, A64I_LDRLx | A64F_S19(mcpofs(as, p)>>2), r); - } else { - Reg base = RID_GL; /* Next, try GL + offset. */ - int64_t ofs = glofs(as, p); - if (!emit_checkofs(ai, ofs)) { /* Else split up into base reg + offset. */ - int64_t i64 = i64ptr(p); - base = ra_allock(as, (i64 & ~0x7fffull), rset_exclude(RSET_GPR, r)); - ofs = i64 & 0x7fffull; - } - emit_lso(as, ai, r, base, ofs); - } -} - -/* Load 64 bit IR constant into register. */ -static void emit_loadk64(ASMState *as, Reg r, IRIns *ir) -{ - const uint64_t *k = &ir_k64(ir)->u64; - int64_t ofs; - if (r >= RID_MAX_GPR) { - uint32_t fpk = emit_isfpk64(*k); - if (fpk != ~0u) { - emit_d(as, A64I_FMOV_DI | A64F_FP8(fpk), (r & 31)); - return; - } - } - ofs = glofs(as, k); - if (emit_checkofs(A64I_LDRx, ofs)) { - emit_lso(as, r >= RID_MAX_GPR ? A64I_LDRd : A64I_LDRx, - (r & 31), RID_GL, ofs); - } else { - if (r >= RID_MAX_GPR) { - emit_dn(as, A64I_FMOV_D_R, (r & 31), RID_TMP); - r = RID_TMP; - } - if (checkmcpofs(as, k)) - emit_d(as, A64I_LDRLx | A64F_S19(mcpofs(as, k)>>2), r); - else - emit_loadu64(as, r, *k); - } -} - -/* Get/set global_State fields. */ -#define emit_getgl(as, r, field) \ - emit_lsptr(as, A64I_LDRx, (r), (void *)&J2G(as->J)->field) -#define emit_setgl(as, r, field) \ - emit_lsptr(as, A64I_STRx, (r), (void *)&J2G(as->J)->field) - -/* Trace number is determined from pc of exit instruction. */ -#define emit_setvmstate(as, i) UNUSED(i) - -/* -- Emit control-flow instructions -------------------------------------- */ - -/* Label for internal jumps. */ -typedef MCode *MCLabel; - -/* Return label pointing to current PC. */ -#define emit_label(as) ((as)->mcp) - -static void emit_cond_branch(ASMState *as, A64CC cond, MCode *target) -{ - MCode *p = --as->mcp; - ptrdiff_t delta = target - p; - lua_assert(A64F_S_OK(delta, 19)); - *p = A64I_BCC | A64F_S19(delta) | cond; -} - -static void emit_branch(ASMState *as, A64Ins ai, MCode *target) -{ - MCode *p = --as->mcp; - ptrdiff_t delta = target - p; - lua_assert(A64F_S_OK(delta, 26)); - *p = ai | A64F_S26(delta); -} - -static void emit_tnb(ASMState *as, A64Ins ai, Reg r, uint32_t bit, MCode *target) -{ - MCode *p = --as->mcp; - ptrdiff_t delta = target - p; - lua_assert(bit < 63 && A64F_S_OK(delta, 14)); - if (bit > 31) ai |= A64I_X; - *p = ai | A64F_BIT(bit & 31) | A64F_S14(delta) | r; -} - -static void emit_cnb(ASMState *as, A64Ins ai, Reg r, MCode *target) -{ - MCode *p = --as->mcp; - ptrdiff_t delta = target - p; - lua_assert(A64F_S_OK(delta, 19)); - *p = ai | A64F_S19(delta) | r; -} - -#define emit_jmp(as, target) emit_branch(as, A64I_B, (target)) - -static void emit_call(ASMState *as, void *target) -{ - MCode *p = --as->mcp; - ptrdiff_t delta = (char *)target - (char *)p; - if (A64F_S_OK(delta>>2, 26)) { - *p = A64I_BL | A64F_S26(delta>>2); - } else { /* Target out of range: need indirect call. But don't use R0-R7. */ - Reg r = ra_allock(as, i64ptr(target), - RSET_RANGE(RID_X8, RID_MAX_GPR)-RSET_FIXED); - *p = A64I_BLR | A64F_N(r); - } -} - -/* -- Emit generic operations --------------------------------------------- */ - -/* Generic move between two regs. */ -static void emit_movrr(ASMState *as, IRIns *ir, Reg dst, Reg src) -{ - if (dst >= RID_MAX_GPR) { - emit_dn(as, irt_isnum(ir->t) ? A64I_FMOV_D : A64I_FMOV_S, - (dst & 31), (src & 31)); - return; - } - if (as->mcp != as->mcloop) { /* Swap early registers for loads/stores. */ - MCode ins = *as->mcp, swp = (src^dst); - if ((ins & 0xbf800000) == 0xb9000000) { - if (!((ins ^ (dst << 5)) & 0x000003e0)) - *as->mcp = ins ^ (swp << 5); /* Swap N in load/store. */ - if (!(ins & 0x00400000) && !((ins ^ dst) & 0x0000001f)) - *as->mcp = ins ^ swp; /* Swap D in store. */ - } - } - emit_dm(as, A64I_MOVx, dst, src); -} - -/* Generic load of register with base and (small) offset address. */ -static void emit_loadofs(ASMState *as, IRIns *ir, Reg r, Reg base, int32_t ofs) -{ - if (r >= RID_MAX_GPR) - emit_lso(as, irt_isnum(ir->t) ? A64I_LDRd : A64I_LDRs, (r & 31), base, ofs); - else - emit_lso(as, irt_is64(ir->t) ? A64I_LDRx : A64I_LDRw, r, base, ofs); -} - -/* Generic store of register with base and (small) offset address. */ -static void emit_storeofs(ASMState *as, IRIns *ir, Reg r, Reg base, int32_t ofs) -{ - if (r >= RID_MAX_GPR) - emit_lso(as, irt_isnum(ir->t) ? A64I_STRd : A64I_STRs, (r & 31), base, ofs); - else - emit_lso(as, irt_is64(ir->t) ? A64I_STRx : A64I_STRw, r, base, ofs); -} - -/* Emit an arithmetic operation with a constant operand. */ -static void emit_opk(ASMState *as, A64Ins ai, Reg dest, Reg src, - int32_t i, RegSet allow) -{ - uint32_t k = emit_isk12(i); - if (k) - emit_dn(as, ai^k, dest, src); - else - emit_dnm(as, ai, dest, src, ra_allock(as, i, allow)); -} - -/* Add offset to pointer. */ -static void emit_addptr(ASMState *as, Reg r, int32_t ofs) -{ - if (ofs) - emit_opk(as, ofs < 0 ? A64I_SUBx : A64I_ADDx, r, r, - ofs < 0 ? -ofs : ofs, rset_exclude(RSET_GPR, r)); -} - -#define emit_spsub(as, ofs) emit_addptr(as, RID_SP, -(ofs)) - diff --git a/lib/LuaJIT/src/lj_emit_mips.h b/lib/LuaJIT/src/lj_emit_mips.h deleted file mode 100644 index bb6593a..0000000 --- a/lib/LuaJIT/src/lj_emit_mips.h +++ /dev/null @@ -1,295 +0,0 @@ -/* -** MIPS instruction emitter. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#if LJ_64 -static intptr_t get_k64val(IRIns *ir) -{ - if (ir->o == IR_KINT64) { - return (intptr_t)ir_kint64(ir)->u64; - } else if (ir->o == IR_KGC) { - return (intptr_t)ir_kgc(ir); - } else if (ir->o == IR_KPTR || ir->o == IR_KKPTR) { - return (intptr_t)ir_kptr(ir); - } else if (LJ_SOFTFP && ir->o == IR_KNUM) { - return (intptr_t)ir_knum(ir)->u64; - } else { - lua_assert(ir->o == IR_KINT || ir->o == IR_KNULL); - return ir->i; /* Sign-extended. */ - } -} -#endif - -#if LJ_64 -#define get_kval(ir) get_k64val(ir) -#else -#define get_kval(ir) ((ir)->i) -#endif - -/* -- Emit basic instructions --------------------------------------------- */ - -static void emit_dst(ASMState *as, MIPSIns mi, Reg rd, Reg rs, Reg rt) -{ - *--as->mcp = mi | MIPSF_D(rd) | MIPSF_S(rs) | MIPSF_T(rt); -} - -static void emit_dta(ASMState *as, MIPSIns mi, Reg rd, Reg rt, uint32_t a) -{ - *--as->mcp = mi | MIPSF_D(rd) | MIPSF_T(rt) | MIPSF_A(a); -} - -#define emit_ds(as, mi, rd, rs) emit_dst(as, (mi), (rd), (rs), 0) -#define emit_tg(as, mi, rt, rg) emit_dst(as, (mi), (rg)&31, 0, (rt)) - -static void emit_tsi(ASMState *as, MIPSIns mi, Reg rt, Reg rs, int32_t i) -{ - *--as->mcp = mi | MIPSF_T(rt) | MIPSF_S(rs) | (i & 0xffff); -} - -#define emit_ti(as, mi, rt, i) emit_tsi(as, (mi), (rt), 0, (i)) -#define emit_hsi(as, mi, rh, rs, i) emit_tsi(as, (mi), (rh) & 31, (rs), (i)) - -static void emit_fgh(ASMState *as, MIPSIns mi, Reg rf, Reg rg, Reg rh) -{ - *--as->mcp = mi | MIPSF_F(rf&31) | MIPSF_G(rg&31) | MIPSF_H(rh&31); -} - -#define emit_fg(as, mi, rf, rg) emit_fgh(as, (mi), (rf), (rg), 0) - -static void emit_rotr(ASMState *as, Reg dest, Reg src, Reg tmp, uint32_t shift) -{ - if (LJ_64 || (as->flags & JIT_F_MIPSXXR2)) { - emit_dta(as, MIPSI_ROTR, dest, src, shift); - } else { - emit_dst(as, MIPSI_OR, dest, dest, tmp); - emit_dta(as, MIPSI_SLL, dest, src, (-shift)&31); - emit_dta(as, MIPSI_SRL, tmp, src, shift); - } -} - -#if LJ_64 -static void emit_tsml(ASMState *as, MIPSIns mi, Reg rt, Reg rs, uint32_t msb, - uint32_t lsb) -{ - *--as->mcp = mi | MIPSF_T(rt) | MIPSF_S(rs) | MIPSF_M(msb) | MIPSF_L(lsb); -} -#endif - -/* -- Emit loads/stores --------------------------------------------------- */ - -/* Prefer rematerialization of BASE/L from global_State over spills. */ -#define emit_canremat(ref) ((ref) <= REF_BASE) - -/* Try to find a one step delta relative to another constant. */ -static int emit_kdelta1(ASMState *as, Reg t, intptr_t i) -{ - RegSet work = ~as->freeset & RSET_GPR; - while (work) { - Reg r = rset_picktop(work); - IRRef ref = regcost_ref(as->cost[r]); - lua_assert(r != t); - if (ref < ASMREF_L) { - intptr_t delta = (intptr_t)((uintptr_t)i - - (uintptr_t)(ra_iskref(ref) ? ra_krefk(as, ref) : get_kval(IR(ref)))); - if (checki16(delta)) { - emit_tsi(as, MIPSI_AADDIU, t, r, delta); - return 1; - } - } - rset_clear(work, r); - } - return 0; /* Failed. */ -} - -/* Load a 32 bit constant into a GPR. */ -static void emit_loadi(ASMState *as, Reg r, int32_t i) -{ - if (checki16(i)) { - emit_ti(as, MIPSI_LI, r, i); - } else { - if ((i & 0xffff)) { - intptr_t jgl = (intptr_t)(void *)J2G(as->J); - if ((uintptr_t)(i-jgl) < 65536) { - emit_tsi(as, MIPSI_ADDIU, r, RID_JGL, i-jgl-32768); - return; - } else if (emit_kdelta1(as, r, i)) { - return; - } else if ((i >> 16) == 0) { - emit_tsi(as, MIPSI_ORI, r, RID_ZERO, i); - return; - } - emit_tsi(as, MIPSI_ORI, r, r, i); - } - emit_ti(as, MIPSI_LUI, r, (i >> 16)); - } -} - -#if LJ_64 -/* Load a 64 bit constant into a GPR. */ -static void emit_loadu64(ASMState *as, Reg r, uint64_t u64) -{ - if (checki32((int64_t)u64)) { - emit_loadi(as, r, (int32_t)u64); - } else { - uint64_t delta = u64 - (uint64_t)(void *)J2G(as->J); - if (delta < 65536) { - emit_tsi(as, MIPSI_DADDIU, r, RID_JGL, (int32_t)(delta-32768)); - } else if (emit_kdelta1(as, r, (intptr_t)u64)) { - return; - } else { - if ((u64 & 0xffff)) { - emit_tsi(as, MIPSI_ORI, r, r, u64 & 0xffff); - } - if (((u64 >> 16) & 0xffff)) { - emit_dta(as, MIPSI_DSLL, r, r, 16); - emit_tsi(as, MIPSI_ORI, r, r, (u64 >> 16) & 0xffff); - emit_dta(as, MIPSI_DSLL, r, r, 16); - } else { - emit_dta(as, MIPSI_DSLL32, r, r, 0); - } - emit_loadi(as, r, (int32_t)(u64 >> 32)); - } - /* TODO: There are probably more optimization opportunities. */ - } -} - -#define emit_loada(as, r, addr) emit_loadu64(as, (r), u64ptr((addr))) -#else -#define emit_loada(as, r, addr) emit_loadi(as, (r), i32ptr((addr))) -#endif - -static Reg ra_allock(ASMState *as, intptr_t k, RegSet allow); -static void ra_allockreg(ASMState *as, intptr_t k, Reg r); - -/* Get/set from constant pointer. */ -static void emit_lsptr(ASMState *as, MIPSIns mi, Reg r, void *p, RegSet allow) -{ - intptr_t jgl = (intptr_t)(J2G(as->J)); - intptr_t i = (intptr_t)(p); - Reg base; - if ((uint32_t)(i-jgl) < 65536) { - i = i-jgl-32768; - base = RID_JGL; - } else { - base = ra_allock(as, i-(int16_t)i, allow); - } - emit_tsi(as, mi, r, base, i); -} - -#if LJ_64 -static void emit_loadk64(ASMState *as, Reg r, IRIns *ir) -{ - const uint64_t *k = &ir_k64(ir)->u64; - Reg r64 = r; - if (rset_test(RSET_FPR, r)) { - r64 = RID_TMP; - emit_tg(as, MIPSI_DMTC1, r64, r); - } - if ((uint32_t)((intptr_t)k-(intptr_t)J2G(as->J)) < 65536) - emit_lsptr(as, MIPSI_LD, r64, (void *)k, 0); - else - emit_loadu64(as, r64, *k); -} -#else -#define emit_loadk64(as, r, ir) \ - emit_lsptr(as, MIPSI_LDC1, ((r) & 31), (void *)&ir_knum((ir))->u64, RSET_GPR) -#endif - -/* Get/set global_State fields. */ -static void emit_lsglptr(ASMState *as, MIPSIns mi, Reg r, int32_t ofs) -{ - emit_tsi(as, mi, r, RID_JGL, ofs-32768); -} - -#define emit_getgl(as, r, field) \ - emit_lsglptr(as, MIPSI_AL, (r), (int32_t)offsetof(global_State, field)) -#define emit_setgl(as, r, field) \ - emit_lsglptr(as, MIPSI_AS, (r), (int32_t)offsetof(global_State, field)) - -/* Trace number is determined from per-trace exit stubs. */ -#define emit_setvmstate(as, i) UNUSED(i) - -/* -- Emit control-flow instructions -------------------------------------- */ - -/* Label for internal jumps. */ -typedef MCode *MCLabel; - -/* Return label pointing to current PC. */ -#define emit_label(as) ((as)->mcp) - -static void emit_branch(ASMState *as, MIPSIns mi, Reg rs, Reg rt, MCode *target) -{ - MCode *p = as->mcp; - ptrdiff_t delta = target - p; - lua_assert(((delta + 0x8000) >> 16) == 0); - *--p = mi | MIPSF_S(rs) | MIPSF_T(rt) | ((uint32_t)delta & 0xffffu); - as->mcp = p; -} - -static void emit_jmp(ASMState *as, MCode *target) -{ - *--as->mcp = MIPSI_NOP; - emit_branch(as, MIPSI_B, RID_ZERO, RID_ZERO, (target)); -} - -static void emit_call(ASMState *as, void *target, int needcfa) -{ - MCode *p = as->mcp; - *--p = MIPSI_NOP; - if ((((uintptr_t)target ^ (uintptr_t)p) >> 28) == 0) { - *--p = (((uintptr_t)target & 1) ? MIPSI_JALX : MIPSI_JAL) | - (((uintptr_t)target >>2) & 0x03ffffffu); - } else { /* Target out of range: need indirect call. */ - *--p = MIPSI_JALR | MIPSF_S(RID_CFUNCADDR); - needcfa = 1; - } - as->mcp = p; - if (needcfa) ra_allockreg(as, (intptr_t)target, RID_CFUNCADDR); -} - -/* -- Emit generic operations --------------------------------------------- */ - -#define emit_move(as, dst, src) \ - emit_ds(as, MIPSI_MOVE, (dst), (src)) - -/* Generic move between two regs. */ -static void emit_movrr(ASMState *as, IRIns *ir, Reg dst, Reg src) -{ - if (dst < RID_MAX_GPR) - emit_move(as, dst, src); - else - emit_fg(as, irt_isnum(ir->t) ? MIPSI_MOV_D : MIPSI_MOV_S, dst, src); -} - -/* Generic load of register with base and (small) offset address. */ -static void emit_loadofs(ASMState *as, IRIns *ir, Reg r, Reg base, int32_t ofs) -{ - if (r < RID_MAX_GPR) - emit_tsi(as, irt_is64(ir->t) ? MIPSI_LD : MIPSI_LW, r, base, ofs); - else - emit_tsi(as, irt_isnum(ir->t) ? MIPSI_LDC1 : MIPSI_LWC1, - (r & 31), base, ofs); -} - -/* Generic store of register with base and (small) offset address. */ -static void emit_storeofs(ASMState *as, IRIns *ir, Reg r, Reg base, int32_t ofs) -{ - if (r < RID_MAX_GPR) - emit_tsi(as, irt_is64(ir->t) ? MIPSI_SD : MIPSI_SW, r, base, ofs); - else - emit_tsi(as, irt_isnum(ir->t) ? MIPSI_SDC1 : MIPSI_SWC1, - (r&31), base, ofs); -} - -/* Add offset to pointer. */ -static void emit_addptr(ASMState *as, Reg r, int32_t ofs) -{ - if (ofs) { - lua_assert(checki16(ofs)); - emit_tsi(as, MIPSI_AADDIU, r, r, ofs); - } -} - -#define emit_spsub(as, ofs) emit_addptr(as, RID_SP, -(ofs)) - diff --git a/lib/LuaJIT/src/lj_emit_ppc.h b/lib/LuaJIT/src/lj_emit_ppc.h deleted file mode 100644 index 21c3c2a..0000000 --- a/lib/LuaJIT/src/lj_emit_ppc.h +++ /dev/null @@ -1,238 +0,0 @@ -/* -** PPC instruction emitter. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -/* -- Emit basic instructions --------------------------------------------- */ - -static void emit_tab(ASMState *as, PPCIns pi, Reg rt, Reg ra, Reg rb) -{ - *--as->mcp = pi | PPCF_T(rt) | PPCF_A(ra) | PPCF_B(rb); -} - -#define emit_asb(as, pi, ra, rs, rb) emit_tab(as, (pi), (rs), (ra), (rb)) -#define emit_as(as, pi, ra, rs) emit_tab(as, (pi), (rs), (ra), 0) -#define emit_ab(as, pi, ra, rb) emit_tab(as, (pi), 0, (ra), (rb)) - -static void emit_tai(ASMState *as, PPCIns pi, Reg rt, Reg ra, int32_t i) -{ - *--as->mcp = pi | PPCF_T(rt) | PPCF_A(ra) | (i & 0xffff); -} - -#define emit_ti(as, pi, rt, i) emit_tai(as, (pi), (rt), 0, (i)) -#define emit_ai(as, pi, ra, i) emit_tai(as, (pi), 0, (ra), (i)) -#define emit_asi(as, pi, ra, rs, i) emit_tai(as, (pi), (rs), (ra), (i)) - -#define emit_fab(as, pi, rf, ra, rb) \ - emit_tab(as, (pi), (rf)&31, (ra)&31, (rb)&31) -#define emit_fb(as, pi, rf, rb) emit_tab(as, (pi), (rf)&31, 0, (rb)&31) -#define emit_fac(as, pi, rf, ra, rc) \ - emit_tab(as, (pi) | PPCF_C((rc) & 31), (rf)&31, (ra)&31, 0) -#define emit_facb(as, pi, rf, ra, rc, rb) \ - emit_tab(as, (pi) | PPCF_C((rc) & 31), (rf)&31, (ra)&31, (rb)&31) -#define emit_fai(as, pi, rf, ra, i) emit_tai(as, (pi), (rf)&31, (ra), (i)) - -static void emit_rot(ASMState *as, PPCIns pi, Reg ra, Reg rs, - int32_t n, int32_t b, int32_t e) -{ - *--as->mcp = pi | PPCF_T(rs) | PPCF_A(ra) | PPCF_B(n) | - PPCF_MB(b) | PPCF_ME(e); -} - -static void emit_slwi(ASMState *as, Reg ra, Reg rs, int32_t n) -{ - lua_assert(n >= 0 && n < 32); - emit_rot(as, PPCI_RLWINM, ra, rs, n, 0, 31-n); -} - -static void emit_rotlwi(ASMState *as, Reg ra, Reg rs, int32_t n) -{ - lua_assert(n >= 0 && n < 32); - emit_rot(as, PPCI_RLWINM, ra, rs, n, 0, 31); -} - -/* -- Emit loads/stores --------------------------------------------------- */ - -/* Prefer rematerialization of BASE/L from global_State over spills. */ -#define emit_canremat(ref) ((ref) <= REF_BASE) - -/* Try to find a one step delta relative to another constant. */ -static int emit_kdelta1(ASMState *as, Reg t, int32_t i) -{ - RegSet work = ~as->freeset & RSET_GPR; - while (work) { - Reg r = rset_picktop(work); - IRRef ref = regcost_ref(as->cost[r]); - lua_assert(r != t); - if (ref < ASMREF_L) { - int32_t delta = i - (ra_iskref(ref) ? ra_krefk(as, ref) : IR(ref)->i); - if (checki16(delta)) { - emit_tai(as, PPCI_ADDI, t, r, delta); - return 1; - } - } - rset_clear(work, r); - } - return 0; /* Failed. */ -} - -/* Load a 32 bit constant into a GPR. */ -static void emit_loadi(ASMState *as, Reg r, int32_t i) -{ - if (checki16(i)) { - emit_ti(as, PPCI_LI, r, i); - } else { - if ((i & 0xffff)) { - int32_t jgl = i32ptr(J2G(as->J)); - if ((uint32_t)(i-jgl) < 65536) { - emit_tai(as, PPCI_ADDI, r, RID_JGL, i-jgl-32768); - return; - } else if (emit_kdelta1(as, r, i)) { - return; - } - emit_asi(as, PPCI_ORI, r, r, i); - } - emit_ti(as, PPCI_LIS, r, (i >> 16)); - } -} - -#define emit_loada(as, r, addr) emit_loadi(as, (r), i32ptr((addr))) - -static Reg ra_allock(ASMState *as, intptr_t k, RegSet allow); - -/* Get/set from constant pointer. */ -static void emit_lsptr(ASMState *as, PPCIns pi, Reg r, void *p, RegSet allow) -{ - int32_t jgl = i32ptr(J2G(as->J)); - int32_t i = i32ptr(p); - Reg base; - if ((uint32_t)(i-jgl) < 65536) { - i = i-jgl-32768; - base = RID_JGL; - } else { - base = ra_allock(as, i-(int16_t)i, allow); - } - emit_tai(as, pi, r, base, i); -} - -#define emit_loadk64(as, r, ir) \ - emit_lsptr(as, PPCI_LFD, ((r) & 31), (void *)&ir_knum((ir))->u64, RSET_GPR) - -/* Get/set global_State fields. */ -static void emit_lsglptr(ASMState *as, PPCIns pi, Reg r, int32_t ofs) -{ - emit_tai(as, pi, r, RID_JGL, ofs-32768); -} - -#define emit_getgl(as, r, field) \ - emit_lsglptr(as, PPCI_LWZ, (r), (int32_t)offsetof(global_State, field)) -#define emit_setgl(as, r, field) \ - emit_lsglptr(as, PPCI_STW, (r), (int32_t)offsetof(global_State, field)) - -/* Trace number is determined from per-trace exit stubs. */ -#define emit_setvmstate(as, i) UNUSED(i) - -/* -- Emit control-flow instructions -------------------------------------- */ - -/* Label for internal jumps. */ -typedef MCode *MCLabel; - -/* Return label pointing to current PC. */ -#define emit_label(as) ((as)->mcp) - -static void emit_condbranch(ASMState *as, PPCIns pi, PPCCC cc, MCode *target) -{ - MCode *p = --as->mcp; - ptrdiff_t delta = (char *)target - (char *)p; - lua_assert(((delta + 0x8000) >> 16) == 0); - pi ^= (delta & 0x8000) * (PPCF_Y/0x8000); - *p = pi | PPCF_CC(cc) | ((uint32_t)delta & 0xffffu); -} - -static void emit_jmp(ASMState *as, MCode *target) -{ - MCode *p = --as->mcp; - ptrdiff_t delta = (char *)target - (char *)p; - *p = PPCI_B | (delta & 0x03fffffcu); -} - -static void emit_call(ASMState *as, void *target) -{ - MCode *p = --as->mcp; - ptrdiff_t delta = (char *)target - (char *)p; - if ((((delta>>2) + 0x00800000) >> 24) == 0) { - *p = PPCI_BL | (delta & 0x03fffffcu); - } else { /* Target out of range: need indirect call. Don't use arg reg. */ - RegSet allow = RSET_GPR & ~RSET_RANGE(RID_R0, REGARG_LASTGPR+1); - Reg r = ra_allock(as, i32ptr(target), allow); - *p = PPCI_BCTRL; - p[-1] = PPCI_MTCTR | PPCF_T(r); - as->mcp = p-1; - } -} - -/* -- Emit generic operations --------------------------------------------- */ - -#define emit_mr(as, dst, src) \ - emit_asb(as, PPCI_MR, (dst), (src), (src)) - -/* Generic move between two regs. */ -static void emit_movrr(ASMState *as, IRIns *ir, Reg dst, Reg src) -{ - UNUSED(ir); - if (dst < RID_MAX_GPR) - emit_mr(as, dst, src); - else - emit_fb(as, PPCI_FMR, dst, src); -} - -/* Generic load of register with base and (small) offset address. */ -static void emit_loadofs(ASMState *as, IRIns *ir, Reg r, Reg base, int32_t ofs) -{ - if (r < RID_MAX_GPR) - emit_tai(as, PPCI_LWZ, r, base, ofs); - else - emit_fai(as, irt_isnum(ir->t) ? PPCI_LFD : PPCI_LFS, r, base, ofs); -} - -/* Generic store of register with base and (small) offset address. */ -static void emit_storeofs(ASMState *as, IRIns *ir, Reg r, Reg base, int32_t ofs) -{ - if (r < RID_MAX_GPR) - emit_tai(as, PPCI_STW, r, base, ofs); - else - emit_fai(as, irt_isnum(ir->t) ? PPCI_STFD : PPCI_STFS, r, base, ofs); -} - -/* Emit a compare (for equality) with a constant operand. */ -static void emit_cmpi(ASMState *as, Reg r, int32_t k) -{ - if (checki16(k)) { - emit_ai(as, PPCI_CMPWI, r, k); - } else if (checku16(k)) { - emit_ai(as, PPCI_CMPLWI, r, k); - } else { - emit_ai(as, PPCI_CMPLWI, RID_TMP, k); - emit_asi(as, PPCI_XORIS, RID_TMP, r, (k >> 16)); - } -} - -/* Add offset to pointer. */ -static void emit_addptr(ASMState *as, Reg r, int32_t ofs) -{ - if (ofs) { - emit_tai(as, PPCI_ADDI, r, r, ofs); - if (!checki16(ofs)) - emit_tai(as, PPCI_ADDIS, r, r, (ofs + 32768) >> 16); - } -} - -static void emit_spsub(ASMState *as, int32_t ofs) -{ - if (ofs) { - emit_tai(as, PPCI_STWU, RID_TMP, RID_SP, -ofs); - emit_tai(as, PPCI_ADDI, RID_TMP, RID_SP, - CFRAME_SIZE + (as->parent ? as->parent->spadjust : 0)); - } -} - diff --git a/lib/LuaJIT/src/lj_emit_x86.h b/lib/LuaJIT/src/lj_emit_x86.h deleted file mode 100644 index b3dc4ea..0000000 --- a/lib/LuaJIT/src/lj_emit_x86.h +++ /dev/null @@ -1,573 +0,0 @@ -/* -** x86/x64 instruction emitter. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -/* -- Emit basic instructions --------------------------------------------- */ - -#define MODRM(mode, r1, r2) ((MCode)((mode)+(((r1)&7)<<3)+((r2)&7))) - -#if LJ_64 -#define REXRB(p, rr, rb) \ - { MCode rex = 0x40 + (((rr)>>1)&4) + (((rb)>>3)&1); \ - if (rex != 0x40) *--(p) = rex; } -#define FORCE_REX 0x200 -#define REX_64 (FORCE_REX|0x080000) -#define VEX_64 0x800000 -#else -#define REXRB(p, rr, rb) ((void)0) -#define FORCE_REX 0 -#define REX_64 0 -#define VEX_64 0 -#endif -#if LJ_GC64 -#define REX_GC64 REX_64 -#else -#define REX_GC64 0 -#endif - -#define emit_i8(as, i) (*--as->mcp = (MCode)(i)) -#define emit_i32(as, i) (*(int32_t *)(as->mcp-4) = (i), as->mcp -= 4) -#define emit_u32(as, u) (*(uint32_t *)(as->mcp-4) = (u), as->mcp -= 4) - -#define emit_x87op(as, xo) \ - (*(uint16_t *)(as->mcp-2) = (uint16_t)(xo), as->mcp -= 2) - -/* op */ -static LJ_AINLINE MCode *emit_op(x86Op xo, Reg rr, Reg rb, Reg rx, - MCode *p, int delta) -{ - int n = (int8_t)xo; - if (n == -60) { /* VEX-encoded instruction */ -#if LJ_64 - xo ^= (((rr>>1)&4)+((rx>>2)&2)+((rb>>3)&1))<<13; -#endif - *(uint32_t *)(p+delta-5) = (uint32_t)xo; - return p+delta-5; - } -#if defined(__GNUC__) - if (__builtin_constant_p(xo) && n == -2) - p[delta-2] = (MCode)(xo >> 24); - else if (__builtin_constant_p(xo) && n == -3) - *(uint16_t *)(p+delta-3) = (uint16_t)(xo >> 16); - else -#endif - *(uint32_t *)(p+delta-5) = (uint32_t)xo; - p += n + delta; -#if LJ_64 - { - uint32_t rex = 0x40 + ((rr>>1)&(4+(FORCE_REX>>1)))+((rx>>2)&2)+((rb>>3)&1); - if (rex != 0x40) { - rex |= (rr >> 16); - if (n == -4) { *p = (MCode)rex; rex = (MCode)(xo >> 8); } - else if ((xo & 0xffffff) == 0x6600fd) { *p = (MCode)rex; rex = 0x66; } - *--p = (MCode)rex; - } - } -#else - UNUSED(rr); UNUSED(rb); UNUSED(rx); -#endif - return p; -} - -/* op + modrm */ -#define emit_opm(xo, mode, rr, rb, p, delta) \ - (p[(delta)-1] = MODRM((mode), (rr), (rb)), \ - emit_op((xo), (rr), (rb), 0, (p), (delta))) - -/* op + modrm + sib */ -#define emit_opmx(xo, mode, scale, rr, rb, rx, p) \ - (p[-1] = MODRM((scale), (rx), (rb)), \ - p[-2] = MODRM((mode), (rr), RID_ESP), \ - emit_op((xo), (rr), (rb), (rx), (p), -1)) - -/* op r1, r2 */ -static void emit_rr(ASMState *as, x86Op xo, Reg r1, Reg r2) -{ - MCode *p = as->mcp; - as->mcp = emit_opm(xo, XM_REG, r1, r2, p, 0); -} - -#if LJ_64 && defined(LUA_USE_ASSERT) -/* [addr] is sign-extended in x64 and must be in lower 2G (not 4G). */ -static int32_t ptr2addr(const void *p) -{ - lua_assert((uintptr_t)p < (uintptr_t)0x80000000); - return i32ptr(p); -} -#else -#define ptr2addr(p) (i32ptr((p))) -#endif - -/* op r, [base+ofs] */ -static void emit_rmro(ASMState *as, x86Op xo, Reg rr, Reg rb, int32_t ofs) -{ - MCode *p = as->mcp; - x86Mode mode; - if (ra_hasreg(rb)) { - if (LJ_GC64 && rb == RID_RIP) { - mode = XM_OFS0; - p -= 4; - *(int32_t *)p = ofs; - } else if (ofs == 0 && (rb&7) != RID_EBP) { - mode = XM_OFS0; - } else if (checki8(ofs)) { - *--p = (MCode)ofs; - mode = XM_OFS8; - } else { - p -= 4; - *(int32_t *)p = ofs; - mode = XM_OFS32; - } - if ((rb&7) == RID_ESP) - *--p = MODRM(XM_SCALE1, RID_ESP, RID_ESP); - } else { - *(int32_t *)(p-4) = ofs; -#if LJ_64 - p[-5] = MODRM(XM_SCALE1, RID_ESP, RID_EBP); - p -= 5; - rb = RID_ESP; -#else - p -= 4; - rb = RID_EBP; -#endif - mode = XM_OFS0; - } - as->mcp = emit_opm(xo, mode, rr, rb, p, 0); -} - -/* op r, [base+idx*scale+ofs] */ -static void emit_rmrxo(ASMState *as, x86Op xo, Reg rr, Reg rb, Reg rx, - x86Mode scale, int32_t ofs) -{ - MCode *p = as->mcp; - x86Mode mode; - if (ofs == 0 && (rb&7) != RID_EBP) { - mode = XM_OFS0; - } else if (checki8(ofs)) { - mode = XM_OFS8; - *--p = (MCode)ofs; - } else { - mode = XM_OFS32; - p -= 4; - *(int32_t *)p = ofs; - } - as->mcp = emit_opmx(xo, mode, scale, rr, rb, rx, p); -} - -/* op r, i */ -static void emit_gri(ASMState *as, x86Group xg, Reg rb, int32_t i) -{ - MCode *p = as->mcp; - x86Op xo; - if (checki8(i)) { - *--p = (MCode)i; - xo = XG_TOXOi8(xg); - } else { - p -= 4; - *(int32_t *)p = i; - xo = XG_TOXOi(xg); - } - as->mcp = emit_opm(xo, XM_REG, (Reg)(xg & 7) | (rb & REX_64), rb, p, 0); -} - -/* op [base+ofs], i */ -static void emit_gmroi(ASMState *as, x86Group xg, Reg rb, int32_t ofs, - int32_t i) -{ - x86Op xo; - if (checki8(i)) { - emit_i8(as, i); - xo = XG_TOXOi8(xg); - } else { - emit_i32(as, i); - xo = XG_TOXOi(xg); - } - emit_rmro(as, xo, (Reg)(xg & 7), rb, ofs); -} - -#define emit_shifti(as, xg, r, i) \ - (emit_i8(as, (i)), emit_rr(as, XO_SHIFTi, (Reg)(xg), (r))) - -/* op r, rm/mrm */ -static void emit_mrm(ASMState *as, x86Op xo, Reg rr, Reg rb) -{ - MCode *p = as->mcp; - x86Mode mode = XM_REG; - if (rb == RID_MRM) { - rb = as->mrm.base; - if (rb == RID_NONE) { - rb = RID_EBP; - mode = XM_OFS0; - p -= 4; - *(int32_t *)p = as->mrm.ofs; - if (as->mrm.idx != RID_NONE) - goto mrmidx; -#if LJ_64 - *--p = MODRM(XM_SCALE1, RID_ESP, RID_EBP); - rb = RID_ESP; -#endif - } else if (LJ_GC64 && rb == RID_RIP) { - lua_assert(as->mrm.idx == RID_NONE); - mode = XM_OFS0; - p -= 4; - *(int32_t *)p = as->mrm.ofs; - } else { - if (as->mrm.ofs == 0 && (rb&7) != RID_EBP) { - mode = XM_OFS0; - } else if (checki8(as->mrm.ofs)) { - *--p = (MCode)as->mrm.ofs; - mode = XM_OFS8; - } else { - p -= 4; - *(int32_t *)p = as->mrm.ofs; - mode = XM_OFS32; - } - if (as->mrm.idx != RID_NONE) { - mrmidx: - as->mcp = emit_opmx(xo, mode, as->mrm.scale, rr, rb, as->mrm.idx, p); - return; - } - if ((rb&7) == RID_ESP) - *--p = MODRM(XM_SCALE1, RID_ESP, RID_ESP); - } - } - as->mcp = emit_opm(xo, mode, rr, rb, p, 0); -} - -/* op rm/mrm, i */ -static void emit_gmrmi(ASMState *as, x86Group xg, Reg rb, int32_t i) -{ - x86Op xo; - if (checki8(i)) { - emit_i8(as, i); - xo = XG_TOXOi8(xg); - } else { - emit_i32(as, i); - xo = XG_TOXOi(xg); - } - emit_mrm(as, xo, (Reg)(xg & 7) | (rb & REX_64), (rb & ~REX_64)); -} - -/* -- Emit loads/stores --------------------------------------------------- */ - -/* mov [base+ofs], i */ -static void emit_movmroi(ASMState *as, Reg base, int32_t ofs, int32_t i) -{ - emit_i32(as, i); - emit_rmro(as, XO_MOVmi, 0, base, ofs); -} - -/* mov [base+ofs], r */ -#define emit_movtomro(as, r, base, ofs) \ - emit_rmro(as, XO_MOVto, (r), (base), (ofs)) - -/* Get/set global_State fields. */ -#define emit_opgl(as, xo, r, field) \ - emit_rma(as, (xo), (r), (void *)&J2G(as->J)->field) -#define emit_getgl(as, r, field) emit_opgl(as, XO_MOV, (r)|REX_GC64, field) -#define emit_setgl(as, r, field) emit_opgl(as, XO_MOVto, (r)|REX_GC64, field) - -#define emit_setvmstate(as, i) \ - (emit_i32(as, i), emit_opgl(as, XO_MOVmi, 0, vmstate)) - -/* mov r, i / xor r, r */ -static void emit_loadi(ASMState *as, Reg r, int32_t i) -{ - /* XOR r,r is shorter, but modifies the flags. This is bad for HIOP/jcc. */ - if (i == 0 && !(LJ_32 && (IR(as->curins)->o == IR_HIOP || - (as->curins+1 < as->T->nins && - IR(as->curins+1)->o == IR_HIOP))) && - !((*as->mcp == 0x0f && (as->mcp[1] & 0xf0) == XI_JCCn) || - (*as->mcp & 0xf0) == XI_JCCs)) { - emit_rr(as, XO_ARITH(XOg_XOR), r, r); - } else { - MCode *p = as->mcp; - *(int32_t *)(p-4) = i; - p[-5] = (MCode)(XI_MOVri+(r&7)); - p -= 5; - REXRB(p, 0, r); - as->mcp = p; - } -} - -#if LJ_GC64 -#define dispofs(as, k) \ - ((intptr_t)((uintptr_t)(k) - (uintptr_t)J2GG(as->J)->dispatch)) -#define mcpofs(as, k) \ - ((intptr_t)((uintptr_t)(k) - (uintptr_t)as->mcp)) -#define mctopofs(as, k) \ - ((intptr_t)((uintptr_t)(k) - (uintptr_t)as->mctop)) -/* mov r, addr */ -#define emit_loada(as, r, addr) \ - emit_loadu64(as, (r), (uintptr_t)(addr)) -#else -/* mov r, addr */ -#define emit_loada(as, r, addr) \ - emit_loadi(as, (r), ptr2addr((addr))) -#endif - -#if LJ_64 -/* mov r, imm64 or shorter 32 bit extended load. */ -static void emit_loadu64(ASMState *as, Reg r, uint64_t u64) -{ - if (checku32(u64)) { /* 32 bit load clears upper 32 bits. */ - emit_loadi(as, r, (int32_t)u64); - } else if (checki32((int64_t)u64)) { /* Sign-extended 32 bit load. */ - MCode *p = as->mcp; - *(int32_t *)(p-4) = (int32_t)u64; - as->mcp = emit_opm(XO_MOVmi, XM_REG, REX_64, r, p, -4); -#if LJ_GC64 - } else if (checki32(dispofs(as, u64))) { - emit_rmro(as, XO_LEA, r|REX_64, RID_DISPATCH, (int32_t)dispofs(as, u64)); - } else if (checki32(mcpofs(as, u64)) && checki32(mctopofs(as, u64))) { - /* Since as->realign assumes the code size doesn't change, check - ** RIP-relative addressing reachability for both as->mcp and as->mctop. - */ - emit_rmro(as, XO_LEA, r|REX_64, RID_RIP, (int32_t)mcpofs(as, u64)); -#endif - } else { /* Full-size 64 bit load. */ - MCode *p = as->mcp; - *(uint64_t *)(p-8) = u64; - p[-9] = (MCode)(XI_MOVri+(r&7)); - p[-10] = 0x48 + ((r>>3)&1); - p -= 10; - as->mcp = p; - } -} -#endif - -/* op r, [addr] */ -static void emit_rma(ASMState *as, x86Op xo, Reg rr, const void *addr) -{ -#if LJ_GC64 - if (checki32(dispofs(as, addr))) { - emit_rmro(as, xo, rr, RID_DISPATCH, (int32_t)dispofs(as, addr)); - } else if (checki32(mcpofs(as, addr)) && checki32(mctopofs(as, addr))) { - emit_rmro(as, xo, rr, RID_RIP, (int32_t)mcpofs(as, addr)); - } else if (!checki32((intptr_t)addr)) { - Reg ra = (rr & 15); - if (xo != XO_MOV) { - /* We can't allocate a register here. Use and restore DISPATCH. Ugly. */ - uint64_t dispaddr = (uintptr_t)J2GG(as->J)->dispatch; - uint8_t i8 = xo == XO_GROUP3b ? *as->mcp++ : 0; - ra = RID_DISPATCH; - if (checku32(dispaddr)) { - emit_loadi(as, ra, (int32_t)dispaddr); - } else { /* Full-size 64 bit load. */ - MCode *p = as->mcp; - *(uint64_t *)(p-8) = dispaddr; - p[-9] = (MCode)(XI_MOVri+(ra&7)); - p[-10] = 0x48 + ((ra>>3)&1); - p -= 10; - as->mcp = p; - } - if (xo == XO_GROUP3b) emit_i8(as, i8); - } - emit_rmro(as, xo, rr, ra, 0); - emit_loadu64(as, ra, (uintptr_t)addr); - } else -#endif - { - MCode *p = as->mcp; - *(int32_t *)(p-4) = ptr2addr(addr); -#if LJ_64 - p[-5] = MODRM(XM_SCALE1, RID_ESP, RID_EBP); - as->mcp = emit_opm(xo, XM_OFS0, rr, RID_ESP, p, -5); -#else - as->mcp = emit_opm(xo, XM_OFS0, rr, RID_EBP, p, -4); -#endif - } -} - -/* Load 64 bit IR constant into register. */ -static void emit_loadk64(ASMState *as, Reg r, IRIns *ir) -{ - Reg r64; - x86Op xo; - const uint64_t *k = &ir_k64(ir)->u64; - if (rset_test(RSET_FPR, r)) { - r64 = r; - xo = XO_MOVSD; - } else { - r64 = r | REX_64; - xo = XO_MOV; - } - if (*k == 0) { - emit_rr(as, rset_test(RSET_FPR, r) ? XO_XORPS : XO_ARITH(XOg_XOR), r, r); -#if LJ_GC64 - } else if (checki32((intptr_t)k) || checki32(dispofs(as, k)) || - (checki32(mcpofs(as, k)) && checki32(mctopofs(as, k)))) { - emit_rma(as, xo, r64, k); - } else { - if (ir->i) { - lua_assert(*k == *(uint64_t*)(as->mctop - ir->i)); - } else if (as->curins <= as->stopins && rset_test(RSET_GPR, r)) { - emit_loadu64(as, r, *k); - return; - } else { - /* If all else fails, add the FP constant at the MCode area bottom. */ - while ((uintptr_t)as->mcbot & 7) *as->mcbot++ = XI_INT3; - *(uint64_t *)as->mcbot = *k; - ir->i = (int32_t)(as->mctop - as->mcbot); - as->mcbot += 8; - as->mclim = as->mcbot + MCLIM_REDZONE; - lj_mcode_commitbot(as->J, as->mcbot); - } - emit_rmro(as, xo, r64, RID_RIP, (int32_t)mcpofs(as, as->mctop - ir->i)); -#else - } else { - emit_rma(as, xo, r64, k); -#endif - } -} - -/* -- Emit control-flow instructions -------------------------------------- */ - -/* Label for short jumps. */ -typedef MCode *MCLabel; - -#if LJ_32 && LJ_HASFFI -/* jmp short target */ -static void emit_sjmp(ASMState *as, MCLabel target) -{ - MCode *p = as->mcp; - ptrdiff_t delta = target - p; - lua_assert(delta == (int8_t)delta); - p[-1] = (MCode)(int8_t)delta; - p[-2] = XI_JMPs; - as->mcp = p - 2; -} -#endif - -/* jcc short target */ -static void emit_sjcc(ASMState *as, int cc, MCLabel target) -{ - MCode *p = as->mcp; - ptrdiff_t delta = target - p; - lua_assert(delta == (int8_t)delta); - p[-1] = (MCode)(int8_t)delta; - p[-2] = (MCode)(XI_JCCs+(cc&15)); - as->mcp = p - 2; -} - -/* jcc short (pending target) */ -static MCLabel emit_sjcc_label(ASMState *as, int cc) -{ - MCode *p = as->mcp; - p[-1] = 0; - p[-2] = (MCode)(XI_JCCs+(cc&15)); - as->mcp = p - 2; - return p; -} - -/* Fixup jcc short target. */ -static void emit_sfixup(ASMState *as, MCLabel source) -{ - source[-1] = (MCode)(as->mcp-source); -} - -/* Return label pointing to current PC. */ -#define emit_label(as) ((as)->mcp) - -/* Compute relative 32 bit offset for jump and call instructions. */ -static LJ_AINLINE int32_t jmprel(MCode *p, MCode *target) -{ - ptrdiff_t delta = target - p; - lua_assert(delta == (int32_t)delta); - return (int32_t)delta; -} - -/* jcc target */ -static void emit_jcc(ASMState *as, int cc, MCode *target) -{ - MCode *p = as->mcp; - *(int32_t *)(p-4) = jmprel(p, target); - p[-5] = (MCode)(XI_JCCn+(cc&15)); - p[-6] = 0x0f; - as->mcp = p - 6; -} - -/* jmp target */ -static void emit_jmp(ASMState *as, MCode *target) -{ - MCode *p = as->mcp; - *(int32_t *)(p-4) = jmprel(p, target); - p[-5] = XI_JMP; - as->mcp = p - 5; -} - -/* call target */ -static void emit_call_(ASMState *as, MCode *target) -{ - MCode *p = as->mcp; -#if LJ_64 - if (target-p != (int32_t)(target-p)) { - /* Assumes RID_RET is never an argument to calls and always clobbered. */ - emit_rr(as, XO_GROUP5, XOg_CALL, RID_RET); - emit_loadu64(as, RID_RET, (uint64_t)target); - return; - } -#endif - *(int32_t *)(p-4) = jmprel(p, target); - p[-5] = XI_CALL; - as->mcp = p - 5; -} - -#define emit_call(as, f) emit_call_(as, (MCode *)(void *)(f)) - -/* -- Emit generic operations --------------------------------------------- */ - -/* Use 64 bit operations to handle 64 bit IR types. */ -#if LJ_64 -#define REX_64IR(ir, r) ((r) + (irt_is64((ir)->t) ? REX_64 : 0)) -#define VEX_64IR(ir, r) ((r) + (irt_is64((ir)->t) ? VEX_64 : 0)) -#else -#define REX_64IR(ir, r) (r) -#define VEX_64IR(ir, r) (r) -#endif - -/* Generic move between two regs. */ -static void emit_movrr(ASMState *as, IRIns *ir, Reg dst, Reg src) -{ - UNUSED(ir); - if (dst < RID_MAX_GPR) - emit_rr(as, XO_MOV, REX_64IR(ir, dst), src); - else - emit_rr(as, XO_MOVAPS, dst, src); -} - -/* Generic load of register with base and (small) offset address. */ -static void emit_loadofs(ASMState *as, IRIns *ir, Reg r, Reg base, int32_t ofs) -{ - if (r < RID_MAX_GPR) - emit_rmro(as, XO_MOV, REX_64IR(ir, r), base, ofs); - else - emit_rmro(as, irt_isnum(ir->t) ? XO_MOVSD : XO_MOVSS, r, base, ofs); -} - -/* Generic store of register with base and (small) offset address. */ -static void emit_storeofs(ASMState *as, IRIns *ir, Reg r, Reg base, int32_t ofs) -{ - if (r < RID_MAX_GPR) - emit_rmro(as, XO_MOVto, REX_64IR(ir, r), base, ofs); - else - emit_rmro(as, irt_isnum(ir->t) ? XO_MOVSDto : XO_MOVSSto, r, base, ofs); -} - -/* Add offset to pointer. */ -static void emit_addptr(ASMState *as, Reg r, int32_t ofs) -{ - if (ofs) { - if ((as->flags & JIT_F_LEA_AGU)) - emit_rmro(as, XO_LEA, r|REX_GC64, r, ofs); - else - emit_gri(as, XG_ARITHi(XOg_ADD), r|REX_GC64, ofs); - } -} - -#define emit_spsub(as, ofs) emit_addptr(as, RID_ESP|REX_64, -(ofs)) - -/* Prefer rematerialization of BASE/L from global_State over spills. */ -#define emit_canremat(ref) ((ref) <= REF_BASE) - diff --git a/lib/LuaJIT/src/lj_err.c b/lib/LuaJIT/src/lj_err.c deleted file mode 100644 index abf176e..0000000 --- a/lib/LuaJIT/src/lj_err.c +++ /dev/null @@ -1,854 +0,0 @@ -/* -** Error handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_err_c -#define LUA_CORE - -#include "lj_obj.h" -#include "lj_err.h" -#include "lj_debug.h" -#include "lj_str.h" -#include "lj_func.h" -#include "lj_state.h" -#include "lj_frame.h" -#include "lj_ff.h" -#include "lj_trace.h" -#include "lj_vm.h" -#include "lj_strfmt.h" - -/* -** LuaJIT can either use internal or external frame unwinding: -** -** - Internal frame unwinding (INT) is free-standing and doesn't require -** any OS or library support. -** -** - External frame unwinding (EXT) uses the system-provided unwind handler. -** -** Pros and Cons: -** -** - EXT requires unwind tables for *all* functions on the C stack between -** the pcall/catch and the error/throw. This is the default on x64, -** but needs to be manually enabled on x86/PPC for non-C++ code. -** -** - INT is faster when actually throwing errors (but this happens rarely). -** Setting up error handlers is zero-cost in any case. -** -** - EXT provides full interoperability with C++ exceptions. You can throw -** Lua errors or C++ exceptions through a mix of Lua frames and C++ frames. -** C++ destructors are called as needed. C++ exceptions caught by pcall -** are converted to the string "C++ exception". Lua errors can be caught -** with catch (...) in C++. -** -** - INT has only limited support for automatically catching C++ exceptions -** on POSIX systems using DWARF2 stack unwinding. Other systems may use -** the wrapper function feature. Lua errors thrown through C++ frames -** cannot be caught by C++ code and C++ destructors are not run. -** -** EXT is the default on x64 systems and on Windows, INT is the default on all -** other systems. -** -** EXT can be manually enabled on POSIX systems using GCC and DWARF2 stack -** unwinding with -DLUAJIT_UNWIND_EXTERNAL. *All* C code must be compiled -** with -funwind-tables (or -fexceptions). This includes LuaJIT itself (set -** TARGET_CFLAGS), all of your C/Lua binding code, all loadable C modules -** and all C libraries that have callbacks which may be used to call back -** into Lua. C++ code must *not* be compiled with -fno-exceptions. -** -** EXT is mandatory on WIN64 since the calling convention has an abundance -** of callee-saved registers (rbx, rbp, rsi, rdi, r12-r15, xmm6-xmm15). -** The POSIX/x64 interpreter only saves r12/r13 for INT (e.g. PS4). -*/ - -#if defined(__GNUC__) && (LJ_TARGET_X64 || defined(LUAJIT_UNWIND_EXTERNAL)) && !LJ_NO_UNWIND -#define LJ_UNWIND_EXT 1 -#elif LJ_TARGET_WINDOWS -#define LJ_UNWIND_EXT 1 -#endif - -/* -- Error messages ------------------------------------------------------ */ - -/* Error message strings. */ -LJ_DATADEF const char *lj_err_allmsg = -#define ERRDEF(name, msg) msg "\0" -#include "lj_errmsg.h" -; - -/* -- Internal frame unwinding -------------------------------------------- */ - -/* Unwind Lua stack and move error message to new top. */ -LJ_NOINLINE static void unwindstack(lua_State *L, TValue *top) -{ - lj_func_closeuv(L, top); - if (top < L->top-1) { - copyTV(L, top, L->top-1); - L->top = top+1; - } - lj_state_relimitstack(L); -} - -/* Unwind until stop frame. Optionally cleanup frames. */ -static void *err_unwind(lua_State *L, void *stopcf, int errcode) -{ - TValue *frame = L->base-1; - void *cf = L->cframe; - while (cf) { - int32_t nres = cframe_nres(cframe_raw(cf)); - if (nres < 0) { /* C frame without Lua frame? */ - TValue *top = restorestack(L, -nres); - if (frame < top) { /* Frame reached? */ - if (errcode) { - L->base = frame+1; - L->cframe = cframe_prev(cf); - unwindstack(L, top); - } - return cf; - } - } - if (frame <= tvref(L->stack)+LJ_FR2) - break; - switch (frame_typep(frame)) { - case FRAME_LUA: /* Lua frame. */ - case FRAME_LUAP: - frame = frame_prevl(frame); - break; - case FRAME_C: /* C frame. */ - unwind_c: -#if LJ_UNWIND_EXT - if (errcode) { - L->base = frame_prevd(frame) + 1; - L->cframe = cframe_prev(cf); - unwindstack(L, frame - LJ_FR2); - } else if (cf != stopcf) { - cf = cframe_prev(cf); - frame = frame_prevd(frame); - break; - } - return NULL; /* Continue unwinding. */ -#else - UNUSED(stopcf); - cf = cframe_prev(cf); - frame = frame_prevd(frame); - break; -#endif - case FRAME_CP: /* Protected C frame. */ - if (cframe_canyield(cf)) { /* Resume? */ - if (errcode) { - hook_leave(G(L)); /* Assumes nobody uses coroutines inside hooks. */ - L->cframe = NULL; - L->status = (uint8_t)errcode; - } - return cf; - } - if (errcode) { - L->base = frame_prevd(frame) + 1; - L->cframe = cframe_prev(cf); - unwindstack(L, frame - LJ_FR2); - } - return cf; - case FRAME_CONT: /* Continuation frame. */ - if (frame_iscont_fficb(frame)) - goto unwind_c; - /* fallthrough */ - case FRAME_VARG: /* Vararg frame. */ - frame = frame_prevd(frame); - break; - case FRAME_PCALL: /* FF pcall() frame. */ - case FRAME_PCALLH: /* FF pcall() frame inside hook. */ - if (errcode) { - if (errcode == LUA_YIELD) { - frame = frame_prevd(frame); - break; - } - if (frame_typep(frame) == FRAME_PCALL) - hook_leave(G(L)); - L->base = frame_prevd(frame) + 1; - L->cframe = cf; - unwindstack(L, L->base); - } - return (void *)((intptr_t)cf | CFRAME_UNWIND_FF); - } - } - /* No C frame. */ - if (errcode) { - L->base = tvref(L->stack)+1+LJ_FR2; - L->cframe = NULL; - unwindstack(L, L->base); - if (G(L)->panic) - G(L)->panic(L); - exit(EXIT_FAILURE); - } - return L; /* Anything non-NULL will do. */ -} - -/* -- External frame unwinding -------------------------------------------- */ - -#if defined(__GNUC__) && !LJ_NO_UNWIND && !LJ_ABI_WIN - -/* -** We have to use our own definitions instead of the mandatory (!) unwind.h, -** since various OS, distros and compilers mess up the header installation. -*/ - -typedef struct _Unwind_Context _Unwind_Context; - -#define _URC_OK 0 -#define _URC_FATAL_PHASE1_ERROR 3 -#define _URC_HANDLER_FOUND 6 -#define _URC_INSTALL_CONTEXT 7 -#define _URC_CONTINUE_UNWIND 8 -#define _URC_FAILURE 9 - -#define LJ_UEXCLASS 0x4c55414a49543200ULL /* LUAJIT2\0 */ -#define LJ_UEXCLASS_MAKE(c) (LJ_UEXCLASS | (uint64_t)(c)) -#define LJ_UEXCLASS_CHECK(cl) (((cl) ^ LJ_UEXCLASS) <= 0xff) -#define LJ_UEXCLASS_ERRCODE(cl) ((int)((cl) & 0xff)) - -#if !LJ_TARGET_ARM - -typedef struct _Unwind_Exception -{ - uint64_t exclass; - void (*excleanup)(int, struct _Unwind_Exception *); - uintptr_t p1, p2; -} __attribute__((__aligned__)) _Unwind_Exception; - -extern uintptr_t _Unwind_GetCFA(_Unwind_Context *); -extern void _Unwind_SetGR(_Unwind_Context *, int, uintptr_t); -extern void _Unwind_SetIP(_Unwind_Context *, uintptr_t); -extern void _Unwind_DeleteException(_Unwind_Exception *); -extern int _Unwind_RaiseException(_Unwind_Exception *); - -#define _UA_SEARCH_PHASE 1 -#define _UA_CLEANUP_PHASE 2 -#define _UA_HANDLER_FRAME 4 -#define _UA_FORCE_UNWIND 8 - -/* DWARF2 personality handler referenced from interpreter .eh_frame. */ -LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions, - uint64_t uexclass, _Unwind_Exception *uex, _Unwind_Context *ctx) -{ - void *cf; - lua_State *L; - if (version != 1) - return _URC_FATAL_PHASE1_ERROR; - UNUSED(uexclass); - cf = (void *)_Unwind_GetCFA(ctx); - L = cframe_L(cf); - if ((actions & _UA_SEARCH_PHASE)) { -#if LJ_UNWIND_EXT - if (err_unwind(L, cf, 0) == NULL) - return _URC_CONTINUE_UNWIND; -#endif - if (!LJ_UEXCLASS_CHECK(uexclass)) { - setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); - } - return _URC_HANDLER_FOUND; - } - if ((actions & _UA_CLEANUP_PHASE)) { - int errcode; - if (LJ_UEXCLASS_CHECK(uexclass)) { - errcode = LJ_UEXCLASS_ERRCODE(uexclass); - } else { - if ((actions & _UA_HANDLER_FRAME)) - _Unwind_DeleteException(uex); - errcode = LUA_ERRRUN; - } -#if LJ_UNWIND_EXT - cf = err_unwind(L, cf, errcode); - if ((actions & _UA_FORCE_UNWIND)) { - return _URC_CONTINUE_UNWIND; - } else if (cf) { - _Unwind_SetGR(ctx, LJ_TARGET_EHRETREG, errcode); - _Unwind_SetIP(ctx, (uintptr_t)(cframe_unwind_ff(cf) ? - lj_vm_unwind_ff_eh : - lj_vm_unwind_c_eh)); - return _URC_INSTALL_CONTEXT; - } -#if LJ_TARGET_X86ORX64 - else if ((actions & _UA_HANDLER_FRAME)) { - /* Workaround for ancient libgcc bug. Still present in RHEL 5.5. :-/ - ** Real fix: http://gcc.gnu.org/viewcvs/trunk/gcc/unwind-dw2.c?r1=121165&r2=124837&pathrev=153877&diff_format=h - */ - _Unwind_SetGR(ctx, LJ_TARGET_EHRETREG, errcode); - _Unwind_SetIP(ctx, (uintptr_t)lj_vm_unwind_rethrow); - return _URC_INSTALL_CONTEXT; - } -#endif -#else - /* This is not the proper way to escape from the unwinder. We get away with - ** it on non-x64 because the interpreter restores all callee-saved regs. - */ - lj_err_throw(L, errcode); -#endif - } - return _URC_CONTINUE_UNWIND; -} - -#if LJ_UNWIND_EXT -#if LJ_TARGET_OSX || defined(__OpenBSD__) -/* Sorry, no thread safety for OSX. Complain to Apple, not me. */ -static _Unwind_Exception static_uex; -#else -static __thread _Unwind_Exception static_uex; -#endif - -/* Raise DWARF2 exception. */ -static void err_raise_ext(int errcode) -{ - static_uex.exclass = LJ_UEXCLASS_MAKE(errcode); - static_uex.excleanup = NULL; - _Unwind_RaiseException(&static_uex); -} -#endif - -#else /* LJ_TARGET_ARM */ - -#define _US_VIRTUAL_UNWIND_FRAME 0 -#define _US_UNWIND_FRAME_STARTING 1 -#define _US_ACTION_MASK 3 -#define _US_FORCE_UNWIND 8 - -typedef struct _Unwind_Control_Block _Unwind_Control_Block; - -struct _Unwind_Control_Block { - uint64_t exclass; - uint32_t misc[20]; -}; - -extern int _Unwind_RaiseException(_Unwind_Control_Block *); -extern int __gnu_unwind_frame(_Unwind_Control_Block *, _Unwind_Context *); -extern int _Unwind_VRS_Set(_Unwind_Context *, int, uint32_t, int, void *); -extern int _Unwind_VRS_Get(_Unwind_Context *, int, uint32_t, int, void *); - -static inline uint32_t _Unwind_GetGR(_Unwind_Context *ctx, int r) -{ - uint32_t v; - _Unwind_VRS_Get(ctx, 0, r, 0, &v); - return v; -} - -static inline void _Unwind_SetGR(_Unwind_Context *ctx, int r, uint32_t v) -{ - _Unwind_VRS_Set(ctx, 0, r, 0, &v); -} - -extern void lj_vm_unwind_ext(void); - -/* ARM unwinder personality handler referenced from interpreter .ARM.extab. */ -LJ_FUNCA int lj_err_unwind_arm(int state, _Unwind_Control_Block *ucb, - _Unwind_Context *ctx) -{ - void *cf = (void *)_Unwind_GetGR(ctx, 13); - lua_State *L = cframe_L(cf); - int errcode; - - switch ((state & _US_ACTION_MASK)) { - case _US_VIRTUAL_UNWIND_FRAME: - if ((state & _US_FORCE_UNWIND)) break; - return _URC_HANDLER_FOUND; - case _US_UNWIND_FRAME_STARTING: - if (LJ_UEXCLASS_CHECK(ucb->exclass)) { - errcode = LJ_UEXCLASS_ERRCODE(ucb->exclass); - } else { - errcode = LUA_ERRRUN; - setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); - } - cf = err_unwind(L, cf, errcode); - if ((state & _US_FORCE_UNWIND) || cf == NULL) break; - _Unwind_SetGR(ctx, 15, (uint32_t)lj_vm_unwind_ext); - _Unwind_SetGR(ctx, 0, (uint32_t)ucb); - _Unwind_SetGR(ctx, 1, (uint32_t)errcode); - _Unwind_SetGR(ctx, 2, cframe_unwind_ff(cf) ? - (uint32_t)lj_vm_unwind_ff_eh : - (uint32_t)lj_vm_unwind_c_eh); - return _URC_INSTALL_CONTEXT; - default: - return _URC_FAILURE; - } - if (__gnu_unwind_frame(ucb, ctx) != _URC_OK) - return _URC_FAILURE; - return _URC_CONTINUE_UNWIND; -} - -#if LJ_UNWIND_EXT -static __thread _Unwind_Control_Block static_uex; - -static void err_raise_ext(int errcode) -{ - memset(&static_uex, 0, sizeof(static_uex)); - static_uex.exclass = LJ_UEXCLASS_MAKE(errcode); - _Unwind_RaiseException(&static_uex); -} -#endif - -#endif /* LJ_TARGET_ARM */ - -#elif LJ_ABI_WIN - -/* -** Someone in Redmond owes me several days of my life. A lot of this is -** undocumented or just plain wrong on MSDN. Some of it can be gathered -** from 3rd party docs or must be found by trial-and-error. They really -** don't want you to write your own language-specific exception handler -** or to interact gracefully with MSVC. :-( -** -** Apparently MSVC doesn't call C++ destructors for foreign exceptions -** unless you compile your C++ code with /EHa. Unfortunately this means -** catch (...) also catches things like access violations. The use of -** _set_se_translator doesn't really help, because it requires /EHa, too. -*/ - -#define WIN32_LEAN_AND_MEAN -#include - -#if LJ_TARGET_X64 -/* Taken from: http://www.nynaeve.net/?p=99 */ -typedef struct UndocumentedDispatcherContext { - ULONG64 ControlPc; - ULONG64 ImageBase; - PRUNTIME_FUNCTION FunctionEntry; - ULONG64 EstablisherFrame; - ULONG64 TargetIp; - PCONTEXT ContextRecord; - void (*LanguageHandler)(void); - PVOID HandlerData; - PUNWIND_HISTORY_TABLE HistoryTable; - ULONG ScopeIndex; - ULONG Fill0; -} UndocumentedDispatcherContext; -#else -typedef void *UndocumentedDispatcherContext; -#endif - -/* Another wild guess. */ -extern void __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow); - -#if LJ_TARGET_X64 && defined(MINGW_SDK_INIT) -/* Workaround for broken MinGW64 declaration. */ -VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx"); -#define RtlUnwindEx RtlUnwindEx_FIXED -#endif - -#define LJ_MSVC_EXCODE ((DWORD)0xe06d7363) -#define LJ_GCC_EXCODE ((DWORD)0x20474343) - -#define LJ_EXCODE ((DWORD)0xe24c4a00) -#define LJ_EXCODE_MAKE(c) (LJ_EXCODE | (DWORD)(c)) -#define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff) -#define LJ_EXCODE_ERRCODE(cl) ((int)((cl) & 0xff)) - -/* Windows exception handler for interpreter frame. */ -LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec, - void *f, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch) -{ -#if LJ_TARGET_X64 - void *cf = f; -#else - void *cf = (char *)f - CFRAME_OFS_SEH; -#endif - lua_State *L = cframe_L(cf); - int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ? - LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN; - if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */ - /* Unwind internal frames. */ - err_unwind(L, cf, errcode); - } else { - void *cf2 = err_unwind(L, cf, 0); - if (cf2) { /* We catch it, so start unwinding the upper frames. */ - if (rec->ExceptionCode == LJ_MSVC_EXCODE || - rec->ExceptionCode == LJ_GCC_EXCODE) { -#if LJ_TARGET_WINDOWS - __DestructExceptionObject(rec, 1); -#endif - setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); - } else if (!LJ_EXCODE_CHECK(rec->ExceptionCode)) { - /* Don't catch access violations etc. */ - return 1; /* ExceptionContinueSearch */ - } -#if LJ_TARGET_X64 - /* Unwind the stack and call all handlers for all lower C frames - ** (including ourselves) again with EH_UNWINDING set. Then set - ** rsp = cf, rax = errcode and jump to the specified target. - */ - RtlUnwindEx(cf, (void *)((cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? - lj_vm_unwind_ff_eh : - lj_vm_unwind_c_eh), - rec, (void *)(uintptr_t)errcode, ctx, dispatch->HistoryTable); - /* RtlUnwindEx should never return. */ -#else - UNUSED(ctx); - UNUSED(dispatch); - /* Call all handlers for all lower C frames (including ourselves) again - ** with EH_UNWINDING set. Then call the specified function, passing cf - ** and errcode. - */ - lj_vm_rtlunwind(cf, (void *)rec, - (cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? - (void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode); - /* lj_vm_rtlunwind does not return. */ -#endif - } - } - return 1; /* ExceptionContinueSearch */ -} - -/* Raise Windows exception. */ -static void err_raise_ext(int errcode) -{ - RaiseException(LJ_EXCODE_MAKE(errcode), 1 /* EH_NONCONTINUABLE */, 0, NULL); -} - -#endif - -/* -- Error handling ------------------------------------------------------ */ - -/* Throw error. Find catch frame, unwind stack and continue. */ -LJ_NOINLINE void LJ_FASTCALL lj_err_throw(lua_State *L, int errcode) -{ - global_State *g = G(L); - lj_trace_abort(g); - setmref(g->jit_base, NULL); - L->status = LUA_OK; -#if LJ_UNWIND_EXT - err_raise_ext(errcode); - /* - ** A return from this function signals a corrupt C stack that cannot be - ** unwound. We have no choice but to call the panic function and exit. - ** - ** Usually this is caused by a C function without unwind information. - ** This should never happen on x64, but may happen if you've manually - ** enabled LUAJIT_UNWIND_EXTERNAL and forgot to recompile *every* - ** non-C++ file with -funwind-tables. - */ - if (G(L)->panic) - G(L)->panic(L); -#else - { - void *cf = err_unwind(L, NULL, errcode); - if (cframe_unwind_ff(cf)) - lj_vm_unwind_ff(cframe_raw(cf)); - else - lj_vm_unwind_c(cframe_raw(cf), errcode); - } -#endif - exit(EXIT_FAILURE); -} - -/* Return string object for error message. */ -LJ_NOINLINE GCstr *lj_err_str(lua_State *L, ErrMsg em) -{ - return lj_str_newz(L, err2msg(em)); -} - -/* Out-of-memory error. */ -LJ_NOINLINE void lj_err_mem(lua_State *L) -{ - if (L->status == LUA_ERRERR+1) /* Don't touch the stack during lua_open. */ - lj_vm_unwind_c(L->cframe, LUA_ERRMEM); - setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRMEM)); - lj_err_throw(L, LUA_ERRMEM); -} - -/* Find error function for runtime errors. Requires an extra stack traversal. */ -static ptrdiff_t finderrfunc(lua_State *L) -{ - cTValue *frame = L->base-1, *bot = tvref(L->stack)+LJ_FR2; - void *cf = L->cframe; - while (frame > bot && cf) { - while (cframe_nres(cframe_raw(cf)) < 0) { /* cframe without frame? */ - if (frame >= restorestack(L, -cframe_nres(cf))) - break; - if (cframe_errfunc(cf) >= 0) /* Error handler not inherited (-1)? */ - return cframe_errfunc(cf); - cf = cframe_prev(cf); /* Else unwind cframe and continue searching. */ - if (cf == NULL) - return 0; - } - switch (frame_typep(frame)) { - case FRAME_LUA: - case FRAME_LUAP: - frame = frame_prevl(frame); - break; - case FRAME_C: - cf = cframe_prev(cf); - /* fallthrough */ - case FRAME_VARG: - frame = frame_prevd(frame); - break; - case FRAME_CONT: - if (frame_iscont_fficb(frame)) - cf = cframe_prev(cf); - frame = frame_prevd(frame); - break; - case FRAME_CP: - if (cframe_canyield(cf)) return 0; - if (cframe_errfunc(cf) >= 0) - return cframe_errfunc(cf); - frame = frame_prevd(frame); - break; - case FRAME_PCALL: - case FRAME_PCALLH: - if (frame_func(frame_prevd(frame))->c.ffid == FF_xpcall) - return savestack(L, frame_prevd(frame)+1); /* xpcall's errorfunc. */ - return 0; - default: - lua_assert(0); - return 0; - } - } - return 0; -} - -/* Runtime error. */ -LJ_NOINLINE void lj_err_run(lua_State *L) -{ - ptrdiff_t ef = finderrfunc(L); - if (ef) { - TValue *errfunc = restorestack(L, ef); - TValue *top = L->top; - lj_trace_abort(G(L)); - if (!tvisfunc(errfunc) || L->status == LUA_ERRERR) { - setstrV(L, top-1, lj_err_str(L, LJ_ERR_ERRERR)); - lj_err_throw(L, LUA_ERRERR); - } - L->status = LUA_ERRERR; - copyTV(L, top+LJ_FR2, top-1); - copyTV(L, top-1, errfunc); - if (LJ_FR2) setnilV(top++); - L->top = top+1; - lj_vm_call(L, top, 1+1); /* Stack: |errfunc|msg| -> |msg| */ - } - lj_err_throw(L, LUA_ERRRUN); -} - -/* Formatted runtime error message. */ -LJ_NORET LJ_NOINLINE static void err_msgv(lua_State *L, ErrMsg em, ...) -{ - const char *msg; - va_list argp; - va_start(argp, em); - if (curr_funcisL(L)) L->top = curr_topL(L); - msg = lj_strfmt_pushvf(L, err2msg(em), argp); - va_end(argp); - lj_debug_addloc(L, msg, L->base-1, NULL); - lj_err_run(L); -} - -/* Non-vararg variant for better calling conventions. */ -LJ_NOINLINE void lj_err_msg(lua_State *L, ErrMsg em) -{ - err_msgv(L, em); -} - -/* Lexer error. */ -LJ_NOINLINE void lj_err_lex(lua_State *L, GCstr *src, const char *tok, - BCLine line, ErrMsg em, va_list argp) -{ - char buff[LUA_IDSIZE]; - const char *msg; - lj_debug_shortname(buff, src, line); - msg = lj_strfmt_pushvf(L, err2msg(em), argp); - msg = lj_strfmt_pushf(L, "%s:%d: %s", buff, line, msg); - if (tok) - lj_strfmt_pushf(L, err2msg(LJ_ERR_XNEAR), msg, tok); - lj_err_throw(L, LUA_ERRSYNTAX); -} - -/* Typecheck error for operands. */ -LJ_NOINLINE void lj_err_optype(lua_State *L, cTValue *o, ErrMsg opm) -{ - const char *tname = lj_typename(o); - const char *opname = err2msg(opm); - if (curr_funcisL(L)) { - GCproto *pt = curr_proto(L); - const BCIns *pc = cframe_Lpc(L) - 1; - const char *oname = NULL; - const char *kind = lj_debug_slotname(pt, pc, (BCReg)(o-L->base), &oname); - if (kind) - err_msgv(L, LJ_ERR_BADOPRT, opname, kind, oname, tname); - } - err_msgv(L, LJ_ERR_BADOPRV, opname, tname); -} - -/* Typecheck error for ordered comparisons. */ -LJ_NOINLINE void lj_err_comp(lua_State *L, cTValue *o1, cTValue *o2) -{ - const char *t1 = lj_typename(o1); - const char *t2 = lj_typename(o2); - err_msgv(L, t1 == t2 ? LJ_ERR_BADCMPV : LJ_ERR_BADCMPT, t1, t2); - /* This assumes the two "boolean" entries are commoned by the C compiler. */ -} - -/* Typecheck error for __call. */ -LJ_NOINLINE void lj_err_optype_call(lua_State *L, TValue *o) -{ - /* Gross hack if lua_[p]call or pcall/xpcall fail for a non-callable object: - ** L->base still points to the caller. So add a dummy frame with L instead - ** of a function. See lua_getstack(). - */ - const BCIns *pc = cframe_Lpc(L); - if (((ptrdiff_t)pc & FRAME_TYPE) != FRAME_LUA) { - const char *tname = lj_typename(o); - if (LJ_FR2) o++; - setframe_pc(o, pc); - setframe_gc(o, obj2gco(L), LJ_TTHREAD); - L->top = L->base = o+1; - err_msgv(L, LJ_ERR_BADCALL, tname); - } - lj_err_optype(L, o, LJ_ERR_OPCALL); -} - -/* Error in context of caller. */ -LJ_NOINLINE void lj_err_callermsg(lua_State *L, const char *msg) -{ - TValue *frame = L->base-1; - TValue *pframe = NULL; - if (frame_islua(frame)) { - pframe = frame_prevl(frame); - } else if (frame_iscont(frame)) { - if (frame_iscont_fficb(frame)) { - pframe = frame; - frame = NULL; - } else { - pframe = frame_prevd(frame); -#if LJ_HASFFI - /* Remove frame for FFI metamethods. */ - if (frame_func(frame)->c.ffid >= FF_ffi_meta___index && - frame_func(frame)->c.ffid <= FF_ffi_meta___tostring) { - L->base = pframe+1; - L->top = frame; - setcframe_pc(cframe_raw(L->cframe), frame_contpc(frame)); - } -#endif - } - } - lj_debug_addloc(L, msg, pframe, frame); - lj_err_run(L); -} - -/* Formatted error in context of caller. */ -LJ_NOINLINE void lj_err_callerv(lua_State *L, ErrMsg em, ...) -{ - const char *msg; - va_list argp; - va_start(argp, em); - msg = lj_strfmt_pushvf(L, err2msg(em), argp); - va_end(argp); - lj_err_callermsg(L, msg); -} - -/* Error in context of caller. */ -LJ_NOINLINE void lj_err_caller(lua_State *L, ErrMsg em) -{ - lj_err_callermsg(L, err2msg(em)); -} - -/* Argument error message. */ -LJ_NORET LJ_NOINLINE static void err_argmsg(lua_State *L, int narg, - const char *msg) -{ - const char *fname = "?"; - const char *ftype = lj_debug_funcname(L, L->base - 1, &fname); - if (narg < 0 && narg > LUA_REGISTRYINDEX) - narg = (int)(L->top - L->base) + narg + 1; - if (ftype && ftype[3] == 'h' && --narg == 0) /* Check for "method". */ - msg = lj_strfmt_pushf(L, err2msg(LJ_ERR_BADSELF), fname, msg); - else - msg = lj_strfmt_pushf(L, err2msg(LJ_ERR_BADARG), narg, fname, msg); - lj_err_callermsg(L, msg); -} - -/* Formatted argument error. */ -LJ_NOINLINE void lj_err_argv(lua_State *L, int narg, ErrMsg em, ...) -{ - const char *msg; - va_list argp; - va_start(argp, em); - msg = lj_strfmt_pushvf(L, err2msg(em), argp); - va_end(argp); - err_argmsg(L, narg, msg); -} - -/* Argument error. */ -LJ_NOINLINE void lj_err_arg(lua_State *L, int narg, ErrMsg em) -{ - err_argmsg(L, narg, err2msg(em)); -} - -/* Typecheck error for arguments. */ -LJ_NOINLINE void lj_err_argtype(lua_State *L, int narg, const char *xname) -{ - const char *tname, *msg; - if (narg <= LUA_REGISTRYINDEX) { - if (narg >= LUA_GLOBALSINDEX) { - tname = lj_obj_itypename[~LJ_TTAB]; - } else { - GCfunc *fn = curr_func(L); - int idx = LUA_GLOBALSINDEX - narg; - if (idx <= fn->c.nupvalues) - tname = lj_typename(&fn->c.upvalue[idx-1]); - else - tname = lj_obj_typename[0]; - } - } else { - TValue *o = narg < 0 ? L->top + narg : L->base + narg-1; - tname = o < L->top ? lj_typename(o) : lj_obj_typename[0]; - } - msg = lj_strfmt_pushf(L, err2msg(LJ_ERR_BADTYPE), xname, tname); - err_argmsg(L, narg, msg); -} - -/* Typecheck error for arguments. */ -LJ_NOINLINE void lj_err_argt(lua_State *L, int narg, int tt) -{ - lj_err_argtype(L, narg, lj_obj_typename[tt+1]); -} - -/* -- Public error handling API ------------------------------------------- */ - -LUA_API lua_CFunction lua_atpanic(lua_State *L, lua_CFunction panicf) -{ - lua_CFunction old = G(L)->panic; - G(L)->panic = panicf; - return old; -} - -/* Forwarders for the public API (C calling convention and no LJ_NORET). */ -LUA_API int lua_error(lua_State *L) -{ - lj_err_run(L); - return 0; /* unreachable */ -} - -LUALIB_API int luaL_argerror(lua_State *L, int narg, const char *msg) -{ - err_argmsg(L, narg, msg); - return 0; /* unreachable */ -} - -LUALIB_API int luaL_typerror(lua_State *L, int narg, const char *xname) -{ - lj_err_argtype(L, narg, xname); - return 0; /* unreachable */ -} - -LUALIB_API void luaL_where(lua_State *L, int level) -{ - int size; - cTValue *frame = lj_debug_frame(L, level, &size); - lj_debug_addloc(L, "", frame, size ? frame+size : NULL); -} - -LUALIB_API int luaL_error(lua_State *L, const char *fmt, ...) -{ - const char *msg; - va_list argp; - va_start(argp, fmt); - msg = lj_strfmt_pushvf(L, fmt, argp); - va_end(argp); - lj_err_callermsg(L, msg); - return 0; /* unreachable */ -} - diff --git a/lib/LuaJIT/src/lj_err.h b/lib/LuaJIT/src/lj_err.h deleted file mode 100644 index cba5fb7..0000000 --- a/lib/LuaJIT/src/lj_err.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -** Error handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_ERR_H -#define _LJ_ERR_H - -#include - -#include "lj_obj.h" - -typedef enum { -#define ERRDEF(name, msg) \ - LJ_ERR_##name, LJ_ERR_##name##_ = LJ_ERR_##name + sizeof(msg)-1, -#include "lj_errmsg.h" - LJ_ERR__MAX -} ErrMsg; - -LJ_DATA const char *lj_err_allmsg; -#define err2msg(em) (lj_err_allmsg+(int)(em)) - -LJ_FUNC GCstr *lj_err_str(lua_State *L, ErrMsg em); -LJ_FUNCA_NORET void LJ_FASTCALL lj_err_throw(lua_State *L, int errcode); -LJ_FUNC_NORET void lj_err_mem(lua_State *L); -LJ_FUNC_NORET void lj_err_run(lua_State *L); -LJ_FUNC_NORET void lj_err_msg(lua_State *L, ErrMsg em); -LJ_FUNC_NORET void lj_err_lex(lua_State *L, GCstr *src, const char *tok, - BCLine line, ErrMsg em, va_list argp); -LJ_FUNC_NORET void lj_err_optype(lua_State *L, cTValue *o, ErrMsg opm); -LJ_FUNC_NORET void lj_err_comp(lua_State *L, cTValue *o1, cTValue *o2); -LJ_FUNC_NORET void lj_err_optype_call(lua_State *L, TValue *o); -LJ_FUNC_NORET void lj_err_callermsg(lua_State *L, const char *msg); -LJ_FUNC_NORET void lj_err_callerv(lua_State *L, ErrMsg em, ...); -LJ_FUNC_NORET void lj_err_caller(lua_State *L, ErrMsg em); -LJ_FUNC_NORET void lj_err_arg(lua_State *L, int narg, ErrMsg em); -LJ_FUNC_NORET void lj_err_argv(lua_State *L, int narg, ErrMsg em, ...); -LJ_FUNC_NORET void lj_err_argtype(lua_State *L, int narg, const char *xname); -LJ_FUNC_NORET void lj_err_argt(lua_State *L, int narg, int tt); - -#endif diff --git a/lib/LuaJIT/src/lj_errmsg.h b/lib/LuaJIT/src/lj_errmsg.h deleted file mode 100644 index 060a9f8..0000000 --- a/lib/LuaJIT/src/lj_errmsg.h +++ /dev/null @@ -1,190 +0,0 @@ -/* -** VM error messages. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -/* This file may be included multiple times with different ERRDEF macros. */ - -/* Basic error handling. */ -ERRDEF(ERRMEM, "not enough memory") -ERRDEF(ERRERR, "error in error handling") -ERRDEF(ERRCPP, "C++ exception") - -/* Allocations. */ -ERRDEF(STROV, "string length overflow") -ERRDEF(UDATAOV, "userdata length overflow") -ERRDEF(STKOV, "stack overflow") -ERRDEF(STKOVM, "stack overflow (%s)") -ERRDEF(TABOV, "table overflow") - -/* Table indexing. */ -ERRDEF(NANIDX, "table index is NaN") -ERRDEF(NILIDX, "table index is nil") -ERRDEF(NEXTIDX, "invalid key to " LUA_QL("next")) - -/* Metamethod resolving. */ -ERRDEF(BADCALL, "attempt to call a %s value") -ERRDEF(BADOPRT, "attempt to %s %s " LUA_QS " (a %s value)") -ERRDEF(BADOPRV, "attempt to %s a %s value") -ERRDEF(BADCMPT, "attempt to compare %s with %s") -ERRDEF(BADCMPV, "attempt to compare two %s values") -ERRDEF(GETLOOP, "loop in gettable") -ERRDEF(SETLOOP, "loop in settable") -ERRDEF(OPCALL, "call") -ERRDEF(OPINDEX, "index") -ERRDEF(OPARITH, "perform arithmetic on") -ERRDEF(OPCAT, "concatenate") -ERRDEF(OPLEN, "get length of") - -/* Type checks. */ -ERRDEF(BADSELF, "calling " LUA_QS " on bad self (%s)") -ERRDEF(BADARG, "bad argument #%d to " LUA_QS " (%s)") -ERRDEF(BADTYPE, "%s expected, got %s") -ERRDEF(BADVAL, "invalid value") -ERRDEF(NOVAL, "value expected") -ERRDEF(NOCORO, "coroutine expected") -ERRDEF(NOTABN, "nil or table expected") -ERRDEF(NOLFUNC, "Lua function expected") -ERRDEF(NOFUNCL, "function or level expected") -ERRDEF(NOSFT, "string/function/table expected") -ERRDEF(NOPROXY, "boolean or proxy expected") -ERRDEF(FORINIT, LUA_QL("for") " initial value must be a number") -ERRDEF(FORLIM, LUA_QL("for") " limit must be a number") -ERRDEF(FORSTEP, LUA_QL("for") " step must be a number") - -/* C API checks. */ -ERRDEF(NOENV, "no calling environment") -ERRDEF(CYIELD, "attempt to yield across C-call boundary") -ERRDEF(BADLU, "bad light userdata pointer") -ERRDEF(NOGCMM, "bad action while in __gc metamethod") -#if LJ_TARGET_WINDOWS -ERRDEF(BADFPU, "bad FPU precision (use D3DCREATE_FPU_PRESERVE with DirectX)") -#endif - -/* Standard library function errors. */ -ERRDEF(ASSERT, "assertion failed!") -ERRDEF(PROTMT, "cannot change a protected metatable") -ERRDEF(UNPACK, "too many results to unpack") -ERRDEF(RDRSTR, "reader function must return a string") -ERRDEF(PRTOSTR, LUA_QL("tostring") " must return a string to " LUA_QL("print")) -ERRDEF(IDXRNG, "index out of range") -ERRDEF(BASERNG, "base out of range") -ERRDEF(LVLRNG, "level out of range") -ERRDEF(INVLVL, "invalid level") -ERRDEF(INVOPT, "invalid option") -ERRDEF(INVOPTM, "invalid option " LUA_QS) -ERRDEF(INVFMT, "invalid format") -ERRDEF(SETFENV, LUA_QL("setfenv") " cannot change environment of given object") -ERRDEF(CORUN, "cannot resume running coroutine") -ERRDEF(CODEAD, "cannot resume dead coroutine") -ERRDEF(COSUSP, "cannot resume non-suspended coroutine") -ERRDEF(TABINS, "wrong number of arguments to " LUA_QL("insert")) -ERRDEF(TABCAT, "invalid value (%s) at index %d in table for " LUA_QL("concat")) -ERRDEF(TABSORT, "invalid order function for sorting") -ERRDEF(IOCLFL, "attempt to use a closed file") -ERRDEF(IOSTDCL, "standard file is closed") -ERRDEF(OSUNIQF, "unable to generate a unique filename") -ERRDEF(OSDATEF, "field " LUA_QS " missing in date table") -ERRDEF(STRDUMP, "unable to dump given function") -ERRDEF(STRSLC, "string slice too long") -ERRDEF(STRPATB, "missing " LUA_QL("[") " after " LUA_QL("%f") " in pattern") -ERRDEF(STRPATC, "invalid pattern capture") -ERRDEF(STRPATE, "malformed pattern (ends with " LUA_QL("%") ")") -ERRDEF(STRPATM, "malformed pattern (missing " LUA_QL("]") ")") -ERRDEF(STRPATU, "unbalanced pattern") -ERRDEF(STRPATX, "pattern too complex") -ERRDEF(STRCAPI, "invalid capture index") -ERRDEF(STRCAPN, "too many captures") -ERRDEF(STRCAPU, "unfinished capture") -ERRDEF(STRFMT, "invalid option " LUA_QS " to " LUA_QL("format")) -ERRDEF(STRGSRV, "invalid replacement value (a %s)") -ERRDEF(BADMODN, "name conflict for module " LUA_QS) -#if LJ_HASJIT -ERRDEF(JITPROT, "runtime code generation failed, restricted kernel?") -#if LJ_TARGET_X86ORX64 -ERRDEF(NOJIT, "JIT compiler disabled, CPU does not support SSE2") -#else -ERRDEF(NOJIT, "JIT compiler disabled") -#endif -#elif defined(LJ_ARCH_NOJIT) -ERRDEF(NOJIT, "no JIT compiler for this architecture (yet)") -#else -ERRDEF(NOJIT, "JIT compiler permanently disabled by build option") -#endif -ERRDEF(JITOPT, "unknown or malformed optimization flag " LUA_QS) - -/* Lexer/parser errors. */ -ERRDEF(XMODE, "attempt to load chunk with wrong mode") -ERRDEF(XNEAR, "%s near " LUA_QS) -ERRDEF(XLINES, "chunk has too many lines") -ERRDEF(XLEVELS, "chunk has too many syntax levels") -ERRDEF(XNUMBER, "malformed number") -ERRDEF(XLSTR, "unfinished long string") -ERRDEF(XLCOM, "unfinished long comment") -ERRDEF(XSTR, "unfinished string") -ERRDEF(XESC, "invalid escape sequence") -ERRDEF(XLDELIM, "invalid long string delimiter") -ERRDEF(XTOKEN, LUA_QS " expected") -ERRDEF(XJUMP, "control structure too long") -ERRDEF(XSLOTS, "function or expression too complex") -ERRDEF(XLIMC, "chunk has more than %d local variables") -ERRDEF(XLIMM, "main function has more than %d %s") -ERRDEF(XLIMF, "function at line %d has more than %d %s") -ERRDEF(XMATCH, LUA_QS " expected (to close " LUA_QS " at line %d)") -ERRDEF(XFIXUP, "function too long for return fixup") -ERRDEF(XPARAM, " or " LUA_QL("...") " expected") -#if !LJ_52 -ERRDEF(XAMBIG, "ambiguous syntax (function call x new statement)") -#endif -ERRDEF(XFUNARG, "function arguments expected") -ERRDEF(XSYMBOL, "unexpected symbol") -ERRDEF(XDOTS, "cannot use " LUA_QL("...") " outside a vararg function") -ERRDEF(XSYNTAX, "syntax error") -ERRDEF(XFOR, LUA_QL("=") " or " LUA_QL("in") " expected") -ERRDEF(XBREAK, "no loop to break") -ERRDEF(XLUNDEF, "undefined label " LUA_QS) -ERRDEF(XLDUP, "duplicate label " LUA_QS) -ERRDEF(XGSCOPE, " jumps into the scope of local " LUA_QS) - -/* Bytecode reader errors. */ -ERRDEF(BCFMT, "cannot load incompatible bytecode") -ERRDEF(BCBAD, "cannot load malformed bytecode") - -#if LJ_HASFFI -/* FFI errors. */ -ERRDEF(FFI_INVTYPE, "invalid C type") -ERRDEF(FFI_INVSIZE, "size of C type is unknown or too large") -ERRDEF(FFI_BADSCL, "bad storage class") -ERRDEF(FFI_DECLSPEC, "declaration specifier expected") -ERRDEF(FFI_BADTAG, "undeclared or implicit tag " LUA_QS) -ERRDEF(FFI_REDEF, "attempt to redefine " LUA_QS) -ERRDEF(FFI_NUMPARAM, "wrong number of type parameters") -ERRDEF(FFI_INITOV, "too many initializers for " LUA_QS) -ERRDEF(FFI_BADCONV, "cannot convert " LUA_QS " to " LUA_QS) -ERRDEF(FFI_BADLEN, "attempt to get length of " LUA_QS) -ERRDEF(FFI_BADCONCAT, "attempt to concatenate " LUA_QS " and " LUA_QS) -ERRDEF(FFI_BADARITH, "attempt to perform arithmetic on " LUA_QS " and " LUA_QS) -ERRDEF(FFI_BADCOMP, "attempt to compare " LUA_QS " with " LUA_QS) -ERRDEF(FFI_BADCALL, LUA_QS " is not callable") -ERRDEF(FFI_NUMARG, "wrong number of arguments for function call") -ERRDEF(FFI_BADMEMBER, LUA_QS " has no member named " LUA_QS) -ERRDEF(FFI_BADIDX, LUA_QS " cannot be indexed") -ERRDEF(FFI_BADIDXW, LUA_QS " cannot be indexed with " LUA_QS) -ERRDEF(FFI_BADMM, LUA_QS " has no " LUA_QS " metamethod") -ERRDEF(FFI_WRCONST, "attempt to write to constant location") -ERRDEF(FFI_NODECL, "missing declaration for symbol " LUA_QS) -ERRDEF(FFI_BADCBACK, "bad callback") -#if LJ_OS_NOJIT -ERRDEF(FFI_CBACKOV, "no support for callbacks on this OS") -#else -ERRDEF(FFI_CBACKOV, "too many callbacks") -#endif -ERRDEF(FFI_NYIPACKBIT, "NYI: packed bit fields") -ERRDEF(FFI_NYICALL, "NYI: cannot call this C function (yet)") -#endif - -#undef ERRDEF - -/* Detecting unused error messages: - awk -F, '/^ERRDEF/ { gsub(/ERRDEF./, ""); printf "grep -q LJ_ERR_%s *.[ch] || echo %s\n", $1, $1}' lj_errmsg.h | sh -*/ diff --git a/lib/LuaJIT/src/lj_ff.h b/lib/LuaJIT/src/lj_ff.h deleted file mode 100644 index 31d65a0..0000000 --- a/lib/LuaJIT/src/lj_ff.h +++ /dev/null @@ -1,18 +0,0 @@ -/* -** Fast function IDs. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_FF_H -#define _LJ_FF_H - -/* Fast function ID. */ -typedef enum { - FF_LUA_ = FF_LUA, /* Lua function (must be 0). */ - FF_C_ = FF_C, /* Regular C function (must be 1). */ -#define FFDEF(name) FF_##name, -#include "lj_ffdef.h" - FF__MAX -} FastFunc; - -#endif diff --git a/lib/LuaJIT/src/lj_ffrecord.c b/lib/LuaJIT/src/lj_ffrecord.c deleted file mode 100644 index 849d7a2..0000000 --- a/lib/LuaJIT/src/lj_ffrecord.c +++ /dev/null @@ -1,1226 +0,0 @@ -/* -** Fast function call recorder. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_ffrecord_c -#define LUA_CORE - -#include "lj_obj.h" - -#if LJ_HASJIT - -#include "lj_err.h" -#include "lj_str.h" -#include "lj_tab.h" -#include "lj_frame.h" -#include "lj_bc.h" -#include "lj_ff.h" -#include "lj_ir.h" -#include "lj_jit.h" -#include "lj_ircall.h" -#include "lj_iropt.h" -#include "lj_trace.h" -#include "lj_record.h" -#include "lj_ffrecord.h" -#include "lj_crecord.h" -#include "lj_dispatch.h" -#include "lj_vm.h" -#include "lj_strscan.h" -#include "lj_strfmt.h" - -/* Some local macros to save typing. Undef'd at the end. */ -#define IR(ref) (&J->cur.ir[(ref)]) - -/* Pass IR on to next optimization in chain (FOLD). */ -#define emitir(ot, a, b) (lj_ir_set(J, (ot), (a), (b)), lj_opt_fold(J)) - -/* -- Fast function recording handlers ------------------------------------ */ - -/* Conventions for fast function call handlers: -** -** The argument slots start at J->base[0]. All of them are guaranteed to be -** valid and type-specialized references. J->base[J->maxslot] is set to 0 -** as a sentinel. The runtime argument values start at rd->argv[0]. -** -** In general fast functions should check for presence of all of their -** arguments and for the correct argument types. Some simplifications -** are allowed if the interpreter throws instead. But even if recording -** is aborted, the generated IR must be consistent (no zero-refs). -** -** The number of results in rd->nres is set to 1. Handlers that return -** a different number of results need to override it. A negative value -** prevents return processing (e.g. for pending calls). -** -** Results need to be stored starting at J->base[0]. Return processing -** moves them to the right slots later. -** -** The per-ffid auxiliary data is the value of the 2nd part of the -** LJLIB_REC() annotation. This allows handling similar functionality -** in a common handler. -*/ - -/* Type of handler to record a fast function. */ -typedef void (LJ_FASTCALL *RecordFunc)(jit_State *J, RecordFFData *rd); - -/* Get runtime value of int argument. */ -static int32_t argv2int(jit_State *J, TValue *o) -{ - if (!lj_strscan_numberobj(o)) - lj_trace_err(J, LJ_TRERR_BADTYPE); - return tvisint(o) ? intV(o) : lj_num2int(numV(o)); -} - -/* Get runtime value of string argument. */ -static GCstr *argv2str(jit_State *J, TValue *o) -{ - if (LJ_LIKELY(tvisstr(o))) { - return strV(o); - } else { - GCstr *s; - if (!tvisnumber(o)) - lj_trace_err(J, LJ_TRERR_BADTYPE); - s = lj_strfmt_number(J->L, o); - setstrV(J->L, o, s); - return s; - } -} - -/* Return number of results wanted by caller. */ -static ptrdiff_t results_wanted(jit_State *J) -{ - TValue *frame = J->L->base-1; - if (frame_islua(frame)) - return (ptrdiff_t)bc_b(frame_pc(frame)[-1]) - 1; - else - return -1; -} - -/* Trace stitching: add continuation below frame to start a new trace. */ -static void recff_stitch(jit_State *J) -{ - ASMFunction cont = lj_cont_stitch; - lua_State *L = J->L; - TValue *base = L->base; - BCReg nslot = J->maxslot + 1 + LJ_FR2; - TValue *nframe = base + 1 + LJ_FR2; - const BCIns *pc = frame_pc(base-1); - TValue *pframe = frame_prevl(base-1); - - /* Move func + args up in Lua stack and insert continuation. */ - memmove(&base[1], &base[-1-LJ_FR2], sizeof(TValue)*nslot); - setframe_ftsz(nframe, ((char *)nframe - (char *)pframe) + FRAME_CONT); - setcont(base-LJ_FR2, cont); - setframe_pc(base, pc); - setnilV(base-1-LJ_FR2); /* Incorrect, but rec_check_slots() won't run anymore. */ - L->base += 2 + LJ_FR2; - L->top += 2 + LJ_FR2; - - /* Ditto for the IR. */ - memmove(&J->base[1], &J->base[-1-LJ_FR2], sizeof(TRef)*nslot); -#if LJ_FR2 - J->base[2] = TREF_FRAME; - J->base[-1] = lj_ir_k64(J, IR_KNUM, u64ptr(contptr(cont))); - J->base[0] = lj_ir_k64(J, IR_KNUM, u64ptr(pc)) | TREF_CONT; -#else - J->base[0] = lj_ir_kptr(J, contptr(cont)) | TREF_CONT; -#endif - J->ktrace = tref_ref((J->base[-1-LJ_FR2] = lj_ir_ktrace(J))); - J->base += 2 + LJ_FR2; - J->baseslot += 2 + LJ_FR2; - J->framedepth++; - - lj_record_stop(J, LJ_TRLINK_STITCH, 0); - - /* Undo Lua stack changes. */ - memmove(&base[-1-LJ_FR2], &base[1], sizeof(TValue)*nslot); - setframe_pc(base-1, pc); - L->base -= 2 + LJ_FR2; - L->top -= 2 + LJ_FR2; -} - -/* Fallback handler for fast functions that are not recorded (yet). */ -static void LJ_FASTCALL recff_nyi(jit_State *J, RecordFFData *rd) -{ - if (J->cur.nins < (IRRef)J->param[JIT_P_minstitch] + REF_BASE) { - lj_trace_err_info(J, LJ_TRERR_TRACEUV); - } else { - /* Can only stitch from Lua call. */ - if (J->framedepth && frame_islua(J->L->base-1)) { - BCOp op = bc_op(*frame_pc(J->L->base-1)); - /* Stitched trace cannot start with *M op with variable # of args. */ - if (!(op == BC_CALLM || op == BC_CALLMT || - op == BC_RETM || op == BC_TSETM)) { - switch (J->fn->c.ffid) { - case FF_error: - case FF_debug_sethook: - case FF_jit_flush: - break; /* Don't stitch across special builtins. */ - default: - recff_stitch(J); /* Use trace stitching. */ - rd->nres = -1; - return; - } - } - } - /* Otherwise stop trace and return to interpreter. */ - lj_record_stop(J, LJ_TRLINK_RETURN, 0); - rd->nres = -1; - } -} - -/* Fallback handler for unsupported variants of fast functions. */ -#define recff_nyiu recff_nyi - -/* Must stop the trace for classic C functions with arbitrary side-effects. */ -#define recff_c recff_nyi - -/* Emit BUFHDR for the global temporary buffer. */ -static TRef recff_bufhdr(jit_State *J) -{ - return emitir(IRT(IR_BUFHDR, IRT_PGC), - lj_ir_kptr(J, &J2G(J)->tmpbuf), IRBUFHDR_RESET); -} - -/* -- Base library fast functions ----------------------------------------- */ - -static void LJ_FASTCALL recff_assert(jit_State *J, RecordFFData *rd) -{ - /* Arguments already specialized. The interpreter throws for nil/false. */ - rd->nres = J->maxslot; /* Pass through all arguments. */ -} - -static void LJ_FASTCALL recff_type(jit_State *J, RecordFFData *rd) -{ - /* Arguments already specialized. Result is a constant string. Neat, huh? */ - uint32_t t; - if (tvisnumber(&rd->argv[0])) - t = ~LJ_TNUMX; - else if (LJ_64 && !LJ_GC64 && tvislightud(&rd->argv[0])) - t = ~LJ_TLIGHTUD; - else - t = ~itype(&rd->argv[0]); - J->base[0] = lj_ir_kstr(J, strV(&J->fn->c.upvalue[t])); - UNUSED(rd); -} - -static void LJ_FASTCALL recff_getmetatable(jit_State *J, RecordFFData *rd) -{ - TRef tr = J->base[0]; - if (tr) { - RecordIndex ix; - ix.tab = tr; - copyTV(J->L, &ix.tabv, &rd->argv[0]); - if (lj_record_mm_lookup(J, &ix, MM_metatable)) - J->base[0] = ix.mobj; - else - J->base[0] = ix.mt; - } /* else: Interpreter will throw. */ -} - -static void LJ_FASTCALL recff_setmetatable(jit_State *J, RecordFFData *rd) -{ - TRef tr = J->base[0]; - TRef mt = J->base[1]; - if (tref_istab(tr) && (tref_istab(mt) || (mt && tref_isnil(mt)))) { - TRef fref, mtref; - RecordIndex ix; - ix.tab = tr; - copyTV(J->L, &ix.tabv, &rd->argv[0]); - lj_record_mm_lookup(J, &ix, MM_metatable); /* Guard for no __metatable. */ - fref = emitir(IRT(IR_FREF, IRT_PGC), tr, IRFL_TAB_META); - mtref = tref_isnil(mt) ? lj_ir_knull(J, IRT_TAB) : mt; - emitir(IRT(IR_FSTORE, IRT_TAB), fref, mtref); - if (!tref_isnil(mt)) - emitir(IRT(IR_TBAR, IRT_TAB), tr, 0); - J->base[0] = tr; - J->needsnap = 1; - } /* else: Interpreter will throw. */ -} - -static void LJ_FASTCALL recff_rawget(jit_State *J, RecordFFData *rd) -{ - RecordIndex ix; - ix.tab = J->base[0]; ix.key = J->base[1]; - if (tref_istab(ix.tab) && ix.key) { - ix.val = 0; ix.idxchain = 0; - settabV(J->L, &ix.tabv, tabV(&rd->argv[0])); - copyTV(J->L, &ix.keyv, &rd->argv[1]); - J->base[0] = lj_record_idx(J, &ix); - } /* else: Interpreter will throw. */ -} - -static void LJ_FASTCALL recff_rawset(jit_State *J, RecordFFData *rd) -{ - RecordIndex ix; - ix.tab = J->base[0]; ix.key = J->base[1]; ix.val = J->base[2]; - if (tref_istab(ix.tab) && ix.key && ix.val) { - ix.idxchain = 0; - settabV(J->L, &ix.tabv, tabV(&rd->argv[0])); - copyTV(J->L, &ix.keyv, &rd->argv[1]); - copyTV(J->L, &ix.valv, &rd->argv[2]); - lj_record_idx(J, &ix); - /* Pass through table at J->base[0] as result. */ - } /* else: Interpreter will throw. */ -} - -static void LJ_FASTCALL recff_rawequal(jit_State *J, RecordFFData *rd) -{ - TRef tra = J->base[0]; - TRef trb = J->base[1]; - if (tra && trb) { - int diff = lj_record_objcmp(J, tra, trb, &rd->argv[0], &rd->argv[1]); - J->base[0] = diff ? TREF_FALSE : TREF_TRUE; - } /* else: Interpreter will throw. */ -} - -#if LJ_52 -static void LJ_FASTCALL recff_rawlen(jit_State *J, RecordFFData *rd) -{ - TRef tr = J->base[0]; - if (tref_isstr(tr)) - J->base[0] = emitir(IRTI(IR_FLOAD), tr, IRFL_STR_LEN); - else if (tref_istab(tr)) - J->base[0] = lj_ir_call(J, IRCALL_lj_tab_len, tr); - /* else: Interpreter will throw. */ - UNUSED(rd); -} -#endif - -/* Determine mode of select() call. */ -int32_t lj_ffrecord_select_mode(jit_State *J, TRef tr, TValue *tv) -{ - if (tref_isstr(tr) && *strVdata(tv) == '#') { /* select('#', ...) */ - if (strV(tv)->len == 1) { - emitir(IRTG(IR_EQ, IRT_STR), tr, lj_ir_kstr(J, strV(tv))); - } else { - TRef trptr = emitir(IRT(IR_STRREF, IRT_PGC), tr, lj_ir_kint(J, 0)); - TRef trchar = emitir(IRT(IR_XLOAD, IRT_U8), trptr, IRXLOAD_READONLY); - emitir(IRTG(IR_EQ, IRT_INT), trchar, lj_ir_kint(J, '#')); - } - return 0; - } else { /* select(n, ...) */ - int32_t start = argv2int(J, tv); - if (start == 0) lj_trace_err(J, LJ_TRERR_BADTYPE); /* A bit misleading. */ - return start; - } -} - -static void LJ_FASTCALL recff_select(jit_State *J, RecordFFData *rd) -{ - TRef tr = J->base[0]; - if (tr) { - ptrdiff_t start = lj_ffrecord_select_mode(J, tr, &rd->argv[0]); - if (start == 0) { /* select('#', ...) */ - J->base[0] = lj_ir_kint(J, J->maxslot - 1); - } else if (tref_isk(tr)) { /* select(k, ...) */ - ptrdiff_t n = (ptrdiff_t)J->maxslot; - if (start < 0) start += n; - else if (start > n) start = n; - rd->nres = n - start; - if (start >= 1) { - ptrdiff_t i; - for (i = 0; i < n - start; i++) - J->base[i] = J->base[start+i]; - } /* else: Interpreter will throw. */ - } else { - recff_nyiu(J, rd); - return; - } - } /* else: Interpreter will throw. */ -} - -static void LJ_FASTCALL recff_tonumber(jit_State *J, RecordFFData *rd) -{ - TRef tr = J->base[0]; - TRef base = J->base[1]; - if (tr && !tref_isnil(base)) { - base = lj_opt_narrow_toint(J, base); - if (!tref_isk(base) || IR(tref_ref(base))->i != 10) { - recff_nyiu(J, rd); - return; - } - } - if (tref_isnumber_str(tr)) { - if (tref_isstr(tr)) { - TValue tmp; - if (!lj_strscan_num(strV(&rd->argv[0]), &tmp)) { - recff_nyiu(J, rd); /* Would need an inverted STRTO for this case. */ - return; - } - tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0); - } -#if LJ_HASFFI - } else if (tref_iscdata(tr)) { - lj_crecord_tonumber(J, rd); - return; -#endif - } else { - tr = TREF_NIL; - } - J->base[0] = tr; - UNUSED(rd); -} - -static TValue *recff_metacall_cp(lua_State *L, lua_CFunction dummy, void *ud) -{ - jit_State *J = (jit_State *)ud; - lj_record_tailcall(J, 0, 1); - UNUSED(L); UNUSED(dummy); - return NULL; -} - -static int recff_metacall(jit_State *J, RecordFFData *rd, MMS mm) -{ - RecordIndex ix; - ix.tab = J->base[0]; - copyTV(J->L, &ix.tabv, &rd->argv[0]); - if (lj_record_mm_lookup(J, &ix, mm)) { /* Has metamethod? */ - int errcode; - TValue argv0; - /* Temporarily insert metamethod below object. */ - J->base[1+LJ_FR2] = J->base[0]; - J->base[0] = ix.mobj; - copyTV(J->L, &argv0, &rd->argv[0]); - copyTV(J->L, &rd->argv[1+LJ_FR2], &rd->argv[0]); - copyTV(J->L, &rd->argv[0], &ix.mobjv); - /* Need to protect lj_record_tailcall because it may throw. */ - errcode = lj_vm_cpcall(J->L, NULL, J, recff_metacall_cp); - /* Always undo Lua stack changes to avoid confusing the interpreter. */ - copyTV(J->L, &rd->argv[0], &argv0); - if (errcode) - lj_err_throw(J->L, errcode); /* Propagate errors. */ - rd->nres = -1; /* Pending call. */ - return 1; /* Tailcalled to metamethod. */ - } - return 0; -} - -static void LJ_FASTCALL recff_tostring(jit_State *J, RecordFFData *rd) -{ - TRef tr = J->base[0]; - if (tref_isstr(tr)) { - /* Ignore __tostring in the string base metatable. */ - /* Pass on result in J->base[0]. */ - } else if (tr && !recff_metacall(J, rd, MM_tostring)) { - if (tref_isnumber(tr)) { - J->base[0] = emitir(IRT(IR_TOSTR, IRT_STR), tr, - tref_isnum(tr) ? IRTOSTR_NUM : IRTOSTR_INT); - } else if (tref_ispri(tr)) { - J->base[0] = lj_ir_kstr(J, lj_strfmt_obj(J->L, &rd->argv[0])); - } else { - recff_nyiu(J, rd); - return; - } - } -} - -static void LJ_FASTCALL recff_ipairs_aux(jit_State *J, RecordFFData *rd) -{ - RecordIndex ix; - ix.tab = J->base[0]; - if (tref_istab(ix.tab)) { - if (!tvisnumber(&rd->argv[1])) /* No support for string coercion. */ - lj_trace_err(J, LJ_TRERR_BADTYPE); - setintV(&ix.keyv, numberVint(&rd->argv[1])+1); - settabV(J->L, &ix.tabv, tabV(&rd->argv[0])); - ix.val = 0; ix.idxchain = 0; - ix.key = lj_opt_narrow_toint(J, J->base[1]); - J->base[0] = ix.key = emitir(IRTI(IR_ADD), ix.key, lj_ir_kint(J, 1)); - J->base[1] = lj_record_idx(J, &ix); - rd->nres = tref_isnil(J->base[1]) ? 0 : 2; - } /* else: Interpreter will throw. */ -} - -static void LJ_FASTCALL recff_xpairs(jit_State *J, RecordFFData *rd) -{ - TRef tr = J->base[0]; - if (!((LJ_52 || (LJ_HASFFI && tref_iscdata(tr))) && - recff_metacall(J, rd, MM_pairs + rd->data))) { - if (tref_istab(tr)) { - J->base[0] = lj_ir_kfunc(J, funcV(&J->fn->c.upvalue[0])); - J->base[1] = tr; - J->base[2] = rd->data ? lj_ir_kint(J, 0) : TREF_NIL; - rd->nres = 3; - } /* else: Interpreter will throw. */ - } -} - -static void LJ_FASTCALL recff_pcall(jit_State *J, RecordFFData *rd) -{ - if (J->maxslot >= 1) { -#if LJ_FR2 - /* Shift function arguments up. */ - memmove(J->base + 1, J->base, sizeof(TRef) * J->maxslot); -#endif - lj_record_call(J, 0, J->maxslot - 1); - rd->nres = -1; /* Pending call. */ - } /* else: Interpreter will throw. */ -} - -static TValue *recff_xpcall_cp(lua_State *L, lua_CFunction dummy, void *ud) -{ - jit_State *J = (jit_State *)ud; - lj_record_call(J, 1, J->maxslot - 2); - UNUSED(L); UNUSED(dummy); - return NULL; -} - -static void LJ_FASTCALL recff_xpcall(jit_State *J, RecordFFData *rd) -{ - if (J->maxslot >= 2) { - TValue argv0, argv1; - TRef tmp; - int errcode; - /* Swap function and traceback. */ - tmp = J->base[0]; J->base[0] = J->base[1]; J->base[1] = tmp; - copyTV(J->L, &argv0, &rd->argv[0]); - copyTV(J->L, &argv1, &rd->argv[1]); - copyTV(J->L, &rd->argv[0], &argv1); - copyTV(J->L, &rd->argv[1], &argv0); -#if LJ_FR2 - /* Shift function arguments up. */ - memmove(J->base + 2, J->base + 1, sizeof(TRef) * (J->maxslot-1)); -#endif - /* Need to protect lj_record_call because it may throw. */ - errcode = lj_vm_cpcall(J->L, NULL, J, recff_xpcall_cp); - /* Always undo Lua stack swap to avoid confusing the interpreter. */ - copyTV(J->L, &rd->argv[0], &argv0); - copyTV(J->L, &rd->argv[1], &argv1); - if (errcode) - lj_err_throw(J->L, errcode); /* Propagate errors. */ - rd->nres = -1; /* Pending call. */ - } /* else: Interpreter will throw. */ -} - -static void LJ_FASTCALL recff_getfenv(jit_State *J, RecordFFData *rd) -{ - TRef tr = J->base[0]; - /* Only support getfenv(0) for now. */ - if (tref_isint(tr) && tref_isk(tr) && IR(tref_ref(tr))->i == 0) { - TRef trl = emitir(IRT(IR_LREF, IRT_THREAD), 0, 0); - J->base[0] = emitir(IRT(IR_FLOAD, IRT_TAB), trl, IRFL_THREAD_ENV); - return; - } - recff_nyiu(J, rd); -} - -/* -- Math library fast functions ----------------------------------------- */ - -static void LJ_FASTCALL recff_math_abs(jit_State *J, RecordFFData *rd) -{ - TRef tr = lj_ir_tonum(J, J->base[0]); - J->base[0] = emitir(IRTN(IR_ABS), tr, lj_ir_ksimd(J, LJ_KSIMD_ABS)); - UNUSED(rd); -} - -/* Record rounding functions math.floor and math.ceil. */ -static void LJ_FASTCALL recff_math_round(jit_State *J, RecordFFData *rd) -{ - TRef tr = J->base[0]; - if (!tref_isinteger(tr)) { /* Pass through integers unmodified. */ - tr = emitir(IRTN(IR_FPMATH), lj_ir_tonum(J, tr), rd->data); - /* Result is integral (or NaN/Inf), but may not fit an int32_t. */ - if (LJ_DUALNUM) { /* Try to narrow using a guarded conversion to int. */ - lua_Number n = lj_vm_foldfpm(numberVnum(&rd->argv[0]), rd->data); - if (n == (lua_Number)lj_num2int(n)) - tr = emitir(IRTGI(IR_CONV), tr, IRCONV_INT_NUM|IRCONV_CHECK); - } - J->base[0] = tr; - } -} - -/* Record unary math.* functions, mapped to IR_FPMATH opcode. */ -static void LJ_FASTCALL recff_math_unary(jit_State *J, RecordFFData *rd) -{ - J->base[0] = emitir(IRTN(IR_FPMATH), lj_ir_tonum(J, J->base[0]), rd->data); -} - -/* Record math.log. */ -static void LJ_FASTCALL recff_math_log(jit_State *J, RecordFFData *rd) -{ - TRef tr = lj_ir_tonum(J, J->base[0]); - if (J->base[1]) { -#ifdef LUAJIT_NO_LOG2 - uint32_t fpm = IRFPM_LOG; -#else - uint32_t fpm = IRFPM_LOG2; -#endif - TRef trb = lj_ir_tonum(J, J->base[1]); - tr = emitir(IRTN(IR_FPMATH), tr, fpm); - trb = emitir(IRTN(IR_FPMATH), trb, fpm); - trb = emitir(IRTN(IR_DIV), lj_ir_knum_one(J), trb); - tr = emitir(IRTN(IR_MUL), tr, trb); - } else { - tr = emitir(IRTN(IR_FPMATH), tr, IRFPM_LOG); - } - J->base[0] = tr; - UNUSED(rd); -} - -/* Record math.atan2. */ -static void LJ_FASTCALL recff_math_atan2(jit_State *J, RecordFFData *rd) -{ - TRef tr = lj_ir_tonum(J, J->base[0]); - TRef tr2 = lj_ir_tonum(J, J->base[1]); - J->base[0] = emitir(IRTN(IR_ATAN2), tr, tr2); - UNUSED(rd); -} - -/* Record math.ldexp. */ -static void LJ_FASTCALL recff_math_ldexp(jit_State *J, RecordFFData *rd) -{ - TRef tr = lj_ir_tonum(J, J->base[0]); -#if LJ_TARGET_X86ORX64 - TRef tr2 = lj_ir_tonum(J, J->base[1]); -#else - TRef tr2 = lj_opt_narrow_toint(J, J->base[1]); -#endif - J->base[0] = emitir(IRTN(IR_LDEXP), tr, tr2); - UNUSED(rd); -} - -/* Record math.asin, math.acos, math.atan. */ -static void LJ_FASTCALL recff_math_atrig(jit_State *J, RecordFFData *rd) -{ - TRef y = lj_ir_tonum(J, J->base[0]); - TRef x = lj_ir_knum_one(J); - uint32_t ffid = rd->data; - if (ffid != FF_math_atan) { - TRef tmp = emitir(IRTN(IR_MUL), y, y); - tmp = emitir(IRTN(IR_SUB), x, tmp); - tmp = emitir(IRTN(IR_FPMATH), tmp, IRFPM_SQRT); - if (ffid == FF_math_asin) { x = tmp; } else { x = y; y = tmp; } - } - J->base[0] = emitir(IRTN(IR_ATAN2), y, x); -} - -static void LJ_FASTCALL recff_math_htrig(jit_State *J, RecordFFData *rd) -{ - TRef tr = lj_ir_tonum(J, J->base[0]); - J->base[0] = emitir(IRTN(IR_CALLN), tr, rd->data); -} - -static void LJ_FASTCALL recff_math_modf(jit_State *J, RecordFFData *rd) -{ - TRef tr = J->base[0]; - if (tref_isinteger(tr)) { - J->base[0] = tr; - J->base[1] = lj_ir_kint(J, 0); - } else { - TRef trt; - tr = lj_ir_tonum(J, tr); - trt = emitir(IRTN(IR_FPMATH), tr, IRFPM_TRUNC); - J->base[0] = trt; - J->base[1] = emitir(IRTN(IR_SUB), tr, trt); - } - rd->nres = 2; -} - -static void LJ_FASTCALL recff_math_pow(jit_State *J, RecordFFData *rd) -{ - J->base[0] = lj_opt_narrow_pow(J, J->base[0], J->base[1], - &rd->argv[0], &rd->argv[1]); - UNUSED(rd); -} - -static void LJ_FASTCALL recff_math_minmax(jit_State *J, RecordFFData *rd) -{ - TRef tr = lj_ir_tonumber(J, J->base[0]); - uint32_t op = rd->data; - BCReg i; - for (i = 1; J->base[i] != 0; i++) { - TRef tr2 = lj_ir_tonumber(J, J->base[i]); - IRType t = IRT_INT; - if (!(tref_isinteger(tr) && tref_isinteger(tr2))) { - if (tref_isinteger(tr)) tr = emitir(IRTN(IR_CONV), tr, IRCONV_NUM_INT); - if (tref_isinteger(tr2)) tr2 = emitir(IRTN(IR_CONV), tr2, IRCONV_NUM_INT); - t = IRT_NUM; - } - tr = emitir(IRT(op, t), tr, tr2); - } - J->base[0] = tr; -} - -static void LJ_FASTCALL recff_math_random(jit_State *J, RecordFFData *rd) -{ - GCudata *ud = udataV(&J->fn->c.upvalue[0]); - TRef tr, one; - lj_ir_kgc(J, obj2gco(ud), IRT_UDATA); /* Prevent collection. */ - tr = lj_ir_call(J, IRCALL_lj_math_random_step, lj_ir_kptr(J, uddata(ud))); - one = lj_ir_knum_one(J); - tr = emitir(IRTN(IR_SUB), tr, one); - if (J->base[0]) { - TRef tr1 = lj_ir_tonum(J, J->base[0]); - if (J->base[1]) { /* d = floor(d*(r2-r1+1.0)) + r1 */ - TRef tr2 = lj_ir_tonum(J, J->base[1]); - tr2 = emitir(IRTN(IR_SUB), tr2, tr1); - tr2 = emitir(IRTN(IR_ADD), tr2, one); - tr = emitir(IRTN(IR_MUL), tr, tr2); - tr = emitir(IRTN(IR_FPMATH), tr, IRFPM_FLOOR); - tr = emitir(IRTN(IR_ADD), tr, tr1); - } else { /* d = floor(d*r1) + 1.0 */ - tr = emitir(IRTN(IR_MUL), tr, tr1); - tr = emitir(IRTN(IR_FPMATH), tr, IRFPM_FLOOR); - tr = emitir(IRTN(IR_ADD), tr, one); - } - } - J->base[0] = tr; - UNUSED(rd); -} - -/* -- Bit library fast functions ------------------------------------------ */ - -/* Record bit.tobit. */ -static void LJ_FASTCALL recff_bit_tobit(jit_State *J, RecordFFData *rd) -{ - TRef tr = J->base[0]; -#if LJ_HASFFI - if (tref_iscdata(tr)) { recff_bit64_tobit(J, rd); return; } -#endif - J->base[0] = lj_opt_narrow_tobit(J, tr); - UNUSED(rd); -} - -/* Record unary bit.bnot, bit.bswap. */ -static void LJ_FASTCALL recff_bit_unary(jit_State *J, RecordFFData *rd) -{ -#if LJ_HASFFI - if (recff_bit64_unary(J, rd)) - return; -#endif - J->base[0] = emitir(IRTI(rd->data), lj_opt_narrow_tobit(J, J->base[0]), 0); -} - -/* Record N-ary bit.band, bit.bor, bit.bxor. */ -static void LJ_FASTCALL recff_bit_nary(jit_State *J, RecordFFData *rd) -{ -#if LJ_HASFFI - if (recff_bit64_nary(J, rd)) - return; -#endif - { - TRef tr = lj_opt_narrow_tobit(J, J->base[0]); - uint32_t ot = IRTI(rd->data); - BCReg i; - for (i = 1; J->base[i] != 0; i++) - tr = emitir(ot, tr, lj_opt_narrow_tobit(J, J->base[i])); - J->base[0] = tr; - } -} - -/* Record bit shifts. */ -static void LJ_FASTCALL recff_bit_shift(jit_State *J, RecordFFData *rd) -{ -#if LJ_HASFFI - if (recff_bit64_shift(J, rd)) - return; -#endif - { - TRef tr = lj_opt_narrow_tobit(J, J->base[0]); - TRef tsh = lj_opt_narrow_tobit(J, J->base[1]); - IROp op = (IROp)rd->data; - if (!(op < IR_BROL ? LJ_TARGET_MASKSHIFT : LJ_TARGET_MASKROT) && - !tref_isk(tsh)) - tsh = emitir(IRTI(IR_BAND), tsh, lj_ir_kint(J, 31)); -#ifdef LJ_TARGET_UNIFYROT - if (op == (LJ_TARGET_UNIFYROT == 1 ? IR_BROR : IR_BROL)) { - op = LJ_TARGET_UNIFYROT == 1 ? IR_BROL : IR_BROR; - tsh = emitir(IRTI(IR_NEG), tsh, tsh); - } -#endif - J->base[0] = emitir(IRTI(op), tr, tsh); - } -} - -static void LJ_FASTCALL recff_bit_tohex(jit_State *J, RecordFFData *rd) -{ -#if LJ_HASFFI - TRef hdr = recff_bufhdr(J); - TRef tr = recff_bit64_tohex(J, rd, hdr); - J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr); -#else - recff_nyiu(J, rd); /* Don't bother working around this NYI. */ -#endif -} - -/* -- String library fast functions --------------------------------------- */ - -/* Specialize to relative starting position for string. */ -static TRef recff_string_start(jit_State *J, GCstr *s, int32_t *st, TRef tr, - TRef trlen, TRef tr0) -{ - int32_t start = *st; - if (start < 0) { - emitir(IRTGI(IR_LT), tr, tr0); - tr = emitir(IRTI(IR_ADD), trlen, tr); - start = start + (int32_t)s->len; - emitir(start < 0 ? IRTGI(IR_LT) : IRTGI(IR_GE), tr, tr0); - if (start < 0) { - tr = tr0; - start = 0; - } - } else if (start == 0) { - emitir(IRTGI(IR_EQ), tr, tr0); - tr = tr0; - } else { - tr = emitir(IRTI(IR_ADD), tr, lj_ir_kint(J, -1)); - emitir(IRTGI(IR_GE), tr, tr0); - start--; - } - *st = start; - return tr; -} - -/* Handle string.byte (rd->data = 0) and string.sub (rd->data = 1). */ -static void LJ_FASTCALL recff_string_range(jit_State *J, RecordFFData *rd) -{ - TRef trstr = lj_ir_tostr(J, J->base[0]); - TRef trlen = emitir(IRTI(IR_FLOAD), trstr, IRFL_STR_LEN); - TRef tr0 = lj_ir_kint(J, 0); - TRef trstart, trend; - GCstr *str = argv2str(J, &rd->argv[0]); - int32_t start, end; - if (rd->data) { /* string.sub(str, start [,end]) */ - start = argv2int(J, &rd->argv[1]); - trstart = lj_opt_narrow_toint(J, J->base[1]); - trend = J->base[2]; - if (tref_isnil(trend)) { - trend = lj_ir_kint(J, -1); - end = -1; - } else { - trend = lj_opt_narrow_toint(J, trend); - end = argv2int(J, &rd->argv[2]); - } - } else { /* string.byte(str, [,start [,end]]) */ - if (tref_isnil(J->base[1])) { - start = 1; - trstart = lj_ir_kint(J, 1); - } else { - start = argv2int(J, &rd->argv[1]); - trstart = lj_opt_narrow_toint(J, J->base[1]); - } - if (J->base[1] && !tref_isnil(J->base[2])) { - trend = lj_opt_narrow_toint(J, J->base[2]); - end = argv2int(J, &rd->argv[2]); - } else { - trend = trstart; - end = start; - } - } - if (end < 0) { - emitir(IRTGI(IR_LT), trend, tr0); - trend = emitir(IRTI(IR_ADD), emitir(IRTI(IR_ADD), trlen, trend), - lj_ir_kint(J, 1)); - end = end+(int32_t)str->len+1; - } else if ((MSize)end <= str->len) { - emitir(IRTGI(IR_ULE), trend, trlen); - } else { - emitir(IRTGI(IR_UGT), trend, trlen); - end = (int32_t)str->len; - trend = trlen; - } - trstart = recff_string_start(J, str, &start, trstart, trlen, tr0); - if (rd->data) { /* Return string.sub result. */ - if (end - start >= 0) { - /* Also handle empty range here, to avoid extra traces. */ - TRef trptr, trslen = emitir(IRTI(IR_SUB), trend, trstart); - emitir(IRTGI(IR_GE), trslen, tr0); - trptr = emitir(IRT(IR_STRREF, IRT_PGC), trstr, trstart); - J->base[0] = emitir(IRT(IR_SNEW, IRT_STR), trptr, trslen); - } else { /* Range underflow: return empty string. */ - emitir(IRTGI(IR_LT), trend, trstart); - J->base[0] = lj_ir_kstr(J, &J2G(J)->strempty); - } - } else { /* Return string.byte result(s). */ - ptrdiff_t i, len = end - start; - if (len > 0) { - TRef trslen = emitir(IRTI(IR_SUB), trend, trstart); - emitir(IRTGI(IR_EQ), trslen, lj_ir_kint(J, (int32_t)len)); - if (J->baseslot + len > LJ_MAX_JSLOTS) - lj_trace_err_info(J, LJ_TRERR_STACKOV); - rd->nres = len; - for (i = 0; i < len; i++) { - TRef tmp = emitir(IRTI(IR_ADD), trstart, lj_ir_kint(J, (int32_t)i)); - tmp = emitir(IRT(IR_STRREF, IRT_PGC), trstr, tmp); - J->base[i] = emitir(IRT(IR_XLOAD, IRT_U8), tmp, IRXLOAD_READONLY); - } - } else { /* Empty range or range underflow: return no results. */ - emitir(IRTGI(IR_LE), trend, trstart); - rd->nres = 0; - } - } -} - -static void LJ_FASTCALL recff_string_char(jit_State *J, RecordFFData *rd) -{ - TRef k255 = lj_ir_kint(J, 255); - BCReg i; - for (i = 0; J->base[i] != 0; i++) { /* Convert char values to strings. */ - TRef tr = lj_opt_narrow_toint(J, J->base[i]); - emitir(IRTGI(IR_ULE), tr, k255); - J->base[i] = emitir(IRT(IR_TOSTR, IRT_STR), tr, IRTOSTR_CHAR); - } - if (i > 1) { /* Concatenate the strings, if there's more than one. */ - TRef hdr = recff_bufhdr(J), tr = hdr; - for (i = 0; J->base[i] != 0; i++) - tr = emitir(IRT(IR_BUFPUT, IRT_PGC), tr, J->base[i]); - J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr); - } - UNUSED(rd); -} - -static void LJ_FASTCALL recff_string_rep(jit_State *J, RecordFFData *rd) -{ - TRef str = lj_ir_tostr(J, J->base[0]); - TRef rep = lj_opt_narrow_toint(J, J->base[1]); - TRef hdr, tr, str2 = 0; - if (!tref_isnil(J->base[2])) { - TRef sep = lj_ir_tostr(J, J->base[2]); - int32_t vrep = argv2int(J, &rd->argv[1]); - emitir(IRTGI(vrep > 1 ? IR_GT : IR_LE), rep, lj_ir_kint(J, 1)); - if (vrep > 1) { - TRef hdr2 = recff_bufhdr(J); - TRef tr2 = emitir(IRT(IR_BUFPUT, IRT_PGC), hdr2, sep); - tr2 = emitir(IRT(IR_BUFPUT, IRT_PGC), tr2, str); - str2 = emitir(IRT(IR_BUFSTR, IRT_STR), tr2, hdr2); - } - } - tr = hdr = recff_bufhdr(J); - if (str2) { - tr = emitir(IRT(IR_BUFPUT, IRT_PGC), tr, str); - str = str2; - rep = emitir(IRTI(IR_ADD), rep, lj_ir_kint(J, -1)); - } - tr = lj_ir_call(J, IRCALL_lj_buf_putstr_rep, tr, str, rep); - J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr); -} - -static void LJ_FASTCALL recff_string_op(jit_State *J, RecordFFData *rd) -{ - TRef str = lj_ir_tostr(J, J->base[0]); - TRef hdr = recff_bufhdr(J); - TRef tr = lj_ir_call(J, rd->data, hdr, str); - J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr); -} - -static void LJ_FASTCALL recff_string_find(jit_State *J, RecordFFData *rd) -{ - TRef trstr = lj_ir_tostr(J, J->base[0]); - TRef trpat = lj_ir_tostr(J, J->base[1]); - TRef trlen = emitir(IRTI(IR_FLOAD), trstr, IRFL_STR_LEN); - TRef tr0 = lj_ir_kint(J, 0); - TRef trstart; - GCstr *str = argv2str(J, &rd->argv[0]); - GCstr *pat = argv2str(J, &rd->argv[1]); - int32_t start; - J->needsnap = 1; - if (tref_isnil(J->base[2])) { - trstart = lj_ir_kint(J, 1); - start = 1; - } else { - trstart = lj_opt_narrow_toint(J, J->base[2]); - start = argv2int(J, &rd->argv[2]); - } - trstart = recff_string_start(J, str, &start, trstart, trlen, tr0); - if ((MSize)start <= str->len) { - emitir(IRTGI(IR_ULE), trstart, trlen); - } else { - emitir(IRTGI(IR_UGT), trstart, trlen); -#if LJ_52 - J->base[0] = TREF_NIL; - return; -#else - trstart = trlen; - start = str->len; -#endif - } - /* Fixed arg or no pattern matching chars? (Specialized to pattern string.) */ - if ((J->base[2] && tref_istruecond(J->base[3])) || - (emitir(IRTG(IR_EQ, IRT_STR), trpat, lj_ir_kstr(J, pat)), - !lj_str_haspattern(pat))) { /* Search for fixed string. */ - TRef trsptr = emitir(IRT(IR_STRREF, IRT_PGC), trstr, trstart); - TRef trpptr = emitir(IRT(IR_STRREF, IRT_PGC), trpat, tr0); - TRef trslen = emitir(IRTI(IR_SUB), trlen, trstart); - TRef trplen = emitir(IRTI(IR_FLOAD), trpat, IRFL_STR_LEN); - TRef tr = lj_ir_call(J, IRCALL_lj_str_find, trsptr, trpptr, trslen, trplen); - TRef trp0 = lj_ir_kkptr(J, NULL); - if (lj_str_find(strdata(str)+(MSize)start, strdata(pat), - str->len-(MSize)start, pat->len)) { - TRef pos; - emitir(IRTG(IR_NE, IRT_PGC), tr, trp0); - pos = emitir(IRTI(IR_SUB), tr, emitir(IRT(IR_STRREF, IRT_PGC), trstr, tr0)); - J->base[0] = emitir(IRTI(IR_ADD), pos, lj_ir_kint(J, 1)); - J->base[1] = emitir(IRTI(IR_ADD), pos, trplen); - rd->nres = 2; - } else { - emitir(IRTG(IR_EQ, IRT_PGC), tr, trp0); - J->base[0] = TREF_NIL; - } - } else { /* Search for pattern. */ - recff_nyiu(J, rd); - return; - } -} - -static void LJ_FASTCALL recff_string_format(jit_State *J, RecordFFData *rd) -{ - TRef trfmt = lj_ir_tostr(J, J->base[0]); - GCstr *fmt = argv2str(J, &rd->argv[0]); - int arg = 1; - TRef hdr, tr; - FormatState fs; - SFormat sf; - /* Specialize to the format string. */ - emitir(IRTG(IR_EQ, IRT_STR), trfmt, lj_ir_kstr(J, fmt)); - tr = hdr = recff_bufhdr(J); - lj_strfmt_init(&fs, strdata(fmt), fmt->len); - while ((sf = lj_strfmt_parse(&fs)) != STRFMT_EOF) { /* Parse format. */ - TRef tra = sf == STRFMT_LIT ? 0 : J->base[arg++]; - TRef trsf = lj_ir_kint(J, (int32_t)sf); - IRCallID id; - switch (STRFMT_TYPE(sf)) { - case STRFMT_LIT: - tr = emitir(IRT(IR_BUFPUT, IRT_PGC), tr, - lj_ir_kstr(J, lj_str_new(J->L, fs.str, fs.len))); - break; - case STRFMT_INT: - id = IRCALL_lj_strfmt_putfnum_int; - handle_int: - if (!tref_isinteger(tra)) - goto handle_num; - if (sf == STRFMT_INT) { /* Shortcut for plain %d. */ - tr = emitir(IRT(IR_BUFPUT, IRT_PGC), tr, - emitir(IRT(IR_TOSTR, IRT_STR), tra, IRTOSTR_INT)); - } else { -#if LJ_HASFFI - tra = emitir(IRT(IR_CONV, IRT_U64), tra, - (IRT_INT|(IRT_U64<<5)|IRCONV_SEXT)); - tr = lj_ir_call(J, IRCALL_lj_strfmt_putfxint, tr, trsf, tra); - lj_needsplit(J); -#else - recff_nyiu(J, rd); /* Don't bother working around this NYI. */ - return; -#endif - } - break; - case STRFMT_UINT: - id = IRCALL_lj_strfmt_putfnum_uint; - goto handle_int; - case STRFMT_NUM: - id = IRCALL_lj_strfmt_putfnum; - handle_num: - tra = lj_ir_tonum(J, tra); - tr = lj_ir_call(J, id, tr, trsf, tra); - if (LJ_SOFTFP32) lj_needsplit(J); - break; - case STRFMT_STR: - if (!tref_isstr(tra)) { - recff_nyiu(J, rd); /* NYI: __tostring and non-string types for %s. */ - return; - } - if (sf == STRFMT_STR) /* Shortcut for plain %s. */ - tr = emitir(IRT(IR_BUFPUT, IRT_PGC), tr, tra); - else if ((sf & STRFMT_T_QUOTED)) - tr = lj_ir_call(J, IRCALL_lj_strfmt_putquoted, tr, tra); - else - tr = lj_ir_call(J, IRCALL_lj_strfmt_putfstr, tr, trsf, tra); - break; - case STRFMT_CHAR: - tra = lj_opt_narrow_toint(J, tra); - if (sf == STRFMT_CHAR) /* Shortcut for plain %c. */ - tr = emitir(IRT(IR_BUFPUT, IRT_PGC), tr, - emitir(IRT(IR_TOSTR, IRT_STR), tra, IRTOSTR_CHAR)); - else - tr = lj_ir_call(J, IRCALL_lj_strfmt_putfchar, tr, trsf, tra); - break; - case STRFMT_PTR: /* NYI */ - case STRFMT_ERR: - default: - recff_nyiu(J, rd); - return; - } - } - J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr); -} - -/* -- Table library fast functions ---------------------------------------- */ - -static void LJ_FASTCALL recff_table_insert(jit_State *J, RecordFFData *rd) -{ - RecordIndex ix; - ix.tab = J->base[0]; - ix.val = J->base[1]; - rd->nres = 0; - if (tref_istab(ix.tab) && ix.val) { - if (!J->base[2]) { /* Simple push: t[#t+1] = v */ - TRef trlen = lj_ir_call(J, IRCALL_lj_tab_len, ix.tab); - GCtab *t = tabV(&rd->argv[0]); - ix.key = emitir(IRTI(IR_ADD), trlen, lj_ir_kint(J, 1)); - settabV(J->L, &ix.tabv, t); - setintV(&ix.keyv, lj_tab_len(t) + 1); - ix.idxchain = 0; - lj_record_idx(J, &ix); /* Set new value. */ - } else { /* Complex case: insert in the middle. */ - recff_nyiu(J, rd); - return; - } - } /* else: Interpreter will throw. */ -} - -static void LJ_FASTCALL recff_table_concat(jit_State *J, RecordFFData *rd) -{ - TRef tab = J->base[0]; - if (tref_istab(tab)) { - TRef sep = !tref_isnil(J->base[1]) ? - lj_ir_tostr(J, J->base[1]) : lj_ir_knull(J, IRT_STR); - TRef tri = (J->base[1] && !tref_isnil(J->base[2])) ? - lj_opt_narrow_toint(J, J->base[2]) : lj_ir_kint(J, 1); - TRef tre = (J->base[1] && J->base[2] && !tref_isnil(J->base[3])) ? - lj_opt_narrow_toint(J, J->base[3]) : - lj_ir_call(J, IRCALL_lj_tab_len, tab); - TRef hdr = recff_bufhdr(J); - TRef tr = lj_ir_call(J, IRCALL_lj_buf_puttab, hdr, tab, sep, tri, tre); - emitir(IRTG(IR_NE, IRT_PTR), tr, lj_ir_kptr(J, NULL)); - J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr); - } /* else: Interpreter will throw. */ - UNUSED(rd); -} - -static void LJ_FASTCALL recff_table_new(jit_State *J, RecordFFData *rd) -{ - TRef tra = lj_opt_narrow_toint(J, J->base[0]); - TRef trh = lj_opt_narrow_toint(J, J->base[1]); - J->base[0] = lj_ir_call(J, IRCALL_lj_tab_new_ah, tra, trh); - UNUSED(rd); -} - -static void LJ_FASTCALL recff_table_clear(jit_State *J, RecordFFData *rd) -{ - TRef tr = J->base[0]; - if (tref_istab(tr)) { - rd->nres = 0; - lj_ir_call(J, IRCALL_lj_tab_clear, tr); - J->needsnap = 1; - } /* else: Interpreter will throw. */ -} - -/* -- I/O library fast functions ------------------------------------------ */ - -/* Get FILE* for I/O function. Any I/O error aborts recording, so there's -** no need to encode the alternate cases for any of the guards. -*/ -static TRef recff_io_fp(jit_State *J, TRef *udp, int32_t id) -{ - TRef tr, ud, fp; - if (id) { /* io.func() */ -#if LJ_GC64 - /* TODO: fix ARM32 asm_fload(), so we can use this for all archs. */ - ud = lj_ir_ggfload(J, IRT_UDATA, GG_OFS(g.gcroot[id])); -#else - tr = lj_ir_kptr(J, &J2G(J)->gcroot[id]); - ud = emitir(IRT(IR_XLOAD, IRT_UDATA), tr, 0); -#endif - } else { /* fp:method() */ - ud = J->base[0]; - if (!tref_isudata(ud)) - lj_trace_err(J, LJ_TRERR_BADTYPE); - tr = emitir(IRT(IR_FLOAD, IRT_U8), ud, IRFL_UDATA_UDTYPE); - emitir(IRTGI(IR_EQ), tr, lj_ir_kint(J, UDTYPE_IO_FILE)); - } - *udp = ud; - fp = emitir(IRT(IR_FLOAD, IRT_PTR), ud, IRFL_UDATA_FILE); - emitir(IRTG(IR_NE, IRT_PTR), fp, lj_ir_knull(J, IRT_PTR)); - return fp; -} - -static void LJ_FASTCALL recff_io_write(jit_State *J, RecordFFData *rd) -{ - TRef ud, fp = recff_io_fp(J, &ud, rd->data); - TRef zero = lj_ir_kint(J, 0); - TRef one = lj_ir_kint(J, 1); - ptrdiff_t i = rd->data == 0 ? 1 : 0; - for (; J->base[i]; i++) { - TRef str = lj_ir_tostr(J, J->base[i]); - TRef buf = emitir(IRT(IR_STRREF, IRT_PGC), str, zero); - TRef len = emitir(IRTI(IR_FLOAD), str, IRFL_STR_LEN); - if (tref_isk(len) && IR(tref_ref(len))->i == 1) { - IRIns *irs = IR(tref_ref(str)); - TRef tr = (irs->o == IR_TOSTR && irs->op2 == IRTOSTR_CHAR) ? - irs->op1 : - emitir(IRT(IR_XLOAD, IRT_U8), buf, IRXLOAD_READONLY); - tr = lj_ir_call(J, IRCALL_fputc, tr, fp); - if (results_wanted(J) != 0) /* Check result only if not ignored. */ - emitir(IRTGI(IR_NE), tr, lj_ir_kint(J, -1)); - } else { - TRef tr = lj_ir_call(J, IRCALL_fwrite, buf, one, len, fp); - if (results_wanted(J) != 0) /* Check result only if not ignored. */ - emitir(IRTGI(IR_EQ), tr, len); - } - } - J->base[0] = LJ_52 ? ud : TREF_TRUE; -} - -static void LJ_FASTCALL recff_io_flush(jit_State *J, RecordFFData *rd) -{ - TRef ud, fp = recff_io_fp(J, &ud, rd->data); - TRef tr = lj_ir_call(J, IRCALL_fflush, fp); - if (results_wanted(J) != 0) /* Check result only if not ignored. */ - emitir(IRTGI(IR_EQ), tr, lj_ir_kint(J, 0)); - J->base[0] = TREF_TRUE; -} - -/* -- Debug library fast functions ---------------------------------------- */ - -static void LJ_FASTCALL recff_debug_getmetatable(jit_State *J, RecordFFData *rd) -{ - GCtab *mt; - TRef mtref; - TRef tr = J->base[0]; - if (tref_istab(tr)) { - mt = tabref(tabV(&rd->argv[0])->metatable); - mtref = emitir(IRT(IR_FLOAD, IRT_TAB), tr, IRFL_TAB_META); - } else if (tref_isudata(tr)) { - mt = tabref(udataV(&rd->argv[0])->metatable); - mtref = emitir(IRT(IR_FLOAD, IRT_TAB), tr, IRFL_UDATA_META); - } else { - mt = tabref(basemt_obj(J2G(J), &rd->argv[0])); - J->base[0] = mt ? lj_ir_ktab(J, mt) : TREF_NIL; - return; - } - emitir(IRTG(mt ? IR_NE : IR_EQ, IRT_TAB), mtref, lj_ir_knull(J, IRT_TAB)); - J->base[0] = mt ? mtref : TREF_NIL; -} - -/* -- Record calls to fast functions -------------------------------------- */ - -#include "lj_recdef.h" - -static uint32_t recdef_lookup(GCfunc *fn) -{ - if (fn->c.ffid < sizeof(recff_idmap)/sizeof(recff_idmap[0])) - return recff_idmap[fn->c.ffid]; - else - return 0; -} - -/* Record entry to a fast function or C function. */ -void lj_ffrecord_func(jit_State *J) -{ - RecordFFData rd; - uint32_t m = recdef_lookup(J->fn); - rd.data = m & 0xff; - rd.nres = 1; /* Default is one result. */ - rd.argv = J->L->base; - J->base[J->maxslot] = 0; /* Mark end of arguments. */ - (recff_func[m >> 8])(J, &rd); /* Call recff_* handler. */ - if (rd.nres >= 0) { - if (J->postproc == LJ_POST_NONE) J->postproc = LJ_POST_FFRETRY; - lj_record_ret(J, 0, rd.nres); - } -} - -#undef IR -#undef emitir - -#endif diff --git a/lib/LuaJIT/src/lj_ffrecord.h b/lib/LuaJIT/src/lj_ffrecord.h deleted file mode 100644 index 3b40745..0000000 --- a/lib/LuaJIT/src/lj_ffrecord.h +++ /dev/null @@ -1,24 +0,0 @@ -/* -** Fast function call recorder. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_FFRECORD_H -#define _LJ_FFRECORD_H - -#include "lj_obj.h" -#include "lj_jit.h" - -#if LJ_HASJIT -/* Data used by handlers to record a fast function. */ -typedef struct RecordFFData { - TValue *argv; /* Runtime argument values. */ - ptrdiff_t nres; /* Number of returned results (defaults to 1). */ - uint32_t data; /* Per-ffid auxiliary data (opcode, literal etc.). */ -} RecordFFData; - -LJ_FUNC int32_t lj_ffrecord_select_mode(jit_State *J, TRef tr, TValue *tv); -LJ_FUNC void lj_ffrecord_func(jit_State *J); -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_frame.h b/lib/LuaJIT/src/lj_frame.h deleted file mode 100644 index 04cb5a3..0000000 --- a/lib/LuaJIT/src/lj_frame.h +++ /dev/null @@ -1,297 +0,0 @@ -/* -** Stack frames. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_FRAME_H -#define _LJ_FRAME_H - -#include "lj_obj.h" -#include "lj_bc.h" - -/* -- Lua stack frame ----------------------------------------------------- */ - -/* Frame type markers in LSB of PC (4-byte aligned) or delta (8-byte aligned: -** -** PC 00 Lua frame -** delta 001 C frame -** delta 010 Continuation frame -** delta 011 Lua vararg frame -** delta 101 cpcall() frame -** delta 110 ff pcall() frame -** delta 111 ff pcall() frame with active hook -*/ -enum { - FRAME_LUA, FRAME_C, FRAME_CONT, FRAME_VARG, - FRAME_LUAP, FRAME_CP, FRAME_PCALL, FRAME_PCALLH -}; -#define FRAME_TYPE 3 -#define FRAME_P 4 -#define FRAME_TYPEP (FRAME_TYPE|FRAME_P) - -/* Macros to access and modify Lua frames. */ -#if LJ_FR2 -/* Two-slot frame info, required for 64 bit PC/GCRef: -** -** base-2 base-1 | base base+1 ... -** [func PC/delta/ft] | [slots ...] -** ^-- frame | ^-- base ^-- top -** -** Continuation frames: -** -** base-4 base-3 base-2 base-1 | base base+1 ... -** [cont PC ] [func PC/delta/ft] | [slots ...] -** ^-- frame | ^-- base ^-- top -*/ -#define frame_gc(f) (gcval((f)-1)) -#define frame_ftsz(f) ((ptrdiff_t)(f)->ftsz) -#define frame_pc(f) ((const BCIns *)frame_ftsz(f)) -#define setframe_gc(f, p, tp) (setgcVraw((f)-1, (p), (tp))) -#define setframe_ftsz(f, sz) ((f)->ftsz = (sz)) -#define setframe_pc(f, pc) ((f)->ftsz = (int64_t)(intptr_t)(pc)) -#else -/* One-slot frame info, sufficient for 32 bit PC/GCRef: -** -** base-1 | base base+1 ... -** lo hi | -** [func | PC/delta/ft] | [slots ...] -** ^-- frame | ^-- base ^-- top -** -** Continuation frames: -** -** base-2 base-1 | base base+1 ... -** lo hi lo hi | -** [cont | PC] [func | PC/delta/ft] | [slots ...] -** ^-- frame | ^-- base ^-- top -*/ -#define frame_gc(f) (gcref((f)->fr.func)) -#define frame_ftsz(f) ((ptrdiff_t)(f)->fr.tp.ftsz) -#define frame_pc(f) (mref((f)->fr.tp.pcr, const BCIns)) -#define setframe_gc(f, p, tp) (setgcref((f)->fr.func, (p)), UNUSED(tp)) -#define setframe_ftsz(f, sz) ((f)->fr.tp.ftsz = (int32_t)(sz)) -#define setframe_pc(f, pc) (setmref((f)->fr.tp.pcr, (pc))) -#endif - -#define frame_type(f) (frame_ftsz(f) & FRAME_TYPE) -#define frame_typep(f) (frame_ftsz(f) & FRAME_TYPEP) -#define frame_islua(f) (frame_type(f) == FRAME_LUA) -#define frame_isc(f) (frame_type(f) == FRAME_C) -#define frame_iscont(f) (frame_typep(f) == FRAME_CONT) -#define frame_isvarg(f) (frame_typep(f) == FRAME_VARG) -#define frame_ispcall(f) ((frame_ftsz(f) & 6) == FRAME_PCALL) - -#define frame_func(f) (&frame_gc(f)->fn) -#define frame_delta(f) (frame_ftsz(f) >> 3) -#define frame_sized(f) (frame_ftsz(f) & ~FRAME_TYPEP) - -enum { LJ_CONT_TAILCALL, LJ_CONT_FFI_CALLBACK }; /* Special continuations. */ - -#if LJ_FR2 -#define frame_contpc(f) (frame_pc((f)-2)) -#define frame_contv(f) (((f)-3)->u64) -#else -#define frame_contpc(f) (frame_pc((f)-1)) -#define frame_contv(f) (((f)-1)->u32.lo) -#endif -#if LJ_FR2 -#define frame_contf(f) ((ASMFunction)(uintptr_t)((f)-3)->u64) -#elif LJ_64 -#define frame_contf(f) \ - ((ASMFunction)(void *)((intptr_t)lj_vm_asm_begin + \ - (intptr_t)(int32_t)((f)-1)->u32.lo)) -#else -#define frame_contf(f) ((ASMFunction)gcrefp(((f)-1)->gcr, void)) -#endif -#define frame_iscont_fficb(f) \ - (LJ_HASFFI && frame_contv(f) == LJ_CONT_FFI_CALLBACK) - -#define frame_prevl(f) ((f) - (1+LJ_FR2+bc_a(frame_pc(f)[-1]))) -#define frame_prevd(f) ((TValue *)((char *)(f) - frame_sized(f))) -#define frame_prev(f) (frame_islua(f)?frame_prevl(f):frame_prevd(f)) -/* Note: this macro does not skip over FRAME_VARG. */ - -/* -- C stack frame ------------------------------------------------------- */ - -/* Macros to access and modify the C stack frame chain. */ - -/* These definitions must match with the arch-specific *.dasc files. */ -#if LJ_TARGET_X86 -#if LJ_ABI_WIN -#define CFRAME_OFS_ERRF (19*4) -#define CFRAME_OFS_NRES (18*4) -#define CFRAME_OFS_PREV (17*4) -#define CFRAME_OFS_L (16*4) -#define CFRAME_OFS_SEH (9*4) -#define CFRAME_OFS_PC (6*4) -#define CFRAME_OFS_MULTRES (5*4) -#define CFRAME_SIZE (16*4) -#define CFRAME_SHIFT_MULTRES 0 -#else -#define CFRAME_OFS_ERRF (15*4) -#define CFRAME_OFS_NRES (14*4) -#define CFRAME_OFS_PREV (13*4) -#define CFRAME_OFS_L (12*4) -#define CFRAME_OFS_PC (6*4) -#define CFRAME_OFS_MULTRES (5*4) -#define CFRAME_SIZE (12*4) -#define CFRAME_SHIFT_MULTRES 0 -#endif -#elif LJ_TARGET_X64 -#if LJ_ABI_WIN -#define CFRAME_OFS_PREV (13*8) -#if LJ_GC64 -#define CFRAME_OFS_PC (12*8) -#define CFRAME_OFS_L (11*8) -#define CFRAME_OFS_ERRF (21*4) -#define CFRAME_OFS_NRES (20*4) -#define CFRAME_OFS_MULTRES (8*4) -#else -#define CFRAME_OFS_PC (25*4) -#define CFRAME_OFS_L (24*4) -#define CFRAME_OFS_ERRF (23*4) -#define CFRAME_OFS_NRES (22*4) -#define CFRAME_OFS_MULTRES (21*4) -#endif -#define CFRAME_SIZE (10*8) -#define CFRAME_SIZE_JIT (CFRAME_SIZE + 9*16 + 4*8) -#define CFRAME_SHIFT_MULTRES 0 -#else -#define CFRAME_OFS_PREV (4*8) -#if LJ_GC64 -#define CFRAME_OFS_PC (3*8) -#define CFRAME_OFS_L (2*8) -#define CFRAME_OFS_ERRF (3*4) -#define CFRAME_OFS_NRES (2*4) -#define CFRAME_OFS_MULTRES (0*4) -#else -#define CFRAME_OFS_PC (7*4) -#define CFRAME_OFS_L (6*4) -#define CFRAME_OFS_ERRF (5*4) -#define CFRAME_OFS_NRES (4*4) -#define CFRAME_OFS_MULTRES (1*4) -#endif -#if LJ_NO_UNWIND -#define CFRAME_SIZE (12*8) -#else -#define CFRAME_SIZE (10*8) -#endif -#define CFRAME_SIZE_JIT (CFRAME_SIZE + 16) -#define CFRAME_SHIFT_MULTRES 0 -#endif -#elif LJ_TARGET_ARM -#define CFRAME_OFS_ERRF 24 -#define CFRAME_OFS_NRES 20 -#define CFRAME_OFS_PREV 16 -#define CFRAME_OFS_L 12 -#define CFRAME_OFS_PC 8 -#define CFRAME_OFS_MULTRES 4 -#if LJ_ARCH_HASFPU -#define CFRAME_SIZE 128 -#else -#define CFRAME_SIZE 64 -#endif -#define CFRAME_SHIFT_MULTRES 3 -#elif LJ_TARGET_ARM64 -#define CFRAME_OFS_ERRF 196 -#define CFRAME_OFS_NRES 200 -#define CFRAME_OFS_PREV 160 -#define CFRAME_OFS_L 176 -#define CFRAME_OFS_PC 168 -#define CFRAME_OFS_MULTRES 192 -#define CFRAME_SIZE 208 -#define CFRAME_SHIFT_MULTRES 3 -#elif LJ_TARGET_PPC -#if LJ_TARGET_XBOX360 -#define CFRAME_OFS_ERRF 424 -#define CFRAME_OFS_NRES 420 -#define CFRAME_OFS_PREV 400 -#define CFRAME_OFS_L 416 -#define CFRAME_OFS_PC 412 -#define CFRAME_OFS_MULTRES 408 -#define CFRAME_SIZE 384 -#define CFRAME_SHIFT_MULTRES 3 -#elif LJ_ARCH_PPC32ON64 -#define CFRAME_OFS_ERRF 472 -#define CFRAME_OFS_NRES 468 -#define CFRAME_OFS_PREV 448 -#define CFRAME_OFS_L 464 -#define CFRAME_OFS_PC 460 -#define CFRAME_OFS_MULTRES 456 -#define CFRAME_SIZE 400 -#define CFRAME_SHIFT_MULTRES 3 -#else -#define CFRAME_OFS_ERRF 48 -#define CFRAME_OFS_NRES 44 -#define CFRAME_OFS_PREV 40 -#define CFRAME_OFS_L 36 -#define CFRAME_OFS_PC 32 -#define CFRAME_OFS_MULTRES 28 -#define CFRAME_SIZE (LJ_ARCH_HASFPU ? 272 : 128) -#define CFRAME_SHIFT_MULTRES 3 -#endif -#elif LJ_TARGET_MIPS32 -#if LJ_ARCH_HASFPU -#define CFRAME_OFS_ERRF 124 -#define CFRAME_OFS_NRES 120 -#define CFRAME_OFS_PREV 116 -#define CFRAME_OFS_L 112 -#define CFRAME_SIZE 112 -#else -#define CFRAME_OFS_ERRF 76 -#define CFRAME_OFS_NRES 72 -#define CFRAME_OFS_PREV 68 -#define CFRAME_OFS_L 64 -#define CFRAME_SIZE 64 -#endif -#define CFRAME_OFS_PC 20 -#define CFRAME_OFS_MULTRES 16 -#define CFRAME_SHIFT_MULTRES 3 -#elif LJ_TARGET_MIPS64 -#if LJ_ARCH_HASFPU -#define CFRAME_OFS_ERRF 188 -#define CFRAME_OFS_NRES 184 -#define CFRAME_OFS_PREV 176 -#define CFRAME_OFS_L 168 -#define CFRAME_OFS_PC 160 -#define CFRAME_SIZE 192 -#else -#define CFRAME_OFS_ERRF 124 -#define CFRAME_OFS_NRES 120 -#define CFRAME_OFS_PREV 112 -#define CFRAME_OFS_L 104 -#define CFRAME_OFS_PC 96 -#define CFRAME_SIZE 128 -#endif -#define CFRAME_OFS_MULTRES 0 -#define CFRAME_SHIFT_MULTRES 3 -#else -#error "Missing CFRAME_* definitions for this architecture" -#endif - -#ifndef CFRAME_SIZE_JIT -#define CFRAME_SIZE_JIT CFRAME_SIZE -#endif - -#define CFRAME_RESUME 1 -#define CFRAME_UNWIND_FF 2 /* Only used in unwinder. */ -#define CFRAME_RAWMASK (~(intptr_t)(CFRAME_RESUME|CFRAME_UNWIND_FF)) - -#define cframe_errfunc(cf) (*(int32_t *)(((char *)(cf))+CFRAME_OFS_ERRF)) -#define cframe_nres(cf) (*(int32_t *)(((char *)(cf))+CFRAME_OFS_NRES)) -#define cframe_prev(cf) (*(void **)(((char *)(cf))+CFRAME_OFS_PREV)) -#define cframe_multres(cf) (*(uint32_t *)(((char *)(cf))+CFRAME_OFS_MULTRES)) -#define cframe_multres_n(cf) (cframe_multres((cf)) >> CFRAME_SHIFT_MULTRES) -#define cframe_L(cf) \ - (&gcref(*(GCRef *)(((char *)(cf))+CFRAME_OFS_L))->th) -#define cframe_pc(cf) \ - (mref(*(MRef *)(((char *)(cf))+CFRAME_OFS_PC), const BCIns)) -#define setcframe_L(cf, L) \ - (setmref(*(MRef *)(((char *)(cf))+CFRAME_OFS_L), (L))) -#define setcframe_pc(cf, pc) \ - (setmref(*(MRef *)(((char *)(cf))+CFRAME_OFS_PC), (pc))) -#define cframe_canyield(cf) ((intptr_t)(cf) & CFRAME_RESUME) -#define cframe_unwind_ff(cf) ((intptr_t)(cf) & CFRAME_UNWIND_FF) -#define cframe_raw(cf) ((void *)((intptr_t)(cf) & CFRAME_RAWMASK)) -#define cframe_Lpc(L) cframe_pc(cframe_raw(L->cframe)) - -#endif diff --git a/lib/LuaJIT/src/lj_func.c b/lib/LuaJIT/src/lj_func.c deleted file mode 100644 index 639dad8..0000000 --- a/lib/LuaJIT/src/lj_func.c +++ /dev/null @@ -1,187 +0,0 @@ -/* -** Function handling (prototypes, functions and upvalues). -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Portions taken verbatim or adapted from the Lua interpreter. -** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h -*/ - -#define lj_func_c -#define LUA_CORE - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_func.h" -#include "lj_trace.h" -#include "lj_vm.h" - -/* -- Prototypes ---------------------------------------------------------- */ - -void LJ_FASTCALL lj_func_freeproto(global_State *g, GCproto *pt) -{ - lj_mem_free(g, pt, pt->sizept); -} - -/* -- Upvalues ------------------------------------------------------------ */ - -static void unlinkuv(GCupval *uv) -{ - lua_assert(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv); - setgcrefr(uvnext(uv)->prev, uv->prev); - setgcrefr(uvprev(uv)->next, uv->next); -} - -/* Find existing open upvalue for a stack slot or create a new one. */ -static GCupval *func_finduv(lua_State *L, TValue *slot) -{ - global_State *g = G(L); - GCRef *pp = &L->openupval; - GCupval *p; - GCupval *uv; - /* Search the sorted list of open upvalues. */ - while (gcref(*pp) != NULL && uvval((p = gco2uv(gcref(*pp)))) >= slot) { - lua_assert(!p->closed && uvval(p) != &p->tv); - if (uvval(p) == slot) { /* Found open upvalue pointing to same slot? */ - if (isdead(g, obj2gco(p))) /* Resurrect it, if it's dead. */ - flipwhite(obj2gco(p)); - return p; - } - pp = &p->nextgc; - } - /* No matching upvalue found. Create a new one. */ - uv = lj_mem_newt(L, sizeof(GCupval), GCupval); - newwhite(g, uv); - uv->gct = ~LJ_TUPVAL; - uv->closed = 0; /* Still open. */ - setmref(uv->v, slot); /* Pointing to the stack slot. */ - /* NOBARRIER: The GCupval is new (marked white) and open. */ - setgcrefr(uv->nextgc, *pp); /* Insert into sorted list of open upvalues. */ - setgcref(*pp, obj2gco(uv)); - setgcref(uv->prev, obj2gco(&g->uvhead)); /* Insert into GC list, too. */ - setgcrefr(uv->next, g->uvhead.next); - setgcref(uvnext(uv)->prev, obj2gco(uv)); - setgcref(g->uvhead.next, obj2gco(uv)); - lua_assert(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv); - return uv; -} - -/* Create an empty and closed upvalue. */ -static GCupval *func_emptyuv(lua_State *L) -{ - GCupval *uv = (GCupval *)lj_mem_newgco(L, sizeof(GCupval)); - uv->gct = ~LJ_TUPVAL; - uv->closed = 1; - setnilV(&uv->tv); - setmref(uv->v, &uv->tv); - return uv; -} - -/* Close all open upvalues pointing to some stack level or above. */ -void LJ_FASTCALL lj_func_closeuv(lua_State *L, TValue *level) -{ - GCupval *uv; - global_State *g = G(L); - while (gcref(L->openupval) != NULL && - uvval((uv = gco2uv(gcref(L->openupval)))) >= level) { - GCobj *o = obj2gco(uv); - lua_assert(!isblack(o) && !uv->closed && uvval(uv) != &uv->tv); - setgcrefr(L->openupval, uv->nextgc); /* No longer in open list. */ - if (isdead(g, o)) { - lj_func_freeuv(g, uv); - } else { - unlinkuv(uv); - lj_gc_closeuv(g, uv); - } - } -} - -void LJ_FASTCALL lj_func_freeuv(global_State *g, GCupval *uv) -{ - if (!uv->closed) - unlinkuv(uv); - lj_mem_freet(g, uv); -} - -/* -- Functions (closures) ------------------------------------------------ */ - -GCfunc *lj_func_newC(lua_State *L, MSize nelems, GCtab *env) -{ - GCfunc *fn = (GCfunc *)lj_mem_newgco(L, sizeCfunc(nelems)); - fn->c.gct = ~LJ_TFUNC; - fn->c.ffid = FF_C; - fn->c.nupvalues = (uint8_t)nelems; - /* NOBARRIER: The GCfunc is new (marked white). */ - setmref(fn->c.pc, &G(L)->bc_cfunc_ext); - setgcref(fn->c.env, obj2gco(env)); - return fn; -} - -static GCfunc *func_newL(lua_State *L, GCproto *pt, GCtab *env) -{ - uint32_t count; - GCfunc *fn = (GCfunc *)lj_mem_newgco(L, sizeLfunc((MSize)pt->sizeuv)); - fn->l.gct = ~LJ_TFUNC; - fn->l.ffid = FF_LUA; - fn->l.nupvalues = 0; /* Set to zero until upvalues are initialized. */ - /* NOBARRIER: Really a setgcref. But the GCfunc is new (marked white). */ - setmref(fn->l.pc, proto_bc(pt)); - setgcref(fn->l.env, obj2gco(env)); - /* Saturating 3 bit counter (0..7) for created closures. */ - count = (uint32_t)pt->flags + PROTO_CLCOUNT; - pt->flags = (uint8_t)(count - ((count >> PROTO_CLC_BITS) & PROTO_CLCOUNT)); - return fn; -} - -/* Create a new Lua function with empty upvalues. */ -GCfunc *lj_func_newL_empty(lua_State *L, GCproto *pt, GCtab *env) -{ - GCfunc *fn = func_newL(L, pt, env); - MSize i, nuv = pt->sizeuv; - /* NOBARRIER: The GCfunc is new (marked white). */ - for (i = 0; i < nuv; i++) { - GCupval *uv = func_emptyuv(L); - int32_t v = proto_uv(pt)[i]; - uv->immutable = ((v / PROTO_UV_IMMUTABLE) & 1); - uv->dhash = (uint32_t)(uintptr_t)pt ^ (v << 24); - setgcref(fn->l.uvptr[i], obj2gco(uv)); - } - fn->l.nupvalues = (uint8_t)nuv; - return fn; -} - -/* Do a GC check and create a new Lua function with inherited upvalues. */ -GCfunc *lj_func_newL_gc(lua_State *L, GCproto *pt, GCfuncL *parent) -{ - GCfunc *fn; - GCRef *puv; - MSize i, nuv; - TValue *base; - lj_gc_check_fixtop(L); - fn = func_newL(L, pt, tabref(parent->env)); - /* NOBARRIER: The GCfunc is new (marked white). */ - puv = parent->uvptr; - nuv = pt->sizeuv; - base = L->base; - for (i = 0; i < nuv; i++) { - uint32_t v = proto_uv(pt)[i]; - GCupval *uv; - if ((v & PROTO_UV_LOCAL)) { - uv = func_finduv(L, base + (v & 0xff)); - uv->immutable = ((v / PROTO_UV_IMMUTABLE) & 1); - uv->dhash = (uint32_t)(uintptr_t)mref(parent->pc, char) ^ (v << 24); - } else { - uv = &gcref(puv[v])->uv; - } - setgcref(fn->l.uvptr[i], obj2gco(uv)); - } - fn->l.nupvalues = (uint8_t)nuv; - return fn; -} - -void LJ_FASTCALL lj_func_free(global_State *g, GCfunc *fn) -{ - MSize size = isluafunc(fn) ? sizeLfunc((MSize)fn->l.nupvalues) : - sizeCfunc((MSize)fn->c.nupvalues); - lj_mem_free(g, fn, size); -} - diff --git a/lib/LuaJIT/src/lj_func.h b/lib/LuaJIT/src/lj_func.h deleted file mode 100644 index 901751b..0000000 --- a/lib/LuaJIT/src/lj_func.h +++ /dev/null @@ -1,24 +0,0 @@ -/* -** Function handling (prototypes, functions and upvalues). -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_FUNC_H -#define _LJ_FUNC_H - -#include "lj_obj.h" - -/* Prototypes. */ -LJ_FUNC void LJ_FASTCALL lj_func_freeproto(global_State *g, GCproto *pt); - -/* Upvalues. */ -LJ_FUNCA void LJ_FASTCALL lj_func_closeuv(lua_State *L, TValue *level); -LJ_FUNC void LJ_FASTCALL lj_func_freeuv(global_State *g, GCupval *uv); - -/* Functions (closures). */ -LJ_FUNC GCfunc *lj_func_newC(lua_State *L, MSize nelems, GCtab *env); -LJ_FUNC GCfunc *lj_func_newL_empty(lua_State *L, GCproto *pt, GCtab *env); -LJ_FUNCA GCfunc *lj_func_newL_gc(lua_State *L, GCproto *pt, GCfuncL *parent); -LJ_FUNC void LJ_FASTCALL lj_func_free(global_State *g, GCfunc *c); - -#endif diff --git a/lib/LuaJIT/src/lj_gc.c b/lib/LuaJIT/src/lj_gc.c deleted file mode 100644 index 2aaf5b2..0000000 --- a/lib/LuaJIT/src/lj_gc.c +++ /dev/null @@ -1,854 +0,0 @@ -/* -** Garbage collector. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Major portions taken verbatim or adapted from the Lua interpreter. -** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h -*/ - -#define lj_gc_c -#define LUA_CORE - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_buf.h" -#include "lj_str.h" -#include "lj_tab.h" -#include "lj_func.h" -#include "lj_udata.h" -#include "lj_meta.h" -#include "lj_state.h" -#include "lj_frame.h" -#if LJ_HASFFI -#include "lj_ctype.h" -#include "lj_cdata.h" -#endif -#include "lj_trace.h" -#include "lj_vm.h" - -#define GCSTEPSIZE 1024u -#define GCSWEEPMAX 40 -#define GCSWEEPCOST 10 -#define GCFINALIZECOST 100 - -/* Macros to set GCobj colors and flags. */ -#define white2gray(x) ((x)->gch.marked &= (uint8_t)~LJ_GC_WHITES) -#define gray2black(x) ((x)->gch.marked |= LJ_GC_BLACK) -#define isfinalized(u) ((u)->marked & LJ_GC_FINALIZED) - -/* -- Mark phase ---------------------------------------------------------- */ - -/* Mark a TValue (if needed). */ -#define gc_marktv(g, tv) \ - { lua_assert(!tvisgcv(tv) || (~itype(tv) == gcval(tv)->gch.gct)); \ - if (tviswhite(tv)) gc_mark(g, gcV(tv)); } - -/* Mark a GCobj (if needed). */ -#define gc_markobj(g, o) \ - { if (iswhite(obj2gco(o))) gc_mark(g, obj2gco(o)); } - -/* Mark a string object. */ -#define gc_mark_str(s) ((s)->marked &= (uint8_t)~LJ_GC_WHITES) - -/* Mark a white GCobj. */ -static void gc_mark(global_State *g, GCobj *o) -{ - int gct = o->gch.gct; - lua_assert(iswhite(o) && !isdead(g, o)); - white2gray(o); - if (LJ_UNLIKELY(gct == ~LJ_TUDATA)) { - GCtab *mt = tabref(gco2ud(o)->metatable); - gray2black(o); /* Userdata are never gray. */ - if (mt) gc_markobj(g, mt); - gc_markobj(g, tabref(gco2ud(o)->env)); - } else if (LJ_UNLIKELY(gct == ~LJ_TUPVAL)) { - GCupval *uv = gco2uv(o); - gc_marktv(g, uvval(uv)); - if (uv->closed) - gray2black(o); /* Closed upvalues are never gray. */ - } else if (gct != ~LJ_TSTR && gct != ~LJ_TCDATA) { - lua_assert(gct == ~LJ_TFUNC || gct == ~LJ_TTAB || - gct == ~LJ_TTHREAD || gct == ~LJ_TPROTO || gct == ~LJ_TTRACE); - setgcrefr(o->gch.gclist, g->gc.gray); - setgcref(g->gc.gray, o); - } -} - -/* Mark GC roots. */ -static void gc_mark_gcroot(global_State *g) -{ - ptrdiff_t i; - for (i = 0; i < GCROOT_MAX; i++) - if (gcref(g->gcroot[i]) != NULL) - gc_markobj(g, gcref(g->gcroot[i])); -} - -/* Start a GC cycle and mark the root set. */ -static void gc_mark_start(global_State *g) -{ - setgcrefnull(g->gc.gray); - setgcrefnull(g->gc.grayagain); - setgcrefnull(g->gc.weak); - gc_markobj(g, mainthread(g)); - gc_markobj(g, tabref(mainthread(g)->env)); - gc_marktv(g, &g->registrytv); - gc_mark_gcroot(g); - g->gc.state = GCSpropagate; -} - -/* Mark open upvalues. */ -static void gc_mark_uv(global_State *g) -{ - GCupval *uv; - for (uv = uvnext(&g->uvhead); uv != &g->uvhead; uv = uvnext(uv)) { - lua_assert(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv); - if (isgray(obj2gco(uv))) - gc_marktv(g, uvval(uv)); - } -} - -/* Mark userdata in mmudata list. */ -static void gc_mark_mmudata(global_State *g) -{ - GCobj *root = gcref(g->gc.mmudata); - GCobj *u = root; - if (u) { - do { - u = gcnext(u); - makewhite(g, u); /* Could be from previous GC. */ - gc_mark(g, u); - } while (u != root); - } -} - -/* Separate userdata objects to be finalized to mmudata list. */ -size_t lj_gc_separateudata(global_State *g, int all) -{ - size_t m = 0; - GCRef *p = &mainthread(g)->nextgc; - GCobj *o; - while ((o = gcref(*p)) != NULL) { - if (!(iswhite(o) || all) || isfinalized(gco2ud(o))) { - p = &o->gch.nextgc; /* Nothing to do. */ - } else if (!lj_meta_fastg(g, tabref(gco2ud(o)->metatable), MM_gc)) { - markfinalized(o); /* Done, as there's no __gc metamethod. */ - p = &o->gch.nextgc; - } else { /* Otherwise move userdata to be finalized to mmudata list. */ - m += sizeudata(gco2ud(o)); - markfinalized(o); - *p = o->gch.nextgc; - if (gcref(g->gc.mmudata)) { /* Link to end of mmudata list. */ - GCobj *root = gcref(g->gc.mmudata); - setgcrefr(o->gch.nextgc, root->gch.nextgc); - setgcref(root->gch.nextgc, o); - setgcref(g->gc.mmudata, o); - } else { /* Create circular list. */ - setgcref(o->gch.nextgc, o); - setgcref(g->gc.mmudata, o); - } - } - } - return m; -} - -/* -- Propagation phase --------------------------------------------------- */ - -/* Traverse a table. */ -static int gc_traverse_tab(global_State *g, GCtab *t) -{ - int weak = 0; - cTValue *mode; - GCtab *mt = tabref(t->metatable); - if (mt) - gc_markobj(g, mt); - mode = lj_meta_fastg(g, mt, MM_mode); - if (mode && tvisstr(mode)) { /* Valid __mode field? */ - const char *modestr = strVdata(mode); - int c; - while ((c = *modestr++)) { - if (c == 'k') weak |= LJ_GC_WEAKKEY; - else if (c == 'v') weak |= LJ_GC_WEAKVAL; - } - if (weak) { /* Weak tables are cleared in the atomic phase. */ -#if LJ_HASFFI - CTState *cts = ctype_ctsG(g); - if (cts && cts->finalizer == t) { - weak = (int)(~0u & ~LJ_GC_WEAKVAL); - } else -#endif - { - t->marked = (uint8_t)((t->marked & ~LJ_GC_WEAK) | weak); - setgcrefr(t->gclist, g->gc.weak); - setgcref(g->gc.weak, obj2gco(t)); - } - } - } - if (weak == LJ_GC_WEAK) /* Nothing to mark if both keys/values are weak. */ - return 1; - if (!(weak & LJ_GC_WEAKVAL)) { /* Mark array part. */ - MSize i, asize = t->asize; - for (i = 0; i < asize; i++) - gc_marktv(g, arrayslot(t, i)); - } - if (t->hmask > 0) { /* Mark hash part. */ - Node *node = noderef(t->node); - MSize i, hmask = t->hmask; - for (i = 0; i <= hmask; i++) { - Node *n = &node[i]; - if (!tvisnil(&n->val)) { /* Mark non-empty slot. */ - lua_assert(!tvisnil(&n->key)); - if (!(weak & LJ_GC_WEAKKEY)) gc_marktv(g, &n->key); - if (!(weak & LJ_GC_WEAKVAL)) gc_marktv(g, &n->val); - } - } - } - return weak; -} - -/* Traverse a function. */ -static void gc_traverse_func(global_State *g, GCfunc *fn) -{ - gc_markobj(g, tabref(fn->c.env)); - if (isluafunc(fn)) { - uint32_t i; - lua_assert(fn->l.nupvalues <= funcproto(fn)->sizeuv); - gc_markobj(g, funcproto(fn)); - for (i = 0; i < fn->l.nupvalues; i++) /* Mark Lua function upvalues. */ - gc_markobj(g, &gcref(fn->l.uvptr[i])->uv); - } else { - uint32_t i; - for (i = 0; i < fn->c.nupvalues; i++) /* Mark C function upvalues. */ - gc_marktv(g, &fn->c.upvalue[i]); - } -} - -#if LJ_HASJIT -/* Mark a trace. */ -static void gc_marktrace(global_State *g, TraceNo traceno) -{ - GCobj *o = obj2gco(traceref(G2J(g), traceno)); - lua_assert(traceno != G2J(g)->cur.traceno); - if (iswhite(o)) { - white2gray(o); - setgcrefr(o->gch.gclist, g->gc.gray); - setgcref(g->gc.gray, o); - } -} - -/* Traverse a trace. */ -static void gc_traverse_trace(global_State *g, GCtrace *T) -{ - IRRef ref; - if (T->traceno == 0) return; - for (ref = T->nk; ref < REF_TRUE; ref++) { - IRIns *ir = &T->ir[ref]; - if (ir->o == IR_KGC) - gc_markobj(g, ir_kgc(ir)); - if (irt_is64(ir->t) && ir->o != IR_KNULL) - ref++; - } - if (T->link) gc_marktrace(g, T->link); - if (T->nextroot) gc_marktrace(g, T->nextroot); - if (T->nextside) gc_marktrace(g, T->nextside); - gc_markobj(g, gcref(T->startpt)); -} - -/* The current trace is a GC root while not anchored in the prototype (yet). */ -#define gc_traverse_curtrace(g) gc_traverse_trace(g, &G2J(g)->cur) -#else -#define gc_traverse_curtrace(g) UNUSED(g) -#endif - -/* Traverse a prototype. */ -static void gc_traverse_proto(global_State *g, GCproto *pt) -{ - ptrdiff_t i; - gc_mark_str(proto_chunkname(pt)); - for (i = -(ptrdiff_t)pt->sizekgc; i < 0; i++) /* Mark collectable consts. */ - gc_markobj(g, proto_kgc(pt, i)); -#if LJ_HASJIT - if (pt->trace) gc_marktrace(g, pt->trace); -#endif -} - -/* Traverse the frame structure of a stack. */ -static MSize gc_traverse_frames(global_State *g, lua_State *th) -{ - TValue *frame, *top = th->top-1, *bot = tvref(th->stack); - /* Note: extra vararg frame not skipped, marks function twice (harmless). */ - for (frame = th->base-1; frame > bot+LJ_FR2; frame = frame_prev(frame)) { - GCfunc *fn = frame_func(frame); - TValue *ftop = frame; - if (isluafunc(fn)) ftop += funcproto(fn)->framesize; - if (ftop > top) top = ftop; - if (!LJ_FR2) gc_markobj(g, fn); /* Need to mark hidden function (or L). */ - } - top++; /* Correct bias of -1 (frame == base-1). */ - if (top > tvref(th->maxstack)) top = tvref(th->maxstack); - return (MSize)(top - bot); /* Return minimum needed stack size. */ -} - -/* Traverse a thread object. */ -static void gc_traverse_thread(global_State *g, lua_State *th) -{ - TValue *o, *top = th->top; - for (o = tvref(th->stack)+1+LJ_FR2; o < top; o++) - gc_marktv(g, o); - if (g->gc.state == GCSatomic) { - top = tvref(th->stack) + th->stacksize; - for (; o < top; o++) /* Clear unmarked slots. */ - setnilV(o); - } - gc_markobj(g, tabref(th->env)); - lj_state_shrinkstack(th, gc_traverse_frames(g, th)); -} - -/* Propagate one gray object. Traverse it and turn it black. */ -static size_t propagatemark(global_State *g) -{ - GCobj *o = gcref(g->gc.gray); - int gct = o->gch.gct; - lua_assert(isgray(o)); - gray2black(o); - setgcrefr(g->gc.gray, o->gch.gclist); /* Remove from gray list. */ - if (LJ_LIKELY(gct == ~LJ_TTAB)) { - GCtab *t = gco2tab(o); - if (gc_traverse_tab(g, t) > 0) - black2gray(o); /* Keep weak tables gray. */ - return sizeof(GCtab) + sizeof(TValue) * t->asize + - (t->hmask ? sizeof(Node) * (t->hmask + 1) : 0); - } else if (LJ_LIKELY(gct == ~LJ_TFUNC)) { - GCfunc *fn = gco2func(o); - gc_traverse_func(g, fn); - return isluafunc(fn) ? sizeLfunc((MSize)fn->l.nupvalues) : - sizeCfunc((MSize)fn->c.nupvalues); - } else if (LJ_LIKELY(gct == ~LJ_TPROTO)) { - GCproto *pt = gco2pt(o); - gc_traverse_proto(g, pt); - return pt->sizept; - } else if (LJ_LIKELY(gct == ~LJ_TTHREAD)) { - lua_State *th = gco2th(o); - setgcrefr(th->gclist, g->gc.grayagain); - setgcref(g->gc.grayagain, o); - black2gray(o); /* Threads are never black. */ - gc_traverse_thread(g, th); - return sizeof(lua_State) + sizeof(TValue) * th->stacksize; - } else { -#if LJ_HASJIT - GCtrace *T = gco2trace(o); - gc_traverse_trace(g, T); - return ((sizeof(GCtrace)+7)&~7) + (T->nins-T->nk)*sizeof(IRIns) + - T->nsnap*sizeof(SnapShot) + T->nsnapmap*sizeof(SnapEntry); -#else - lua_assert(0); - return 0; -#endif - } -} - -/* Propagate all gray objects. */ -static size_t gc_propagate_gray(global_State *g) -{ - size_t m = 0; - while (gcref(g->gc.gray) != NULL) - m += propagatemark(g); - return m; -} - -/* -- Sweep phase --------------------------------------------------------- */ - -/* Type of GC free functions. */ -typedef void (LJ_FASTCALL *GCFreeFunc)(global_State *g, GCobj *o); - -/* GC free functions for LJ_TSTR .. LJ_TUDATA. ORDER LJ_T */ -static const GCFreeFunc gc_freefunc[] = { - (GCFreeFunc)lj_str_free, - (GCFreeFunc)lj_func_freeuv, - (GCFreeFunc)lj_state_free, - (GCFreeFunc)lj_func_freeproto, - (GCFreeFunc)lj_func_free, -#if LJ_HASJIT - (GCFreeFunc)lj_trace_free, -#else - (GCFreeFunc)0, -#endif -#if LJ_HASFFI - (GCFreeFunc)lj_cdata_free, -#else - (GCFreeFunc)0, -#endif - (GCFreeFunc)lj_tab_free, - (GCFreeFunc)lj_udata_free -}; - -/* Full sweep of a GC list. */ -#define gc_fullsweep(g, p) gc_sweep(g, (p), ~(uint32_t)0) - -/* Partial sweep of a GC list. */ -static GCRef *gc_sweep(global_State *g, GCRef *p, uint32_t lim) -{ - /* Mask with other white and LJ_GC_FIXED. Or LJ_GC_SFIXED on shutdown. */ - int ow = otherwhite(g); - GCobj *o; - while ((o = gcref(*p)) != NULL && lim-- > 0) { - if (o->gch.gct == ~LJ_TTHREAD) /* Need to sweep open upvalues, too. */ - gc_fullsweep(g, &gco2th(o)->openupval); - if (((o->gch.marked ^ LJ_GC_WHITES) & ow)) { /* Black or current white? */ - lua_assert(!isdead(g, o) || (o->gch.marked & LJ_GC_FIXED)); - makewhite(g, o); /* Value is alive, change to the current white. */ - p = &o->gch.nextgc; - } else { /* Otherwise value is dead, free it. */ - lua_assert(isdead(g, o) || ow == LJ_GC_SFIXED); - setgcrefr(*p, o->gch.nextgc); - if (o == gcref(g->gc.root)) - setgcrefr(g->gc.root, o->gch.nextgc); /* Adjust list anchor. */ - gc_freefunc[o->gch.gct - ~LJ_TSTR](g, o); - } - } - return p; -} - -/* Check whether we can clear a key or a value slot from a table. */ -static int gc_mayclear(cTValue *o, int val) -{ - if (tvisgcv(o)) { /* Only collectable objects can be weak references. */ - if (tvisstr(o)) { /* But strings cannot be used as weak references. */ - gc_mark_str(strV(o)); /* And need to be marked. */ - return 0; - } - if (iswhite(gcV(o))) - return 1; /* Object is about to be collected. */ - if (tvisudata(o) && val && isfinalized(udataV(o))) - return 1; /* Finalized userdata is dropped only from values. */ - } - return 0; /* Cannot clear. */ -} - -/* Clear collected entries from weak tables. */ -static void gc_clearweak(GCobj *o) -{ - while (o) { - GCtab *t = gco2tab(o); - lua_assert((t->marked & LJ_GC_WEAK)); - if ((t->marked & LJ_GC_WEAKVAL)) { - MSize i, asize = t->asize; - for (i = 0; i < asize; i++) { - /* Clear array slot when value is about to be collected. */ - TValue *tv = arrayslot(t, i); - if (gc_mayclear(tv, 1)) - setnilV(tv); - } - } - if (t->hmask > 0) { - Node *node = noderef(t->node); - MSize i, hmask = t->hmask; - for (i = 0; i <= hmask; i++) { - Node *n = &node[i]; - /* Clear hash slot when key or value is about to be collected. */ - if (!tvisnil(&n->val) && (gc_mayclear(&n->key, 0) || - gc_mayclear(&n->val, 1))) - setnilV(&n->val); - } - } - o = gcref(t->gclist); - } -} - -/* Call a userdata or cdata finalizer. */ -static void gc_call_finalizer(global_State *g, lua_State *L, - cTValue *mo, GCobj *o) -{ - /* Save and restore lots of state around the __gc callback. */ - uint8_t oldh = hook_save(g); - GCSize oldt = g->gc.threshold; - int errcode; - TValue *top; - lj_trace_abort(g); - hook_entergc(g); /* Disable hooks and new traces during __gc. */ - g->gc.threshold = LJ_MAX_MEM; /* Prevent GC steps. */ - top = L->top; - copyTV(L, top++, mo); - if (LJ_FR2) setnilV(top++); - setgcV(L, top, o, ~o->gch.gct); - L->top = top+1; - errcode = lj_vm_pcall(L, top, 1+0, -1); /* Stack: |mo|o| -> | */ - hook_restore(g, oldh); - g->gc.threshold = oldt; /* Restore GC threshold. */ - if (errcode) - lj_err_throw(L, errcode); /* Propagate errors. */ -} - -/* Finalize one userdata or cdata object from the mmudata list. */ -static void gc_finalize(lua_State *L) -{ - global_State *g = G(L); - GCobj *o = gcnext(gcref(g->gc.mmudata)); - cTValue *mo; - lua_assert(tvref(g->jit_base) == NULL); /* Must not be called on trace. */ - /* Unchain from list of userdata to be finalized. */ - if (o == gcref(g->gc.mmudata)) - setgcrefnull(g->gc.mmudata); - else - setgcrefr(gcref(g->gc.mmudata)->gch.nextgc, o->gch.nextgc); -#if LJ_HASFFI - if (o->gch.gct == ~LJ_TCDATA) { - TValue tmp, *tv; - /* Add cdata back to the GC list and make it white. */ - setgcrefr(o->gch.nextgc, g->gc.root); - setgcref(g->gc.root, o); - makewhite(g, o); - o->gch.marked &= (uint8_t)~LJ_GC_CDATA_FIN; - /* Resolve finalizer. */ - setcdataV(L, &tmp, gco2cd(o)); - tv = lj_tab_set(L, ctype_ctsG(g)->finalizer, &tmp); - if (!tvisnil(tv)) { - g->gc.nocdatafin = 0; - copyTV(L, &tmp, tv); - setnilV(tv); /* Clear entry in finalizer table. */ - gc_call_finalizer(g, L, &tmp, o); - } - return; - } -#endif - /* Add userdata back to the main userdata list and make it white. */ - setgcrefr(o->gch.nextgc, mainthread(g)->nextgc); - setgcref(mainthread(g)->nextgc, o); - makewhite(g, o); - /* Resolve the __gc metamethod. */ - mo = lj_meta_fastg(g, tabref(gco2ud(o)->metatable), MM_gc); - if (mo) - gc_call_finalizer(g, L, mo, o); -} - -/* Finalize all userdata objects from mmudata list. */ -void lj_gc_finalize_udata(lua_State *L) -{ - while (gcref(G(L)->gc.mmudata) != NULL) - gc_finalize(L); -} - -#if LJ_HASFFI -/* Finalize all cdata objects from finalizer table. */ -void lj_gc_finalize_cdata(lua_State *L) -{ - global_State *g = G(L); - CTState *cts = ctype_ctsG(g); - if (cts) { - GCtab *t = cts->finalizer; - Node *node = noderef(t->node); - ptrdiff_t i; - setgcrefnull(t->metatable); /* Mark finalizer table as disabled. */ - for (i = (ptrdiff_t)t->hmask; i >= 0; i--) - if (!tvisnil(&node[i].val) && tviscdata(&node[i].key)) { - GCobj *o = gcV(&node[i].key); - TValue tmp; - makewhite(g, o); - o->gch.marked &= (uint8_t)~LJ_GC_CDATA_FIN; - copyTV(L, &tmp, &node[i].val); - setnilV(&node[i].val); - gc_call_finalizer(g, L, &tmp, o); - } - } -} -#endif - -/* Free all remaining GC objects. */ -void lj_gc_freeall(global_State *g) -{ - MSize i, strmask; - /* Free everything, except super-fixed objects (the main thread). */ - g->gc.currentwhite = LJ_GC_WHITES | LJ_GC_SFIXED; - gc_fullsweep(g, &g->gc.root); - strmask = g->strmask; - for (i = 0; i <= strmask; i++) /* Free all string hash chains. */ - gc_fullsweep(g, &g->strhash[i]); -} - -/* -- Collector ----------------------------------------------------------- */ - -/* Atomic part of the GC cycle, transitioning from mark to sweep phase. */ -static void atomic(global_State *g, lua_State *L) -{ - size_t udsize; - - gc_mark_uv(g); /* Need to remark open upvalues (the thread may be dead). */ - gc_propagate_gray(g); /* Propagate any left-overs. */ - - setgcrefr(g->gc.gray, g->gc.weak); /* Empty the list of weak tables. */ - setgcrefnull(g->gc.weak); - lua_assert(!iswhite(obj2gco(mainthread(g)))); - gc_markobj(g, L); /* Mark running thread. */ - gc_traverse_curtrace(g); /* Traverse current trace. */ - gc_mark_gcroot(g); /* Mark GC roots (again). */ - gc_propagate_gray(g); /* Propagate all of the above. */ - - setgcrefr(g->gc.gray, g->gc.grayagain); /* Empty the 2nd chance list. */ - setgcrefnull(g->gc.grayagain); - gc_propagate_gray(g); /* Propagate it. */ - - udsize = lj_gc_separateudata(g, 0); /* Separate userdata to be finalized. */ - gc_mark_mmudata(g); /* Mark them. */ - udsize += gc_propagate_gray(g); /* And propagate the marks. */ - - /* All marking done, clear weak tables. */ - gc_clearweak(gcref(g->gc.weak)); - - lj_buf_shrink(L, &g->tmpbuf); /* Shrink temp buffer. */ - - /* Prepare for sweep phase. */ - g->gc.currentwhite = (uint8_t)otherwhite(g); /* Flip current white. */ - g->strempty.marked = g->gc.currentwhite; - setmref(g->gc.sweep, &g->gc.root); - g->gc.estimate = g->gc.total - (GCSize)udsize; /* Initial estimate. */ -} - -/* GC state machine. Returns a cost estimate for each step performed. */ -static size_t gc_onestep(lua_State *L) -{ - global_State *g = G(L); - switch (g->gc.state) { - case GCSpause: - gc_mark_start(g); /* Start a new GC cycle by marking all GC roots. */ - return 0; - case GCSpropagate: - if (gcref(g->gc.gray) != NULL) - return propagatemark(g); /* Propagate one gray object. */ - g->gc.state = GCSatomic; /* End of mark phase. */ - return 0; - case GCSatomic: - if (tvref(g->jit_base)) /* Don't run atomic phase on trace. */ - return LJ_MAX_MEM; - atomic(g, L); - g->gc.state = GCSsweepstring; /* Start of sweep phase. */ - g->gc.sweepstr = 0; - return 0; - case GCSsweepstring: { - GCSize old = g->gc.total; - gc_fullsweep(g, &g->strhash[g->gc.sweepstr++]); /* Sweep one chain. */ - if (g->gc.sweepstr > g->strmask) - g->gc.state = GCSsweep; /* All string hash chains sweeped. */ - lua_assert(old >= g->gc.total); - g->gc.estimate -= old - g->gc.total; - return GCSWEEPCOST; - } - case GCSsweep: { - GCSize old = g->gc.total; - setmref(g->gc.sweep, gc_sweep(g, mref(g->gc.sweep, GCRef), GCSWEEPMAX)); - lua_assert(old >= g->gc.total); - g->gc.estimate -= old - g->gc.total; - if (gcref(*mref(g->gc.sweep, GCRef)) == NULL) { - if (g->strnum <= (g->strmask >> 2) && g->strmask > LJ_MIN_STRTAB*2-1) - lj_str_resize(L, g->strmask >> 1); /* Shrink string table. */ - if (gcref(g->gc.mmudata)) { /* Need any finalizations? */ - g->gc.state = GCSfinalize; -#if LJ_HASFFI - g->gc.nocdatafin = 1; -#endif - } else { /* Otherwise skip this phase to help the JIT. */ - g->gc.state = GCSpause; /* End of GC cycle. */ - g->gc.debt = 0; - } - } - return GCSWEEPMAX*GCSWEEPCOST; - } - case GCSfinalize: - if (gcref(g->gc.mmudata) != NULL) { - if (tvref(g->jit_base)) /* Don't call finalizers on trace. */ - return LJ_MAX_MEM; - gc_finalize(L); /* Finalize one userdata object. */ - if (g->gc.estimate > GCFINALIZECOST) - g->gc.estimate -= GCFINALIZECOST; - return GCFINALIZECOST; - } -#if LJ_HASFFI - if (!g->gc.nocdatafin) lj_tab_rehash(L, ctype_ctsG(g)->finalizer); -#endif - g->gc.state = GCSpause; /* End of GC cycle. */ - g->gc.debt = 0; - return 0; - default: - lua_assert(0); - return 0; - } -} - -/* Perform a limited amount of incremental GC steps. */ -int LJ_FASTCALL lj_gc_step(lua_State *L) -{ - global_State *g = G(L); - GCSize lim; - int32_t ostate = g->vmstate; - setvmstate(g, GC); - lim = (GCSTEPSIZE/100) * g->gc.stepmul; - if (lim == 0) - lim = LJ_MAX_MEM; - if (g->gc.total > g->gc.threshold) - g->gc.debt += g->gc.total - g->gc.threshold; - do { - lim -= (GCSize)gc_onestep(L); - if (g->gc.state == GCSpause) { - g->gc.threshold = (g->gc.estimate/100) * g->gc.pause; - g->vmstate = ostate; - return 1; /* Finished a GC cycle. */ - } - } while (sizeof(lim) == 8 ? ((int64_t)lim > 0) : ((int32_t)lim > 0)); - if (g->gc.debt < GCSTEPSIZE) { - g->gc.threshold = g->gc.total + GCSTEPSIZE; - g->vmstate = ostate; - return -1; - } else { - g->gc.debt -= GCSTEPSIZE; - g->gc.threshold = g->gc.total; - g->vmstate = ostate; - return 0; - } -} - -/* Ditto, but fix the stack top first. */ -void LJ_FASTCALL lj_gc_step_fixtop(lua_State *L) -{ - if (curr_funcisL(L)) L->top = curr_topL(L); - lj_gc_step(L); -} - -#if LJ_HASJIT -/* Perform multiple GC steps. Called from JIT-compiled code. */ -int LJ_FASTCALL lj_gc_step_jit(global_State *g, MSize steps) -{ - lua_State *L = gco2th(gcref(g->cur_L)); - L->base = tvref(G(L)->jit_base); - L->top = curr_topL(L); - while (steps-- > 0 && lj_gc_step(L) == 0) - ; - /* Return 1 to force a trace exit. */ - return (G(L)->gc.state == GCSatomic || G(L)->gc.state == GCSfinalize); -} -#endif - -/* Perform a full GC cycle. */ -void lj_gc_fullgc(lua_State *L) -{ - global_State *g = G(L); - int32_t ostate = g->vmstate; - setvmstate(g, GC); - if (g->gc.state <= GCSatomic) { /* Caught somewhere in the middle. */ - setmref(g->gc.sweep, &g->gc.root); /* Sweep everything (preserving it). */ - setgcrefnull(g->gc.gray); /* Reset lists from partial propagation. */ - setgcrefnull(g->gc.grayagain); - setgcrefnull(g->gc.weak); - g->gc.state = GCSsweepstring; /* Fast forward to the sweep phase. */ - g->gc.sweepstr = 0; - } - while (g->gc.state == GCSsweepstring || g->gc.state == GCSsweep) - gc_onestep(L); /* Finish sweep. */ - lua_assert(g->gc.state == GCSfinalize || g->gc.state == GCSpause); - /* Now perform a full GC. */ - g->gc.state = GCSpause; - do { gc_onestep(L); } while (g->gc.state != GCSpause); - g->gc.threshold = (g->gc.estimate/100) * g->gc.pause; - g->vmstate = ostate; -} - -/* -- Write barriers ------------------------------------------------------ */ - -/* Move the GC propagation frontier forward. */ -void lj_gc_barrierf(global_State *g, GCobj *o, GCobj *v) -{ - lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); - lua_assert(g->gc.state != GCSfinalize && g->gc.state != GCSpause); - lua_assert(o->gch.gct != ~LJ_TTAB); - /* Preserve invariant during propagation. Otherwise it doesn't matter. */ - if (g->gc.state == GCSpropagate || g->gc.state == GCSatomic) - gc_mark(g, v); /* Move frontier forward. */ - else - makewhite(g, o); /* Make it white to avoid the following barrier. */ -} - -/* Specialized barrier for closed upvalue. Pass &uv->tv. */ -void LJ_FASTCALL lj_gc_barrieruv(global_State *g, TValue *tv) -{ -#define TV2MARKED(x) \ - (*((uint8_t *)(x) - offsetof(GCupval, tv) + offsetof(GCupval, marked))) - if (g->gc.state == GCSpropagate || g->gc.state == GCSatomic) - gc_mark(g, gcV(tv)); - else - TV2MARKED(tv) = (TV2MARKED(tv) & (uint8_t)~LJ_GC_COLORS) | curwhite(g); -#undef TV2MARKED -} - -/* Close upvalue. Also needs a write barrier. */ -void lj_gc_closeuv(global_State *g, GCupval *uv) -{ - GCobj *o = obj2gco(uv); - /* Copy stack slot to upvalue itself and point to the copy. */ - copyTV(mainthread(g), &uv->tv, uvval(uv)); - setmref(uv->v, &uv->tv); - uv->closed = 1; - setgcrefr(o->gch.nextgc, g->gc.root); - setgcref(g->gc.root, o); - if (isgray(o)) { /* A closed upvalue is never gray, so fix this. */ - if (g->gc.state == GCSpropagate || g->gc.state == GCSatomic) { - gray2black(o); /* Make it black and preserve invariant. */ - if (tviswhite(&uv->tv)) - lj_gc_barrierf(g, o, gcV(&uv->tv)); - } else { - makewhite(g, o); /* Make it white, i.e. sweep the upvalue. */ - lua_assert(g->gc.state != GCSfinalize && g->gc.state != GCSpause); - } - } -} - -#if LJ_HASJIT -/* Mark a trace if it's saved during the propagation phase. */ -void lj_gc_barriertrace(global_State *g, uint32_t traceno) -{ - if (g->gc.state == GCSpropagate || g->gc.state == GCSatomic) - gc_marktrace(g, traceno); -} -#endif - -/* -- Allocator ----------------------------------------------------------- */ - -/* Call pluggable memory allocator to allocate or resize a fragment. */ -void *lj_mem_realloc(lua_State *L, void *p, GCSize osz, GCSize nsz) -{ - global_State *g = G(L); - lua_assert((osz == 0) == (p == NULL)); - p = g->allocf(g->allocd, p, osz, nsz); - if (p == NULL && nsz > 0) - lj_err_mem(L); - lua_assert((nsz == 0) == (p == NULL)); - lua_assert(checkptrGC(p)); - g->gc.total = (g->gc.total - osz) + nsz; - return p; -} - -/* Allocate new GC object and link it to the root set. */ -void * LJ_FASTCALL lj_mem_newgco(lua_State *L, GCSize size) -{ - global_State *g = G(L); - GCobj *o = (GCobj *)g->allocf(g->allocd, NULL, 0, size); - if (o == NULL) - lj_err_mem(L); - lua_assert(checkptrGC(o)); - g->gc.total += size; - setgcrefr(o->gch.nextgc, g->gc.root); - setgcref(g->gc.root, o); - newwhite(g, o); - return o; -} - -/* Resize growable vector. */ -void *lj_mem_grow(lua_State *L, void *p, MSize *szp, MSize lim, MSize esz) -{ - MSize sz = (*szp) << 1; - if (sz < LJ_MIN_VECSZ) - sz = LJ_MIN_VECSZ; - if (sz > lim) - sz = lim; - p = lj_mem_realloc(L, p, (*szp)*esz, sz*esz); - *szp = sz; - return p; -} - diff --git a/lib/LuaJIT/src/lj_gc.h b/lib/LuaJIT/src/lj_gc.h deleted file mode 100644 index 669bbe9..0000000 --- a/lib/LuaJIT/src/lj_gc.h +++ /dev/null @@ -1,134 +0,0 @@ -/* -** Garbage collector. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_GC_H -#define _LJ_GC_H - -#include "lj_obj.h" - -/* Garbage collector states. Order matters. */ -enum { - GCSpause, GCSpropagate, GCSatomic, GCSsweepstring, GCSsweep, GCSfinalize -}; - -/* Bitmasks for marked field of GCobj. */ -#define LJ_GC_WHITE0 0x01 -#define LJ_GC_WHITE1 0x02 -#define LJ_GC_BLACK 0x04 -#define LJ_GC_FINALIZED 0x08 -#define LJ_GC_WEAKKEY 0x08 -#define LJ_GC_WEAKVAL 0x10 -#define LJ_GC_CDATA_FIN 0x10 -#define LJ_GC_FIXED 0x20 -#define LJ_GC_SFIXED 0x40 - -#define LJ_GC_WHITES (LJ_GC_WHITE0 | LJ_GC_WHITE1) -#define LJ_GC_COLORS (LJ_GC_WHITES | LJ_GC_BLACK) -#define LJ_GC_WEAK (LJ_GC_WEAKKEY | LJ_GC_WEAKVAL) - -/* Macros to test and set GCobj colors. */ -#define iswhite(x) ((x)->gch.marked & LJ_GC_WHITES) -#define isblack(x) ((x)->gch.marked & LJ_GC_BLACK) -#define isgray(x) (!((x)->gch.marked & (LJ_GC_BLACK|LJ_GC_WHITES))) -#define tviswhite(x) (tvisgcv(x) && iswhite(gcV(x))) -#define otherwhite(g) (g->gc.currentwhite ^ LJ_GC_WHITES) -#define isdead(g, v) ((v)->gch.marked & otherwhite(g) & LJ_GC_WHITES) - -#define curwhite(g) ((g)->gc.currentwhite & LJ_GC_WHITES) -#define newwhite(g, x) (obj2gco(x)->gch.marked = (uint8_t)curwhite(g)) -#define makewhite(g, x) \ - ((x)->gch.marked = ((x)->gch.marked & (uint8_t)~LJ_GC_COLORS) | curwhite(g)) -#define flipwhite(x) ((x)->gch.marked ^= LJ_GC_WHITES) -#define black2gray(x) ((x)->gch.marked &= (uint8_t)~LJ_GC_BLACK) -#define fixstring(s) ((s)->marked |= LJ_GC_FIXED) -#define markfinalized(x) ((x)->gch.marked |= LJ_GC_FINALIZED) - -/* Collector. */ -LJ_FUNC size_t lj_gc_separateudata(global_State *g, int all); -LJ_FUNC void lj_gc_finalize_udata(lua_State *L); -#if LJ_HASFFI -LJ_FUNC void lj_gc_finalize_cdata(lua_State *L); -#else -#define lj_gc_finalize_cdata(L) UNUSED(L) -#endif -LJ_FUNC void lj_gc_freeall(global_State *g); -LJ_FUNCA int LJ_FASTCALL lj_gc_step(lua_State *L); -LJ_FUNCA void LJ_FASTCALL lj_gc_step_fixtop(lua_State *L); -#if LJ_HASJIT -LJ_FUNC int LJ_FASTCALL lj_gc_step_jit(global_State *g, MSize steps); -#endif -LJ_FUNC void lj_gc_fullgc(lua_State *L); - -/* GC check: drive collector forward if the GC threshold has been reached. */ -#define lj_gc_check(L) \ - { if (LJ_UNLIKELY(G(L)->gc.total >= G(L)->gc.threshold)) \ - lj_gc_step(L); } -#define lj_gc_check_fixtop(L) \ - { if (LJ_UNLIKELY(G(L)->gc.total >= G(L)->gc.threshold)) \ - lj_gc_step_fixtop(L); } - -/* Write barriers. */ -LJ_FUNC void lj_gc_barrierf(global_State *g, GCobj *o, GCobj *v); -LJ_FUNCA void LJ_FASTCALL lj_gc_barrieruv(global_State *g, TValue *tv); -LJ_FUNC void lj_gc_closeuv(global_State *g, GCupval *uv); -#if LJ_HASJIT -LJ_FUNC void lj_gc_barriertrace(global_State *g, uint32_t traceno); -#endif - -/* Move the GC propagation frontier back for tables (make it gray again). */ -static LJ_AINLINE void lj_gc_barrierback(global_State *g, GCtab *t) -{ - GCobj *o = obj2gco(t); - lua_assert(isblack(o) && !isdead(g, o)); - lua_assert(g->gc.state != GCSfinalize && g->gc.state != GCSpause); - black2gray(o); - setgcrefr(t->gclist, g->gc.grayagain); - setgcref(g->gc.grayagain, o); -} - -/* Barrier for stores to table objects. TValue and GCobj variant. */ -#define lj_gc_anybarriert(L, t) \ - { if (LJ_UNLIKELY(isblack(obj2gco(t)))) lj_gc_barrierback(G(L), (t)); } -#define lj_gc_barriert(L, t, tv) \ - { if (tviswhite(tv) && isblack(obj2gco(t))) \ - lj_gc_barrierback(G(L), (t)); } -#define lj_gc_objbarriert(L, t, o) \ - { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) \ - lj_gc_barrierback(G(L), (t)); } - -/* Barrier for stores to any other object. TValue and GCobj variant. */ -#define lj_gc_barrier(L, p, tv) \ - { if (tviswhite(tv) && isblack(obj2gco(p))) \ - lj_gc_barrierf(G(L), obj2gco(p), gcV(tv)); } -#define lj_gc_objbarrier(L, p, o) \ - { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ - lj_gc_barrierf(G(L), obj2gco(p), obj2gco(o)); } - -/* Allocator. */ -LJ_FUNC void *lj_mem_realloc(lua_State *L, void *p, GCSize osz, GCSize nsz); -LJ_FUNC void * LJ_FASTCALL lj_mem_newgco(lua_State *L, GCSize size); -LJ_FUNC void *lj_mem_grow(lua_State *L, void *p, - MSize *szp, MSize lim, MSize esz); - -#define lj_mem_new(L, s) lj_mem_realloc(L, NULL, 0, (s)) - -static LJ_AINLINE void lj_mem_free(global_State *g, void *p, size_t osize) -{ - g->gc.total -= (GCSize)osize; - g->allocf(g->allocd, p, osize, 0); -} - -#define lj_mem_newvec(L, n, t) ((t *)lj_mem_new(L, (GCSize)((n)*sizeof(t)))) -#define lj_mem_reallocvec(L, p, on, n, t) \ - ((p) = (t *)lj_mem_realloc(L, p, (on)*sizeof(t), (GCSize)((n)*sizeof(t)))) -#define lj_mem_growvec(L, p, n, m, t) \ - ((p) = (t *)lj_mem_grow(L, (p), &(n), (m), (MSize)sizeof(t))) -#define lj_mem_freevec(g, p, n, t) lj_mem_free(g, (p), (n)*sizeof(t)) - -#define lj_mem_newobj(L, t) ((t *)lj_mem_newgco(L, sizeof(t))) -#define lj_mem_newt(L, s, t) ((t *)lj_mem_new(L, (s))) -#define lj_mem_freet(g, p) lj_mem_free(g, (p), sizeof(*(p))) - -#endif diff --git a/lib/LuaJIT/src/lj_gdbjit.c b/lib/LuaJIT/src/lj_gdbjit.c deleted file mode 100644 index c219ffa..0000000 --- a/lib/LuaJIT/src/lj_gdbjit.c +++ /dev/null @@ -1,817 +0,0 @@ -/* -** Client for the GDB JIT API. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_gdbjit_c -#define LUA_CORE - -#include "lj_obj.h" - -#if LJ_HASJIT - -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_debug.h" -#include "lj_frame.h" -#include "lj_buf.h" -#include "lj_strfmt.h" -#include "lj_jit.h" -#include "lj_dispatch.h" - -/* This is not compiled in by default. -** Enable with -DLUAJIT_USE_GDBJIT in the Makefile and recompile everything. -*/ -#ifdef LUAJIT_USE_GDBJIT - -/* The GDB JIT API allows JIT compilers to pass debug information about -** JIT-compiled code back to GDB. You need at least GDB 7.0 or higher -** to see it in action. -** -** This is a passive API, so it works even when not running under GDB -** or when attaching to an already running process. Alas, this implies -** enabling it always has a non-negligible overhead -- do not use in -** release mode! -** -** The LuaJIT GDB JIT client is rather minimal at the moment. It gives -** each trace a symbol name and adds a source location and frame unwind -** information. Obviously LuaJIT itself and any embedding C application -** should be compiled with debug symbols, too (see the Makefile). -** -** Traces are named TRACE_1, TRACE_2, ... these correspond to the trace -** numbers from -jv or -jdump. Use "break TRACE_1" or "tbreak TRACE_1" etc. -** to set breakpoints on specific traces (even ahead of their creation). -** -** The source location for each trace allows listing the corresponding -** source lines with the GDB command "list" (but only if the Lua source -** has been loaded from a file). Currently this is always set to the -** location where the trace has been started. -** -** Frame unwind information can be inspected with the GDB command -** "info frame". This also allows proper backtraces across JIT-compiled -** code with the GDB command "bt". -** -** You probably want to add the following settings to a .gdbinit file -** (or add them to ~/.gdbinit): -** set disassembly-flavor intel -** set breakpoint pending on -** -** Here's a sample GDB session: -** ------------------------------------------------------------------------ - -$ cat >x.lua -for outer=1,100 do - for inner=1,100 do end -end -^D - -$ luajit -jv x.lua -[TRACE 1 x.lua:2] -[TRACE 2 (1/3) x.lua:1 -> 1] - -$ gdb --quiet --args luajit x.lua -(gdb) tbreak TRACE_1 -Function "TRACE_1" not defined. -Temporary breakpoint 1 (TRACE_1) pending. -(gdb) run -Starting program: luajit x.lua - -Temporary breakpoint 1, TRACE_1 () at x.lua:2 -2 for inner=1,100 do end -(gdb) list -1 for outer=1,100 do -2 for inner=1,100 do end -3 end -(gdb) bt -#0 TRACE_1 () at x.lua:2 -#1 0x08053690 in lua_pcall [...] -[...] -#7 0x0806ff90 in main [...] -(gdb) disass TRACE_1 -Dump of assembler code for function TRACE_1: -0xf7fd9fba : mov DWORD PTR ds:0xf7e0e2a0,0x1 -0xf7fd9fc4 : movsd xmm7,QWORD PTR [edx+0x20] -[...] -0xf7fd9ff8 : jmp 0xf7fd2014 -End of assembler dump. -(gdb) tbreak TRACE_2 -Function "TRACE_2" not defined. -Temporary breakpoint 2 (TRACE_2) pending. -(gdb) cont -Continuing. - -Temporary breakpoint 2, TRACE_2 () at x.lua:1 -1 for outer=1,100 do -(gdb) info frame -Stack level 0, frame at 0xffffd7c0: - eip = 0xf7fd9f60 in TRACE_2 (x.lua:1); saved eip 0x8053690 - called by frame at 0xffffd7e0 - source language unknown. - Arglist at 0xffffd78c, args: - Locals at 0xffffd78c, Previous frame's sp is 0xffffd7c0 - Saved registers: - ebx at 0xffffd7ac, ebp at 0xffffd7b8, esi at 0xffffd7b0, edi at 0xffffd7b4, - eip at 0xffffd7bc -(gdb) - -** ------------------------------------------------------------------------ -*/ - -/* -- GDB JIT API --------------------------------------------------------- */ - -/* GDB JIT actions. */ -enum { - GDBJIT_NOACTION = 0, - GDBJIT_REGISTER, - GDBJIT_UNREGISTER -}; - -/* GDB JIT entry. */ -typedef struct GDBJITentry { - struct GDBJITentry *next_entry; - struct GDBJITentry *prev_entry; - const char *symfile_addr; - uint64_t symfile_size; -} GDBJITentry; - -/* GDB JIT descriptor. */ -typedef struct GDBJITdesc { - uint32_t version; - uint32_t action_flag; - GDBJITentry *relevant_entry; - GDBJITentry *first_entry; -} GDBJITdesc; - -GDBJITdesc __jit_debug_descriptor = { - 1, GDBJIT_NOACTION, NULL, NULL -}; - -/* GDB sets a breakpoint at this function. */ -void LJ_NOINLINE __jit_debug_register_code() -{ - __asm__ __volatile__(""); -}; - -/* -- In-memory ELF object definitions ------------------------------------ */ - -/* ELF definitions. */ -typedef struct ELFheader { - uint8_t emagic[4]; - uint8_t eclass; - uint8_t eendian; - uint8_t eversion; - uint8_t eosabi; - uint8_t eabiversion; - uint8_t epad[7]; - uint16_t type; - uint16_t machine; - uint32_t version; - uintptr_t entry; - uintptr_t phofs; - uintptr_t shofs; - uint32_t flags; - uint16_t ehsize; - uint16_t phentsize; - uint16_t phnum; - uint16_t shentsize; - uint16_t shnum; - uint16_t shstridx; -} ELFheader; - -typedef struct ELFsectheader { - uint32_t name; - uint32_t type; - uintptr_t flags; - uintptr_t addr; - uintptr_t ofs; - uintptr_t size; - uint32_t link; - uint32_t info; - uintptr_t align; - uintptr_t entsize; -} ELFsectheader; - -#define ELFSECT_IDX_ABS 0xfff1 - -enum { - ELFSECT_TYPE_PROGBITS = 1, - ELFSECT_TYPE_SYMTAB = 2, - ELFSECT_TYPE_STRTAB = 3, - ELFSECT_TYPE_NOBITS = 8 -}; - -#define ELFSECT_FLAGS_WRITE 1 -#define ELFSECT_FLAGS_ALLOC 2 -#define ELFSECT_FLAGS_EXEC 4 - -typedef struct ELFsymbol { -#if LJ_64 - uint32_t name; - uint8_t info; - uint8_t other; - uint16_t sectidx; - uintptr_t value; - uint64_t size; -#else - uint32_t name; - uintptr_t value; - uint32_t size; - uint8_t info; - uint8_t other; - uint16_t sectidx; -#endif -} ELFsymbol; - -enum { - ELFSYM_TYPE_FUNC = 2, - ELFSYM_TYPE_FILE = 4, - ELFSYM_BIND_LOCAL = 0 << 4, - ELFSYM_BIND_GLOBAL = 1 << 4, -}; - -/* DWARF definitions. */ -#define DW_CIE_VERSION 1 - -enum { - DW_CFA_nop = 0x0, - DW_CFA_offset_extended = 0x5, - DW_CFA_def_cfa = 0xc, - DW_CFA_def_cfa_offset = 0xe, - DW_CFA_offset_extended_sf = 0x11, - DW_CFA_advance_loc = 0x40, - DW_CFA_offset = 0x80 -}; - -enum { - DW_EH_PE_udata4 = 3, - DW_EH_PE_textrel = 0x20 -}; - -enum { - DW_TAG_compile_unit = 0x11 -}; - -enum { - DW_children_no = 0, - DW_children_yes = 1 -}; - -enum { - DW_AT_name = 0x03, - DW_AT_stmt_list = 0x10, - DW_AT_low_pc = 0x11, - DW_AT_high_pc = 0x12 -}; - -enum { - DW_FORM_addr = 0x01, - DW_FORM_data4 = 0x06, - DW_FORM_string = 0x08 -}; - -enum { - DW_LNS_extended_op = 0, - DW_LNS_copy = 1, - DW_LNS_advance_pc = 2, - DW_LNS_advance_line = 3 -}; - -enum { - DW_LNE_end_sequence = 1, - DW_LNE_set_address = 2 -}; - -enum { -#if LJ_TARGET_X86 - DW_REG_AX, DW_REG_CX, DW_REG_DX, DW_REG_BX, - DW_REG_SP, DW_REG_BP, DW_REG_SI, DW_REG_DI, - DW_REG_RA, -#elif LJ_TARGET_X64 - /* Yes, the order is strange, but correct. */ - DW_REG_AX, DW_REG_DX, DW_REG_CX, DW_REG_BX, - DW_REG_SI, DW_REG_DI, DW_REG_BP, DW_REG_SP, - DW_REG_8, DW_REG_9, DW_REG_10, DW_REG_11, - DW_REG_12, DW_REG_13, DW_REG_14, DW_REG_15, - DW_REG_RA, -#elif LJ_TARGET_ARM - DW_REG_SP = 13, - DW_REG_RA = 14, -#elif LJ_TARGET_ARM64 - DW_REG_SP = 31, - DW_REG_RA = 30, -#elif LJ_TARGET_PPC - DW_REG_SP = 1, - DW_REG_RA = 65, - DW_REG_CR = 70, -#elif LJ_TARGET_MIPS - DW_REG_SP = 29, - DW_REG_RA = 31, -#else -#error "Unsupported target architecture" -#endif -}; - -/* Minimal list of sections for the in-memory ELF object. */ -enum { - GDBJIT_SECT_NULL, - GDBJIT_SECT_text, - GDBJIT_SECT_eh_frame, - GDBJIT_SECT_shstrtab, - GDBJIT_SECT_strtab, - GDBJIT_SECT_symtab, - GDBJIT_SECT_debug_info, - GDBJIT_SECT_debug_abbrev, - GDBJIT_SECT_debug_line, - GDBJIT_SECT__MAX -}; - -enum { - GDBJIT_SYM_UNDEF, - GDBJIT_SYM_FILE, - GDBJIT_SYM_FUNC, - GDBJIT_SYM__MAX -}; - -/* In-memory ELF object. */ -typedef struct GDBJITobj { - ELFheader hdr; /* ELF header. */ - ELFsectheader sect[GDBJIT_SECT__MAX]; /* ELF sections. */ - ELFsymbol sym[GDBJIT_SYM__MAX]; /* ELF symbol table. */ - uint8_t space[4096]; /* Space for various section data. */ -} GDBJITobj; - -/* Combined structure for GDB JIT entry and ELF object. */ -typedef struct GDBJITentryobj { - GDBJITentry entry; - size_t sz; - GDBJITobj obj; -} GDBJITentryobj; - -/* Template for in-memory ELF header. */ -static const ELFheader elfhdr_template = { - .emagic = { 0x7f, 'E', 'L', 'F' }, - .eclass = LJ_64 ? 2 : 1, - .eendian = LJ_ENDIAN_SELECT(1, 2), - .eversion = 1, -#if LJ_TARGET_LINUX - .eosabi = 0, /* Nope, it's not 3. */ -#elif defined(__FreeBSD__) - .eosabi = 9, -#elif defined(__NetBSD__) - .eosabi = 2, -#elif defined(__OpenBSD__) - .eosabi = 12, -#elif defined(__DragonFly__) - .eosabi = 0, -#elif (defined(__sun__) && defined(__svr4__)) - .eosabi = 6, -#else - .eosabi = 0, -#endif - .eabiversion = 0, - .epad = { 0, 0, 0, 0, 0, 0, 0 }, - .type = 1, -#if LJ_TARGET_X86 - .machine = 3, -#elif LJ_TARGET_X64 - .machine = 62, -#elif LJ_TARGET_ARM - .machine = 40, -#elif LJ_TARGET_ARM64 - .machine = 183, -#elif LJ_TARGET_PPC - .machine = 20, -#elif LJ_TARGET_MIPS - .machine = 8, -#else -#error "Unsupported target architecture" -#endif - .version = 1, - .entry = 0, - .phofs = 0, - .shofs = offsetof(GDBJITobj, sect), - .flags = 0, - .ehsize = sizeof(ELFheader), - .phentsize = 0, - .phnum = 0, - .shentsize = sizeof(ELFsectheader), - .shnum = GDBJIT_SECT__MAX, - .shstridx = GDBJIT_SECT_shstrtab -}; - -/* -- In-memory ELF object generation ------------------------------------- */ - -/* Context for generating the ELF object for the GDB JIT API. */ -typedef struct GDBJITctx { - uint8_t *p; /* Pointer to next address in obj.space. */ - uint8_t *startp; /* Pointer to start address in obj.space. */ - GCtrace *T; /* Generate symbols for this trace. */ - uintptr_t mcaddr; /* Machine code address. */ - MSize szmcode; /* Size of machine code. */ - MSize spadjp; /* Stack adjustment for parent trace or interpreter. */ - MSize spadj; /* Stack adjustment for trace itself. */ - BCLine lineno; /* Starting line number. */ - const char *filename; /* Starting file name. */ - size_t objsize; /* Final size of ELF object. */ - GDBJITobj obj; /* In-memory ELF object. */ -} GDBJITctx; - -/* Add a zero-terminated string. */ -static uint32_t gdbjit_strz(GDBJITctx *ctx, const char *str) -{ - uint8_t *p = ctx->p; - uint32_t ofs = (uint32_t)(p - ctx->startp); - do { - *p++ = (uint8_t)*str; - } while (*str++); - ctx->p = p; - return ofs; -} - -/* Append a decimal number. */ -static void gdbjit_catnum(GDBJITctx *ctx, uint32_t n) -{ - if (n >= 10) { uint32_t m = n / 10; n = n % 10; gdbjit_catnum(ctx, m); } - *ctx->p++ = '0' + n; -} - -/* Add a SLEB128 value. */ -static void gdbjit_sleb128(GDBJITctx *ctx, int32_t v) -{ - uint8_t *p = ctx->p; - for (; (uint32_t)(v+0x40) >= 0x80; v >>= 7) - *p++ = (uint8_t)((v & 0x7f) | 0x80); - *p++ = (uint8_t)(v & 0x7f); - ctx->p = p; -} - -/* Shortcuts to generate DWARF structures. */ -#define DB(x) (*p++ = (x)) -#define DI8(x) (*(int8_t *)p = (x), p++) -#define DU16(x) (*(uint16_t *)p = (x), p += 2) -#define DU32(x) (*(uint32_t *)p = (x), p += 4) -#define DADDR(x) (*(uintptr_t *)p = (x), p += sizeof(uintptr_t)) -#define DUV(x) (p = (uint8_t *)lj_strfmt_wuleb128((char *)p, (x))) -#define DSV(x) (ctx->p = p, gdbjit_sleb128(ctx, (x)), p = ctx->p) -#define DSTR(str) (ctx->p = p, gdbjit_strz(ctx, (str)), p = ctx->p) -#define DALIGNNOP(s) while ((uintptr_t)p & ((s)-1)) *p++ = DW_CFA_nop -#define DSECT(name, stmt) \ - { uint32_t *szp_##name = (uint32_t *)p; p += 4; stmt \ - *szp_##name = (uint32_t)((p-(uint8_t *)szp_##name)-4); } \ - -/* Initialize ELF section headers. */ -static void LJ_FASTCALL gdbjit_secthdr(GDBJITctx *ctx) -{ - ELFsectheader *sect; - - *ctx->p++ = '\0'; /* Empty string at start of string table. */ - -#define SECTDEF(id, tp, al) \ - sect = &ctx->obj.sect[GDBJIT_SECT_##id]; \ - sect->name = gdbjit_strz(ctx, "." #id); \ - sect->type = ELFSECT_TYPE_##tp; \ - sect->align = (al) - - SECTDEF(text, NOBITS, 16); - sect->flags = ELFSECT_FLAGS_ALLOC|ELFSECT_FLAGS_EXEC; - sect->addr = ctx->mcaddr; - sect->ofs = 0; - sect->size = ctx->szmcode; - - SECTDEF(eh_frame, PROGBITS, sizeof(uintptr_t)); - sect->flags = ELFSECT_FLAGS_ALLOC; - - SECTDEF(shstrtab, STRTAB, 1); - SECTDEF(strtab, STRTAB, 1); - - SECTDEF(symtab, SYMTAB, sizeof(uintptr_t)); - sect->ofs = offsetof(GDBJITobj, sym); - sect->size = sizeof(ctx->obj.sym); - sect->link = GDBJIT_SECT_strtab; - sect->entsize = sizeof(ELFsymbol); - sect->info = GDBJIT_SYM_FUNC; - - SECTDEF(debug_info, PROGBITS, 1); - SECTDEF(debug_abbrev, PROGBITS, 1); - SECTDEF(debug_line, PROGBITS, 1); - -#undef SECTDEF -} - -/* Initialize symbol table. */ -static void LJ_FASTCALL gdbjit_symtab(GDBJITctx *ctx) -{ - ELFsymbol *sym; - - *ctx->p++ = '\0'; /* Empty string at start of string table. */ - - sym = &ctx->obj.sym[GDBJIT_SYM_FILE]; - sym->name = gdbjit_strz(ctx, "JIT mcode"); - sym->sectidx = ELFSECT_IDX_ABS; - sym->info = ELFSYM_TYPE_FILE|ELFSYM_BIND_LOCAL; - - sym = &ctx->obj.sym[GDBJIT_SYM_FUNC]; - sym->name = gdbjit_strz(ctx, "TRACE_"); ctx->p--; - gdbjit_catnum(ctx, ctx->T->traceno); *ctx->p++ = '\0'; - sym->sectidx = GDBJIT_SECT_text; - sym->value = 0; - sym->size = ctx->szmcode; - sym->info = ELFSYM_TYPE_FUNC|ELFSYM_BIND_GLOBAL; -} - -/* Initialize .eh_frame section. */ -static void LJ_FASTCALL gdbjit_ehframe(GDBJITctx *ctx) -{ - uint8_t *p = ctx->p; - uint8_t *framep = p; - - /* Emit DWARF EH CIE. */ - DSECT(CIE, - DU32(0); /* Offset to CIE itself. */ - DB(DW_CIE_VERSION); - DSTR("zR"); /* Augmentation. */ - DUV(1); /* Code alignment factor. */ - DSV(-(int32_t)sizeof(uintptr_t)); /* Data alignment factor. */ - DB(DW_REG_RA); /* Return address register. */ - DB(1); DB(DW_EH_PE_textrel|DW_EH_PE_udata4); /* Augmentation data. */ - DB(DW_CFA_def_cfa); DUV(DW_REG_SP); DUV(sizeof(uintptr_t)); -#if LJ_TARGET_PPC - DB(DW_CFA_offset_extended_sf); DB(DW_REG_RA); DSV(-1); -#else - DB(DW_CFA_offset|DW_REG_RA); DUV(1); -#endif - DALIGNNOP(sizeof(uintptr_t)); - ) - - /* Emit DWARF EH FDE. */ - DSECT(FDE, - DU32((uint32_t)(p-framep)); /* Offset to CIE. */ - DU32(0); /* Machine code offset relative to .text. */ - DU32(ctx->szmcode); /* Machine code length. */ - DB(0); /* Augmentation data. */ - /* Registers saved in CFRAME. */ -#if LJ_TARGET_X86 - DB(DW_CFA_offset|DW_REG_BP); DUV(2); - DB(DW_CFA_offset|DW_REG_DI); DUV(3); - DB(DW_CFA_offset|DW_REG_SI); DUV(4); - DB(DW_CFA_offset|DW_REG_BX); DUV(5); -#elif LJ_TARGET_X64 - DB(DW_CFA_offset|DW_REG_BP); DUV(2); - DB(DW_CFA_offset|DW_REG_BX); DUV(3); - DB(DW_CFA_offset|DW_REG_15); DUV(4); - DB(DW_CFA_offset|DW_REG_14); DUV(5); - /* Extra registers saved for JIT-compiled code. */ - DB(DW_CFA_offset|DW_REG_13); DUV(LJ_GC64 ? 10 : 9); - DB(DW_CFA_offset|DW_REG_12); DUV(LJ_GC64 ? 11 : 10); -#elif LJ_TARGET_ARM - { - int i; - for (i = 11; i >= 4; i--) { DB(DW_CFA_offset|i); DUV(2+(11-i)); } - } -#elif LJ_TARGET_ARM64 - { - int i; - DB(DW_CFA_offset|31); DUV(2); - for (i = 28; i >= 19; i--) { DB(DW_CFA_offset|i); DUV(3+(28-i)); } - for (i = 15; i >= 8; i--) { DB(DW_CFA_offset|32|i); DUV(28-i); } - } -#elif LJ_TARGET_PPC - { - int i; - DB(DW_CFA_offset_extended); DB(DW_REG_CR); DUV(55); - for (i = 14; i <= 31; i++) { - DB(DW_CFA_offset|i); DUV(37+(31-i)); - DB(DW_CFA_offset|32|i); DUV(2+2*(31-i)); - } - } -#elif LJ_TARGET_MIPS - { - int i; - DB(DW_CFA_offset|30); DUV(2); - for (i = 23; i >= 16; i--) { DB(DW_CFA_offset|i); DUV(26-i); } - for (i = 30; i >= 20; i -= 2) { DB(DW_CFA_offset|32|i); DUV(42-i); } - } -#else -#error "Unsupported target architecture" -#endif - if (ctx->spadjp != ctx->spadj) { /* Parent/interpreter stack frame size. */ - DB(DW_CFA_def_cfa_offset); DUV(ctx->spadjp); - DB(DW_CFA_advance_loc|1); /* Only an approximation. */ - } - DB(DW_CFA_def_cfa_offset); DUV(ctx->spadj); /* Trace stack frame size. */ - DALIGNNOP(sizeof(uintptr_t)); - ) - - ctx->p = p; -} - -/* Initialize .debug_info section. */ -static void LJ_FASTCALL gdbjit_debuginfo(GDBJITctx *ctx) -{ - uint8_t *p = ctx->p; - - DSECT(info, - DU16(2); /* DWARF version. */ - DU32(0); /* Abbrev offset. */ - DB(sizeof(uintptr_t)); /* Pointer size. */ - - DUV(1); /* Abbrev #1: DW_TAG_compile_unit. */ - DSTR(ctx->filename); /* DW_AT_name. */ - DADDR(ctx->mcaddr); /* DW_AT_low_pc. */ - DADDR(ctx->mcaddr + ctx->szmcode); /* DW_AT_high_pc. */ - DU32(0); /* DW_AT_stmt_list. */ - ) - - ctx->p = p; -} - -/* Initialize .debug_abbrev section. */ -static void LJ_FASTCALL gdbjit_debugabbrev(GDBJITctx *ctx) -{ - uint8_t *p = ctx->p; - - /* Abbrev #1: DW_TAG_compile_unit. */ - DUV(1); DUV(DW_TAG_compile_unit); - DB(DW_children_no); - DUV(DW_AT_name); DUV(DW_FORM_string); - DUV(DW_AT_low_pc); DUV(DW_FORM_addr); - DUV(DW_AT_high_pc); DUV(DW_FORM_addr); - DUV(DW_AT_stmt_list); DUV(DW_FORM_data4); - DB(0); DB(0); - - ctx->p = p; -} - -#define DLNE(op, s) (DB(DW_LNS_extended_op), DUV(1+(s)), DB((op))) - -/* Initialize .debug_line section. */ -static void LJ_FASTCALL gdbjit_debugline(GDBJITctx *ctx) -{ - uint8_t *p = ctx->p; - - DSECT(line, - DU16(2); /* DWARF version. */ - DSECT(header, - DB(1); /* Minimum instruction length. */ - DB(1); /* is_stmt. */ - DI8(0); /* Line base for special opcodes. */ - DB(2); /* Line range for special opcodes. */ - DB(3+1); /* Opcode base at DW_LNS_advance_line+1. */ - DB(0); DB(1); DB(1); /* Standard opcode lengths. */ - /* Directory table. */ - DB(0); - /* File name table. */ - DSTR(ctx->filename); DUV(0); DUV(0); DUV(0); - DB(0); - ) - - DLNE(DW_LNE_set_address, sizeof(uintptr_t)); DADDR(ctx->mcaddr); - if (ctx->lineno) { - DB(DW_LNS_advance_line); DSV(ctx->lineno-1); - } - DB(DW_LNS_copy); - DB(DW_LNS_advance_pc); DUV(ctx->szmcode); - DLNE(DW_LNE_end_sequence, 0); - ) - - ctx->p = p; -} - -#undef DLNE - -/* Undef shortcuts. */ -#undef DB -#undef DI8 -#undef DU16 -#undef DU32 -#undef DADDR -#undef DUV -#undef DSV -#undef DSTR -#undef DALIGNNOP -#undef DSECT - -/* Type of a section initializer callback. */ -typedef void (LJ_FASTCALL *GDBJITinitf)(GDBJITctx *ctx); - -/* Call section initializer and set the section offset and size. */ -static void gdbjit_initsect(GDBJITctx *ctx, int sect, GDBJITinitf initf) -{ - ctx->startp = ctx->p; - ctx->obj.sect[sect].ofs = (uintptr_t)((char *)ctx->p - (char *)&ctx->obj); - initf(ctx); - ctx->obj.sect[sect].size = (uintptr_t)(ctx->p - ctx->startp); -} - -#define SECTALIGN(p, a) \ - ((p) = (uint8_t *)(((uintptr_t)(p) + ((a)-1)) & ~(uintptr_t)((a)-1))) - -/* Build in-memory ELF object. */ -static void gdbjit_buildobj(GDBJITctx *ctx) -{ - GDBJITobj *obj = &ctx->obj; - /* Fill in ELF header and clear structures. */ - memcpy(&obj->hdr, &elfhdr_template, sizeof(ELFheader)); - memset(&obj->sect, 0, sizeof(ELFsectheader)*GDBJIT_SECT__MAX); - memset(&obj->sym, 0, sizeof(ELFsymbol)*GDBJIT_SYM__MAX); - /* Initialize sections. */ - ctx->p = obj->space; - gdbjit_initsect(ctx, GDBJIT_SECT_shstrtab, gdbjit_secthdr); - gdbjit_initsect(ctx, GDBJIT_SECT_strtab, gdbjit_symtab); - gdbjit_initsect(ctx, GDBJIT_SECT_debug_info, gdbjit_debuginfo); - gdbjit_initsect(ctx, GDBJIT_SECT_debug_abbrev, gdbjit_debugabbrev); - gdbjit_initsect(ctx, GDBJIT_SECT_debug_line, gdbjit_debugline); - SECTALIGN(ctx->p, sizeof(uintptr_t)); - gdbjit_initsect(ctx, GDBJIT_SECT_eh_frame, gdbjit_ehframe); - ctx->objsize = (size_t)((char *)ctx->p - (char *)obj); - lua_assert(ctx->objsize < sizeof(GDBJITobj)); -} - -#undef SECTALIGN - -/* -- Interface to GDB JIT API -------------------------------------------- */ - -static int gdbjit_lock; - -static void gdbjit_lock_acquire() -{ - while (__sync_lock_test_and_set(&gdbjit_lock, 1)) { - /* Just spin; futexes or pthreads aren't worth the portability cost. */ - } -} - -static void gdbjit_lock_release() -{ - __sync_lock_release(&gdbjit_lock); -} - -/* Add new entry to GDB JIT symbol chain. */ -static void gdbjit_newentry(lua_State *L, GDBJITctx *ctx) -{ - /* Allocate memory for GDB JIT entry and ELF object. */ - MSize sz = (MSize)(sizeof(GDBJITentryobj) - sizeof(GDBJITobj) + ctx->objsize); - GDBJITentryobj *eo = lj_mem_newt(L, sz, GDBJITentryobj); - memcpy(&eo->obj, &ctx->obj, ctx->objsize); /* Copy ELF object. */ - eo->sz = sz; - ctx->T->gdbjit_entry = (void *)eo; - /* Link new entry to chain and register it. */ - eo->entry.prev_entry = NULL; - gdbjit_lock_acquire(); - eo->entry.next_entry = __jit_debug_descriptor.first_entry; - if (eo->entry.next_entry) - eo->entry.next_entry->prev_entry = &eo->entry; - eo->entry.symfile_addr = (const char *)&eo->obj; - eo->entry.symfile_size = ctx->objsize; - __jit_debug_descriptor.first_entry = &eo->entry; - __jit_debug_descriptor.relevant_entry = &eo->entry; - __jit_debug_descriptor.action_flag = GDBJIT_REGISTER; - __jit_debug_register_code(); - gdbjit_lock_release(); -} - -/* Add debug info for newly compiled trace and notify GDB. */ -void lj_gdbjit_addtrace(jit_State *J, GCtrace *T) -{ - GDBJITctx ctx; - GCproto *pt = &gcref(T->startpt)->pt; - TraceNo parent = T->ir[REF_BASE].op1; - const BCIns *startpc = mref(T->startpc, const BCIns); - ctx.T = T; - ctx.mcaddr = (uintptr_t)T->mcode; - ctx.szmcode = T->szmcode; - ctx.spadjp = CFRAME_SIZE_JIT + - (MSize)(parent ? traceref(J, parent)->spadjust : 0); - ctx.spadj = CFRAME_SIZE_JIT + T->spadjust; - lua_assert(startpc >= proto_bc(pt) && startpc < proto_bc(pt) + pt->sizebc); - ctx.lineno = lj_debug_line(pt, proto_bcpos(pt, startpc)); - ctx.filename = proto_chunknamestr(pt); - if (*ctx.filename == '@' || *ctx.filename == '=') - ctx.filename++; - else - ctx.filename = "(string)"; - gdbjit_buildobj(&ctx); - gdbjit_newentry(J->L, &ctx); -} - -/* Delete debug info for trace and notify GDB. */ -void lj_gdbjit_deltrace(jit_State *J, GCtrace *T) -{ - GDBJITentryobj *eo = (GDBJITentryobj *)T->gdbjit_entry; - if (eo) { - gdbjit_lock_acquire(); - if (eo->entry.prev_entry) - eo->entry.prev_entry->next_entry = eo->entry.next_entry; - else - __jit_debug_descriptor.first_entry = eo->entry.next_entry; - if (eo->entry.next_entry) - eo->entry.next_entry->prev_entry = eo->entry.prev_entry; - __jit_debug_descriptor.relevant_entry = &eo->entry; - __jit_debug_descriptor.action_flag = GDBJIT_UNREGISTER; - __jit_debug_register_code(); - gdbjit_lock_release(); - lj_mem_free(J2G(J), eo, eo->sz); - } -} - -#endif -#endif diff --git a/lib/LuaJIT/src/lj_gdbjit.h b/lib/LuaJIT/src/lj_gdbjit.h deleted file mode 100644 index bbaa156..0000000 --- a/lib/LuaJIT/src/lj_gdbjit.h +++ /dev/null @@ -1,22 +0,0 @@ -/* -** Client for the GDB JIT API. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_GDBJIT_H -#define _LJ_GDBJIT_H - -#include "lj_obj.h" -#include "lj_jit.h" - -#if LJ_HASJIT && defined(LUAJIT_USE_GDBJIT) - -LJ_FUNC void lj_gdbjit_addtrace(jit_State *J, GCtrace *T); -LJ_FUNC void lj_gdbjit_deltrace(jit_State *J, GCtrace *T); - -#else -#define lj_gdbjit_addtrace(J, T) UNUSED(T) -#define lj_gdbjit_deltrace(J, T) UNUSED(T) -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_ir.c b/lib/LuaJIT/src/lj_ir.c deleted file mode 100644 index 5baece6..0000000 --- a/lib/LuaJIT/src/lj_ir.c +++ /dev/null @@ -1,494 +0,0 @@ -/* -** SSA IR (Intermediate Representation) emitter. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_ir_c -#define LUA_CORE - -/* For pointers to libc/libm functions. */ -#include -#include - -#include "lj_obj.h" - -#if LJ_HASJIT - -#include "lj_gc.h" -#include "lj_buf.h" -#include "lj_str.h" -#include "lj_tab.h" -#include "lj_ir.h" -#include "lj_jit.h" -#include "lj_ircall.h" -#include "lj_iropt.h" -#include "lj_trace.h" -#if LJ_HASFFI -#include "lj_ctype.h" -#include "lj_cdata.h" -#include "lj_carith.h" -#endif -#include "lj_vm.h" -#include "lj_strscan.h" -#include "lj_strfmt.h" -#include "lj_lib.h" - -/* Some local macros to save typing. Undef'd at the end. */ -#define IR(ref) (&J->cur.ir[(ref)]) -#define fins (&J->fold.ins) - -/* Pass IR on to next optimization in chain (FOLD). */ -#define emitir(ot, a, b) (lj_ir_set(J, (ot), (a), (b)), lj_opt_fold(J)) - -/* -- IR tables ----------------------------------------------------------- */ - -/* IR instruction modes. */ -LJ_DATADEF const uint8_t lj_ir_mode[IR__MAX+1] = { -IRDEF(IRMODE) - 0 -}; - -/* IR type sizes. */ -LJ_DATADEF const uint8_t lj_ir_type_size[IRT__MAX+1] = { -#define IRTSIZE(name, size) size, -IRTDEF(IRTSIZE) -#undef IRTSIZE - 0 -}; - -/* C call info for CALL* instructions. */ -LJ_DATADEF const CCallInfo lj_ir_callinfo[] = { -#define IRCALLCI(cond, name, nargs, kind, type, flags) \ - { (ASMFunction)IRCALLCOND_##cond(name), \ - (nargs)|(CCI_CALL_##kind)|(IRT_##type<irbuf + J->irbotlim; - MSize szins = J->irtoplim - J->irbotlim; - if (szins) { - baseir = (IRIns *)lj_mem_realloc(J->L, baseir, szins*sizeof(IRIns), - 2*szins*sizeof(IRIns)); - J->irtoplim = J->irbotlim + 2*szins; - } else { - baseir = (IRIns *)lj_mem_realloc(J->L, NULL, 0, LJ_MIN_IRSZ*sizeof(IRIns)); - J->irbotlim = REF_BASE - LJ_MIN_IRSZ/4; - J->irtoplim = J->irbotlim + LJ_MIN_IRSZ; - } - J->cur.ir = J->irbuf = baseir - J->irbotlim; -} - -/* Grow IR buffer at the bottom or shift it up. */ -static void lj_ir_growbot(jit_State *J) -{ - IRIns *baseir = J->irbuf + J->irbotlim; - MSize szins = J->irtoplim - J->irbotlim; - lua_assert(szins != 0); - lua_assert(J->cur.nk == J->irbotlim || J->cur.nk-1 == J->irbotlim); - if (J->cur.nins + (szins >> 1) < J->irtoplim) { - /* More than half of the buffer is free on top: shift up by a quarter. */ - MSize ofs = szins >> 2; - memmove(baseir + ofs, baseir, (J->cur.nins - J->irbotlim)*sizeof(IRIns)); - J->irbotlim -= ofs; - J->irtoplim -= ofs; - J->cur.ir = J->irbuf = baseir - J->irbotlim; - } else { - /* Double the buffer size, but split the growth amongst top/bottom. */ - IRIns *newbase = lj_mem_newt(J->L, 2*szins*sizeof(IRIns), IRIns); - MSize ofs = szins >= 256 ? 128 : (szins >> 1); /* Limit bottom growth. */ - memcpy(newbase + ofs, baseir, (J->cur.nins - J->irbotlim)*sizeof(IRIns)); - lj_mem_free(G(J->L), baseir, szins*sizeof(IRIns)); - J->irbotlim -= ofs; - J->irtoplim = J->irbotlim + 2*szins; - J->cur.ir = J->irbuf = newbase - J->irbotlim; - } -} - -/* Emit IR without any optimizations. */ -TRef LJ_FASTCALL lj_ir_emit(jit_State *J) -{ - IRRef ref = lj_ir_nextins(J); - IRIns *ir = IR(ref); - IROp op = fins->o; - ir->prev = J->chain[op]; - J->chain[op] = (IRRef1)ref; - ir->o = op; - ir->op1 = fins->op1; - ir->op2 = fins->op2; - J->guardemit.irt |= fins->t.irt; - return TREF(ref, irt_t((ir->t = fins->t))); -} - -/* Emit call to a C function. */ -TRef lj_ir_call(jit_State *J, IRCallID id, ...) -{ - const CCallInfo *ci = &lj_ir_callinfo[id]; - uint32_t n = CCI_NARGS(ci); - TRef tr = TREF_NIL; - va_list argp; - va_start(argp, id); - if ((ci->flags & CCI_L)) n--; - if (n > 0) - tr = va_arg(argp, IRRef); - while (n-- > 1) - tr = emitir(IRT(IR_CARG, IRT_NIL), tr, va_arg(argp, IRRef)); - va_end(argp); - if (CCI_OP(ci) == IR_CALLS) - J->needsnap = 1; /* Need snapshot after call with side effect. */ - return emitir(CCI_OPTYPE(ci), tr, id); -} - -/* Load field of type t from GG_State + offset. Must be 32 bit aligned. */ -LJ_FUNC TRef lj_ir_ggfload(jit_State *J, IRType t, uintptr_t ofs) -{ - lua_assert((ofs & 3) == 0); - ofs >>= 2; - lua_assert(ofs >= IRFL__MAX && ofs <= 0x3ff); /* 10 bit FOLD key limit. */ - lj_ir_set(J, IRT(IR_FLOAD, t), REF_NIL, ofs); - return lj_opt_fold(J); -} - -/* -- Interning of constants ---------------------------------------------- */ - -/* -** IR instructions for constants are kept between J->cur.nk >= ref < REF_BIAS. -** They are chained like all other instructions, but grow downwards. -** The are interned (like strings in the VM) to facilitate reference -** comparisons. The same constant must get the same reference. -*/ - -/* Get ref of next IR constant and optionally grow IR. -** Note: this may invalidate all IRIns *! -*/ -static LJ_AINLINE IRRef ir_nextk(jit_State *J) -{ - IRRef ref = J->cur.nk; - if (LJ_UNLIKELY(ref <= J->irbotlim)) lj_ir_growbot(J); - J->cur.nk = --ref; - return ref; -} - -/* Get ref of next 64 bit IR constant and optionally grow IR. -** Note: this may invalidate all IRIns *! -*/ -static LJ_AINLINE IRRef ir_nextk64(jit_State *J) -{ - IRRef ref = J->cur.nk - 2; - lua_assert(J->state != LJ_TRACE_ASM); - if (LJ_UNLIKELY(ref < J->irbotlim)) lj_ir_growbot(J); - J->cur.nk = ref; - return ref; -} - -#if LJ_GC64 -#define ir_nextkgc ir_nextk64 -#else -#define ir_nextkgc ir_nextk -#endif - -/* Intern int32_t constant. */ -TRef LJ_FASTCALL lj_ir_kint(jit_State *J, int32_t k) -{ - IRIns *ir, *cir = J->cur.ir; - IRRef ref; - for (ref = J->chain[IR_KINT]; ref; ref = cir[ref].prev) - if (cir[ref].i == k) - goto found; - ref = ir_nextk(J); - ir = IR(ref); - ir->i = k; - ir->t.irt = IRT_INT; - ir->o = IR_KINT; - ir->prev = J->chain[IR_KINT]; - J->chain[IR_KINT] = (IRRef1)ref; -found: - return TREF(ref, IRT_INT); -} - -/* Intern 64 bit constant, given by its 64 bit pattern. */ -TRef lj_ir_k64(jit_State *J, IROp op, uint64_t u64) -{ - IRIns *ir, *cir = J->cur.ir; - IRRef ref; - IRType t = op == IR_KNUM ? IRT_NUM : IRT_I64; - for (ref = J->chain[op]; ref; ref = cir[ref].prev) - if (ir_k64(&cir[ref])->u64 == u64) - goto found; - ref = ir_nextk64(J); - ir = IR(ref); - ir[1].tv.u64 = u64; - ir->t.irt = t; - ir->o = op; - ir->op12 = 0; - ir->prev = J->chain[op]; - J->chain[op] = (IRRef1)ref; -found: - return TREF(ref, t); -} - -/* Intern FP constant, given by its 64 bit pattern. */ -TRef lj_ir_knum_u64(jit_State *J, uint64_t u64) -{ - return lj_ir_k64(J, IR_KNUM, u64); -} - -/* Intern 64 bit integer constant. */ -TRef lj_ir_kint64(jit_State *J, uint64_t u64) -{ - return lj_ir_k64(J, IR_KINT64, u64); -} - -/* Check whether a number is int and return it. -0 is NOT considered an int. */ -static int numistrueint(lua_Number n, int32_t *kp) -{ - int32_t k = lj_num2int(n); - if (n == (lua_Number)k) { - if (kp) *kp = k; - if (k == 0) { /* Special check for -0. */ - TValue tv; - setnumV(&tv, n); - if (tv.u32.hi != 0) - return 0; - } - return 1; - } - return 0; -} - -/* Intern number as int32_t constant if possible, otherwise as FP constant. */ -TRef lj_ir_knumint(jit_State *J, lua_Number n) -{ - int32_t k; - if (numistrueint(n, &k)) - return lj_ir_kint(J, k); - else - return lj_ir_knum(J, n); -} - -/* Intern GC object "constant". */ -TRef lj_ir_kgc(jit_State *J, GCobj *o, IRType t) -{ - IRIns *ir, *cir = J->cur.ir; - IRRef ref; - lua_assert(!isdead(J2G(J), o)); - for (ref = J->chain[IR_KGC]; ref; ref = cir[ref].prev) - if (ir_kgc(&cir[ref]) == o) - goto found; - ref = ir_nextkgc(J); - ir = IR(ref); - /* NOBARRIER: Current trace is a GC root. */ - ir->op12 = 0; - setgcref(ir[LJ_GC64].gcr, o); - ir->t.irt = (uint8_t)t; - ir->o = IR_KGC; - ir->prev = J->chain[IR_KGC]; - J->chain[IR_KGC] = (IRRef1)ref; -found: - return TREF(ref, t); -} - -/* Allocate GCtrace constant placeholder (no interning). */ -TRef lj_ir_ktrace(jit_State *J) -{ - IRRef ref = ir_nextkgc(J); - IRIns *ir = IR(ref); - lua_assert(irt_toitype_(IRT_P64) == LJ_TTRACE); - ir->t.irt = IRT_P64; - ir->o = LJ_GC64 ? IR_KNUM : IR_KNULL; /* Not IR_KGC yet, but same size. */ - ir->op12 = 0; - ir->prev = 0; - return TREF(ref, IRT_P64); -} - -/* Intern pointer constant. */ -TRef lj_ir_kptr_(jit_State *J, IROp op, void *ptr) -{ - IRIns *ir, *cir = J->cur.ir; - IRRef ref; -#if LJ_64 && !LJ_GC64 - lua_assert((void *)(uintptr_t)u32ptr(ptr) == ptr); -#endif - for (ref = J->chain[op]; ref; ref = cir[ref].prev) - if (ir_kptr(&cir[ref]) == ptr) - goto found; -#if LJ_GC64 - ref = ir_nextk64(J); -#else - ref = ir_nextk(J); -#endif - ir = IR(ref); - ir->op12 = 0; - setmref(ir[LJ_GC64].ptr, ptr); - ir->t.irt = IRT_PGC; - ir->o = op; - ir->prev = J->chain[op]; - J->chain[op] = (IRRef1)ref; -found: - return TREF(ref, IRT_PGC); -} - -/* Intern typed NULL constant. */ -TRef lj_ir_knull(jit_State *J, IRType t) -{ - IRIns *ir, *cir = J->cur.ir; - IRRef ref; - for (ref = J->chain[IR_KNULL]; ref; ref = cir[ref].prev) - if (irt_t(cir[ref].t) == t) - goto found; - ref = ir_nextk(J); - ir = IR(ref); - ir->i = 0; - ir->t.irt = (uint8_t)t; - ir->o = IR_KNULL; - ir->prev = J->chain[IR_KNULL]; - J->chain[IR_KNULL] = (IRRef1)ref; -found: - return TREF(ref, t); -} - -/* Intern key slot. */ -TRef lj_ir_kslot(jit_State *J, TRef key, IRRef slot) -{ - IRIns *ir, *cir = J->cur.ir; - IRRef2 op12 = IRREF2((IRRef1)key, (IRRef1)slot); - IRRef ref; - /* Const part is not touched by CSE/DCE, so 0-65535 is ok for IRMlit here. */ - lua_assert(tref_isk(key) && slot == (IRRef)(IRRef1)slot); - for (ref = J->chain[IR_KSLOT]; ref; ref = cir[ref].prev) - if (cir[ref].op12 == op12) - goto found; - ref = ir_nextk(J); - ir = IR(ref); - ir->op12 = op12; - ir->t.irt = IRT_P32; - ir->o = IR_KSLOT; - ir->prev = J->chain[IR_KSLOT]; - J->chain[IR_KSLOT] = (IRRef1)ref; -found: - return TREF(ref, IRT_P32); -} - -/* -- Access to IR constants ---------------------------------------------- */ - -/* Copy value of IR constant. */ -void lj_ir_kvalue(lua_State *L, TValue *tv, const IRIns *ir) -{ - UNUSED(L); - lua_assert(ir->o != IR_KSLOT); /* Common mistake. */ - switch (ir->o) { - case IR_KPRI: setpriV(tv, irt_toitype(ir->t)); break; - case IR_KINT: setintV(tv, ir->i); break; - case IR_KGC: setgcV(L, tv, ir_kgc(ir), irt_toitype(ir->t)); break; - case IR_KPTR: case IR_KKPTR: setlightudV(tv, ir_kptr(ir)); break; - case IR_KNULL: setlightudV(tv, NULL); break; - case IR_KNUM: setnumV(tv, ir_knum(ir)->n); break; -#if LJ_HASFFI - case IR_KINT64: { - GCcdata *cd = lj_cdata_new_(L, CTID_INT64, 8); - *(uint64_t *)cdataptr(cd) = ir_kint64(ir)->u64; - setcdataV(L, tv, cd); - break; - } -#endif - default: lua_assert(0); break; - } -} - -/* -- Convert IR operand types -------------------------------------------- */ - -/* Convert from string to number. */ -TRef LJ_FASTCALL lj_ir_tonumber(jit_State *J, TRef tr) -{ - if (!tref_isnumber(tr)) { - if (tref_isstr(tr)) - tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0); - else - lj_trace_err(J, LJ_TRERR_BADTYPE); - } - return tr; -} - -/* Convert from integer or string to number. */ -TRef LJ_FASTCALL lj_ir_tonum(jit_State *J, TRef tr) -{ - if (!tref_isnum(tr)) { - if (tref_isinteger(tr)) - tr = emitir(IRTN(IR_CONV), tr, IRCONV_NUM_INT); - else if (tref_isstr(tr)) - tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0); - else - lj_trace_err(J, LJ_TRERR_BADTYPE); - } - return tr; -} - -/* Convert from integer or number to string. */ -TRef LJ_FASTCALL lj_ir_tostr(jit_State *J, TRef tr) -{ - if (!tref_isstr(tr)) { - if (!tref_isnumber(tr)) - lj_trace_err(J, LJ_TRERR_BADTYPE); - tr = emitir(IRT(IR_TOSTR, IRT_STR), tr, - tref_isnum(tr) ? IRTOSTR_NUM : IRTOSTR_INT); - } - return tr; -} - -/* -- Miscellaneous IR ops ------------------------------------------------ */ - -/* Evaluate numeric comparison. */ -int lj_ir_numcmp(lua_Number a, lua_Number b, IROp op) -{ - switch (op) { - case IR_EQ: return (a == b); - case IR_NE: return (a != b); - case IR_LT: return (a < b); - case IR_GE: return (a >= b); - case IR_LE: return (a <= b); - case IR_GT: return (a > b); - case IR_ULT: return !(a >= b); - case IR_UGE: return !(a < b); - case IR_ULE: return !(a > b); - case IR_UGT: return !(a <= b); - default: lua_assert(0); return 0; - } -} - -/* Evaluate string comparison. */ -int lj_ir_strcmp(GCstr *a, GCstr *b, IROp op) -{ - int res = lj_str_cmp(a, b); - switch (op) { - case IR_LT: return (res < 0); - case IR_GE: return (res >= 0); - case IR_LE: return (res <= 0); - case IR_GT: return (res > 0); - default: lua_assert(0); return 0; - } -} - -/* Rollback IR to previous state. */ -void lj_ir_rollback(jit_State *J, IRRef ref) -{ - IRRef nins = J->cur.nins; - while (nins > ref) { - IRIns *ir; - nins--; - ir = IR(nins); - J->chain[ir->o] = ir->prev; - } - J->cur.nins = nins; -} - -#undef IR -#undef fins -#undef emitir - -#endif diff --git a/lib/LuaJIT/src/lj_ir.h b/lib/LuaJIT/src/lj_ir.h deleted file mode 100644 index 8057a75..0000000 --- a/lib/LuaJIT/src/lj_ir.h +++ /dev/null @@ -1,590 +0,0 @@ -/* -** SSA IR (Intermediate Representation) format. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_IR_H -#define _LJ_IR_H - -#include "lj_obj.h" - -/* -- IR instructions ----------------------------------------------------- */ - -/* IR instruction definition. Order matters, see below. ORDER IR */ -#define IRDEF(_) \ - /* Guarded assertions. */ \ - /* Must be properly aligned to flip opposites (^1) and (un)ordered (^4). */ \ - _(LT, N , ref, ref) \ - _(GE, N , ref, ref) \ - _(LE, N , ref, ref) \ - _(GT, N , ref, ref) \ - \ - _(ULT, N , ref, ref) \ - _(UGE, N , ref, ref) \ - _(ULE, N , ref, ref) \ - _(UGT, N , ref, ref) \ - \ - _(EQ, C , ref, ref) \ - _(NE, C , ref, ref) \ - \ - _(ABC, N , ref, ref) \ - _(RETF, S , ref, ref) \ - \ - /* Miscellaneous ops. */ \ - _(NOP, N , ___, ___) \ - _(BASE, N , lit, lit) \ - _(PVAL, N , lit, ___) \ - _(GCSTEP, S , ___, ___) \ - _(HIOP, S , ref, ref) \ - _(LOOP, S , ___, ___) \ - _(USE, S , ref, ___) \ - _(PHI, S , ref, ref) \ - _(RENAME, S , ref, lit) \ - _(PROF, S , ___, ___) \ - \ - /* Constants. */ \ - _(KPRI, N , ___, ___) \ - _(KINT, N , cst, ___) \ - _(KGC, N , cst, ___) \ - _(KPTR, N , cst, ___) \ - _(KKPTR, N , cst, ___) \ - _(KNULL, N , cst, ___) \ - _(KNUM, N , cst, ___) \ - _(KINT64, N , cst, ___) \ - _(KSLOT, N , ref, lit) \ - \ - /* Bit ops. */ \ - _(BNOT, N , ref, ___) \ - _(BSWAP, N , ref, ___) \ - _(BAND, C , ref, ref) \ - _(BOR, C , ref, ref) \ - _(BXOR, C , ref, ref) \ - _(BSHL, N , ref, ref) \ - _(BSHR, N , ref, ref) \ - _(BSAR, N , ref, ref) \ - _(BROL, N , ref, ref) \ - _(BROR, N , ref, ref) \ - \ - /* Arithmetic ops. ORDER ARITH */ \ - _(ADD, C , ref, ref) \ - _(SUB, N , ref, ref) \ - _(MUL, C , ref, ref) \ - _(DIV, N , ref, ref) \ - _(MOD, N , ref, ref) \ - _(POW, N , ref, ref) \ - _(NEG, N , ref, ref) \ - \ - _(ABS, N , ref, ref) \ - _(ATAN2, N , ref, ref) \ - _(LDEXP, N , ref, ref) \ - _(MIN, C , ref, ref) \ - _(MAX, C , ref, ref) \ - _(FPMATH, N , ref, lit) \ - \ - /* Overflow-checking arithmetic ops. */ \ - _(ADDOV, CW, ref, ref) \ - _(SUBOV, NW, ref, ref) \ - _(MULOV, CW, ref, ref) \ - \ - /* Memory ops. A = array, H = hash, U = upvalue, F = field, S = stack. */ \ - \ - /* Memory references. */ \ - _(AREF, R , ref, ref) \ - _(HREFK, R , ref, ref) \ - _(HREF, L , ref, ref) \ - _(NEWREF, S , ref, ref) \ - _(UREFO, LW, ref, lit) \ - _(UREFC, LW, ref, lit) \ - _(FREF, R , ref, lit) \ - _(STRREF, N , ref, ref) \ - _(LREF, L , ___, ___) \ - \ - /* Loads and Stores. These must be in the same order. */ \ - _(ALOAD, L , ref, ___) \ - _(HLOAD, L , ref, ___) \ - _(ULOAD, L , ref, ___) \ - _(FLOAD, L , ref, lit) \ - _(XLOAD, L , ref, lit) \ - _(SLOAD, L , lit, lit) \ - _(VLOAD, L , ref, ___) \ - \ - _(ASTORE, S , ref, ref) \ - _(HSTORE, S , ref, ref) \ - _(USTORE, S , ref, ref) \ - _(FSTORE, S , ref, ref) \ - _(XSTORE, S , ref, ref) \ - \ - /* Allocations. */ \ - _(SNEW, N , ref, ref) /* CSE is ok, not marked as A. */ \ - _(XSNEW, A , ref, ref) \ - _(TNEW, AW, lit, lit) \ - _(TDUP, AW, ref, ___) \ - _(CNEW, AW, ref, ref) \ - _(CNEWI, NW, ref, ref) /* CSE is ok, not marked as A. */ \ - \ - /* Buffer operations. */ \ - _(BUFHDR, L , ref, lit) \ - _(BUFPUT, L , ref, ref) \ - _(BUFSTR, A , ref, ref) \ - \ - /* Barriers. */ \ - _(TBAR, S , ref, ___) \ - _(OBAR, S , ref, ref) \ - _(XBAR, S , ___, ___) \ - \ - /* Type conversions. */ \ - _(CONV, NW, ref, lit) \ - _(TOBIT, N , ref, ref) \ - _(TOSTR, N , ref, lit) \ - _(STRTO, N , ref, ___) \ - \ - /* Calls. */ \ - _(CALLN, N , ref, lit) \ - _(CALLA, A , ref, lit) \ - _(CALLL, L , ref, lit) \ - _(CALLS, S , ref, lit) \ - _(CALLXS, S , ref, ref) \ - _(CARG, N , ref, ref) \ - \ - /* End of list. */ - -/* IR opcodes (max. 256). */ -typedef enum { -#define IRENUM(name, m, m1, m2) IR_##name, -IRDEF(IRENUM) -#undef IRENUM - IR__MAX -} IROp; - -/* Stored opcode. */ -typedef uint8_t IROp1; - -LJ_STATIC_ASSERT(((int)IR_EQ^1) == (int)IR_NE); -LJ_STATIC_ASSERT(((int)IR_LT^1) == (int)IR_GE); -LJ_STATIC_ASSERT(((int)IR_LE^1) == (int)IR_GT); -LJ_STATIC_ASSERT(((int)IR_LT^3) == (int)IR_GT); -LJ_STATIC_ASSERT(((int)IR_LT^4) == (int)IR_ULT); - -/* Delta between xLOAD and xSTORE. */ -#define IRDELTA_L2S ((int)IR_ASTORE - (int)IR_ALOAD) - -LJ_STATIC_ASSERT((int)IR_HLOAD + IRDELTA_L2S == (int)IR_HSTORE); -LJ_STATIC_ASSERT((int)IR_ULOAD + IRDELTA_L2S == (int)IR_USTORE); -LJ_STATIC_ASSERT((int)IR_FLOAD + IRDELTA_L2S == (int)IR_FSTORE); -LJ_STATIC_ASSERT((int)IR_XLOAD + IRDELTA_L2S == (int)IR_XSTORE); - -/* -- Named IR literals --------------------------------------------------- */ - -/* FPMATH sub-functions. ORDER FPM. */ -#define IRFPMDEF(_) \ - _(FLOOR) _(CEIL) _(TRUNC) /* Must be first and in this order. */ \ - _(SQRT) _(EXP) _(EXP2) _(LOG) _(LOG2) _(LOG10) \ - _(SIN) _(COS) _(TAN) \ - _(OTHER) - -typedef enum { -#define FPMENUM(name) IRFPM_##name, -IRFPMDEF(FPMENUM) -#undef FPMENUM - IRFPM__MAX -} IRFPMathOp; - -/* FLOAD fields. */ -#define IRFLDEF(_) \ - _(STR_LEN, offsetof(GCstr, len)) \ - _(FUNC_ENV, offsetof(GCfunc, l.env)) \ - _(FUNC_PC, offsetof(GCfunc, l.pc)) \ - _(FUNC_FFID, offsetof(GCfunc, l.ffid)) \ - _(THREAD_ENV, offsetof(lua_State, env)) \ - _(TAB_META, offsetof(GCtab, metatable)) \ - _(TAB_ARRAY, offsetof(GCtab, array)) \ - _(TAB_NODE, offsetof(GCtab, node)) \ - _(TAB_ASIZE, offsetof(GCtab, asize)) \ - _(TAB_HMASK, offsetof(GCtab, hmask)) \ - _(TAB_NOMM, offsetof(GCtab, nomm)) \ - _(UDATA_META, offsetof(GCudata, metatable)) \ - _(UDATA_UDTYPE, offsetof(GCudata, udtype)) \ - _(UDATA_FILE, sizeof(GCudata)) \ - _(CDATA_CTYPEID, offsetof(GCcdata, ctypeid)) \ - _(CDATA_PTR, sizeof(GCcdata)) \ - _(CDATA_INT, sizeof(GCcdata)) \ - _(CDATA_INT64, sizeof(GCcdata)) \ - _(CDATA_INT64_4, sizeof(GCcdata) + 4) - -typedef enum { -#define FLENUM(name, ofs) IRFL_##name, -IRFLDEF(FLENUM) -#undef FLENUM - IRFL__MAX -} IRFieldID; - -/* SLOAD mode bits, stored in op2. */ -#define IRSLOAD_PARENT 0x01 /* Coalesce with parent trace. */ -#define IRSLOAD_FRAME 0x02 /* Load 32 bits of ftsz. */ -#define IRSLOAD_TYPECHECK 0x04 /* Needs type check. */ -#define IRSLOAD_CONVERT 0x08 /* Number to integer conversion. */ -#define IRSLOAD_READONLY 0x10 /* Read-only, omit slot store. */ -#define IRSLOAD_INHERIT 0x20 /* Inherited by exits/side traces. */ - -/* XLOAD mode, stored in op2. */ -#define IRXLOAD_READONLY 1 /* Load from read-only data. */ -#define IRXLOAD_VOLATILE 2 /* Load from volatile data. */ -#define IRXLOAD_UNALIGNED 4 /* Unaligned load. */ - -/* BUFHDR mode, stored in op2. */ -#define IRBUFHDR_RESET 0 /* Reset buffer. */ -#define IRBUFHDR_APPEND 1 /* Append to buffer. */ - -/* CONV mode, stored in op2. */ -#define IRCONV_SRCMASK 0x001f /* Source IRType. */ -#define IRCONV_DSTMASK 0x03e0 /* Dest. IRType (also in ir->t). */ -#define IRCONV_DSH 5 -#define IRCONV_NUM_INT ((IRT_NUM<>2)&3)) -#define irm_iscomm(m) ((m) & IRM_C) -#define irm_kind(m) ((m) & IRM_S) - -#define IRMODE(name, m, m1, m2) (((IRM##m1)|((IRM##m2)<<2)|(IRM_##m))^IRM_W), - -LJ_DATA const uint8_t lj_ir_mode[IR__MAX+1]; - -/* -- IR instruction types ------------------------------------------------ */ - -#define IRTSIZE_PGC (LJ_GC64 ? 8 : 4) - -/* Map of itypes to non-negative numbers and their sizes. ORDER LJ_T. -** LJ_TUPVAL/LJ_TTRACE never appear in a TValue. Use these itypes for -** IRT_P32 and IRT_P64, which never escape the IR. -** The various integers are only used in the IR and can only escape to -** a TValue after implicit or explicit conversion. Their types must be -** contiguous and next to IRT_NUM (see the typerange macros below). -*/ -#define IRTDEF(_) \ - _(NIL, 4) _(FALSE, 4) _(TRUE, 4) _(LIGHTUD, LJ_64 ? 8 : 4) \ - _(STR, IRTSIZE_PGC) _(P32, 4) _(THREAD, IRTSIZE_PGC) _(PROTO, IRTSIZE_PGC) \ - _(FUNC, IRTSIZE_PGC) _(P64, 8) _(CDATA, IRTSIZE_PGC) _(TAB, IRTSIZE_PGC) \ - _(UDATA, IRTSIZE_PGC) \ - _(FLOAT, 4) _(NUM, 8) _(I8, 1) _(U8, 1) _(I16, 2) _(U16, 2) \ - _(INT, 4) _(U32, 4) _(I64, 8) _(U64, 8) \ - _(SOFTFP, 4) /* There is room for 8 more types. */ - -/* IR result type and flags (8 bit). */ -typedef enum { -#define IRTENUM(name, size) IRT_##name, -IRTDEF(IRTENUM) -#undef IRTENUM - IRT__MAX, - - /* Native pointer type and the corresponding integer type. */ - IRT_PTR = LJ_64 ? IRT_P64 : IRT_P32, - IRT_PGC = LJ_GC64 ? IRT_P64 : IRT_P32, - IRT_IGC = LJ_GC64 ? IRT_I64 : IRT_INT, - IRT_INTP = LJ_64 ? IRT_I64 : IRT_INT, - IRT_UINTP = LJ_64 ? IRT_U64 : IRT_U32, - - /* Additional flags. */ - IRT_MARK = 0x20, /* Marker for misc. purposes. */ - IRT_ISPHI = 0x40, /* Instruction is left or right PHI operand. */ - IRT_GUARD = 0x80, /* Instruction is a guard. */ - - /* Masks. */ - IRT_TYPE = 0x1f, - IRT_T = 0xff -} IRType; - -#define irtype_ispri(irt) ((uint32_t)(irt) <= IRT_TRUE) - -/* Stored IRType. */ -typedef struct IRType1 { uint8_t irt; } IRType1; - -#define IRT(o, t) ((uint32_t)(((o)<<8) | (t))) -#define IRTI(o) (IRT((o), IRT_INT)) -#define IRTN(o) (IRT((o), IRT_NUM)) -#define IRTG(o, t) (IRT((o), IRT_GUARD|(t))) -#define IRTGI(o) (IRT((o), IRT_GUARD|IRT_INT)) - -#define irt_t(t) ((IRType)(t).irt) -#define irt_type(t) ((IRType)((t).irt & IRT_TYPE)) -#define irt_sametype(t1, t2) ((((t1).irt ^ (t2).irt) & IRT_TYPE) == 0) -#define irt_typerange(t, first, last) \ - ((uint32_t)((t).irt & IRT_TYPE) - (uint32_t)(first) <= (uint32_t)(last-first)) - -#define irt_isnil(t) (irt_type(t) == IRT_NIL) -#define irt_ispri(t) ((uint32_t)irt_type(t) <= IRT_TRUE) -#define irt_islightud(t) (irt_type(t) == IRT_LIGHTUD) -#define irt_isstr(t) (irt_type(t) == IRT_STR) -#define irt_istab(t) (irt_type(t) == IRT_TAB) -#define irt_iscdata(t) (irt_type(t) == IRT_CDATA) -#define irt_isfloat(t) (irt_type(t) == IRT_FLOAT) -#define irt_isnum(t) (irt_type(t) == IRT_NUM) -#define irt_isint(t) (irt_type(t) == IRT_INT) -#define irt_isi8(t) (irt_type(t) == IRT_I8) -#define irt_isu8(t) (irt_type(t) == IRT_U8) -#define irt_isi16(t) (irt_type(t) == IRT_I16) -#define irt_isu16(t) (irt_type(t) == IRT_U16) -#define irt_isu32(t) (irt_type(t) == IRT_U32) -#define irt_isi64(t) (irt_type(t) == IRT_I64) -#define irt_isu64(t) (irt_type(t) == IRT_U64) - -#define irt_isfp(t) (irt_isnum(t) || irt_isfloat(t)) -#define irt_isinteger(t) (irt_typerange((t), IRT_I8, IRT_INT)) -#define irt_isgcv(t) (irt_typerange((t), IRT_STR, IRT_UDATA)) -#define irt_isaddr(t) (irt_typerange((t), IRT_LIGHTUD, IRT_UDATA)) -#define irt_isint64(t) (irt_typerange((t), IRT_I64, IRT_U64)) - -#if LJ_GC64 -/* Include IRT_NIL, so IR(ASMREF_L) (aka REF_NIL) is considered 64 bit. */ -#define IRT_IS64 \ - ((1u<> irt_type(t)) & 1) -#define irt_is64orfp(t) (((IRT_IS64|(1u<>irt_type(t)) & 1) - -#define irt_size(t) (lj_ir_type_size[irt_t((t))]) - -LJ_DATA const uint8_t lj_ir_type_size[]; - -static LJ_AINLINE IRType itype2irt(const TValue *tv) -{ - if (tvisint(tv)) - return IRT_INT; - else if (tvisnum(tv)) - return IRT_NUM; -#if LJ_64 && !LJ_GC64 - else if (tvislightud(tv)) - return IRT_LIGHTUD; -#endif - else - return (IRType)~itype(tv); -} - -static LJ_AINLINE uint32_t irt_toitype_(IRType t) -{ - lua_assert(!LJ_64 || LJ_GC64 || t != IRT_LIGHTUD); - if (LJ_DUALNUM && t > IRT_NUM) { - return LJ_TISNUM; - } else { - lua_assert(t <= IRT_NUM); - return ~(uint32_t)t; - } -} - -#define irt_toitype(t) irt_toitype_(irt_type((t))) - -#define irt_isguard(t) ((t).irt & IRT_GUARD) -#define irt_ismarked(t) ((t).irt & IRT_MARK) -#define irt_setmark(t) ((t).irt |= IRT_MARK) -#define irt_clearmark(t) ((t).irt &= ~IRT_MARK) -#define irt_isphi(t) ((t).irt & IRT_ISPHI) -#define irt_setphi(t) ((t).irt |= IRT_ISPHI) -#define irt_clearphi(t) ((t).irt &= ~IRT_ISPHI) - -/* Stored combined IR opcode and type. */ -typedef uint16_t IROpT; - -/* -- IR references ------------------------------------------------------- */ - -/* IR references. */ -typedef uint16_t IRRef1; /* One stored reference. */ -typedef uint32_t IRRef2; /* Two stored references. */ -typedef uint32_t IRRef; /* Used to pass around references. */ - -/* Fixed references. */ -enum { - REF_BIAS = 0x8000, - REF_TRUE = REF_BIAS-3, - REF_FALSE = REF_BIAS-2, - REF_NIL = REF_BIAS-1, /* \--- Constants grow downwards. */ - REF_BASE = REF_BIAS, /* /--- IR grows upwards. */ - REF_FIRST = REF_BIAS+1, - REF_DROP = 0xffff -}; - -/* Note: IRMlit operands must be < REF_BIAS, too! -** This allows for fast and uniform manipulation of all operands -** without looking up the operand mode in lj_ir_mode: -** - CSE calculates the maximum reference of two operands. -** This must work with mixed reference/literal operands, too. -** - DCE marking only checks for operand >= REF_BIAS. -** - LOOP needs to substitute reference operands. -** Constant references and literals must not be modified. -*/ - -#define IRREF2(lo, hi) ((IRRef2)(lo) | ((IRRef2)(hi) << 16)) - -#define irref_isk(ref) ((ref) < REF_BIAS) - -/* Tagged IR references (32 bit). -** -** +-------+-------+---------------+ -** | irt | flags | ref | -** +-------+-------+---------------+ -** -** The tag holds a copy of the IRType and speeds up IR type checks. -*/ -typedef uint32_t TRef; - -#define TREF_REFMASK 0x0000ffff -#define TREF_FRAME 0x00010000 -#define TREF_CONT 0x00020000 - -#define TREF(ref, t) ((TRef)((ref) + ((t)<<24))) - -#define tref_ref(tr) ((IRRef1)(tr)) -#define tref_t(tr) ((IRType)((tr)>>24)) -#define tref_type(tr) ((IRType)(((tr)>>24) & IRT_TYPE)) -#define tref_typerange(tr, first, last) \ - ((((tr)>>24) & IRT_TYPE) - (TRef)(first) <= (TRef)(last-first)) - -#define tref_istype(tr, t) (((tr) & (IRT_TYPE<<24)) == ((t)<<24)) -#define tref_isnil(tr) (tref_istype((tr), IRT_NIL)) -#define tref_isfalse(tr) (tref_istype((tr), IRT_FALSE)) -#define tref_istrue(tr) (tref_istype((tr), IRT_TRUE)) -#define tref_islightud(tr) (tref_istype((tr), IRT_LIGHTUD)) -#define tref_isstr(tr) (tref_istype((tr), IRT_STR)) -#define tref_isfunc(tr) (tref_istype((tr), IRT_FUNC)) -#define tref_iscdata(tr) (tref_istype((tr), IRT_CDATA)) -#define tref_istab(tr) (tref_istype((tr), IRT_TAB)) -#define tref_isudata(tr) (tref_istype((tr), IRT_UDATA)) -#define tref_isnum(tr) (tref_istype((tr), IRT_NUM)) -#define tref_isint(tr) (tref_istype((tr), IRT_INT)) - -#define tref_isbool(tr) (tref_typerange((tr), IRT_FALSE, IRT_TRUE)) -#define tref_ispri(tr) (tref_typerange((tr), IRT_NIL, IRT_TRUE)) -#define tref_istruecond(tr) (!tref_typerange((tr), IRT_NIL, IRT_FALSE)) -#define tref_isinteger(tr) (tref_typerange((tr), IRT_I8, IRT_INT)) -#define tref_isnumber(tr) (tref_typerange((tr), IRT_NUM, IRT_INT)) -#define tref_isnumber_str(tr) (tref_isnumber((tr)) || tref_isstr((tr))) -#define tref_isgcv(tr) (tref_typerange((tr), IRT_STR, IRT_UDATA)) - -#define tref_isk(tr) (irref_isk(tref_ref((tr)))) -#define tref_isk2(tr1, tr2) (irref_isk(tref_ref((tr1) | (tr2)))) - -#define TREF_PRI(t) (TREF(REF_NIL-(t), (t))) -#define TREF_NIL (TREF_PRI(IRT_NIL)) -#define TREF_FALSE (TREF_PRI(IRT_FALSE)) -#define TREF_TRUE (TREF_PRI(IRT_TRUE)) - -/* -- IR format ----------------------------------------------------------- */ - -/* IR instruction format (64 bit). -** -** 16 16 8 8 8 8 -** +-------+-------+---+---+---+---+ -** | op1 | op2 | t | o | r | s | -** +-------+-------+---+---+---+---+ -** | op12/i/gco32 | ot | prev | (alternative fields in union) -** +-------+-------+---+---+---+---+ -** | TValue/gco64 | (2nd IR slot for 64 bit constants) -** +---------------+-------+-------+ -** 32 16 16 -** -** prev is only valid prior to register allocation and then reused for r + s. -*/ - -typedef union IRIns { - struct { - LJ_ENDIAN_LOHI( - IRRef1 op1; /* IR operand 1. */ - , IRRef1 op2; /* IR operand 2. */ - ) - IROpT ot; /* IR opcode and type (overlaps t and o). */ - IRRef1 prev; /* Previous ins in same chain (overlaps r and s). */ - }; - struct { - IRRef2 op12; /* IR operand 1 and 2 (overlaps op1 and op2). */ - LJ_ENDIAN_LOHI( - IRType1 t; /* IR type. */ - , IROp1 o; /* IR opcode. */ - ) - LJ_ENDIAN_LOHI( - uint8_t r; /* Register allocation (overlaps prev). */ - , uint8_t s; /* Spill slot allocation (overlaps prev). */ - ) - }; - int32_t i; /* 32 bit signed integer literal (overlaps op12). */ - GCRef gcr; /* GCobj constant (overlaps op12 or entire slot). */ - MRef ptr; /* Pointer constant (overlaps op12 or entire slot). */ - TValue tv; /* TValue constant (overlaps entire slot). */ -} IRIns; - -#define ir_kgc(ir) check_exp((ir)->o == IR_KGC, gcref((ir)[LJ_GC64].gcr)) -#define ir_kstr(ir) (gco2str(ir_kgc((ir)))) -#define ir_ktab(ir) (gco2tab(ir_kgc((ir)))) -#define ir_kfunc(ir) (gco2func(ir_kgc((ir)))) -#define ir_kcdata(ir) (gco2cd(ir_kgc((ir)))) -#define ir_knum(ir) check_exp((ir)->o == IR_KNUM, &(ir)[1].tv) -#define ir_kint64(ir) check_exp((ir)->o == IR_KINT64, &(ir)[1].tv) -#define ir_k64(ir) \ - check_exp((ir)->o == IR_KNUM || (ir)->o == IR_KINT64 || \ - (LJ_GC64 && \ - ((ir)->o == IR_KGC || \ - (ir)->o == IR_KPTR || (ir)->o == IR_KKPTR)), \ - &(ir)[1].tv) -#define ir_kptr(ir) \ - check_exp((ir)->o == IR_KPTR || (ir)->o == IR_KKPTR, \ - mref((ir)[LJ_GC64].ptr, void)) - -/* A store or any other op with a non-weak guard has a side-effect. */ -static LJ_AINLINE int ir_sideeff(IRIns *ir) -{ - return (((ir->t.irt | ~IRT_GUARD) & lj_ir_mode[ir->o]) >= IRM_S); -} - -LJ_STATIC_ASSERT((int)IRT_GUARD == (int)IRM_W); - -#endif diff --git a/lib/LuaJIT/src/lj_ircall.h b/lib/LuaJIT/src/lj_ircall.h deleted file mode 100644 index 9b3883b..0000000 --- a/lib/LuaJIT/src/lj_ircall.h +++ /dev/null @@ -1,358 +0,0 @@ -/* -** IR CALL* instruction definitions. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_IRCALL_H -#define _LJ_IRCALL_H - -#include "lj_obj.h" -#include "lj_ir.h" -#include "lj_jit.h" - -/* C call info for CALL* instructions. */ -typedef struct CCallInfo { - ASMFunction func; /* Function pointer. */ - uint32_t flags; /* Number of arguments and flags. */ -} CCallInfo; - -#define CCI_NARGS(ci) ((ci)->flags & 0xff) /* # of args. */ -#define CCI_NARGS_MAX 32 /* Max. # of args. */ - -#define CCI_OTSHIFT 16 -#define CCI_OPTYPE(ci) ((ci)->flags >> CCI_OTSHIFT) /* Get op/type. */ -#define CCI_OPSHIFT 24 -#define CCI_OP(ci) ((ci)->flags >> CCI_OPSHIFT) /* Get op. */ - -#define CCI_CALL_N (IR_CALLN << CCI_OPSHIFT) -#define CCI_CALL_A (IR_CALLA << CCI_OPSHIFT) -#define CCI_CALL_L (IR_CALLL << CCI_OPSHIFT) -#define CCI_CALL_S (IR_CALLS << CCI_OPSHIFT) -#define CCI_CALL_FN (CCI_CALL_N|CCI_CC_FASTCALL) -#define CCI_CALL_FL (CCI_CALL_L|CCI_CC_FASTCALL) -#define CCI_CALL_FS (CCI_CALL_S|CCI_CC_FASTCALL) - -/* C call info flags. */ -#define CCI_L 0x0100 /* Implicit L arg. */ -#define CCI_CASTU64 0x0200 /* Cast u64 result to number. */ -#define CCI_NOFPRCLOBBER 0x0400 /* Does not clobber any FPRs. */ -#define CCI_VARARG 0x0800 /* Vararg function. */ - -#define CCI_CC_MASK 0x3000 /* Calling convention mask. */ -#define CCI_CC_SHIFT 12 -/* ORDER CC */ -#define CCI_CC_CDECL 0x0000 /* Default cdecl calling convention. */ -#define CCI_CC_THISCALL 0x1000 /* Thiscall calling convention. */ -#define CCI_CC_FASTCALL 0x2000 /* Fastcall calling convention. */ -#define CCI_CC_STDCALL 0x3000 /* Stdcall calling convention. */ - -/* Extra args for SOFTFP, SPLIT 64 bit. */ -#define CCI_XARGS_SHIFT 14 -#define CCI_XARGS(ci) (((ci)->flags >> CCI_XARGS_SHIFT) & 3) -#define CCI_XA (1u << CCI_XARGS_SHIFT) - -#if LJ_SOFTFP32 || (LJ_32 && LJ_HASFFI) -#define CCI_XNARGS(ci) (CCI_NARGS((ci)) + CCI_XARGS((ci))) -#else -#define CCI_XNARGS(ci) CCI_NARGS((ci)) -#endif - -/* Helpers for conditional function definitions. */ -#define IRCALLCOND_ANY(x) x - -#if LJ_TARGET_X86ORX64 -#define IRCALLCOND_FPMATH(x) NULL -#else -#define IRCALLCOND_FPMATH(x) x -#endif - -#if LJ_SOFTFP -#define IRCALLCOND_SOFTFP(x) x -#if LJ_HASFFI -#define IRCALLCOND_SOFTFP_FFI(x) x -#else -#define IRCALLCOND_SOFTFP_FFI(x) NULL -#endif -#else -#define IRCALLCOND_SOFTFP(x) NULL -#define IRCALLCOND_SOFTFP_FFI(x) NULL -#endif - -#if LJ_SOFTFP && LJ_TARGET_MIPS -#define IRCALLCOND_SOFTFP_MIPS(x) x -#else -#define IRCALLCOND_SOFTFP_MIPS(x) NULL -#endif - -#if LJ_SOFTFP && LJ_TARGET_MIPS64 -#define IRCALLCOND_SOFTFP_MIPS64(x) x -#else -#define IRCALLCOND_SOFTFP_MIPS64(x) NULL -#endif - -#define LJ_NEED_FP64 (LJ_TARGET_ARM || LJ_TARGET_PPC || LJ_TARGET_MIPS) - -#if LJ_HASFFI && (LJ_SOFTFP || LJ_NEED_FP64) -#define IRCALLCOND_FP64_FFI(x) x -#else -#define IRCALLCOND_FP64_FFI(x) NULL -#endif - -#if LJ_HASFFI -#define IRCALLCOND_FFI(x) x -#if LJ_32 -#define IRCALLCOND_FFI32(x) x -#else -#define IRCALLCOND_FFI32(x) NULL -#endif -#else -#define IRCALLCOND_FFI(x) NULL -#define IRCALLCOND_FFI32(x) NULL -#endif - -#if LJ_SOFTFP -#define XA_FP CCI_XA -#define XA2_FP (CCI_XA+CCI_XA) -#else -#define XA_FP 0 -#define XA2_FP 0 -#endif - -#if LJ_SOFTFP32 -#define XA_FP32 CCI_XA -#define XA2_FP32 (CCI_XA+CCI_XA) -#else -#define XA_FP32 0 -#define XA2_FP32 0 -#endif - -#if LJ_32 -#define XA_64 CCI_XA -#define XA2_64 (CCI_XA+CCI_XA) -#else -#define XA_64 0 -#define XA2_64 0 -#endif - -/* Function definitions for CALL* instructions. */ -#define IRCALLDEF(_) \ - _(ANY, lj_str_cmp, 2, FN, INT, CCI_NOFPRCLOBBER) \ - _(ANY, lj_str_find, 4, N, PGC, 0) \ - _(ANY, lj_str_new, 3, S, STR, CCI_L) \ - _(ANY, lj_strscan_num, 2, FN, INT, 0) \ - _(ANY, lj_strfmt_int, 2, FN, STR, CCI_L) \ - _(ANY, lj_strfmt_num, 2, FN, STR, CCI_L) \ - _(ANY, lj_strfmt_char, 2, FN, STR, CCI_L) \ - _(ANY, lj_strfmt_putint, 2, FL, PGC, 0) \ - _(ANY, lj_strfmt_putnum, 2, FL, PGC, 0) \ - _(ANY, lj_strfmt_putquoted, 2, FL, PGC, 0) \ - _(ANY, lj_strfmt_putfxint, 3, L, PGC, XA_64) \ - _(ANY, lj_strfmt_putfnum_int, 3, L, PGC, XA_FP) \ - _(ANY, lj_strfmt_putfnum_uint, 3, L, PGC, XA_FP) \ - _(ANY, lj_strfmt_putfnum, 3, L, PGC, XA_FP) \ - _(ANY, lj_strfmt_putfstr, 3, L, PGC, 0) \ - _(ANY, lj_strfmt_putfchar, 3, L, PGC, 0) \ - _(ANY, lj_buf_putmem, 3, S, PGC, 0) \ - _(ANY, lj_buf_putstr, 2, FL, PGC, 0) \ - _(ANY, lj_buf_putchar, 2, FL, PGC, 0) \ - _(ANY, lj_buf_putstr_reverse, 2, FL, PGC, 0) \ - _(ANY, lj_buf_putstr_lower, 2, FL, PGC, 0) \ - _(ANY, lj_buf_putstr_upper, 2, FL, PGC, 0) \ - _(ANY, lj_buf_putstr_rep, 3, L, PGC, 0) \ - _(ANY, lj_buf_puttab, 5, L, PGC, 0) \ - _(ANY, lj_buf_tostr, 1, FL, STR, 0) \ - _(ANY, lj_tab_new_ah, 3, A, TAB, CCI_L) \ - _(ANY, lj_tab_new1, 2, FS, TAB, CCI_L) \ - _(ANY, lj_tab_dup, 2, FS, TAB, CCI_L) \ - _(ANY, lj_tab_clear, 1, FS, NIL, 0) \ - _(ANY, lj_tab_newkey, 3, S, PGC, CCI_L) \ - _(ANY, lj_tab_len, 1, FL, INT, 0) \ - _(ANY, lj_gc_step_jit, 2, FS, NIL, CCI_L) \ - _(ANY, lj_gc_barrieruv, 2, FS, NIL, 0) \ - _(ANY, lj_mem_newgco, 2, FS, PGC, CCI_L) \ - _(ANY, lj_math_random_step, 1, FS, NUM, CCI_CASTU64) \ - _(ANY, lj_vm_modi, 2, FN, INT, 0) \ - _(ANY, sinh, 1, N, NUM, XA_FP) \ - _(ANY, cosh, 1, N, NUM, XA_FP) \ - _(ANY, tanh, 1, N, NUM, XA_FP) \ - _(ANY, fputc, 2, S, INT, 0) \ - _(ANY, fwrite, 4, S, INT, 0) \ - _(ANY, fflush, 1, S, INT, 0) \ - /* ORDER FPM */ \ - _(FPMATH, lj_vm_floor, 1, N, NUM, XA_FP) \ - _(FPMATH, lj_vm_ceil, 1, N, NUM, XA_FP) \ - _(FPMATH, lj_vm_trunc, 1, N, NUM, XA_FP) \ - _(FPMATH, sqrt, 1, N, NUM, XA_FP) \ - _(ANY, exp, 1, N, NUM, XA_FP) \ - _(ANY, lj_vm_exp2, 1, N, NUM, XA_FP) \ - _(ANY, log, 1, N, NUM, XA_FP) \ - _(ANY, lj_vm_log2, 1, N, NUM, XA_FP) \ - _(ANY, log10, 1, N, NUM, XA_FP) \ - _(ANY, sin, 1, N, NUM, XA_FP) \ - _(ANY, cos, 1, N, NUM, XA_FP) \ - _(ANY, tan, 1, N, NUM, XA_FP) \ - _(ANY, lj_vm_powi, 2, N, NUM, XA_FP) \ - _(ANY, pow, 2, N, NUM, XA2_FP) \ - _(ANY, atan2, 2, N, NUM, XA2_FP) \ - _(ANY, ldexp, 2, N, NUM, XA_FP) \ - _(SOFTFP, lj_vm_tobit, 1, N, INT, XA_FP32) \ - _(SOFTFP, softfp_add, 2, N, NUM, XA2_FP32) \ - _(SOFTFP, softfp_sub, 2, N, NUM, XA2_FP32) \ - _(SOFTFP, softfp_mul, 2, N, NUM, XA2_FP32) \ - _(SOFTFP, softfp_div, 2, N, NUM, XA2_FP32) \ - _(SOFTFP, softfp_cmp, 2, N, NIL, XA2_FP32) \ - _(SOFTFP, softfp_i2d, 1, N, NUM, 0) \ - _(SOFTFP, softfp_d2i, 1, N, INT, XA_FP32) \ - _(SOFTFP_MIPS, lj_vm_sfmin, 2, N, NUM, XA2_FP32) \ - _(SOFTFP_MIPS, lj_vm_sfmax, 2, N, NUM, XA2_FP32) \ - _(SOFTFP_MIPS64, lj_vm_tointg, 1, N, INT, 0) \ - _(SOFTFP_FFI, softfp_ui2d, 1, N, NUM, 0) \ - _(SOFTFP_FFI, softfp_f2d, 1, N, NUM, 0) \ - _(SOFTFP_FFI, softfp_d2ui, 1, N, INT, XA_FP32) \ - _(SOFTFP_FFI, softfp_d2f, 1, N, FLOAT, XA_FP32) \ - _(SOFTFP_FFI, softfp_i2f, 1, N, FLOAT, 0) \ - _(SOFTFP_FFI, softfp_ui2f, 1, N, FLOAT, 0) \ - _(SOFTFP_FFI, softfp_f2i, 1, N, INT, 0) \ - _(SOFTFP_FFI, softfp_f2ui, 1, N, INT, 0) \ - _(FP64_FFI, fp64_l2d, 1, N, NUM, XA_64) \ - _(FP64_FFI, fp64_ul2d, 1, N, NUM, XA_64) \ - _(FP64_FFI, fp64_l2f, 1, N, FLOAT, XA_64) \ - _(FP64_FFI, fp64_ul2f, 1, N, FLOAT, XA_64) \ - _(FP64_FFI, fp64_d2l, 1, N, I64, XA_FP) \ - _(FP64_FFI, fp64_d2ul, 1, N, U64, XA_FP) \ - _(FP64_FFI, fp64_f2l, 1, N, I64, 0) \ - _(FP64_FFI, fp64_f2ul, 1, N, U64, 0) \ - _(FFI, lj_carith_divi64, 2, N, I64, XA2_64|CCI_NOFPRCLOBBER) \ - _(FFI, lj_carith_divu64, 2, N, U64, XA2_64|CCI_NOFPRCLOBBER) \ - _(FFI, lj_carith_modi64, 2, N, I64, XA2_64|CCI_NOFPRCLOBBER) \ - _(FFI, lj_carith_modu64, 2, N, U64, XA2_64|CCI_NOFPRCLOBBER) \ - _(FFI, lj_carith_powi64, 2, N, I64, XA2_64|CCI_NOFPRCLOBBER) \ - _(FFI, lj_carith_powu64, 2, N, U64, XA2_64|CCI_NOFPRCLOBBER) \ - _(FFI, lj_cdata_newv, 4, S, CDATA, CCI_L) \ - _(FFI, lj_cdata_setfin, 4, S, NIL, CCI_L) \ - _(FFI, strlen, 1, L, INTP, 0) \ - _(FFI, memcpy, 3, S, PTR, 0) \ - _(FFI, memset, 3, S, PTR, 0) \ - _(FFI, lj_vm_errno, 0, S, INT, CCI_NOFPRCLOBBER) \ - _(FFI32, lj_carith_mul64, 2, N, I64, XA2_64|CCI_NOFPRCLOBBER) \ - _(FFI32, lj_carith_shl64, 2, N, U64, XA_64|CCI_NOFPRCLOBBER) \ - _(FFI32, lj_carith_shr64, 2, N, U64, XA_64|CCI_NOFPRCLOBBER) \ - _(FFI32, lj_carith_sar64, 2, N, U64, XA_64|CCI_NOFPRCLOBBER) \ - _(FFI32, lj_carith_rol64, 2, N, U64, XA_64|CCI_NOFPRCLOBBER) \ - _(FFI32, lj_carith_ror64, 2, N, U64, XA_64|CCI_NOFPRCLOBBER) \ - \ - /* End of list. */ - -typedef enum { -#define IRCALLENUM(cond, name, nargs, kind, type, flags) IRCALL_##name, -IRCALLDEF(IRCALLENUM) -#undef IRCALLENUM - IRCALL__MAX -} IRCallID; - -LJ_FUNC TRef lj_ir_call(jit_State *J, IRCallID id, ...); - -LJ_DATA const CCallInfo lj_ir_callinfo[IRCALL__MAX+1]; - -/* Soft-float declarations. */ -#if LJ_SOFTFP -#if LJ_TARGET_ARM -#define softfp_add __aeabi_dadd -#define softfp_sub __aeabi_dsub -#define softfp_mul __aeabi_dmul -#define softfp_div __aeabi_ddiv -#define softfp_cmp __aeabi_cdcmple -#define softfp_i2d __aeabi_i2d -#define softfp_d2i __aeabi_d2iz -#define softfp_ui2d __aeabi_ui2d -#define softfp_f2d __aeabi_f2d -#define softfp_d2ui __aeabi_d2uiz -#define softfp_d2f __aeabi_d2f -#define softfp_i2f __aeabi_i2f -#define softfp_ui2f __aeabi_ui2f -#define softfp_f2i __aeabi_f2iz -#define softfp_f2ui __aeabi_f2uiz -#define fp64_l2d __aeabi_l2d -#define fp64_ul2d __aeabi_ul2d -#define fp64_l2f __aeabi_l2f -#define fp64_ul2f __aeabi_ul2f -#if LJ_TARGET_IOS -#define fp64_d2l __fixdfdi -#define fp64_d2ul __fixunsdfdi -#define fp64_f2l __fixsfdi -#define fp64_f2ul __fixunssfdi -#else -#define fp64_d2l __aeabi_d2lz -#define fp64_d2ul __aeabi_d2ulz -#define fp64_f2l __aeabi_f2lz -#define fp64_f2ul __aeabi_f2ulz -#endif -#elif LJ_TARGET_MIPS || LJ_TARGET_PPC -#define softfp_add __adddf3 -#define softfp_sub __subdf3 -#define softfp_mul __muldf3 -#define softfp_div __divdf3 -#define softfp_cmp __ledf2 -#define softfp_i2d __floatsidf -#define softfp_d2i __fixdfsi -#define softfp_ui2d __floatunsidf -#define softfp_f2d __extendsfdf2 -#define softfp_d2ui __fixunsdfsi -#define softfp_d2f __truncdfsf2 -#define softfp_i2f __floatsisf -#define softfp_ui2f __floatunsisf -#define softfp_f2i __fixsfsi -#define softfp_f2ui __fixunssfsi -#else -#error "Missing soft-float definitions for target architecture" -#endif -extern double softfp_add(double a, double b); -extern double softfp_sub(double a, double b); -extern double softfp_mul(double a, double b); -extern double softfp_div(double a, double b); -extern void softfp_cmp(double a, double b); -extern double softfp_i2d(int32_t a); -extern int32_t softfp_d2i(double a); -#if LJ_HASFFI -extern double softfp_ui2d(uint32_t a); -extern double softfp_f2d(float a); -extern uint32_t softfp_d2ui(double a); -extern float softfp_d2f(double a); -extern float softfp_i2f(int32_t a); -extern float softfp_ui2f(uint32_t a); -extern int32_t softfp_f2i(float a); -extern uint32_t softfp_f2ui(float a); -#endif -#if LJ_TARGET_MIPS -extern double lj_vm_sfmin(double a, double b); -extern double lj_vm_sfmax(double a, double b); -#endif -#endif - -#if LJ_HASFFI && LJ_NEED_FP64 && !(LJ_TARGET_ARM && LJ_SOFTFP) -#ifdef __GNUC__ -#define fp64_l2d __floatdidf -#define fp64_ul2d __floatundidf -#define fp64_l2f __floatdisf -#define fp64_ul2f __floatundisf -#define fp64_d2l __fixdfdi -#define fp64_d2ul __fixunsdfdi -#define fp64_f2l __fixsfdi -#define fp64_f2ul __fixunssfdi -#else -#error "Missing fp64 helper definitions for this compiler" -#endif -#endif - -#if LJ_HASFFI && (LJ_SOFTFP || LJ_NEED_FP64) -extern double fp64_l2d(int64_t a); -extern double fp64_ul2d(uint64_t a); -extern float fp64_l2f(int64_t a); -extern float fp64_ul2f(uint64_t a); -extern int64_t fp64_d2l(double a); -extern uint64_t fp64_d2ul(double a); -extern int64_t fp64_f2l(float a); -extern uint64_t fp64_f2ul(float a); -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_iropt.h b/lib/LuaJIT/src/lj_iropt.h deleted file mode 100644 index a59ba3f..0000000 --- a/lib/LuaJIT/src/lj_iropt.h +++ /dev/null @@ -1,162 +0,0 @@ -/* -** Common header for IR emitter and optimizations. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_IROPT_H -#define _LJ_IROPT_H - -#include - -#include "lj_obj.h" -#include "lj_jit.h" - -#if LJ_HASJIT -/* IR emitter. */ -LJ_FUNC void LJ_FASTCALL lj_ir_growtop(jit_State *J); -LJ_FUNC TRef LJ_FASTCALL lj_ir_emit(jit_State *J); - -/* Save current IR in J->fold.ins, but do not emit it (yet). */ -static LJ_AINLINE void lj_ir_set_(jit_State *J, uint16_t ot, IRRef1 a, IRRef1 b) -{ - J->fold.ins.ot = ot; J->fold.ins.op1 = a; J->fold.ins.op2 = b; -} - -#define lj_ir_set(J, ot, a, b) \ - lj_ir_set_(J, (uint16_t)(ot), (IRRef1)(a), (IRRef1)(b)) - -/* Get ref of next IR instruction and optionally grow IR. -** Note: this may invalidate all IRIns*! -*/ -static LJ_AINLINE IRRef lj_ir_nextins(jit_State *J) -{ - IRRef ref = J->cur.nins; - if (LJ_UNLIKELY(ref >= J->irtoplim)) lj_ir_growtop(J); - J->cur.nins = ref + 1; - return ref; -} - -LJ_FUNC TRef lj_ir_ggfload(jit_State *J, IRType t, uintptr_t ofs); - -/* Interning of constants. */ -LJ_FUNC TRef LJ_FASTCALL lj_ir_kint(jit_State *J, int32_t k); -LJ_FUNC TRef lj_ir_k64(jit_State *J, IROp op, uint64_t u64); -LJ_FUNC TRef lj_ir_knum_u64(jit_State *J, uint64_t u64); -LJ_FUNC TRef lj_ir_knumint(jit_State *J, lua_Number n); -LJ_FUNC TRef lj_ir_kint64(jit_State *J, uint64_t u64); -LJ_FUNC TRef lj_ir_kgc(jit_State *J, GCobj *o, IRType t); -LJ_FUNC TRef lj_ir_kptr_(jit_State *J, IROp op, void *ptr); -LJ_FUNC TRef lj_ir_knull(jit_State *J, IRType t); -LJ_FUNC TRef lj_ir_kslot(jit_State *J, TRef key, IRRef slot); -LJ_FUNC TRef lj_ir_ktrace(jit_State *J); - -#if LJ_64 -#define lj_ir_kintp(J, k) lj_ir_kint64(J, (uint64_t)(k)) -#else -#define lj_ir_kintp(J, k) lj_ir_kint(J, (int32_t)(k)) -#endif - -static LJ_AINLINE TRef lj_ir_knum(jit_State *J, lua_Number n) -{ - TValue tv; - tv.n = n; - return lj_ir_knum_u64(J, tv.u64); -} - -#define lj_ir_kstr(J, str) lj_ir_kgc(J, obj2gco((str)), IRT_STR) -#define lj_ir_ktab(J, tab) lj_ir_kgc(J, obj2gco((tab)), IRT_TAB) -#define lj_ir_kfunc(J, func) lj_ir_kgc(J, obj2gco((func)), IRT_FUNC) -#define lj_ir_kptr(J, ptr) lj_ir_kptr_(J, IR_KPTR, (ptr)) -#define lj_ir_kkptr(J, ptr) lj_ir_kptr_(J, IR_KKPTR, (ptr)) - -/* Special FP constants. */ -#define lj_ir_knum_zero(J) lj_ir_knum_u64(J, U64x(00000000,00000000)) -#define lj_ir_knum_one(J) lj_ir_knum_u64(J, U64x(3ff00000,00000000)) -#define lj_ir_knum_tobit(J) lj_ir_knum_u64(J, U64x(43380000,00000000)) - -/* Special 128 bit SIMD constants. */ -#define lj_ir_ksimd(J, idx) \ - lj_ir_ggfload(J, IRT_NUM, (uintptr_t)LJ_KSIMD(J, idx) - (uintptr_t)J2GG(J)) - -/* Access to constants. */ -LJ_FUNC void lj_ir_kvalue(lua_State *L, TValue *tv, const IRIns *ir); - -/* Convert IR operand types. */ -LJ_FUNC TRef LJ_FASTCALL lj_ir_tonumber(jit_State *J, TRef tr); -LJ_FUNC TRef LJ_FASTCALL lj_ir_tonum(jit_State *J, TRef tr); -LJ_FUNC TRef LJ_FASTCALL lj_ir_tostr(jit_State *J, TRef tr); - -/* Miscellaneous IR ops. */ -LJ_FUNC int lj_ir_numcmp(lua_Number a, lua_Number b, IROp op); -LJ_FUNC int lj_ir_strcmp(GCstr *a, GCstr *b, IROp op); -LJ_FUNC void lj_ir_rollback(jit_State *J, IRRef ref); - -/* Emit IR instructions with on-the-fly optimizations. */ -LJ_FUNC TRef LJ_FASTCALL lj_opt_fold(jit_State *J); -LJ_FUNC TRef LJ_FASTCALL lj_opt_cse(jit_State *J); -LJ_FUNC TRef LJ_FASTCALL lj_opt_cselim(jit_State *J, IRRef lim); - -/* Special return values for the fold functions. */ -enum { - NEXTFOLD, /* Couldn't fold, pass on. */ - RETRYFOLD, /* Retry fold with modified fins. */ - KINTFOLD, /* Return ref for int constant in fins->i. */ - FAILFOLD, /* Guard would always fail. */ - DROPFOLD, /* Guard eliminated. */ - MAX_FOLD -}; - -#define INTFOLD(k) ((J->fold.ins.i = (k)), (TRef)KINTFOLD) -#define INT64FOLD(k) (lj_ir_kint64(J, (k))) -#define CONDFOLD(cond) ((TRef)FAILFOLD + (TRef)(cond)) -#define LEFTFOLD (J->fold.ins.op1) -#define RIGHTFOLD (J->fold.ins.op2) -#define CSEFOLD (lj_opt_cse(J)) -#define EMITFOLD (lj_ir_emit(J)) - -/* Load/store forwarding. */ -LJ_FUNC TRef LJ_FASTCALL lj_opt_fwd_aload(jit_State *J); -LJ_FUNC TRef LJ_FASTCALL lj_opt_fwd_hload(jit_State *J); -LJ_FUNC TRef LJ_FASTCALL lj_opt_fwd_uload(jit_State *J); -LJ_FUNC TRef LJ_FASTCALL lj_opt_fwd_fload(jit_State *J); -LJ_FUNC TRef LJ_FASTCALL lj_opt_fwd_xload(jit_State *J); -LJ_FUNC TRef LJ_FASTCALL lj_opt_fwd_tab_len(jit_State *J); -LJ_FUNC TRef LJ_FASTCALL lj_opt_fwd_hrefk(jit_State *J); -LJ_FUNC int LJ_FASTCALL lj_opt_fwd_href_nokey(jit_State *J); -LJ_FUNC int LJ_FASTCALL lj_opt_fwd_tptr(jit_State *J, IRRef lim); -LJ_FUNC int lj_opt_fwd_wasnonnil(jit_State *J, IROpT loadop, IRRef xref); - -/* Dead-store elimination. */ -LJ_FUNC TRef LJ_FASTCALL lj_opt_dse_ahstore(jit_State *J); -LJ_FUNC TRef LJ_FASTCALL lj_opt_dse_ustore(jit_State *J); -LJ_FUNC TRef LJ_FASTCALL lj_opt_dse_fstore(jit_State *J); -LJ_FUNC TRef LJ_FASTCALL lj_opt_dse_xstore(jit_State *J); - -/* Narrowing. */ -LJ_FUNC TRef LJ_FASTCALL lj_opt_narrow_convert(jit_State *J); -LJ_FUNC TRef LJ_FASTCALL lj_opt_narrow_index(jit_State *J, TRef key); -LJ_FUNC TRef LJ_FASTCALL lj_opt_narrow_toint(jit_State *J, TRef tr); -LJ_FUNC TRef LJ_FASTCALL lj_opt_narrow_tobit(jit_State *J, TRef tr); -#if LJ_HASFFI -LJ_FUNC TRef LJ_FASTCALL lj_opt_narrow_cindex(jit_State *J, TRef key); -#endif -LJ_FUNC TRef lj_opt_narrow_arith(jit_State *J, TRef rb, TRef rc, - TValue *vb, TValue *vc, IROp op); -LJ_FUNC TRef lj_opt_narrow_unm(jit_State *J, TRef rc, TValue *vc); -LJ_FUNC TRef lj_opt_narrow_mod(jit_State *J, TRef rb, TRef rc, TValue *vb, TValue *vc); -LJ_FUNC TRef lj_opt_narrow_pow(jit_State *J, TRef rb, TRef rc, TValue *vb, TValue *vc); -LJ_FUNC IRType lj_opt_narrow_forl(jit_State *J, cTValue *forbase); - -/* Optimization passes. */ -LJ_FUNC void lj_opt_dce(jit_State *J); -LJ_FUNC int lj_opt_loop(jit_State *J); -#if LJ_SOFTFP32 || (LJ_32 && LJ_HASFFI) -LJ_FUNC void lj_opt_split(jit_State *J); -#else -#define lj_opt_split(J) UNUSED(J) -#endif -LJ_FUNC void lj_opt_sink(jit_State *J); - -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_jit.h b/lib/LuaJIT/src/lj_jit.h deleted file mode 100644 index 5d41ef4..0000000 --- a/lib/LuaJIT/src/lj_jit.h +++ /dev/null @@ -1,505 +0,0 @@ -/* -** Common definitions for the JIT compiler. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_JIT_H -#define _LJ_JIT_H - -#include "lj_obj.h" -#include "lj_ir.h" - -/* JIT engine flags. */ -#define JIT_F_ON 0x00000001 - -/* CPU-specific JIT engine flags. */ -#if LJ_TARGET_X86ORX64 -#define JIT_F_SSE2 0x00000010 -#define JIT_F_SSE3 0x00000020 -#define JIT_F_SSE4_1 0x00000040 -#define JIT_F_PREFER_IMUL 0x00000080 -#define JIT_F_LEA_AGU 0x00000100 -#define JIT_F_BMI2 0x00000200 - -/* Names for the CPU-specific flags. Must match the order above. */ -#define JIT_F_CPU_FIRST JIT_F_SSE2 -#define JIT_F_CPUSTRING "\4SSE2\4SSE3\6SSE4.1\3AMD\4ATOM\4BMI2" -#elif LJ_TARGET_ARM -#define JIT_F_ARMV6_ 0x00000010 -#define JIT_F_ARMV6T2_ 0x00000020 -#define JIT_F_ARMV7 0x00000040 -#define JIT_F_VFPV2 0x00000080 -#define JIT_F_VFPV3 0x00000100 - -#define JIT_F_ARMV6 (JIT_F_ARMV6_|JIT_F_ARMV6T2_|JIT_F_ARMV7) -#define JIT_F_ARMV6T2 (JIT_F_ARMV6T2_|JIT_F_ARMV7) -#define JIT_F_VFP (JIT_F_VFPV2|JIT_F_VFPV3) - -/* Names for the CPU-specific flags. Must match the order above. */ -#define JIT_F_CPU_FIRST JIT_F_ARMV6_ -#define JIT_F_CPUSTRING "\5ARMv6\7ARMv6T2\5ARMv7\5VFPv2\5VFPv3" -#elif LJ_TARGET_PPC -#define JIT_F_SQRT 0x00000010 -#define JIT_F_ROUND 0x00000020 - -/* Names for the CPU-specific flags. Must match the order above. */ -#define JIT_F_CPU_FIRST JIT_F_SQRT -#define JIT_F_CPUSTRING "\4SQRT\5ROUND" -#elif LJ_TARGET_MIPS -#define JIT_F_MIPSXXR2 0x00000010 - -/* Names for the CPU-specific flags. Must match the order above. */ -#define JIT_F_CPU_FIRST JIT_F_MIPSXXR2 -#if LJ_TARGET_MIPS32 -#define JIT_F_CPUSTRING "\010MIPS32R2" -#else -#define JIT_F_CPUSTRING "\010MIPS64R2" -#endif -#else -#define JIT_F_CPU_FIRST 0 -#define JIT_F_CPUSTRING "" -#endif - -/* Optimization flags. */ -#define JIT_F_OPT_MASK 0x0fff0000 - -#define JIT_F_OPT_FOLD 0x00010000 -#define JIT_F_OPT_CSE 0x00020000 -#define JIT_F_OPT_DCE 0x00040000 -#define JIT_F_OPT_FWD 0x00080000 -#define JIT_F_OPT_DSE 0x00100000 -#define JIT_F_OPT_NARROW 0x00200000 -#define JIT_F_OPT_LOOP 0x00400000 -#define JIT_F_OPT_ABC 0x00800000 -#define JIT_F_OPT_SINK 0x01000000 -#define JIT_F_OPT_FUSE 0x02000000 - -/* Optimizations names for -O. Must match the order above. */ -#define JIT_F_OPT_FIRST JIT_F_OPT_FOLD -#define JIT_F_OPTSTRING \ - "\4fold\3cse\3dce\3fwd\3dse\6narrow\4loop\3abc\4sink\4fuse" - -/* Optimization levels set a fixed combination of flags. */ -#define JIT_F_OPT_0 0 -#define JIT_F_OPT_1 (JIT_F_OPT_FOLD|JIT_F_OPT_CSE|JIT_F_OPT_DCE) -#define JIT_F_OPT_2 (JIT_F_OPT_1|JIT_F_OPT_NARROW|JIT_F_OPT_LOOP) -#define JIT_F_OPT_3 (JIT_F_OPT_2|\ - JIT_F_OPT_FWD|JIT_F_OPT_DSE|JIT_F_OPT_ABC|JIT_F_OPT_SINK|JIT_F_OPT_FUSE) -#define JIT_F_OPT_DEFAULT JIT_F_OPT_3 - -#if LJ_TARGET_WINDOWS || LJ_64 -/* See: http://blogs.msdn.com/oldnewthing/archive/2003/10/08/55239.aspx */ -#define JIT_P_sizemcode_DEFAULT 64 -#else -/* Could go as low as 4K, but the mmap() overhead would be rather high. */ -#define JIT_P_sizemcode_DEFAULT 32 -#endif - -/* Optimization parameters and their defaults. Length is a char in octal! */ -#define JIT_PARAMDEF(_) \ - _(\010, maxtrace, 1000) /* Max. # of traces in cache. */ \ - _(\011, maxrecord, 4000) /* Max. # of recorded IR instructions. */ \ - _(\012, maxirconst, 500) /* Max. # of IR constants of a trace. */ \ - _(\007, maxside, 100) /* Max. # of side traces of a root trace. */ \ - _(\007, maxsnap, 500) /* Max. # of snapshots for a trace. */ \ - _(\011, minstitch, 0) /* Min. # of IR ins for a stitched trace. */ \ - \ - _(\007, hotloop, 56) /* # of iter. to detect a hot loop/call. */ \ - _(\007, hotexit, 10) /* # of taken exits to start a side trace. */ \ - _(\007, tryside, 4) /* # of attempts to compile a side trace. */ \ - \ - _(\012, instunroll, 4) /* Max. unroll for instable loops. */ \ - _(\012, loopunroll, 15) /* Max. unroll for loop ops in side traces. */ \ - _(\012, callunroll, 3) /* Max. unroll for recursive calls. */ \ - _(\011, recunroll, 2) /* Min. unroll for true recursion. */ \ - \ - /* Size of each machine code area (in KBytes). */ \ - _(\011, sizemcode, JIT_P_sizemcode_DEFAULT) \ - /* Max. total size of all machine code areas (in KBytes). */ \ - _(\010, maxmcode, 512) \ - /* End of list. */ - -enum { -#define JIT_PARAMENUM(len, name, value) JIT_P_##name, -JIT_PARAMDEF(JIT_PARAMENUM) -#undef JIT_PARAMENUM - JIT_P__MAX -}; - -#define JIT_PARAMSTR(len, name, value) #len #name -#define JIT_P_STRING JIT_PARAMDEF(JIT_PARAMSTR) - -/* Trace compiler state. */ -typedef enum { - LJ_TRACE_IDLE, /* Trace compiler idle. */ - LJ_TRACE_ACTIVE = 0x10, - LJ_TRACE_RECORD, /* Bytecode recording active. */ - LJ_TRACE_START, /* New trace started. */ - LJ_TRACE_END, /* End of trace. */ - LJ_TRACE_ASM, /* Assemble trace. */ - LJ_TRACE_ERR /* Trace aborted with error. */ -} TraceState; - -/* Post-processing action. */ -typedef enum { - LJ_POST_NONE, /* No action. */ - LJ_POST_FIXCOMP, /* Fixup comparison and emit pending guard. */ - LJ_POST_FIXGUARD, /* Fixup and emit pending guard. */ - LJ_POST_FIXGUARDSNAP, /* Fixup and emit pending guard and snapshot. */ - LJ_POST_FIXBOOL, /* Fixup boolean result. */ - LJ_POST_FIXCONST, /* Fixup constant results. */ - LJ_POST_FFRETRY /* Suppress recording of retried fast functions. */ -} PostProc; - -/* Machine code type. */ -#if LJ_TARGET_X86ORX64 -typedef uint8_t MCode; -#else -typedef uint32_t MCode; -#endif - -/* Linked list of MCode areas. */ -typedef struct MCLink { - MCode *next; /* Next area. */ - size_t size; /* Size of current area. */ -} MCLink; - -/* Stack snapshot header. */ -typedef struct SnapShot { - uint32_t mapofs; /* Offset into snapshot map. */ - IRRef1 ref; /* First IR ref for this snapshot. */ - uint8_t nslots; /* Number of valid slots. */ - uint8_t topslot; /* Maximum frame extent. */ - uint8_t nent; /* Number of compressed entries. */ - uint8_t count; /* Count of taken exits for this snapshot. */ -} SnapShot; - -#define SNAPCOUNT_DONE 255 /* Already compiled and linked a side trace. */ - -/* Compressed snapshot entry. */ -typedef uint32_t SnapEntry; - -#define SNAP_FRAME 0x010000 /* Frame slot. */ -#define SNAP_CONT 0x020000 /* Continuation slot. */ -#define SNAP_NORESTORE 0x040000 /* No need to restore slot. */ -#define SNAP_SOFTFPNUM 0x080000 /* Soft-float number. */ -LJ_STATIC_ASSERT(SNAP_FRAME == TREF_FRAME); -LJ_STATIC_ASSERT(SNAP_CONT == TREF_CONT); - -#define SNAP(slot, flags, ref) (((SnapEntry)(slot) << 24) + (flags) + (ref)) -#define SNAP_TR(slot, tr) \ - (((SnapEntry)(slot) << 24) + ((tr) & (TREF_CONT|TREF_FRAME|TREF_REFMASK))) -#if !LJ_FR2 -#define SNAP_MKPC(pc) ((SnapEntry)u32ptr(pc)) -#endif -#define SNAP_MKFTSZ(ftsz) ((SnapEntry)(ftsz)) -#define snap_ref(sn) ((sn) & 0xffff) -#define snap_slot(sn) ((BCReg)((sn) >> 24)) -#define snap_isframe(sn) ((sn) & SNAP_FRAME) -#define snap_setref(sn, ref) (((sn) & (0xffff0000&~SNAP_NORESTORE)) | (ref)) - -static LJ_AINLINE const BCIns *snap_pc(SnapEntry *sn) -{ -#if LJ_FR2 - uint64_t pcbase; - memcpy(&pcbase, sn, sizeof(uint64_t)); - return (const BCIns *)(pcbase >> 8); -#else - return (const BCIns *)(uintptr_t)*sn; -#endif -} - -/* Snapshot and exit numbers. */ -typedef uint32_t SnapNo; -typedef uint32_t ExitNo; - -/* Trace number. */ -typedef uint32_t TraceNo; /* Used to pass around trace numbers. */ -typedef uint16_t TraceNo1; /* Stored trace number. */ - -/* Type of link. ORDER LJ_TRLINK */ -typedef enum { - LJ_TRLINK_NONE, /* Incomplete trace. No link, yet. */ - LJ_TRLINK_ROOT, /* Link to other root trace. */ - LJ_TRLINK_LOOP, /* Loop to same trace. */ - LJ_TRLINK_TAILREC, /* Tail-recursion. */ - LJ_TRLINK_UPREC, /* Up-recursion. */ - LJ_TRLINK_DOWNREC, /* Down-recursion. */ - LJ_TRLINK_INTERP, /* Fallback to interpreter. */ - LJ_TRLINK_RETURN, /* Return to interpreter. */ - LJ_TRLINK_STITCH /* Trace stitching. */ -} TraceLink; - -/* Trace object. */ -typedef struct GCtrace { - GCHeader; - uint16_t nsnap; /* Number of snapshots. */ - IRRef nins; /* Next IR instruction. Biased with REF_BIAS. */ -#if LJ_GC64 - uint32_t unused_gc64; -#endif - GCRef gclist; - IRIns *ir; /* IR instructions/constants. Biased with REF_BIAS. */ - IRRef nk; /* Lowest IR constant. Biased with REF_BIAS. */ - uint32_t nsnapmap; /* Number of snapshot map elements. */ - SnapShot *snap; /* Snapshot array. */ - SnapEntry *snapmap; /* Snapshot map. */ - GCRef startpt; /* Starting prototype. */ - MRef startpc; /* Bytecode PC of starting instruction. */ - BCIns startins; /* Original bytecode of starting instruction. */ - MSize szmcode; /* Size of machine code. */ - MCode *mcode; /* Start of machine code. */ - MSize mcloop; /* Offset of loop start in machine code. */ - uint16_t nchild; /* Number of child traces (root trace only). */ - uint16_t spadjust; /* Stack pointer adjustment (offset in bytes). */ - TraceNo1 traceno; /* Trace number. */ - TraceNo1 link; /* Linked trace (or self for loops). */ - TraceNo1 root; /* Root trace of side trace (or 0 for root traces). */ - TraceNo1 nextroot; /* Next root trace for same prototype. */ - TraceNo1 nextside; /* Next side trace of same root trace. */ - uint8_t sinktags; /* Trace has SINK tags. */ - uint8_t topslot; /* Top stack slot already checked to be allocated. */ - uint8_t linktype; /* Type of link. */ - uint8_t unused1; -#ifdef LUAJIT_USE_GDBJIT - void *gdbjit_entry; /* GDB JIT entry. */ -#endif -} GCtrace; - -#define gco2trace(o) check_exp((o)->gch.gct == ~LJ_TTRACE, (GCtrace *)(o)) -#define traceref(J, n) \ - check_exp((n)>0 && (MSize)(n)sizetrace, (GCtrace *)gcref(J->trace[(n)])) - -LJ_STATIC_ASSERT(offsetof(GChead, gclist) == offsetof(GCtrace, gclist)); - -static LJ_AINLINE MSize snap_nextofs(GCtrace *T, SnapShot *snap) -{ - if (snap+1 == &T->snap[T->nsnap]) - return T->nsnapmap; - else - return (snap+1)->mapofs; -} - -/* Round-robin penalty cache for bytecodes leading to aborted traces. */ -typedef struct HotPenalty { - MRef pc; /* Starting bytecode PC. */ - uint16_t val; /* Penalty value, i.e. hotcount start. */ - uint16_t reason; /* Abort reason (really TraceErr). */ -} HotPenalty; - -#define PENALTY_SLOTS 64 /* Penalty cache slot. Must be a power of 2. */ -#define PENALTY_MIN (36*2) /* Minimum penalty value. */ -#define PENALTY_MAX 60000 /* Maximum penalty value. */ -#define PENALTY_RNDBITS 4 /* # of random bits to add to penalty value. */ - -/* Round-robin backpropagation cache for narrowing conversions. */ -typedef struct BPropEntry { - IRRef1 key; /* Key: original reference. */ - IRRef1 val; /* Value: reference after conversion. */ - IRRef mode; /* Mode for this entry (currently IRCONV_*). */ -} BPropEntry; - -/* Number of slots for the backpropagation cache. Must be a power of 2. */ -#define BPROP_SLOTS 16 - -/* Scalar evolution analysis cache. */ -typedef struct ScEvEntry { - MRef pc; /* Bytecode PC of FORI. */ - IRRef1 idx; /* Index reference. */ - IRRef1 start; /* Constant start reference. */ - IRRef1 stop; /* Constant stop reference. */ - IRRef1 step; /* Constant step reference. */ - IRType1 t; /* Scalar type. */ - uint8_t dir; /* Direction. 1: +, 0: -. */ -} ScEvEntry; - -/* Reverse bytecode map (IRRef -> PC). Only for selected instructions. */ -typedef struct RBCHashEntry { - MRef pc; /* Bytecode PC. */ - GCRef pt; /* Prototype. */ - IRRef ref; /* IR reference. */ -} RBCHashEntry; - -/* Number of slots in the reverse bytecode hash table. Must be a power of 2. */ -#define RBCHASH_SLOTS 8 - -/* 128 bit SIMD constants. */ -enum { - LJ_KSIMD_ABS, - LJ_KSIMD_NEG, - LJ_KSIMD__MAX -}; - -enum { -#if LJ_TARGET_X86ORX64 - LJ_K64_TOBIT, /* 2^52 + 2^51 */ - LJ_K64_2P64, /* 2^64 */ - LJ_K64_M2P64, /* -2^64 */ -#if LJ_32 - LJ_K64_M2P64_31, /* -2^64 or -2^31 */ -#else - LJ_K64_M2P64_31 = LJ_K64_M2P64, -#endif -#endif -#if LJ_TARGET_MIPS - LJ_K64_2P31, /* 2^31 */ -#if LJ_64 - LJ_K64_2P63, /* 2^63 */ - LJ_K64_M2P64, /* -2^64 */ -#endif -#endif - LJ_K64__MAX, -}; - -enum { -#if LJ_TARGET_X86ORX64 - LJ_K32_M2P64_31, /* -2^64 or -2^31 */ -#endif -#if LJ_TARGET_PPC - LJ_K32_2P52_2P31, /* 2^52 + 2^31 */ - LJ_K32_2P52, /* 2^52 */ -#endif -#if LJ_TARGET_PPC || LJ_TARGET_MIPS - LJ_K32_2P31, /* 2^31 */ -#endif -#if LJ_TARGET_MIPS64 - LJ_K32_2P63, /* 2^63 */ - LJ_K32_M2P64, /* -2^64 */ -#endif - LJ_K32__MAX -}; - -/* Get 16 byte aligned pointer to SIMD constant. */ -#define LJ_KSIMD(J, n) \ - ((TValue *)(((intptr_t)&J->ksimd[2*(n)] + 15) & ~(intptr_t)15)) - -/* Set/reset flag to activate the SPLIT pass for the current trace. */ -#if LJ_SOFTFP32 || (LJ_32 && LJ_HASFFI) -#define lj_needsplit(J) (J->needsplit = 1) -#define lj_resetsplit(J) (J->needsplit = 0) -#else -#define lj_needsplit(J) UNUSED(J) -#define lj_resetsplit(J) UNUSED(J) -#endif - -/* Fold state is used to fold instructions on-the-fly. */ -typedef struct FoldState { - IRIns ins; /* Currently emitted instruction. */ - IRIns left[2]; /* Instruction referenced by left operand. */ - IRIns right[2]; /* Instruction referenced by right operand. */ -} FoldState; - -/* JIT compiler state. */ -typedef struct jit_State { - GCtrace cur; /* Current trace. */ - GCtrace *curfinal; /* Final address of current trace (set during asm). */ - - lua_State *L; /* Current Lua state. */ - const BCIns *pc; /* Current PC. */ - GCfunc *fn; /* Current function. */ - GCproto *pt; /* Current prototype. */ - TRef *base; /* Current frame base, points into J->slots. */ - - uint32_t flags; /* JIT engine flags. */ - BCReg maxslot; /* Relative to baseslot. */ - BCReg baseslot; /* Current frame base, offset into J->slots. */ - - uint8_t mergesnap; /* Allowed to merge with next snapshot. */ - uint8_t needsnap; /* Need snapshot before recording next bytecode. */ - IRType1 guardemit; /* Accumulated IRT_GUARD for emitted instructions. */ - uint8_t bcskip; /* Number of bytecode instructions to skip. */ - - FoldState fold; /* Fold state. */ - - const BCIns *bc_min; /* Start of allowed bytecode range for root trace. */ - MSize bc_extent; /* Extent of the range. */ - - TraceState state; /* Trace compiler state. */ - - int32_t instunroll; /* Unroll counter for instable loops. */ - int32_t loopunroll; /* Unroll counter for loop ops in side traces. */ - int32_t tailcalled; /* Number of successive tailcalls. */ - int32_t framedepth; /* Current frame depth. */ - int32_t retdepth; /* Return frame depth (count of RETF). */ - - TValue ksimd[LJ_KSIMD__MAX*2+1]; /* 16 byte aligned SIMD constants. */ - TValue k64[LJ_K64__MAX]; /* Common 8 byte constants used by backends. */ - uint32_t k32[LJ_K32__MAX]; /* Ditto for 4 byte constants. */ - - IRIns *irbuf; /* Temp. IR instruction buffer. Biased with REF_BIAS. */ - IRRef irtoplim; /* Upper limit of instuction buffer (biased). */ - IRRef irbotlim; /* Lower limit of instuction buffer (biased). */ - IRRef loopref; /* Last loop reference or ref of final LOOP (or 0). */ - - MSize sizesnap; /* Size of temp. snapshot buffer. */ - SnapShot *snapbuf; /* Temp. snapshot buffer. */ - SnapEntry *snapmapbuf; /* Temp. snapshot map buffer. */ - MSize sizesnapmap; /* Size of temp. snapshot map buffer. */ - - PostProc postproc; /* Required post-processing after execution. */ -#if LJ_SOFTFP32 || (LJ_32 && LJ_HASFFI) - uint8_t needsplit; /* Need SPLIT pass. */ -#endif - uint8_t retryrec; /* Retry recording. */ - - GCRef *trace; /* Array of traces. */ - TraceNo freetrace; /* Start of scan for next free trace. */ - MSize sizetrace; /* Size of trace array. */ - IRRef1 ktrace; /* Reference to KGC with GCtrace. */ - - IRRef1 chain[IR__MAX]; /* IR instruction skip-list chain anchors. */ - TRef slot[LJ_MAX_JSLOTS+LJ_STACK_EXTRA]; /* Stack slot map. */ - - int32_t param[JIT_P__MAX]; /* JIT engine parameters. */ - - MCode *exitstubgroup[LJ_MAX_EXITSTUBGR]; /* Exit stub group addresses. */ - - HotPenalty penalty[PENALTY_SLOTS]; /* Penalty slots. */ - uint32_t penaltyslot; /* Round-robin index into penalty slots. */ - uint32_t prngstate; /* PRNG state. */ - -#ifdef LUAJIT_ENABLE_TABLE_BUMP - RBCHashEntry rbchash[RBCHASH_SLOTS]; /* Reverse bytecode map. */ -#endif - - BPropEntry bpropcache[BPROP_SLOTS]; /* Backpropagation cache slots. */ - uint32_t bpropslot; /* Round-robin index into bpropcache slots. */ - - ScEvEntry scev; /* Scalar evolution analysis cache slots. */ - - const BCIns *startpc; /* Bytecode PC of starting instruction. */ - TraceNo parent; /* Parent of current side trace (0 for root traces). */ - ExitNo exitno; /* Exit number in parent of current side trace. */ - - BCIns *patchpc; /* PC for pending re-patch. */ - BCIns patchins; /* Instruction for pending re-patch. */ - - int mcprot; /* Protection of current mcode area. */ - MCode *mcarea; /* Base of current mcode area. */ - MCode *mctop; /* Top of current mcode area. */ - MCode *mcbot; /* Bottom of current mcode area. */ - size_t szmcarea; /* Size of current mcode area. */ - size_t szallmcarea; /* Total size of all allocated mcode areas. */ - - TValue errinfo; /* Additional info element for trace errors. */ - -#if LJ_HASPROFILE - GCproto *prev_pt; /* Previous prototype. */ - BCLine prev_line; /* Previous line. */ - int prof_mode; /* Profiling mode: 0, 'f', 'l'. */ -#endif -} -#if LJ_TARGET_ARM -LJ_ALIGN(16) /* For DISPATCH-relative addresses in assembler part. */ -#endif -jit_State; - -/* Trivial PRNG e.g. used for penalty randomization. */ -static LJ_AINLINE uint32_t LJ_PRNG_BITS(jit_State *J, int bits) -{ - /* Yes, this LCG is very weak, but that doesn't matter for our use case. */ - J->prngstate = J->prngstate * 1103515245 + 12345; - return J->prngstate >> (32-bits); -} - -#endif diff --git a/lib/LuaJIT/src/lj_lex.c b/lib/LuaJIT/src/lj_lex.c deleted file mode 100644 index 2d2f819..0000000 --- a/lib/LuaJIT/src/lj_lex.c +++ /dev/null @@ -1,509 +0,0 @@ -/* -** Lexical analyzer. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Major portions taken verbatim or adapted from the Lua interpreter. -** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h -*/ - -#define lj_lex_c -#define LUA_CORE - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_buf.h" -#include "lj_str.h" -#if LJ_HASFFI -#include "lj_tab.h" -#include "lj_ctype.h" -#include "lj_cdata.h" -#include "lualib.h" -#endif -#include "lj_state.h" -#include "lj_lex.h" -#include "lj_parse.h" -#include "lj_char.h" -#include "lj_strscan.h" -#include "lj_strfmt.h" - -/* Lua lexer token names. */ -static const char *const tokennames[] = { -#define TKSTR1(name) #name, -#define TKSTR2(name, sym) #sym, -TKDEF(TKSTR1, TKSTR2) -#undef TKSTR1 -#undef TKSTR2 - NULL -}; - -/* -- Buffer handling ----------------------------------------------------- */ - -#define LEX_EOF (-1) -#define lex_iseol(ls) (ls->c == '\n' || ls->c == '\r') - -/* Get more input from reader. */ -static LJ_NOINLINE LexChar lex_more(LexState *ls) -{ - size_t sz; - const char *p = ls->rfunc(ls->L, ls->rdata, &sz); - if (p == NULL || sz == 0) return LEX_EOF; - ls->pe = p + sz; - ls->p = p + 1; - return (LexChar)(uint8_t)p[0]; -} - -/* Get next character. */ -static LJ_AINLINE LexChar lex_next(LexState *ls) -{ - return (ls->c = ls->p < ls->pe ? (LexChar)(uint8_t)*ls->p++ : lex_more(ls)); -} - -/* Save character. */ -static LJ_AINLINE void lex_save(LexState *ls, LexChar c) -{ - lj_buf_putb(&ls->sb, c); -} - -/* Save previous character and get next character. */ -static LJ_AINLINE LexChar lex_savenext(LexState *ls) -{ - lex_save(ls, ls->c); - return lex_next(ls); -} - -/* Skip line break. Handles "\n", "\r", "\r\n" or "\n\r". */ -static void lex_newline(LexState *ls) -{ - LexChar old = ls->c; - lua_assert(lex_iseol(ls)); - lex_next(ls); /* Skip "\n" or "\r". */ - if (lex_iseol(ls) && ls->c != old) lex_next(ls); /* Skip "\n\r" or "\r\n". */ - if (++ls->linenumber >= LJ_MAX_LINE) - lj_lex_error(ls, ls->tok, LJ_ERR_XLINES); -} - -/* -- Scanner for terminals ----------------------------------------------- */ - -/* Parse a number literal. */ -static void lex_number(LexState *ls, TValue *tv) -{ - StrScanFmt fmt; - LexChar c, xp = 'e'; - lua_assert(lj_char_isdigit(ls->c)); - if ((c = ls->c) == '0' && (lex_savenext(ls) | 0x20) == 'x') - xp = 'p'; - while (lj_char_isident(ls->c) || ls->c == '.' || - ((ls->c == '-' || ls->c == '+') && (c | 0x20) == xp)) { - c = ls->c; - lex_savenext(ls); - } - lex_save(ls, '\0'); - fmt = lj_strscan_scan((const uint8_t *)sbufB(&ls->sb), tv, - (LJ_DUALNUM ? STRSCAN_OPT_TOINT : STRSCAN_OPT_TONUM) | - (LJ_HASFFI ? (STRSCAN_OPT_LL|STRSCAN_OPT_IMAG) : 0)); - if (LJ_DUALNUM && fmt == STRSCAN_INT) { - setitype(tv, LJ_TISNUM); - } else if (fmt == STRSCAN_NUM) { - /* Already in correct format. */ -#if LJ_HASFFI - } else if (fmt != STRSCAN_ERROR) { - lua_State *L = ls->L; - GCcdata *cd; - lua_assert(fmt == STRSCAN_I64 || fmt == STRSCAN_U64 || fmt == STRSCAN_IMAG); - if (!ctype_ctsG(G(L))) { - ptrdiff_t oldtop = savestack(L, L->top); - luaopen_ffi(L); /* Load FFI library on-demand. */ - L->top = restorestack(L, oldtop); - } - if (fmt == STRSCAN_IMAG) { - cd = lj_cdata_new_(L, CTID_COMPLEX_DOUBLE, 2*sizeof(double)); - ((double *)cdataptr(cd))[0] = 0; - ((double *)cdataptr(cd))[1] = numV(tv); - } else { - cd = lj_cdata_new_(L, fmt==STRSCAN_I64 ? CTID_INT64 : CTID_UINT64, 8); - *(uint64_t *)cdataptr(cd) = tv->u64; - } - lj_parse_keepcdata(ls, tv, cd); -#endif - } else { - lua_assert(fmt == STRSCAN_ERROR); - lj_lex_error(ls, TK_number, LJ_ERR_XNUMBER); - } -} - -/* Skip equal signs for "[=...=[" and "]=...=]" and return their count. */ -static int lex_skipeq(LexState *ls) -{ - int count = 0; - LexChar s = ls->c; - lua_assert(s == '[' || s == ']'); - while (lex_savenext(ls) == '=') - count++; - return (ls->c == s) ? count : (-count) - 1; -} - -/* Parse a long string or long comment (tv set to NULL). */ -static void lex_longstring(LexState *ls, TValue *tv, int sep) -{ - lex_savenext(ls); /* Skip second '['. */ - if (lex_iseol(ls)) /* Skip initial newline. */ - lex_newline(ls); - for (;;) { - switch (ls->c) { - case LEX_EOF: - lj_lex_error(ls, TK_eof, tv ? LJ_ERR_XLSTR : LJ_ERR_XLCOM); - break; - case ']': - if (lex_skipeq(ls) == sep) { - lex_savenext(ls); /* Skip second ']'. */ - goto endloop; - } - break; - case '\n': - case '\r': - lex_save(ls, '\n'); - lex_newline(ls); - if (!tv) lj_buf_reset(&ls->sb); /* Don't waste space for comments. */ - break; - default: - lex_savenext(ls); - break; - } - } endloop: - if (tv) { - GCstr *str = lj_parse_keepstr(ls, sbufB(&ls->sb) + (2 + (MSize)sep), - sbuflen(&ls->sb) - 2*(2 + (MSize)sep)); - setstrV(ls->L, tv, str); - } -} - -/* Parse a string. */ -static void lex_string(LexState *ls, TValue *tv) -{ - LexChar delim = ls->c; /* Delimiter is '\'' or '"'. */ - lex_savenext(ls); - while (ls->c != delim) { - switch (ls->c) { - case LEX_EOF: - lj_lex_error(ls, TK_eof, LJ_ERR_XSTR); - continue; - case '\n': - case '\r': - lj_lex_error(ls, TK_string, LJ_ERR_XSTR); - continue; - case '\\': { - LexChar c = lex_next(ls); /* Skip the '\\'. */ - switch (c) { - case 'a': c = '\a'; break; - case 'b': c = '\b'; break; - case 'f': c = '\f'; break; - case 'n': c = '\n'; break; - case 'r': c = '\r'; break; - case 't': c = '\t'; break; - case 'v': c = '\v'; break; - case 'x': /* Hexadecimal escape '\xXX'. */ - c = (lex_next(ls) & 15u) << 4; - if (!lj_char_isdigit(ls->c)) { - if (!lj_char_isxdigit(ls->c)) goto err_xesc; - c += 9 << 4; - } - c += (lex_next(ls) & 15u); - if (!lj_char_isdigit(ls->c)) { - if (!lj_char_isxdigit(ls->c)) goto err_xesc; - c += 9; - } - break; - case 'u': /* Unicode escape '\u{XX...}'. */ - if (lex_next(ls) != '{') goto err_xesc; - lex_next(ls); - c = 0; - do { - c = (c << 4) | (ls->c & 15u); - if (!lj_char_isdigit(ls->c)) { - if (!lj_char_isxdigit(ls->c)) goto err_xesc; - c += 9; - } - if (c >= 0x110000) goto err_xesc; /* Out of Unicode range. */ - } while (lex_next(ls) != '}'); - if (c < 0x800) { - if (c < 0x80) break; - lex_save(ls, 0xc0 | (c >> 6)); - } else { - if (c >= 0x10000) { - lex_save(ls, 0xf0 | (c >> 18)); - lex_save(ls, 0x80 | ((c >> 12) & 0x3f)); - } else { - if (c >= 0xd800 && c < 0xe000) goto err_xesc; /* No surrogates. */ - lex_save(ls, 0xe0 | (c >> 12)); - } - lex_save(ls, 0x80 | ((c >> 6) & 0x3f)); - } - c = 0x80 | (c & 0x3f); - break; - case 'z': /* Skip whitespace. */ - lex_next(ls); - while (lj_char_isspace(ls->c)) - if (lex_iseol(ls)) lex_newline(ls); else lex_next(ls); - continue; - case '\n': case '\r': lex_save(ls, '\n'); lex_newline(ls); continue; - case '\\': case '\"': case '\'': break; - case LEX_EOF: continue; - default: - if (!lj_char_isdigit(c)) - goto err_xesc; - c -= '0'; /* Decimal escape '\ddd'. */ - if (lj_char_isdigit(lex_next(ls))) { - c = c*10 + (ls->c - '0'); - if (lj_char_isdigit(lex_next(ls))) { - c = c*10 + (ls->c - '0'); - if (c > 255) { - err_xesc: - lj_lex_error(ls, TK_string, LJ_ERR_XESC); - } - lex_next(ls); - } - } - lex_save(ls, c); - continue; - } - lex_save(ls, c); - lex_next(ls); - continue; - } - default: - lex_savenext(ls); - break; - } - } - lex_savenext(ls); /* Skip trailing delimiter. */ - setstrV(ls->L, tv, - lj_parse_keepstr(ls, sbufB(&ls->sb)+1, sbuflen(&ls->sb)-2)); -} - -/* -- Main lexical scanner ------------------------------------------------ */ - -/* Get next lexical token. */ -static LexToken lex_scan(LexState *ls, TValue *tv) -{ - lj_buf_reset(&ls->sb); - for (;;) { - if (lj_char_isident(ls->c)) { - GCstr *s; - if (lj_char_isdigit(ls->c)) { /* Numeric literal. */ - lex_number(ls, tv); - return TK_number; - } - /* Identifier or reserved word. */ - do { - lex_savenext(ls); - } while (lj_char_isident(ls->c)); - s = lj_parse_keepstr(ls, sbufB(&ls->sb), sbuflen(&ls->sb)); - setstrV(ls->L, tv, s); - if (s->reserved > 0) /* Reserved word? */ - return TK_OFS + s->reserved; - return TK_name; - } - switch (ls->c) { - case '\n': - case '\r': - lex_newline(ls); - continue; - case ' ': - case '\t': - case '\v': - case '\f': - lex_next(ls); - continue; - case '-': - lex_next(ls); - if (ls->c != '-') return '-'; - lex_next(ls); - if (ls->c == '[') { /* Long comment "--[=*[...]=*]". */ - int sep = lex_skipeq(ls); - lj_buf_reset(&ls->sb); /* `lex_skipeq' may dirty the buffer */ - if (sep >= 0) { - lex_longstring(ls, NULL, sep); - lj_buf_reset(&ls->sb); - continue; - } - } - /* Short comment "--.*\n". */ - while (!lex_iseol(ls) && ls->c != LEX_EOF) - lex_next(ls); - continue; - case '[': { - int sep = lex_skipeq(ls); - if (sep >= 0) { - lex_longstring(ls, tv, sep); - return TK_string; - } else if (sep == -1) { - return '['; - } else { - lj_lex_error(ls, TK_string, LJ_ERR_XLDELIM); - continue; - } - } - case '=': - lex_next(ls); - if (ls->c != '=') return '='; else { lex_next(ls); return TK_eq; } - case '<': - lex_next(ls); - if (ls->c != '=') return '<'; else { lex_next(ls); return TK_le; } - case '>': - lex_next(ls); - if (ls->c != '=') return '>'; else { lex_next(ls); return TK_ge; } - case '~': - lex_next(ls); - if (ls->c != '=') return '~'; else { lex_next(ls); return TK_ne; } - case ':': - lex_next(ls); - if (ls->c != ':') return ':'; else { lex_next(ls); return TK_label; } - case '"': - case '\'': - lex_string(ls, tv); - return TK_string; - case '.': - if (lex_savenext(ls) == '.') { - lex_next(ls); - if (ls->c == '.') { - lex_next(ls); - return TK_dots; /* ... */ - } - return TK_concat; /* .. */ - } else if (!lj_char_isdigit(ls->c)) { - return '.'; - } else { - lex_number(ls, tv); - return TK_number; - } - case LEX_EOF: - return TK_eof; - default: { - LexChar c = ls->c; - lex_next(ls); - return c; /* Single-char tokens (+ - / ...). */ - } - } - } -} - -/* -- Lexer API ----------------------------------------------------------- */ - -/* Setup lexer state. */ -int lj_lex_setup(lua_State *L, LexState *ls) -{ - int header = 0; - ls->L = L; - ls->fs = NULL; - ls->pe = ls->p = NULL; - ls->vstack = NULL; - ls->sizevstack = 0; - ls->vtop = 0; - ls->bcstack = NULL; - ls->sizebcstack = 0; - ls->tok = 0; - ls->lookahead = TK_eof; /* No look-ahead token. */ - ls->linenumber = 1; - ls->lastline = 1; - lex_next(ls); /* Read-ahead first char. */ - if (ls->c == 0xef && ls->p + 2 <= ls->pe && (uint8_t)ls->p[0] == 0xbb && - (uint8_t)ls->p[1] == 0xbf) { /* Skip UTF-8 BOM (if buffered). */ - ls->p += 2; - lex_next(ls); - header = 1; - } - if (ls->c == '#') { /* Skip POSIX #! header line. */ - do { - lex_next(ls); - if (ls->c == LEX_EOF) return 0; - } while (!lex_iseol(ls)); - lex_newline(ls); - header = 1; - } - if (ls->c == LUA_SIGNATURE[0]) { /* Bytecode dump. */ - if (header) { - /* - ** Loading bytecode with an extra header is disabled for security - ** reasons. This may circumvent the usual check for bytecode vs. - ** Lua code by looking at the first char. Since this is a potential - ** security violation no attempt is made to echo the chunkname either. - */ - setstrV(L, L->top++, lj_err_str(L, LJ_ERR_BCBAD)); - lj_err_throw(L, LUA_ERRSYNTAX); - } - return 1; - } - return 0; -} - -/* Cleanup lexer state. */ -void lj_lex_cleanup(lua_State *L, LexState *ls) -{ - global_State *g = G(L); - lj_mem_freevec(g, ls->bcstack, ls->sizebcstack, BCInsLine); - lj_mem_freevec(g, ls->vstack, ls->sizevstack, VarInfo); - lj_buf_free(g, &ls->sb); -} - -/* Return next lexical token. */ -void lj_lex_next(LexState *ls) -{ - ls->lastline = ls->linenumber; - if (LJ_LIKELY(ls->lookahead == TK_eof)) { /* No lookahead token? */ - ls->tok = lex_scan(ls, &ls->tokval); /* Get next token. */ - } else { /* Otherwise return lookahead token. */ - ls->tok = ls->lookahead; - ls->lookahead = TK_eof; - ls->tokval = ls->lookaheadval; - } -} - -/* Look ahead for the next token. */ -LexToken lj_lex_lookahead(LexState *ls) -{ - lua_assert(ls->lookahead == TK_eof); - ls->lookahead = lex_scan(ls, &ls->lookaheadval); - return ls->lookahead; -} - -/* Convert token to string. */ -const char *lj_lex_token2str(LexState *ls, LexToken tok) -{ - if (tok > TK_OFS) - return tokennames[tok-TK_OFS-1]; - else if (!lj_char_iscntrl(tok)) - return lj_strfmt_pushf(ls->L, "%c", tok); - else - return lj_strfmt_pushf(ls->L, "char(%d)", tok); -} - -/* Lexer error. */ -void lj_lex_error(LexState *ls, LexToken tok, ErrMsg em, ...) -{ - const char *tokstr; - va_list argp; - if (tok == 0) { - tokstr = NULL; - } else if (tok == TK_name || tok == TK_string || tok == TK_number) { - lex_save(ls, '\0'); - tokstr = sbufB(&ls->sb); - } else { - tokstr = lj_lex_token2str(ls, tok); - } - va_start(argp, em); - lj_err_lex(ls->L, ls->chunkname, tokstr, ls->linenumber, em, argp); - va_end(argp); -} - -/* Initialize strings for reserved words. */ -void lj_lex_init(lua_State *L) -{ - uint32_t i; - for (i = 0; i < TK_RESERVED; i++) { - GCstr *s = lj_str_newz(L, tokennames[i]); - fixstring(s); /* Reserved words are never collected. */ - s->reserved = (uint8_t)(i+1); - } -} - diff --git a/lib/LuaJIT/src/lj_lex.h b/lib/LuaJIT/src/lj_lex.h deleted file mode 100644 index 33fa865..0000000 --- a/lib/LuaJIT/src/lj_lex.h +++ /dev/null @@ -1,86 +0,0 @@ -/* -** Lexical analyzer. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_LEX_H -#define _LJ_LEX_H - -#include - -#include "lj_obj.h" -#include "lj_err.h" - -/* Lua lexer tokens. */ -#define TKDEF(_, __) \ - _(and) _(break) _(do) _(else) _(elseif) _(end) _(false) \ - _(for) _(function) _(goto) _(if) _(in) _(local) _(nil) _(not) _(or) \ - _(repeat) _(return) _(then) _(true) _(until) _(while) \ - __(concat, ..) __(dots, ...) __(eq, ==) __(ge, >=) __(le, <=) __(ne, ~=) \ - __(label, ::) __(number, ) __(name, ) __(string, ) \ - __(eof, ) - -enum { - TK_OFS = 256, -#define TKENUM1(name) TK_##name, -#define TKENUM2(name, sym) TK_##name, -TKDEF(TKENUM1, TKENUM2) -#undef TKENUM1 -#undef TKENUM2 - TK_RESERVED = TK_while - TK_OFS -}; - -typedef int LexChar; /* Lexical character. Unsigned ext. from char. */ -typedef int LexToken; /* Lexical token. */ - -/* Combined bytecode ins/line. Only used during bytecode generation. */ -typedef struct BCInsLine { - BCIns ins; /* Bytecode instruction. */ - BCLine line; /* Line number for this bytecode. */ -} BCInsLine; - -/* Info for local variables. Only used during bytecode generation. */ -typedef struct VarInfo { - GCRef name; /* Local variable name or goto/label name. */ - BCPos startpc; /* First point where the local variable is active. */ - BCPos endpc; /* First point where the local variable is dead. */ - uint8_t slot; /* Variable slot. */ - uint8_t info; /* Variable/goto/label info. */ -} VarInfo; - -/* Lua lexer state. */ -typedef struct LexState { - struct FuncState *fs; /* Current FuncState. Defined in lj_parse.c. */ - struct lua_State *L; /* Lua state. */ - TValue tokval; /* Current token value. */ - TValue lookaheadval; /* Lookahead token value. */ - const char *p; /* Current position in input buffer. */ - const char *pe; /* End of input buffer. */ - LexChar c; /* Current character. */ - LexToken tok; /* Current token. */ - LexToken lookahead; /* Lookahead token. */ - SBuf sb; /* String buffer for tokens. */ - lua_Reader rfunc; /* Reader callback. */ - void *rdata; /* Reader callback data. */ - BCLine linenumber; /* Input line counter. */ - BCLine lastline; /* Line of last token. */ - GCstr *chunkname; /* Current chunk name (interned string). */ - const char *chunkarg; /* Chunk name argument. */ - const char *mode; /* Allow loading bytecode (b) and/or source text (t). */ - VarInfo *vstack; /* Stack for names and extents of local variables. */ - MSize sizevstack; /* Size of variable stack. */ - MSize vtop; /* Top of variable stack. */ - BCInsLine *bcstack; /* Stack for bytecode instructions/line numbers. */ - MSize sizebcstack; /* Size of bytecode stack. */ - uint32_t level; /* Syntactical nesting level. */ -} LexState; - -LJ_FUNC int lj_lex_setup(lua_State *L, LexState *ls); -LJ_FUNC void lj_lex_cleanup(lua_State *L, LexState *ls); -LJ_FUNC void lj_lex_next(LexState *ls); -LJ_FUNC LexToken lj_lex_lookahead(LexState *ls); -LJ_FUNC const char *lj_lex_token2str(LexState *ls, LexToken tok); -LJ_FUNC_NORET void lj_lex_error(LexState *ls, LexToken tok, ErrMsg em, ...); -LJ_FUNC void lj_lex_init(lua_State *L); - -#endif diff --git a/lib/LuaJIT/src/lj_lib.c b/lib/LuaJIT/src/lj_lib.c deleted file mode 100644 index b8638de..0000000 --- a/lib/LuaJIT/src/lj_lib.c +++ /dev/null @@ -1,303 +0,0 @@ -/* -** Library function support. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_lib_c -#define LUA_CORE - -#include "lauxlib.h" - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_str.h" -#include "lj_tab.h" -#include "lj_func.h" -#include "lj_bc.h" -#include "lj_dispatch.h" -#include "lj_vm.h" -#include "lj_strscan.h" -#include "lj_strfmt.h" -#include "lj_lex.h" -#include "lj_bcdump.h" -#include "lj_lib.h" - -/* -- Library initialization ---------------------------------------------- */ - -static GCtab *lib_create_table(lua_State *L, const char *libname, int hsize) -{ - if (libname) { - luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 16); - lua_getfield(L, -1, libname); - if (!tvistab(L->top-1)) { - L->top--; - if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, hsize) != NULL) - lj_err_callerv(L, LJ_ERR_BADMODN, libname); - settabV(L, L->top, tabV(L->top-1)); - L->top++; - lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ - } - L->top--; - settabV(L, L->top-1, tabV(L->top)); - } else { - lua_createtable(L, 0, hsize); - } - return tabV(L->top-1); -} - -static const uint8_t *lib_read_lfunc(lua_State *L, const uint8_t *p, GCtab *tab) -{ - int len = *p++; - GCstr *name = lj_str_new(L, (const char *)p, len); - LexState ls; - GCproto *pt; - GCfunc *fn; - memset(&ls, 0, sizeof(ls)); - ls.L = L; - ls.p = (const char *)(p+len); - ls.pe = (const char *)~(uintptr_t)0; - ls.c = -1; - ls.level = (BCDUMP_F_STRIP|(LJ_BE*BCDUMP_F_BE)); - ls.chunkname = name; - pt = lj_bcread_proto(&ls); - pt->firstline = ~(BCLine)0; - fn = lj_func_newL_empty(L, pt, tabref(L->env)); - /* NOBARRIER: See below for common barrier. */ - setfuncV(L, lj_tab_setstr(L, tab, name), fn); - return (const uint8_t *)ls.p; -} - -void lj_lib_register(lua_State *L, const char *libname, - const uint8_t *p, const lua_CFunction *cf) -{ - GCtab *env = tabref(L->env); - GCfunc *ofn = NULL; - int ffid = *p++; - BCIns *bcff = &L2GG(L)->bcff[*p++]; - GCtab *tab = lib_create_table(L, libname, *p++); - ptrdiff_t tpos = L->top - L->base; - - /* Avoid barriers further down. */ - lj_gc_anybarriert(L, tab); - tab->nomm = 0; - - for (;;) { - uint32_t tag = *p++; - MSize len = tag & LIBINIT_LENMASK; - tag &= LIBINIT_TAGMASK; - if (tag != LIBINIT_STRING) { - const char *name; - MSize nuv = (MSize)(L->top - L->base - tpos); - GCfunc *fn = lj_func_newC(L, nuv, env); - if (nuv) { - L->top = L->base + tpos; - memcpy(fn->c.upvalue, L->top, sizeof(TValue)*nuv); - } - fn->c.ffid = (uint8_t)(ffid++); - name = (const char *)p; - p += len; - if (tag == LIBINIT_CF) - setmref(fn->c.pc, &G(L)->bc_cfunc_int); - else - setmref(fn->c.pc, bcff++); - if (tag == LIBINIT_ASM_) - fn->c.f = ofn->c.f; /* Copy handler from previous function. */ - else - fn->c.f = *cf++; /* Get cf or handler from C function table. */ - if (len) { - /* NOBARRIER: See above for common barrier. */ - setfuncV(L, lj_tab_setstr(L, tab, lj_str_new(L, name, len)), fn); - } - ofn = fn; - } else { - switch (tag | len) { - case LIBINIT_LUA: - p = lib_read_lfunc(L, p, tab); - break; - case LIBINIT_SET: - L->top -= 2; - if (tvisstr(L->top+1) && strV(L->top+1)->len == 0) - env = tabV(L->top); - else /* NOBARRIER: See above for common barrier. */ - copyTV(L, lj_tab_set(L, tab, L->top+1), L->top); - break; - case LIBINIT_NUMBER: - memcpy(&L->top->n, p, sizeof(double)); - L->top++; - p += sizeof(double); - break; - case LIBINIT_COPY: - copyTV(L, L->top, L->top - *p++); - L->top++; - break; - case LIBINIT_LASTCL: - setfuncV(L, L->top++, ofn); - break; - case LIBINIT_FFID: - ffid++; - break; - case LIBINIT_END: - return; - default: - setstrV(L, L->top++, lj_str_new(L, (const char *)p, len)); - p += len; - break; - } - } - } -} - -/* Push internal function on the stack. */ -GCfunc *lj_lib_pushcc(lua_State *L, lua_CFunction f, int id, int n) -{ - GCfunc *fn; - lua_pushcclosure(L, f, n); - fn = funcV(L->top-1); - fn->c.ffid = (uint8_t)id; - setmref(fn->c.pc, &G(L)->bc_cfunc_int); - return fn; -} - -void lj_lib_prereg(lua_State *L, const char *name, lua_CFunction f, GCtab *env) -{ - luaL_findtable(L, LUA_REGISTRYINDEX, "_PRELOAD", 4); - lua_pushcfunction(L, f); - /* NOBARRIER: The function is new (marked white). */ - setgcref(funcV(L->top-1)->c.env, obj2gco(env)); - lua_setfield(L, -2, name); - L->top--; -} - -int lj_lib_postreg(lua_State *L, lua_CFunction cf, int id, const char *name) -{ - GCfunc *fn = lj_lib_pushcf(L, cf, id); - GCtab *t = tabref(curr_func(L)->c.env); /* Reference to parent table. */ - setfuncV(L, lj_tab_setstr(L, t, lj_str_newz(L, name)), fn); - lj_gc_anybarriert(L, t); - setfuncV(L, L->top++, fn); - return 1; -} - -/* -- Type checks --------------------------------------------------------- */ - -TValue *lj_lib_checkany(lua_State *L, int narg) -{ - TValue *o = L->base + narg-1; - if (o >= L->top) - lj_err_arg(L, narg, LJ_ERR_NOVAL); - return o; -} - -GCstr *lj_lib_checkstr(lua_State *L, int narg) -{ - TValue *o = L->base + narg-1; - if (o < L->top) { - if (LJ_LIKELY(tvisstr(o))) { - return strV(o); - } else if (tvisnumber(o)) { - GCstr *s = lj_strfmt_number(L, o); - setstrV(L, o, s); - return s; - } - } - lj_err_argt(L, narg, LUA_TSTRING); - return NULL; /* unreachable */ -} - -GCstr *lj_lib_optstr(lua_State *L, int narg) -{ - TValue *o = L->base + narg-1; - return (o < L->top && !tvisnil(o)) ? lj_lib_checkstr(L, narg) : NULL; -} - -#if LJ_DUALNUM -void lj_lib_checknumber(lua_State *L, int narg) -{ - TValue *o = L->base + narg-1; - if (!(o < L->top && lj_strscan_numberobj(o))) - lj_err_argt(L, narg, LUA_TNUMBER); -} -#endif - -lua_Number lj_lib_checknum(lua_State *L, int narg) -{ - TValue *o = L->base + narg-1; - if (!(o < L->top && - (tvisnumber(o) || (tvisstr(o) && lj_strscan_num(strV(o), o))))) - lj_err_argt(L, narg, LUA_TNUMBER); - if (LJ_UNLIKELY(tvisint(o))) { - lua_Number n = (lua_Number)intV(o); - setnumV(o, n); - return n; - } else { - return numV(o); - } -} - -int32_t lj_lib_checkint(lua_State *L, int narg) -{ - TValue *o = L->base + narg-1; - if (!(o < L->top && lj_strscan_numberobj(o))) - lj_err_argt(L, narg, LUA_TNUMBER); - if (LJ_LIKELY(tvisint(o))) { - return intV(o); - } else { - int32_t i = lj_num2int(numV(o)); - if (LJ_DUALNUM) setintV(o, i); - return i; - } -} - -int32_t lj_lib_optint(lua_State *L, int narg, int32_t def) -{ - TValue *o = L->base + narg-1; - return (o < L->top && !tvisnil(o)) ? lj_lib_checkint(L, narg) : def; -} - -GCfunc *lj_lib_checkfunc(lua_State *L, int narg) -{ - TValue *o = L->base + narg-1; - if (!(o < L->top && tvisfunc(o))) - lj_err_argt(L, narg, LUA_TFUNCTION); - return funcV(o); -} - -GCtab *lj_lib_checktab(lua_State *L, int narg) -{ - TValue *o = L->base + narg-1; - if (!(o < L->top && tvistab(o))) - lj_err_argt(L, narg, LUA_TTABLE); - return tabV(o); -} - -GCtab *lj_lib_checktabornil(lua_State *L, int narg) -{ - TValue *o = L->base + narg-1; - if (o < L->top) { - if (tvistab(o)) - return tabV(o); - else if (tvisnil(o)) - return NULL; - } - lj_err_arg(L, narg, LJ_ERR_NOTABN); - return NULL; /* unreachable */ -} - -int lj_lib_checkopt(lua_State *L, int narg, int def, const char *lst) -{ - GCstr *s = def >= 0 ? lj_lib_optstr(L, narg) : lj_lib_checkstr(L, narg); - if (s) { - const char *opt = strdata(s); - MSize len = s->len; - int i; - for (i = 0; *(const uint8_t *)lst; i++) { - if (*(const uint8_t *)lst == len && memcmp(opt, lst+1, len) == 0) - return i; - lst += 1+*(const uint8_t *)lst; - } - lj_err_argv(L, narg, LJ_ERR_INVOPTM, opt); - } - return def; -} - diff --git a/lib/LuaJIT/src/lj_lib.h b/lib/LuaJIT/src/lj_lib.h deleted file mode 100644 index 37ec9d7..0000000 --- a/lib/LuaJIT/src/lj_lib.h +++ /dev/null @@ -1,115 +0,0 @@ -/* -** Library function support. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_LIB_H -#define _LJ_LIB_H - -#include "lj_obj.h" - -/* -** A fallback handler is called by the assembler VM if the fast path fails: -** -** - too few arguments: unrecoverable. -** - wrong argument type: recoverable, if coercion succeeds. -** - bad argument value: unrecoverable. -** - stack overflow: recoverable, if stack reallocation succeeds. -** - extra handling: recoverable. -** -** The unrecoverable cases throw an error with lj_err_arg(), lj_err_argtype(), -** lj_err_caller() or lj_err_callermsg(). -** The recoverable cases return 0 or the number of results + 1. -** The assembler VM retries the fast path only if 0 is returned. -** This time the fallback must not be called again or it gets stuck in a loop. -*/ - -/* Return values from fallback handler. */ -#define FFH_RETRY 0 -#define FFH_UNREACHABLE FFH_RETRY -#define FFH_RES(n) ((n)+1) -#define FFH_TAILCALL (-1) - -LJ_FUNC TValue *lj_lib_checkany(lua_State *L, int narg); -LJ_FUNC GCstr *lj_lib_checkstr(lua_State *L, int narg); -LJ_FUNC GCstr *lj_lib_optstr(lua_State *L, int narg); -#if LJ_DUALNUM -LJ_FUNC void lj_lib_checknumber(lua_State *L, int narg); -#else -#define lj_lib_checknumber(L, narg) lj_lib_checknum((L), (narg)) -#endif -LJ_FUNC lua_Number lj_lib_checknum(lua_State *L, int narg); -LJ_FUNC int32_t lj_lib_checkint(lua_State *L, int narg); -LJ_FUNC int32_t lj_lib_optint(lua_State *L, int narg, int32_t def); -LJ_FUNC GCfunc *lj_lib_checkfunc(lua_State *L, int narg); -LJ_FUNC GCtab *lj_lib_checktab(lua_State *L, int narg); -LJ_FUNC GCtab *lj_lib_checktabornil(lua_State *L, int narg); -LJ_FUNC int lj_lib_checkopt(lua_State *L, int narg, int def, const char *lst); - -/* Avoid including lj_frame.h. */ -#if LJ_GC64 -#define lj_lib_upvalue(L, n) \ - (&gcval(L->base-2)->fn.c.upvalue[(n)-1]) -#elif LJ_FR2 -#define lj_lib_upvalue(L, n) \ - (&gcref((L->base-2)->gcr)->fn.c.upvalue[(n)-1]) -#else -#define lj_lib_upvalue(L, n) \ - (&gcref((L->base-1)->fr.func)->fn.c.upvalue[(n)-1]) -#endif - -#if LJ_TARGET_WINDOWS -#define lj_lib_checkfpu(L) \ - do { setnumV(L->top++, (lua_Number)1437217655); \ - if (lua_tointeger(L, -1) != 1437217655) lj_err_caller(L, LJ_ERR_BADFPU); \ - L->top--; } while (0) -#else -#define lj_lib_checkfpu(L) UNUSED(L) -#endif - -LJ_FUNC GCfunc *lj_lib_pushcc(lua_State *L, lua_CFunction f, int id, int n); -#define lj_lib_pushcf(L, fn, id) (lj_lib_pushcc(L, (fn), (id), 0)) - -/* Library function declarations. Scanned by buildvm. */ -#define LJLIB_CF(name) static int lj_cf_##name(lua_State *L) -#define LJLIB_ASM(name) static int lj_ffh_##name(lua_State *L) -#define LJLIB_ASM_(name) -#define LJLIB_LUA(name) -#define LJLIB_SET(name) -#define LJLIB_PUSH(arg) -#define LJLIB_REC(handler) -#define LJLIB_NOREGUV -#define LJLIB_NOREG - -#define LJ_LIB_REG(L, regname, name) \ - lj_lib_register(L, regname, lj_lib_init_##name, lj_lib_cf_##name) - -LJ_FUNC void lj_lib_register(lua_State *L, const char *libname, - const uint8_t *init, const lua_CFunction *cf); -LJ_FUNC void lj_lib_prereg(lua_State *L, const char *name, lua_CFunction f, - GCtab *env); -LJ_FUNC int lj_lib_postreg(lua_State *L, lua_CFunction cf, int id, - const char *name); - -/* Library init data tags. */ -#define LIBINIT_LENMASK 0x3f -#define LIBINIT_TAGMASK 0xc0 -#define LIBINIT_CF 0x00 -#define LIBINIT_ASM 0x40 -#define LIBINIT_ASM_ 0x80 -#define LIBINIT_STRING 0xc0 -#define LIBINIT_MAXSTR 0x38 -#define LIBINIT_LUA 0xf9 -#define LIBINIT_SET 0xfa -#define LIBINIT_NUMBER 0xfb -#define LIBINIT_COPY 0xfc -#define LIBINIT_LASTCL 0xfd -#define LIBINIT_FFID 0xfe -#define LIBINIT_END 0xff - -/* Exported library functions. */ - -typedef struct RandomState RandomState; -LJ_FUNC uint64_t LJ_FASTCALL lj_math_random_step(RandomState *rs); - -#endif diff --git a/lib/LuaJIT/src/lj_load.c b/lib/LuaJIT/src/lj_load.c deleted file mode 100644 index 9a31d9a..0000000 --- a/lib/LuaJIT/src/lj_load.c +++ /dev/null @@ -1,168 +0,0 @@ -/* -** Load and dump code. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#include -#include - -#define lj_load_c -#define LUA_CORE - -#include "lua.h" -#include "lauxlib.h" - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_buf.h" -#include "lj_func.h" -#include "lj_frame.h" -#include "lj_vm.h" -#include "lj_lex.h" -#include "lj_bcdump.h" -#include "lj_parse.h" - -/* -- Load Lua source code and bytecode ----------------------------------- */ - -static TValue *cpparser(lua_State *L, lua_CFunction dummy, void *ud) -{ - LexState *ls = (LexState *)ud; - GCproto *pt; - GCfunc *fn; - int bc; - UNUSED(dummy); - cframe_errfunc(L->cframe) = -1; /* Inherit error function. */ - bc = lj_lex_setup(L, ls); - if (ls->mode && !strchr(ls->mode, bc ? 'b' : 't')) { - setstrV(L, L->top++, lj_err_str(L, LJ_ERR_XMODE)); - lj_err_throw(L, LUA_ERRSYNTAX); - } - pt = bc ? lj_bcread(ls) : lj_parse(ls); - fn = lj_func_newL_empty(L, pt, tabref(L->env)); - /* Don't combine above/below into one statement. */ - setfuncV(L, L->top++, fn); - return NULL; -} - -LUA_API int lua_loadx(lua_State *L, lua_Reader reader, void *data, - const char *chunkname, const char *mode) -{ - LexState ls; - int status; - ls.rfunc = reader; - ls.rdata = data; - ls.chunkarg = chunkname ? chunkname : "?"; - ls.mode = mode; - lj_buf_init(L, &ls.sb); - status = lj_vm_cpcall(L, NULL, &ls, cpparser); - lj_lex_cleanup(L, &ls); - lj_gc_check(L); - return status; -} - -LUA_API int lua_load(lua_State *L, lua_Reader reader, void *data, - const char *chunkname) -{ - return lua_loadx(L, reader, data, chunkname, NULL); -} - -typedef struct FileReaderCtx { - FILE *fp; - char buf[LUAL_BUFFERSIZE]; -} FileReaderCtx; - -static const char *reader_file(lua_State *L, void *ud, size_t *size) -{ - FileReaderCtx *ctx = (FileReaderCtx *)ud; - UNUSED(L); - if (feof(ctx->fp)) return NULL; - *size = fread(ctx->buf, 1, sizeof(ctx->buf), ctx->fp); - return *size > 0 ? ctx->buf : NULL; -} - -LUALIB_API int luaL_loadfilex(lua_State *L, const char *filename, - const char *mode) -{ - FileReaderCtx ctx; - int status; - const char *chunkname; - if (filename) { - ctx.fp = fopen(filename, "rb"); - if (ctx.fp == NULL) { - lua_pushfstring(L, "cannot open %s: %s", filename, strerror(errno)); - return LUA_ERRFILE; - } - chunkname = lua_pushfstring(L, "@%s", filename); - } else { - ctx.fp = stdin; - chunkname = "=stdin"; - } - status = lua_loadx(L, reader_file, &ctx, chunkname, mode); - if (ferror(ctx.fp)) { - L->top -= filename ? 2 : 1; - lua_pushfstring(L, "cannot read %s: %s", chunkname+1, strerror(errno)); - if (filename) - fclose(ctx.fp); - return LUA_ERRFILE; - } - if (filename) { - L->top--; - copyTV(L, L->top-1, L->top); - fclose(ctx.fp); - } - return status; -} - -LUALIB_API int luaL_loadfile(lua_State *L, const char *filename) -{ - return luaL_loadfilex(L, filename, NULL); -} - -typedef struct StringReaderCtx { - const char *str; - size_t size; -} StringReaderCtx; - -static const char *reader_string(lua_State *L, void *ud, size_t *size) -{ - StringReaderCtx *ctx = (StringReaderCtx *)ud; - UNUSED(L); - if (ctx->size == 0) return NULL; - *size = ctx->size; - ctx->size = 0; - return ctx->str; -} - -LUALIB_API int luaL_loadbufferx(lua_State *L, const char *buf, size_t size, - const char *name, const char *mode) -{ - StringReaderCtx ctx; - ctx.str = buf; - ctx.size = size; - return lua_loadx(L, reader_string, &ctx, name, mode); -} - -LUALIB_API int luaL_loadbuffer(lua_State *L, const char *buf, size_t size, - const char *name) -{ - return luaL_loadbufferx(L, buf, size, name, NULL); -} - -LUALIB_API int luaL_loadstring(lua_State *L, const char *s) -{ - return luaL_loadbuffer(L, s, strlen(s), s); -} - -/* -- Dump bytecode ------------------------------------------------------- */ - -LUA_API int lua_dump(lua_State *L, lua_Writer writer, void *data) -{ - cTValue *o = L->top-1; - api_check(L, L->top > L->base); - if (tvisfunc(o) && isluafunc(funcV(o))) - return lj_bcwrite(L, funcproto(funcV(o)), writer, data, 0); - else - return 1; -} - diff --git a/lib/LuaJIT/src/lj_mcode.c b/lib/LuaJIT/src/lj_mcode.c deleted file mode 100644 index 64b0ca9..0000000 --- a/lib/LuaJIT/src/lj_mcode.c +++ /dev/null @@ -1,381 +0,0 @@ -/* -** Machine code management. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_mcode_c -#define LUA_CORE - -#include "lj_obj.h" -#if LJ_HASJIT -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_jit.h" -#include "lj_mcode.h" -#include "lj_trace.h" -#include "lj_dispatch.h" -#endif -#if LJ_HASJIT || LJ_HASFFI -#include "lj_vm.h" -#endif - -/* -- OS-specific functions ----------------------------------------------- */ - -#if LJ_HASJIT || LJ_HASFFI - -/* Define this if you want to run LuaJIT with Valgrind. */ -#ifdef LUAJIT_USE_VALGRIND -#include -#endif - -#if LJ_TARGET_IOS -void sys_icache_invalidate(void *start, size_t len); -#endif - -/* Synchronize data/instruction cache. */ -void lj_mcode_sync(void *start, void *end) -{ -#ifdef LUAJIT_USE_VALGRIND - VALGRIND_DISCARD_TRANSLATIONS(start, (char *)end-(char *)start); -#endif -#if LJ_TARGET_X86ORX64 - UNUSED(start); UNUSED(end); -#elif LJ_TARGET_IOS - sys_icache_invalidate(start, (char *)end-(char *)start); -#elif LJ_TARGET_PPC - lj_vm_cachesync(start, end); -#elif defined(__GNUC__) - __clear_cache(start, end); -#else -#error "Missing builtin to flush instruction cache" -#endif -} - -#endif - -#if LJ_HASJIT - -#if LJ_TARGET_WINDOWS - -#define WIN32_LEAN_AND_MEAN -#include - -#define MCPROT_RW PAGE_READWRITE -#define MCPROT_RX PAGE_EXECUTE_READ -#define MCPROT_RWX PAGE_EXECUTE_READWRITE - -static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, DWORD prot) -{ - void *p = LJ_WIN_VALLOC((void *)hint, sz, - MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, prot); - if (!p && !hint) - lj_trace_err(J, LJ_TRERR_MCODEAL); - return p; -} - -static void mcode_free(jit_State *J, void *p, size_t sz) -{ - UNUSED(J); UNUSED(sz); - VirtualFree(p, 0, MEM_RELEASE); -} - -static int mcode_setprot(void *p, size_t sz, DWORD prot) -{ - DWORD oprot; - return !LJ_WIN_VPROTECT(p, sz, prot, &oprot); -} - -#elif LJ_TARGET_POSIX - -#include - -#ifndef MAP_ANONYMOUS -#define MAP_ANONYMOUS MAP_ANON -#endif - -#define MCPROT_RW (PROT_READ|PROT_WRITE) -#define MCPROT_RX (PROT_READ|PROT_EXEC) -#define MCPROT_RWX (PROT_READ|PROT_WRITE|PROT_EXEC) - -static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, int prot) -{ - void *p = mmap((void *)hint, sz, prot, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); - if (p == MAP_FAILED) { - if (!hint) lj_trace_err(J, LJ_TRERR_MCODEAL); - p = NULL; - } - return p; -} - -static void mcode_free(jit_State *J, void *p, size_t sz) -{ - UNUSED(J); - munmap(p, sz); -} - -static int mcode_setprot(void *p, size_t sz, int prot) -{ - return mprotect(p, sz, prot); -} - -#elif LJ_64 - -#error "Missing OS support for explicit placement of executable memory" - -#else - -/* Fallback allocator. This will fail if memory is not executable by default. */ -#define LUAJIT_UNPROTECT_MCODE -#define MCPROT_RW 0 -#define MCPROT_RX 0 -#define MCPROT_RWX 0 - -static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, int prot) -{ - UNUSED(hint); UNUSED(prot); - return lj_mem_new(J->L, sz); -} - -static void mcode_free(jit_State *J, void *p, size_t sz) -{ - lj_mem_free(J2G(J), p, sz); -} - -#endif - -/* -- MCode area protection ----------------------------------------------- */ - -/* Define this ONLY if page protection twiddling becomes a bottleneck. */ -#ifdef LUAJIT_UNPROTECT_MCODE - -/* It's generally considered to be a potential security risk to have -** pages with simultaneous write *and* execute access in a process. -** -** Do not even think about using this mode for server processes or -** apps handling untrusted external data (such as a browser). -** -** The security risk is not in LuaJIT itself -- but if an adversary finds -** any *other* flaw in your C application logic, then any RWX memory page -** simplifies writing an exploit considerably. -*/ -#define MCPROT_GEN MCPROT_RWX -#define MCPROT_RUN MCPROT_RWX - -static void mcode_protect(jit_State *J, int prot) -{ - UNUSED(J); UNUSED(prot); -} - -#else - -/* This is the default behaviour and much safer: -** -** Most of the time the memory pages holding machine code are executable, -** but NONE of them is writable. -** -** The current memory area is marked read-write (but NOT executable) only -** during the short time window while the assembler generates machine code. -*/ -#define MCPROT_GEN MCPROT_RW -#define MCPROT_RUN MCPROT_RX - -/* Protection twiddling failed. Probably due to kernel security. */ -static LJ_NOINLINE void mcode_protfail(jit_State *J) -{ - lua_CFunction panic = J2G(J)->panic; - if (panic) { - lua_State *L = J->L; - setstrV(L, L->top++, lj_err_str(L, LJ_ERR_JITPROT)); - panic(L); - } -} - -/* Change protection of MCode area. */ -static void mcode_protect(jit_State *J, int prot) -{ - if (J->mcprot != prot) { - if (LJ_UNLIKELY(mcode_setprot(J->mcarea, J->szmcarea, prot))) - mcode_protfail(J); - J->mcprot = prot; - } -} - -#endif - -/* -- MCode area allocation ----------------------------------------------- */ - -#if LJ_64 -#define mcode_validptr(p) (p) -#else -#define mcode_validptr(p) ((p) && (uintptr_t)(p) < 0xffff0000) -#endif - -#ifdef LJ_TARGET_JUMPRANGE - -/* Get memory within relative jump distance of our code in 64 bit mode. */ -static void *mcode_alloc(jit_State *J, size_t sz) -{ - /* Target an address in the static assembler code (64K aligned). - ** Try addresses within a distance of target-range/2+1MB..target+range/2-1MB. - ** Use half the jump range so every address in the range can reach any other. - */ -#if LJ_TARGET_MIPS - /* Use the middle of the 256MB-aligned region. */ - uintptr_t target = ((uintptr_t)(void *)lj_vm_exit_handler & - ~(uintptr_t)0x0fffffffu) + 0x08000000u; -#else - uintptr_t target = (uintptr_t)(void *)lj_vm_exit_handler & ~(uintptr_t)0xffff; -#endif - const uintptr_t range = (1u << (LJ_TARGET_JUMPRANGE-1)) - (1u << 21); - /* First try a contiguous area below the last one. */ - uintptr_t hint = J->mcarea ? (uintptr_t)J->mcarea - sz : 0; - int i; - /* Limit probing iterations, depending on the available pool size. */ - for (i = 0; i < LJ_TARGET_JUMPRANGE; i++) { - if (mcode_validptr(hint)) { - void *p = mcode_alloc_at(J, hint, sz, MCPROT_GEN); - - if (mcode_validptr(p) && - ((uintptr_t)p + sz - target < range || target - (uintptr_t)p < range)) - return p; - if (p) mcode_free(J, p, sz); /* Free badly placed area. */ - } - /* Next try probing 64K-aligned pseudo-random addresses. */ - do { - hint = LJ_PRNG_BITS(J, LJ_TARGET_JUMPRANGE-16) << 16; - } while (!(hint + sz < range+range)); - hint = target + hint - range; - } - lj_trace_err(J, LJ_TRERR_MCODEAL); /* Give up. OS probably ignores hints? */ - return NULL; -} - -#else - -/* All memory addresses are reachable by relative jumps. */ -static void *mcode_alloc(jit_State *J, size_t sz) -{ -#if defined(__OpenBSD__) || LJ_TARGET_UWP - /* Allow better executable memory allocation for OpenBSD W^X mode. */ - void *p = mcode_alloc_at(J, 0, sz, MCPROT_RUN); - if (p && mcode_setprot(p, sz, MCPROT_GEN)) { - mcode_free(J, p, sz); - return NULL; - } - return p; -#else - return mcode_alloc_at(J, 0, sz, MCPROT_GEN); -#endif -} - -#endif - -/* -- MCode area management ----------------------------------------------- */ - -/* Allocate a new MCode area. */ -static void mcode_allocarea(jit_State *J) -{ - MCode *oldarea = J->mcarea; - size_t sz = (size_t)J->param[JIT_P_sizemcode] << 10; - sz = (sz + LJ_PAGESIZE-1) & ~(size_t)(LJ_PAGESIZE - 1); - J->mcarea = (MCode *)mcode_alloc(J, sz); - J->szmcarea = sz; - J->mcprot = MCPROT_GEN; - J->mctop = (MCode *)((char *)J->mcarea + J->szmcarea); - J->mcbot = (MCode *)((char *)J->mcarea + sizeof(MCLink)); - ((MCLink *)J->mcarea)->next = oldarea; - ((MCLink *)J->mcarea)->size = sz; - J->szallmcarea += sz; -} - -/* Free all MCode areas. */ -void lj_mcode_free(jit_State *J) -{ - MCode *mc = J->mcarea; - J->mcarea = NULL; - J->szallmcarea = 0; - while (mc) { - MCode *next = ((MCLink *)mc)->next; - mcode_free(J, mc, ((MCLink *)mc)->size); - mc = next; - } -} - -/* -- MCode transactions -------------------------------------------------- */ - -/* Reserve the remainder of the current MCode area. */ -MCode *lj_mcode_reserve(jit_State *J, MCode **lim) -{ - if (!J->mcarea) - mcode_allocarea(J); - else - mcode_protect(J, MCPROT_GEN); - *lim = J->mcbot; - return J->mctop; -} - -/* Commit the top part of the current MCode area. */ -void lj_mcode_commit(jit_State *J, MCode *top) -{ - J->mctop = top; - mcode_protect(J, MCPROT_RUN); -} - -/* Abort the reservation. */ -void lj_mcode_abort(jit_State *J) -{ - if (J->mcarea) - mcode_protect(J, MCPROT_RUN); -} - -/* Set/reset protection to allow patching of MCode areas. */ -MCode *lj_mcode_patch(jit_State *J, MCode *ptr, int finish) -{ -#ifdef LUAJIT_UNPROTECT_MCODE - UNUSED(J); UNUSED(ptr); UNUSED(finish); - return NULL; -#else - if (finish) { - if (J->mcarea == ptr) - mcode_protect(J, MCPROT_RUN); - else if (LJ_UNLIKELY(mcode_setprot(ptr, ((MCLink *)ptr)->size, MCPROT_RUN))) - mcode_protfail(J); - return NULL; - } else { - MCode *mc = J->mcarea; - /* Try current area first to use the protection cache. */ - if (ptr >= mc && ptr < (MCode *)((char *)mc + J->szmcarea)) { - mcode_protect(J, MCPROT_GEN); - return mc; - } - /* Otherwise search through the list of MCode areas. */ - for (;;) { - mc = ((MCLink *)mc)->next; - lua_assert(mc != NULL); - if (ptr >= mc && ptr < (MCode *)((char *)mc + ((MCLink *)mc)->size)) { - if (LJ_UNLIKELY(mcode_setprot(mc, ((MCLink *)mc)->size, MCPROT_GEN))) - mcode_protfail(J); - return mc; - } - } - } -#endif -} - -/* Limit of MCode reservation reached. */ -void lj_mcode_limiterr(jit_State *J, size_t need) -{ - size_t sizemcode, maxmcode; - lj_mcode_abort(J); - sizemcode = (size_t)J->param[JIT_P_sizemcode] << 10; - sizemcode = (sizemcode + LJ_PAGESIZE-1) & ~(size_t)(LJ_PAGESIZE - 1); - maxmcode = (size_t)J->param[JIT_P_maxmcode] << 10; - if ((size_t)need > sizemcode) - lj_trace_err(J, LJ_TRERR_MCODEOV); /* Too long for any area. */ - if (J->szallmcarea + sizemcode > maxmcode) - lj_trace_err(J, LJ_TRERR_MCODEAL); - mcode_allocarea(J); - lj_trace_err(J, LJ_TRERR_MCODELM); /* Retry with new area. */ -} - -#endif diff --git a/lib/LuaJIT/src/lj_mcode.h b/lib/LuaJIT/src/lj_mcode.h deleted file mode 100644 index f0847e9..0000000 --- a/lib/LuaJIT/src/lj_mcode.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -** Machine code management. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_MCODE_H -#define _LJ_MCODE_H - -#include "lj_obj.h" - -#if LJ_HASJIT || LJ_HASFFI -LJ_FUNC void lj_mcode_sync(void *start, void *end); -#endif - -#if LJ_HASJIT - -#include "lj_jit.h" - -LJ_FUNC void lj_mcode_free(jit_State *J); -LJ_FUNC MCode *lj_mcode_reserve(jit_State *J, MCode **lim); -LJ_FUNC void lj_mcode_commit(jit_State *J, MCode *m); -LJ_FUNC void lj_mcode_abort(jit_State *J); -LJ_FUNC MCode *lj_mcode_patch(jit_State *J, MCode *ptr, int finish); -LJ_FUNC_NORET void lj_mcode_limiterr(jit_State *J, size_t need); - -#define lj_mcode_commitbot(J, m) (J->mcbot = (m)) - -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_meta.c b/lib/LuaJIT/src/lj_meta.c deleted file mode 100644 index 0bd4d84..0000000 --- a/lib/LuaJIT/src/lj_meta.c +++ /dev/null @@ -1,477 +0,0 @@ -/* -** Metamethod handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Portions taken verbatim or adapted from the Lua interpreter. -** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h -*/ - -#define lj_meta_c -#define LUA_CORE - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_buf.h" -#include "lj_str.h" -#include "lj_tab.h" -#include "lj_meta.h" -#include "lj_frame.h" -#include "lj_bc.h" -#include "lj_vm.h" -#include "lj_strscan.h" -#include "lj_strfmt.h" -#include "lj_lib.h" - -/* -- Metamethod handling ------------------------------------------------- */ - -/* String interning of metamethod names for fast indexing. */ -void lj_meta_init(lua_State *L) -{ -#define MMNAME(name) "__" #name - const char *metanames = MMDEF(MMNAME); -#undef MMNAME - global_State *g = G(L); - const char *p, *q; - uint32_t mm; - for (mm = 0, p = metanames; *p; mm++, p = q) { - GCstr *s; - for (q = p+2; *q && *q != '_'; q++) ; - s = lj_str_new(L, p, (size_t)(q-p)); - /* NOBARRIER: g->gcroot[] is a GC root. */ - setgcref(g->gcroot[GCROOT_MMNAME+mm], obj2gco(s)); - } -} - -/* Negative caching of a few fast metamethods. See the lj_meta_fast() macro. */ -cTValue *lj_meta_cache(GCtab *mt, MMS mm, GCstr *name) -{ - cTValue *mo = lj_tab_getstr(mt, name); - lua_assert(mm <= MM_FAST); - if (!mo || tvisnil(mo)) { /* No metamethod? */ - mt->nomm |= (uint8_t)(1u<metatable); - else if (tvisudata(o)) - mt = tabref(udataV(o)->metatable); - else - mt = tabref(basemt_obj(G(L), o)); - if (mt) { - cTValue *mo = lj_tab_getstr(mt, mmname_str(G(L), mm)); - if (mo) - return mo; - } - return niltv(L); -} - -#if LJ_HASFFI -/* Tailcall from C function. */ -int lj_meta_tailcall(lua_State *L, cTValue *tv) -{ - TValue *base = L->base; - TValue *top = L->top; - const BCIns *pc = frame_pc(base-1); /* Preserve old PC from frame. */ - copyTV(L, base-1-LJ_FR2, tv); /* Replace frame with new object. */ - if (LJ_FR2) - (top++)->u64 = LJ_CONT_TAILCALL; - else - top->u32.lo = LJ_CONT_TAILCALL; - setframe_pc(top++, pc); - if (LJ_FR2) top++; - setframe_gc(top, obj2gco(L), LJ_TTHREAD); /* Dummy frame object. */ - setframe_ftsz(top, ((char *)(top+1) - (char *)base) + FRAME_CONT); - L->base = L->top = top+1; - /* - ** before: [old_mo|PC] [... ...] - ** ^base ^top - ** after: [new_mo|itype] [... ...] [NULL|PC] [dummy|delta] - ** ^base/top - ** tailcall: [new_mo|PC] [... ...] - ** ^base ^top - */ - return 0; -} -#endif - -/* Setup call to metamethod to be run by Assembler VM. */ -static TValue *mmcall(lua_State *L, ASMFunction cont, cTValue *mo, - cTValue *a, cTValue *b) -{ - /* - ** |-- framesize -> top top+1 top+2 top+3 - ** before: [func slots ...] - ** mm setup: [func slots ...] [cont|?] [mo|tmtype] [a] [b] - ** in asm: [func slots ...] [cont|PC] [mo|delta] [a] [b] - ** ^-- func base ^-- mm base - ** after mm: [func slots ...] [result] - ** ^-- copy to base[PC_RA] --/ for lj_cont_ra - ** istruecond + branch for lj_cont_cond* - ** ignore for lj_cont_nop - ** next PC: [func slots ...] - */ - TValue *top = L->top; - if (curr_funcisL(L)) top = curr_topL(L); - setcont(top++, cont); /* Assembler VM stores PC in upper word or FR2. */ - if (LJ_FR2) setnilV(top++); - copyTV(L, top++, mo); /* Store metamethod and two arguments. */ - if (LJ_FR2) setnilV(top++); - copyTV(L, top, a); - copyTV(L, top+1, b); - return top; /* Return new base. */ -} - -/* -- C helpers for some instructions, called from assembler VM ----------- */ - -/* Helper for TGET*. __index chain and metamethod. */ -cTValue *lj_meta_tget(lua_State *L, cTValue *o, cTValue *k) -{ - int loop; - for (loop = 0; loop < LJ_MAX_IDXCHAIN; loop++) { - cTValue *mo; - if (LJ_LIKELY(tvistab(o))) { - GCtab *t = tabV(o); - cTValue *tv = lj_tab_get(L, t, k); - if (!tvisnil(tv) || - !(mo = lj_meta_fast(L, tabref(t->metatable), MM_index))) - return tv; - } else if (tvisnil(mo = lj_meta_lookup(L, o, MM_index))) { - lj_err_optype(L, o, LJ_ERR_OPINDEX); - return NULL; /* unreachable */ - } - if (tvisfunc(mo)) { - L->top = mmcall(L, lj_cont_ra, mo, o, k); - return NULL; /* Trigger metamethod call. */ - } - o = mo; - } - lj_err_msg(L, LJ_ERR_GETLOOP); - return NULL; /* unreachable */ -} - -/* Helper for TSET*. __newindex chain and metamethod. */ -TValue *lj_meta_tset(lua_State *L, cTValue *o, cTValue *k) -{ - TValue tmp; - int loop; - for (loop = 0; loop < LJ_MAX_IDXCHAIN; loop++) { - cTValue *mo; - if (LJ_LIKELY(tvistab(o))) { - GCtab *t = tabV(o); - cTValue *tv = lj_tab_get(L, t, k); - if (LJ_LIKELY(!tvisnil(tv))) { - t->nomm = 0; /* Invalidate negative metamethod cache. */ - lj_gc_anybarriert(L, t); - return (TValue *)tv; - } else if (!(mo = lj_meta_fast(L, tabref(t->metatable), MM_newindex))) { - t->nomm = 0; /* Invalidate negative metamethod cache. */ - lj_gc_anybarriert(L, t); - if (tv != niltv(L)) - return (TValue *)tv; - if (tvisnil(k)) lj_err_msg(L, LJ_ERR_NILIDX); - else if (tvisint(k)) { setnumV(&tmp, (lua_Number)intV(k)); k = &tmp; } - else if (tvisnum(k) && tvisnan(k)) lj_err_msg(L, LJ_ERR_NANIDX); - return lj_tab_newkey(L, t, k); - } - } else if (tvisnil(mo = lj_meta_lookup(L, o, MM_newindex))) { - lj_err_optype(L, o, LJ_ERR_OPINDEX); - return NULL; /* unreachable */ - } - if (tvisfunc(mo)) { - L->top = mmcall(L, lj_cont_nop, mo, o, k); - /* L->top+2 = v filled in by caller. */ - return NULL; /* Trigger metamethod call. */ - } - copyTV(L, &tmp, mo); - o = &tmp; - } - lj_err_msg(L, LJ_ERR_SETLOOP); - return NULL; /* unreachable */ -} - -static cTValue *str2num(cTValue *o, TValue *n) -{ - if (tvisnum(o)) - return o; - else if (tvisint(o)) - return (setnumV(n, (lua_Number)intV(o)), n); - else if (tvisstr(o) && lj_strscan_num(strV(o), n)) - return n; - else - return NULL; -} - -/* Helper for arithmetic instructions. Coercion, metamethod. */ -TValue *lj_meta_arith(lua_State *L, TValue *ra, cTValue *rb, cTValue *rc, - BCReg op) -{ - MMS mm = bcmode_mm(op); - TValue tempb, tempc; - cTValue *b, *c; - if ((b = str2num(rb, &tempb)) != NULL && - (c = str2num(rc, &tempc)) != NULL) { /* Try coercion first. */ - setnumV(ra, lj_vm_foldarith(numV(b), numV(c), (int)mm-MM_add)); - return NULL; - } else { - cTValue *mo = lj_meta_lookup(L, rb, mm); - if (tvisnil(mo)) { - mo = lj_meta_lookup(L, rc, mm); - if (tvisnil(mo)) { - if (str2num(rb, &tempb) == NULL) rc = rb; - lj_err_optype(L, rc, LJ_ERR_OPARITH); - return NULL; /* unreachable */ - } - } - return mmcall(L, lj_cont_ra, mo, rb, rc); - } -} - -/* Helper for CAT. Coercion, iterative concat, __concat metamethod. */ -TValue *lj_meta_cat(lua_State *L, TValue *top, int left) -{ - int fromc = 0; - if (left < 0) { left = -left; fromc = 1; } - do { - if (!(tvisstr(top) || tvisnumber(top)) || - !(tvisstr(top-1) || tvisnumber(top-1))) { - cTValue *mo = lj_meta_lookup(L, top-1, MM_concat); - if (tvisnil(mo)) { - mo = lj_meta_lookup(L, top, MM_concat); - if (tvisnil(mo)) { - if (tvisstr(top-1) || tvisnumber(top-1)) top++; - lj_err_optype(L, top-1, LJ_ERR_OPCAT); - return NULL; /* unreachable */ - } - } - /* One of the top two elements is not a string, call __cat metamethod: - ** - ** before: [...][CAT stack .........................] - ** top-1 top top+1 top+2 - ** pick two: [...][CAT stack ...] [o1] [o2] - ** setup mm: [...][CAT stack ...] [cont|?] [mo|tmtype] [o1] [o2] - ** in asm: [...][CAT stack ...] [cont|PC] [mo|delta] [o1] [o2] - ** ^-- func base ^-- mm base - ** after mm: [...][CAT stack ...] <--push-- [result] - ** next step: [...][CAT stack .............] - */ - copyTV(L, top+2*LJ_FR2+2, top); /* Carefully ordered stack copies! */ - copyTV(L, top+2*LJ_FR2+1, top-1); - copyTV(L, top+LJ_FR2, mo); - setcont(top-1, lj_cont_cat); - if (LJ_FR2) { setnilV(top); setnilV(top+2); top += 2; } - return top+1; /* Trigger metamethod call. */ - } else { - /* Pick as many strings as possible from the top and concatenate them: - ** - ** before: [...][CAT stack ...........................] - ** pick str: [...][CAT stack ...] [...... strings ......] - ** concat: [...][CAT stack ...] [result] - ** next step: [...][CAT stack ............] - */ - TValue *e, *o = top; - uint64_t tlen = tvisstr(o) ? strV(o)->len : STRFMT_MAXBUF_NUM; - SBuf *sb; - do { - o--; tlen += tvisstr(o) ? strV(o)->len : STRFMT_MAXBUF_NUM; - } while (--left > 0 && (tvisstr(o-1) || tvisnumber(o-1))); - if (tlen >= LJ_MAX_STR) lj_err_msg(L, LJ_ERR_STROV); - sb = lj_buf_tmp_(L); - lj_buf_more(sb, (MSize)tlen); - for (e = top, top = o; o <= e; o++) { - if (tvisstr(o)) { - GCstr *s = strV(o); - MSize len = s->len; - lj_buf_putmem(sb, strdata(s), len); - } else if (tvisint(o)) { - lj_strfmt_putint(sb, intV(o)); - } else { - lj_strfmt_putfnum(sb, STRFMT_G14, numV(o)); - } - } - setstrV(L, top, lj_buf_str(L, sb)); - } - } while (left >= 1); - if (LJ_UNLIKELY(G(L)->gc.total >= G(L)->gc.threshold)) { - if (!fromc) L->top = curr_topL(L); - lj_gc_step(L); - } - return NULL; -} - -/* Helper for LEN. __len metamethod. */ -TValue * LJ_FASTCALL lj_meta_len(lua_State *L, cTValue *o) -{ - cTValue *mo = lj_meta_lookup(L, o, MM_len); - if (tvisnil(mo)) { - if (LJ_52 && tvistab(o)) - tabref(tabV(o)->metatable)->nomm |= (uint8_t)(1u<gch.metatable), MM_eq); - if (mo) { - TValue *top; - uint32_t it; - if (tabref(o1->gch.metatable) != tabref(o2->gch.metatable)) { - cTValue *mo2 = lj_meta_fast(L, tabref(o2->gch.metatable), MM_eq); - if (mo2 == NULL || !lj_obj_equal(mo, mo2)) - return (TValue *)(intptr_t)ne; - } - top = curr_top(L); - setcont(top++, ne ? lj_cont_condf : lj_cont_condt); - if (LJ_FR2) setnilV(top++); - copyTV(L, top++, mo); - if (LJ_FR2) setnilV(top++); - it = ~(uint32_t)o1->gch.gct; - setgcV(L, top, o1, it); - setgcV(L, top+1, o2, it); - return top; /* Trigger metamethod call. */ - } - return (TValue *)(intptr_t)ne; -} - -#if LJ_HASFFI -TValue * LJ_FASTCALL lj_meta_equal_cd(lua_State *L, BCIns ins) -{ - ASMFunction cont = (bc_op(ins) & 1) ? lj_cont_condf : lj_cont_condt; - int op = (int)bc_op(ins) & ~1; - TValue tv; - cTValue *mo, *o2, *o1 = &L->base[bc_a(ins)]; - cTValue *o1mm = o1; - if (op == BC_ISEQV) { - o2 = &L->base[bc_d(ins)]; - if (!tviscdata(o1mm)) o1mm = o2; - } else if (op == BC_ISEQS) { - setstrV(L, &tv, gco2str(proto_kgc(curr_proto(L), ~(ptrdiff_t)bc_d(ins)))); - o2 = &tv; - } else if (op == BC_ISEQN) { - o2 = &mref(curr_proto(L)->k, cTValue)[bc_d(ins)]; - } else { - lua_assert(op == BC_ISEQP); - setpriV(&tv, ~bc_d(ins)); - o2 = &tv; - } - mo = lj_meta_lookup(L, o1mm, MM_eq); - if (LJ_LIKELY(!tvisnil(mo))) - return mmcall(L, cont, mo, o1, o2); - else - return (TValue *)(intptr_t)(bc_op(ins) & 1); -} -#endif - -/* Helper for ordered comparisons. String compare, __lt/__le metamethods. */ -TValue *lj_meta_comp(lua_State *L, cTValue *o1, cTValue *o2, int op) -{ - if (LJ_HASFFI && (tviscdata(o1) || tviscdata(o2))) { - ASMFunction cont = (op & 1) ? lj_cont_condf : lj_cont_condt; - MMS mm = (op & 2) ? MM_le : MM_lt; - cTValue *mo = lj_meta_lookup(L, tviscdata(o1) ? o1 : o2, mm); - if (LJ_UNLIKELY(tvisnil(mo))) goto err; - return mmcall(L, cont, mo, o1, o2); - } else if (LJ_52 || itype(o1) == itype(o2)) { - /* Never called with two numbers. */ - if (tvisstr(o1) && tvisstr(o2)) { - int32_t res = lj_str_cmp(strV(o1), strV(o2)); - return (TValue *)(intptr_t)(((op&2) ? res <= 0 : res < 0) ^ (op&1)); - } else { - trymt: - while (1) { - ASMFunction cont = (op & 1) ? lj_cont_condf : lj_cont_condt; - MMS mm = (op & 2) ? MM_le : MM_lt; - cTValue *mo = lj_meta_lookup(L, o1, mm); -#if LJ_52 - if (tvisnil(mo) && tvisnil((mo = lj_meta_lookup(L, o2, mm)))) -#else - cTValue *mo2 = lj_meta_lookup(L, o2, mm); - if (tvisnil(mo) || !lj_obj_equal(mo, mo2)) -#endif - { - if (op & 2) { /* MM_le not found: retry with MM_lt. */ - cTValue *ot = o1; o1 = o2; o2 = ot; /* Swap operands. */ - op ^= 3; /* Use LT and flip condition. */ - continue; - } - goto err; - } - return mmcall(L, cont, mo, o1, o2); - } - } - } else if (tvisbool(o1) && tvisbool(o2)) { - goto trymt; - } else { - err: - lj_err_comp(L, o1, o2); - return NULL; - } -} - -/* Helper for ISTYPE and ISNUM. Implicit coercion or error. */ -void lj_meta_istype(lua_State *L, BCReg ra, BCReg tp) -{ - L->top = curr_topL(L); - ra++; tp--; - lua_assert(LJ_DUALNUM || tp != ~LJ_TNUMX); /* ISTYPE -> ISNUM broken. */ - if (LJ_DUALNUM && tp == ~LJ_TNUMX) lj_lib_checkint(L, ra); - else if (tp == ~LJ_TNUMX+1) lj_lib_checknum(L, ra); - else if (tp == ~LJ_TSTR) lj_lib_checkstr(L, ra); - else lj_err_argtype(L, ra, lj_obj_itypename[tp]); -} - -/* Helper for calls. __call metamethod. */ -void lj_meta_call(lua_State *L, TValue *func, TValue *top) -{ - cTValue *mo = lj_meta_lookup(L, func, MM_call); - TValue *p; - if (!tvisfunc(mo)) - lj_err_optype_call(L, func); - for (p = top; p > func+2*LJ_FR2; p--) copyTV(L, p, p-1); - if (LJ_FR2) copyTV(L, func+2, func); - copyTV(L, func, mo); -} - -/* Helper for FORI. Coercion. */ -void LJ_FASTCALL lj_meta_for(lua_State *L, TValue *o) -{ - if (!lj_strscan_numberobj(o)) lj_err_msg(L, LJ_ERR_FORINIT); - if (!lj_strscan_numberobj(o+1)) lj_err_msg(L, LJ_ERR_FORLIM); - if (!lj_strscan_numberobj(o+2)) lj_err_msg(L, LJ_ERR_FORSTEP); - if (LJ_DUALNUM) { - /* Ensure all slots are integers or all slots are numbers. */ - int32_t k[3]; - int nint = 0; - ptrdiff_t i; - for (i = 0; i <= 2; i++) { - if (tvisint(o+i)) { - k[i] = intV(o+i); nint++; - } else { - k[i] = lj_num2int(numV(o+i)); nint += ((lua_Number)k[i] == numV(o+i)); - } - } - if (nint == 3) { /* Narrow to integers. */ - setintV(o, k[0]); - setintV(o+1, k[1]); - setintV(o+2, k[2]); - } else if (nint != 0) { /* Widen to numbers. */ - if (tvisint(o)) setnumV(o, (lua_Number)intV(o)); - if (tvisint(o+1)) setnumV(o+1, (lua_Number)intV(o+1)); - if (tvisint(o+2)) setnumV(o+2, (lua_Number)intV(o+2)); - } - } -} - diff --git a/lib/LuaJIT/src/lj_meta.h b/lib/LuaJIT/src/lj_meta.h deleted file mode 100644 index 73b4572..0000000 --- a/lib/LuaJIT/src/lj_meta.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -** Metamethod handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_META_H -#define _LJ_META_H - -#include "lj_obj.h" - -/* Metamethod handling */ -LJ_FUNC void lj_meta_init(lua_State *L); -LJ_FUNC cTValue *lj_meta_cache(GCtab *mt, MMS mm, GCstr *name); -LJ_FUNC cTValue *lj_meta_lookup(lua_State *L, cTValue *o, MMS mm); -#if LJ_HASFFI -LJ_FUNC int lj_meta_tailcall(lua_State *L, cTValue *tv); -#endif - -#define lj_meta_fastg(g, mt, mm) \ - ((mt) == NULL ? NULL : ((mt)->nomm & (1u<<(mm))) ? NULL : \ - lj_meta_cache(mt, mm, mmname_str(g, mm))) -#define lj_meta_fast(L, mt, mm) lj_meta_fastg(G(L), mt, mm) - -/* C helpers for some instructions, called from assembler VM. */ -LJ_FUNCA cTValue *lj_meta_tget(lua_State *L, cTValue *o, cTValue *k); -LJ_FUNCA TValue *lj_meta_tset(lua_State *L, cTValue *o, cTValue *k); -LJ_FUNCA TValue *lj_meta_arith(lua_State *L, TValue *ra, cTValue *rb, - cTValue *rc, BCReg op); -LJ_FUNCA TValue *lj_meta_cat(lua_State *L, TValue *top, int left); -LJ_FUNCA TValue * LJ_FASTCALL lj_meta_len(lua_State *L, cTValue *o); -LJ_FUNCA TValue *lj_meta_equal(lua_State *L, GCobj *o1, GCobj *o2, int ne); -LJ_FUNCA TValue * LJ_FASTCALL lj_meta_equal_cd(lua_State *L, BCIns ins); -LJ_FUNCA TValue *lj_meta_comp(lua_State *L, cTValue *o1, cTValue *o2, int op); -LJ_FUNCA void lj_meta_istype(lua_State *L, BCReg ra, BCReg tp); -LJ_FUNCA void lj_meta_call(lua_State *L, TValue *func, TValue *top); -LJ_FUNCA void LJ_FASTCALL lj_meta_for(lua_State *L, TValue *o); - -#endif diff --git a/lib/LuaJIT/src/lj_obj.c b/lib/LuaJIT/src/lj_obj.c deleted file mode 100644 index ee33aeb..0000000 --- a/lib/LuaJIT/src/lj_obj.c +++ /dev/null @@ -1,50 +0,0 @@ -/* -** Miscellaneous object handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_obj_c -#define LUA_CORE - -#include "lj_obj.h" - -/* Object type names. */ -LJ_DATADEF const char *const lj_obj_typename[] = { /* ORDER LUA_T */ - "no value", "nil", "boolean", "userdata", "number", "string", - "table", "function", "userdata", "thread", "proto", "cdata" -}; - -LJ_DATADEF const char *const lj_obj_itypename[] = { /* ORDER LJ_T */ - "nil", "boolean", "boolean", "userdata", "string", "upval", "thread", - "proto", "function", "trace", "cdata", "table", "userdata", "number" -}; - -/* Compare two objects without calling metamethods. */ -int LJ_FASTCALL lj_obj_equal(cTValue *o1, cTValue *o2) -{ - if (itype(o1) == itype(o2)) { - if (tvispri(o1)) - return 1; - if (!tvisnum(o1)) - return gcrefeq(o1->gcr, o2->gcr); - } else if (!tvisnumber(o1) || !tvisnumber(o2)) { - return 0; - } - return numberVnum(o1) == numberVnum(o2); -} - -/* Return pointer to object or its object data. */ -const void * LJ_FASTCALL lj_obj_ptr(cTValue *o) -{ - if (tvisudata(o)) - return uddata(udataV(o)); - else if (tvislightud(o)) - return lightudV(o); - else if (LJ_HASFFI && tviscdata(o)) - return cdataptr(cdataV(o)); - else if (tvisgcv(o)) - return gcV(o); - else - return NULL; -} - diff --git a/lib/LuaJIT/src/lj_obj.h b/lib/LuaJIT/src/lj_obj.h deleted file mode 100644 index 72b7ace..0000000 --- a/lib/LuaJIT/src/lj_obj.h +++ /dev/null @@ -1,991 +0,0 @@ -/* -** LuaJIT VM tags, values and objects. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Portions taken verbatim or adapted from the Lua interpreter. -** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h -*/ - -#ifndef _LJ_OBJ_H -#define _LJ_OBJ_H - -#include "lua.h" -#include "lj_def.h" -#include "lj_arch.h" - -/* -- Memory references (32 bit address space) ---------------------------- */ - -/* Memory and GC object sizes. */ -typedef uint32_t MSize; -#if LJ_GC64 -typedef uint64_t GCSize; -#else -typedef uint32_t GCSize; -#endif - -/* Memory reference */ -typedef struct MRef { -#if LJ_GC64 - uint64_t ptr64; /* True 64 bit pointer. */ -#else - uint32_t ptr32; /* Pseudo 32 bit pointer. */ -#endif -} MRef; - -#if LJ_GC64 -#define mref(r, t) ((t *)(void *)(r).ptr64) - -#define setmref(r, p) ((r).ptr64 = (uint64_t)(void *)(p)) -#define setmrefr(r, v) ((r).ptr64 = (v).ptr64) -#else -#define mref(r, t) ((t *)(void *)(uintptr_t)(r).ptr32) - -#define setmref(r, p) ((r).ptr32 = (uint32_t)(uintptr_t)(void *)(p)) -#define setmrefr(r, v) ((r).ptr32 = (v).ptr32) -#endif - -/* -- GC object references (32 bit address space) ------------------------- */ - -/* GCobj reference */ -typedef struct GCRef { -#if LJ_GC64 - uint64_t gcptr64; /* True 64 bit pointer. */ -#else - uint32_t gcptr32; /* Pseudo 32 bit pointer. */ -#endif -} GCRef; - -/* Common GC header for all collectable objects. */ -#define GCHeader GCRef nextgc; uint8_t marked; uint8_t gct -/* This occupies 6 bytes, so use the next 2 bytes for non-32 bit fields. */ - -#if LJ_GC64 -#define gcref(r) ((GCobj *)(r).gcptr64) -#define gcrefp(r, t) ((t *)(void *)(r).gcptr64) -#define gcrefu(r) ((r).gcptr64) -#define gcrefeq(r1, r2) ((r1).gcptr64 == (r2).gcptr64) - -#define setgcref(r, gc) ((r).gcptr64 = (uint64_t)&(gc)->gch) -#define setgcreft(r, gc, it) \ - (r).gcptr64 = (uint64_t)&(gc)->gch | (((uint64_t)(it)) << 47) -#define setgcrefp(r, p) ((r).gcptr64 = (uint64_t)(p)) -#define setgcrefnull(r) ((r).gcptr64 = 0) -#define setgcrefr(r, v) ((r).gcptr64 = (v).gcptr64) -#else -#define gcref(r) ((GCobj *)(uintptr_t)(r).gcptr32) -#define gcrefp(r, t) ((t *)(void *)(uintptr_t)(r).gcptr32) -#define gcrefu(r) ((r).gcptr32) -#define gcrefeq(r1, r2) ((r1).gcptr32 == (r2).gcptr32) - -#define setgcref(r, gc) ((r).gcptr32 = (uint32_t)(uintptr_t)&(gc)->gch) -#define setgcrefp(r, p) ((r).gcptr32 = (uint32_t)(uintptr_t)(p)) -#define setgcrefnull(r) ((r).gcptr32 = 0) -#define setgcrefr(r, v) ((r).gcptr32 = (v).gcptr32) -#endif - -#define gcnext(gc) (gcref((gc)->gch.nextgc)) - -/* IMPORTANT NOTE: -** -** All uses of the setgcref* macros MUST be accompanied with a write barrier. -** -** This is to ensure the integrity of the incremental GC. The invariant -** to preserve is that a black object never points to a white object. -** I.e. never store a white object into a field of a black object. -** -** It's ok to LEAVE OUT the write barrier ONLY in the following cases: -** - The source is not a GC object (NULL). -** - The target is a GC root. I.e. everything in global_State. -** - The target is a lua_State field (threads are never black). -** - The target is a stack slot, see setgcV et al. -** - The target is an open upvalue, i.e. pointing to a stack slot. -** - The target is a newly created object (i.e. marked white). But make -** sure nothing invokes the GC inbetween. -** - The target and the source are the same object (self-reference). -** - The target already contains the object (e.g. moving elements around). -** -** The most common case is a store to a stack slot. All other cases where -** a barrier has been omitted are annotated with a NOBARRIER comment. -** -** The same logic applies for stores to table slots (array part or hash -** part). ALL uses of lj_tab_set* require a barrier for the stored value -** *and* the stored key, based on the above rules. In practice this means -** a barrier is needed if *either* of the key or value are a GC object. -** -** It's ok to LEAVE OUT the write barrier in the following special cases: -** - The stored value is nil. The key doesn't matter because it's either -** not resurrected or lj_tab_newkey() will take care of the key barrier. -** - The key doesn't matter if the *previously* stored value is guaranteed -** to be non-nil (because the key is kept alive in the table). -** - The key doesn't matter if it's guaranteed not to be part of the table, -** since lj_tab_newkey() takes care of the key barrier. This applies -** trivially to new tables, but watch out for resurrected keys. Storing -** a nil value leaves the key in the table! -** -** In case of doubt use lj_gc_anybarriert() as it's rather cheap. It's used -** by the interpreter for all table stores. -** -** Note: In contrast to Lua's GC, LuaJIT's GC does *not* specially mark -** dead keys in tables. The reference is left in, but it's guaranteed to -** be never dereferenced as long as the value is nil. It's ok if the key is -** freed or if any object subsequently gets the same address. -** -** Not destroying dead keys helps to keep key hash slots stable. This avoids -** specialization back-off for HREFK when a value flips between nil and -** non-nil and the GC gets in the way. It also allows safely hoisting -** HREF/HREFK across GC steps. Dead keys are only removed if a table is -** resized (i.e. by NEWREF) and xREF must not be CSEd across a resize. -** -** The trade-off is that a write barrier for tables must take the key into -** account, too. Implicitly resurrecting the key by storing a non-nil value -** may invalidate the incremental GC invariant. -*/ - -/* -- Common type definitions --------------------------------------------- */ - -/* Types for handling bytecodes. Need this here, details in lj_bc.h. */ -typedef uint32_t BCIns; /* Bytecode instruction. */ -typedef uint32_t BCPos; /* Bytecode position. */ -typedef uint32_t BCReg; /* Bytecode register. */ -typedef int32_t BCLine; /* Bytecode line number. */ - -/* Internal assembler functions. Never call these directly from C. */ -typedef void (*ASMFunction)(void); - -/* Resizable string buffer. Need this here, details in lj_buf.h. */ -typedef struct SBuf { - MRef p; /* String buffer pointer. */ - MRef e; /* String buffer end pointer. */ - MRef b; /* String buffer base. */ - MRef L; /* lua_State, used for buffer resizing. */ -} SBuf; - -/* -- Tags and values ----------------------------------------------------- */ - -/* Frame link. */ -typedef union { - int32_t ftsz; /* Frame type and size of previous frame. */ - MRef pcr; /* Or PC for Lua frames. */ -} FrameLink; - -/* Tagged value. */ -typedef LJ_ALIGN(8) union TValue { - uint64_t u64; /* 64 bit pattern overlaps number. */ - lua_Number n; /* Number object overlaps split tag/value object. */ -#if LJ_GC64 - GCRef gcr; /* GCobj reference with tag. */ - int64_t it64; - struct { - LJ_ENDIAN_LOHI( - int32_t i; /* Integer value. */ - , uint32_t it; /* Internal object tag. Must overlap MSW of number. */ - ) - }; -#else - struct { - LJ_ENDIAN_LOHI( - union { - GCRef gcr; /* GCobj reference (if any). */ - int32_t i; /* Integer value. */ - }; - , uint32_t it; /* Internal object tag. Must overlap MSW of number. */ - ) - }; -#endif -#if LJ_FR2 - int64_t ftsz; /* Frame type and size of previous frame, or PC. */ -#else - struct { - LJ_ENDIAN_LOHI( - GCRef func; /* Function for next frame (or dummy L). */ - , FrameLink tp; /* Link to previous frame. */ - ) - } fr; -#endif - struct { - LJ_ENDIAN_LOHI( - uint32_t lo; /* Lower 32 bits of number. */ - , uint32_t hi; /* Upper 32 bits of number. */ - ) - } u32; -} TValue; - -typedef const TValue cTValue; - -#define tvref(r) (mref(r, TValue)) - -/* More external and GCobj tags for internal objects. */ -#define LAST_TT LUA_TTHREAD -#define LUA_TPROTO (LAST_TT+1) -#define LUA_TCDATA (LAST_TT+2) - -/* Internal object tags. -** -** Format for 32 bit GC references (!LJ_GC64): -** -** Internal tags overlap the MSW of a number object (must be a double). -** Interpreted as a double these are special NaNs. The FPU only generates -** one type of NaN (0xfff8_0000_0000_0000). So MSWs > 0xfff80000 are available -** for use as internal tags. Small negative numbers are used to shorten the -** encoding of type comparisons (reg/mem against sign-ext. 8 bit immediate). -** -** ---MSW---.---LSW--- -** primitive types | itype | | -** lightuserdata | itype | void * | (32 bit platforms) -** lightuserdata |ffff| void * | (64 bit platforms, 47 bit pointers) -** GC objects | itype | GCRef | -** int (LJ_DUALNUM)| itype | int | -** number -------double------ -** -** Format for 64 bit GC references (LJ_GC64): -** -** The upper 13 bits must be 1 (0xfff8...) for a special NaN. The next -** 4 bits hold the internal tag. The lowest 47 bits either hold a pointer, -** a zero-extended 32 bit integer or all bits set to 1 for primitive types. -** -** ------MSW------.------LSW------ -** primitive types |1..1|itype|1..................1| -** GC objects/lightud |1..1|itype|-------GCRef--------| -** int (LJ_DUALNUM) |1..1|itype|0..0|-----int-------| -** number ------------double------------- -** -** ORDER LJ_T -** Primitive types nil/false/true must be first, lightuserdata next. -** GC objects are at the end, table/userdata must be lowest. -** Also check lj_ir.h for similar ordering constraints. -*/ -#define LJ_TNIL (~0u) -#define LJ_TFALSE (~1u) -#define LJ_TTRUE (~2u) -#define LJ_TLIGHTUD (~3u) -#define LJ_TSTR (~4u) -#define LJ_TUPVAL (~5u) -#define LJ_TTHREAD (~6u) -#define LJ_TPROTO (~7u) -#define LJ_TFUNC (~8u) -#define LJ_TTRACE (~9u) -#define LJ_TCDATA (~10u) -#define LJ_TTAB (~11u) -#define LJ_TUDATA (~12u) -/* This is just the canonical number type used in some places. */ -#define LJ_TNUMX (~13u) - -/* Integers have itype == LJ_TISNUM doubles have itype < LJ_TISNUM */ -#if LJ_64 && !LJ_GC64 -#define LJ_TISNUM 0xfffeffffu -#else -#define LJ_TISNUM LJ_TNUMX -#endif -#define LJ_TISTRUECOND LJ_TFALSE -#define LJ_TISPRI LJ_TTRUE -#define LJ_TISGCV (LJ_TSTR+1) -#define LJ_TISTABUD LJ_TTAB - -#if LJ_GC64 -#define LJ_GCVMASK (((uint64_t)1 << 47) - 1) -#endif - -/* -- String object ------------------------------------------------------- */ - -/* String object header. String payload follows. */ -typedef struct GCstr { - GCHeader; - uint8_t reserved; /* Used by lexer for fast lookup of reserved words. */ - uint8_t unused; - MSize hash; /* Hash of string. */ - MSize len; /* Size of string. */ -} GCstr; - -#define strref(r) (&gcref((r))->str) -#define strdata(s) ((const char *)((s)+1)) -#define strdatawr(s) ((char *)((s)+1)) -#define strVdata(o) strdata(strV(o)) -#define sizestring(s) (sizeof(struct GCstr)+(s)->len+1) - -/* -- Userdata object ----------------------------------------------------- */ - -/* Userdata object. Payload follows. */ -typedef struct GCudata { - GCHeader; - uint8_t udtype; /* Userdata type. */ - uint8_t unused2; - GCRef env; /* Should be at same offset in GCfunc. */ - MSize len; /* Size of payload. */ - GCRef metatable; /* Must be at same offset in GCtab. */ - uint32_t align1; /* To force 8 byte alignment of the payload. */ -} GCudata; - -/* Userdata types. */ -enum { - UDTYPE_USERDATA, /* Regular userdata. */ - UDTYPE_IO_FILE, /* I/O library FILE. */ - UDTYPE_FFI_CLIB, /* FFI C library namespace. */ - UDTYPE__MAX -}; - -#define uddata(u) ((void *)((u)+1)) -#define sizeudata(u) (sizeof(struct GCudata)+(u)->len) - -/* -- C data object ------------------------------------------------------- */ - -/* C data object. Payload follows. */ -typedef struct GCcdata { - GCHeader; - uint16_t ctypeid; /* C type ID. */ -} GCcdata; - -/* Prepended to variable-sized or realigned C data objects. */ -typedef struct GCcdataVar { - uint16_t offset; /* Offset to allocated memory (relative to GCcdata). */ - uint16_t extra; /* Extra space allocated (incl. GCcdata + GCcdatav). */ - MSize len; /* Size of payload. */ -} GCcdataVar; - -#define cdataptr(cd) ((void *)((cd)+1)) -#define cdataisv(cd) ((cd)->marked & 0x80) -#define cdatav(cd) ((GCcdataVar *)((char *)(cd) - sizeof(GCcdataVar))) -#define cdatavlen(cd) check_exp(cdataisv(cd), cdatav(cd)->len) -#define sizecdatav(cd) (cdatavlen(cd) + cdatav(cd)->extra) -#define memcdatav(cd) ((void *)((char *)(cd) - cdatav(cd)->offset)) - -/* -- Prototype object ---------------------------------------------------- */ - -#define SCALE_NUM_GCO ((int32_t)sizeof(lua_Number)/sizeof(GCRef)) -#define round_nkgc(n) (((n) + SCALE_NUM_GCO-1) & ~(SCALE_NUM_GCO-1)) - -typedef struct GCproto { - GCHeader; - uint8_t numparams; /* Number of parameters. */ - uint8_t framesize; /* Fixed frame size. */ - MSize sizebc; /* Number of bytecode instructions. */ -#if LJ_GC64 - uint32_t unused_gc64; -#endif - GCRef gclist; - MRef k; /* Split constant array (points to the middle). */ - MRef uv; /* Upvalue list. local slot|0x8000 or parent uv idx. */ - MSize sizekgc; /* Number of collectable constants. */ - MSize sizekn; /* Number of lua_Number constants. */ - MSize sizept; /* Total size including colocated arrays. */ - uint8_t sizeuv; /* Number of upvalues. */ - uint8_t flags; /* Miscellaneous flags (see below). */ - uint16_t trace; /* Anchor for chain of root traces. */ - /* ------ The following fields are for debugging/tracebacks only ------ */ - GCRef chunkname; /* Name of the chunk this function was defined in. */ - BCLine firstline; /* First line of the function definition. */ - BCLine numline; /* Number of lines for the function definition. */ - MRef lineinfo; /* Compressed map from bytecode ins. to source line. */ - MRef uvinfo; /* Upvalue names. */ - MRef varinfo; /* Names and compressed extents of local variables. */ -} GCproto; - -/* Flags for prototype. */ -#define PROTO_CHILD 0x01 /* Has child prototypes. */ -#define PROTO_VARARG 0x02 /* Vararg function. */ -#define PROTO_FFI 0x04 /* Uses BC_KCDATA for FFI datatypes. */ -#define PROTO_NOJIT 0x08 /* JIT disabled for this function. */ -#define PROTO_ILOOP 0x10 /* Patched bytecode with ILOOP etc. */ -/* Only used during parsing. */ -#define PROTO_HAS_RETURN 0x20 /* Already emitted a return. */ -#define PROTO_FIXUP_RETURN 0x40 /* Need to fixup emitted returns. */ -/* Top bits used for counting created closures. */ -#define PROTO_CLCOUNT 0x20 /* Base of saturating 3 bit counter. */ -#define PROTO_CLC_BITS 3 -#define PROTO_CLC_POLY (3*PROTO_CLCOUNT) /* Polymorphic threshold. */ - -#define PROTO_UV_LOCAL 0x8000 /* Upvalue for local slot. */ -#define PROTO_UV_IMMUTABLE 0x4000 /* Immutable upvalue. */ - -#define proto_kgc(pt, idx) \ - check_exp((uintptr_t)(intptr_t)(idx) >= (uintptr_t)-(intptr_t)(pt)->sizekgc, \ - gcref(mref((pt)->k, GCRef)[(idx)])) -#define proto_knumtv(pt, idx) \ - check_exp((uintptr_t)(idx) < (pt)->sizekn, &mref((pt)->k, TValue)[(idx)]) -#define proto_bc(pt) ((BCIns *)((char *)(pt) + sizeof(GCproto))) -#define proto_bcpos(pt, pc) ((BCPos)((pc) - proto_bc(pt))) -#define proto_uv(pt) (mref((pt)->uv, uint16_t)) - -#define proto_chunkname(pt) (strref((pt)->chunkname)) -#define proto_chunknamestr(pt) (strdata(proto_chunkname((pt)))) -#define proto_lineinfo(pt) (mref((pt)->lineinfo, const void)) -#define proto_uvinfo(pt) (mref((pt)->uvinfo, const uint8_t)) -#define proto_varinfo(pt) (mref((pt)->varinfo, const uint8_t)) - -/* -- Upvalue object ------------------------------------------------------ */ - -typedef struct GCupval { - GCHeader; - uint8_t closed; /* Set if closed (i.e. uv->v == &uv->u.value). */ - uint8_t immutable; /* Immutable value. */ - union { - TValue tv; /* If closed: the value itself. */ - struct { /* If open: double linked list, anchored at thread. */ - GCRef prev; - GCRef next; - }; - }; - MRef v; /* Points to stack slot (open) or above (closed). */ - uint32_t dhash; /* Disambiguation hash: dh1 != dh2 => cannot alias. */ -} GCupval; - -#define uvprev(uv_) (&gcref((uv_)->prev)->uv) -#define uvnext(uv_) (&gcref((uv_)->next)->uv) -#define uvval(uv_) (mref((uv_)->v, TValue)) - -/* -- Function object (closures) ------------------------------------------ */ - -/* Common header for functions. env should be at same offset in GCudata. */ -#define GCfuncHeader \ - GCHeader; uint8_t ffid; uint8_t nupvalues; \ - GCRef env; GCRef gclist; MRef pc - -typedef struct GCfuncC { - GCfuncHeader; - lua_CFunction f; /* C function to be called. */ - TValue upvalue[1]; /* Array of upvalues (TValue). */ -} GCfuncC; - -typedef struct GCfuncL { - GCfuncHeader; - GCRef uvptr[1]; /* Array of _pointers_ to upvalue objects (GCupval). */ -} GCfuncL; - -typedef union GCfunc { - GCfuncC c; - GCfuncL l; -} GCfunc; - -#define FF_LUA 0 -#define FF_C 1 -#define isluafunc(fn) ((fn)->c.ffid == FF_LUA) -#define iscfunc(fn) ((fn)->c.ffid == FF_C) -#define isffunc(fn) ((fn)->c.ffid > FF_C) -#define funcproto(fn) \ - check_exp(isluafunc(fn), (GCproto *)(mref((fn)->l.pc, char)-sizeof(GCproto))) -#define sizeCfunc(n) (sizeof(GCfuncC)-sizeof(TValue)+sizeof(TValue)*(n)) -#define sizeLfunc(n) (sizeof(GCfuncL)-sizeof(GCRef)+sizeof(GCRef)*(n)) - -/* -- Table object -------------------------------------------------------- */ - -/* Hash node. */ -typedef struct Node { - TValue val; /* Value object. Must be first field. */ - TValue key; /* Key object. */ - MRef next; /* Hash chain. */ -#if !LJ_GC64 - MRef freetop; /* Top of free elements (stored in t->node[0]). */ -#endif -} Node; - -LJ_STATIC_ASSERT(offsetof(Node, val) == 0); - -typedef struct GCtab { - GCHeader; - uint8_t nomm; /* Negative cache for fast metamethods. */ - int8_t colo; /* Array colocation. */ - MRef array; /* Array part. */ - GCRef gclist; - GCRef metatable; /* Must be at same offset in GCudata. */ - MRef node; /* Hash part. */ - uint32_t asize; /* Size of array part (keys [0, asize-1]). */ - uint32_t hmask; /* Hash part mask (size of hash part - 1). */ -#if LJ_GC64 - MRef freetop; /* Top of free elements. */ -#endif -} GCtab; - -#define sizetabcolo(n) ((n)*sizeof(TValue) + sizeof(GCtab)) -#define tabref(r) (&gcref((r))->tab) -#define noderef(r) (mref((r), Node)) -#define nextnode(n) (mref((n)->next, Node)) -#if LJ_GC64 -#define getfreetop(t, n) (noderef((t)->freetop)) -#define setfreetop(t, n, v) (setmref((t)->freetop, (v))) -#else -#define getfreetop(t, n) (noderef((n)->freetop)) -#define setfreetop(t, n, v) (setmref((n)->freetop, (v))) -#endif - -/* -- State objects ------------------------------------------------------- */ - -/* VM states. */ -enum { - LJ_VMST_INTERP, /* Interpreter. */ - LJ_VMST_C, /* C function. */ - LJ_VMST_GC, /* Garbage collector. */ - LJ_VMST_EXIT, /* Trace exit handler. */ - LJ_VMST_RECORD, /* Trace recorder. */ - LJ_VMST_OPT, /* Optimizer. */ - LJ_VMST_ASM, /* Assembler. */ - LJ_VMST__MAX -}; - -#define setvmstate(g, st) ((g)->vmstate = ~LJ_VMST_##st) - -/* Metamethods. ORDER MM */ -#ifdef LJ_HASFFI -#define MMDEF_FFI(_) _(new) -#else -#define MMDEF_FFI(_) -#endif - -#if LJ_52 || LJ_HASFFI -#define MMDEF_PAIRS(_) _(pairs) _(ipairs) -#else -#define MMDEF_PAIRS(_) -#define MM_pairs 255 -#define MM_ipairs 255 -#endif - -#define MMDEF(_) \ - _(index) _(newindex) _(gc) _(mode) _(eq) _(len) \ - /* Only the above (fast) metamethods are negative cached (max. 8). */ \ - _(lt) _(le) _(concat) _(call) \ - /* The following must be in ORDER ARITH. */ \ - _(add) _(sub) _(mul) _(div) _(mod) _(pow) _(unm) \ - /* The following are used in the standard libraries. */ \ - _(metatable) _(tostring) MMDEF_FFI(_) MMDEF_PAIRS(_) - -typedef enum { -#define MMENUM(name) MM_##name, -MMDEF(MMENUM) -#undef MMENUM - MM__MAX, - MM____ = MM__MAX, - MM_FAST = MM_len -} MMS; - -/* GC root IDs. */ -typedef enum { - GCROOT_MMNAME, /* Metamethod names. */ - GCROOT_MMNAME_LAST = GCROOT_MMNAME + MM__MAX-1, - GCROOT_BASEMT, /* Metatables for base types. */ - GCROOT_BASEMT_NUM = GCROOT_BASEMT + ~LJ_TNUMX, - GCROOT_IO_INPUT, /* Userdata for default I/O input file. */ - GCROOT_IO_OUTPUT, /* Userdata for default I/O output file. */ - GCROOT_MAX -} GCRootID; - -#define basemt_it(g, it) ((g)->gcroot[GCROOT_BASEMT+~(it)]) -#define basemt_obj(g, o) ((g)->gcroot[GCROOT_BASEMT+itypemap(o)]) -#define mmname_str(g, mm) (strref((g)->gcroot[GCROOT_MMNAME+(mm)])) - -typedef struct GCState { - GCSize total; /* Memory currently allocated. */ - GCSize threshold; /* Memory threshold. */ - uint8_t currentwhite; /* Current white color. */ - uint8_t state; /* GC state. */ - uint8_t nocdatafin; /* No cdata finalizer called. */ - uint8_t unused2; - MSize sweepstr; /* Sweep position in string table. */ - GCRef root; /* List of all collectable objects. */ - MRef sweep; /* Sweep position in root list. */ - GCRef gray; /* List of gray objects. */ - GCRef grayagain; /* List of objects for atomic traversal. */ - GCRef weak; /* List of weak tables (to be cleared). */ - GCRef mmudata; /* List of userdata (to be finalized). */ - GCSize debt; /* Debt (how much GC is behind schedule). */ - GCSize estimate; /* Estimate of memory actually in use. */ - MSize stepmul; /* Incremental GC step granularity. */ - MSize pause; /* Pause between successive GC cycles. */ -} GCState; - -/* Global state, shared by all threads of a Lua universe. */ -typedef struct global_State { - GCRef *strhash; /* String hash table (hash chain anchors). */ - MSize strmask; /* String hash mask (size of hash table - 1). */ - MSize strnum; /* Number of strings in hash table. */ - lua_Alloc allocf; /* Memory allocator. */ - void *allocd; /* Memory allocator data. */ - GCState gc; /* Garbage collector. */ - volatile int32_t vmstate; /* VM state or current JIT code trace number. */ - SBuf tmpbuf; /* Temporary string buffer. */ - GCstr strempty; /* Empty string. */ - uint8_t stremptyz; /* Zero terminator of empty string. */ - uint8_t hookmask; /* Hook mask. */ - uint8_t dispatchmode; /* Dispatch mode. */ - uint8_t vmevmask; /* VM event mask. */ - GCRef mainthref; /* Link to main thread. */ - TValue registrytv; /* Anchor for registry. */ - TValue tmptv, tmptv2; /* Temporary TValues. */ - Node nilnode; /* Fallback 1-element hash part (nil key and value). */ - GCupval uvhead; /* Head of double-linked list of all open upvalues. */ - int32_t hookcount; /* Instruction hook countdown. */ - int32_t hookcstart; /* Start count for instruction hook counter. */ - lua_Hook hookf; /* Hook function. */ - lua_CFunction wrapf; /* Wrapper for C function calls. */ - lua_CFunction panic; /* Called as a last resort for errors. */ - BCIns bc_cfunc_int; /* Bytecode for internal C function calls. */ - BCIns bc_cfunc_ext; /* Bytecode for external C function calls. */ - GCRef cur_L; /* Currently executing lua_State. */ - MRef jit_base; /* Current JIT code L->base or NULL. */ - MRef ctype_state; /* Pointer to C type state. */ - GCRef gcroot[GCROOT_MAX]; /* GC roots. */ -} global_State; - -#define mainthread(g) (&gcref(g->mainthref)->th) -#define niltv(L) \ - check_exp(tvisnil(&G(L)->nilnode.val), &G(L)->nilnode.val) -#define niltvg(g) \ - check_exp(tvisnil(&(g)->nilnode.val), &(g)->nilnode.val) - -/* Hook management. Hook event masks are defined in lua.h. */ -#define HOOK_EVENTMASK 0x0f -#define HOOK_ACTIVE 0x10 -#define HOOK_ACTIVE_SHIFT 4 -#define HOOK_VMEVENT 0x20 -#define HOOK_GC 0x40 -#define HOOK_PROFILE 0x80 -#define hook_active(g) ((g)->hookmask & HOOK_ACTIVE) -#define hook_enter(g) ((g)->hookmask |= HOOK_ACTIVE) -#define hook_entergc(g) ((g)->hookmask |= (HOOK_ACTIVE|HOOK_GC)) -#define hook_vmevent(g) ((g)->hookmask |= (HOOK_ACTIVE|HOOK_VMEVENT)) -#define hook_leave(g) ((g)->hookmask &= ~HOOK_ACTIVE) -#define hook_save(g) ((g)->hookmask & ~HOOK_EVENTMASK) -#define hook_restore(g, h) \ - ((g)->hookmask = ((g)->hookmask & HOOK_EVENTMASK) | (h)) - -/* Per-thread state object. */ -struct lua_State { - GCHeader; - uint8_t dummy_ffid; /* Fake FF_C for curr_funcisL() on dummy frames. */ - uint8_t status; /* Thread status. */ - MRef glref; /* Link to global state. */ - GCRef gclist; /* GC chain. */ - TValue *base; /* Base of currently executing function. */ - TValue *top; /* First free slot in the stack. */ - MRef maxstack; /* Last free slot in the stack. */ - MRef stack; /* Stack base. */ - GCRef openupval; /* List of open upvalues in the stack. */ - GCRef env; /* Thread environment (table of globals). */ - void *cframe; /* End of C stack frame chain. */ - MSize stacksize; /* True stack size (incl. LJ_STACK_EXTRA). */ -}; - -#define G(L) (mref(L->glref, global_State)) -#define registry(L) (&G(L)->registrytv) - -/* Macros to access the currently executing (Lua) function. */ -#if LJ_GC64 -#define curr_func(L) (&gcval(L->base-2)->fn) -#elif LJ_FR2 -#define curr_func(L) (&gcref((L->base-2)->gcr)->fn) -#else -#define curr_func(L) (&gcref((L->base-1)->fr.func)->fn) -#endif -#define curr_funcisL(L) (isluafunc(curr_func(L))) -#define curr_proto(L) (funcproto(curr_func(L))) -#define curr_topL(L) (L->base + curr_proto(L)->framesize) -#define curr_top(L) (curr_funcisL(L) ? curr_topL(L) : L->top) - -/* -- GC object definition and conversions -------------------------------- */ - -/* GC header for generic access to common fields of GC objects. */ -typedef struct GChead { - GCHeader; - uint8_t unused1; - uint8_t unused2; - GCRef env; - GCRef gclist; - GCRef metatable; -} GChead; - -/* The env field SHOULD be at the same offset for all GC objects. */ -LJ_STATIC_ASSERT(offsetof(GChead, env) == offsetof(GCfuncL, env)); -LJ_STATIC_ASSERT(offsetof(GChead, env) == offsetof(GCudata, env)); - -/* The metatable field MUST be at the same offset for all GC objects. */ -LJ_STATIC_ASSERT(offsetof(GChead, metatable) == offsetof(GCtab, metatable)); -LJ_STATIC_ASSERT(offsetof(GChead, metatable) == offsetof(GCudata, metatable)); - -/* The gclist field MUST be at the same offset for all GC objects. */ -LJ_STATIC_ASSERT(offsetof(GChead, gclist) == offsetof(lua_State, gclist)); -LJ_STATIC_ASSERT(offsetof(GChead, gclist) == offsetof(GCproto, gclist)); -LJ_STATIC_ASSERT(offsetof(GChead, gclist) == offsetof(GCfuncL, gclist)); -LJ_STATIC_ASSERT(offsetof(GChead, gclist) == offsetof(GCtab, gclist)); - -typedef union GCobj { - GChead gch; - GCstr str; - GCupval uv; - lua_State th; - GCproto pt; - GCfunc fn; - GCcdata cd; - GCtab tab; - GCudata ud; -} GCobj; - -/* Macros to convert a GCobj pointer into a specific value. */ -#define gco2str(o) check_exp((o)->gch.gct == ~LJ_TSTR, &(o)->str) -#define gco2uv(o) check_exp((o)->gch.gct == ~LJ_TUPVAL, &(o)->uv) -#define gco2th(o) check_exp((o)->gch.gct == ~LJ_TTHREAD, &(o)->th) -#define gco2pt(o) check_exp((o)->gch.gct == ~LJ_TPROTO, &(o)->pt) -#define gco2func(o) check_exp((o)->gch.gct == ~LJ_TFUNC, &(o)->fn) -#define gco2cd(o) check_exp((o)->gch.gct == ~LJ_TCDATA, &(o)->cd) -#define gco2tab(o) check_exp((o)->gch.gct == ~LJ_TTAB, &(o)->tab) -#define gco2ud(o) check_exp((o)->gch.gct == ~LJ_TUDATA, &(o)->ud) - -/* Macro to convert any collectable object into a GCobj pointer. */ -#define obj2gco(v) ((GCobj *)(v)) - -/* -- TValue getters/setters ---------------------------------------------- */ - -#ifdef LUA_USE_ASSERT -#include "lj_gc.h" -#endif - -/* Macros to test types. */ -#if LJ_GC64 -#define itype(o) ((uint32_t)((o)->it64 >> 47)) -#define tvisnil(o) ((o)->it64 == -1) -#else -#define itype(o) ((o)->it) -#define tvisnil(o) (itype(o) == LJ_TNIL) -#endif -#define tvisfalse(o) (itype(o) == LJ_TFALSE) -#define tvistrue(o) (itype(o) == LJ_TTRUE) -#define tvisbool(o) (tvisfalse(o) || tvistrue(o)) -#if LJ_64 && !LJ_GC64 -#define tvislightud(o) (((int32_t)itype(o) >> 15) == -2) -#else -#define tvislightud(o) (itype(o) == LJ_TLIGHTUD) -#endif -#define tvisstr(o) (itype(o) == LJ_TSTR) -#define tvisfunc(o) (itype(o) == LJ_TFUNC) -#define tvisthread(o) (itype(o) == LJ_TTHREAD) -#define tvisproto(o) (itype(o) == LJ_TPROTO) -#define tviscdata(o) (itype(o) == LJ_TCDATA) -#define tvistab(o) (itype(o) == LJ_TTAB) -#define tvisudata(o) (itype(o) == LJ_TUDATA) -#define tvisnumber(o) (itype(o) <= LJ_TISNUM) -#define tvisint(o) (LJ_DUALNUM && itype(o) == LJ_TISNUM) -#define tvisnum(o) (itype(o) < LJ_TISNUM) - -#define tvistruecond(o) (itype(o) < LJ_TISTRUECOND) -#define tvispri(o) (itype(o) >= LJ_TISPRI) -#define tvistabud(o) (itype(o) <= LJ_TISTABUD) /* && !tvisnum() */ -#define tvisgcv(o) ((itype(o) - LJ_TISGCV) > (LJ_TNUMX - LJ_TISGCV)) - -/* Special macros to test numbers for NaN, +0, -0, +1 and raw equality. */ -#define tvisnan(o) ((o)->n != (o)->n) -#if LJ_64 -#define tviszero(o) (((o)->u64 << 1) == 0) -#else -#define tviszero(o) (((o)->u32.lo | ((o)->u32.hi << 1)) == 0) -#endif -#define tvispzero(o) ((o)->u64 == 0) -#define tvismzero(o) ((o)->u64 == U64x(80000000,00000000)) -#define tvispone(o) ((o)->u64 == U64x(3ff00000,00000000)) -#define rawnumequal(o1, o2) ((o1)->u64 == (o2)->u64) - -/* Macros to convert type ids. */ -#if LJ_64 && !LJ_GC64 -#define itypemap(o) \ - (tvisnumber(o) ? ~LJ_TNUMX : tvislightud(o) ? ~LJ_TLIGHTUD : ~itype(o)) -#else -#define itypemap(o) (tvisnumber(o) ? ~LJ_TNUMX : ~itype(o)) -#endif - -/* Macros to get tagged values. */ -#if LJ_GC64 -#define gcval(o) ((GCobj *)(gcrefu((o)->gcr) & LJ_GCVMASK)) -#else -#define gcval(o) (gcref((o)->gcr)) -#endif -#define boolV(o) check_exp(tvisbool(o), (LJ_TFALSE - itype(o))) -#if LJ_64 -#define lightudV(o) \ - check_exp(tvislightud(o), (void *)((o)->u64 & U64x(00007fff,ffffffff))) -#else -#define lightudV(o) check_exp(tvislightud(o), gcrefp((o)->gcr, void)) -#endif -#define gcV(o) check_exp(tvisgcv(o), gcval(o)) -#define strV(o) check_exp(tvisstr(o), &gcval(o)->str) -#define funcV(o) check_exp(tvisfunc(o), &gcval(o)->fn) -#define threadV(o) check_exp(tvisthread(o), &gcval(o)->th) -#define protoV(o) check_exp(tvisproto(o), &gcval(o)->pt) -#define cdataV(o) check_exp(tviscdata(o), &gcval(o)->cd) -#define tabV(o) check_exp(tvistab(o), &gcval(o)->tab) -#define udataV(o) check_exp(tvisudata(o), &gcval(o)->ud) -#define numV(o) check_exp(tvisnum(o), (o)->n) -#define intV(o) check_exp(tvisint(o), (int32_t)(o)->i) - -/* Macros to set tagged values. */ -#if LJ_GC64 -#define setitype(o, i) ((o)->it = ((i) << 15)) -#define setnilV(o) ((o)->it64 = -1) -#define setpriV(o, x) ((o)->it64 = (int64_t)~((uint64_t)~(x)<<47)) -#define setboolV(o, x) ((o)->it64 = (int64_t)~((uint64_t)((x)+1)<<47)) -#else -#define setitype(o, i) ((o)->it = (i)) -#define setnilV(o) ((o)->it = LJ_TNIL) -#define setboolV(o, x) ((o)->it = LJ_TFALSE-(uint32_t)(x)) -#define setpriV(o, i) (setitype((o), (i))) -#endif - -static LJ_AINLINE void setlightudV(TValue *o, void *p) -{ -#if LJ_GC64 - o->u64 = (uint64_t)p | (((uint64_t)LJ_TLIGHTUD) << 47); -#elif LJ_64 - o->u64 = (uint64_t)p | (((uint64_t)0xffff) << 48); -#else - setgcrefp(o->gcr, p); setitype(o, LJ_TLIGHTUD); -#endif -} - -#if LJ_64 -#define checklightudptr(L, p) \ - (((uint64_t)(p) >> 47) ? (lj_err_msg(L, LJ_ERR_BADLU), NULL) : (p)) -#else -#define checklightudptr(L, p) (p) -#endif - -#if LJ_FR2 -#define contptr(f) ((void *)(f)) -#define setcont(o, f) ((o)->u64 = (uint64_t)(uintptr_t)contptr(f)) -#elif LJ_64 -#define contptr(f) \ - ((void *)(uintptr_t)(uint32_t)((intptr_t)(f) - (intptr_t)lj_vm_asm_begin)) -#define setcont(o, f) \ - ((o)->u64 = (uint64_t)(void *)(f) - (uint64_t)lj_vm_asm_begin) -#else -#define contptr(f) ((void *)(f)) -#define setcont(o, f) setlightudV((o), contptr(f)) -#endif - -#define tvchecklive(L, o) \ - UNUSED(L), lua_assert(!tvisgcv(o) || \ - ((~itype(o) == gcval(o)->gch.gct) && !isdead(G(L), gcval(o)))) - -static LJ_AINLINE void setgcVraw(TValue *o, GCobj *v, uint32_t itype) -{ -#if LJ_GC64 - setgcreft(o->gcr, v, itype); -#else - setgcref(o->gcr, v); setitype(o, itype); -#endif -} - -static LJ_AINLINE void setgcV(lua_State *L, TValue *o, GCobj *v, uint32_t it) -{ - setgcVraw(o, v, it); tvchecklive(L, o); -} - -#define define_setV(name, type, tag) \ -static LJ_AINLINE void name(lua_State *L, TValue *o, type *v) \ -{ \ - setgcV(L, o, obj2gco(v), tag); \ -} -define_setV(setstrV, GCstr, LJ_TSTR) -define_setV(setthreadV, lua_State, LJ_TTHREAD) -define_setV(setprotoV, GCproto, LJ_TPROTO) -define_setV(setfuncV, GCfunc, LJ_TFUNC) -define_setV(setcdataV, GCcdata, LJ_TCDATA) -define_setV(settabV, GCtab, LJ_TTAB) -define_setV(setudataV, GCudata, LJ_TUDATA) - -#define setnumV(o, x) ((o)->n = (x)) -#define setnanV(o) ((o)->u64 = U64x(fff80000,00000000)) -#define setpinfV(o) ((o)->u64 = U64x(7ff00000,00000000)) -#define setminfV(o) ((o)->u64 = U64x(fff00000,00000000)) - -static LJ_AINLINE void setintV(TValue *o, int32_t i) -{ -#if LJ_DUALNUM - o->i = (uint32_t)i; setitype(o, LJ_TISNUM); -#else - o->n = (lua_Number)i; -#endif -} - -static LJ_AINLINE void setint64V(TValue *o, int64_t i) -{ - if (LJ_DUALNUM && LJ_LIKELY(i == (int64_t)(int32_t)i)) - setintV(o, (int32_t)i); - else - setnumV(o, (lua_Number)i); -} - -#if LJ_64 -#define setintptrV(o, i) setint64V((o), (i)) -#else -#define setintptrV(o, i) setintV((o), (i)) -#endif - -/* Copy tagged values. */ -static LJ_AINLINE void copyTV(lua_State *L, TValue *o1, const TValue *o2) -{ - *o1 = *o2; tvchecklive(L, o1); -} - -/* -- Number to integer conversion ---------------------------------------- */ - -#if LJ_SOFTFP -LJ_ASMF int32_t lj_vm_tobit(double x); -#if LJ_TARGET_MIPS64 -LJ_ASMF int32_t lj_vm_tointg(double x); -#endif -#endif - -static LJ_AINLINE int32_t lj_num2bit(lua_Number n) -{ -#if LJ_SOFTFP - return lj_vm_tobit(n); -#else - TValue o; - o.n = n + 6755399441055744.0; /* 2^52 + 2^51 */ - return (int32_t)o.u32.lo; -#endif -} - -#define lj_num2int(n) ((int32_t)(n)) - -/* -** This must match the JIT backend behavior. In particular for archs -** that don't have a common hardware instruction for this conversion. -** Note that signed FP to unsigned int conversions have an undefined -** result and should never be relied upon in portable FFI code. -** See also: C99 or C11 standard, 6.3.1.4, footnote of (1). -*/ -static LJ_AINLINE uint64_t lj_num2u64(lua_Number n) -{ -#if LJ_TARGET_X86ORX64 || LJ_TARGET_MIPS - int64_t i = (int64_t)n; - if (i < 0) i = (int64_t)(n - 18446744073709551616.0); - return (uint64_t)i; -#else - return (uint64_t)n; -#endif -} - -static LJ_AINLINE int32_t numberVint(cTValue *o) -{ - if (LJ_LIKELY(tvisint(o))) - return intV(o); - else - return lj_num2int(numV(o)); -} - -static LJ_AINLINE lua_Number numberVnum(cTValue *o) -{ - if (LJ_UNLIKELY(tvisint(o))) - return (lua_Number)intV(o); - else - return numV(o); -} - -/* -- Miscellaneous object handling --------------------------------------- */ - -/* Names and maps for internal and external object tags. */ -LJ_DATA const char *const lj_obj_typename[1+LUA_TCDATA+1]; -LJ_DATA const char *const lj_obj_itypename[~LJ_TNUMX+1]; - -#define lj_typename(o) (lj_obj_itypename[itypemap(o)]) - -/* Compare two objects without calling metamethods. */ -LJ_FUNC int LJ_FASTCALL lj_obj_equal(cTValue *o1, cTValue *o2); -LJ_FUNC const void * LJ_FASTCALL lj_obj_ptr(cTValue *o); - -#endif diff --git a/lib/LuaJIT/src/lj_opt_dce.c b/lib/LuaJIT/src/lj_opt_dce.c deleted file mode 100644 index 2417f32..0000000 --- a/lib/LuaJIT/src/lj_opt_dce.c +++ /dev/null @@ -1,78 +0,0 @@ -/* -** DCE: Dead Code Elimination. Pre-LOOP only -- ASM already performs DCE. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_opt_dce_c -#define LUA_CORE - -#include "lj_obj.h" - -#if LJ_HASJIT - -#include "lj_ir.h" -#include "lj_jit.h" -#include "lj_iropt.h" - -/* Some local macros to save typing. Undef'd at the end. */ -#define IR(ref) (&J->cur.ir[(ref)]) - -/* Scan through all snapshots and mark all referenced instructions. */ -static void dce_marksnap(jit_State *J) -{ - SnapNo i, nsnap = J->cur.nsnap; - for (i = 0; i < nsnap; i++) { - SnapShot *snap = &J->cur.snap[i]; - SnapEntry *map = &J->cur.snapmap[snap->mapofs]; - MSize n, nent = snap->nent; - for (n = 0; n < nent; n++) { - IRRef ref = snap_ref(map[n]); - if (ref >= REF_FIRST) - irt_setmark(IR(ref)->t); - } - } -} - -/* Backwards propagate marks. Replace unused instructions with NOPs. */ -static void dce_propagate(jit_State *J) -{ - IRRef1 *pchain[IR__MAX]; - IRRef ins; - uint32_t i; - for (i = 0; i < IR__MAX; i++) pchain[i] = &J->chain[i]; - for (ins = J->cur.nins-1; ins >= REF_FIRST; ins--) { - IRIns *ir = IR(ins); - if (irt_ismarked(ir->t)) { - irt_clearmark(ir->t); - pchain[ir->o] = &ir->prev; - } else if (!ir_sideeff(ir)) { - *pchain[ir->o] = ir->prev; /* Reroute original instruction chain. */ - ir->t.irt = IRT_NIL; - ir->o = IR_NOP; /* Replace instruction with NOP. */ - ir->op1 = ir->op2 = 0; - ir->prev = 0; - continue; - } - if (ir->op1 >= REF_FIRST) irt_setmark(IR(ir->op1)->t); - if (ir->op2 >= REF_FIRST) irt_setmark(IR(ir->op2)->t); - } -} - -/* Dead Code Elimination. -** -** First backpropagate marks for all used instructions. Then replace -** the unused ones with a NOP. Note that compressing the IR to eliminate -** the NOPs does not pay off. -*/ -void lj_opt_dce(jit_State *J) -{ - if ((J->flags & JIT_F_OPT_DCE)) { - dce_marksnap(J); - dce_propagate(J); - memset(J->bpropcache, 0, sizeof(J->bpropcache)); /* Invalidate cache. */ - } -} - -#undef IR - -#endif diff --git a/lib/LuaJIT/src/lj_opt_fold.c b/lib/LuaJIT/src/lj_opt_fold.c deleted file mode 100644 index 9873b47..0000000 --- a/lib/LuaJIT/src/lj_opt_fold.c +++ /dev/null @@ -1,2555 +0,0 @@ -/* -** FOLD: Constant Folding, Algebraic Simplifications and Reassociation. -** ABCelim: Array Bounds Check Elimination. -** CSE: Common-Subexpression Elimination. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_opt_fold_c -#define LUA_CORE - -#include - -#include "lj_obj.h" - -#if LJ_HASJIT - -#include "lj_buf.h" -#include "lj_str.h" -#include "lj_tab.h" -#include "lj_ir.h" -#include "lj_jit.h" -#include "lj_ircall.h" -#include "lj_iropt.h" -#include "lj_trace.h" -#if LJ_HASFFI -#include "lj_ctype.h" -#include "lj_carith.h" -#endif -#include "lj_vm.h" -#include "lj_strscan.h" -#include "lj_strfmt.h" - -/* Here's a short description how the FOLD engine processes instructions: -** -** The FOLD engine receives a single instruction stored in fins (J->fold.ins). -** The instruction and its operands are used to select matching fold rules. -** These are applied iteratively until a fixed point is reached. -** -** The 8 bit opcode of the instruction itself plus the opcodes of the -** two instructions referenced by its operands form a 24 bit key -** 'ins left right' (unused operands -> 0, literals -> lowest 8 bits). -** -** This key is used for partial matching against the fold rules. The -** left/right operand fields of the key are successively masked with -** the 'any' wildcard, from most specific to least specific: -** -** ins left right -** ins any right -** ins left any -** ins any any -** -** The masked key is used to lookup a matching fold rule in a semi-perfect -** hash table. If a matching rule is found, the related fold function is run. -** Multiple rules can share the same fold function. A fold rule may return -** one of several special values: -** -** - NEXTFOLD means no folding was applied, because an additional test -** inside the fold function failed. Matching continues against less -** specific fold rules. Finally the instruction is passed on to CSE. -** -** - RETRYFOLD means the instruction was modified in-place. Folding is -** retried as if this instruction had just been received. -** -** All other return values are terminal actions -- no further folding is -** applied: -** -** - INTFOLD(i) returns a reference to the integer constant i. -** -** - LEFTFOLD and RIGHTFOLD return the left/right operand reference -** without emitting an instruction. -** -** - CSEFOLD and EMITFOLD pass the instruction directly to CSE or emit -** it without passing through any further optimizations. -** -** - FAILFOLD, DROPFOLD and CONDFOLD only apply to instructions which have -** no result (e.g. guarded assertions): FAILFOLD means the guard would -** always fail, i.e. the current trace is pointless. DROPFOLD means -** the guard is always true and has been eliminated. CONDFOLD is a -** shortcut for FAILFOLD + cond (i.e. drop if true, otherwise fail). -** -** - Any other return value is interpreted as an IRRef or TRef. This -** can be a reference to an existing or a newly created instruction. -** Only the least-significant 16 bits (IRRef1) are used to form a TRef -** which is finally returned to the caller. -** -** The FOLD engine receives instructions both from the trace recorder and -** substituted instructions from LOOP unrolling. This means all types -** of instructions may end up here, even though the recorder bypasses -** FOLD in some cases. Thus all loads, stores and allocations must have -** an any/any rule to avoid being passed on to CSE. -** -** Carefully read the following requirements before adding or modifying -** any fold rules: -** -** Requirement #1: All fold rules must preserve their destination type. -** -** Consistently use INTFOLD() (KINT result) or lj_ir_knum() (KNUM result). -** Never use lj_ir_knumint() which can have either a KINT or KNUM result. -** -** Requirement #2: Fold rules should not create *new* instructions which -** reference operands *across* PHIs. -** -** E.g. a RETRYFOLD with 'fins->op1 = fleft->op1' is invalid if the -** left operand is a PHI. Then fleft->op1 would point across the PHI -** frontier to an invariant instruction. Adding a PHI for this instruction -** would be counterproductive. The solution is to add a barrier which -** prevents folding across PHIs, i.e. 'PHIBARRIER(fleft)' in this case. -** The only exception is for recurrences with high latencies like -** repeated int->num->int conversions. -** -** One could relax this condition a bit if the referenced instruction is -** a PHI, too. But this often leads to worse code due to excessive -** register shuffling. -** -** Note: returning *existing* instructions (e.g. LEFTFOLD) is ok, though. -** Even returning fleft->op1 would be ok, because a new PHI will added, -** if needed. But again, this leads to excessive register shuffling and -** should be avoided. -** -** Requirement #3: The set of all fold rules must be monotonic to guarantee -** termination. -** -** The goal is optimization, so one primarily wants to add strength-reducing -** rules. This means eliminating an instruction or replacing an instruction -** with one or more simpler instructions. Don't add fold rules which point -** into the other direction. -** -** Some rules (like commutativity) do not directly reduce the strength of -** an instruction, but enable other fold rules (e.g. by moving constants -** to the right operand). These rules must be made unidirectional to avoid -** cycles. -** -** Rule of thumb: the trace recorder expands the IR and FOLD shrinks it. -*/ - -/* Some local macros to save typing. Undef'd at the end. */ -#define IR(ref) (&J->cur.ir[(ref)]) -#define fins (&J->fold.ins) -#define fleft (J->fold.left) -#define fright (J->fold.right) -#define knumleft (ir_knum(fleft)->n) -#define knumright (ir_knum(fright)->n) - -/* Pass IR on to next optimization in chain (FOLD). */ -#define emitir(ot, a, b) (lj_ir_set(J, (ot), (a), (b)), lj_opt_fold(J)) - -/* Fold function type. Fastcall on x86 significantly reduces their size. */ -typedef IRRef (LJ_FASTCALL *FoldFunc)(jit_State *J); - -/* Macros for the fold specs, so buildvm can recognize them. */ -#define LJFOLD(x) -#define LJFOLDX(x) -#define LJFOLDF(name) static TRef LJ_FASTCALL fold_##name(jit_State *J) -/* Note: They must be at the start of a line or buildvm ignores them! */ - -/* Barrier to prevent using operands across PHIs. */ -#define PHIBARRIER(ir) if (irt_isphi((ir)->t)) return NEXTFOLD - -/* Barrier to prevent folding across a GC step. -** GC steps can only happen at the head of a trace and at LOOP. -** And the GC is only driven forward if there's at least one allocation. -*/ -#define gcstep_barrier(J, ref) \ - ((ref) < J->chain[IR_LOOP] && \ - (J->chain[IR_SNEW] || J->chain[IR_XSNEW] || \ - J->chain[IR_TNEW] || J->chain[IR_TDUP] || \ - J->chain[IR_CNEW] || J->chain[IR_CNEWI] || \ - J->chain[IR_BUFSTR] || J->chain[IR_TOSTR] || J->chain[IR_CALLA])) - -/* -- Constant folding for FP numbers ------------------------------------- */ - -LJFOLD(ADD KNUM KNUM) -LJFOLD(SUB KNUM KNUM) -LJFOLD(MUL KNUM KNUM) -LJFOLD(DIV KNUM KNUM) -LJFOLD(ATAN2 KNUM KNUM) -LJFOLD(LDEXP KNUM KNUM) -LJFOLD(MIN KNUM KNUM) -LJFOLD(MAX KNUM KNUM) -LJFOLDF(kfold_numarith) -{ - lua_Number a = knumleft; - lua_Number b = knumright; - lua_Number y = lj_vm_foldarith(a, b, fins->o - IR_ADD); - return lj_ir_knum(J, y); -} - -LJFOLD(NEG KNUM FLOAD) -LJFOLD(ABS KNUM FLOAD) -LJFOLDF(kfold_numabsneg) -{ - lua_Number a = knumleft; - lua_Number y = lj_vm_foldarith(a, a, fins->o - IR_ADD); - return lj_ir_knum(J, y); -} - -LJFOLD(LDEXP KNUM KINT) -LJFOLDF(kfold_ldexp) -{ -#if LJ_TARGET_X86ORX64 - UNUSED(J); - return NEXTFOLD; -#else - return lj_ir_knum(J, ldexp(knumleft, fright->i)); -#endif -} - -LJFOLD(FPMATH KNUM any) -LJFOLDF(kfold_fpmath) -{ - lua_Number a = knumleft; - lua_Number y = lj_vm_foldfpm(a, fins->op2); - return lj_ir_knum(J, y); -} - -LJFOLD(POW KNUM KINT) -LJFOLDF(kfold_numpow) -{ - lua_Number a = knumleft; - lua_Number b = (lua_Number)fright->i; - lua_Number y = lj_vm_foldarith(a, b, IR_POW - IR_ADD); - return lj_ir_knum(J, y); -} - -/* Must not use kfold_kref for numbers (could be NaN). */ -LJFOLD(EQ KNUM KNUM) -LJFOLD(NE KNUM KNUM) -LJFOLD(LT KNUM KNUM) -LJFOLD(GE KNUM KNUM) -LJFOLD(LE KNUM KNUM) -LJFOLD(GT KNUM KNUM) -LJFOLD(ULT KNUM KNUM) -LJFOLD(UGE KNUM KNUM) -LJFOLD(ULE KNUM KNUM) -LJFOLD(UGT KNUM KNUM) -LJFOLDF(kfold_numcomp) -{ - return CONDFOLD(lj_ir_numcmp(knumleft, knumright, (IROp)fins->o)); -} - -/* -- Constant folding for 32 bit integers -------------------------------- */ - -static int32_t kfold_intop(int32_t k1, int32_t k2, IROp op) -{ - switch (op) { - case IR_ADD: k1 += k2; break; - case IR_SUB: k1 -= k2; break; - case IR_MUL: k1 *= k2; break; - case IR_MOD: k1 = lj_vm_modi(k1, k2); break; - case IR_NEG: k1 = -k1; break; - case IR_BAND: k1 &= k2; break; - case IR_BOR: k1 |= k2; break; - case IR_BXOR: k1 ^= k2; break; - case IR_BSHL: k1 <<= (k2 & 31); break; - case IR_BSHR: k1 = (int32_t)((uint32_t)k1 >> (k2 & 31)); break; - case IR_BSAR: k1 >>= (k2 & 31); break; - case IR_BROL: k1 = (int32_t)lj_rol((uint32_t)k1, (k2 & 31)); break; - case IR_BROR: k1 = (int32_t)lj_ror((uint32_t)k1, (k2 & 31)); break; - case IR_MIN: k1 = k1 < k2 ? k1 : k2; break; - case IR_MAX: k1 = k1 > k2 ? k1 : k2; break; - default: lua_assert(0); break; - } - return k1; -} - -LJFOLD(ADD KINT KINT) -LJFOLD(SUB KINT KINT) -LJFOLD(MUL KINT KINT) -LJFOLD(MOD KINT KINT) -LJFOLD(NEG KINT KINT) -LJFOLD(BAND KINT KINT) -LJFOLD(BOR KINT KINT) -LJFOLD(BXOR KINT KINT) -LJFOLD(BSHL KINT KINT) -LJFOLD(BSHR KINT KINT) -LJFOLD(BSAR KINT KINT) -LJFOLD(BROL KINT KINT) -LJFOLD(BROR KINT KINT) -LJFOLD(MIN KINT KINT) -LJFOLD(MAX KINT KINT) -LJFOLDF(kfold_intarith) -{ - return INTFOLD(kfold_intop(fleft->i, fright->i, (IROp)fins->o)); -} - -LJFOLD(ADDOV KINT KINT) -LJFOLD(SUBOV KINT KINT) -LJFOLD(MULOV KINT KINT) -LJFOLDF(kfold_intovarith) -{ - lua_Number n = lj_vm_foldarith((lua_Number)fleft->i, (lua_Number)fright->i, - fins->o - IR_ADDOV); - int32_t k = lj_num2int(n); - if (n != (lua_Number)k) - return FAILFOLD; - return INTFOLD(k); -} - -LJFOLD(BNOT KINT) -LJFOLDF(kfold_bnot) -{ - return INTFOLD(~fleft->i); -} - -LJFOLD(BSWAP KINT) -LJFOLDF(kfold_bswap) -{ - return INTFOLD((int32_t)lj_bswap((uint32_t)fleft->i)); -} - -LJFOLD(LT KINT KINT) -LJFOLD(GE KINT KINT) -LJFOLD(LE KINT KINT) -LJFOLD(GT KINT KINT) -LJFOLD(ULT KINT KINT) -LJFOLD(UGE KINT KINT) -LJFOLD(ULE KINT KINT) -LJFOLD(UGT KINT KINT) -LJFOLD(ABC KINT KINT) -LJFOLDF(kfold_intcomp) -{ - int32_t a = fleft->i, b = fright->i; - switch ((IROp)fins->o) { - case IR_LT: return CONDFOLD(a < b); - case IR_GE: return CONDFOLD(a >= b); - case IR_LE: return CONDFOLD(a <= b); - case IR_GT: return CONDFOLD(a > b); - case IR_ULT: return CONDFOLD((uint32_t)a < (uint32_t)b); - case IR_UGE: return CONDFOLD((uint32_t)a >= (uint32_t)b); - case IR_ULE: return CONDFOLD((uint32_t)a <= (uint32_t)b); - case IR_ABC: - case IR_UGT: return CONDFOLD((uint32_t)a > (uint32_t)b); - default: lua_assert(0); return FAILFOLD; - } -} - -LJFOLD(UGE any KINT) -LJFOLDF(kfold_intcomp0) -{ - if (fright->i == 0) - return DROPFOLD; - return NEXTFOLD; -} - -/* -- Constant folding for 64 bit integers -------------------------------- */ - -static uint64_t kfold_int64arith(uint64_t k1, uint64_t k2, IROp op) -{ - switch (op) { -#if LJ_HASFFI - case IR_ADD: k1 += k2; break; - case IR_SUB: k1 -= k2; break; - case IR_MUL: k1 *= k2; break; - case IR_BAND: k1 &= k2; break; - case IR_BOR: k1 |= k2; break; - case IR_BXOR: k1 ^= k2; break; - case IR_BSHL: k1 <<= (k2 & 63); break; - case IR_BSHR: k1 = (int32_t)((uint32_t)k1 >> (k2 & 63)); break; - case IR_BSAR: k1 >>= (k2 & 63); break; - case IR_BROL: k1 = (int32_t)lj_rol((uint32_t)k1, (k2 & 63)); break; - case IR_BROR: k1 = (int32_t)lj_ror((uint32_t)k1, (k2 & 63)); break; -#endif - default: UNUSED(k2); lua_assert(0); break; - } - return k1; -} - -LJFOLD(ADD KINT64 KINT64) -LJFOLD(SUB KINT64 KINT64) -LJFOLD(MUL KINT64 KINT64) -LJFOLD(BAND KINT64 KINT64) -LJFOLD(BOR KINT64 KINT64) -LJFOLD(BXOR KINT64 KINT64) -LJFOLDF(kfold_int64arith) -{ - return INT64FOLD(kfold_int64arith(ir_k64(fleft)->u64, - ir_k64(fright)->u64, (IROp)fins->o)); -} - -LJFOLD(DIV KINT64 KINT64) -LJFOLD(MOD KINT64 KINT64) -LJFOLD(POW KINT64 KINT64) -LJFOLDF(kfold_int64arith2) -{ -#if LJ_HASFFI - uint64_t k1 = ir_k64(fleft)->u64, k2 = ir_k64(fright)->u64; - if (irt_isi64(fins->t)) { - k1 = fins->o == IR_DIV ? lj_carith_divi64((int64_t)k1, (int64_t)k2) : - fins->o == IR_MOD ? lj_carith_modi64((int64_t)k1, (int64_t)k2) : - lj_carith_powi64((int64_t)k1, (int64_t)k2); - } else { - k1 = fins->o == IR_DIV ? lj_carith_divu64(k1, k2) : - fins->o == IR_MOD ? lj_carith_modu64(k1, k2) : - lj_carith_powu64(k1, k2); - } - return INT64FOLD(k1); -#else - UNUSED(J); lua_assert(0); return FAILFOLD; -#endif -} - -LJFOLD(BSHL KINT64 KINT) -LJFOLD(BSHR KINT64 KINT) -LJFOLD(BSAR KINT64 KINT) -LJFOLD(BROL KINT64 KINT) -LJFOLD(BROR KINT64 KINT) -LJFOLDF(kfold_int64shift) -{ -#if LJ_HASFFI - uint64_t k = ir_k64(fleft)->u64; - int32_t sh = (fright->i & 63); - return INT64FOLD(lj_carith_shift64(k, sh, fins->o - IR_BSHL)); -#else - UNUSED(J); lua_assert(0); return FAILFOLD; -#endif -} - -LJFOLD(BNOT KINT64) -LJFOLDF(kfold_bnot64) -{ -#if LJ_HASFFI - return INT64FOLD(~ir_k64(fleft)->u64); -#else - UNUSED(J); lua_assert(0); return FAILFOLD; -#endif -} - -LJFOLD(BSWAP KINT64) -LJFOLDF(kfold_bswap64) -{ -#if LJ_HASFFI - return INT64FOLD(lj_bswap64(ir_k64(fleft)->u64)); -#else - UNUSED(J); lua_assert(0); return FAILFOLD; -#endif -} - -LJFOLD(LT KINT64 KINT64) -LJFOLD(GE KINT64 KINT64) -LJFOLD(LE KINT64 KINT64) -LJFOLD(GT KINT64 KINT64) -LJFOLD(ULT KINT64 KINT64) -LJFOLD(UGE KINT64 KINT64) -LJFOLD(ULE KINT64 KINT64) -LJFOLD(UGT KINT64 KINT64) -LJFOLDF(kfold_int64comp) -{ -#if LJ_HASFFI - uint64_t a = ir_k64(fleft)->u64, b = ir_k64(fright)->u64; - switch ((IROp)fins->o) { - case IR_LT: return CONDFOLD((int64_t)a < (int64_t)b); - case IR_GE: return CONDFOLD((int64_t)a >= (int64_t)b); - case IR_LE: return CONDFOLD((int64_t)a <= (int64_t)b); - case IR_GT: return CONDFOLD((int64_t)a > (int64_t)b); - case IR_ULT: return CONDFOLD(a < b); - case IR_UGE: return CONDFOLD(a >= b); - case IR_ULE: return CONDFOLD(a <= b); - case IR_UGT: return CONDFOLD(a > b); - default: lua_assert(0); return FAILFOLD; - } -#else - UNUSED(J); lua_assert(0); return FAILFOLD; -#endif -} - -LJFOLD(UGE any KINT64) -LJFOLDF(kfold_int64comp0) -{ -#if LJ_HASFFI - if (ir_k64(fright)->u64 == 0) - return DROPFOLD; - return NEXTFOLD; -#else - UNUSED(J); lua_assert(0); return FAILFOLD; -#endif -} - -/* -- Constant folding for strings ---------------------------------------- */ - -LJFOLD(SNEW KKPTR KINT) -LJFOLDF(kfold_snew_kptr) -{ - GCstr *s = lj_str_new(J->L, (const char *)ir_kptr(fleft), (size_t)fright->i); - return lj_ir_kstr(J, s); -} - -LJFOLD(SNEW any KINT) -LJFOLDF(kfold_snew_empty) -{ - if (fright->i == 0) - return lj_ir_kstr(J, &J2G(J)->strempty); - return NEXTFOLD; -} - -LJFOLD(STRREF KGC KINT) -LJFOLDF(kfold_strref) -{ - GCstr *str = ir_kstr(fleft); - lua_assert((MSize)fright->i <= str->len); - return lj_ir_kkptr(J, (char *)strdata(str) + fright->i); -} - -LJFOLD(STRREF SNEW any) -LJFOLDF(kfold_strref_snew) -{ - PHIBARRIER(fleft); - if (irref_isk(fins->op2) && fright->i == 0) { - return fleft->op1; /* strref(snew(ptr, len), 0) ==> ptr */ - } else { - /* Reassociate: strref(snew(strref(str, a), len), b) ==> strref(str, a+b) */ - IRIns *ir = IR(fleft->op1); - if (ir->o == IR_STRREF) { - IRRef1 str = ir->op1; /* IRIns * is not valid across emitir. */ - PHIBARRIER(ir); - fins->op2 = emitir(IRTI(IR_ADD), ir->op2, fins->op2); /* Clobbers fins! */ - fins->op1 = str; - fins->ot = IRT(IR_STRREF, IRT_PGC); - return RETRYFOLD; - } - } - return NEXTFOLD; -} - -LJFOLD(CALLN CARG IRCALL_lj_str_cmp) -LJFOLDF(kfold_strcmp) -{ - if (irref_isk(fleft->op1) && irref_isk(fleft->op2)) { - GCstr *a = ir_kstr(IR(fleft->op1)); - GCstr *b = ir_kstr(IR(fleft->op2)); - return INTFOLD(lj_str_cmp(a, b)); - } - return NEXTFOLD; -} - -/* -- Constant folding and forwarding for buffers ------------------------- */ - -/* -** Buffer ops perform stores, but their effect is limited to the buffer -** itself. Also, buffer ops are chained: a use of an op implies a use of -** all other ops up the chain. Conversely, if an op is unused, all ops -** up the chain can go unsed. This largely eliminates the need to treat -** them as stores. -** -** Alas, treating them as normal (IRM_N) ops doesn't work, because they -** cannot be CSEd in isolation. CSE for IRM_N is implicitly done in LOOP -** or if FOLD is disabled. -** -** The compromise is to declare them as loads, emit them like stores and -** CSE whole chains manually when the BUFSTR is to be emitted. Any chain -** fragments left over from CSE are eliminated by DCE. -*/ - -/* BUFHDR is emitted like a store, see below. */ - -LJFOLD(BUFPUT BUFHDR BUFSTR) -LJFOLDF(bufput_append) -{ - /* New buffer, no other buffer op inbetween and same buffer? */ - if ((J->flags & JIT_F_OPT_FWD) && - !(fleft->op2 & IRBUFHDR_APPEND) && - fleft->prev == fright->op2 && - fleft->op1 == IR(fright->op2)->op1) { - IRRef ref = fins->op1; - IR(ref)->op2 = (fleft->op2 | IRBUFHDR_APPEND); /* Modify BUFHDR. */ - IR(ref)->op1 = fright->op1; - return ref; - } - return EMITFOLD; /* Always emit, CSE later. */ -} - -LJFOLD(BUFPUT any any) -LJFOLDF(bufput_kgc) -{ - if (LJ_LIKELY(J->flags & JIT_F_OPT_FOLD) && fright->o == IR_KGC) { - GCstr *s2 = ir_kstr(fright); - if (s2->len == 0) { /* Empty string? */ - return LEFTFOLD; - } else { - if (fleft->o == IR_BUFPUT && irref_isk(fleft->op2) && - !irt_isphi(fleft->t)) { /* Join two constant string puts in a row. */ - GCstr *s1 = ir_kstr(IR(fleft->op2)); - IRRef kref = lj_ir_kstr(J, lj_buf_cat2str(J->L, s1, s2)); - /* lj_ir_kstr() may realloc the IR and invalidates any IRIns *. */ - IR(fins->op1)->op2 = kref; /* Modify previous BUFPUT. */ - return fins->op1; - } - } - } - return EMITFOLD; /* Always emit, CSE later. */ -} - -LJFOLD(BUFSTR any any) -LJFOLDF(bufstr_kfold_cse) -{ - lua_assert(fleft->o == IR_BUFHDR || fleft->o == IR_BUFPUT || - fleft->o == IR_CALLL); - if (LJ_LIKELY(J->flags & JIT_F_OPT_FOLD)) { - if (fleft->o == IR_BUFHDR) { /* No put operations? */ - if (!(fleft->op2 & IRBUFHDR_APPEND)) /* Empty buffer? */ - return lj_ir_kstr(J, &J2G(J)->strempty); - fins->op1 = fleft->op1; - fins->op2 = fleft->prev; /* Relies on checks in bufput_append. */ - return CSEFOLD; - } else if (fleft->o == IR_BUFPUT) { - IRIns *irb = IR(fleft->op1); - if (irb->o == IR_BUFHDR && !(irb->op2 & IRBUFHDR_APPEND)) - return fleft->op2; /* Shortcut for a single put operation. */ - } - } - /* Try to CSE the whole chain. */ - if (LJ_LIKELY(J->flags & JIT_F_OPT_CSE)) { - IRRef ref = J->chain[IR_BUFSTR]; - while (ref) { - IRIns *irs = IR(ref), *ira = fleft, *irb = IR(irs->op1); - while (ira->o == irb->o && ira->op2 == irb->op2) { - lua_assert(ira->o == IR_BUFHDR || ira->o == IR_BUFPUT || - ira->o == IR_CALLL || ira->o == IR_CARG); - if (ira->o == IR_BUFHDR && !(ira->op2 & IRBUFHDR_APPEND)) - return ref; /* CSE succeeded. */ - if (ira->o == IR_CALLL && ira->op2 == IRCALL_lj_buf_puttab) - break; - ira = IR(ira->op1); - irb = IR(irb->op1); - } - ref = irs->prev; - } - } - return EMITFOLD; /* No CSE possible. */ -} - -LJFOLD(CALLL CARG IRCALL_lj_buf_putstr_reverse) -LJFOLD(CALLL CARG IRCALL_lj_buf_putstr_upper) -LJFOLD(CALLL CARG IRCALL_lj_buf_putstr_lower) -LJFOLD(CALLL CARG IRCALL_lj_strfmt_putquoted) -LJFOLDF(bufput_kfold_op) -{ - if (irref_isk(fleft->op2)) { - const CCallInfo *ci = &lj_ir_callinfo[fins->op2]; - SBuf *sb = lj_buf_tmp_(J->L); - sb = ((SBuf * (LJ_FASTCALL *)(SBuf *, GCstr *))ci->func)(sb, - ir_kstr(IR(fleft->op2))); - fins->o = IR_BUFPUT; - fins->op1 = fleft->op1; - fins->op2 = lj_ir_kstr(J, lj_buf_tostr(sb)); - return RETRYFOLD; - } - return EMITFOLD; /* Always emit, CSE later. */ -} - -LJFOLD(CALLL CARG IRCALL_lj_buf_putstr_rep) -LJFOLDF(bufput_kfold_rep) -{ - if (irref_isk(fleft->op2)) { - IRIns *irc = IR(fleft->op1); - if (irref_isk(irc->op2)) { - SBuf *sb = lj_buf_tmp_(J->L); - sb = lj_buf_putstr_rep(sb, ir_kstr(IR(irc->op2)), IR(fleft->op2)->i); - fins->o = IR_BUFPUT; - fins->op1 = irc->op1; - fins->op2 = lj_ir_kstr(J, lj_buf_tostr(sb)); - return RETRYFOLD; - } - } - return EMITFOLD; /* Always emit, CSE later. */ -} - -LJFOLD(CALLL CARG IRCALL_lj_strfmt_putfxint) -LJFOLD(CALLL CARG IRCALL_lj_strfmt_putfnum_int) -LJFOLD(CALLL CARG IRCALL_lj_strfmt_putfnum_uint) -LJFOLD(CALLL CARG IRCALL_lj_strfmt_putfnum) -LJFOLD(CALLL CARG IRCALL_lj_strfmt_putfstr) -LJFOLD(CALLL CARG IRCALL_lj_strfmt_putfchar) -LJFOLDF(bufput_kfold_fmt) -{ - IRIns *irc = IR(fleft->op1); - lua_assert(irref_isk(irc->op2)); /* SFormat must be const. */ - if (irref_isk(fleft->op2)) { - SFormat sf = (SFormat)IR(irc->op2)->i; - IRIns *ira = IR(fleft->op2); - SBuf *sb = lj_buf_tmp_(J->L); - switch (fins->op2) { - case IRCALL_lj_strfmt_putfxint: - sb = lj_strfmt_putfxint(sb, sf, ir_k64(ira)->u64); - break; - case IRCALL_lj_strfmt_putfstr: - sb = lj_strfmt_putfstr(sb, sf, ir_kstr(ira)); - break; - case IRCALL_lj_strfmt_putfchar: - sb = lj_strfmt_putfchar(sb, sf, ira->i); - break; - case IRCALL_lj_strfmt_putfnum_int: - case IRCALL_lj_strfmt_putfnum_uint: - case IRCALL_lj_strfmt_putfnum: - default: { - const CCallInfo *ci = &lj_ir_callinfo[fins->op2]; - sb = ((SBuf * (*)(SBuf *, SFormat, lua_Number))ci->func)(sb, sf, - ir_knum(ira)->n); - break; - } - } - fins->o = IR_BUFPUT; - fins->op1 = irc->op1; - fins->op2 = lj_ir_kstr(J, lj_buf_tostr(sb)); - return RETRYFOLD; - } - return EMITFOLD; /* Always emit, CSE later. */ -} - -/* -- Constant folding of pointer arithmetic ------------------------------ */ - -LJFOLD(ADD KGC KINT) -LJFOLD(ADD KGC KINT64) -LJFOLDF(kfold_add_kgc) -{ - GCobj *o = ir_kgc(fleft); -#if LJ_64 - ptrdiff_t ofs = (ptrdiff_t)ir_kint64(fright)->u64; -#else - ptrdiff_t ofs = fright->i; -#endif -#if LJ_HASFFI - if (irt_iscdata(fleft->t)) { - CType *ct = ctype_raw(ctype_ctsG(J2G(J)), gco2cd(o)->ctypeid); - if (ctype_isnum(ct->info) || ctype_isenum(ct->info) || - ctype_isptr(ct->info) || ctype_isfunc(ct->info) || - ctype_iscomplex(ct->info) || ctype_isvector(ct->info)) - return lj_ir_kkptr(J, (char *)o + ofs); - } -#endif - return lj_ir_kptr(J, (char *)o + ofs); -} - -LJFOLD(ADD KPTR KINT) -LJFOLD(ADD KPTR KINT64) -LJFOLD(ADD KKPTR KINT) -LJFOLD(ADD KKPTR KINT64) -LJFOLDF(kfold_add_kptr) -{ - void *p = ir_kptr(fleft); -#if LJ_64 - ptrdiff_t ofs = (ptrdiff_t)ir_kint64(fright)->u64; -#else - ptrdiff_t ofs = fright->i; -#endif - return lj_ir_kptr_(J, fleft->o, (char *)p + ofs); -} - -LJFOLD(ADD any KGC) -LJFOLD(ADD any KPTR) -LJFOLD(ADD any KKPTR) -LJFOLDF(kfold_add_kright) -{ - if (fleft->o == IR_KINT || fleft->o == IR_KINT64) { - IRRef1 tmp = fins->op1; fins->op1 = fins->op2; fins->op2 = tmp; - return RETRYFOLD; - } - return NEXTFOLD; -} - -/* -- Constant folding of conversions ------------------------------------- */ - -LJFOLD(TOBIT KNUM KNUM) -LJFOLDF(kfold_tobit) -{ - return INTFOLD(lj_num2bit(knumleft)); -} - -LJFOLD(CONV KINT IRCONV_NUM_INT) -LJFOLDF(kfold_conv_kint_num) -{ - return lj_ir_knum(J, (lua_Number)fleft->i); -} - -LJFOLD(CONV KINT IRCONV_NUM_U32) -LJFOLDF(kfold_conv_kintu32_num) -{ - return lj_ir_knum(J, (lua_Number)(uint32_t)fleft->i); -} - -LJFOLD(CONV KINT IRCONV_INT_I8) -LJFOLD(CONV KINT IRCONV_INT_U8) -LJFOLD(CONV KINT IRCONV_INT_I16) -LJFOLD(CONV KINT IRCONV_INT_U16) -LJFOLDF(kfold_conv_kint_ext) -{ - int32_t k = fleft->i; - if ((fins->op2 & IRCONV_SRCMASK) == IRT_I8) k = (int8_t)k; - else if ((fins->op2 & IRCONV_SRCMASK) == IRT_U8) k = (uint8_t)k; - else if ((fins->op2 & IRCONV_SRCMASK) == IRT_I16) k = (int16_t)k; - else k = (uint16_t)k; - return INTFOLD(k); -} - -LJFOLD(CONV KINT IRCONV_I64_INT) -LJFOLD(CONV KINT IRCONV_U64_INT) -LJFOLD(CONV KINT IRCONV_I64_U32) -LJFOLD(CONV KINT IRCONV_U64_U32) -LJFOLDF(kfold_conv_kint_i64) -{ - if ((fins->op2 & IRCONV_SEXT)) - return INT64FOLD((uint64_t)(int64_t)fleft->i); - else - return INT64FOLD((uint64_t)(int64_t)(uint32_t)fleft->i); -} - -LJFOLD(CONV KINT64 IRCONV_NUM_I64) -LJFOLDF(kfold_conv_kint64_num_i64) -{ - return lj_ir_knum(J, (lua_Number)(int64_t)ir_kint64(fleft)->u64); -} - -LJFOLD(CONV KINT64 IRCONV_NUM_U64) -LJFOLDF(kfold_conv_kint64_num_u64) -{ - return lj_ir_knum(J, (lua_Number)ir_kint64(fleft)->u64); -} - -LJFOLD(CONV KINT64 IRCONV_INT_I64) -LJFOLD(CONV KINT64 IRCONV_U32_I64) -LJFOLDF(kfold_conv_kint64_int_i64) -{ - return INTFOLD((int32_t)ir_kint64(fleft)->u64); -} - -LJFOLD(CONV KNUM IRCONV_INT_NUM) -LJFOLDF(kfold_conv_knum_int_num) -{ - lua_Number n = knumleft; - int32_t k = lj_num2int(n); - if (irt_isguard(fins->t) && n != (lua_Number)k) { - /* We're about to create a guard which always fails, like CONV +1.5. - ** Some pathological loops cause this during LICM, e.g.: - ** local x,k,t = 0,1.5,{1,[1.5]=2} - ** for i=1,200 do x = x+ t[k]; k = k == 1 and 1.5 or 1 end - ** assert(x == 300) - */ - return FAILFOLD; - } - return INTFOLD(k); -} - -LJFOLD(CONV KNUM IRCONV_U32_NUM) -LJFOLDF(kfold_conv_knum_u32_num) -{ -#ifdef _MSC_VER - { /* Workaround for MSVC bug. */ - volatile uint32_t u = (uint32_t)knumleft; - return INTFOLD((int32_t)u); - } -#else - return INTFOLD((int32_t)(uint32_t)knumleft); -#endif -} - -LJFOLD(CONV KNUM IRCONV_I64_NUM) -LJFOLDF(kfold_conv_knum_i64_num) -{ - return INT64FOLD((uint64_t)(int64_t)knumleft); -} - -LJFOLD(CONV KNUM IRCONV_U64_NUM) -LJFOLDF(kfold_conv_knum_u64_num) -{ - return INT64FOLD(lj_num2u64(knumleft)); -} - -LJFOLD(TOSTR KNUM any) -LJFOLDF(kfold_tostr_knum) -{ - return lj_ir_kstr(J, lj_strfmt_num(J->L, ir_knum(fleft))); -} - -LJFOLD(TOSTR KINT any) -LJFOLDF(kfold_tostr_kint) -{ - return lj_ir_kstr(J, fins->op2 == IRTOSTR_INT ? - lj_strfmt_int(J->L, fleft->i) : - lj_strfmt_char(J->L, fleft->i)); -} - -LJFOLD(STRTO KGC) -LJFOLDF(kfold_strto) -{ - TValue n; - if (lj_strscan_num(ir_kstr(fleft), &n)) - return lj_ir_knum(J, numV(&n)); - return FAILFOLD; -} - -/* -- Constant folding of equality checks --------------------------------- */ - -/* Don't constant-fold away FLOAD checks against KNULL. */ -LJFOLD(EQ FLOAD KNULL) -LJFOLD(NE FLOAD KNULL) -LJFOLDX(lj_opt_cse) - -/* But fold all other KNULL compares, since only KNULL is equal to KNULL. */ -LJFOLD(EQ any KNULL) -LJFOLD(NE any KNULL) -LJFOLD(EQ KNULL any) -LJFOLD(NE KNULL any) -LJFOLD(EQ KINT KINT) /* Constants are unique, so same refs <==> same value. */ -LJFOLD(NE KINT KINT) -LJFOLD(EQ KINT64 KINT64) -LJFOLD(NE KINT64 KINT64) -LJFOLD(EQ KGC KGC) -LJFOLD(NE KGC KGC) -LJFOLDF(kfold_kref) -{ - return CONDFOLD((fins->op1 == fins->op2) ^ (fins->o == IR_NE)); -} - -/* -- Algebraic shortcuts ------------------------------------------------- */ - -LJFOLD(FPMATH FPMATH IRFPM_FLOOR) -LJFOLD(FPMATH FPMATH IRFPM_CEIL) -LJFOLD(FPMATH FPMATH IRFPM_TRUNC) -LJFOLDF(shortcut_round) -{ - IRFPMathOp op = (IRFPMathOp)fleft->op2; - if (op == IRFPM_FLOOR || op == IRFPM_CEIL || op == IRFPM_TRUNC) - return LEFTFOLD; /* round(round_left(x)) = round_left(x) */ - return NEXTFOLD; -} - -LJFOLD(ABS ABS FLOAD) -LJFOLDF(shortcut_left) -{ - return LEFTFOLD; /* f(g(x)) ==> g(x) */ -} - -LJFOLD(ABS NEG FLOAD) -LJFOLDF(shortcut_dropleft) -{ - PHIBARRIER(fleft); - fins->op1 = fleft->op1; /* abs(neg(x)) ==> abs(x) */ - return RETRYFOLD; -} - -/* Note: no safe shortcuts with STRTO and TOSTR ("1e2" ==> +100 ==> "100"). */ -LJFOLD(NEG NEG any) -LJFOLD(BNOT BNOT) -LJFOLD(BSWAP BSWAP) -LJFOLDF(shortcut_leftleft) -{ - PHIBARRIER(fleft); /* See above. Fold would be ok, but not beneficial. */ - return fleft->op1; /* f(g(x)) ==> x */ -} - -/* -- FP algebraic simplifications ---------------------------------------- */ - -/* FP arithmetic is tricky -- there's not much to simplify. -** Please note the following common pitfalls before sending "improvements": -** x+0 ==> x is INVALID for x=-0 -** 0-x ==> -x is INVALID for x=+0 -** x*0 ==> 0 is INVALID for x=-0, x=+-Inf or x=NaN -*/ - -LJFOLD(ADD NEG any) -LJFOLDF(simplify_numadd_negx) -{ - PHIBARRIER(fleft); - fins->o = IR_SUB; /* (-a) + b ==> b - a */ - fins->op1 = fins->op2; - fins->op2 = fleft->op1; - return RETRYFOLD; -} - -LJFOLD(ADD any NEG) -LJFOLDF(simplify_numadd_xneg) -{ - PHIBARRIER(fright); - fins->o = IR_SUB; /* a + (-b) ==> a - b */ - fins->op2 = fright->op1; - return RETRYFOLD; -} - -LJFOLD(SUB any KNUM) -LJFOLDF(simplify_numsub_k) -{ - lua_Number n = knumright; - if (n == 0.0) /* x - (+-0) ==> x */ - return LEFTFOLD; - return NEXTFOLD; -} - -LJFOLD(SUB NEG KNUM) -LJFOLDF(simplify_numsub_negk) -{ - PHIBARRIER(fleft); - fins->op2 = fleft->op1; /* (-x) - k ==> (-k) - x */ - fins->op1 = (IRRef1)lj_ir_knum(J, -knumright); - return RETRYFOLD; -} - -LJFOLD(SUB any NEG) -LJFOLDF(simplify_numsub_xneg) -{ - PHIBARRIER(fright); - fins->o = IR_ADD; /* a - (-b) ==> a + b */ - fins->op2 = fright->op1; - return RETRYFOLD; -} - -LJFOLD(MUL any KNUM) -LJFOLD(DIV any KNUM) -LJFOLDF(simplify_nummuldiv_k) -{ - lua_Number n = knumright; - if (n == 1.0) { /* x o 1 ==> x */ - return LEFTFOLD; - } else if (n == -1.0) { /* x o -1 ==> -x */ - IRRef op1 = fins->op1; - fins->op2 = (IRRef1)lj_ir_ksimd(J, LJ_KSIMD_NEG); /* Modifies fins. */ - fins->op1 = op1; - fins->o = IR_NEG; - return RETRYFOLD; - } else if (fins->o == IR_MUL && n == 2.0) { /* x * 2 ==> x + x */ - fins->o = IR_ADD; - fins->op2 = fins->op1; - return RETRYFOLD; - } else if (fins->o == IR_DIV) { /* x / 2^k ==> x * 2^-k */ - uint64_t u = ir_knum(fright)->u64; - uint32_t ex = ((uint32_t)(u >> 52) & 0x7ff); - if ((u & U64x(000fffff,ffffffff)) == 0 && ex - 1 < 0x7fd) { - u = (u & ((uint64_t)1 << 63)) | ((uint64_t)(0x7fe - ex) << 52); - fins->o = IR_MUL; /* Multiply by exact reciprocal. */ - fins->op2 = lj_ir_knum_u64(J, u); - return RETRYFOLD; - } - } - return NEXTFOLD; -} - -LJFOLD(MUL NEG KNUM) -LJFOLD(DIV NEG KNUM) -LJFOLDF(simplify_nummuldiv_negk) -{ - PHIBARRIER(fleft); - fins->op1 = fleft->op1; /* (-a) o k ==> a o (-k) */ - fins->op2 = (IRRef1)lj_ir_knum(J, -knumright); - return RETRYFOLD; -} - -LJFOLD(MUL NEG NEG) -LJFOLD(DIV NEG NEG) -LJFOLDF(simplify_nummuldiv_negneg) -{ - PHIBARRIER(fleft); - PHIBARRIER(fright); - fins->op1 = fleft->op1; /* (-a) o (-b) ==> a o b */ - fins->op2 = fright->op1; - return RETRYFOLD; -} - -LJFOLD(POW any KINT) -LJFOLDF(simplify_numpow_xk) -{ - int32_t k = fright->i; - TRef ref = fins->op1; - if (k == 0) /* x ^ 0 ==> 1 */ - return lj_ir_knum_one(J); /* Result must be a number, not an int. */ - if (k == 1) /* x ^ 1 ==> x */ - return LEFTFOLD; - if ((uint32_t)(k+65536) > 2*65536u) /* Limit code explosion. */ - return NEXTFOLD; - if (k < 0) { /* x ^ (-k) ==> (1/x) ^ k. */ - ref = emitir(IRTN(IR_DIV), lj_ir_knum_one(J), ref); - k = -k; - } - /* Unroll x^k for 1 <= k <= 65536. */ - for (; (k & 1) == 0; k >>= 1) /* Handle leading zeros. */ - ref = emitir(IRTN(IR_MUL), ref, ref); - if ((k >>= 1) != 0) { /* Handle trailing bits. */ - TRef tmp = emitir(IRTN(IR_MUL), ref, ref); - for (; k != 1; k >>= 1) { - if (k & 1) - ref = emitir(IRTN(IR_MUL), ref, tmp); - tmp = emitir(IRTN(IR_MUL), tmp, tmp); - } - ref = emitir(IRTN(IR_MUL), ref, tmp); - } - return ref; -} - -LJFOLD(POW KNUM any) -LJFOLDF(simplify_numpow_kx) -{ - lua_Number n = knumleft; - if (n == 2.0) { /* 2.0 ^ i ==> ldexp(1.0, tonum(i)) */ - fins->o = IR_CONV; -#if LJ_TARGET_X86ORX64 - fins->op1 = fins->op2; - fins->op2 = IRCONV_NUM_INT; - fins->op2 = (IRRef1)lj_opt_fold(J); -#endif - fins->op1 = (IRRef1)lj_ir_knum_one(J); - fins->o = IR_LDEXP; - return RETRYFOLD; - } - return NEXTFOLD; -} - -/* -- Simplify conversions ------------------------------------------------ */ - -LJFOLD(CONV CONV IRCONV_NUM_INT) /* _NUM */ -LJFOLDF(shortcut_conv_num_int) -{ - PHIBARRIER(fleft); - /* Only safe with a guarded conversion to int. */ - if ((fleft->op2 & IRCONV_SRCMASK) == IRT_NUM && irt_isguard(fleft->t)) - return fleft->op1; /* f(g(x)) ==> x */ - return NEXTFOLD; -} - -LJFOLD(CONV CONV IRCONV_INT_NUM) /* _INT */ -LJFOLD(CONV CONV IRCONV_U32_NUM) /* _U32*/ -LJFOLDF(simplify_conv_int_num) -{ - /* Fold even across PHI to avoid expensive num->int conversions in loop. */ - if ((fleft->op2 & IRCONV_SRCMASK) == - ((fins->op2 & IRCONV_DSTMASK) >> IRCONV_DSH)) - return fleft->op1; - return NEXTFOLD; -} - -LJFOLD(CONV CONV IRCONV_I64_NUM) /* _INT or _U32 */ -LJFOLD(CONV CONV IRCONV_U64_NUM) /* _INT or _U32 */ -LJFOLDF(simplify_conv_i64_num) -{ - PHIBARRIER(fleft); - if ((fleft->op2 & IRCONV_SRCMASK) == IRT_INT) { - /* Reduce to a sign-extension. */ - fins->op1 = fleft->op1; - fins->op2 = ((IRT_I64<<5)|IRT_INT|IRCONV_SEXT); - return RETRYFOLD; - } else if ((fleft->op2 & IRCONV_SRCMASK) == IRT_U32) { -#if LJ_TARGET_X64 - return fleft->op1; -#else - /* Reduce to a zero-extension. */ - fins->op1 = fleft->op1; - fins->op2 = (IRT_I64<<5)|IRT_U32; - return RETRYFOLD; -#endif - } - return NEXTFOLD; -} - -LJFOLD(CONV CONV IRCONV_INT_I64) /* _INT or _U32 */ -LJFOLD(CONV CONV IRCONV_INT_U64) /* _INT or _U32 */ -LJFOLD(CONV CONV IRCONV_U32_I64) /* _INT or _U32 */ -LJFOLD(CONV CONV IRCONV_U32_U64) /* _INT or _U32 */ -LJFOLDF(simplify_conv_int_i64) -{ - int src; - PHIBARRIER(fleft); - src = (fleft->op2 & IRCONV_SRCMASK); - if (src == IRT_INT || src == IRT_U32) { - if (src == ((fins->op2 & IRCONV_DSTMASK) >> IRCONV_DSH)) { - return fleft->op1; - } else { - fins->op2 = ((fins->op2 & IRCONV_DSTMASK) | src); - fins->op1 = fleft->op1; - return RETRYFOLD; - } - } - return NEXTFOLD; -} - -LJFOLD(CONV CONV IRCONV_FLOAT_NUM) /* _FLOAT */ -LJFOLDF(simplify_conv_flt_num) -{ - PHIBARRIER(fleft); - if ((fleft->op2 & IRCONV_SRCMASK) == IRT_FLOAT) - return fleft->op1; - return NEXTFOLD; -} - -/* Shortcut TOBIT + IRT_NUM <- IRT_INT/IRT_U32 conversion. */ -LJFOLD(TOBIT CONV KNUM) -LJFOLDF(simplify_tobit_conv) -{ - /* Fold even across PHI to avoid expensive num->int conversions in loop. */ - if ((fleft->op2 & IRCONV_SRCMASK) == IRT_INT) { - lua_assert(irt_isnum(fleft->t)); - return fleft->op1; - } else if ((fleft->op2 & IRCONV_SRCMASK) == IRT_U32) { - lua_assert(irt_isnum(fleft->t)); - fins->o = IR_CONV; - fins->op1 = fleft->op1; - fins->op2 = (IRT_INT<<5)|IRT_U32; - return RETRYFOLD; - } - return NEXTFOLD; -} - -/* Shortcut floor/ceil/round + IRT_NUM <- IRT_INT/IRT_U32 conversion. */ -LJFOLD(FPMATH CONV IRFPM_FLOOR) -LJFOLD(FPMATH CONV IRFPM_CEIL) -LJFOLD(FPMATH CONV IRFPM_TRUNC) -LJFOLDF(simplify_floor_conv) -{ - if ((fleft->op2 & IRCONV_SRCMASK) == IRT_INT || - (fleft->op2 & IRCONV_SRCMASK) == IRT_U32) - return LEFTFOLD; - return NEXTFOLD; -} - -/* Strength reduction of widening. */ -LJFOLD(CONV any IRCONV_I64_INT) -LJFOLD(CONV any IRCONV_U64_INT) -LJFOLDF(simplify_conv_sext) -{ - IRRef ref = fins->op1; - int64_t ofs = 0; - if (!(fins->op2 & IRCONV_SEXT)) - return NEXTFOLD; - PHIBARRIER(fleft); - if (fleft->o == IR_XLOAD && (irt_isu8(fleft->t) || irt_isu16(fleft->t))) - goto ok_reduce; - if (fleft->o == IR_ADD && irref_isk(fleft->op2)) { - ofs = (int64_t)IR(fleft->op2)->i; - ref = fleft->op1; - } - /* Use scalar evolution analysis results to strength-reduce sign-extension. */ - if (ref == J->scev.idx) { - IRRef lo = J->scev.dir ? J->scev.start : J->scev.stop; - lua_assert(irt_isint(J->scev.t)); - if (lo && IR(lo)->o == IR_KINT && IR(lo)->i + ofs >= 0) { - ok_reduce: -#if LJ_TARGET_X64 - /* Eliminate widening. All 32 bit ops do an implicit zero-extension. */ - return LEFTFOLD; -#else - /* Reduce to a (cheaper) zero-extension. */ - fins->op2 &= ~IRCONV_SEXT; - return RETRYFOLD; -#endif - } - } - return NEXTFOLD; -} - -/* Strength reduction of narrowing. */ -LJFOLD(CONV ADD IRCONV_INT_I64) -LJFOLD(CONV SUB IRCONV_INT_I64) -LJFOLD(CONV MUL IRCONV_INT_I64) -LJFOLD(CONV ADD IRCONV_INT_U64) -LJFOLD(CONV SUB IRCONV_INT_U64) -LJFOLD(CONV MUL IRCONV_INT_U64) -LJFOLD(CONV ADD IRCONV_U32_I64) -LJFOLD(CONV SUB IRCONV_U32_I64) -LJFOLD(CONV MUL IRCONV_U32_I64) -LJFOLD(CONV ADD IRCONV_U32_U64) -LJFOLD(CONV SUB IRCONV_U32_U64) -LJFOLD(CONV MUL IRCONV_U32_U64) -LJFOLDF(simplify_conv_narrow) -{ - IROp op = (IROp)fleft->o; - IRType t = irt_type(fins->t); - IRRef op1 = fleft->op1, op2 = fleft->op2, mode = fins->op2; - PHIBARRIER(fleft); - op1 = emitir(IRTI(IR_CONV), op1, mode); - op2 = emitir(IRTI(IR_CONV), op2, mode); - fins->ot = IRT(op, t); - fins->op1 = op1; - fins->op2 = op2; - return RETRYFOLD; -} - -/* Special CSE rule for CONV. */ -LJFOLD(CONV any any) -LJFOLDF(cse_conv) -{ - if (LJ_LIKELY(J->flags & JIT_F_OPT_CSE)) { - IRRef op1 = fins->op1, op2 = (fins->op2 & IRCONV_MODEMASK); - uint8_t guard = irt_isguard(fins->t); - IRRef ref = J->chain[IR_CONV]; - while (ref > op1) { - IRIns *ir = IR(ref); - /* Commoning with stronger checks is ok. */ - if (ir->op1 == op1 && (ir->op2 & IRCONV_MODEMASK) == op2 && - irt_isguard(ir->t) >= guard) - return ref; - ref = ir->prev; - } - } - return EMITFOLD; /* No fallthrough to regular CSE. */ -} - -/* FP conversion narrowing. */ -LJFOLD(TOBIT ADD KNUM) -LJFOLD(TOBIT SUB KNUM) -LJFOLD(CONV ADD IRCONV_INT_NUM) -LJFOLD(CONV SUB IRCONV_INT_NUM) -LJFOLD(CONV ADD IRCONV_I64_NUM) -LJFOLD(CONV SUB IRCONV_I64_NUM) -LJFOLDF(narrow_convert) -{ - PHIBARRIER(fleft); - /* Narrowing ignores PHIs and repeating it inside the loop is not useful. */ - if (J->chain[IR_LOOP]) - return NEXTFOLD; - lua_assert(fins->o != IR_CONV || (fins->op2&IRCONV_CONVMASK) != IRCONV_TOBIT); - return lj_opt_narrow_convert(J); -} - -/* -- Integer algebraic simplifications ----------------------------------- */ - -LJFOLD(ADD any KINT) -LJFOLD(ADDOV any KINT) -LJFOLD(SUBOV any KINT) -LJFOLDF(simplify_intadd_k) -{ - if (fright->i == 0) /* i o 0 ==> i */ - return LEFTFOLD; - return NEXTFOLD; -} - -LJFOLD(MULOV any KINT) -LJFOLDF(simplify_intmul_k) -{ - if (fright->i == 0) /* i * 0 ==> 0 */ - return RIGHTFOLD; - if (fright->i == 1) /* i * 1 ==> i */ - return LEFTFOLD; - if (fright->i == 2) { /* i * 2 ==> i + i */ - fins->o = IR_ADDOV; - fins->op2 = fins->op1; - return RETRYFOLD; - } - return NEXTFOLD; -} - -LJFOLD(SUB any KINT) -LJFOLDF(simplify_intsub_k) -{ - if (fright->i == 0) /* i - 0 ==> i */ - return LEFTFOLD; - fins->o = IR_ADD; /* i - k ==> i + (-k) */ - fins->op2 = (IRRef1)lj_ir_kint(J, -fright->i); /* Overflow for -2^31 ok. */ - return RETRYFOLD; -} - -LJFOLD(SUB KINT any) -LJFOLD(SUB KINT64 any) -LJFOLDF(simplify_intsub_kleft) -{ - if (fleft->o == IR_KINT ? (fleft->i == 0) : (ir_kint64(fleft)->u64 == 0)) { - fins->o = IR_NEG; /* 0 - i ==> -i */ - fins->op1 = fins->op2; - return RETRYFOLD; - } - return NEXTFOLD; -} - -LJFOLD(ADD any KINT64) -LJFOLDF(simplify_intadd_k64) -{ - if (ir_kint64(fright)->u64 == 0) /* i + 0 ==> i */ - return LEFTFOLD; - return NEXTFOLD; -} - -LJFOLD(SUB any KINT64) -LJFOLDF(simplify_intsub_k64) -{ - uint64_t k = ir_kint64(fright)->u64; - if (k == 0) /* i - 0 ==> i */ - return LEFTFOLD; - fins->o = IR_ADD; /* i - k ==> i + (-k) */ - fins->op2 = (IRRef1)lj_ir_kint64(J, (uint64_t)-(int64_t)k); - return RETRYFOLD; -} - -static TRef simplify_intmul_k(jit_State *J, int32_t k) -{ - /* Note: many more simplifications are possible, e.g. 2^k1 +- 2^k2. - ** But this is mainly intended for simple address arithmetic. - ** Also it's easier for the backend to optimize the original multiplies. - */ - if (k == 0) { /* i * 0 ==> 0 */ - return RIGHTFOLD; - } else if (k == 1) { /* i * 1 ==> i */ - return LEFTFOLD; - } else if ((k & (k-1)) == 0) { /* i * 2^k ==> i << k */ - fins->o = IR_BSHL; - fins->op2 = lj_ir_kint(J, lj_fls((uint32_t)k)); - return RETRYFOLD; - } - return NEXTFOLD; -} - -LJFOLD(MUL any KINT) -LJFOLDF(simplify_intmul_k32) -{ - if (fright->i >= 0) - return simplify_intmul_k(J, fright->i); - return NEXTFOLD; -} - -LJFOLD(MUL any KINT64) -LJFOLDF(simplify_intmul_k64) -{ -#if LJ_HASFFI - if (ir_kint64(fright)->u64 < 0x80000000u) - return simplify_intmul_k(J, (int32_t)ir_kint64(fright)->u64); - return NEXTFOLD; -#else - UNUSED(J); lua_assert(0); return FAILFOLD; -#endif -} - -LJFOLD(MOD any KINT) -LJFOLDF(simplify_intmod_k) -{ - int32_t k = fright->i; - lua_assert(k != 0); - if (k > 0 && (k & (k-1)) == 0) { /* i % (2^k) ==> i & (2^k-1) */ - fins->o = IR_BAND; - fins->op2 = lj_ir_kint(J, k-1); - return RETRYFOLD; - } - return NEXTFOLD; -} - -LJFOLD(MOD KINT any) -LJFOLDF(simplify_intmod_kleft) -{ - if (fleft->i == 0) - return INTFOLD(0); - return NEXTFOLD; -} - -LJFOLD(SUB any any) -LJFOLD(SUBOV any any) -LJFOLDF(simplify_intsub) -{ - if (fins->op1 == fins->op2 && !irt_isnum(fins->t)) /* i - i ==> 0 */ - return irt_is64(fins->t) ? INT64FOLD(0) : INTFOLD(0); - return NEXTFOLD; -} - -LJFOLD(SUB ADD any) -LJFOLDF(simplify_intsubadd_leftcancel) -{ - if (!irt_isnum(fins->t)) { - PHIBARRIER(fleft); - if (fins->op2 == fleft->op1) /* (i + j) - i ==> j */ - return fleft->op2; - if (fins->op2 == fleft->op2) /* (i + j) - j ==> i */ - return fleft->op1; - } - return NEXTFOLD; -} - -LJFOLD(SUB SUB any) -LJFOLDF(simplify_intsubsub_leftcancel) -{ - if (!irt_isnum(fins->t)) { - PHIBARRIER(fleft); - if (fins->op2 == fleft->op1) { /* (i - j) - i ==> 0 - j */ - fins->op1 = (IRRef1)lj_ir_kint(J, 0); - fins->op2 = fleft->op2; - return RETRYFOLD; - } - } - return NEXTFOLD; -} - -LJFOLD(SUB any SUB) -LJFOLDF(simplify_intsubsub_rightcancel) -{ - if (!irt_isnum(fins->t)) { - PHIBARRIER(fright); - if (fins->op1 == fright->op1) /* i - (i - j) ==> j */ - return fright->op2; - } - return NEXTFOLD; -} - -LJFOLD(SUB any ADD) -LJFOLDF(simplify_intsubadd_rightcancel) -{ - if (!irt_isnum(fins->t)) { - PHIBARRIER(fright); - if (fins->op1 == fright->op1) { /* i - (i + j) ==> 0 - j */ - fins->op2 = fright->op2; - fins->op1 = (IRRef1)lj_ir_kint(J, 0); - return RETRYFOLD; - } - if (fins->op1 == fright->op2) { /* i - (j + i) ==> 0 - j */ - fins->op2 = fright->op1; - fins->op1 = (IRRef1)lj_ir_kint(J, 0); - return RETRYFOLD; - } - } - return NEXTFOLD; -} - -LJFOLD(SUB ADD ADD) -LJFOLDF(simplify_intsubaddadd_cancel) -{ - if (!irt_isnum(fins->t)) { - PHIBARRIER(fleft); - PHIBARRIER(fright); - if (fleft->op1 == fright->op1) { /* (i + j1) - (i + j2) ==> j1 - j2 */ - fins->op1 = fleft->op2; - fins->op2 = fright->op2; - return RETRYFOLD; - } - if (fleft->op1 == fright->op2) { /* (i + j1) - (j2 + i) ==> j1 - j2 */ - fins->op1 = fleft->op2; - fins->op2 = fright->op1; - return RETRYFOLD; - } - if (fleft->op2 == fright->op1) { /* (j1 + i) - (i + j2) ==> j1 - j2 */ - fins->op1 = fleft->op1; - fins->op2 = fright->op2; - return RETRYFOLD; - } - if (fleft->op2 == fright->op2) { /* (j1 + i) - (j2 + i) ==> j1 - j2 */ - fins->op1 = fleft->op1; - fins->op2 = fright->op1; - return RETRYFOLD; - } - } - return NEXTFOLD; -} - -LJFOLD(BAND any KINT) -LJFOLD(BAND any KINT64) -LJFOLDF(simplify_band_k) -{ - int64_t k = fright->o == IR_KINT ? (int64_t)fright->i : - (int64_t)ir_k64(fright)->u64; - if (k == 0) /* i & 0 ==> 0 */ - return RIGHTFOLD; - if (k == -1) /* i & -1 ==> i */ - return LEFTFOLD; - return NEXTFOLD; -} - -LJFOLD(BOR any KINT) -LJFOLD(BOR any KINT64) -LJFOLDF(simplify_bor_k) -{ - int64_t k = fright->o == IR_KINT ? (int64_t)fright->i : - (int64_t)ir_k64(fright)->u64; - if (k == 0) /* i | 0 ==> i */ - return LEFTFOLD; - if (k == -1) /* i | -1 ==> -1 */ - return RIGHTFOLD; - return NEXTFOLD; -} - -LJFOLD(BXOR any KINT) -LJFOLD(BXOR any KINT64) -LJFOLDF(simplify_bxor_k) -{ - int64_t k = fright->o == IR_KINT ? (int64_t)fright->i : - (int64_t)ir_k64(fright)->u64; - if (k == 0) /* i xor 0 ==> i */ - return LEFTFOLD; - if (k == -1) { /* i xor -1 ==> ~i */ - fins->o = IR_BNOT; - fins->op2 = 0; - return RETRYFOLD; - } - return NEXTFOLD; -} - -LJFOLD(BSHL any KINT) -LJFOLD(BSHR any KINT) -LJFOLD(BSAR any KINT) -LJFOLD(BROL any KINT) -LJFOLD(BROR any KINT) -LJFOLDF(simplify_shift_ik) -{ - int32_t mask = irt_is64(fins->t) ? 63 : 31; - int32_t k = (fright->i & mask); - if (k == 0) /* i o 0 ==> i */ - return LEFTFOLD; - if (k == 1 && fins->o == IR_BSHL) { /* i << 1 ==> i + i */ - fins->o = IR_ADD; - fins->op2 = fins->op1; - return RETRYFOLD; - } - if (k != fright->i) { /* i o k ==> i o (k & mask) */ - fins->op2 = (IRRef1)lj_ir_kint(J, k); - return RETRYFOLD; - } -#ifndef LJ_TARGET_UNIFYROT - if (fins->o == IR_BROR) { /* bror(i, k) ==> brol(i, (-k)&mask) */ - fins->o = IR_BROL; - fins->op2 = (IRRef1)lj_ir_kint(J, (-k)&mask); - return RETRYFOLD; - } -#endif - return NEXTFOLD; -} - -LJFOLD(BSHL any BAND) -LJFOLD(BSHR any BAND) -LJFOLD(BSAR any BAND) -LJFOLD(BROL any BAND) -LJFOLD(BROR any BAND) -LJFOLDF(simplify_shift_andk) -{ - IRIns *irk = IR(fright->op2); - PHIBARRIER(fright); - if ((fins->o < IR_BROL ? LJ_TARGET_MASKSHIFT : LJ_TARGET_MASKROT) && - irk->o == IR_KINT) { /* i o (j & mask) ==> i o j */ - int32_t mask = irt_is64(fins->t) ? 63 : 31; - int32_t k = irk->i & mask; - if (k == mask) { - fins->op2 = fright->op1; - return RETRYFOLD; - } - } - return NEXTFOLD; -} - -LJFOLD(BSHL KINT any) -LJFOLD(BSHR KINT any) -LJFOLD(BSHL KINT64 any) -LJFOLD(BSHR KINT64 any) -LJFOLDF(simplify_shift1_ki) -{ - int64_t k = fleft->o == IR_KINT ? (int64_t)fleft->i : - (int64_t)ir_k64(fleft)->u64; - if (k == 0) /* 0 o i ==> 0 */ - return LEFTFOLD; - return NEXTFOLD; -} - -LJFOLD(BSAR KINT any) -LJFOLD(BROL KINT any) -LJFOLD(BROR KINT any) -LJFOLD(BSAR KINT64 any) -LJFOLD(BROL KINT64 any) -LJFOLD(BROR KINT64 any) -LJFOLDF(simplify_shift2_ki) -{ - int64_t k = fleft->o == IR_KINT ? (int64_t)fleft->i : - (int64_t)ir_k64(fleft)->u64; - if (k == 0 || k == -1) /* 0 o i ==> 0; -1 o i ==> -1 */ - return LEFTFOLD; - return NEXTFOLD; -} - -LJFOLD(BSHL BAND KINT) -LJFOLD(BSHR BAND KINT) -LJFOLD(BROL BAND KINT) -LJFOLD(BROR BAND KINT) -LJFOLDF(simplify_shiftk_andk) -{ - IRIns *irk = IR(fleft->op2); - PHIBARRIER(fleft); - if (irk->o == IR_KINT) { /* (i & k1) o k2 ==> (i o k2) & (k1 o k2) */ - int32_t k = kfold_intop(irk->i, fright->i, (IROp)fins->o); - fins->op1 = fleft->op1; - fins->op1 = (IRRef1)lj_opt_fold(J); - fins->op2 = (IRRef1)lj_ir_kint(J, k); - fins->ot = IRTI(IR_BAND); - return RETRYFOLD; - } else if (irk->o == IR_KINT64) { - uint64_t k = kfold_int64arith(ir_k64(irk)->u64, fright->i, (IROp)fins->o); - IROpT ot = fleft->ot; - fins->op1 = fleft->op1; - fins->op1 = (IRRef1)lj_opt_fold(J); - fins->op2 = (IRRef1)lj_ir_kint64(J, k); - fins->ot = ot; - return RETRYFOLD; - } - return NEXTFOLD; -} - -LJFOLD(BAND BSHL KINT) -LJFOLD(BAND BSHR KINT) -LJFOLDF(simplify_andk_shiftk) -{ - IRIns *irk = IR(fleft->op2); - if (irk->o == IR_KINT && - kfold_intop(-1, irk->i, (IROp)fleft->o) == fright->i) - return LEFTFOLD; /* (i o k1) & k2 ==> i, if (-1 o k1) == k2 */ - return NEXTFOLD; -} - -LJFOLD(BAND BOR KINT) -LJFOLD(BOR BAND KINT) -LJFOLDF(simplify_andor_k) -{ - IRIns *irk = IR(fleft->op2); - PHIBARRIER(fleft); - if (irk->o == IR_KINT) { - int32_t k = kfold_intop(irk->i, fright->i, (IROp)fins->o); - /* (i | k1) & k2 ==> i & k2, if (k1 & k2) == 0. */ - /* (i & k1) | k2 ==> i | k2, if (k1 | k2) == -1. */ - if (k == (fins->o == IR_BAND ? 0 : -1)) { - fins->op1 = fleft->op1; - return RETRYFOLD; - } - } - return NEXTFOLD; -} - -LJFOLD(BAND BOR KINT64) -LJFOLD(BOR BAND KINT64) -LJFOLDF(simplify_andor_k64) -{ -#if LJ_HASFFI - IRIns *irk = IR(fleft->op2); - PHIBARRIER(fleft); - if (irk->o == IR_KINT64) { - uint64_t k = kfold_int64arith(ir_k64(irk)->u64, - ir_k64(fright)->u64, (IROp)fins->o); - /* (i | k1) & k2 ==> i & k2, if (k1 & k2) == 0. */ - /* (i & k1) | k2 ==> i | k2, if (k1 | k2) == -1. */ - if (k == (fins->o == IR_BAND ? (uint64_t)0 : ~(uint64_t)0)) { - fins->op1 = fleft->op1; - return RETRYFOLD; - } - } - return NEXTFOLD; -#else - UNUSED(J); lua_assert(0); return FAILFOLD; -#endif -} - -/* -- Reassociation ------------------------------------------------------- */ - -LJFOLD(ADD ADD KINT) -LJFOLD(MUL MUL KINT) -LJFOLD(BAND BAND KINT) -LJFOLD(BOR BOR KINT) -LJFOLD(BXOR BXOR KINT) -LJFOLDF(reassoc_intarith_k) -{ - IRIns *irk = IR(fleft->op2); - if (irk->o == IR_KINT) { - int32_t k = kfold_intop(irk->i, fright->i, (IROp)fins->o); - if (k == irk->i) /* (i o k1) o k2 ==> i o k1, if (k1 o k2) == k1. */ - return LEFTFOLD; - PHIBARRIER(fleft); - fins->op1 = fleft->op1; - fins->op2 = (IRRef1)lj_ir_kint(J, k); - return RETRYFOLD; /* (i o k1) o k2 ==> i o (k1 o k2) */ - } - return NEXTFOLD; -} - -LJFOLD(ADD ADD KINT64) -LJFOLD(MUL MUL KINT64) -LJFOLD(BAND BAND KINT64) -LJFOLD(BOR BOR KINT64) -LJFOLD(BXOR BXOR KINT64) -LJFOLDF(reassoc_intarith_k64) -{ -#if LJ_HASFFI - IRIns *irk = IR(fleft->op2); - if (irk->o == IR_KINT64) { - uint64_t k = kfold_int64arith(ir_k64(irk)->u64, - ir_k64(fright)->u64, (IROp)fins->o); - PHIBARRIER(fleft); - fins->op1 = fleft->op1; - fins->op2 = (IRRef1)lj_ir_kint64(J, k); - return RETRYFOLD; /* (i o k1) o k2 ==> i o (k1 o k2) */ - } - return NEXTFOLD; -#else - UNUSED(J); lua_assert(0); return FAILFOLD; -#endif -} - -LJFOLD(MIN MIN any) -LJFOLD(MAX MAX any) -LJFOLD(BAND BAND any) -LJFOLD(BOR BOR any) -LJFOLDF(reassoc_dup) -{ - if (fins->op2 == fleft->op1 || fins->op2 == fleft->op2) - return LEFTFOLD; /* (a o b) o a ==> a o b; (a o b) o b ==> a o b */ - return NEXTFOLD; -} - -LJFOLD(BXOR BXOR any) -LJFOLDF(reassoc_bxor) -{ - PHIBARRIER(fleft); - if (fins->op2 == fleft->op1) /* (a xor b) xor a ==> b */ - return fleft->op2; - if (fins->op2 == fleft->op2) /* (a xor b) xor b ==> a */ - return fleft->op1; - return NEXTFOLD; -} - -LJFOLD(BSHL BSHL KINT) -LJFOLD(BSHR BSHR KINT) -LJFOLD(BSAR BSAR KINT) -LJFOLD(BROL BROL KINT) -LJFOLD(BROR BROR KINT) -LJFOLDF(reassoc_shift) -{ - IRIns *irk = IR(fleft->op2); - PHIBARRIER(fleft); /* The (shift any KINT) rule covers k2 == 0 and more. */ - if (irk->o == IR_KINT) { /* (i o k1) o k2 ==> i o (k1 + k2) */ - int32_t mask = irt_is64(fins->t) ? 63 : 31; - int32_t k = (irk->i & mask) + (fright->i & mask); - if (k > mask) { /* Combined shift too wide? */ - if (fins->o == IR_BSHL || fins->o == IR_BSHR) - return mask == 31 ? INTFOLD(0) : INT64FOLD(0); - else if (fins->o == IR_BSAR) - k = mask; - else - k &= mask; - } - fins->op1 = fleft->op1; - fins->op2 = (IRRef1)lj_ir_kint(J, k); - return RETRYFOLD; - } - return NEXTFOLD; -} - -LJFOLD(MIN MIN KNUM) -LJFOLD(MAX MAX KNUM) -LJFOLD(MIN MIN KINT) -LJFOLD(MAX MAX KINT) -LJFOLDF(reassoc_minmax_k) -{ - IRIns *irk = IR(fleft->op2); - if (irk->o == IR_KNUM) { - lua_Number a = ir_knum(irk)->n; - lua_Number y = lj_vm_foldarith(a, knumright, fins->o - IR_ADD); - if (a == y) /* (x o k1) o k2 ==> x o k1, if (k1 o k2) == k1. */ - return LEFTFOLD; - PHIBARRIER(fleft); - fins->op1 = fleft->op1; - fins->op2 = (IRRef1)lj_ir_knum(J, y); - return RETRYFOLD; /* (x o k1) o k2 ==> x o (k1 o k2) */ - } else if (irk->o == IR_KINT) { - int32_t a = irk->i; - int32_t y = kfold_intop(a, fright->i, fins->o); - if (a == y) /* (x o k1) o k2 ==> x o k1, if (k1 o k2) == k1. */ - return LEFTFOLD; - PHIBARRIER(fleft); - fins->op1 = fleft->op1; - fins->op2 = (IRRef1)lj_ir_kint(J, y); - return RETRYFOLD; /* (x o k1) o k2 ==> x o (k1 o k2) */ - } - return NEXTFOLD; -} - -LJFOLD(MIN MAX any) -LJFOLD(MAX MIN any) -LJFOLDF(reassoc_minmax_left) -{ - if (fins->op2 == fleft->op1 || fins->op2 == fleft->op2) - return RIGHTFOLD; /* (b o1 a) o2 b ==> b; (a o1 b) o2 b ==> b */ - return NEXTFOLD; -} - -LJFOLD(MIN any MAX) -LJFOLD(MAX any MIN) -LJFOLDF(reassoc_minmax_right) -{ - if (fins->op1 == fright->op1 || fins->op1 == fright->op2) - return LEFTFOLD; /* a o2 (a o1 b) ==> a; a o2 (b o1 a) ==> a */ - return NEXTFOLD; -} - -/* -- Array bounds check elimination -------------------------------------- */ - -/* Eliminate ABC across PHIs to handle t[i-1] forwarding case. -** ABC(asize, (i+k)+(-k)) ==> ABC(asize, i), but only if it already exists. -** Could be generalized to (i+k1)+k2 ==> i+(k1+k2), but needs better disambig. -*/ -LJFOLD(ABC any ADD) -LJFOLDF(abc_fwd) -{ - if (LJ_LIKELY(J->flags & JIT_F_OPT_ABC)) { - if (irref_isk(fright->op2)) { - IRIns *add2 = IR(fright->op1); - if (add2->o == IR_ADD && irref_isk(add2->op2) && - IR(fright->op2)->i == -IR(add2->op2)->i) { - IRRef ref = J->chain[IR_ABC]; - IRRef lim = add2->op1; - if (fins->op1 > lim) lim = fins->op1; - while (ref > lim) { - IRIns *ir = IR(ref); - if (ir->op1 == fins->op1 && ir->op2 == add2->op1) - return DROPFOLD; - ref = ir->prev; - } - } - } - } - return NEXTFOLD; -} - -/* Eliminate ABC for constants. -** ABC(asize, k1), ABC(asize k2) ==> ABC(asize, max(k1, k2)) -** Drop second ABC if k2 is lower. Otherwise patch first ABC with k2. -*/ -LJFOLD(ABC any KINT) -LJFOLDF(abc_k) -{ - if (LJ_LIKELY(J->flags & JIT_F_OPT_ABC)) { - IRRef ref = J->chain[IR_ABC]; - IRRef asize = fins->op1; - while (ref > asize) { - IRIns *ir = IR(ref); - if (ir->op1 == asize && irref_isk(ir->op2)) { - int32_t k = IR(ir->op2)->i; - if (fright->i > k) - ir->op2 = fins->op2; - return DROPFOLD; - } - ref = ir->prev; - } - return EMITFOLD; /* Already performed CSE. */ - } - return NEXTFOLD; -} - -/* Eliminate invariant ABC inside loop. */ -LJFOLD(ABC any any) -LJFOLDF(abc_invar) -{ - /* Invariant ABC marked as PTR. Drop if op1 is invariant, too. */ - if (!irt_isint(fins->t) && fins->op1 < J->chain[IR_LOOP] && - !irt_isphi(IR(fins->op1)->t)) - return DROPFOLD; - return NEXTFOLD; -} - -/* -- Commutativity ------------------------------------------------------- */ - -/* The refs of commutative ops are canonicalized. Lower refs go to the right. -** Rationale behind this: -** - It (also) moves constants to the right. -** - It reduces the number of FOLD rules (e.g. (BOR any KINT) suffices). -** - It helps CSE to find more matches. -** - The assembler generates better code with constants at the right. -*/ - -LJFOLD(ADD any any) -LJFOLD(MUL any any) -LJFOLD(ADDOV any any) -LJFOLD(MULOV any any) -LJFOLDF(comm_swap) -{ - if (fins->op1 < fins->op2) { /* Move lower ref to the right. */ - IRRef1 tmp = fins->op1; - fins->op1 = fins->op2; - fins->op2 = tmp; - return RETRYFOLD; - } - return NEXTFOLD; -} - -LJFOLD(EQ any any) -LJFOLD(NE any any) -LJFOLDF(comm_equal) -{ - /* For non-numbers only: x == x ==> drop; x ~= x ==> fail */ - if (fins->op1 == fins->op2 && !irt_isnum(fins->t)) - return CONDFOLD(fins->o == IR_EQ); - return fold_comm_swap(J); -} - -LJFOLD(LT any any) -LJFOLD(GE any any) -LJFOLD(LE any any) -LJFOLD(GT any any) -LJFOLD(ULT any any) -LJFOLD(UGE any any) -LJFOLD(ULE any any) -LJFOLD(UGT any any) -LJFOLDF(comm_comp) -{ - /* For non-numbers only: x <=> x ==> drop; x <> x ==> fail */ - if (fins->op1 == fins->op2 && !irt_isnum(fins->t)) - return CONDFOLD((fins->o ^ (fins->o >> 1)) & 1); - if (fins->op1 < fins->op2) { /* Move lower ref to the right. */ - IRRef1 tmp = fins->op1; - fins->op1 = fins->op2; - fins->op2 = tmp; - fins->o ^= 3; /* GT <-> LT, GE <-> LE, does not affect U */ - return RETRYFOLD; - } - return NEXTFOLD; -} - -LJFOLD(BAND any any) -LJFOLD(BOR any any) -LJFOLD(MIN any any) -LJFOLD(MAX any any) -LJFOLDF(comm_dup) -{ - if (fins->op1 == fins->op2) /* x o x ==> x */ - return LEFTFOLD; - return fold_comm_swap(J); -} - -LJFOLD(BXOR any any) -LJFOLDF(comm_bxor) -{ - if (fins->op1 == fins->op2) /* i xor i ==> 0 */ - return irt_is64(fins->t) ? INT64FOLD(0) : INTFOLD(0); - return fold_comm_swap(J); -} - -/* -- Simplification of compound expressions ------------------------------ */ - -static TRef kfold_xload(jit_State *J, IRIns *ir, const void *p) -{ - int32_t k; - switch (irt_type(ir->t)) { - case IRT_NUM: return lj_ir_knum_u64(J, *(uint64_t *)p); - case IRT_I8: k = (int32_t)*(int8_t *)p; break; - case IRT_U8: k = (int32_t)*(uint8_t *)p; break; - case IRT_I16: k = (int32_t)(int16_t)lj_getu16(p); break; - case IRT_U16: k = (int32_t)(uint16_t)lj_getu16(p); break; - case IRT_INT: case IRT_U32: k = (int32_t)lj_getu32(p); break; - case IRT_I64: case IRT_U64: return lj_ir_kint64(J, *(uint64_t *)p); - default: return 0; - } - return lj_ir_kint(J, k); -} - -/* Turn: string.sub(str, a, b) == kstr -** into: string.byte(str, a) == string.byte(kstr, 1) etc. -** Note: this creates unaligned XLOADs on x86/x64. -*/ -LJFOLD(EQ SNEW KGC) -LJFOLD(NE SNEW KGC) -LJFOLDF(merge_eqne_snew_kgc) -{ - GCstr *kstr = ir_kstr(fright); - int32_t len = (int32_t)kstr->len; - lua_assert(irt_isstr(fins->t)); - -#if LJ_TARGET_UNALIGNED -#define FOLD_SNEW_MAX_LEN 4 /* Handle string lengths 0, 1, 2, 3, 4. */ -#define FOLD_SNEW_TYPE8 IRT_I8 /* Creates shorter immediates. */ -#else -#define FOLD_SNEW_MAX_LEN 1 /* Handle string lengths 0 or 1. */ -#define FOLD_SNEW_TYPE8 IRT_U8 /* Prefer unsigned loads. */ -#endif - - PHIBARRIER(fleft); - if (len <= FOLD_SNEW_MAX_LEN) { - IROp op = (IROp)fins->o; - IRRef strref = fleft->op1; - if (IR(strref)->o != IR_STRREF) - return NEXTFOLD; - if (op == IR_EQ) { - emitir(IRTGI(IR_EQ), fleft->op2, lj_ir_kint(J, len)); - /* Caveat: fins/fleft/fright is no longer valid after emitir. */ - } else { - /* NE is not expanded since this would need an OR of two conds. */ - if (!irref_isk(fleft->op2)) /* Only handle the constant length case. */ - return NEXTFOLD; - if (IR(fleft->op2)->i != len) - return DROPFOLD; - } - if (len > 0) { - /* A 4 byte load for length 3 is ok -- all strings have an extra NUL. */ - uint16_t ot = (uint16_t)(len == 1 ? IRT(IR_XLOAD, FOLD_SNEW_TYPE8) : - len == 2 ? IRT(IR_XLOAD, IRT_U16) : - IRTI(IR_XLOAD)); - TRef tmp = emitir(ot, strref, - IRXLOAD_READONLY | (len > 1 ? IRXLOAD_UNALIGNED : 0)); - TRef val = kfold_xload(J, IR(tref_ref(tmp)), strdata(kstr)); - if (len == 3) - tmp = emitir(IRTI(IR_BAND), tmp, - lj_ir_kint(J, LJ_ENDIAN_SELECT(0x00ffffff, 0xffffff00))); - fins->op1 = (IRRef1)tmp; - fins->op2 = (IRRef1)val; - fins->ot = (IROpT)IRTGI(op); - return RETRYFOLD; - } else { - return DROPFOLD; - } - } - return NEXTFOLD; -} - -/* -- Loads --------------------------------------------------------------- */ - -/* Loads cannot be folded or passed on to CSE in general. -** Alias analysis is needed to check for forwarding opportunities. -** -** Caveat: *all* loads must be listed here or they end up at CSE! -*/ - -LJFOLD(ALOAD any) -LJFOLDX(lj_opt_fwd_aload) - -/* From HREF fwd (see below). Must eliminate, not supported by fwd/backend. */ -LJFOLD(HLOAD KKPTR) -LJFOLDF(kfold_hload_kkptr) -{ - UNUSED(J); - lua_assert(ir_kptr(fleft) == niltvg(J2G(J))); - return TREF_NIL; -} - -LJFOLD(HLOAD any) -LJFOLDX(lj_opt_fwd_hload) - -LJFOLD(ULOAD any) -LJFOLDX(lj_opt_fwd_uload) - -LJFOLD(CALLL any IRCALL_lj_tab_len) -LJFOLDX(lj_opt_fwd_tab_len) - -/* Upvalue refs are really loads, but there are no corresponding stores. -** So CSE is ok for them, except for UREFO across a GC step (see below). -** If the referenced function is const, its upvalue addresses are const, too. -** This can be used to improve CSE by looking for the same address, -** even if the upvalues originate from a different function. -*/ -LJFOLD(UREFO KGC any) -LJFOLD(UREFC KGC any) -LJFOLDF(cse_uref) -{ - if (LJ_LIKELY(J->flags & JIT_F_OPT_CSE)) { - IRRef ref = J->chain[fins->o]; - GCfunc *fn = ir_kfunc(fleft); - GCupval *uv = gco2uv(gcref(fn->l.uvptr[(fins->op2 >> 8)])); - while (ref > 0) { - IRIns *ir = IR(ref); - if (irref_isk(ir->op1)) { - GCfunc *fn2 = ir_kfunc(IR(ir->op1)); - if (gco2uv(gcref(fn2->l.uvptr[(ir->op2 >> 8)])) == uv) { - if (fins->o == IR_UREFO && gcstep_barrier(J, ref)) - break; - return ref; - } - } - ref = ir->prev; - } - } - return EMITFOLD; -} - -LJFOLD(HREFK any any) -LJFOLDX(lj_opt_fwd_hrefk) - -LJFOLD(HREF TNEW any) -LJFOLDF(fwd_href_tnew) -{ - if (lj_opt_fwd_href_nokey(J)) - return lj_ir_kkptr(J, niltvg(J2G(J))); - return NEXTFOLD; -} - -LJFOLD(HREF TDUP KPRI) -LJFOLD(HREF TDUP KGC) -LJFOLD(HREF TDUP KNUM) -LJFOLDF(fwd_href_tdup) -{ - TValue keyv; - lj_ir_kvalue(J->L, &keyv, fright); - if (lj_tab_get(J->L, ir_ktab(IR(fleft->op1)), &keyv) == niltvg(J2G(J)) && - lj_opt_fwd_href_nokey(J)) - return lj_ir_kkptr(J, niltvg(J2G(J))); - return NEXTFOLD; -} - -/* We can safely FOLD/CSE array/hash refs and field loads, since there -** are no corresponding stores. But we need to check for any NEWREF with -** an aliased table, as it may invalidate all of the pointers and fields. -** Only HREF needs the NEWREF check -- AREF and HREFK already depend on -** FLOADs. And NEWREF itself is treated like a store (see below). -** LREF is constant (per trace) since coroutine switches are not inlined. -*/ -LJFOLD(FLOAD TNEW IRFL_TAB_ASIZE) -LJFOLDF(fload_tab_tnew_asize) -{ - if (LJ_LIKELY(J->flags & JIT_F_OPT_FOLD) && lj_opt_fwd_tptr(J, fins->op1)) - return INTFOLD(fleft->op1); - return NEXTFOLD; -} - -LJFOLD(FLOAD TNEW IRFL_TAB_HMASK) -LJFOLDF(fload_tab_tnew_hmask) -{ - if (LJ_LIKELY(J->flags & JIT_F_OPT_FOLD) && lj_opt_fwd_tptr(J, fins->op1)) - return INTFOLD((1 << fleft->op2)-1); - return NEXTFOLD; -} - -LJFOLD(FLOAD TDUP IRFL_TAB_ASIZE) -LJFOLDF(fload_tab_tdup_asize) -{ - if (LJ_LIKELY(J->flags & JIT_F_OPT_FOLD) && lj_opt_fwd_tptr(J, fins->op1)) - return INTFOLD((int32_t)ir_ktab(IR(fleft->op1))->asize); - return NEXTFOLD; -} - -LJFOLD(FLOAD TDUP IRFL_TAB_HMASK) -LJFOLDF(fload_tab_tdup_hmask) -{ - if (LJ_LIKELY(J->flags & JIT_F_OPT_FOLD) && lj_opt_fwd_tptr(J, fins->op1)) - return INTFOLD((int32_t)ir_ktab(IR(fleft->op1))->hmask); - return NEXTFOLD; -} - -LJFOLD(HREF any any) -LJFOLD(FLOAD any IRFL_TAB_ARRAY) -LJFOLD(FLOAD any IRFL_TAB_NODE) -LJFOLD(FLOAD any IRFL_TAB_ASIZE) -LJFOLD(FLOAD any IRFL_TAB_HMASK) -LJFOLDF(fload_tab_ah) -{ - TRef tr = lj_opt_cse(J); - return lj_opt_fwd_tptr(J, tref_ref(tr)) ? tr : EMITFOLD; -} - -/* Strings are immutable, so we can safely FOLD/CSE the related FLOAD. */ -LJFOLD(FLOAD KGC IRFL_STR_LEN) -LJFOLDF(fload_str_len_kgc) -{ - if (LJ_LIKELY(J->flags & JIT_F_OPT_FOLD)) - return INTFOLD((int32_t)ir_kstr(fleft)->len); - return NEXTFOLD; -} - -LJFOLD(FLOAD SNEW IRFL_STR_LEN) -LJFOLDF(fload_str_len_snew) -{ - if (LJ_LIKELY(J->flags & JIT_F_OPT_FOLD)) { - PHIBARRIER(fleft); - return fleft->op2; - } - return NEXTFOLD; -} - -LJFOLD(FLOAD TOSTR IRFL_STR_LEN) -LJFOLDF(fload_str_len_tostr) -{ - if (LJ_LIKELY(J->flags & JIT_F_OPT_FOLD) && fleft->op2 == IRTOSTR_CHAR) - return INTFOLD(1); - return NEXTFOLD; -} - -/* The C type ID of cdata objects is immutable. */ -LJFOLD(FLOAD KGC IRFL_CDATA_CTYPEID) -LJFOLDF(fload_cdata_typeid_kgc) -{ - if (LJ_LIKELY(J->flags & JIT_F_OPT_FOLD)) - return INTFOLD((int32_t)ir_kcdata(fleft)->ctypeid); - return NEXTFOLD; -} - -/* Get the contents of immutable cdata objects. */ -LJFOLD(FLOAD KGC IRFL_CDATA_PTR) -LJFOLD(FLOAD KGC IRFL_CDATA_INT) -LJFOLD(FLOAD KGC IRFL_CDATA_INT64) -LJFOLDF(fload_cdata_int64_kgc) -{ - if (LJ_LIKELY(J->flags & JIT_F_OPT_FOLD)) { - void *p = cdataptr(ir_kcdata(fleft)); - if (irt_is64(fins->t)) - return INT64FOLD(*(uint64_t *)p); - else - return INTFOLD(*(int32_t *)p); - } - return NEXTFOLD; -} - -LJFOLD(FLOAD CNEW IRFL_CDATA_CTYPEID) -LJFOLD(FLOAD CNEWI IRFL_CDATA_CTYPEID) -LJFOLDF(fload_cdata_typeid_cnew) -{ - if (LJ_LIKELY(J->flags & JIT_F_OPT_FOLD)) - return fleft->op1; /* No PHI barrier needed. CNEW/CNEWI op1 is const. */ - return NEXTFOLD; -} - -/* Pointer, int and int64 cdata objects are immutable. */ -LJFOLD(FLOAD CNEWI IRFL_CDATA_PTR) -LJFOLD(FLOAD CNEWI IRFL_CDATA_INT) -LJFOLD(FLOAD CNEWI IRFL_CDATA_INT64) -LJFOLDF(fload_cdata_ptr_int64_cnew) -{ - if (LJ_LIKELY(J->flags & JIT_F_OPT_FOLD)) - return fleft->op2; /* Fold even across PHI to avoid allocations. */ - return NEXTFOLD; -} - -LJFOLD(FLOAD any IRFL_STR_LEN) -LJFOLD(FLOAD any IRFL_FUNC_ENV) -LJFOLD(FLOAD any IRFL_THREAD_ENV) -LJFOLD(FLOAD any IRFL_CDATA_CTYPEID) -LJFOLD(FLOAD any IRFL_CDATA_PTR) -LJFOLD(FLOAD any IRFL_CDATA_INT) -LJFOLD(FLOAD any IRFL_CDATA_INT64) -LJFOLD(VLOAD any any) /* Vararg loads have no corresponding stores. */ -LJFOLDX(lj_opt_cse) - -/* All other field loads need alias analysis. */ -LJFOLD(FLOAD any any) -LJFOLDX(lj_opt_fwd_fload) - -/* This is for LOOP only. Recording handles SLOADs internally. */ -LJFOLD(SLOAD any any) -LJFOLDF(fwd_sload) -{ - if ((fins->op2 & IRSLOAD_FRAME)) { - TRef tr = lj_opt_cse(J); - return tref_ref(tr) < J->chain[IR_RETF] ? EMITFOLD : tr; - } else { - lua_assert(J->slot[fins->op1] != 0); - return J->slot[fins->op1]; - } -} - -/* Only fold for KKPTR. The pointer _and_ the contents must be const. */ -LJFOLD(XLOAD KKPTR any) -LJFOLDF(xload_kptr) -{ - TRef tr = kfold_xload(J, fins, ir_kptr(fleft)); - return tr ? tr : NEXTFOLD; -} - -LJFOLD(XLOAD any any) -LJFOLDX(lj_opt_fwd_xload) - -/* -- Write barriers ------------------------------------------------------ */ - -/* Write barriers are amenable to CSE, but not across any incremental -** GC steps. -** -** The same logic applies to open upvalue references, because a stack -** may be resized during a GC step (not the current stack, but maybe that -** of a coroutine). -*/ -LJFOLD(TBAR any) -LJFOLD(OBAR any any) -LJFOLD(UREFO any any) -LJFOLDF(barrier_tab) -{ - TRef tr = lj_opt_cse(J); - if (gcstep_barrier(J, tref_ref(tr))) /* CSE across GC step? */ - return EMITFOLD; /* Raw emit. Assumes fins is left intact by CSE. */ - return tr; -} - -LJFOLD(TBAR TNEW) -LJFOLD(TBAR TDUP) -LJFOLDF(barrier_tnew_tdup) -{ - /* New tables are always white and never need a barrier. */ - if (fins->op1 < J->chain[IR_LOOP]) /* Except across a GC step. */ - return NEXTFOLD; - return DROPFOLD; -} - -/* -- Profiling ----------------------------------------------------------- */ - -LJFOLD(PROF any any) -LJFOLDF(prof) -{ - IRRef ref = J->chain[IR_PROF]; - if (ref+1 == J->cur.nins) /* Drop neighbouring IR_PROF. */ - return ref; - return EMITFOLD; -} - -/* -- Stores and allocations ---------------------------------------------- */ - -/* Stores and allocations cannot be folded or passed on to CSE in general. -** But some stores can be eliminated with dead-store elimination (DSE). -** -** Caveat: *all* stores and allocs must be listed here or they end up at CSE! -*/ - -LJFOLD(ASTORE any any) -LJFOLD(HSTORE any any) -LJFOLDX(lj_opt_dse_ahstore) - -LJFOLD(USTORE any any) -LJFOLDX(lj_opt_dse_ustore) - -LJFOLD(FSTORE any any) -LJFOLDX(lj_opt_dse_fstore) - -LJFOLD(XSTORE any any) -LJFOLDX(lj_opt_dse_xstore) - -LJFOLD(NEWREF any any) /* Treated like a store. */ -LJFOLD(CALLA any any) -LJFOLD(CALLL any any) /* Safeguard fallback. */ -LJFOLD(CALLS any any) -LJFOLD(CALLXS any any) -LJFOLD(XBAR) -LJFOLD(RETF any any) /* Modifies BASE. */ -LJFOLD(TNEW any any) -LJFOLD(TDUP any) -LJFOLD(CNEW any any) -LJFOLD(XSNEW any any) -LJFOLD(BUFHDR any any) -LJFOLDX(lj_ir_emit) - -/* ------------------------------------------------------------------------ */ - -/* Every entry in the generated hash table is a 32 bit pattern: -** -** xxxxxxxx iiiiiii lllllll rrrrrrrrrr -** -** xxxxxxxx = 8 bit index into fold function table -** iiiiiii = 7 bit folded instruction opcode -** lllllll = 7 bit left instruction opcode -** rrrrrrrrrr = 8 bit right instruction opcode or 10 bits from literal field -*/ - -#include "lj_folddef.h" - -/* ------------------------------------------------------------------------ */ - -/* Fold IR instruction. */ -TRef LJ_FASTCALL lj_opt_fold(jit_State *J) -{ - uint32_t key, any; - IRRef ref; - - if (LJ_UNLIKELY((J->flags & JIT_F_OPT_MASK) != JIT_F_OPT_DEFAULT)) { - lua_assert(((JIT_F_OPT_FOLD|JIT_F_OPT_FWD|JIT_F_OPT_CSE|JIT_F_OPT_DSE) | - JIT_F_OPT_DEFAULT) == JIT_F_OPT_DEFAULT); - /* Folding disabled? Chain to CSE, but not for loads/stores/allocs. */ - if (!(J->flags & JIT_F_OPT_FOLD) && irm_kind(lj_ir_mode[fins->o]) == IRM_N) - return lj_opt_cse(J); - - /* No FOLD, forwarding or CSE? Emit raw IR for loads, except for SLOAD. */ - if ((J->flags & (JIT_F_OPT_FOLD|JIT_F_OPT_FWD|JIT_F_OPT_CSE)) != - (JIT_F_OPT_FOLD|JIT_F_OPT_FWD|JIT_F_OPT_CSE) && - irm_kind(lj_ir_mode[fins->o]) == IRM_L && fins->o != IR_SLOAD) - return lj_ir_emit(J); - - /* No FOLD or DSE? Emit raw IR for stores. */ - if ((J->flags & (JIT_F_OPT_FOLD|JIT_F_OPT_DSE)) != - (JIT_F_OPT_FOLD|JIT_F_OPT_DSE) && - irm_kind(lj_ir_mode[fins->o]) == IRM_S) - return lj_ir_emit(J); - } - - /* Fold engine start/retry point. */ -retry: - /* Construct key from opcode and operand opcodes (unless literal/none). */ - key = ((uint32_t)fins->o << 17); - if (fins->op1 >= J->cur.nk) { - key += (uint32_t)IR(fins->op1)->o << 10; - *fleft = *IR(fins->op1); - if (fins->op1 < REF_TRUE) - fleft[1] = IR(fins->op1)[1]; - } - if (fins->op2 >= J->cur.nk) { - key += (uint32_t)IR(fins->op2)->o; - *fright = *IR(fins->op2); - if (fins->op2 < REF_TRUE) - fright[1] = IR(fins->op2)[1]; - } else { - key += (fins->op2 & 0x3ffu); /* Literal mask. Must include IRCONV_*MASK. */ - } - - /* Check for a match in order from most specific to least specific. */ - any = 0; - for (;;) { - uint32_t k = key | (any & 0x1ffff); - uint32_t h = fold_hashkey(k); - uint32_t fh = fold_hash[h]; /* Lookup key in semi-perfect hash table. */ - if ((fh & 0xffffff) == k || (fh = fold_hash[h+1], (fh & 0xffffff) == k)) { - ref = (IRRef)tref_ref(fold_func[fh >> 24](J)); - if (ref != NEXTFOLD) - break; - } - if (any == 0xfffff) /* Exhausted folding. Pass on to CSE. */ - return lj_opt_cse(J); - any = (any | (any >> 10)) ^ 0xffc00; - } - - /* Return value processing, ordered by frequency. */ - if (LJ_LIKELY(ref >= MAX_FOLD)) - return TREF(ref, irt_t(IR(ref)->t)); - if (ref == RETRYFOLD) - goto retry; - if (ref == KINTFOLD) - return lj_ir_kint(J, fins->i); - if (ref == FAILFOLD) - lj_trace_err(J, LJ_TRERR_GFAIL); - lua_assert(ref == DROPFOLD); - return REF_DROP; -} - -/* -- Common-Subexpression Elimination ------------------------------------ */ - -/* CSE an IR instruction. This is very fast due to the skip-list chains. */ -TRef LJ_FASTCALL lj_opt_cse(jit_State *J) -{ - /* Avoid narrow to wide store-to-load forwarding stall */ - IRRef2 op12 = (IRRef2)fins->op1 + ((IRRef2)fins->op2 << 16); - IROp op = fins->o; - if (LJ_LIKELY(J->flags & JIT_F_OPT_CSE)) { - /* Limited search for same operands in per-opcode chain. */ - IRRef ref = J->chain[op]; - IRRef lim = fins->op1; - if (fins->op2 > lim) lim = fins->op2; /* Relies on lit < REF_BIAS. */ - while (ref > lim) { - if (IR(ref)->op12 == op12) - return TREF(ref, irt_t(IR(ref)->t)); /* Common subexpression found. */ - ref = IR(ref)->prev; - } - } - /* Otherwise emit IR (inlined for speed). */ - { - IRRef ref = lj_ir_nextins(J); - IRIns *ir = IR(ref); - ir->prev = J->chain[op]; - ir->op12 = op12; - J->chain[op] = (IRRef1)ref; - ir->o = fins->o; - J->guardemit.irt |= fins->t.irt; - return TREF(ref, irt_t((ir->t = fins->t))); - } -} - -/* CSE with explicit search limit. */ -TRef LJ_FASTCALL lj_opt_cselim(jit_State *J, IRRef lim) -{ - IRRef ref = J->chain[fins->o]; - IRRef2 op12 = (IRRef2)fins->op1 + ((IRRef2)fins->op2 << 16); - while (ref > lim) { - if (IR(ref)->op12 == op12) - return ref; - ref = IR(ref)->prev; - } - return lj_ir_emit(J); -} - -/* ------------------------------------------------------------------------ */ - -#undef IR -#undef fins -#undef fleft -#undef fright -#undef knumleft -#undef knumright -#undef emitir - -#endif diff --git a/lib/LuaJIT/src/lj_opt_loop.c b/lib/LuaJIT/src/lj_opt_loop.c deleted file mode 100644 index 441b8ad..0000000 --- a/lib/LuaJIT/src/lj_opt_loop.c +++ /dev/null @@ -1,449 +0,0 @@ -/* -** LOOP: Loop Optimizations. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_opt_loop_c -#define LUA_CORE - -#include "lj_obj.h" - -#if LJ_HASJIT - -#include "lj_err.h" -#include "lj_buf.h" -#include "lj_ir.h" -#include "lj_jit.h" -#include "lj_iropt.h" -#include "lj_trace.h" -#include "lj_snap.h" -#include "lj_vm.h" - -/* Loop optimization: -** -** Traditional Loop-Invariant Code Motion (LICM) splits the instructions -** of a loop into invariant and variant instructions. The invariant -** instructions are hoisted out of the loop and only the variant -** instructions remain inside the loop body. -** -** Unfortunately LICM is mostly useless for compiling dynamic languages. -** The IR has many guards and most of the subsequent instructions are -** control-dependent on them. The first non-hoistable guard would -** effectively prevent hoisting of all subsequent instructions. -** -** That's why we use a special form of unrolling using copy-substitution, -** combined with redundancy elimination: -** -** The recorded instruction stream is re-emitted to the compiler pipeline -** with substituted operands. The substitution table is filled with the -** refs returned by re-emitting each instruction. This can be done -** on-the-fly, because the IR is in strict SSA form, where every ref is -** defined before its use. -** -** This aproach generates two code sections, separated by the LOOP -** instruction: -** -** 1. The recorded instructions form a kind of pre-roll for the loop. It -** contains a mix of invariant and variant instructions and performs -** exactly one loop iteration (but not necessarily the 1st iteration). -** -** 2. The loop body contains only the variant instructions and performs -** all remaining loop iterations. -** -** On first sight that looks like a waste of space, because the variant -** instructions are present twice. But the key insight is that the -** pre-roll honors the control-dependencies for *both* the pre-roll itself -** *and* the loop body! -** -** It also means one doesn't have to explicitly model control-dependencies -** (which, BTW, wouldn't help LICM much). And it's much easier to -** integrate sparse snapshotting with this approach. -** -** One of the nicest aspects of this approach is that all of the -** optimizations of the compiler pipeline (FOLD, CSE, FWD, etc.) can be -** reused with only minor restrictions (e.g. one should not fold -** instructions across loop-carried dependencies). -** -** But in general all optimizations can be applied which only need to look -** backwards into the generated instruction stream. At any point in time -** during the copy-substitution process this contains both a static loop -** iteration (the pre-roll) and a dynamic one (from the to-be-copied -** instruction up to the end of the partial loop body). -** -** Since control-dependencies are implicitly kept, CSE also applies to all -** kinds of guards. The major advantage is that all invariant guards can -** be hoisted, too. -** -** Load/store forwarding works across loop iterations, too. This is -** important if loop-carried dependencies are kept in upvalues or tables. -** E.g. 'self.idx = self.idx + 1' deep down in some OO-style method may -** become a forwarded loop-recurrence after inlining. -** -** Since the IR is in SSA form, loop-carried dependencies have to be -** modeled with PHI instructions. The potential candidates for PHIs are -** collected on-the-fly during copy-substitution. After eliminating the -** redundant ones, PHI instructions are emitted *below* the loop body. -** -** Note that this departure from traditional SSA form doesn't change the -** semantics of the PHI instructions themselves. But it greatly simplifies -** on-the-fly generation of the IR and the machine code. -*/ - -/* Some local macros to save typing. Undef'd at the end. */ -#define IR(ref) (&J->cur.ir[(ref)]) - -/* Pass IR on to next optimization in chain (FOLD). */ -#define emitir(ot, a, b) (lj_ir_set(J, (ot), (a), (b)), lj_opt_fold(J)) - -/* Emit raw IR without passing through optimizations. */ -#define emitir_raw(ot, a, b) (lj_ir_set(J, (ot), (a), (b)), lj_ir_emit(J)) - -/* -- PHI elimination ----------------------------------------------------- */ - -/* Emit or eliminate collected PHIs. */ -static void loop_emit_phi(jit_State *J, IRRef1 *subst, IRRef1 *phi, IRRef nphi, - SnapNo onsnap) -{ - int passx = 0; - IRRef i, j, nslots; - IRRef invar = J->chain[IR_LOOP]; - /* Pass #1: mark redundant and potentially redundant PHIs. */ - for (i = 0, j = 0; i < nphi; i++) { - IRRef lref = phi[i]; - IRRef rref = subst[lref]; - if (lref == rref || rref == REF_DROP) { /* Invariants are redundant. */ - irt_clearphi(IR(lref)->t); - } else { - phi[j++] = (IRRef1)lref; - if (!(IR(rref)->op1 == lref || IR(rref)->op2 == lref)) { - /* Quick check for simple recurrences failed, need pass2. */ - irt_setmark(IR(lref)->t); - passx = 1; - } - } - } - nphi = j; - /* Pass #2: traverse variant part and clear marks of non-redundant PHIs. */ - if (passx) { - SnapNo s; - for (i = J->cur.nins-1; i > invar; i--) { - IRIns *ir = IR(i); - if (!irref_isk(ir->op2)) irt_clearmark(IR(ir->op2)->t); - if (!irref_isk(ir->op1)) { - irt_clearmark(IR(ir->op1)->t); - if (ir->op1 < invar && - ir->o >= IR_CALLN && ir->o <= IR_CARG) { /* ORDER IR */ - ir = IR(ir->op1); - while (ir->o == IR_CARG) { - if (!irref_isk(ir->op2)) irt_clearmark(IR(ir->op2)->t); - if (irref_isk(ir->op1)) break; - ir = IR(ir->op1); - irt_clearmark(ir->t); - } - } - } - } - for (s = J->cur.nsnap-1; s >= onsnap; s--) { - SnapShot *snap = &J->cur.snap[s]; - SnapEntry *map = &J->cur.snapmap[snap->mapofs]; - MSize n, nent = snap->nent; - for (n = 0; n < nent; n++) { - IRRef ref = snap_ref(map[n]); - if (!irref_isk(ref)) irt_clearmark(IR(ref)->t); - } - } - } - /* Pass #3: add PHIs for variant slots without a corresponding SLOAD. */ - nslots = J->baseslot+J->maxslot; - for (i = 1; i < nslots; i++) { - IRRef ref = tref_ref(J->slot[i]); - while (!irref_isk(ref) && ref != subst[ref]) { - IRIns *ir = IR(ref); - irt_clearmark(ir->t); /* Unmark potential uses, too. */ - if (irt_isphi(ir->t) || irt_ispri(ir->t)) - break; - irt_setphi(ir->t); - if (nphi >= LJ_MAX_PHI) - lj_trace_err(J, LJ_TRERR_PHIOV); - phi[nphi++] = (IRRef1)ref; - ref = subst[ref]; - if (ref > invar) - break; - } - } - /* Pass #4: propagate non-redundant PHIs. */ - while (passx) { - passx = 0; - for (i = 0; i < nphi; i++) { - IRRef lref = phi[i]; - IRIns *ir = IR(lref); - if (!irt_ismarked(ir->t)) { /* Propagate only from unmarked PHIs. */ - IRIns *irr = IR(subst[lref]); - if (irt_ismarked(irr->t)) { /* Right ref points to other PHI? */ - irt_clearmark(irr->t); /* Mark that PHI as non-redundant. */ - passx = 1; /* Retry. */ - } - } - } - } - /* Pass #5: emit PHI instructions or eliminate PHIs. */ - for (i = 0; i < nphi; i++) { - IRRef lref = phi[i]; - IRIns *ir = IR(lref); - if (!irt_ismarked(ir->t)) { /* Emit PHI if not marked. */ - IRRef rref = subst[lref]; - if (rref > invar) - irt_setphi(IR(rref)->t); - emitir_raw(IRT(IR_PHI, irt_type(ir->t)), lref, rref); - } else { /* Otherwise eliminate PHI. */ - irt_clearmark(ir->t); - irt_clearphi(ir->t); - } - } -} - -/* -- Loop unrolling using copy-substitution ------------------------------ */ - -/* Copy-substitute snapshot. */ -static void loop_subst_snap(jit_State *J, SnapShot *osnap, - SnapEntry *loopmap, IRRef1 *subst) -{ - SnapEntry *nmap, *omap = &J->cur.snapmap[osnap->mapofs]; - SnapEntry *nextmap = &J->cur.snapmap[snap_nextofs(&J->cur, osnap)]; - MSize nmapofs; - MSize on, ln, nn, onent = osnap->nent; - BCReg nslots = osnap->nslots; - SnapShot *snap = &J->cur.snap[J->cur.nsnap]; - if (irt_isguard(J->guardemit)) { /* Guard inbetween? */ - nmapofs = J->cur.nsnapmap; - J->cur.nsnap++; /* Add new snapshot. */ - } else { /* Otherwise overwrite previous snapshot. */ - snap--; - nmapofs = snap->mapofs; - } - J->guardemit.irt = 0; - /* Setup new snapshot. */ - snap->mapofs = (uint32_t)nmapofs; - snap->ref = (IRRef1)J->cur.nins; - snap->nslots = nslots; - snap->topslot = osnap->topslot; - snap->count = 0; - nmap = &J->cur.snapmap[nmapofs]; - /* Substitute snapshot slots. */ - on = ln = nn = 0; - while (on < onent) { - SnapEntry osn = omap[on], lsn = loopmap[ln]; - if (snap_slot(lsn) < snap_slot(osn)) { /* Copy slot from loop map. */ - nmap[nn++] = lsn; - ln++; - } else { /* Copy substituted slot from snapshot map. */ - if (snap_slot(lsn) == snap_slot(osn)) ln++; /* Shadowed loop slot. */ - if (!irref_isk(snap_ref(osn))) - osn = snap_setref(osn, subst[snap_ref(osn)]); - nmap[nn++] = osn; - on++; - } - } - while (snap_slot(loopmap[ln]) < nslots) /* Copy remaining loop slots. */ - nmap[nn++] = loopmap[ln++]; - snap->nent = (uint8_t)nn; - omap += onent; - nmap += nn; - while (omap < nextmap) /* Copy PC + frame links. */ - *nmap++ = *omap++; - J->cur.nsnapmap = (uint32_t)(nmap - J->cur.snapmap); -} - -typedef struct LoopState { - jit_State *J; - IRRef1 *subst; - MSize sizesubst; -} LoopState; - -/* Unroll loop. */ -static void loop_unroll(LoopState *lps) -{ - jit_State *J = lps->J; - IRRef1 phi[LJ_MAX_PHI]; - uint32_t nphi = 0; - IRRef1 *subst; - SnapNo onsnap; - SnapShot *osnap, *loopsnap; - SnapEntry *loopmap, *psentinel; - IRRef ins, invar; - - /* Allocate substitution table. - ** Only non-constant refs in [REF_BIAS,invar) are valid indexes. - */ - invar = J->cur.nins; - lps->sizesubst = invar - REF_BIAS; - lps->subst = lj_mem_newvec(J->L, lps->sizesubst, IRRef1); - subst = lps->subst - REF_BIAS; - subst[REF_BASE] = REF_BASE; - - /* LOOP separates the pre-roll from the loop body. */ - emitir_raw(IRTG(IR_LOOP, IRT_NIL), 0, 0); - - /* Grow snapshot buffer and map for copy-substituted snapshots. - ** Need up to twice the number of snapshots minus #0 and loop snapshot. - ** Need up to twice the number of entries plus fallback substitutions - ** from the loop snapshot entries for each new snapshot. - ** Caveat: both calls may reallocate J->cur.snap and J->cur.snapmap! - */ - onsnap = J->cur.nsnap; - lj_snap_grow_buf(J, 2*onsnap-2); - lj_snap_grow_map(J, J->cur.nsnapmap*2+(onsnap-2)*J->cur.snap[onsnap-1].nent); - - /* The loop snapshot is used for fallback substitutions. */ - loopsnap = &J->cur.snap[onsnap-1]; - loopmap = &J->cur.snapmap[loopsnap->mapofs]; - /* The PC of snapshot #0 and the loop snapshot must match. */ - psentinel = &loopmap[loopsnap->nent]; - lua_assert(*psentinel == J->cur.snapmap[J->cur.snap[0].nent]); - *psentinel = SNAP(255, 0, 0); /* Replace PC with temporary sentinel. */ - - /* Start substitution with snapshot #1 (#0 is empty for root traces). */ - osnap = &J->cur.snap[1]; - - /* Copy and substitute all recorded instructions and snapshots. */ - for (ins = REF_FIRST; ins < invar; ins++) { - IRIns *ir; - IRRef op1, op2; - - if (ins >= osnap->ref) /* Instruction belongs to next snapshot? */ - loop_subst_snap(J, osnap++, loopmap, subst); /* Copy-substitute it. */ - - /* Substitute instruction operands. */ - ir = IR(ins); - op1 = ir->op1; - if (!irref_isk(op1)) op1 = subst[op1]; - op2 = ir->op2; - if (!irref_isk(op2)) op2 = subst[op2]; - if (irm_kind(lj_ir_mode[ir->o]) == IRM_N && - op1 == ir->op1 && op2 == ir->op2) { /* Regular invariant ins? */ - subst[ins] = (IRRef1)ins; /* Shortcut. */ - } else { - /* Re-emit substituted instruction to the FOLD/CSE/etc. pipeline. */ - IRType1 t = ir->t; /* Get this first, since emitir may invalidate ir. */ - IRRef ref = tref_ref(emitir(ir->ot & ~IRT_ISPHI, op1, op2)); - subst[ins] = (IRRef1)ref; - if (ref != ins) { - IRIns *irr = IR(ref); - if (ref < invar) { /* Loop-carried dependency? */ - /* Potential PHI? */ - if (!irref_isk(ref) && !irt_isphi(irr->t) && !irt_ispri(irr->t)) { - irt_setphi(irr->t); - if (nphi >= LJ_MAX_PHI) - lj_trace_err(J, LJ_TRERR_PHIOV); - phi[nphi++] = (IRRef1)ref; - } - /* Check all loop-carried dependencies for type instability. */ - if (!irt_sametype(t, irr->t)) { - if (irt_isinteger(t) && irt_isinteger(irr->t)) - continue; - else if (irt_isnum(t) && irt_isinteger(irr->t)) /* Fix int->num. */ - ref = tref_ref(emitir(IRTN(IR_CONV), ref, IRCONV_NUM_INT)); - else if (irt_isnum(irr->t) && irt_isinteger(t)) /* Fix num->int. */ - ref = tref_ref(emitir(IRTGI(IR_CONV), ref, - IRCONV_INT_NUM|IRCONV_CHECK)); - else - lj_trace_err(J, LJ_TRERR_TYPEINS); - subst[ins] = (IRRef1)ref; - irr = IR(ref); - goto phiconv; - } - } else if (ref != REF_DROP && irr->o == IR_CONV && - ref > invar && irr->op1 < invar) { - /* May need an extra PHI for a CONV. */ - ref = irr->op1; - irr = IR(ref); - phiconv: - if (ref < invar && !irref_isk(ref) && !irt_isphi(irr->t)) { - irt_setphi(irr->t); - if (nphi >= LJ_MAX_PHI) - lj_trace_err(J, LJ_TRERR_PHIOV); - phi[nphi++] = (IRRef1)ref; - } - } - } - } - } - if (!irt_isguard(J->guardemit)) /* Drop redundant snapshot. */ - J->cur.nsnapmap = (uint32_t)J->cur.snap[--J->cur.nsnap].mapofs; - lua_assert(J->cur.nsnapmap <= J->sizesnapmap); - *psentinel = J->cur.snapmap[J->cur.snap[0].nent]; /* Restore PC. */ - - loop_emit_phi(J, subst, phi, nphi, onsnap); -} - -/* Undo any partial changes made by the loop optimization. */ -static void loop_undo(jit_State *J, IRRef ins, SnapNo nsnap, MSize nsnapmap) -{ - ptrdiff_t i; - SnapShot *snap = &J->cur.snap[nsnap-1]; - SnapEntry *map = J->cur.snapmap; - map[snap->mapofs + snap->nent] = map[J->cur.snap[0].nent]; /* Restore PC. */ - J->cur.nsnapmap = (uint32_t)nsnapmap; - J->cur.nsnap = nsnap; - J->guardemit.irt = 0; - lj_ir_rollback(J, ins); - for (i = 0; i < BPROP_SLOTS; i++) { /* Remove backprop. cache entries. */ - BPropEntry *bp = &J->bpropcache[i]; - if (bp->val >= ins) - bp->key = 0; - } - for (ins--; ins >= REF_FIRST; ins--) { /* Remove flags. */ - IRIns *ir = IR(ins); - irt_clearphi(ir->t); - irt_clearmark(ir->t); - } -} - -/* Protected callback for loop optimization. */ -static TValue *cploop_opt(lua_State *L, lua_CFunction dummy, void *ud) -{ - UNUSED(L); UNUSED(dummy); - loop_unroll((LoopState *)ud); - return NULL; -} - -/* Loop optimization. */ -int lj_opt_loop(jit_State *J) -{ - IRRef nins = J->cur.nins; - SnapNo nsnap = J->cur.nsnap; - MSize nsnapmap = J->cur.nsnapmap; - LoopState lps; - int errcode; - lps.J = J; - lps.subst = NULL; - lps.sizesubst = 0; - errcode = lj_vm_cpcall(J->L, NULL, &lps, cploop_opt); - lj_mem_freevec(J2G(J), lps.subst, lps.sizesubst, IRRef1); - if (LJ_UNLIKELY(errcode)) { - lua_State *L = J->L; - if (errcode == LUA_ERRRUN && tvisnumber(L->top-1)) { /* Trace error? */ - int32_t e = numberVint(L->top-1); - switch ((TraceError)e) { - case LJ_TRERR_TYPEINS: /* Type instability. */ - case LJ_TRERR_GFAIL: /* Guard would always fail. */ - /* Unrolling via recording fixes many cases, e.g. a flipped boolean. */ - if (--J->instunroll < 0) /* But do not unroll forever. */ - break; - L->top--; /* Remove error object. */ - loop_undo(J, nins, nsnap, nsnapmap); - return 1; /* Loop optimization failed, continue recording. */ - default: - break; - } - } - lj_err_throw(L, errcode); /* Propagate all other errors. */ - } - return 0; /* Loop optimization is ok. */ -} - -#undef IR -#undef emitir -#undef emitir_raw - -#endif diff --git a/lib/LuaJIT/src/lj_opt_mem.c b/lib/LuaJIT/src/lj_opt_mem.c deleted file mode 100644 index cc177d3..0000000 --- a/lib/LuaJIT/src/lj_opt_mem.c +++ /dev/null @@ -1,935 +0,0 @@ -/* -** Memory access optimizations. -** AA: Alias Analysis using high-level semantic disambiguation. -** FWD: Load Forwarding (L2L) + Store Forwarding (S2L). -** DSE: Dead-Store Elimination. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_opt_mem_c -#define LUA_CORE - -#include "lj_obj.h" - -#if LJ_HASJIT - -#include "lj_tab.h" -#include "lj_ir.h" -#include "lj_jit.h" -#include "lj_iropt.h" -#include "lj_ircall.h" - -/* Some local macros to save typing. Undef'd at the end. */ -#define IR(ref) (&J->cur.ir[(ref)]) -#define fins (&J->fold.ins) -#define fleft (J->fold.left) -#define fright (J->fold.right) - -/* -** Caveat #1: return value is not always a TRef -- only use with tref_ref(). -** Caveat #2: FWD relies on active CSE for xREF operands -- see lj_opt_fold(). -*/ - -/* Return values from alias analysis. */ -typedef enum { - ALIAS_NO, /* The two refs CANNOT alias (exact). */ - ALIAS_MAY, /* The two refs MAY alias (inexact). */ - ALIAS_MUST /* The two refs MUST alias (exact). */ -} AliasRet; - -/* -- ALOAD/HLOAD forwarding and ASTORE/HSTORE elimination ---------------- */ - -/* Simplified escape analysis: check for intervening stores. */ -static AliasRet aa_escape(jit_State *J, IRIns *ir, IRIns *stop) -{ - IRRef ref = (IRRef)(ir - J->cur.ir); /* The ref that might be stored. */ - for (ir++; ir < stop; ir++) - if (ir->op2 == ref && - (ir->o == IR_ASTORE || ir->o == IR_HSTORE || - ir->o == IR_USTORE || ir->o == IR_FSTORE)) - return ALIAS_MAY; /* Reference was stored and might alias. */ - return ALIAS_NO; /* Reference was not stored. */ -} - -/* Alias analysis for two different table references. */ -static AliasRet aa_table(jit_State *J, IRRef ta, IRRef tb) -{ - IRIns *taba = IR(ta), *tabb = IR(tb); - int newa, newb; - lua_assert(ta != tb); - lua_assert(irt_istab(taba->t) && irt_istab(tabb->t)); - /* Disambiguate new allocations. */ - newa = (taba->o == IR_TNEW || taba->o == IR_TDUP); - newb = (tabb->o == IR_TNEW || tabb->o == IR_TDUP); - if (newa && newb) - return ALIAS_NO; /* Two different allocations never alias. */ - if (newb) { /* At least one allocation? */ - IRIns *tmp = taba; taba = tabb; tabb = tmp; - } else if (!newa) { - return ALIAS_MAY; /* Anything else: we just don't know. */ - } - return aa_escape(J, taba, tabb); -} - -/* Alias analysis for array and hash access using key-based disambiguation. */ -static AliasRet aa_ahref(jit_State *J, IRIns *refa, IRIns *refb) -{ - IRRef ka = refa->op2; - IRRef kb = refb->op2; - IRIns *keya, *keyb; - IRRef ta, tb; - if (refa == refb) - return ALIAS_MUST; /* Shortcut for same refs. */ - keya = IR(ka); - if (keya->o == IR_KSLOT) { ka = keya->op1; keya = IR(ka); } - keyb = IR(kb); - if (keyb->o == IR_KSLOT) { kb = keyb->op1; keyb = IR(kb); } - ta = (refa->o==IR_HREFK || refa->o==IR_AREF) ? IR(refa->op1)->op1 : refa->op1; - tb = (refb->o==IR_HREFK || refb->o==IR_AREF) ? IR(refb->op1)->op1 : refb->op1; - if (ka == kb) { - /* Same key. Check for same table with different ref (NEWREF vs. HREF). */ - if (ta == tb) - return ALIAS_MUST; /* Same key, same table. */ - else - return aa_table(J, ta, tb); /* Same key, possibly different table. */ - } - if (irref_isk(ka) && irref_isk(kb)) - return ALIAS_NO; /* Different constant keys. */ - if (refa->o == IR_AREF) { - /* Disambiguate array references based on index arithmetic. */ - int32_t ofsa = 0, ofsb = 0; - IRRef basea = ka, baseb = kb; - lua_assert(refb->o == IR_AREF); - /* Gather base and offset from t[base] or t[base+-ofs]. */ - if (keya->o == IR_ADD && irref_isk(keya->op2)) { - basea = keya->op1; - ofsa = IR(keya->op2)->i; - if (basea == kb && ofsa != 0) - return ALIAS_NO; /* t[base+-ofs] vs. t[base]. */ - } - if (keyb->o == IR_ADD && irref_isk(keyb->op2)) { - baseb = keyb->op1; - ofsb = IR(keyb->op2)->i; - if (ka == baseb && ofsb != 0) - return ALIAS_NO; /* t[base] vs. t[base+-ofs]. */ - } - if (basea == baseb && ofsa != ofsb) - return ALIAS_NO; /* t[base+-o1] vs. t[base+-o2] and o1 != o2. */ - } else { - /* Disambiguate hash references based on the type of their keys. */ - lua_assert((refa->o==IR_HREF || refa->o==IR_HREFK || refa->o==IR_NEWREF) && - (refb->o==IR_HREF || refb->o==IR_HREFK || refb->o==IR_NEWREF)); - if (!irt_sametype(keya->t, keyb->t)) - return ALIAS_NO; /* Different key types. */ - } - if (ta == tb) - return ALIAS_MAY; /* Same table, cannot disambiguate keys. */ - else - return aa_table(J, ta, tb); /* Try to disambiguate tables. */ -} - -/* Array and hash load forwarding. */ -static TRef fwd_ahload(jit_State *J, IRRef xref) -{ - IRIns *xr = IR(xref); - IRRef lim = xref; /* Search limit. */ - IRRef ref; - - /* Search for conflicting stores. */ - ref = J->chain[fins->o+IRDELTA_L2S]; - while (ref > xref) { - IRIns *store = IR(ref); - switch (aa_ahref(J, xr, IR(store->op1))) { - case ALIAS_NO: break; /* Continue searching. */ - case ALIAS_MAY: lim = ref; goto cselim; /* Limit search for load. */ - case ALIAS_MUST: return store->op2; /* Store forwarding. */ - } - ref = store->prev; - } - - /* No conflicting store (yet): const-fold loads from allocations. */ - { - IRIns *ir = (xr->o == IR_HREFK || xr->o == IR_AREF) ? IR(xr->op1) : xr; - IRRef tab = ir->op1; - ir = IR(tab); - if (ir->o == IR_TNEW || (ir->o == IR_TDUP && irref_isk(xr->op2))) { - /* A NEWREF with a number key may end up pointing to the array part. - ** But it's referenced from HSTORE and not found in the ASTORE chain. - ** For now simply consider this a conflict without forwarding anything. - */ - if (xr->o == IR_AREF) { - IRRef ref2 = J->chain[IR_NEWREF]; - while (ref2 > tab) { - IRIns *newref = IR(ref2); - if (irt_isnum(IR(newref->op2)->t)) - goto cselim; - ref2 = newref->prev; - } - } - /* NEWREF inhibits CSE for HREF, and dependent FLOADs from HREFK/AREF. - ** But the above search for conflicting stores was limited by xref. - ** So continue searching, limited by the TNEW/TDUP. Store forwarding - ** is ok, too. A conflict does NOT limit the search for a matching load. - */ - while (ref > tab) { - IRIns *store = IR(ref); - switch (aa_ahref(J, xr, IR(store->op1))) { - case ALIAS_NO: break; /* Continue searching. */ - case ALIAS_MAY: goto cselim; /* Conflicting store. */ - case ALIAS_MUST: return store->op2; /* Store forwarding. */ - } - ref = store->prev; - } - lua_assert(ir->o != IR_TNEW || irt_isnil(fins->t)); - if (irt_ispri(fins->t)) { - return TREF_PRI(irt_type(fins->t)); - } else if (irt_isnum(fins->t) || (LJ_DUALNUM && irt_isint(fins->t)) || - irt_isstr(fins->t)) { - TValue keyv; - cTValue *tv; - IRIns *key = IR(xr->op2); - if (key->o == IR_KSLOT) key = IR(key->op1); - lj_ir_kvalue(J->L, &keyv, key); - tv = lj_tab_get(J->L, ir_ktab(IR(ir->op1)), &keyv); - lua_assert(itype2irt(tv) == irt_type(fins->t)); - if (irt_isnum(fins->t)) - return lj_ir_knum_u64(J, tv->u64); - else if (LJ_DUALNUM && irt_isint(fins->t)) - return lj_ir_kint(J, intV(tv)); - else - return lj_ir_kstr(J, strV(tv)); - } - /* Othwerwise: don't intern as a constant. */ - } - } - -cselim: - /* Try to find a matching load. Below the conflicting store, if any. */ - ref = J->chain[fins->o]; - while (ref > lim) { - IRIns *load = IR(ref); - if (load->op1 == xref) - return ref; /* Load forwarding. */ - ref = load->prev; - } - return 0; /* Conflict or no match. */ -} - -/* Reassociate ALOAD across PHIs to handle t[i-1] forwarding case. */ -static TRef fwd_aload_reassoc(jit_State *J) -{ - IRIns *irx = IR(fins->op1); - IRIns *key = IR(irx->op2); - if (key->o == IR_ADD && irref_isk(key->op2)) { - IRIns *add2 = IR(key->op1); - if (add2->o == IR_ADD && irref_isk(add2->op2) && - IR(key->op2)->i == -IR(add2->op2)->i) { - IRRef ref = J->chain[IR_AREF]; - IRRef lim = add2->op1; - if (irx->op1 > lim) lim = irx->op1; - while (ref > lim) { - IRIns *ir = IR(ref); - if (ir->op1 == irx->op1 && ir->op2 == add2->op1) - return fwd_ahload(J, ref); - ref = ir->prev; - } - } - } - return 0; -} - -/* ALOAD forwarding. */ -TRef LJ_FASTCALL lj_opt_fwd_aload(jit_State *J) -{ - IRRef ref; - if ((ref = fwd_ahload(J, fins->op1)) || - (ref = fwd_aload_reassoc(J))) - return ref; - return EMITFOLD; -} - -/* HLOAD forwarding. */ -TRef LJ_FASTCALL lj_opt_fwd_hload(jit_State *J) -{ - IRRef ref = fwd_ahload(J, fins->op1); - if (ref) - return ref; - return EMITFOLD; -} - -/* HREFK forwarding. */ -TRef LJ_FASTCALL lj_opt_fwd_hrefk(jit_State *J) -{ - IRRef tab = fleft->op1; - IRRef ref = J->chain[IR_NEWREF]; - while (ref > tab) { - IRIns *newref = IR(ref); - if (tab == newref->op1) { - if (fright->op1 == newref->op2) - return ref; /* Forward from NEWREF. */ - else - goto docse; - } else if (aa_table(J, tab, newref->op1) != ALIAS_NO) { - goto docse; - } - ref = newref->prev; - } - /* No conflicting NEWREF: key location unchanged for HREFK of TDUP. */ - if (IR(tab)->o == IR_TDUP) - fins->t.irt &= ~IRT_GUARD; /* Drop HREFK guard. */ -docse: - return CSEFOLD; -} - -/* Check whether HREF of TNEW/TDUP can be folded to niltv. */ -int LJ_FASTCALL lj_opt_fwd_href_nokey(jit_State *J) -{ - IRRef lim = fins->op1; /* Search limit. */ - IRRef ref; - - /* The key for an ASTORE may end up in the hash part after a NEWREF. */ - if (irt_isnum(fright->t) && J->chain[IR_NEWREF] > lim) { - ref = J->chain[IR_ASTORE]; - while (ref > lim) { - if (ref < J->chain[IR_NEWREF]) - return 0; /* Conflict. */ - ref = IR(ref)->prev; - } - } - - /* Search for conflicting stores. */ - ref = J->chain[IR_HSTORE]; - while (ref > lim) { - IRIns *store = IR(ref); - if (aa_ahref(J, fins, IR(store->op1)) != ALIAS_NO) - return 0; /* Conflict. */ - ref = store->prev; - } - - return 1; /* No conflict. Can fold to niltv. */ -} - -/* Check whether there's no aliasing table.clear. */ -static int fwd_aa_tab_clear(jit_State *J, IRRef lim, IRRef ta) -{ - IRRef ref = J->chain[IR_CALLS]; - while (ref > lim) { - IRIns *calls = IR(ref); - if (calls->op2 == IRCALL_lj_tab_clear && - (ta == calls->op1 || aa_table(J, ta, calls->op1) != ALIAS_NO)) - return 0; /* Conflict. */ - ref = calls->prev; - } - return 1; /* No conflict. Can safely FOLD/CSE. */ -} - -/* Check whether there's no aliasing NEWREF/table.clear for the left operand. */ -int LJ_FASTCALL lj_opt_fwd_tptr(jit_State *J, IRRef lim) -{ - IRRef ta = fins->op1; - IRRef ref = J->chain[IR_NEWREF]; - while (ref > lim) { - IRIns *newref = IR(ref); - if (ta == newref->op1 || aa_table(J, ta, newref->op1) != ALIAS_NO) - return 0; /* Conflict. */ - ref = newref->prev; - } - return fwd_aa_tab_clear(J, lim, ta); -} - -/* ASTORE/HSTORE elimination. */ -TRef LJ_FASTCALL lj_opt_dse_ahstore(jit_State *J) -{ - IRRef xref = fins->op1; /* xREF reference. */ - IRRef val = fins->op2; /* Stored value reference. */ - IRIns *xr = IR(xref); - IRRef1 *refp = &J->chain[fins->o]; - IRRef ref = *refp; - while (ref > xref) { /* Search for redundant or conflicting stores. */ - IRIns *store = IR(ref); - switch (aa_ahref(J, xr, IR(store->op1))) { - case ALIAS_NO: - break; /* Continue searching. */ - case ALIAS_MAY: /* Store to MAYBE the same location. */ - if (store->op2 != val) /* Conflict if the value is different. */ - goto doemit; - break; /* Otherwise continue searching. */ - case ALIAS_MUST: /* Store to the same location. */ - if (store->op2 == val) /* Same value: drop the new store. */ - return DROPFOLD; - /* Different value: try to eliminate the redundant store. */ - if (ref > J->chain[IR_LOOP]) { /* Quick check to avoid crossing LOOP. */ - IRIns *ir; - /* Check for any intervening guards (includes conflicting loads). */ - for (ir = IR(J->cur.nins-1); ir > store; ir--) - if (irt_isguard(ir->t) || ir->o == IR_CALLL) - goto doemit; /* No elimination possible. */ - /* Remove redundant store from chain and replace with NOP. */ - *refp = store->prev; - store->o = IR_NOP; - store->t.irt = IRT_NIL; - store->op1 = store->op2 = 0; - store->prev = 0; - /* Now emit the new store instead. */ - } - goto doemit; - } - ref = *(refp = &store->prev); - } -doemit: - return EMITFOLD; /* Otherwise we have a conflict or simply no match. */ -} - -/* -- ULOAD forwarding ---------------------------------------------------- */ - -/* The current alias analysis for upvalues is very simplistic. It only -** disambiguates between the unique upvalues of the same function. -** This is good enough for now, since most upvalues are read-only. -** -** A more precise analysis would be feasible with the help of the parser: -** generate a unique key for every upvalue, even across all prototypes. -** Lacking a realistic use-case, it's unclear whether this is beneficial. -*/ -static AliasRet aa_uref(IRIns *refa, IRIns *refb) -{ - if (refa->o != refb->o) - return ALIAS_NO; /* Different UREFx type. */ - if (refa->op1 == refb->op1) { /* Same function. */ - if (refa->op2 == refb->op2) - return ALIAS_MUST; /* Same function, same upvalue idx. */ - else - return ALIAS_NO; /* Same function, different upvalue idx. */ - } else { /* Different functions, check disambiguation hash values. */ - if (((refa->op2 ^ refb->op2) & 0xff)) - return ALIAS_NO; /* Upvalues with different hash values cannot alias. */ - else - return ALIAS_MAY; /* No conclusion can be drawn for same hash value. */ - } -} - -/* ULOAD forwarding. */ -TRef LJ_FASTCALL lj_opt_fwd_uload(jit_State *J) -{ - IRRef uref = fins->op1; - IRRef lim = REF_BASE; /* Search limit. */ - IRIns *xr = IR(uref); - IRRef ref; - - /* Search for conflicting stores. */ - ref = J->chain[IR_USTORE]; - while (ref > lim) { - IRIns *store = IR(ref); - switch (aa_uref(xr, IR(store->op1))) { - case ALIAS_NO: break; /* Continue searching. */ - case ALIAS_MAY: lim = ref; goto cselim; /* Limit search for load. */ - case ALIAS_MUST: return store->op2; /* Store forwarding. */ - } - ref = store->prev; - } - -cselim: - /* Try to find a matching load. Below the conflicting store, if any. */ - - ref = J->chain[IR_ULOAD]; - while (ref > lim) { - IRIns *ir = IR(ref); - if (ir->op1 == uref || - (IR(ir->op1)->op12 == IR(uref)->op12 && IR(ir->op1)->o == IR(uref)->o)) - return ref; /* Match for identical or equal UREFx (non-CSEable UREFO). */ - ref = ir->prev; - } - return lj_ir_emit(J); -} - -/* USTORE elimination. */ -TRef LJ_FASTCALL lj_opt_dse_ustore(jit_State *J) -{ - IRRef xref = fins->op1; /* xREF reference. */ - IRRef val = fins->op2; /* Stored value reference. */ - IRIns *xr = IR(xref); - IRRef1 *refp = &J->chain[IR_USTORE]; - IRRef ref = *refp; - while (ref > xref) { /* Search for redundant or conflicting stores. */ - IRIns *store = IR(ref); - switch (aa_uref(xr, IR(store->op1))) { - case ALIAS_NO: - break; /* Continue searching. */ - case ALIAS_MAY: /* Store to MAYBE the same location. */ - if (store->op2 != val) /* Conflict if the value is different. */ - goto doemit; - break; /* Otherwise continue searching. */ - case ALIAS_MUST: /* Store to the same location. */ - if (store->op2 == val) /* Same value: drop the new store. */ - return DROPFOLD; - /* Different value: try to eliminate the redundant store. */ - if (ref > J->chain[IR_LOOP]) { /* Quick check to avoid crossing LOOP. */ - IRIns *ir; - /* Check for any intervening guards (includes conflicting loads). */ - for (ir = IR(J->cur.nins-1); ir > store; ir--) - if (irt_isguard(ir->t)) - goto doemit; /* No elimination possible. */ - /* Remove redundant store from chain and replace with NOP. */ - *refp = store->prev; - store->o = IR_NOP; - store->t.irt = IRT_NIL; - store->op1 = store->op2 = 0; - store->prev = 0; - if (ref+1 < J->cur.nins && - store[1].o == IR_OBAR && store[1].op1 == xref) { - IRRef1 *bp = &J->chain[IR_OBAR]; - IRIns *obar; - for (obar = IR(*bp); *bp > ref+1; obar = IR(*bp)) - bp = &obar->prev; - /* Remove OBAR, too. */ - *bp = obar->prev; - obar->o = IR_NOP; - obar->t.irt = IRT_NIL; - obar->op1 = obar->op2 = 0; - obar->prev = 0; - } - /* Now emit the new store instead. */ - } - goto doemit; - } - ref = *(refp = &store->prev); - } -doemit: - return EMITFOLD; /* Otherwise we have a conflict or simply no match. */ -} - -/* -- FLOAD forwarding and FSTORE elimination ----------------------------- */ - -/* Alias analysis for field access. -** Field loads are cheap and field stores are rare. -** Simple disambiguation based on field types is good enough. -*/ -static AliasRet aa_fref(jit_State *J, IRIns *refa, IRIns *refb) -{ - if (refa->op2 != refb->op2) - return ALIAS_NO; /* Different fields. */ - if (refa->op1 == refb->op1) - return ALIAS_MUST; /* Same field, same object. */ - else if (refa->op2 >= IRFL_TAB_META && refa->op2 <= IRFL_TAB_NOMM) - return aa_table(J, refa->op1, refb->op1); /* Disambiguate tables. */ - else - return ALIAS_MAY; /* Same field, possibly different object. */ -} - -/* Only the loads for mutable fields end up here (see FOLD). */ -TRef LJ_FASTCALL lj_opt_fwd_fload(jit_State *J) -{ - IRRef oref = fins->op1; /* Object reference. */ - IRRef fid = fins->op2; /* Field ID. */ - IRRef lim = oref; /* Search limit. */ - IRRef ref; - - /* Search for conflicting stores. */ - ref = J->chain[IR_FSTORE]; - while (ref > oref) { - IRIns *store = IR(ref); - switch (aa_fref(J, fins, IR(store->op1))) { - case ALIAS_NO: break; /* Continue searching. */ - case ALIAS_MAY: lim = ref; goto cselim; /* Limit search for load. */ - case ALIAS_MUST: return store->op2; /* Store forwarding. */ - } - ref = store->prev; - } - - /* No conflicting store: const-fold field loads from allocations. */ - if (fid == IRFL_TAB_META) { - IRIns *ir = IR(oref); - if (ir->o == IR_TNEW || ir->o == IR_TDUP) - return lj_ir_knull(J, IRT_TAB); - } - -cselim: - /* Try to find a matching load. Below the conflicting store, if any. */ - return lj_opt_cselim(J, lim); -} - -/* FSTORE elimination. */ -TRef LJ_FASTCALL lj_opt_dse_fstore(jit_State *J) -{ - IRRef fref = fins->op1; /* FREF reference. */ - IRRef val = fins->op2; /* Stored value reference. */ - IRIns *xr = IR(fref); - IRRef1 *refp = &J->chain[IR_FSTORE]; - IRRef ref = *refp; - while (ref > fref) { /* Search for redundant or conflicting stores. */ - IRIns *store = IR(ref); - switch (aa_fref(J, xr, IR(store->op1))) { - case ALIAS_NO: - break; /* Continue searching. */ - case ALIAS_MAY: - if (store->op2 != val) /* Conflict if the value is different. */ - goto doemit; - break; /* Otherwise continue searching. */ - case ALIAS_MUST: - if (store->op2 == val) /* Same value: drop the new store. */ - return DROPFOLD; - /* Different value: try to eliminate the redundant store. */ - if (ref > J->chain[IR_LOOP]) { /* Quick check to avoid crossing LOOP. */ - IRIns *ir; - /* Check for any intervening guards or conflicting loads. */ - for (ir = IR(J->cur.nins-1); ir > store; ir--) - if (irt_isguard(ir->t) || (ir->o == IR_FLOAD && ir->op2 == xr->op2)) - goto doemit; /* No elimination possible. */ - /* Remove redundant store from chain and replace with NOP. */ - *refp = store->prev; - store->o = IR_NOP; - store->t.irt = IRT_NIL; - store->op1 = store->op2 = 0; - store->prev = 0; - /* Now emit the new store instead. */ - } - goto doemit; - } - ref = *(refp = &store->prev); - } -doemit: - return EMITFOLD; /* Otherwise we have a conflict or simply no match. */ -} - -/* -- XLOAD forwarding and XSTORE elimination ----------------------------- */ - -/* Find cdata allocation for a reference (if any). */ -static IRIns *aa_findcnew(jit_State *J, IRIns *ir) -{ - while (ir->o == IR_ADD) { - if (!irref_isk(ir->op1)) { - IRIns *ir1 = aa_findcnew(J, IR(ir->op1)); /* Left-recursion. */ - if (ir1) return ir1; - } - if (irref_isk(ir->op2)) return NULL; - ir = IR(ir->op2); /* Flatten right-recursion. */ - } - return ir->o == IR_CNEW ? ir : NULL; -} - -/* Alias analysis for two cdata allocations. */ -static AliasRet aa_cnew(jit_State *J, IRIns *refa, IRIns *refb) -{ - IRIns *cnewa = aa_findcnew(J, refa); - IRIns *cnewb = aa_findcnew(J, refb); - if (cnewa == cnewb) - return ALIAS_MAY; /* Same allocation or neither is an allocation. */ - if (cnewa && cnewb) - return ALIAS_NO; /* Two different allocations never alias. */ - if (cnewb) { cnewa = cnewb; refb = refa; } - return aa_escape(J, cnewa, refb); -} - -/* Alias analysis for XLOAD/XSTORE. */ -static AliasRet aa_xref(jit_State *J, IRIns *refa, IRIns *xa, IRIns *xb) -{ - ptrdiff_t ofsa = 0, ofsb = 0; - IRIns *refb = IR(xb->op1); - IRIns *basea = refa, *baseb = refb; - if (refa == refb && irt_sametype(xa->t, xb->t)) - return ALIAS_MUST; /* Shortcut for same refs with identical type. */ - /* Offset-based disambiguation. */ - if (refa->o == IR_ADD && irref_isk(refa->op2)) { - IRIns *irk = IR(refa->op2); - basea = IR(refa->op1); - ofsa = (LJ_64 && irk->o == IR_KINT64) ? (ptrdiff_t)ir_k64(irk)->u64 : - (ptrdiff_t)irk->i; - } - if (refb->o == IR_ADD && irref_isk(refb->op2)) { - IRIns *irk = IR(refb->op2); - baseb = IR(refb->op1); - ofsb = (LJ_64 && irk->o == IR_KINT64) ? (ptrdiff_t)ir_k64(irk)->u64 : - (ptrdiff_t)irk->i; - } - /* Treat constified pointers like base vs. base+offset. */ - if (basea->o == IR_KPTR && baseb->o == IR_KPTR) { - ofsb += (char *)ir_kptr(baseb) - (char *)ir_kptr(basea); - baseb = basea; - } - /* This implements (very) strict aliasing rules. - ** Different types do NOT alias, except for differences in signedness. - ** Type punning through unions is allowed (but forces a reload). - */ - if (basea == baseb) { - ptrdiff_t sza = irt_size(xa->t), szb = irt_size(xb->t); - if (ofsa == ofsb) { - if (sza == szb && irt_isfp(xa->t) == irt_isfp(xb->t)) - return ALIAS_MUST; /* Same-sized, same-kind. May need to convert. */ - } else if (ofsa + sza <= ofsb || ofsb + szb <= ofsa) { - return ALIAS_NO; /* Non-overlapping base+-o1 vs. base+-o2. */ - } - /* NYI: extract, extend or reinterpret bits (int <-> fp). */ - return ALIAS_MAY; /* Overlapping or type punning: force reload. */ - } - if (!irt_sametype(xa->t, xb->t) && - !(irt_typerange(xa->t, IRT_I8, IRT_U64) && - ((xa->t.irt - IRT_I8) ^ (xb->t.irt - IRT_I8)) == 1)) - return ALIAS_NO; - /* NYI: structural disambiguation. */ - return aa_cnew(J, basea, baseb); /* Try to disambiguate allocations. */ -} - -/* Return CSEd reference or 0. Caveat: swaps lower ref to the right! */ -static IRRef reassoc_trycse(jit_State *J, IROp op, IRRef op1, IRRef op2) -{ - IRRef ref = J->chain[op]; - IRRef lim = op1; - if (op2 > lim) { lim = op2; op2 = op1; op1 = lim; } - while (ref > lim) { - IRIns *ir = IR(ref); - if (ir->op1 == op1 && ir->op2 == op2) - return ref; - ref = ir->prev; - } - return 0; -} - -/* Reassociate index references. */ -static IRRef reassoc_xref(jit_State *J, IRIns *ir) -{ - ptrdiff_t ofs = 0; - if (ir->o == IR_ADD && irref_isk(ir->op2)) { /* Get constant offset. */ - IRIns *irk = IR(ir->op2); - ofs = (LJ_64 && irk->o == IR_KINT64) ? (ptrdiff_t)ir_k64(irk)->u64 : - (ptrdiff_t)irk->i; - ir = IR(ir->op1); - } - if (ir->o == IR_ADD) { /* Add of base + index. */ - /* Index ref > base ref for loop-carried dependences. Only check op1. */ - IRIns *ir2, *ir1 = IR(ir->op1); - int32_t shift = 0; - IRRef idxref; - /* Determine index shifts. Don't bother with IR_MUL here. */ - if (ir1->o == IR_BSHL && irref_isk(ir1->op2)) - shift = IR(ir1->op2)->i; - else if (ir1->o == IR_ADD && ir1->op1 == ir1->op2) - shift = 1; - else - ir1 = ir; - ir2 = IR(ir1->op1); - /* A non-reassociated add. Must be a loop-carried dependence. */ - if (ir2->o == IR_ADD && irt_isint(ir2->t) && irref_isk(ir2->op2)) - ofs += (ptrdiff_t)IR(ir2->op2)->i << shift; - else - return 0; - idxref = ir2->op1; - /* Try to CSE the reassociated chain. Give up if not found. */ - if (ir1 != ir && - !(idxref = reassoc_trycse(J, ir1->o, idxref, - ir1->o == IR_BSHL ? ir1->op2 : idxref))) - return 0; - if (!(idxref = reassoc_trycse(J, IR_ADD, idxref, ir->op2))) - return 0; - if (ofs != 0) { - IRRef refk = tref_ref(lj_ir_kintp(J, ofs)); - if (!(idxref = reassoc_trycse(J, IR_ADD, idxref, refk))) - return 0; - } - return idxref; /* Success, found a reassociated index reference. Phew. */ - } - return 0; /* Failure. */ -} - -/* XLOAD forwarding. */ -TRef LJ_FASTCALL lj_opt_fwd_xload(jit_State *J) -{ - IRRef xref = fins->op1; - IRIns *xr = IR(xref); - IRRef lim = xref; /* Search limit. */ - IRRef ref; - - if ((fins->op2 & IRXLOAD_READONLY)) - goto cselim; - if ((fins->op2 & IRXLOAD_VOLATILE)) - goto doemit; - - /* Search for conflicting stores. */ - ref = J->chain[IR_XSTORE]; -retry: - if (J->chain[IR_CALLXS] > lim) lim = J->chain[IR_CALLXS]; - if (J->chain[IR_XBAR] > lim) lim = J->chain[IR_XBAR]; - while (ref > lim) { - IRIns *store = IR(ref); - switch (aa_xref(J, xr, fins, store)) { - case ALIAS_NO: break; /* Continue searching. */ - case ALIAS_MAY: lim = ref; goto cselim; /* Limit search for load. */ - case ALIAS_MUST: - /* Emit conversion if the loaded type doesn't match the forwarded type. */ - if (!irt_sametype(fins->t, IR(store->op2)->t)) { - IRType dt = irt_type(fins->t), st = irt_type(IR(store->op2)->t); - if (dt == IRT_I8 || dt == IRT_I16) { /* Trunc + sign-extend. */ - st = dt | IRCONV_SEXT; - dt = IRT_INT; - } else if (dt == IRT_U8 || dt == IRT_U16) { /* Trunc + zero-extend. */ - st = dt; - dt = IRT_INT; - } - fins->ot = IRT(IR_CONV, dt); - fins->op1 = store->op2; - fins->op2 = (dt<<5)|st; - return RETRYFOLD; - } - return store->op2; /* Store forwarding. */ - } - ref = store->prev; - } - -cselim: - /* Try to find a matching load. Below the conflicting store, if any. */ - ref = J->chain[IR_XLOAD]; - while (ref > lim) { - /* CSE for XLOAD depends on the type, but not on the IRXLOAD_* flags. */ - if (IR(ref)->op1 == xref && irt_sametype(IR(ref)->t, fins->t)) - return ref; - ref = IR(ref)->prev; - } - - /* Reassociate XLOAD across PHIs to handle a[i-1] forwarding case. */ - if (!(fins->op2 & IRXLOAD_READONLY) && J->chain[IR_LOOP] && - xref == fins->op1 && (xref = reassoc_xref(J, xr)) != 0) { - ref = J->chain[IR_XSTORE]; - while (ref > lim) /* Skip stores that have already been checked. */ - ref = IR(ref)->prev; - lim = xref; - xr = IR(xref); - goto retry; /* Retry with the reassociated reference. */ - } -doemit: - return EMITFOLD; -} - -/* XSTORE elimination. */ -TRef LJ_FASTCALL lj_opt_dse_xstore(jit_State *J) -{ - IRRef xref = fins->op1; - IRIns *xr = IR(xref); - IRRef lim = xref; /* Search limit. */ - IRRef val = fins->op2; /* Stored value reference. */ - IRRef1 *refp = &J->chain[IR_XSTORE]; - IRRef ref = *refp; - if (J->chain[IR_CALLXS] > lim) lim = J->chain[IR_CALLXS]; - if (J->chain[IR_XBAR] > lim) lim = J->chain[IR_XBAR]; - if (J->chain[IR_XSNEW] > lim) lim = J->chain[IR_XSNEW]; - while (ref > lim) { /* Search for redundant or conflicting stores. */ - IRIns *store = IR(ref); - switch (aa_xref(J, xr, fins, store)) { - case ALIAS_NO: - break; /* Continue searching. */ - case ALIAS_MAY: - if (store->op2 != val) /* Conflict if the value is different. */ - goto doemit; - break; /* Otherwise continue searching. */ - case ALIAS_MUST: - if (store->op2 == val) /* Same value: drop the new store. */ - return DROPFOLD; - /* Different value: try to eliminate the redundant store. */ - if (ref > J->chain[IR_LOOP]) { /* Quick check to avoid crossing LOOP. */ - IRIns *ir; - /* Check for any intervening guards or any XLOADs (no AA performed). */ - for (ir = IR(J->cur.nins-1); ir > store; ir--) - if (irt_isguard(ir->t) || ir->o == IR_XLOAD) - goto doemit; /* No elimination possible. */ - /* Remove redundant store from chain and replace with NOP. */ - *refp = store->prev; - store->o = IR_NOP; - store->t.irt = IRT_NIL; - store->op1 = store->op2 = 0; - store->prev = 0; - /* Now emit the new store instead. */ - } - goto doemit; - } - ref = *(refp = &store->prev); - } -doemit: - return EMITFOLD; /* Otherwise we have a conflict or simply no match. */ -} - -/* -- Forwarding of lj_tab_len -------------------------------------------- */ - -/* This is rather simplistic right now, but better than nothing. */ -TRef LJ_FASTCALL lj_opt_fwd_tab_len(jit_State *J) -{ - IRRef tab = fins->op1; /* Table reference. */ - IRRef lim = tab; /* Search limit. */ - IRRef ref; - - /* Any ASTORE is a conflict and limits the search. */ - if (J->chain[IR_ASTORE] > lim) lim = J->chain[IR_ASTORE]; - - /* Search for conflicting HSTORE with numeric key. */ - ref = J->chain[IR_HSTORE]; - while (ref > lim) { - IRIns *store = IR(ref); - IRIns *href = IR(store->op1); - IRIns *key = IR(href->op2); - if (irt_isnum(key->o == IR_KSLOT ? IR(key->op1)->t : key->t)) { - lim = ref; /* Conflicting store found, limits search for TLEN. */ - break; - } - ref = store->prev; - } - - /* Search for aliasing table.clear. */ - if (!fwd_aa_tab_clear(J, lim, tab)) - return lj_ir_emit(J); - - /* Try to find a matching load. Below the conflicting store, if any. */ - return lj_opt_cselim(J, lim); -} - -/* -- ASTORE/HSTORE previous type analysis -------------------------------- */ - -/* Check whether the previous value for a table store is non-nil. -** This can be derived either from a previous store or from a previous -** load (because all loads from tables perform a type check). -** -** The result of the analysis can be used to avoid the metatable check -** and the guard against HREF returning niltv. Both of these are cheap, -** so let's not spend too much effort on the analysis. -** -** A result of 1 is exact: previous value CANNOT be nil. -** A result of 0 is inexact: previous value MAY be nil. -*/ -int lj_opt_fwd_wasnonnil(jit_State *J, IROpT loadop, IRRef xref) -{ - /* First check stores. */ - IRRef ref = J->chain[loadop+IRDELTA_L2S]; - while (ref > xref) { - IRIns *store = IR(ref); - if (store->op1 == xref) { /* Same xREF. */ - /* A nil store MAY alias, but a non-nil store MUST alias. */ - return !irt_isnil(store->t); - } else if (irt_isnil(store->t)) { /* Must check any nil store. */ - IRRef skref = IR(store->op1)->op2; - IRRef xkref = IR(xref)->op2; - /* Same key type MAY alias. Need ALOAD check due to multiple int types. */ - if (loadop == IR_ALOAD || irt_sametype(IR(skref)->t, IR(xkref)->t)) { - if (skref == xkref || !irref_isk(skref) || !irref_isk(xkref)) - return 0; /* A nil store with same const key or var key MAY alias. */ - /* Different const keys CANNOT alias. */ - } /* Different key types CANNOT alias. */ - } /* Other non-nil stores MAY alias. */ - ref = store->prev; - } - - /* Check loads since nothing could be derived from stores. */ - ref = J->chain[loadop]; - while (ref > xref) { - IRIns *load = IR(ref); - if (load->op1 == xref) { /* Same xREF. */ - /* A nil load MAY alias, but a non-nil load MUST alias. */ - return !irt_isnil(load->t); - } /* Other non-nil loads MAY alias. */ - ref = load->prev; - } - return 0; /* Nothing derived at all, previous value MAY be nil. */ -} - -/* ------------------------------------------------------------------------ */ - -#undef IR -#undef fins -#undef fleft -#undef fright - -#endif diff --git a/lib/LuaJIT/src/lj_opt_narrow.c b/lib/LuaJIT/src/lj_opt_narrow.c deleted file mode 100644 index cd96ca4..0000000 --- a/lib/LuaJIT/src/lj_opt_narrow.c +++ /dev/null @@ -1,654 +0,0 @@ -/* -** NARROW: Narrowing of numbers to integers (double to int32_t). -** STRIPOV: Stripping of overflow checks. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_opt_narrow_c -#define LUA_CORE - -#include "lj_obj.h" - -#if LJ_HASJIT - -#include "lj_bc.h" -#include "lj_ir.h" -#include "lj_jit.h" -#include "lj_iropt.h" -#include "lj_trace.h" -#include "lj_vm.h" -#include "lj_strscan.h" - -/* Rationale for narrowing optimizations: -** -** Lua has only a single number type and this is a FP double by default. -** Narrowing doubles to integers does not pay off for the interpreter on a -** current-generation x86/x64 machine. Most FP operations need the same -** amount of execution resources as their integer counterparts, except -** with slightly longer latencies. Longer latencies are a non-issue for -** the interpreter, since they are usually hidden by other overhead. -** -** The total CPU execution bandwidth is the sum of the bandwidth of the FP -** and the integer units, because they execute in parallel. The FP units -** have an equal or higher bandwidth than the integer units. Not using -** them means losing execution bandwidth. Moving work away from them to -** the already quite busy integer units is a losing proposition. -** -** The situation for JIT-compiled code is a bit different: the higher code -** density makes the extra latencies much more visible. Tight loops expose -** the latencies for updating the induction variables. Array indexing -** requires narrowing conversions with high latencies and additional -** guards (to check that the index is really an integer). And many common -** optimizations only work on integers. -** -** One solution would be speculative, eager narrowing of all number loads. -** This causes many problems, like losing -0 or the need to resolve type -** mismatches between traces. It also effectively forces the integer type -** to have overflow-checking semantics. This impedes many basic -** optimizations and requires adding overflow checks to all integer -** arithmetic operations (whereas FP arithmetics can do without). -** -** Always replacing an FP op with an integer op plus an overflow check is -** counter-productive on a current-generation super-scalar CPU. Although -** the overflow check branches are highly predictable, they will clog the -** execution port for the branch unit and tie up reorder buffers. This is -** turning a pure data-flow dependency into a different data-flow -** dependency (with slightly lower latency) *plus* a control dependency. -** In general, you don't want to do this since latencies due to data-flow -** dependencies can be well hidden by out-of-order execution. -** -** A better solution is to keep all numbers as FP values and only narrow -** when it's beneficial to do so. LuaJIT uses predictive narrowing for -** induction variables and demand-driven narrowing for index expressions, -** integer arguments and bit operations. Additionally it can eliminate or -** hoist most of the resulting overflow checks. Regular arithmetic -** computations are never narrowed to integers. -** -** The integer type in the IR has convenient wrap-around semantics and -** ignores overflow. Extra operations have been added for -** overflow-checking arithmetic (ADDOV/SUBOV) instead of an extra type. -** Apart from reducing overall complexity of the compiler, this also -** nicely solves the problem where you want to apply algebraic -** simplifications to ADD, but not to ADDOV. And the x86/x64 assembler can -** use lea instead of an add for integer ADD, but not for ADDOV (lea does -** not affect the flags, but it helps to avoid register moves). -** -** -** All of the above has to be reconsidered for architectures with slow FP -** operations or without a hardware FPU. The dual-number mode of LuaJIT -** addresses this issue. Arithmetic operations are performed on integers -** as far as possible and overflow checks are added as needed. -** -** This implies that narrowing for integer arguments and bit operations -** should also strip overflow checks, e.g. replace ADDOV with ADD. The -** original overflow guards are weak and can be eliminated by DCE, if -** there's no other use. -** -** A slight twist is that it's usually beneficial to use overflow-checked -** integer arithmetics if all inputs are already integers. This is the only -** change that affects the single-number mode, too. -*/ - -/* Some local macros to save typing. Undef'd at the end. */ -#define IR(ref) (&J->cur.ir[(ref)]) -#define fins (&J->fold.ins) - -/* Pass IR on to next optimization in chain (FOLD). */ -#define emitir(ot, a, b) (lj_ir_set(J, (ot), (a), (b)), lj_opt_fold(J)) - -#define emitir_raw(ot, a, b) (lj_ir_set(J, (ot), (a), (b)), lj_ir_emit(J)) - -/* -- Elimination of narrowing type conversions --------------------------- */ - -/* Narrowing of index expressions and bit operations is demand-driven. The -** trace recorder emits a narrowing type conversion (CONV.int.num or TOBIT) -** in all of these cases (e.g. array indexing or string indexing). FOLD -** already takes care of eliminating simple redundant conversions like -** CONV.int.num(CONV.num.int(x)) ==> x. -** -** But the surrounding code is FP-heavy and arithmetic operations are -** performed on FP numbers (for the single-number mode). Consider a common -** example such as 'x=t[i+1]', with 'i' already an integer (due to induction -** variable narrowing). The index expression would be recorded as -** CONV.int.num(ADD(CONV.num.int(i), 1)) -** which is clearly suboptimal. -** -** One can do better by recursively backpropagating the narrowing type -** conversion across FP arithmetic operations. This turns FP ops into -** their corresponding integer counterparts. Depending on the semantics of -** the conversion they also need to check for overflow. Currently only ADD -** and SUB are supported. -** -** The above example can be rewritten as -** ADDOV(CONV.int.num(CONV.num.int(i)), 1) -** and then into ADDOV(i, 1) after folding of the conversions. The original -** FP ops remain in the IR and are eliminated by DCE since all references to -** them are gone. -** -** [In dual-number mode the trace recorder already emits ADDOV etc., but -** this can be further reduced. See below.] -** -** Special care has to be taken to avoid narrowing across an operation -** which is potentially operating on non-integral operands. One obvious -** case is when an expression contains a non-integral constant, but ends -** up as an integer index at runtime (like t[x+1.5] with x=0.5). -** -** Operations with two non-constant operands illustrate a similar problem -** (like t[a+b] with a=1.5 and b=2.5). Backpropagation has to stop there, -** unless it can be proven that either operand is integral (e.g. by CSEing -** a previous conversion). As a not-so-obvious corollary this logic also -** applies for a whole expression tree (e.g. t[(a+1)+(b+1)]). -** -** Correctness of the transformation is guaranteed by avoiding to expand -** the tree by adding more conversions than the one we would need to emit -** if not backpropagating. TOBIT employs a more optimistic rule, because -** the conversion has special semantics, designed to make the life of the -** compiler writer easier. ;-) -** -** Using on-the-fly backpropagation of an expression tree doesn't work -** because it's unknown whether the transform is correct until the end. -** This either requires IR rollback and cache invalidation for every -** subtree or a two-pass algorithm. The former didn't work out too well, -** so the code now combines a recursive collector with a stack-based -** emitter. -** -** [A recursive backpropagation algorithm with backtracking, employing -** skip-list lookup and round-robin caching, emitting stack operations -** on-the-fly for a stack-based interpreter -- and all of that in a meager -** kilobyte? Yep, compilers are a great treasure chest. Throw away your -** textbooks and read the codebase of a compiler today!] -** -** There's another optimization opportunity for array indexing: it's -** always accompanied by an array bounds-check. The outermost overflow -** check may be delegated to the ABC operation. This works because ABC is -** an unsigned comparison and wrap-around due to overflow creates negative -** numbers. -** -** But this optimization is only valid for constants that cannot overflow -** an int32_t into the range of valid array indexes [0..2^27+1). A check -** for +-2^30 is safe since -2^31 - 2^30 wraps to 2^30 and 2^31-1 + 2^30 -** wraps to -2^30-1. -** -** It's also good enough in practice, since e.g. t[i+1] or t[i-10] are -** quite common. So the above example finally ends up as ADD(i, 1)! -** -** Later on, the assembler is able to fuse the whole array reference and -** the ADD into the memory operands of loads and other instructions. This -** is why LuaJIT is able to generate very pretty (and fast) machine code -** for array indexing. And that, my dear, concludes another story about -** one of the hidden secrets of LuaJIT ... -*/ - -/* Maximum backpropagation depth and maximum stack size. */ -#define NARROW_MAX_BACKPROP 100 -#define NARROW_MAX_STACK 256 - -/* The stack machine has a 32 bit instruction format: [IROpT | IRRef1] -** The lower 16 bits hold a reference (or 0). The upper 16 bits hold -** the IR opcode + type or one of the following special opcodes: -*/ -enum { - NARROW_REF, /* Push ref. */ - NARROW_CONV, /* Push conversion of ref. */ - NARROW_SEXT, /* Push sign-extension of ref. */ - NARROW_INT /* Push KINT ref. The next code holds an int32_t. */ -}; - -typedef uint32_t NarrowIns; - -#define NARROWINS(op, ref) (((op) << 16) + (ref)) -#define narrow_op(ins) ((IROpT)((ins) >> 16)) -#define narrow_ref(ins) ((IRRef1)(ins)) - -/* Context used for narrowing of type conversions. */ -typedef struct NarrowConv { - jit_State *J; /* JIT compiler state. */ - NarrowIns *sp; /* Current stack pointer. */ - NarrowIns *maxsp; /* Maximum stack pointer minus redzone. */ - IRRef mode; /* Conversion mode (IRCONV_*). */ - IRType t; /* Destination type: IRT_INT or IRT_I64. */ - NarrowIns stack[NARROW_MAX_STACK]; /* Stack holding stack-machine code. */ -} NarrowConv; - -/* Lookup a reference in the backpropagation cache. */ -static BPropEntry *narrow_bpc_get(jit_State *J, IRRef1 key, IRRef mode) -{ - ptrdiff_t i; - for (i = 0; i < BPROP_SLOTS; i++) { - BPropEntry *bp = &J->bpropcache[i]; - /* Stronger checks are ok, too. */ - if (bp->key == key && bp->mode >= mode && - ((bp->mode ^ mode) & IRCONV_MODEMASK) == 0) - return bp; - } - return NULL; -} - -/* Add an entry to the backpropagation cache. */ -static void narrow_bpc_set(jit_State *J, IRRef1 key, IRRef1 val, IRRef mode) -{ - uint32_t slot = J->bpropslot; - BPropEntry *bp = &J->bpropcache[slot]; - J->bpropslot = (slot + 1) & (BPROP_SLOTS-1); - bp->key = key; - bp->val = val; - bp->mode = mode; -} - -/* Backpropagate overflow stripping. */ -static void narrow_stripov_backprop(NarrowConv *nc, IRRef ref, int depth) -{ - jit_State *J = nc->J; - IRIns *ir = IR(ref); - if (ir->o == IR_ADDOV || ir->o == IR_SUBOV || - (ir->o == IR_MULOV && (nc->mode & IRCONV_CONVMASK) == IRCONV_ANY)) { - BPropEntry *bp = narrow_bpc_get(nc->J, ref, IRCONV_TOBIT); - if (bp) { - ref = bp->val; - } else if (++depth < NARROW_MAX_BACKPROP && nc->sp < nc->maxsp) { - NarrowIns *savesp = nc->sp; - narrow_stripov_backprop(nc, ir->op1, depth); - if (nc->sp < nc->maxsp) { - narrow_stripov_backprop(nc, ir->op2, depth); - if (nc->sp < nc->maxsp) { - *nc->sp++ = NARROWINS(IRT(ir->o - IR_ADDOV + IR_ADD, IRT_INT), ref); - return; - } - } - nc->sp = savesp; /* Path too deep, need to backtrack. */ - } - } - *nc->sp++ = NARROWINS(NARROW_REF, ref); -} - -/* Backpropagate narrowing conversion. Return number of needed conversions. */ -static int narrow_conv_backprop(NarrowConv *nc, IRRef ref, int depth) -{ - jit_State *J = nc->J; - IRIns *ir = IR(ref); - IRRef cref; - - if (nc->sp >= nc->maxsp) return 10; /* Path too deep. */ - - /* Check the easy cases first. */ - if (ir->o == IR_CONV && (ir->op2 & IRCONV_SRCMASK) == IRT_INT) { - if ((nc->mode & IRCONV_CONVMASK) <= IRCONV_ANY) - narrow_stripov_backprop(nc, ir->op1, depth+1); - else - *nc->sp++ = NARROWINS(NARROW_REF, ir->op1); /* Undo conversion. */ - if (nc->t == IRT_I64) - *nc->sp++ = NARROWINS(NARROW_SEXT, 0); /* Sign-extend integer. */ - return 0; - } else if (ir->o == IR_KNUM) { /* Narrow FP constant. */ - lua_Number n = ir_knum(ir)->n; - if ((nc->mode & IRCONV_CONVMASK) == IRCONV_TOBIT) { - /* Allows a wider range of constants. */ - int64_t k64 = (int64_t)n; - if (n == (lua_Number)k64) { /* Only if const doesn't lose precision. */ - *nc->sp++ = NARROWINS(NARROW_INT, 0); - *nc->sp++ = (NarrowIns)k64; /* But always truncate to 32 bits. */ - return 0; - } - } else { - int32_t k = lj_num2int(n); - /* Only if constant is a small integer. */ - if (checki16(k) && n == (lua_Number)k) { - *nc->sp++ = NARROWINS(NARROW_INT, 0); - *nc->sp++ = (NarrowIns)k; - return 0; - } - } - return 10; /* Never narrow other FP constants (this is rare). */ - } - - /* Try to CSE the conversion. Stronger checks are ok, too. */ - cref = J->chain[fins->o]; - while (cref > ref) { - IRIns *cr = IR(cref); - if (cr->op1 == ref && - (fins->o == IR_TOBIT || - ((cr->op2 & IRCONV_MODEMASK) == (nc->mode & IRCONV_MODEMASK) && - irt_isguard(cr->t) >= irt_isguard(fins->t)))) { - *nc->sp++ = NARROWINS(NARROW_REF, cref); - return 0; /* Already there, no additional conversion needed. */ - } - cref = cr->prev; - } - - /* Backpropagate across ADD/SUB. */ - if (ir->o == IR_ADD || ir->o == IR_SUB) { - /* Try cache lookup first. */ - IRRef mode = nc->mode; - BPropEntry *bp; - /* Inner conversions need a stronger check. */ - if ((mode & IRCONV_CONVMASK) == IRCONV_INDEX && depth > 0) - mode += IRCONV_CHECK-IRCONV_INDEX; - bp = narrow_bpc_get(nc->J, (IRRef1)ref, mode); - if (bp) { - *nc->sp++ = NARROWINS(NARROW_REF, bp->val); - return 0; - } else if (nc->t == IRT_I64) { - /* Try sign-extending from an existing (checked) conversion to int. */ - mode = (IRT_INT<<5)|IRT_NUM|IRCONV_INDEX; - bp = narrow_bpc_get(nc->J, (IRRef1)ref, mode); - if (bp) { - *nc->sp++ = NARROWINS(NARROW_REF, bp->val); - *nc->sp++ = NARROWINS(NARROW_SEXT, 0); - return 0; - } - } - if (++depth < NARROW_MAX_BACKPROP && nc->sp < nc->maxsp) { - NarrowIns *savesp = nc->sp; - int count = narrow_conv_backprop(nc, ir->op1, depth); - count += narrow_conv_backprop(nc, ir->op2, depth); - if (count <= 1) { /* Limit total number of conversions. */ - *nc->sp++ = NARROWINS(IRT(ir->o, nc->t), ref); - return count; - } - nc->sp = savesp; /* Too many conversions, need to backtrack. */ - } - } - - /* Otherwise add a conversion. */ - *nc->sp++ = NARROWINS(NARROW_CONV, ref); - return 1; -} - -/* Emit the conversions collected during backpropagation. */ -static IRRef narrow_conv_emit(jit_State *J, NarrowConv *nc) -{ - /* The fins fields must be saved now -- emitir() overwrites them. */ - IROpT guardot = irt_isguard(fins->t) ? IRTG(IR_ADDOV-IR_ADD, 0) : 0; - IROpT convot = fins->ot; - IRRef1 convop2 = fins->op2; - NarrowIns *next = nc->stack; /* List of instructions from backpropagation. */ - NarrowIns *last = nc->sp; - NarrowIns *sp = nc->stack; /* Recycle the stack to store operands. */ - while (next < last) { /* Simple stack machine to process the ins. list. */ - NarrowIns ref = *next++; - IROpT op = narrow_op(ref); - if (op == NARROW_REF) { - *sp++ = ref; - } else if (op == NARROW_CONV) { - *sp++ = emitir_raw(convot, ref, convop2); /* Raw emit avoids a loop. */ - } else if (op == NARROW_SEXT) { - lua_assert(sp >= nc->stack+1); - sp[-1] = emitir(IRT(IR_CONV, IRT_I64), sp[-1], - (IRT_I64<<5)|IRT_INT|IRCONV_SEXT); - } else if (op == NARROW_INT) { - lua_assert(next < last); - *sp++ = nc->t == IRT_I64 ? - lj_ir_kint64(J, (int64_t)(int32_t)*next++) : - lj_ir_kint(J, *next++); - } else { /* Regular IROpT. Pops two operands and pushes one result. */ - IRRef mode = nc->mode; - lua_assert(sp >= nc->stack+2); - sp--; - /* Omit some overflow checks for array indexing. See comments above. */ - if ((mode & IRCONV_CONVMASK) == IRCONV_INDEX) { - if (next == last && irref_isk(narrow_ref(sp[0])) && - (uint32_t)IR(narrow_ref(sp[0]))->i + 0x40000000u < 0x80000000u) - guardot = 0; - else /* Otherwise cache a stronger check. */ - mode += IRCONV_CHECK-IRCONV_INDEX; - } - sp[-1] = emitir(op+guardot, sp[-1], sp[0]); - /* Add to cache. */ - if (narrow_ref(ref)) - narrow_bpc_set(J, narrow_ref(ref), narrow_ref(sp[-1]), mode); - } - } - lua_assert(sp == nc->stack+1); - return nc->stack[0]; -} - -/* Narrow a type conversion of an arithmetic operation. */ -TRef LJ_FASTCALL lj_opt_narrow_convert(jit_State *J) -{ - if ((J->flags & JIT_F_OPT_NARROW)) { - NarrowConv nc; - nc.J = J; - nc.sp = nc.stack; - nc.maxsp = &nc.stack[NARROW_MAX_STACK-4]; - nc.t = irt_type(fins->t); - if (fins->o == IR_TOBIT) { - nc.mode = IRCONV_TOBIT; /* Used only in the backpropagation cache. */ - } else { - nc.mode = fins->op2; - } - if (narrow_conv_backprop(&nc, fins->op1, 0) <= 1) - return narrow_conv_emit(J, &nc); - } - return NEXTFOLD; -} - -/* -- Narrowing of implicit conversions ----------------------------------- */ - -/* Recursively strip overflow checks. */ -static TRef narrow_stripov(jit_State *J, TRef tr, int lastop, IRRef mode) -{ - IRRef ref = tref_ref(tr); - IRIns *ir = IR(ref); - int op = ir->o; - if (op >= IR_ADDOV && op <= lastop) { - BPropEntry *bp = narrow_bpc_get(J, ref, mode); - if (bp) { - return TREF(bp->val, irt_t(IR(bp->val)->t)); - } else { - IRRef op1 = ir->op1, op2 = ir->op2; /* The IR may be reallocated. */ - op1 = narrow_stripov(J, op1, lastop, mode); - op2 = narrow_stripov(J, op2, lastop, mode); - tr = emitir(IRT(op - IR_ADDOV + IR_ADD, - ((mode & IRCONV_DSTMASK) >> IRCONV_DSH)), op1, op2); - narrow_bpc_set(J, ref, tref_ref(tr), mode); - } - } else if (LJ_64 && (mode & IRCONV_SEXT) && !irt_is64(ir->t)) { - tr = emitir(IRT(IR_CONV, IRT_INTP), tr, mode); - } - return tr; -} - -/* Narrow array index. */ -TRef LJ_FASTCALL lj_opt_narrow_index(jit_State *J, TRef tr) -{ - IRIns *ir; - lua_assert(tref_isnumber(tr)); - if (tref_isnum(tr)) /* Conversion may be narrowed, too. See above. */ - return emitir(IRTGI(IR_CONV), tr, IRCONV_INT_NUM|IRCONV_INDEX); - /* Omit some overflow checks for array indexing. See comments above. */ - ir = IR(tref_ref(tr)); - if ((ir->o == IR_ADDOV || ir->o == IR_SUBOV) && irref_isk(ir->op2) && - (uint32_t)IR(ir->op2)->i + 0x40000000u < 0x80000000u) - return emitir(IRTI(ir->o - IR_ADDOV + IR_ADD), ir->op1, ir->op2); - return tr; -} - -/* Narrow conversion to integer operand (overflow undefined). */ -TRef LJ_FASTCALL lj_opt_narrow_toint(jit_State *J, TRef tr) -{ - if (tref_isstr(tr)) - tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0); - if (tref_isnum(tr)) /* Conversion may be narrowed, too. See above. */ - return emitir(IRTI(IR_CONV), tr, IRCONV_INT_NUM|IRCONV_ANY); - if (!tref_isinteger(tr)) - lj_trace_err(J, LJ_TRERR_BADTYPE); - /* - ** Undefined overflow semantics allow stripping of ADDOV, SUBOV and MULOV. - ** Use IRCONV_TOBIT for the cache entries, since the semantics are the same. - */ - return narrow_stripov(J, tr, IR_MULOV, (IRT_INT<<5)|IRT_INT|IRCONV_TOBIT); -} - -/* Narrow conversion to bitop operand (overflow wrapped). */ -TRef LJ_FASTCALL lj_opt_narrow_tobit(jit_State *J, TRef tr) -{ - if (tref_isstr(tr)) - tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0); - if (tref_isnum(tr)) /* Conversion may be narrowed, too. See above. */ - return emitir(IRTI(IR_TOBIT), tr, lj_ir_knum_tobit(J)); - if (!tref_isinteger(tr)) - lj_trace_err(J, LJ_TRERR_BADTYPE); - /* - ** Wrapped overflow semantics allow stripping of ADDOV and SUBOV. - ** MULOV cannot be stripped due to precision widening. - */ - return narrow_stripov(J, tr, IR_SUBOV, (IRT_INT<<5)|IRT_INT|IRCONV_TOBIT); -} - -#if LJ_HASFFI -/* Narrow C array index (overflow undefined). */ -TRef LJ_FASTCALL lj_opt_narrow_cindex(jit_State *J, TRef tr) -{ - lua_assert(tref_isnumber(tr)); - if (tref_isnum(tr)) - return emitir(IRT(IR_CONV, IRT_INTP), tr, (IRT_INTP<<5)|IRT_NUM|IRCONV_ANY); - /* Undefined overflow semantics allow stripping of ADDOV, SUBOV and MULOV. */ - return narrow_stripov(J, tr, IR_MULOV, - LJ_64 ? ((IRT_INTP<<5)|IRT_INT|IRCONV_SEXT) : - ((IRT_INTP<<5)|IRT_INT|IRCONV_TOBIT)); -} -#endif - -/* -- Narrowing of arithmetic operators ----------------------------------- */ - -/* Check whether a number fits into an int32_t (-0 is ok, too). */ -static int numisint(lua_Number n) -{ - return (n == (lua_Number)lj_num2int(n)); -} - -/* Convert string to number. Error out for non-numeric string values. */ -static TRef conv_str_tonum(jit_State *J, TRef tr, TValue *o) -{ - if (tref_isstr(tr)) { - tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0); - /* Would need an inverted STRTO for this rare and useless case. */ - if (!lj_strscan_num(strV(o), o)) /* Convert in-place. Value used below. */ - lj_trace_err(J, LJ_TRERR_BADTYPE); /* Punt if non-numeric. */ - } - return tr; -} - -/* Narrowing of arithmetic operations. */ -TRef lj_opt_narrow_arith(jit_State *J, TRef rb, TRef rc, - TValue *vb, TValue *vc, IROp op) -{ - rb = conv_str_tonum(J, rb, vb); - rc = conv_str_tonum(J, rc, vc); - /* Must not narrow MUL in non-DUALNUM variant, because it loses -0. */ - if ((op >= IR_ADD && op <= (LJ_DUALNUM ? IR_MUL : IR_SUB)) && - tref_isinteger(rb) && tref_isinteger(rc) && - numisint(lj_vm_foldarith(numberVnum(vb), numberVnum(vc), - (int)op - (int)IR_ADD))) - return emitir(IRTGI((int)op - (int)IR_ADD + (int)IR_ADDOV), rb, rc); - if (!tref_isnum(rb)) rb = emitir(IRTN(IR_CONV), rb, IRCONV_NUM_INT); - if (!tref_isnum(rc)) rc = emitir(IRTN(IR_CONV), rc, IRCONV_NUM_INT); - return emitir(IRTN(op), rb, rc); -} - -/* Narrowing of unary minus operator. */ -TRef lj_opt_narrow_unm(jit_State *J, TRef rc, TValue *vc) -{ - rc = conv_str_tonum(J, rc, vc); - if (tref_isinteger(rc)) { - if ((uint32_t)numberVint(vc) != 0x80000000u) - return emitir(IRTGI(IR_SUBOV), lj_ir_kint(J, 0), rc); - rc = emitir(IRTN(IR_CONV), rc, IRCONV_NUM_INT); - } - return emitir(IRTN(IR_NEG), rc, lj_ir_ksimd(J, LJ_KSIMD_NEG)); -} - -/* Narrowing of modulo operator. */ -TRef lj_opt_narrow_mod(jit_State *J, TRef rb, TRef rc, TValue *vb, TValue *vc) -{ - TRef tmp; - rb = conv_str_tonum(J, rb, vb); - rc = conv_str_tonum(J, rc, vc); - if ((LJ_DUALNUM || (J->flags & JIT_F_OPT_NARROW)) && - tref_isinteger(rb) && tref_isinteger(rc) && - (tvisint(vc) ? intV(vc) != 0 : !tviszero(vc))) { - emitir(IRTGI(IR_NE), rc, lj_ir_kint(J, 0)); - return emitir(IRTI(IR_MOD), rb, rc); - } - /* b % c ==> b - floor(b/c)*c */ - rb = lj_ir_tonum(J, rb); - rc = lj_ir_tonum(J, rc); - tmp = emitir(IRTN(IR_DIV), rb, rc); - tmp = emitir(IRTN(IR_FPMATH), tmp, IRFPM_FLOOR); - tmp = emitir(IRTN(IR_MUL), tmp, rc); - return emitir(IRTN(IR_SUB), rb, tmp); -} - -/* Narrowing of power operator or math.pow. */ -TRef lj_opt_narrow_pow(jit_State *J, TRef rb, TRef rc, TValue *vb, TValue *vc) -{ - rb = conv_str_tonum(J, rb, vb); - rb = lj_ir_tonum(J, rb); /* Left arg is always treated as an FP number. */ - rc = conv_str_tonum(J, rc, vc); - /* Narrowing must be unconditional to preserve (-x)^i semantics. */ - if (tvisint(vc) || numisint(numV(vc))) { - int checkrange = 0; - /* Split pow is faster for bigger exponents. But do this only for (+k)^i. */ - if (tref_isk(rb) && (int32_t)ir_knum(IR(tref_ref(rb)))->u32.hi >= 0) { - int32_t k = numberVint(vc); - if (!(k >= -65536 && k <= 65536)) goto split_pow; - checkrange = 1; - } - if (!tref_isinteger(rc)) { - /* Guarded conversion to integer! */ - rc = emitir(IRTGI(IR_CONV), rc, IRCONV_INT_NUM|IRCONV_CHECK); - } - if (checkrange && !tref_isk(rc)) { /* Range guard: -65536 <= i <= 65536 */ - TRef tmp = emitir(IRTI(IR_ADD), rc, lj_ir_kint(J, 65536)); - emitir(IRTGI(IR_ULE), tmp, lj_ir_kint(J, 2*65536)); - } - return emitir(IRTN(IR_POW), rb, rc); - } -split_pow: - /* FOLD covers most cases, but some are easier to do here. */ - if (tref_isk(rb) && tvispone(ir_knum(IR(tref_ref(rb))))) - return rb; /* 1 ^ x ==> 1 */ - rc = lj_ir_tonum(J, rc); - if (tref_isk(rc) && ir_knum(IR(tref_ref(rc)))->n == 0.5) - return emitir(IRTN(IR_FPMATH), rb, IRFPM_SQRT); /* x ^ 0.5 ==> sqrt(x) */ - /* Split up b^c into exp2(c*log2(b)). Assembler may rejoin later. */ - rb = emitir(IRTN(IR_FPMATH), rb, IRFPM_LOG2); - rc = emitir(IRTN(IR_MUL), rb, rc); - return emitir(IRTN(IR_FPMATH), rc, IRFPM_EXP2); -} - -/* -- Predictive narrowing of induction variables ------------------------- */ - -/* Narrow a single runtime value. */ -static int narrow_forl(jit_State *J, cTValue *o) -{ - if (tvisint(o)) return 1; - if (LJ_DUALNUM || (J->flags & JIT_F_OPT_NARROW)) return numisint(numV(o)); - return 0; -} - -/* Narrow the FORL index type by looking at the runtime values. */ -IRType lj_opt_narrow_forl(jit_State *J, cTValue *tv) -{ - lua_assert(tvisnumber(&tv[FORL_IDX]) && - tvisnumber(&tv[FORL_STOP]) && - tvisnumber(&tv[FORL_STEP])); - /* Narrow only if the runtime values of start/stop/step are all integers. */ - if (narrow_forl(J, &tv[FORL_IDX]) && - narrow_forl(J, &tv[FORL_STOP]) && - narrow_forl(J, &tv[FORL_STEP])) { - /* And if the loop index can't possibly overflow. */ - lua_Number step = numberVnum(&tv[FORL_STEP]); - lua_Number sum = numberVnum(&tv[FORL_STOP]) + step; - if (0 <= step ? (sum <= 2147483647.0) : (sum >= -2147483648.0)) - return IRT_INT; - } - return IRT_NUM; -} - -#undef IR -#undef fins -#undef emitir -#undef emitir_raw - -#endif diff --git a/lib/LuaJIT/src/lj_opt_sink.c b/lib/LuaJIT/src/lj_opt_sink.c deleted file mode 100644 index c16363e..0000000 --- a/lib/LuaJIT/src/lj_opt_sink.c +++ /dev/null @@ -1,251 +0,0 @@ -/* -** SINK: Allocation Sinking and Store Sinking. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_opt_sink_c -#define LUA_CORE - -#include "lj_obj.h" - -#if LJ_HASJIT - -#include "lj_ir.h" -#include "lj_jit.h" -#include "lj_iropt.h" -#include "lj_target.h" - -/* Some local macros to save typing. Undef'd at the end. */ -#define IR(ref) (&J->cur.ir[(ref)]) - -/* Check whether the store ref points to an eligible allocation. */ -static IRIns *sink_checkalloc(jit_State *J, IRIns *irs) -{ - IRIns *ir = IR(irs->op1); - if (!irref_isk(ir->op2)) - return NULL; /* Non-constant key. */ - if (ir->o == IR_HREFK || ir->o == IR_AREF) - ir = IR(ir->op1); - else if (!(ir->o == IR_HREF || ir->o == IR_NEWREF || - ir->o == IR_FREF || ir->o == IR_ADD)) - return NULL; /* Unhandled reference type (for XSTORE). */ - ir = IR(ir->op1); - if (!(ir->o == IR_TNEW || ir->o == IR_TDUP || ir->o == IR_CNEW)) - return NULL; /* Not an allocation. */ - return ir; /* Return allocation. */ -} - -/* Recursively check whether a value depends on a PHI. */ -static int sink_phidep(jit_State *J, IRRef ref) -{ - IRIns *ir = IR(ref); - if (irt_isphi(ir->t)) return 1; - if (ir->op1 >= REF_FIRST && sink_phidep(J, ir->op1)) return 1; - if (ir->op2 >= REF_FIRST && sink_phidep(J, ir->op2)) return 1; - return 0; -} - -/* Check whether a value is a sinkable PHI or loop-invariant. */ -static int sink_checkphi(jit_State *J, IRIns *ira, IRRef ref) -{ - if (ref >= REF_FIRST) { - IRIns *ir = IR(ref); - if (irt_isphi(ir->t) || (ir->o == IR_CONV && ir->op2 == IRCONV_NUM_INT && - irt_isphi(IR(ir->op1)->t))) { - ira->prev++; - return 1; /* Sinkable PHI. */ - } - /* Otherwise the value must be loop-invariant. */ - return ref < J->loopref && !sink_phidep(J, ref); - } - return 1; /* Constant (non-PHI). */ -} - -/* Mark non-sinkable allocations using single-pass backward propagation. -** -** Roots for the marking process are: -** - Some PHIs or snapshots (see below). -** - Non-PHI, non-constant values stored to PHI allocations. -** - All guards. -** - Any remaining loads not eliminated by store-to-load forwarding. -** - Stores with non-constant keys. -** - All stored values. -*/ -static void sink_mark_ins(jit_State *J) -{ - IRIns *ir, *irlast = IR(J->cur.nins-1); - for (ir = irlast ; ; ir--) { - switch (ir->o) { - case IR_BASE: - return; /* Finished. */ - case IR_CALLL: /* IRCALL_lj_tab_len */ - case IR_ALOAD: case IR_HLOAD: case IR_XLOAD: case IR_TBAR: - irt_setmark(IR(ir->op1)->t); /* Mark ref for remaining loads. */ - break; - case IR_FLOAD: - if (irt_ismarked(ir->t) || ir->op2 == IRFL_TAB_META) - irt_setmark(IR(ir->op1)->t); /* Mark table for remaining loads. */ - break; - case IR_ASTORE: case IR_HSTORE: case IR_FSTORE: case IR_XSTORE: { - IRIns *ira = sink_checkalloc(J, ir); - if (!ira || (irt_isphi(ira->t) && !sink_checkphi(J, ira, ir->op2))) - irt_setmark(IR(ir->op1)->t); /* Mark ineligible ref. */ - irt_setmark(IR(ir->op2)->t); /* Mark stored value. */ - break; - } -#if LJ_HASFFI - case IR_CNEWI: - if (irt_isphi(ir->t) && - (!sink_checkphi(J, ir, ir->op2) || - (LJ_32 && ir+1 < irlast && (ir+1)->o == IR_HIOP && - !sink_checkphi(J, ir, (ir+1)->op2)))) - irt_setmark(ir->t); /* Mark ineligible allocation. */ -#endif - /* fallthrough */ - case IR_USTORE: - irt_setmark(IR(ir->op2)->t); /* Mark stored value. */ - break; -#if LJ_HASFFI - case IR_CALLXS: -#endif - case IR_CALLS: - irt_setmark(IR(ir->op1)->t); /* Mark (potentially) stored values. */ - break; - case IR_PHI: { - IRIns *irl = IR(ir->op1), *irr = IR(ir->op2); - irl->prev = irr->prev = 0; /* Clear PHI value counts. */ - if (irl->o == irr->o && - (irl->o == IR_TNEW || irl->o == IR_TDUP || - (LJ_HASFFI && (irl->o == IR_CNEW || irl->o == IR_CNEWI)))) - break; - irt_setmark(irl->t); - irt_setmark(irr->t); - break; - } - default: - if (irt_ismarked(ir->t) || irt_isguard(ir->t)) { /* Propagate mark. */ - if (ir->op1 >= REF_FIRST) irt_setmark(IR(ir->op1)->t); - if (ir->op2 >= REF_FIRST) irt_setmark(IR(ir->op2)->t); - } - break; - } - } -} - -/* Mark all instructions referenced by a snapshot. */ -static void sink_mark_snap(jit_State *J, SnapShot *snap) -{ - SnapEntry *map = &J->cur.snapmap[snap->mapofs]; - MSize n, nent = snap->nent; - for (n = 0; n < nent; n++) { - IRRef ref = snap_ref(map[n]); - if (!irref_isk(ref)) - irt_setmark(IR(ref)->t); - } -} - -/* Iteratively remark PHI refs with differing marks or PHI value counts. */ -static void sink_remark_phi(jit_State *J) -{ - IRIns *ir; - int remark; - do { - remark = 0; - for (ir = IR(J->cur.nins-1); ir->o == IR_PHI; ir--) { - IRIns *irl = IR(ir->op1), *irr = IR(ir->op2); - if (!((irl->t.irt ^ irr->t.irt) & IRT_MARK) && irl->prev == irr->prev) - continue; - remark |= (~(irl->t.irt & irr->t.irt) & IRT_MARK); - irt_setmark(IR(ir->op1)->t); - irt_setmark(IR(ir->op2)->t); - } - } while (remark); -} - -/* Sweep instructions and tag sunken allocations and stores. */ -static void sink_sweep_ins(jit_State *J) -{ - IRIns *ir, *irbase = IR(REF_BASE); - for (ir = IR(J->cur.nins-1) ; ir >= irbase; ir--) { - switch (ir->o) { - case IR_ASTORE: case IR_HSTORE: case IR_FSTORE: case IR_XSTORE: { - IRIns *ira = sink_checkalloc(J, ir); - if (ira && !irt_ismarked(ira->t)) { - int delta = (int)(ir - ira); - ir->prev = REGSP(RID_SINK, delta > 255 ? 255 : delta); - } else { - ir->prev = REGSP_INIT; - } - break; - } - case IR_NEWREF: - if (!irt_ismarked(IR(ir->op1)->t)) { - ir->prev = REGSP(RID_SINK, 0); - } else { - irt_clearmark(ir->t); - ir->prev = REGSP_INIT; - } - break; -#if LJ_HASFFI - case IR_CNEW: case IR_CNEWI: -#endif - case IR_TNEW: case IR_TDUP: - if (!irt_ismarked(ir->t)) { - ir->t.irt &= ~IRT_GUARD; - ir->prev = REGSP(RID_SINK, 0); - J->cur.sinktags = 1; /* Signal present SINK tags to assembler. */ - } else { - irt_clearmark(ir->t); - ir->prev = REGSP_INIT; - } - break; - case IR_PHI: { - IRIns *ira = IR(ir->op2); - if (!irt_ismarked(ira->t) && - (ira->o == IR_TNEW || ira->o == IR_TDUP || - (LJ_HASFFI && (ira->o == IR_CNEW || ira->o == IR_CNEWI)))) { - ir->prev = REGSP(RID_SINK, 0); - } else { - ir->prev = REGSP_INIT; - } - break; - } - default: - irt_clearmark(ir->t); - ir->prev = REGSP_INIT; - break; - } - } - for (ir = IR(J->cur.nk); ir < irbase; ir++) { - irt_clearmark(ir->t); - ir->prev = REGSP_INIT; - /* The false-positive of irt_is64() for ASMREF_L (REF_NIL) is OK here. */ - if (irt_is64(ir->t) && ir->o != IR_KNULL) - ir++; - } -} - -/* Allocation sinking and store sinking. -** -** 1. Mark all non-sinkable allocations. -** 2. Then sink all remaining allocations and the related stores. -*/ -void lj_opt_sink(jit_State *J) -{ - const uint32_t need = (JIT_F_OPT_SINK|JIT_F_OPT_FWD| - JIT_F_OPT_DCE|JIT_F_OPT_CSE|JIT_F_OPT_FOLD); - if ((J->flags & need) == need && - (J->chain[IR_TNEW] || J->chain[IR_TDUP] || - (LJ_HASFFI && (J->chain[IR_CNEW] || J->chain[IR_CNEWI])))) { - if (!J->loopref) - sink_mark_snap(J, &J->cur.snap[J->cur.nsnap-1]); - sink_mark_ins(J); - if (J->loopref) - sink_remark_phi(J); - sink_sweep_ins(J); - } -} - -#undef IR - -#endif diff --git a/lib/LuaJIT/src/lj_opt_split.c b/lib/LuaJIT/src/lj_opt_split.c deleted file mode 100644 index 79ac3cc..0000000 --- a/lib/LuaJIT/src/lj_opt_split.c +++ /dev/null @@ -1,870 +0,0 @@ -/* -** SPLIT: Split 64 bit IR instructions into 32 bit IR instructions. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_opt_split_c -#define LUA_CORE - -#include "lj_obj.h" - -#if LJ_HASJIT && (LJ_SOFTFP32 || (LJ_32 && LJ_HASFFI)) - -#include "lj_err.h" -#include "lj_buf.h" -#include "lj_ir.h" -#include "lj_jit.h" -#include "lj_ircall.h" -#include "lj_iropt.h" -#include "lj_dispatch.h" -#include "lj_vm.h" - -/* SPLIT pass: -** -** This pass splits up 64 bit IR instructions into multiple 32 bit IR -** instructions. It's only active for soft-float targets or for 32 bit CPUs -** which lack native 64 bit integer operations (the FFI is currently the -** only emitter for 64 bit integer instructions). -** -** Splitting the IR in a separate pass keeps each 32 bit IR assembler -** backend simple. Only a small amount of extra functionality needs to be -** implemented. This is much easier than adding support for allocating -** register pairs to each backend (believe me, I tried). A few simple, but -** important optimizations can be performed by the SPLIT pass, which would -** be tedious to do in the backend. -** -** The basic idea is to replace each 64 bit IR instruction with its 32 bit -** equivalent plus an extra HIOP instruction. The splitted IR is not passed -** through FOLD or any other optimizations, so each HIOP is guaranteed to -** immediately follow it's counterpart. The actual functionality of HIOP is -** inferred from the previous instruction. -** -** The operands of HIOP hold the hiword input references. The output of HIOP -** is the hiword output reference, which is also used to hold the hiword -** register or spill slot information. The register allocator treats this -** instruction independently of any other instruction, which improves code -** quality compared to using fixed register pairs. -** -** It's easier to split up some instructions into two regular 32 bit -** instructions. E.g. XLOAD is split up into two XLOADs with two different -** addresses. Obviously 64 bit constants need to be split up into two 32 bit -** constants, too. Some hiword instructions can be entirely omitted, e.g. -** when zero-extending a 32 bit value to 64 bits. 64 bit arguments for calls -** are split up into two 32 bit arguments each. -** -** On soft-float targets, floating-point instructions are directly converted -** to soft-float calls by the SPLIT pass (except for comparisons and MIN/MAX). -** HIOP for number results has the type IRT_SOFTFP ("sfp" in -jdump). -** -** Here's the IR and x64 machine code for 'x.b = x.a + 1' for a struct with -** two int64_t fields: -** -** 0100 p32 ADD base +8 -** 0101 i64 XLOAD 0100 -** 0102 i64 ADD 0101 +1 -** 0103 p32 ADD base +16 -** 0104 i64 XSTORE 0103 0102 -** -** mov rax, [esi+0x8] -** add rax, +0x01 -** mov [esi+0x10], rax -** -** Here's the transformed IR and the x86 machine code after the SPLIT pass: -** -** 0100 p32 ADD base +8 -** 0101 int XLOAD 0100 -** 0102 p32 ADD base +12 -** 0103 int XLOAD 0102 -** 0104 int ADD 0101 +1 -** 0105 int HIOP 0103 +0 -** 0106 p32 ADD base +16 -** 0107 int XSTORE 0106 0104 -** 0108 int HIOP 0106 0105 -** -** mov eax, [esi+0x8] -** mov ecx, [esi+0xc] -** add eax, +0x01 -** adc ecx, +0x00 -** mov [esi+0x10], eax -** mov [esi+0x14], ecx -** -** You may notice the reassociated hiword address computation, which is -** later fused into the mov operands by the assembler. -*/ - -/* Some local macros to save typing. Undef'd at the end. */ -#define IR(ref) (&J->cur.ir[(ref)]) - -/* Directly emit the transformed IR without updating chains etc. */ -static IRRef split_emit(jit_State *J, uint16_t ot, IRRef1 op1, IRRef1 op2) -{ - IRRef nref = lj_ir_nextins(J); - IRIns *ir = IR(nref); - ir->ot = ot; - ir->op1 = op1; - ir->op2 = op2; - return nref; -} - -#if LJ_SOFTFP -/* Emit a (checked) number to integer conversion. */ -static IRRef split_num2int(jit_State *J, IRRef lo, IRRef hi, int check) -{ - IRRef tmp, res; -#if LJ_LE - tmp = split_emit(J, IRT(IR_CARG, IRT_NIL), lo, hi); -#else - tmp = split_emit(J, IRT(IR_CARG, IRT_NIL), hi, lo); -#endif - res = split_emit(J, IRTI(IR_CALLN), tmp, IRCALL_softfp_d2i); - if (check) { - tmp = split_emit(J, IRTI(IR_CALLN), res, IRCALL_softfp_i2d); - split_emit(J, IRT(IR_HIOP, IRT_SOFTFP), tmp, tmp); - split_emit(J, IRTGI(IR_EQ), tmp, lo); - split_emit(J, IRTG(IR_HIOP, IRT_SOFTFP), tmp+1, hi); - } - return res; -} - -/* Emit a CALLN with one split 64 bit argument. */ -static IRRef split_call_l(jit_State *J, IRRef1 *hisubst, IRIns *oir, - IRIns *ir, IRCallID id) -{ - IRRef tmp, op1 = ir->op1; - J->cur.nins--; -#if LJ_LE - tmp = split_emit(J, IRT(IR_CARG, IRT_NIL), oir[op1].prev, hisubst[op1]); -#else - tmp = split_emit(J, IRT(IR_CARG, IRT_NIL), hisubst[op1], oir[op1].prev); -#endif - ir->prev = tmp = split_emit(J, IRTI(IR_CALLN), tmp, id); - return split_emit(J, IRT(IR_HIOP, IRT_SOFTFP), tmp, tmp); -} -#endif - -/* Emit a CALLN with one split 64 bit argument and a 32 bit argument. */ -static IRRef split_call_li(jit_State *J, IRRef1 *hisubst, IRIns *oir, - IRIns *ir, IRCallID id) -{ - IRRef tmp, op1 = ir->op1, op2 = ir->op2; - J->cur.nins--; -#if LJ_LE - tmp = split_emit(J, IRT(IR_CARG, IRT_NIL), oir[op1].prev, hisubst[op1]); -#else - tmp = split_emit(J, IRT(IR_CARG, IRT_NIL), hisubst[op1], oir[op1].prev); -#endif - tmp = split_emit(J, IRT(IR_CARG, IRT_NIL), tmp, oir[op2].prev); - ir->prev = tmp = split_emit(J, IRTI(IR_CALLN), tmp, id); - return split_emit(J, IRT(IR_HIOP, IRT_SOFTFP), tmp, tmp); -} - -/* Emit a CALLN with two split 64 bit arguments. */ -static IRRef split_call_ll(jit_State *J, IRRef1 *hisubst, IRIns *oir, - IRIns *ir, IRCallID id) -{ - IRRef tmp, op1 = ir->op1, op2 = ir->op2; - J->cur.nins--; -#if LJ_LE - tmp = split_emit(J, IRT(IR_CARG, IRT_NIL), oir[op1].prev, hisubst[op1]); - tmp = split_emit(J, IRT(IR_CARG, IRT_NIL), tmp, oir[op2].prev); - tmp = split_emit(J, IRT(IR_CARG, IRT_NIL), tmp, hisubst[op2]); -#else - tmp = split_emit(J, IRT(IR_CARG, IRT_NIL), hisubst[op1], oir[op1].prev); - tmp = split_emit(J, IRT(IR_CARG, IRT_NIL), tmp, hisubst[op2]); - tmp = split_emit(J, IRT(IR_CARG, IRT_NIL), tmp, oir[op2].prev); -#endif - ir->prev = tmp = split_emit(J, IRTI(IR_CALLN), tmp, id); - return split_emit(J, - IRT(IR_HIOP, (LJ_SOFTFP && irt_isnum(ir->t)) ? IRT_SOFTFP : IRT_INT), - tmp, tmp); -} - -/* Get a pointer to the other 32 bit word (LE: hiword, BE: loword). */ -static IRRef split_ptr(jit_State *J, IRIns *oir, IRRef ref) -{ - IRRef nref = oir[ref].prev; - IRIns *ir = IR(nref); - int32_t ofs = 4; - if (ir->o == IR_KPTR) - return lj_ir_kptr(J, (char *)ir_kptr(ir) + ofs); - if (ir->o == IR_ADD && irref_isk(ir->op2) && !irt_isphi(oir[ref].t)) { - /* Reassociate address. */ - ofs += IR(ir->op2)->i; - nref = ir->op1; - if (ofs == 0) return nref; - } - return split_emit(J, IRT(IR_ADD, IRT_PTR), nref, lj_ir_kint(J, ofs)); -} - -#if LJ_HASFFI -static IRRef split_bitshift(jit_State *J, IRRef1 *hisubst, - IRIns *oir, IRIns *nir, IRIns *ir) -{ - IROp op = ir->o; - IRRef kref = nir->op2; - if (irref_isk(kref)) { /* Optimize constant shifts. */ - int32_t k = (IR(kref)->i & 63); - IRRef lo = nir->op1, hi = hisubst[ir->op1]; - if (op == IR_BROL || op == IR_BROR) { - if (op == IR_BROR) k = (-k & 63); - if (k >= 32) { IRRef t = lo; lo = hi; hi = t; k -= 32; } - if (k == 0) { - passthrough: - J->cur.nins--; - ir->prev = lo; - return hi; - } else { - TRef k1, k2; - IRRef t1, t2, t3, t4; - J->cur.nins--; - k1 = lj_ir_kint(J, k); - k2 = lj_ir_kint(J, (-k & 31)); - t1 = split_emit(J, IRTI(IR_BSHL), lo, k1); - t2 = split_emit(J, IRTI(IR_BSHL), hi, k1); - t3 = split_emit(J, IRTI(IR_BSHR), lo, k2); - t4 = split_emit(J, IRTI(IR_BSHR), hi, k2); - ir->prev = split_emit(J, IRTI(IR_BOR), t1, t4); - return split_emit(J, IRTI(IR_BOR), t2, t3); - } - } else if (k == 0) { - goto passthrough; - } else if (k < 32) { - if (op == IR_BSHL) { - IRRef t1 = split_emit(J, IRTI(IR_BSHL), hi, kref); - IRRef t2 = split_emit(J, IRTI(IR_BSHR), lo, lj_ir_kint(J, (-k&31))); - return split_emit(J, IRTI(IR_BOR), t1, t2); - } else { - IRRef t1 = ir->prev, t2; - lua_assert(op == IR_BSHR || op == IR_BSAR); - nir->o = IR_BSHR; - t2 = split_emit(J, IRTI(IR_BSHL), hi, lj_ir_kint(J, (-k&31))); - ir->prev = split_emit(J, IRTI(IR_BOR), t1, t2); - return split_emit(J, IRTI(op), hi, kref); - } - } else { - if (op == IR_BSHL) { - if (k == 32) - J->cur.nins--; - else - lo = ir->prev; - ir->prev = lj_ir_kint(J, 0); - return lo; - } else { - lua_assert(op == IR_BSHR || op == IR_BSAR); - if (k == 32) { - J->cur.nins--; - ir->prev = hi; - } else { - nir->op1 = hi; - } - if (op == IR_BSHR) - return lj_ir_kint(J, 0); - else - return split_emit(J, IRTI(IR_BSAR), hi, lj_ir_kint(J, 31)); - } - } - } - return split_call_li(J, hisubst, oir, ir, - op - IR_BSHL + IRCALL_lj_carith_shl64); -} - -static IRRef split_bitop(jit_State *J, IRRef1 *hisubst, - IRIns *nir, IRIns *ir) -{ - IROp op = ir->o; - IRRef hi, kref = nir->op2; - if (irref_isk(kref)) { /* Optimize bit operations with lo constant. */ - int32_t k = IR(kref)->i; - if (k == 0 || k == -1) { - if (op == IR_BAND) k = ~k; - if (k == 0) { - J->cur.nins--; - ir->prev = nir->op1; - } else if (op == IR_BXOR) { - nir->o = IR_BNOT; - nir->op2 = 0; - } else { - J->cur.nins--; - ir->prev = kref; - } - } - } - hi = hisubst[ir->op1]; - kref = hisubst[ir->op2]; - if (irref_isk(kref)) { /* Optimize bit operations with hi constant. */ - int32_t k = IR(kref)->i; - if (k == 0 || k == -1) { - if (op == IR_BAND) k = ~k; - if (k == 0) { - return hi; - } else if (op == IR_BXOR) { - return split_emit(J, IRTI(IR_BNOT), hi, 0); - } else { - return kref; - } - } - } - return split_emit(J, IRTI(op), hi, kref); -} -#endif - -/* Substitute references of a snapshot. */ -static void split_subst_snap(jit_State *J, SnapShot *snap, IRIns *oir) -{ - SnapEntry *map = &J->cur.snapmap[snap->mapofs]; - MSize n, nent = snap->nent; - for (n = 0; n < nent; n++) { - SnapEntry sn = map[n]; - IRIns *ir = &oir[snap_ref(sn)]; - if (!(LJ_SOFTFP && (sn & SNAP_SOFTFPNUM) && irref_isk(snap_ref(sn)))) - map[n] = ((sn & 0xffff0000) | ir->prev); - } -} - -/* Transform the old IR to the new IR. */ -static void split_ir(jit_State *J) -{ - IRRef nins = J->cur.nins, nk = J->cur.nk; - MSize irlen = nins - nk; - MSize need = (irlen+1)*(sizeof(IRIns) + sizeof(IRRef1)); - IRIns *oir = (IRIns *)lj_buf_tmp(J->L, need); - IRRef1 *hisubst; - IRRef ref, snref; - SnapShot *snap; - - /* Copy old IR to buffer. */ - memcpy(oir, IR(nk), irlen*sizeof(IRIns)); - /* Bias hiword substitution table and old IR. Loword kept in field prev. */ - hisubst = (IRRef1 *)&oir[irlen] - nk; - oir -= nk; - - /* Remove all IR instructions, but retain IR constants. */ - J->cur.nins = REF_FIRST; - J->loopref = 0; - - /* Process constants and fixed references. */ - for (ref = nk; ref <= REF_BASE; ref++) { - IRIns *ir = &oir[ref]; - if ((LJ_SOFTFP && ir->o == IR_KNUM) || ir->o == IR_KINT64) { - /* Split up 64 bit constant. */ - TValue tv = *ir_k64(ir); - ir->prev = lj_ir_kint(J, (int32_t)tv.u32.lo); - hisubst[ref] = lj_ir_kint(J, (int32_t)tv.u32.hi); - } else { - ir->prev = ref; /* Identity substitution for loword. */ - hisubst[ref] = 0; - } - if (irt_is64(ir->t) && ir->o != IR_KNULL) - ref++; - } - - /* Process old IR instructions. */ - snap = J->cur.snap; - snref = snap->ref; - for (ref = REF_FIRST; ref < nins; ref++) { - IRIns *ir = &oir[ref]; - IRRef nref = lj_ir_nextins(J); - IRIns *nir = IR(nref); - IRRef hi = 0; - - if (ref >= snref) { - snap->ref = nref; - split_subst_snap(J, snap++, oir); - snref = snap < &J->cur.snap[J->cur.nsnap] ? snap->ref : ~(IRRef)0; - } - - /* Copy-substitute old instruction to new instruction. */ - nir->op1 = ir->op1 < nk ? ir->op1 : oir[ir->op1].prev; - nir->op2 = ir->op2 < nk ? ir->op2 : oir[ir->op2].prev; - ir->prev = nref; /* Loword substitution. */ - nir->o = ir->o; - nir->t.irt = ir->t.irt & ~(IRT_MARK|IRT_ISPHI); - hisubst[ref] = 0; - - /* Split 64 bit instructions. */ -#if LJ_SOFTFP - if (irt_isnum(ir->t)) { - nir->t.irt = IRT_INT | (nir->t.irt & IRT_GUARD); /* Turn into INT op. */ - /* Note: hi ref = lo ref + 1! Required for SNAP_SOFTFPNUM logic. */ - switch (ir->o) { - case IR_ADD: - hi = split_call_ll(J, hisubst, oir, ir, IRCALL_softfp_add); - break; - case IR_SUB: - hi = split_call_ll(J, hisubst, oir, ir, IRCALL_softfp_sub); - break; - case IR_MUL: - hi = split_call_ll(J, hisubst, oir, ir, IRCALL_softfp_mul); - break; - case IR_DIV: - hi = split_call_ll(J, hisubst, oir, ir, IRCALL_softfp_div); - break; - case IR_POW: - hi = split_call_li(J, hisubst, oir, ir, IRCALL_lj_vm_powi); - break; - case IR_FPMATH: - /* Try to rejoin pow from EXP2, MUL and LOG2. */ - if (nir->op2 == IRFPM_EXP2 && nir->op1 > J->loopref) { - IRIns *irp = IR(nir->op1); - if (irp->o == IR_CALLN && irp->op2 == IRCALL_softfp_mul) { - IRIns *irm4 = IR(irp->op1); - IRIns *irm3 = IR(irm4->op1); - IRIns *irm12 = IR(irm3->op1); - IRIns *irl1 = IR(irm12->op1); - if (irm12->op1 > J->loopref && irl1->o == IR_CALLN && - irl1->op2 == IRCALL_lj_vm_log2) { - IRRef tmp = irl1->op1; /* Recycle first two args from LOG2. */ - IRRef arg3 = irm3->op2, arg4 = irm4->op2; - J->cur.nins--; - tmp = split_emit(J, IRT(IR_CARG, IRT_NIL), tmp, arg3); - tmp = split_emit(J, IRT(IR_CARG, IRT_NIL), tmp, arg4); - ir->prev = tmp = split_emit(J, IRTI(IR_CALLN), tmp, IRCALL_pow); - hi = split_emit(J, IRT(IR_HIOP, IRT_SOFTFP), tmp, tmp); - break; - } - } - } - hi = split_call_l(J, hisubst, oir, ir, IRCALL_lj_vm_floor + ir->op2); - break; - case IR_ATAN2: - hi = split_call_ll(J, hisubst, oir, ir, IRCALL_atan2); - break; - case IR_LDEXP: - hi = split_call_li(J, hisubst, oir, ir, IRCALL_ldexp); - break; - case IR_NEG: case IR_ABS: - nir->o = IR_CONV; /* Pass through loword. */ - nir->op2 = (IRT_INT << 5) | IRT_INT; - hi = split_emit(J, IRT(ir->o == IR_NEG ? IR_BXOR : IR_BAND, IRT_SOFTFP), - hisubst[ir->op1], - lj_ir_kint(J, (int32_t)(0x7fffffffu + (ir->o == IR_NEG)))); - break; - case IR_SLOAD: - if ((nir->op2 & IRSLOAD_CONVERT)) { /* Convert from int to number. */ - nir->op2 &= ~IRSLOAD_CONVERT; - ir->prev = nref = split_emit(J, IRTI(IR_CALLN), nref, - IRCALL_softfp_i2d); - hi = split_emit(J, IRT(IR_HIOP, IRT_SOFTFP), nref, nref); - break; - } - /* fallthrough */ - case IR_ALOAD: case IR_HLOAD: case IR_ULOAD: case IR_VLOAD: - case IR_STRTO: - hi = split_emit(J, IRT(IR_HIOP, IRT_SOFTFP), nref, nref); - break; - case IR_FLOAD: - lua_assert(ir->op1 == REF_NIL); - hi = lj_ir_kint(J, *(int32_t*)((char*)J2GG(J) + ir->op2 + LJ_LE*4)); - nir->op2 += LJ_BE*4; - break; - case IR_XLOAD: { - IRIns inslo = *nir; /* Save/undo the emit of the lo XLOAD. */ - J->cur.nins--; - hi = split_ptr(J, oir, ir->op1); /* Insert the hiref ADD. */ -#if LJ_BE - hi = split_emit(J, IRT(IR_XLOAD, IRT_INT), hi, ir->op2); - inslo.t.irt = IRT_SOFTFP | (inslo.t.irt & IRT_GUARD); -#endif - nref = lj_ir_nextins(J); - nir = IR(nref); - *nir = inslo; /* Re-emit lo XLOAD. */ -#if LJ_LE - hi = split_emit(J, IRT(IR_XLOAD, IRT_SOFTFP), hi, ir->op2); - ir->prev = nref; -#else - ir->prev = hi; hi = nref; -#endif - break; - } - case IR_ASTORE: case IR_HSTORE: case IR_USTORE: case IR_XSTORE: - split_emit(J, IRT(IR_HIOP, IRT_SOFTFP), nir->op1, hisubst[ir->op2]); - break; - case IR_CONV: { /* Conversion to number. Others handled below. */ - IRType st = (IRType)(ir->op2 & IRCONV_SRCMASK); - UNUSED(st); -#if LJ_32 && LJ_HASFFI - if (st == IRT_I64 || st == IRT_U64) { - hi = split_call_l(J, hisubst, oir, ir, - st == IRT_I64 ? IRCALL_fp64_l2d : IRCALL_fp64_ul2d); - break; - } -#endif - lua_assert(st == IRT_INT || - (LJ_32 && LJ_HASFFI && (st == IRT_U32 || st == IRT_FLOAT))); - nir->o = IR_CALLN; -#if LJ_32 && LJ_HASFFI - nir->op2 = st == IRT_INT ? IRCALL_softfp_i2d : - st == IRT_FLOAT ? IRCALL_softfp_f2d : - IRCALL_softfp_ui2d; -#else - nir->op2 = IRCALL_softfp_i2d; -#endif - hi = split_emit(J, IRT(IR_HIOP, IRT_SOFTFP), nref, nref); - break; - } - case IR_CALLN: - case IR_CALLL: - case IR_CALLS: - case IR_CALLXS: - goto split_call; - case IR_PHI: - if (nir->op1 == nir->op2) - J->cur.nins--; /* Drop useless PHIs. */ - if (hisubst[ir->op1] != hisubst[ir->op2]) - split_emit(J, IRT(IR_PHI, IRT_SOFTFP), - hisubst[ir->op1], hisubst[ir->op2]); - break; - case IR_HIOP: - J->cur.nins--; /* Drop joining HIOP. */ - ir->prev = nir->op1; - hi = nir->op2; - break; - default: - lua_assert(ir->o <= IR_NE || ir->o == IR_MIN || ir->o == IR_MAX); - hi = split_emit(J, IRTG(IR_HIOP, IRT_SOFTFP), - hisubst[ir->op1], hisubst[ir->op2]); - break; - } - } else -#endif -#if LJ_32 && LJ_HASFFI - if (irt_isint64(ir->t)) { - IRRef hiref = hisubst[ir->op1]; - nir->t.irt = IRT_INT | (nir->t.irt & IRT_GUARD); /* Turn into INT op. */ - switch (ir->o) { - case IR_ADD: - case IR_SUB: - /* Use plain op for hiword if loword cannot produce a carry/borrow. */ - if (irref_isk(nir->op2) && IR(nir->op2)->i == 0) { - ir->prev = nir->op1; /* Pass through loword. */ - nir->op1 = hiref; nir->op2 = hisubst[ir->op2]; - hi = nref; - break; - } - /* fallthrough */ - case IR_NEG: - hi = split_emit(J, IRTI(IR_HIOP), hiref, hisubst[ir->op2]); - break; - case IR_MUL: - hi = split_call_ll(J, hisubst, oir, ir, IRCALL_lj_carith_mul64); - break; - case IR_DIV: - hi = split_call_ll(J, hisubst, oir, ir, - irt_isi64(ir->t) ? IRCALL_lj_carith_divi64 : - IRCALL_lj_carith_divu64); - break; - case IR_MOD: - hi = split_call_ll(J, hisubst, oir, ir, - irt_isi64(ir->t) ? IRCALL_lj_carith_modi64 : - IRCALL_lj_carith_modu64); - break; - case IR_POW: - hi = split_call_ll(J, hisubst, oir, ir, - irt_isi64(ir->t) ? IRCALL_lj_carith_powi64 : - IRCALL_lj_carith_powu64); - break; - case IR_BNOT: - hi = split_emit(J, IRTI(IR_BNOT), hiref, 0); - break; - case IR_BSWAP: - ir->prev = split_emit(J, IRTI(IR_BSWAP), hiref, 0); - hi = nref; - break; - case IR_BAND: case IR_BOR: case IR_BXOR: - hi = split_bitop(J, hisubst, nir, ir); - break; - case IR_BSHL: case IR_BSHR: case IR_BSAR: case IR_BROL: case IR_BROR: - hi = split_bitshift(J, hisubst, oir, nir, ir); - break; - case IR_FLOAD: - lua_assert(ir->op2 == IRFL_CDATA_INT64); - hi = split_emit(J, IRTI(IR_FLOAD), nir->op1, IRFL_CDATA_INT64_4); -#if LJ_BE - ir->prev = hi; hi = nref; -#endif - break; - case IR_XLOAD: - hi = split_emit(J, IRTI(IR_XLOAD), split_ptr(J, oir, ir->op1), ir->op2); -#if LJ_BE - ir->prev = hi; hi = nref; -#endif - break; - case IR_XSTORE: - split_emit(J, IRTI(IR_HIOP), nir->op1, hisubst[ir->op2]); - break; - case IR_CONV: { /* Conversion to 64 bit integer. Others handled below. */ - IRType st = (IRType)(ir->op2 & IRCONV_SRCMASK); -#if LJ_SOFTFP - if (st == IRT_NUM) { /* NUM to 64 bit int conv. */ - hi = split_call_l(J, hisubst, oir, ir, - irt_isi64(ir->t) ? IRCALL_fp64_d2l : IRCALL_fp64_d2ul); - } else if (st == IRT_FLOAT) { /* FLOAT to 64 bit int conv. */ - nir->o = IR_CALLN; - nir->op2 = irt_isi64(ir->t) ? IRCALL_fp64_f2l : IRCALL_fp64_f2ul; - hi = split_emit(J, IRTI(IR_HIOP), nref, nref); - } -#else - if (st == IRT_NUM || st == IRT_FLOAT) { /* FP to 64 bit int conv. */ - hi = split_emit(J, IRTI(IR_HIOP), nir->op1, nref); - } -#endif - else if (st == IRT_I64 || st == IRT_U64) { /* 64/64 bit cast. */ - /* Drop cast, since assembler doesn't care. But fwd both parts. */ - hi = hiref; - goto fwdlo; - } else if ((ir->op2 & IRCONV_SEXT)) { /* Sign-extend to 64 bit. */ - IRRef k31 = lj_ir_kint(J, 31); - nir = IR(nref); /* May have been reallocated. */ - ir->prev = nir->op1; /* Pass through loword. */ - nir->o = IR_BSAR; /* hi = bsar(lo, 31). */ - nir->op2 = k31; - hi = nref; - } else { /* Zero-extend to 64 bit. */ - hi = lj_ir_kint(J, 0); - goto fwdlo; - } - break; - } - case IR_CALLXS: - goto split_call; - case IR_PHI: { - IRRef hiref2; - if ((irref_isk(nir->op1) && irref_isk(nir->op2)) || - nir->op1 == nir->op2) - J->cur.nins--; /* Drop useless PHIs. */ - hiref2 = hisubst[ir->op2]; - if (!((irref_isk(hiref) && irref_isk(hiref2)) || hiref == hiref2)) - split_emit(J, IRTI(IR_PHI), hiref, hiref2); - break; - } - case IR_HIOP: - J->cur.nins--; /* Drop joining HIOP. */ - ir->prev = nir->op1; - hi = nir->op2; - break; - default: - lua_assert(ir->o <= IR_NE); /* Comparisons. */ - split_emit(J, IRTGI(IR_HIOP), hiref, hisubst[ir->op2]); - break; - } - } else -#endif -#if LJ_SOFTFP - if (ir->o == IR_SLOAD) { - if ((nir->op2 & IRSLOAD_CONVERT)) { /* Convert from number to int. */ - nir->op2 &= ~IRSLOAD_CONVERT; - if (!(nir->op2 & IRSLOAD_TYPECHECK)) - nir->t.irt = IRT_INT; /* Drop guard. */ - split_emit(J, IRT(IR_HIOP, IRT_SOFTFP), nref, nref); - ir->prev = split_num2int(J, nref, nref+1, irt_isguard(ir->t)); - } - } else if (ir->o == IR_TOBIT) { - IRRef tmp, op1 = ir->op1; - J->cur.nins--; -#if LJ_LE - tmp = split_emit(J, IRT(IR_CARG, IRT_NIL), oir[op1].prev, hisubst[op1]); -#else - tmp = split_emit(J, IRT(IR_CARG, IRT_NIL), hisubst[op1], oir[op1].prev); -#endif - ir->prev = split_emit(J, IRTI(IR_CALLN), tmp, IRCALL_lj_vm_tobit); - } else if (ir->o == IR_TOSTR) { - if (hisubst[ir->op1]) { - if (irref_isk(ir->op1)) - nir->op1 = ir->op1; - else - split_emit(J, IRT(IR_HIOP, IRT_NIL), hisubst[ir->op1], nref); - } - } else if (ir->o == IR_HREF || ir->o == IR_NEWREF) { - if (irref_isk(ir->op2) && hisubst[ir->op2]) - nir->op2 = ir->op2; - } else -#endif - if (ir->o == IR_CONV) { /* See above, too. */ - IRType st = (IRType)(ir->op2 & IRCONV_SRCMASK); -#if LJ_32 && LJ_HASFFI - if (st == IRT_I64 || st == IRT_U64) { /* Conversion from 64 bit int. */ -#if LJ_SOFTFP - if (irt_isfloat(ir->t)) { - split_call_l(J, hisubst, oir, ir, - st == IRT_I64 ? IRCALL_fp64_l2f : IRCALL_fp64_ul2f); - J->cur.nins--; /* Drop unused HIOP. */ - } -#else - if (irt_isfp(ir->t)) { /* 64 bit integer to FP conversion. */ - ir->prev = split_emit(J, IRT(IR_HIOP, irt_type(ir->t)), - hisubst[ir->op1], nref); - } -#endif - else { /* Truncate to lower 32 bits. */ - fwdlo: - ir->prev = nir->op1; /* Forward loword. */ - /* Replace with NOP to avoid messing up the snapshot logic. */ - nir->ot = IRT(IR_NOP, IRT_NIL); - nir->op1 = nir->op2 = 0; - } - } -#endif -#if LJ_SOFTFP && LJ_32 && LJ_HASFFI - else if (irt_isfloat(ir->t)) { - if (st == IRT_NUM) { - split_call_l(J, hisubst, oir, ir, IRCALL_softfp_d2f); - J->cur.nins--; /* Drop unused HIOP. */ - } else { - nir->o = IR_CALLN; - nir->op2 = st == IRT_INT ? IRCALL_softfp_i2f : IRCALL_softfp_ui2f; - } - } else if (st == IRT_FLOAT) { - nir->o = IR_CALLN; - nir->op2 = irt_isint(ir->t) ? IRCALL_softfp_f2i : IRCALL_softfp_f2ui; - } else -#endif -#if LJ_SOFTFP - if (st == IRT_NUM || (LJ_32 && LJ_HASFFI && st == IRT_FLOAT)) { - if (irt_isguard(ir->t)) { - lua_assert(st == IRT_NUM && irt_isint(ir->t)); - J->cur.nins--; - ir->prev = split_num2int(J, nir->op1, hisubst[ir->op1], 1); - } else { - split_call_l(J, hisubst, oir, ir, -#if LJ_32 && LJ_HASFFI - st == IRT_NUM ? - (irt_isint(ir->t) ? IRCALL_softfp_d2i : IRCALL_softfp_d2ui) : - (irt_isint(ir->t) ? IRCALL_softfp_f2i : IRCALL_softfp_f2ui) -#else - IRCALL_softfp_d2i -#endif - ); - J->cur.nins--; /* Drop unused HIOP. */ - } - } -#endif - } else if (ir->o == IR_CALLXS) { - IRRef hiref; - split_call: - hiref = hisubst[ir->op1]; - if (hiref) { - IROpT ot = nir->ot; - IRRef op2 = nir->op2; - nir->ot = IRT(IR_CARG, IRT_NIL); -#if LJ_LE - nir->op2 = hiref; -#else - nir->op2 = nir->op1; nir->op1 = hiref; -#endif - ir->prev = nref = split_emit(J, ot, nref, op2); - } - if (LJ_SOFTFP ? irt_is64(ir->t) : irt_isint64(ir->t)) - hi = split_emit(J, - IRT(IR_HIOP, (LJ_SOFTFP && irt_isnum(ir->t)) ? IRT_SOFTFP : IRT_INT), - nref, nref); - } else if (ir->o == IR_CARG) { - IRRef hiref = hisubst[ir->op1]; - if (hiref) { - IRRef op2 = nir->op2; -#if LJ_LE - nir->op2 = hiref; -#else - nir->op2 = nir->op1; nir->op1 = hiref; -#endif - ir->prev = nref = split_emit(J, IRT(IR_CARG, IRT_NIL), nref, op2); - nir = IR(nref); - } - hiref = hisubst[ir->op2]; - if (hiref) { -#if !LJ_TARGET_X86 - int carg = 0; - IRIns *cir; - for (cir = IR(nir->op1); cir->o == IR_CARG; cir = IR(cir->op1)) - carg++; - if ((carg & 1) == 0) { /* Align 64 bit arguments. */ - IRRef op2 = nir->op2; - nir->op2 = REF_NIL; - nref = split_emit(J, IRT(IR_CARG, IRT_NIL), nref, op2); - nir = IR(nref); - } -#endif -#if LJ_BE - { IRRef tmp = nir->op2; nir->op2 = hiref; hiref = tmp; } -#endif - ir->prev = split_emit(J, IRT(IR_CARG, IRT_NIL), nref, hiref); - } - } else if (ir->o == IR_CNEWI) { - if (hisubst[ir->op2]) - split_emit(J, IRT(IR_HIOP, IRT_NIL), nref, hisubst[ir->op2]); - } else if (ir->o == IR_LOOP) { - J->loopref = nref; /* Needed by assembler. */ - } - hisubst[ref] = hi; /* Store hiword substitution. */ - } - if (snref == nins) { /* Substitution for last snapshot. */ - snap->ref = J->cur.nins; - split_subst_snap(J, snap, oir); - } - - /* Add PHI marks. */ - for (ref = J->cur.nins-1; ref >= REF_FIRST; ref--) { - IRIns *ir = IR(ref); - if (ir->o != IR_PHI) break; - if (!irref_isk(ir->op1)) irt_setphi(IR(ir->op1)->t); - if (ir->op2 > J->loopref) irt_setphi(IR(ir->op2)->t); - } -} - -/* Protected callback for split pass. */ -static TValue *cpsplit(lua_State *L, lua_CFunction dummy, void *ud) -{ - jit_State *J = (jit_State *)ud; - split_ir(J); - UNUSED(L); UNUSED(dummy); - return NULL; -} - -#if defined(LUA_USE_ASSERT) || LJ_SOFTFP -/* Slow, but sure way to check whether a SPLIT pass is needed. */ -static int split_needsplit(jit_State *J) -{ - IRIns *ir, *irend; - IRRef ref; - for (ir = IR(REF_FIRST), irend = IR(J->cur.nins); ir < irend; ir++) - if (LJ_SOFTFP ? irt_is64orfp(ir->t) : irt_isint64(ir->t)) - return 1; - if (LJ_SOFTFP) { - for (ref = J->chain[IR_SLOAD]; ref; ref = IR(ref)->prev) - if ((IR(ref)->op2 & IRSLOAD_CONVERT)) - return 1; - if (J->chain[IR_TOBIT]) - return 1; - } - for (ref = J->chain[IR_CONV]; ref; ref = IR(ref)->prev) { - IRType st = (IR(ref)->op2 & IRCONV_SRCMASK); - if ((LJ_SOFTFP && (st == IRT_NUM || st == IRT_FLOAT)) || - st == IRT_I64 || st == IRT_U64) - return 1; - } - return 0; /* Nope. */ -} -#endif - -/* SPLIT pass. */ -void lj_opt_split(jit_State *J) -{ -#if LJ_SOFTFP - if (!J->needsplit) - J->needsplit = split_needsplit(J); -#else - lua_assert(J->needsplit >= split_needsplit(J)); /* Verify flag. */ -#endif - if (J->needsplit) { - int errcode = lj_vm_cpcall(J->L, NULL, J, cpsplit); - if (errcode) { - /* Completely reset the trace to avoid inconsistent dump on abort. */ - J->cur.nins = J->cur.nk = REF_BASE; - J->cur.nsnap = 0; - lj_err_throw(J->L, errcode); /* Propagate errors. */ - } - } -} - -#undef IR - -#endif diff --git a/lib/LuaJIT/src/lj_parse.c b/lib/LuaJIT/src/lj_parse.c deleted file mode 100644 index c8efafa..0000000 --- a/lib/LuaJIT/src/lj_parse.c +++ /dev/null @@ -1,2728 +0,0 @@ -/* -** Lua parser (source code -> bytecode). -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Major portions taken verbatim or adapted from the Lua interpreter. -** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h -*/ - -#define lj_parse_c -#define LUA_CORE - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_debug.h" -#include "lj_buf.h" -#include "lj_str.h" -#include "lj_tab.h" -#include "lj_func.h" -#include "lj_state.h" -#include "lj_bc.h" -#if LJ_HASFFI -#include "lj_ctype.h" -#endif -#include "lj_strfmt.h" -#include "lj_lex.h" -#include "lj_parse.h" -#include "lj_vm.h" -#include "lj_vmevent.h" - -/* -- Parser structures and definitions ----------------------------------- */ - -/* Expression kinds. */ -typedef enum { - /* Constant expressions must be first and in this order: */ - VKNIL, - VKFALSE, - VKTRUE, - VKSTR, /* sval = string value */ - VKNUM, /* nval = number value */ - VKLAST = VKNUM, - VKCDATA, /* nval = cdata value, not treated as a constant expression */ - /* Non-constant expressions follow: */ - VLOCAL, /* info = local register, aux = vstack index */ - VUPVAL, /* info = upvalue index, aux = vstack index */ - VGLOBAL, /* sval = string value */ - VINDEXED, /* info = table register, aux = index reg/byte/string const */ - VJMP, /* info = instruction PC */ - VRELOCABLE, /* info = instruction PC */ - VNONRELOC, /* info = result register */ - VCALL, /* info = instruction PC, aux = base */ - VVOID -} ExpKind; - -/* Expression descriptor. */ -typedef struct ExpDesc { - union { - struct { - uint32_t info; /* Primary info. */ - uint32_t aux; /* Secondary info. */ - } s; - TValue nval; /* Number value. */ - GCstr *sval; /* String value. */ - } u; - ExpKind k; - BCPos t; /* True condition jump list. */ - BCPos f; /* False condition jump list. */ -} ExpDesc; - -/* Macros for expressions. */ -#define expr_hasjump(e) ((e)->t != (e)->f) - -#define expr_isk(e) ((e)->k <= VKLAST) -#define expr_isk_nojump(e) (expr_isk(e) && !expr_hasjump(e)) -#define expr_isnumk(e) ((e)->k == VKNUM) -#define expr_isnumk_nojump(e) (expr_isnumk(e) && !expr_hasjump(e)) -#define expr_isstrk(e) ((e)->k == VKSTR) - -#define expr_numtv(e) check_exp(expr_isnumk((e)), &(e)->u.nval) -#define expr_numberV(e) numberVnum(expr_numtv((e))) - -/* Initialize expression. */ -static LJ_AINLINE void expr_init(ExpDesc *e, ExpKind k, uint32_t info) -{ - e->k = k; - e->u.s.info = info; - e->f = e->t = NO_JMP; -} - -/* Check number constant for +-0. */ -static int expr_numiszero(ExpDesc *e) -{ - TValue *o = expr_numtv(e); - return tvisint(o) ? (intV(o) == 0) : tviszero(o); -} - -/* Per-function linked list of scope blocks. */ -typedef struct FuncScope { - struct FuncScope *prev; /* Link to outer scope. */ - MSize vstart; /* Start of block-local variables. */ - uint8_t nactvar; /* Number of active vars outside the scope. */ - uint8_t flags; /* Scope flags. */ -} FuncScope; - -#define FSCOPE_LOOP 0x01 /* Scope is a (breakable) loop. */ -#define FSCOPE_BREAK 0x02 /* Break used in scope. */ -#define FSCOPE_GOLA 0x04 /* Goto or label used in scope. */ -#define FSCOPE_UPVAL 0x08 /* Upvalue in scope. */ -#define FSCOPE_NOCLOSE 0x10 /* Do not close upvalues. */ - -#define NAME_BREAK ((GCstr *)(uintptr_t)1) - -/* Index into variable stack. */ -typedef uint16_t VarIndex; -#define LJ_MAX_VSTACK (65536 - LJ_MAX_UPVAL) - -/* Variable/goto/label info. */ -#define VSTACK_VAR_RW 0x01 /* R/W variable. */ -#define VSTACK_GOTO 0x02 /* Pending goto. */ -#define VSTACK_LABEL 0x04 /* Label. */ - -/* Per-function state. */ -typedef struct FuncState { - GCtab *kt; /* Hash table for constants. */ - LexState *ls; /* Lexer state. */ - lua_State *L; /* Lua state. */ - FuncScope *bl; /* Current scope. */ - struct FuncState *prev; /* Enclosing function. */ - BCPos pc; /* Next bytecode position. */ - BCPos lasttarget; /* Bytecode position of last jump target. */ - BCPos jpc; /* Pending jump list to next bytecode. */ - BCReg freereg; /* First free register. */ - BCReg nactvar; /* Number of active local variables. */ - BCReg nkn, nkgc; /* Number of lua_Number/GCobj constants */ - BCLine linedefined; /* First line of the function definition. */ - BCInsLine *bcbase; /* Base of bytecode stack. */ - BCPos bclim; /* Limit of bytecode stack. */ - MSize vbase; /* Base of variable stack for this function. */ - uint8_t flags; /* Prototype flags. */ - uint8_t numparams; /* Number of parameters. */ - uint8_t framesize; /* Fixed frame size. */ - uint8_t nuv; /* Number of upvalues */ - VarIndex varmap[LJ_MAX_LOCVAR]; /* Map from register to variable idx. */ - VarIndex uvmap[LJ_MAX_UPVAL]; /* Map from upvalue to variable idx. */ - VarIndex uvtmp[LJ_MAX_UPVAL]; /* Temporary upvalue map. */ -} FuncState; - -/* Binary and unary operators. ORDER OPR */ -typedef enum BinOpr { - OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW, /* ORDER ARITH */ - OPR_CONCAT, - OPR_NE, OPR_EQ, - OPR_LT, OPR_GE, OPR_LE, OPR_GT, - OPR_AND, OPR_OR, - OPR_NOBINOPR -} BinOpr; - -LJ_STATIC_ASSERT((int)BC_ISGE-(int)BC_ISLT == (int)OPR_GE-(int)OPR_LT); -LJ_STATIC_ASSERT((int)BC_ISLE-(int)BC_ISLT == (int)OPR_LE-(int)OPR_LT); -LJ_STATIC_ASSERT((int)BC_ISGT-(int)BC_ISLT == (int)OPR_GT-(int)OPR_LT); -LJ_STATIC_ASSERT((int)BC_SUBVV-(int)BC_ADDVV == (int)OPR_SUB-(int)OPR_ADD); -LJ_STATIC_ASSERT((int)BC_MULVV-(int)BC_ADDVV == (int)OPR_MUL-(int)OPR_ADD); -LJ_STATIC_ASSERT((int)BC_DIVVV-(int)BC_ADDVV == (int)OPR_DIV-(int)OPR_ADD); -LJ_STATIC_ASSERT((int)BC_MODVV-(int)BC_ADDVV == (int)OPR_MOD-(int)OPR_ADD); - -/* -- Error handling ------------------------------------------------------ */ - -LJ_NORET LJ_NOINLINE static void err_syntax(LexState *ls, ErrMsg em) -{ - lj_lex_error(ls, ls->tok, em); -} - -LJ_NORET LJ_NOINLINE static void err_token(LexState *ls, LexToken tok) -{ - lj_lex_error(ls, ls->tok, LJ_ERR_XTOKEN, lj_lex_token2str(ls, tok)); -} - -LJ_NORET static void err_limit(FuncState *fs, uint32_t limit, const char *what) -{ - if (fs->linedefined == 0) - lj_lex_error(fs->ls, 0, LJ_ERR_XLIMM, limit, what); - else - lj_lex_error(fs->ls, 0, LJ_ERR_XLIMF, fs->linedefined, limit, what); -} - -#define checklimit(fs, v, l, m) if ((v) >= (l)) err_limit(fs, l, m) -#define checklimitgt(fs, v, l, m) if ((v) > (l)) err_limit(fs, l, m) -#define checkcond(ls, c, em) { if (!(c)) err_syntax(ls, em); } - -/* -- Management of constants --------------------------------------------- */ - -/* Return bytecode encoding for primitive constant. */ -#define const_pri(e) check_exp((e)->k <= VKTRUE, (e)->k) - -#define tvhaskslot(o) ((o)->u32.hi == 0) -#define tvkslot(o) ((o)->u32.lo) - -/* Add a number constant. */ -static BCReg const_num(FuncState *fs, ExpDesc *e) -{ - lua_State *L = fs->L; - TValue *o; - lua_assert(expr_isnumk(e)); - o = lj_tab_set(L, fs->kt, &e->u.nval); - if (tvhaskslot(o)) - return tvkslot(o); - o->u64 = fs->nkn; - return fs->nkn++; -} - -/* Add a GC object constant. */ -static BCReg const_gc(FuncState *fs, GCobj *gc, uint32_t itype) -{ - lua_State *L = fs->L; - TValue key, *o; - setgcV(L, &key, gc, itype); - /* NOBARRIER: the key is new or kept alive. */ - o = lj_tab_set(L, fs->kt, &key); - if (tvhaskslot(o)) - return tvkslot(o); - o->u64 = fs->nkgc; - return fs->nkgc++; -} - -/* Add a string constant. */ -static BCReg const_str(FuncState *fs, ExpDesc *e) -{ - lua_assert(expr_isstrk(e) || e->k == VGLOBAL); - return const_gc(fs, obj2gco(e->u.sval), LJ_TSTR); -} - -/* Anchor string constant to avoid GC. */ -GCstr *lj_parse_keepstr(LexState *ls, const char *str, size_t len) -{ - /* NOBARRIER: the key is new or kept alive. */ - lua_State *L = ls->L; - GCstr *s = lj_str_new(L, str, len); - TValue *tv = lj_tab_setstr(L, ls->fs->kt, s); - if (tvisnil(tv)) setboolV(tv, 1); - lj_gc_check(L); - return s; -} - -#if LJ_HASFFI -/* Anchor cdata to avoid GC. */ -void lj_parse_keepcdata(LexState *ls, TValue *tv, GCcdata *cd) -{ - /* NOBARRIER: the key is new or kept alive. */ - lua_State *L = ls->L; - setcdataV(L, tv, cd); - setboolV(lj_tab_set(L, ls->fs->kt, tv), 1); -} -#endif - -/* -- Jump list handling -------------------------------------------------- */ - -/* Get next element in jump list. */ -static BCPos jmp_next(FuncState *fs, BCPos pc) -{ - ptrdiff_t delta = bc_j(fs->bcbase[pc].ins); - if ((BCPos)delta == NO_JMP) - return NO_JMP; - else - return (BCPos)(((ptrdiff_t)pc+1)+delta); -} - -/* Check if any of the instructions on the jump list produce no value. */ -static int jmp_novalue(FuncState *fs, BCPos list) -{ - for (; list != NO_JMP; list = jmp_next(fs, list)) { - BCIns p = fs->bcbase[list >= 1 ? list-1 : list].ins; - if (!(bc_op(p) == BC_ISTC || bc_op(p) == BC_ISFC || bc_a(p) == NO_REG)) - return 1; - } - return 0; -} - -/* Patch register of test instructions. */ -static int jmp_patchtestreg(FuncState *fs, BCPos pc, BCReg reg) -{ - BCInsLine *ilp = &fs->bcbase[pc >= 1 ? pc-1 : pc]; - BCOp op = bc_op(ilp->ins); - if (op == BC_ISTC || op == BC_ISFC) { - if (reg != NO_REG && reg != bc_d(ilp->ins)) { - setbc_a(&ilp->ins, reg); - } else { /* Nothing to store or already in the right register. */ - setbc_op(&ilp->ins, op+(BC_IST-BC_ISTC)); - setbc_a(&ilp->ins, 0); - } - } else if (bc_a(ilp->ins) == NO_REG) { - if (reg == NO_REG) { - ilp->ins = BCINS_AJ(BC_JMP, bc_a(fs->bcbase[pc].ins), 0); - } else { - setbc_a(&ilp->ins, reg); - if (reg >= bc_a(ilp[1].ins)) - setbc_a(&ilp[1].ins, reg+1); - } - } else { - return 0; /* Cannot patch other instructions. */ - } - return 1; -} - -/* Drop values for all instructions on jump list. */ -static void jmp_dropval(FuncState *fs, BCPos list) -{ - for (; list != NO_JMP; list = jmp_next(fs, list)) - jmp_patchtestreg(fs, list, NO_REG); -} - -/* Patch jump instruction to target. */ -static void jmp_patchins(FuncState *fs, BCPos pc, BCPos dest) -{ - BCIns *jmp = &fs->bcbase[pc].ins; - BCPos offset = dest-(pc+1)+BCBIAS_J; - lua_assert(dest != NO_JMP); - if (offset > BCMAX_D) - err_syntax(fs->ls, LJ_ERR_XJUMP); - setbc_d(jmp, offset); -} - -/* Append to jump list. */ -static void jmp_append(FuncState *fs, BCPos *l1, BCPos l2) -{ - if (l2 == NO_JMP) { - return; - } else if (*l1 == NO_JMP) { - *l1 = l2; - } else { - BCPos list = *l1; - BCPos next; - while ((next = jmp_next(fs, list)) != NO_JMP) /* Find last element. */ - list = next; - jmp_patchins(fs, list, l2); - } -} - -/* Patch jump list and preserve produced values. */ -static void jmp_patchval(FuncState *fs, BCPos list, BCPos vtarget, - BCReg reg, BCPos dtarget) -{ - while (list != NO_JMP) { - BCPos next = jmp_next(fs, list); - if (jmp_patchtestreg(fs, list, reg)) - jmp_patchins(fs, list, vtarget); /* Jump to target with value. */ - else - jmp_patchins(fs, list, dtarget); /* Jump to default target. */ - list = next; - } -} - -/* Jump to following instruction. Append to list of pending jumps. */ -static void jmp_tohere(FuncState *fs, BCPos list) -{ - fs->lasttarget = fs->pc; - jmp_append(fs, &fs->jpc, list); -} - -/* Patch jump list to target. */ -static void jmp_patch(FuncState *fs, BCPos list, BCPos target) -{ - if (target == fs->pc) { - jmp_tohere(fs, list); - } else { - lua_assert(target < fs->pc); - jmp_patchval(fs, list, target, NO_REG, target); - } -} - -/* -- Bytecode register allocator ----------------------------------------- */ - -/* Bump frame size. */ -static void bcreg_bump(FuncState *fs, BCReg n) -{ - BCReg sz = fs->freereg + n; - if (sz > fs->framesize) { - if (sz >= LJ_MAX_SLOTS) - err_syntax(fs->ls, LJ_ERR_XSLOTS); - fs->framesize = (uint8_t)sz; - } -} - -/* Reserve registers. */ -static void bcreg_reserve(FuncState *fs, BCReg n) -{ - bcreg_bump(fs, n); - fs->freereg += n; -} - -/* Free register. */ -static void bcreg_free(FuncState *fs, BCReg reg) -{ - if (reg >= fs->nactvar) { - fs->freereg--; - lua_assert(reg == fs->freereg); - } -} - -/* Free register for expression. */ -static void expr_free(FuncState *fs, ExpDesc *e) -{ - if (e->k == VNONRELOC) - bcreg_free(fs, e->u.s.info); -} - -/* -- Bytecode emitter ---------------------------------------------------- */ - -/* Emit bytecode instruction. */ -static BCPos bcemit_INS(FuncState *fs, BCIns ins) -{ - BCPos pc = fs->pc; - LexState *ls = fs->ls; - jmp_patchval(fs, fs->jpc, pc, NO_REG, pc); - fs->jpc = NO_JMP; - if (LJ_UNLIKELY(pc >= fs->bclim)) { - ptrdiff_t base = fs->bcbase - ls->bcstack; - checklimit(fs, ls->sizebcstack, LJ_MAX_BCINS, "bytecode instructions"); - lj_mem_growvec(fs->L, ls->bcstack, ls->sizebcstack, LJ_MAX_BCINS,BCInsLine); - fs->bclim = (BCPos)(ls->sizebcstack - base); - fs->bcbase = ls->bcstack + base; - } - fs->bcbase[pc].ins = ins; - fs->bcbase[pc].line = ls->lastline; - fs->pc = pc+1; - return pc; -} - -#define bcemit_ABC(fs, o, a, b, c) bcemit_INS(fs, BCINS_ABC(o, a, b, c)) -#define bcemit_AD(fs, o, a, d) bcemit_INS(fs, BCINS_AD(o, a, d)) -#define bcemit_AJ(fs, o, a, j) bcemit_INS(fs, BCINS_AJ(o, a, j)) - -#define bcptr(fs, e) (&(fs)->bcbase[(e)->u.s.info].ins) - -/* -- Bytecode emitter for expressions ------------------------------------ */ - -/* Discharge non-constant expression to any register. */ -static void expr_discharge(FuncState *fs, ExpDesc *e) -{ - BCIns ins; - if (e->k == VUPVAL) { - ins = BCINS_AD(BC_UGET, 0, e->u.s.info); - } else if (e->k == VGLOBAL) { - ins = BCINS_AD(BC_GGET, 0, const_str(fs, e)); - } else if (e->k == VINDEXED) { - BCReg rc = e->u.s.aux; - if ((int32_t)rc < 0) { - ins = BCINS_ABC(BC_TGETS, 0, e->u.s.info, ~rc); - } else if (rc > BCMAX_C) { - ins = BCINS_ABC(BC_TGETB, 0, e->u.s.info, rc-(BCMAX_C+1)); - } else { - bcreg_free(fs, rc); - ins = BCINS_ABC(BC_TGETV, 0, e->u.s.info, rc); - } - bcreg_free(fs, e->u.s.info); - } else if (e->k == VCALL) { - e->u.s.info = e->u.s.aux; - e->k = VNONRELOC; - return; - } else if (e->k == VLOCAL) { - e->k = VNONRELOC; - return; - } else { - return; - } - e->u.s.info = bcemit_INS(fs, ins); - e->k = VRELOCABLE; -} - -/* Emit bytecode to set a range of registers to nil. */ -static void bcemit_nil(FuncState *fs, BCReg from, BCReg n) -{ - if (fs->pc > fs->lasttarget) { /* No jumps to current position? */ - BCIns *ip = &fs->bcbase[fs->pc-1].ins; - BCReg pto, pfrom = bc_a(*ip); - switch (bc_op(*ip)) { /* Try to merge with the previous instruction. */ - case BC_KPRI: - if (bc_d(*ip) != ~LJ_TNIL) break; - if (from == pfrom) { - if (n == 1) return; - } else if (from == pfrom+1) { - from = pfrom; - n++; - } else { - break; - } - *ip = BCINS_AD(BC_KNIL, from, from+n-1); /* Replace KPRI. */ - return; - case BC_KNIL: - pto = bc_d(*ip); - if (pfrom <= from && from <= pto+1) { /* Can we connect both ranges? */ - if (from+n-1 > pto) - setbc_d(ip, from+n-1); /* Patch previous instruction range. */ - return; - } - break; - default: - break; - } - } - /* Emit new instruction or replace old instruction. */ - bcemit_INS(fs, n == 1 ? BCINS_AD(BC_KPRI, from, VKNIL) : - BCINS_AD(BC_KNIL, from, from+n-1)); -} - -/* Discharge an expression to a specific register. Ignore branches. */ -static void expr_toreg_nobranch(FuncState *fs, ExpDesc *e, BCReg reg) -{ - BCIns ins; - expr_discharge(fs, e); - if (e->k == VKSTR) { - ins = BCINS_AD(BC_KSTR, reg, const_str(fs, e)); - } else if (e->k == VKNUM) { -#if LJ_DUALNUM - cTValue *tv = expr_numtv(e); - if (tvisint(tv) && checki16(intV(tv))) - ins = BCINS_AD(BC_KSHORT, reg, (BCReg)(uint16_t)intV(tv)); - else -#else - lua_Number n = expr_numberV(e); - int32_t k = lj_num2int(n); - if (checki16(k) && n == (lua_Number)k) - ins = BCINS_AD(BC_KSHORT, reg, (BCReg)(uint16_t)k); - else -#endif - ins = BCINS_AD(BC_KNUM, reg, const_num(fs, e)); -#if LJ_HASFFI - } else if (e->k == VKCDATA) { - fs->flags |= PROTO_FFI; - ins = BCINS_AD(BC_KCDATA, reg, - const_gc(fs, obj2gco(cdataV(&e->u.nval)), LJ_TCDATA)); -#endif - } else if (e->k == VRELOCABLE) { - setbc_a(bcptr(fs, e), reg); - goto noins; - } else if (e->k == VNONRELOC) { - if (reg == e->u.s.info) - goto noins; - ins = BCINS_AD(BC_MOV, reg, e->u.s.info); - } else if (e->k == VKNIL) { - bcemit_nil(fs, reg, 1); - goto noins; - } else if (e->k <= VKTRUE) { - ins = BCINS_AD(BC_KPRI, reg, const_pri(e)); - } else { - lua_assert(e->k == VVOID || e->k == VJMP); - return; - } - bcemit_INS(fs, ins); -noins: - e->u.s.info = reg; - e->k = VNONRELOC; -} - -/* Forward declaration. */ -static BCPos bcemit_jmp(FuncState *fs); - -/* Discharge an expression to a specific register. */ -static void expr_toreg(FuncState *fs, ExpDesc *e, BCReg reg) -{ - expr_toreg_nobranch(fs, e, reg); - if (e->k == VJMP) - jmp_append(fs, &e->t, e->u.s.info); /* Add it to the true jump list. */ - if (expr_hasjump(e)) { /* Discharge expression with branches. */ - BCPos jend, jfalse = NO_JMP, jtrue = NO_JMP; - if (jmp_novalue(fs, e->t) || jmp_novalue(fs, e->f)) { - BCPos jval = (e->k == VJMP) ? NO_JMP : bcemit_jmp(fs); - jfalse = bcemit_AD(fs, BC_KPRI, reg, VKFALSE); - bcemit_AJ(fs, BC_JMP, fs->freereg, 1); - jtrue = bcemit_AD(fs, BC_KPRI, reg, VKTRUE); - jmp_tohere(fs, jval); - } - jend = fs->pc; - fs->lasttarget = jend; - jmp_patchval(fs, e->f, jend, reg, jfalse); - jmp_patchval(fs, e->t, jend, reg, jtrue); - } - e->f = e->t = NO_JMP; - e->u.s.info = reg; - e->k = VNONRELOC; -} - -/* Discharge an expression to the next free register. */ -static void expr_tonextreg(FuncState *fs, ExpDesc *e) -{ - expr_discharge(fs, e); - expr_free(fs, e); - bcreg_reserve(fs, 1); - expr_toreg(fs, e, fs->freereg - 1); -} - -/* Discharge an expression to any register. */ -static BCReg expr_toanyreg(FuncState *fs, ExpDesc *e) -{ - expr_discharge(fs, e); - if (e->k == VNONRELOC) { - if (!expr_hasjump(e)) return e->u.s.info; /* Already in a register. */ - if (e->u.s.info >= fs->nactvar) { - expr_toreg(fs, e, e->u.s.info); /* Discharge to temp. register. */ - return e->u.s.info; - } - } - expr_tonextreg(fs, e); /* Discharge to next register. */ - return e->u.s.info; -} - -/* Partially discharge expression to a value. */ -static void expr_toval(FuncState *fs, ExpDesc *e) -{ - if (expr_hasjump(e)) - expr_toanyreg(fs, e); - else - expr_discharge(fs, e); -} - -/* Emit store for LHS expression. */ -static void bcemit_store(FuncState *fs, ExpDesc *var, ExpDesc *e) -{ - BCIns ins; - if (var->k == VLOCAL) { - fs->ls->vstack[var->u.s.aux].info |= VSTACK_VAR_RW; - expr_free(fs, e); - expr_toreg(fs, e, var->u.s.info); - return; - } else if (var->k == VUPVAL) { - fs->ls->vstack[var->u.s.aux].info |= VSTACK_VAR_RW; - expr_toval(fs, e); - if (e->k <= VKTRUE) - ins = BCINS_AD(BC_USETP, var->u.s.info, const_pri(e)); - else if (e->k == VKSTR) - ins = BCINS_AD(BC_USETS, var->u.s.info, const_str(fs, e)); - else if (e->k == VKNUM) - ins = BCINS_AD(BC_USETN, var->u.s.info, const_num(fs, e)); - else - ins = BCINS_AD(BC_USETV, var->u.s.info, expr_toanyreg(fs, e)); - } else if (var->k == VGLOBAL) { - BCReg ra = expr_toanyreg(fs, e); - ins = BCINS_AD(BC_GSET, ra, const_str(fs, var)); - } else { - BCReg ra, rc; - lua_assert(var->k == VINDEXED); - ra = expr_toanyreg(fs, e); - rc = var->u.s.aux; - if ((int32_t)rc < 0) { - ins = BCINS_ABC(BC_TSETS, ra, var->u.s.info, ~rc); - } else if (rc > BCMAX_C) { - ins = BCINS_ABC(BC_TSETB, ra, var->u.s.info, rc-(BCMAX_C+1)); - } else { - /* Free late alloced key reg to avoid assert on free of value reg. */ - /* This can only happen when called from expr_table(). */ - lua_assert(e->k != VNONRELOC || ra < fs->nactvar || - rc < ra || (bcreg_free(fs, rc),1)); - ins = BCINS_ABC(BC_TSETV, ra, var->u.s.info, rc); - } - } - bcemit_INS(fs, ins); - expr_free(fs, e); -} - -/* Emit method lookup expression. */ -static void bcemit_method(FuncState *fs, ExpDesc *e, ExpDesc *key) -{ - BCReg idx, func, obj = expr_toanyreg(fs, e); - expr_free(fs, e); - func = fs->freereg; - bcemit_AD(fs, BC_MOV, func+1+LJ_FR2, obj); /* Copy object to 1st argument. */ - lua_assert(expr_isstrk(key)); - idx = const_str(fs, key); - if (idx <= BCMAX_C) { - bcreg_reserve(fs, 2+LJ_FR2); - bcemit_ABC(fs, BC_TGETS, func, obj, idx); - } else { - bcreg_reserve(fs, 3+LJ_FR2); - bcemit_AD(fs, BC_KSTR, func+2+LJ_FR2, idx); - bcemit_ABC(fs, BC_TGETV, func, obj, func+2+LJ_FR2); - fs->freereg--; - } - e->u.s.info = func; - e->k = VNONRELOC; -} - -/* -- Bytecode emitter for branches --------------------------------------- */ - -/* Emit unconditional branch. */ -static BCPos bcemit_jmp(FuncState *fs) -{ - BCPos jpc = fs->jpc; - BCPos j = fs->pc - 1; - BCIns *ip = &fs->bcbase[j].ins; - fs->jpc = NO_JMP; - if ((int32_t)j >= (int32_t)fs->lasttarget && bc_op(*ip) == BC_UCLO) { - setbc_j(ip, NO_JMP); - fs->lasttarget = j+1; - } else { - j = bcemit_AJ(fs, BC_JMP, fs->freereg, NO_JMP); - } - jmp_append(fs, &j, jpc); - return j; -} - -/* Invert branch condition of bytecode instruction. */ -static void invertcond(FuncState *fs, ExpDesc *e) -{ - BCIns *ip = &fs->bcbase[e->u.s.info - 1].ins; - setbc_op(ip, bc_op(*ip)^1); -} - -/* Emit conditional branch. */ -static BCPos bcemit_branch(FuncState *fs, ExpDesc *e, int cond) -{ - BCPos pc; - if (e->k == VRELOCABLE) { - BCIns *ip = bcptr(fs, e); - if (bc_op(*ip) == BC_NOT) { - *ip = BCINS_AD(cond ? BC_ISF : BC_IST, 0, bc_d(*ip)); - return bcemit_jmp(fs); - } - } - if (e->k != VNONRELOC) { - bcreg_reserve(fs, 1); - expr_toreg_nobranch(fs, e, fs->freereg-1); - } - bcemit_AD(fs, cond ? BC_ISTC : BC_ISFC, NO_REG, e->u.s.info); - pc = bcemit_jmp(fs); - expr_free(fs, e); - return pc; -} - -/* Emit branch on true condition. */ -static void bcemit_branch_t(FuncState *fs, ExpDesc *e) -{ - BCPos pc; - expr_discharge(fs, e); - if (e->k == VKSTR || e->k == VKNUM || e->k == VKTRUE) - pc = NO_JMP; /* Never jump. */ - else if (e->k == VJMP) - invertcond(fs, e), pc = e->u.s.info; - else if (e->k == VKFALSE || e->k == VKNIL) - expr_toreg_nobranch(fs, e, NO_REG), pc = bcemit_jmp(fs); - else - pc = bcemit_branch(fs, e, 0); - jmp_append(fs, &e->f, pc); - jmp_tohere(fs, e->t); - e->t = NO_JMP; -} - -/* Emit branch on false condition. */ -static void bcemit_branch_f(FuncState *fs, ExpDesc *e) -{ - BCPos pc; - expr_discharge(fs, e); - if (e->k == VKNIL || e->k == VKFALSE) - pc = NO_JMP; /* Never jump. */ - else if (e->k == VJMP) - pc = e->u.s.info; - else if (e->k == VKSTR || e->k == VKNUM || e->k == VKTRUE) - expr_toreg_nobranch(fs, e, NO_REG), pc = bcemit_jmp(fs); - else - pc = bcemit_branch(fs, e, 1); - jmp_append(fs, &e->t, pc); - jmp_tohere(fs, e->f); - e->f = NO_JMP; -} - -/* -- Bytecode emitter for operators -------------------------------------- */ - -/* Try constant-folding of arithmetic operators. */ -static int foldarith(BinOpr opr, ExpDesc *e1, ExpDesc *e2) -{ - TValue o; - lua_Number n; - if (!expr_isnumk_nojump(e1) || !expr_isnumk_nojump(e2)) return 0; - n = lj_vm_foldarith(expr_numberV(e1), expr_numberV(e2), (int)opr-OPR_ADD); - setnumV(&o, n); - if (tvisnan(&o) || tvismzero(&o)) return 0; /* Avoid NaN and -0 as consts. */ - if (LJ_DUALNUM) { - int32_t k = lj_num2int(n); - if ((lua_Number)k == n) { - setintV(&e1->u.nval, k); - return 1; - } - } - setnumV(&e1->u.nval, n); - return 1; -} - -/* Emit arithmetic operator. */ -static void bcemit_arith(FuncState *fs, BinOpr opr, ExpDesc *e1, ExpDesc *e2) -{ - BCReg rb, rc, t; - uint32_t op; - if (foldarith(opr, e1, e2)) - return; - if (opr == OPR_POW) { - op = BC_POW; - rc = expr_toanyreg(fs, e2); - rb = expr_toanyreg(fs, e1); - } else { - op = opr-OPR_ADD+BC_ADDVV; - /* Must discharge 2nd operand first since VINDEXED might free regs. */ - expr_toval(fs, e2); - if (expr_isnumk(e2) && (rc = const_num(fs, e2)) <= BCMAX_C) - op -= BC_ADDVV-BC_ADDVN; - else - rc = expr_toanyreg(fs, e2); - /* 1st operand discharged by bcemit_binop_left, but need KNUM/KSHORT. */ - lua_assert(expr_isnumk(e1) || e1->k == VNONRELOC); - expr_toval(fs, e1); - /* Avoid two consts to satisfy bytecode constraints. */ - if (expr_isnumk(e1) && !expr_isnumk(e2) && - (t = const_num(fs, e1)) <= BCMAX_B) { - rb = rc; rc = t; op -= BC_ADDVV-BC_ADDNV; - } else { - rb = expr_toanyreg(fs, e1); - } - } - /* Using expr_free might cause asserts if the order is wrong. */ - if (e1->k == VNONRELOC && e1->u.s.info >= fs->nactvar) fs->freereg--; - if (e2->k == VNONRELOC && e2->u.s.info >= fs->nactvar) fs->freereg--; - e1->u.s.info = bcemit_ABC(fs, op, 0, rb, rc); - e1->k = VRELOCABLE; -} - -/* Emit comparison operator. */ -static void bcemit_comp(FuncState *fs, BinOpr opr, ExpDesc *e1, ExpDesc *e2) -{ - ExpDesc *eret = e1; - BCIns ins; - expr_toval(fs, e1); - if (opr == OPR_EQ || opr == OPR_NE) { - BCOp op = opr == OPR_EQ ? BC_ISEQV : BC_ISNEV; - BCReg ra; - if (expr_isk(e1)) { e1 = e2; e2 = eret; } /* Need constant in 2nd arg. */ - ra = expr_toanyreg(fs, e1); /* First arg must be in a reg. */ - expr_toval(fs, e2); - switch (e2->k) { - case VKNIL: case VKFALSE: case VKTRUE: - ins = BCINS_AD(op+(BC_ISEQP-BC_ISEQV), ra, const_pri(e2)); - break; - case VKSTR: - ins = BCINS_AD(op+(BC_ISEQS-BC_ISEQV), ra, const_str(fs, e2)); - break; - case VKNUM: - ins = BCINS_AD(op+(BC_ISEQN-BC_ISEQV), ra, const_num(fs, e2)); - break; - default: - ins = BCINS_AD(op, ra, expr_toanyreg(fs, e2)); - break; - } - } else { - uint32_t op = opr-OPR_LT+BC_ISLT; - BCReg ra, rd; - if ((op-BC_ISLT) & 1) { /* GT -> LT, GE -> LE */ - e1 = e2; e2 = eret; /* Swap operands. */ - op = ((op-BC_ISLT)^3)+BC_ISLT; - expr_toval(fs, e1); - } - rd = expr_toanyreg(fs, e2); - ra = expr_toanyreg(fs, e1); - ins = BCINS_AD(op, ra, rd); - } - /* Using expr_free might cause asserts if the order is wrong. */ - if (e1->k == VNONRELOC && e1->u.s.info >= fs->nactvar) fs->freereg--; - if (e2->k == VNONRELOC && e2->u.s.info >= fs->nactvar) fs->freereg--; - bcemit_INS(fs, ins); - eret->u.s.info = bcemit_jmp(fs); - eret->k = VJMP; -} - -/* Fixup left side of binary operator. */ -static void bcemit_binop_left(FuncState *fs, BinOpr op, ExpDesc *e) -{ - if (op == OPR_AND) { - bcemit_branch_t(fs, e); - } else if (op == OPR_OR) { - bcemit_branch_f(fs, e); - } else if (op == OPR_CONCAT) { - expr_tonextreg(fs, e); - } else if (op == OPR_EQ || op == OPR_NE) { - if (!expr_isk_nojump(e)) expr_toanyreg(fs, e); - } else { - if (!expr_isnumk_nojump(e)) expr_toanyreg(fs, e); - } -} - -/* Emit binary operator. */ -static void bcemit_binop(FuncState *fs, BinOpr op, ExpDesc *e1, ExpDesc *e2) -{ - if (op <= OPR_POW) { - bcemit_arith(fs, op, e1, e2); - } else if (op == OPR_AND) { - lua_assert(e1->t == NO_JMP); /* List must be closed. */ - expr_discharge(fs, e2); - jmp_append(fs, &e2->f, e1->f); - *e1 = *e2; - } else if (op == OPR_OR) { - lua_assert(e1->f == NO_JMP); /* List must be closed. */ - expr_discharge(fs, e2); - jmp_append(fs, &e2->t, e1->t); - *e1 = *e2; - } else if (op == OPR_CONCAT) { - expr_toval(fs, e2); - if (e2->k == VRELOCABLE && bc_op(*bcptr(fs, e2)) == BC_CAT) { - lua_assert(e1->u.s.info == bc_b(*bcptr(fs, e2))-1); - expr_free(fs, e1); - setbc_b(bcptr(fs, e2), e1->u.s.info); - e1->u.s.info = e2->u.s.info; - } else { - expr_tonextreg(fs, e2); - expr_free(fs, e2); - expr_free(fs, e1); - e1->u.s.info = bcemit_ABC(fs, BC_CAT, 0, e1->u.s.info, e2->u.s.info); - } - e1->k = VRELOCABLE; - } else { - lua_assert(op == OPR_NE || op == OPR_EQ || - op == OPR_LT || op == OPR_GE || op == OPR_LE || op == OPR_GT); - bcemit_comp(fs, op, e1, e2); - } -} - -/* Emit unary operator. */ -static void bcemit_unop(FuncState *fs, BCOp op, ExpDesc *e) -{ - if (op == BC_NOT) { - /* Swap true and false lists. */ - { BCPos temp = e->f; e->f = e->t; e->t = temp; } - jmp_dropval(fs, e->f); - jmp_dropval(fs, e->t); - expr_discharge(fs, e); - if (e->k == VKNIL || e->k == VKFALSE) { - e->k = VKTRUE; - return; - } else if (expr_isk(e) || (LJ_HASFFI && e->k == VKCDATA)) { - e->k = VKFALSE; - return; - } else if (e->k == VJMP) { - invertcond(fs, e); - return; - } else if (e->k == VRELOCABLE) { - bcreg_reserve(fs, 1); - setbc_a(bcptr(fs, e), fs->freereg-1); - e->u.s.info = fs->freereg-1; - e->k = VNONRELOC; - } else { - lua_assert(e->k == VNONRELOC); - } - } else { - lua_assert(op == BC_UNM || op == BC_LEN); - if (op == BC_UNM && !expr_hasjump(e)) { /* Constant-fold negations. */ -#if LJ_HASFFI - if (e->k == VKCDATA) { /* Fold in-place since cdata is not interned. */ - GCcdata *cd = cdataV(&e->u.nval); - int64_t *p = (int64_t *)cdataptr(cd); - if (cd->ctypeid == CTID_COMPLEX_DOUBLE) - p[1] ^= (int64_t)U64x(80000000,00000000); - else - *p = -*p; - return; - } else -#endif - if (expr_isnumk(e) && !expr_numiszero(e)) { /* Avoid folding to -0. */ - TValue *o = expr_numtv(e); - if (tvisint(o)) { - int32_t k = intV(o); - if (k == -k) - setnumV(o, -(lua_Number)k); - else - setintV(o, -k); - return; - } else { - o->u64 ^= U64x(80000000,00000000); - return; - } - } - } - expr_toanyreg(fs, e); - } - expr_free(fs, e); - e->u.s.info = bcemit_AD(fs, op, 0, e->u.s.info); - e->k = VRELOCABLE; -} - -/* -- Lexer support ------------------------------------------------------- */ - -/* Check and consume optional token. */ -static int lex_opt(LexState *ls, LexToken tok) -{ - if (ls->tok == tok) { - lj_lex_next(ls); - return 1; - } - return 0; -} - -/* Check and consume token. */ -static void lex_check(LexState *ls, LexToken tok) -{ - if (ls->tok != tok) - err_token(ls, tok); - lj_lex_next(ls); -} - -/* Check for matching token. */ -static void lex_match(LexState *ls, LexToken what, LexToken who, BCLine line) -{ - if (!lex_opt(ls, what)) { - if (line == ls->linenumber) { - err_token(ls, what); - } else { - const char *swhat = lj_lex_token2str(ls, what); - const char *swho = lj_lex_token2str(ls, who); - lj_lex_error(ls, ls->tok, LJ_ERR_XMATCH, swhat, swho, line); - } - } -} - -/* Check for string token. */ -static GCstr *lex_str(LexState *ls) -{ - GCstr *s; - if (ls->tok != TK_name && (LJ_52 || ls->tok != TK_goto)) - err_token(ls, TK_name); - s = strV(&ls->tokval); - lj_lex_next(ls); - return s; -} - -/* -- Variable handling --------------------------------------------------- */ - -#define var_get(ls, fs, i) ((ls)->vstack[(fs)->varmap[(i)]]) - -/* Define a new local variable. */ -static void var_new(LexState *ls, BCReg n, GCstr *name) -{ - FuncState *fs = ls->fs; - MSize vtop = ls->vtop; - checklimit(fs, fs->nactvar+n, LJ_MAX_LOCVAR, "local variables"); - if (LJ_UNLIKELY(vtop >= ls->sizevstack)) { - if (ls->sizevstack >= LJ_MAX_VSTACK) - lj_lex_error(ls, 0, LJ_ERR_XLIMC, LJ_MAX_VSTACK); - lj_mem_growvec(ls->L, ls->vstack, ls->sizevstack, LJ_MAX_VSTACK, VarInfo); - } - lua_assert((uintptr_t)name < VARNAME__MAX || - lj_tab_getstr(fs->kt, name) != NULL); - /* NOBARRIER: name is anchored in fs->kt and ls->vstack is not a GCobj. */ - setgcref(ls->vstack[vtop].name, obj2gco(name)); - fs->varmap[fs->nactvar+n] = (uint16_t)vtop; - ls->vtop = vtop+1; -} - -#define var_new_lit(ls, n, v) \ - var_new(ls, (n), lj_parse_keepstr(ls, "" v, sizeof(v)-1)) - -#define var_new_fixed(ls, n, vn) \ - var_new(ls, (n), (GCstr *)(uintptr_t)(vn)) - -/* Add local variables. */ -static void var_add(LexState *ls, BCReg nvars) -{ - FuncState *fs = ls->fs; - BCReg nactvar = fs->nactvar; - while (nvars--) { - VarInfo *v = &var_get(ls, fs, nactvar); - v->startpc = fs->pc; - v->slot = nactvar++; - v->info = 0; - } - fs->nactvar = nactvar; -} - -/* Remove local variables. */ -static void var_remove(LexState *ls, BCReg tolevel) -{ - FuncState *fs = ls->fs; - while (fs->nactvar > tolevel) - var_get(ls, fs, --fs->nactvar).endpc = fs->pc; -} - -/* Lookup local variable name. */ -static BCReg var_lookup_local(FuncState *fs, GCstr *n) -{ - int i; - for (i = fs->nactvar-1; i >= 0; i--) { - if (n == strref(var_get(fs->ls, fs, i).name)) - return (BCReg)i; - } - return (BCReg)-1; /* Not found. */ -} - -/* Lookup or add upvalue index. */ -static MSize var_lookup_uv(FuncState *fs, MSize vidx, ExpDesc *e) -{ - MSize i, n = fs->nuv; - for (i = 0; i < n; i++) - if (fs->uvmap[i] == vidx) - return i; /* Already exists. */ - /* Otherwise create a new one. */ - checklimit(fs, fs->nuv, LJ_MAX_UPVAL, "upvalues"); - lua_assert(e->k == VLOCAL || e->k == VUPVAL); - fs->uvmap[n] = (uint16_t)vidx; - fs->uvtmp[n] = (uint16_t)(e->k == VLOCAL ? vidx : LJ_MAX_VSTACK+e->u.s.info); - fs->nuv = n+1; - return n; -} - -/* Forward declaration. */ -static void fscope_uvmark(FuncState *fs, BCReg level); - -/* Recursively lookup variables in enclosing functions. */ -static MSize var_lookup_(FuncState *fs, GCstr *name, ExpDesc *e, int first) -{ - if (fs) { - BCReg reg = var_lookup_local(fs, name); - if ((int32_t)reg >= 0) { /* Local in this function? */ - expr_init(e, VLOCAL, reg); - if (!first) - fscope_uvmark(fs, reg); /* Scope now has an upvalue. */ - return (MSize)(e->u.s.aux = (uint32_t)fs->varmap[reg]); - } else { - MSize vidx = var_lookup_(fs->prev, name, e, 0); /* Var in outer func? */ - if ((int32_t)vidx >= 0) { /* Yes, make it an upvalue here. */ - e->u.s.info = (uint8_t)var_lookup_uv(fs, vidx, e); - e->k = VUPVAL; - return vidx; - } - } - } else { /* Not found in any function, must be a global. */ - expr_init(e, VGLOBAL, 0); - e->u.sval = name; - } - return (MSize)-1; /* Global. */ -} - -/* Lookup variable name. */ -#define var_lookup(ls, e) \ - var_lookup_((ls)->fs, lex_str(ls), (e), 1) - -/* -- Goto an label handling ---------------------------------------------- */ - -/* Add a new goto or label. */ -static MSize gola_new(LexState *ls, GCstr *name, uint8_t info, BCPos pc) -{ - FuncState *fs = ls->fs; - MSize vtop = ls->vtop; - if (LJ_UNLIKELY(vtop >= ls->sizevstack)) { - if (ls->sizevstack >= LJ_MAX_VSTACK) - lj_lex_error(ls, 0, LJ_ERR_XLIMC, LJ_MAX_VSTACK); - lj_mem_growvec(ls->L, ls->vstack, ls->sizevstack, LJ_MAX_VSTACK, VarInfo); - } - lua_assert(name == NAME_BREAK || lj_tab_getstr(fs->kt, name) != NULL); - /* NOBARRIER: name is anchored in fs->kt and ls->vstack is not a GCobj. */ - setgcref(ls->vstack[vtop].name, obj2gco(name)); - ls->vstack[vtop].startpc = pc; - ls->vstack[vtop].slot = (uint8_t)fs->nactvar; - ls->vstack[vtop].info = info; - ls->vtop = vtop+1; - return vtop; -} - -#define gola_isgoto(v) ((v)->info & VSTACK_GOTO) -#define gola_islabel(v) ((v)->info & VSTACK_LABEL) -#define gola_isgotolabel(v) ((v)->info & (VSTACK_GOTO|VSTACK_LABEL)) - -/* Patch goto to jump to label. */ -static void gola_patch(LexState *ls, VarInfo *vg, VarInfo *vl) -{ - FuncState *fs = ls->fs; - BCPos pc = vg->startpc; - setgcrefnull(vg->name); /* Invalidate pending goto. */ - setbc_a(&fs->bcbase[pc].ins, vl->slot); - jmp_patch(fs, pc, vl->startpc); -} - -/* Patch goto to close upvalues. */ -static void gola_close(LexState *ls, VarInfo *vg) -{ - FuncState *fs = ls->fs; - BCPos pc = vg->startpc; - BCIns *ip = &fs->bcbase[pc].ins; - lua_assert(gola_isgoto(vg)); - lua_assert(bc_op(*ip) == BC_JMP || bc_op(*ip) == BC_UCLO); - setbc_a(ip, vg->slot); - if (bc_op(*ip) == BC_JMP) { - BCPos next = jmp_next(fs, pc); - if (next != NO_JMP) jmp_patch(fs, next, pc); /* Jump to UCLO. */ - setbc_op(ip, BC_UCLO); /* Turn into UCLO. */ - setbc_j(ip, NO_JMP); - } -} - -/* Resolve pending forward gotos for label. */ -static void gola_resolve(LexState *ls, FuncScope *bl, MSize idx) -{ - VarInfo *vg = ls->vstack + bl->vstart; - VarInfo *vl = ls->vstack + idx; - for (; vg < vl; vg++) - if (gcrefeq(vg->name, vl->name) && gola_isgoto(vg)) { - if (vg->slot < vl->slot) { - GCstr *name = strref(var_get(ls, ls->fs, vg->slot).name); - lua_assert((uintptr_t)name >= VARNAME__MAX); - ls->linenumber = ls->fs->bcbase[vg->startpc].line; - lua_assert(strref(vg->name) != NAME_BREAK); - lj_lex_error(ls, 0, LJ_ERR_XGSCOPE, - strdata(strref(vg->name)), strdata(name)); - } - gola_patch(ls, vg, vl); - } -} - -/* Fixup remaining gotos and labels for scope. */ -static void gola_fixup(LexState *ls, FuncScope *bl) -{ - VarInfo *v = ls->vstack + bl->vstart; - VarInfo *ve = ls->vstack + ls->vtop; - for (; v < ve; v++) { - GCstr *name = strref(v->name); - if (name != NULL) { /* Only consider remaining valid gotos/labels. */ - if (gola_islabel(v)) { - VarInfo *vg; - setgcrefnull(v->name); /* Invalidate label that goes out of scope. */ - for (vg = v+1; vg < ve; vg++) /* Resolve pending backward gotos. */ - if (strref(vg->name) == name && gola_isgoto(vg)) { - if ((bl->flags&FSCOPE_UPVAL) && vg->slot > v->slot) - gola_close(ls, vg); - gola_patch(ls, vg, v); - } - } else if (gola_isgoto(v)) { - if (bl->prev) { /* Propagate goto or break to outer scope. */ - bl->prev->flags |= name == NAME_BREAK ? FSCOPE_BREAK : FSCOPE_GOLA; - v->slot = bl->nactvar; - if ((bl->flags & FSCOPE_UPVAL)) - gola_close(ls, v); - } else { /* No outer scope: undefined goto label or no loop. */ - ls->linenumber = ls->fs->bcbase[v->startpc].line; - if (name == NAME_BREAK) - lj_lex_error(ls, 0, LJ_ERR_XBREAK); - else - lj_lex_error(ls, 0, LJ_ERR_XLUNDEF, strdata(name)); - } - } - } - } -} - -/* Find existing label. */ -static VarInfo *gola_findlabel(LexState *ls, GCstr *name) -{ - VarInfo *v = ls->vstack + ls->fs->bl->vstart; - VarInfo *ve = ls->vstack + ls->vtop; - for (; v < ve; v++) - if (strref(v->name) == name && gola_islabel(v)) - return v; - return NULL; -} - -/* -- Scope handling ------------------------------------------------------ */ - -/* Begin a scope. */ -static void fscope_begin(FuncState *fs, FuncScope *bl, int flags) -{ - bl->nactvar = (uint8_t)fs->nactvar; - bl->flags = flags; - bl->vstart = fs->ls->vtop; - bl->prev = fs->bl; - fs->bl = bl; - lua_assert(fs->freereg == fs->nactvar); -} - -/* End a scope. */ -static void fscope_end(FuncState *fs) -{ - FuncScope *bl = fs->bl; - LexState *ls = fs->ls; - fs->bl = bl->prev; - var_remove(ls, bl->nactvar); - fs->freereg = fs->nactvar; - lua_assert(bl->nactvar == fs->nactvar); - if ((bl->flags & (FSCOPE_UPVAL|FSCOPE_NOCLOSE)) == FSCOPE_UPVAL) - bcemit_AJ(fs, BC_UCLO, bl->nactvar, 0); - if ((bl->flags & FSCOPE_BREAK)) { - if ((bl->flags & FSCOPE_LOOP)) { - MSize idx = gola_new(ls, NAME_BREAK, VSTACK_LABEL, fs->pc); - ls->vtop = idx; /* Drop break label immediately. */ - gola_resolve(ls, bl, idx); - } else { /* Need the fixup step to propagate the breaks. */ - gola_fixup(ls, bl); - return; - } - } - if ((bl->flags & FSCOPE_GOLA)) { - gola_fixup(ls, bl); - } -} - -/* Mark scope as having an upvalue. */ -static void fscope_uvmark(FuncState *fs, BCReg level) -{ - FuncScope *bl; - for (bl = fs->bl; bl && bl->nactvar > level; bl = bl->prev) - ; - if (bl) - bl->flags |= FSCOPE_UPVAL; -} - -/* -- Function state management ------------------------------------------- */ - -/* Fixup bytecode for prototype. */ -static void fs_fixup_bc(FuncState *fs, GCproto *pt, BCIns *bc, MSize n) -{ - BCInsLine *base = fs->bcbase; - MSize i; - pt->sizebc = n; - bc[0] = BCINS_AD((fs->flags & PROTO_VARARG) ? BC_FUNCV : BC_FUNCF, - fs->framesize, 0); - for (i = 1; i < n; i++) - bc[i] = base[i].ins; -} - -/* Fixup upvalues for child prototype, step #2. */ -static void fs_fixup_uv2(FuncState *fs, GCproto *pt) -{ - VarInfo *vstack = fs->ls->vstack; - uint16_t *uv = proto_uv(pt); - MSize i, n = pt->sizeuv; - for (i = 0; i < n; i++) { - VarIndex vidx = uv[i]; - if (vidx >= LJ_MAX_VSTACK) - uv[i] = vidx - LJ_MAX_VSTACK; - else if ((vstack[vidx].info & VSTACK_VAR_RW)) - uv[i] = vstack[vidx].slot | PROTO_UV_LOCAL; - else - uv[i] = vstack[vidx].slot | PROTO_UV_LOCAL | PROTO_UV_IMMUTABLE; - } -} - -/* Fixup constants for prototype. */ -static void fs_fixup_k(FuncState *fs, GCproto *pt, void *kptr) -{ - GCtab *kt; - TValue *array; - Node *node; - MSize i, hmask; - checklimitgt(fs, fs->nkn, BCMAX_D+1, "constants"); - checklimitgt(fs, fs->nkgc, BCMAX_D+1, "constants"); - setmref(pt->k, kptr); - pt->sizekn = fs->nkn; - pt->sizekgc = fs->nkgc; - kt = fs->kt; - array = tvref(kt->array); - for (i = 0; i < kt->asize; i++) - if (tvhaskslot(&array[i])) { - TValue *tv = &((TValue *)kptr)[tvkslot(&array[i])]; - if (LJ_DUALNUM) - setintV(tv, (int32_t)i); - else - setnumV(tv, (lua_Number)i); - } - node = noderef(kt->node); - hmask = kt->hmask; - for (i = 0; i <= hmask; i++) { - Node *n = &node[i]; - if (tvhaskslot(&n->val)) { - ptrdiff_t kidx = (ptrdiff_t)tvkslot(&n->val); - lua_assert(!tvisint(&n->key)); - if (tvisnum(&n->key)) { - TValue *tv = &((TValue *)kptr)[kidx]; - if (LJ_DUALNUM) { - lua_Number nn = numV(&n->key); - int32_t k = lj_num2int(nn); - lua_assert(!tvismzero(&n->key)); - if ((lua_Number)k == nn) - setintV(tv, k); - else - *tv = n->key; - } else { - *tv = n->key; - } - } else { - GCobj *o = gcV(&n->key); - setgcref(((GCRef *)kptr)[~kidx], o); - lj_gc_objbarrier(fs->L, pt, o); - if (tvisproto(&n->key)) - fs_fixup_uv2(fs, gco2pt(o)); - } - } - } -} - -/* Fixup upvalues for prototype, step #1. */ -static void fs_fixup_uv1(FuncState *fs, GCproto *pt, uint16_t *uv) -{ - setmref(pt->uv, uv); - pt->sizeuv = fs->nuv; - memcpy(uv, fs->uvtmp, fs->nuv*sizeof(VarIndex)); -} - -#ifndef LUAJIT_DISABLE_DEBUGINFO -/* Prepare lineinfo for prototype. */ -static size_t fs_prep_line(FuncState *fs, BCLine numline) -{ - return (fs->pc-1) << (numline < 256 ? 0 : numline < 65536 ? 1 : 2); -} - -/* Fixup lineinfo for prototype. */ -static void fs_fixup_line(FuncState *fs, GCproto *pt, - void *lineinfo, BCLine numline) -{ - BCInsLine *base = fs->bcbase + 1; - BCLine first = fs->linedefined; - MSize i = 0, n = fs->pc-1; - pt->firstline = fs->linedefined; - pt->numline = numline; - setmref(pt->lineinfo, lineinfo); - if (LJ_LIKELY(numline < 256)) { - uint8_t *li = (uint8_t *)lineinfo; - do { - BCLine delta = base[i].line - first; - lua_assert(delta >= 0 && delta < 256); - li[i] = (uint8_t)delta; - } while (++i < n); - } else if (LJ_LIKELY(numline < 65536)) { - uint16_t *li = (uint16_t *)lineinfo; - do { - BCLine delta = base[i].line - first; - lua_assert(delta >= 0 && delta < 65536); - li[i] = (uint16_t)delta; - } while (++i < n); - } else { - uint32_t *li = (uint32_t *)lineinfo; - do { - BCLine delta = base[i].line - first; - lua_assert(delta >= 0); - li[i] = (uint32_t)delta; - } while (++i < n); - } -} - -/* Prepare variable info for prototype. */ -static size_t fs_prep_var(LexState *ls, FuncState *fs, size_t *ofsvar) -{ - VarInfo *vs =ls->vstack, *ve; - MSize i, n; - BCPos lastpc; - lj_buf_reset(&ls->sb); /* Copy to temp. string buffer. */ - /* Store upvalue names. */ - for (i = 0, n = fs->nuv; i < n; i++) { - GCstr *s = strref(vs[fs->uvmap[i]].name); - MSize len = s->len+1; - char *p = lj_buf_more(&ls->sb, len); - p = lj_buf_wmem(p, strdata(s), len); - setsbufP(&ls->sb, p); - } - *ofsvar = sbuflen(&ls->sb); - lastpc = 0; - /* Store local variable names and compressed ranges. */ - for (ve = vs + ls->vtop, vs += fs->vbase; vs < ve; vs++) { - if (!gola_isgotolabel(vs)) { - GCstr *s = strref(vs->name); - BCPos startpc; - char *p; - if ((uintptr_t)s < VARNAME__MAX) { - p = lj_buf_more(&ls->sb, 1 + 2*5); - *p++ = (char)(uintptr_t)s; - } else { - MSize len = s->len+1; - p = lj_buf_more(&ls->sb, len + 2*5); - p = lj_buf_wmem(p, strdata(s), len); - } - startpc = vs->startpc; - p = lj_strfmt_wuleb128(p, startpc-lastpc); - p = lj_strfmt_wuleb128(p, vs->endpc-startpc); - setsbufP(&ls->sb, p); - lastpc = startpc; - } - } - lj_buf_putb(&ls->sb, '\0'); /* Terminator for varinfo. */ - return sbuflen(&ls->sb); -} - -/* Fixup variable info for prototype. */ -static void fs_fixup_var(LexState *ls, GCproto *pt, uint8_t *p, size_t ofsvar) -{ - setmref(pt->uvinfo, p); - setmref(pt->varinfo, (char *)p + ofsvar); - memcpy(p, sbufB(&ls->sb), sbuflen(&ls->sb)); /* Copy from temp. buffer. */ -} -#else - -/* Initialize with empty debug info, if disabled. */ -#define fs_prep_line(fs, numline) (UNUSED(numline), 0) -#define fs_fixup_line(fs, pt, li, numline) \ - pt->firstline = pt->numline = 0, setmref((pt)->lineinfo, NULL) -#define fs_prep_var(ls, fs, ofsvar) (UNUSED(ofsvar), 0) -#define fs_fixup_var(ls, pt, p, ofsvar) \ - setmref((pt)->uvinfo, NULL), setmref((pt)->varinfo, NULL) - -#endif - -/* Check if bytecode op returns. */ -static int bcopisret(BCOp op) -{ - switch (op) { - case BC_CALLMT: case BC_CALLT: - case BC_RETM: case BC_RET: case BC_RET0: case BC_RET1: - return 1; - default: - return 0; - } -} - -/* Fixup return instruction for prototype. */ -static void fs_fixup_ret(FuncState *fs) -{ - BCPos lastpc = fs->pc; - if (lastpc <= fs->lasttarget || !bcopisret(bc_op(fs->bcbase[lastpc-1].ins))) { - if ((fs->bl->flags & FSCOPE_UPVAL)) - bcemit_AJ(fs, BC_UCLO, 0, 0); - bcemit_AD(fs, BC_RET0, 0, 1); /* Need final return. */ - } - fs->bl->flags |= FSCOPE_NOCLOSE; /* Handled above. */ - fscope_end(fs); - lua_assert(fs->bl == NULL); - /* May need to fixup returns encoded before first function was created. */ - if (fs->flags & PROTO_FIXUP_RETURN) { - BCPos pc; - for (pc = 1; pc < lastpc; pc++) { - BCIns ins = fs->bcbase[pc].ins; - BCPos offset; - switch (bc_op(ins)) { - case BC_CALLMT: case BC_CALLT: - case BC_RETM: case BC_RET: case BC_RET0: case BC_RET1: - offset = bcemit_INS(fs, ins); /* Copy original instruction. */ - fs->bcbase[offset].line = fs->bcbase[pc].line; - offset = offset-(pc+1)+BCBIAS_J; - if (offset > BCMAX_D) - err_syntax(fs->ls, LJ_ERR_XFIXUP); - /* Replace with UCLO plus branch. */ - fs->bcbase[pc].ins = BCINS_AD(BC_UCLO, 0, offset); - break; - case BC_UCLO: - return; /* We're done. */ - default: - break; - } - } - } -} - -/* Finish a FuncState and return the new prototype. */ -static GCproto *fs_finish(LexState *ls, BCLine line) -{ - lua_State *L = ls->L; - FuncState *fs = ls->fs; - BCLine numline = line - fs->linedefined; - size_t sizept, ofsk, ofsuv, ofsli, ofsdbg, ofsvar; - GCproto *pt; - - /* Apply final fixups. */ - fs_fixup_ret(fs); - - /* Calculate total size of prototype including all colocated arrays. */ - sizept = sizeof(GCproto) + fs->pc*sizeof(BCIns) + fs->nkgc*sizeof(GCRef); - sizept = (sizept + sizeof(TValue)-1) & ~(sizeof(TValue)-1); - ofsk = sizept; sizept += fs->nkn*sizeof(TValue); - ofsuv = sizept; sizept += ((fs->nuv+1)&~1)*2; - ofsli = sizept; sizept += fs_prep_line(fs, numline); - ofsdbg = sizept; sizept += fs_prep_var(ls, fs, &ofsvar); - - /* Allocate prototype and initialize its fields. */ - pt = (GCproto *)lj_mem_newgco(L, (MSize)sizept); - pt->gct = ~LJ_TPROTO; - pt->sizept = (MSize)sizept; - pt->trace = 0; - pt->flags = (uint8_t)(fs->flags & ~(PROTO_HAS_RETURN|PROTO_FIXUP_RETURN)); - pt->numparams = fs->numparams; - pt->framesize = fs->framesize; - setgcref(pt->chunkname, obj2gco(ls->chunkname)); - - /* Close potentially uninitialized gap between bc and kgc. */ - *(uint32_t *)((char *)pt + ofsk - sizeof(GCRef)*(fs->nkgc+1)) = 0; - fs_fixup_bc(fs, pt, (BCIns *)((char *)pt + sizeof(GCproto)), fs->pc); - fs_fixup_k(fs, pt, (void *)((char *)pt + ofsk)); - fs_fixup_uv1(fs, pt, (uint16_t *)((char *)pt + ofsuv)); - fs_fixup_line(fs, pt, (void *)((char *)pt + ofsli), numline); - fs_fixup_var(ls, pt, (uint8_t *)((char *)pt + ofsdbg), ofsvar); - - lj_vmevent_send(L, BC, - setprotoV(L, L->top++, pt); - ); - - L->top--; /* Pop table of constants. */ - ls->vtop = fs->vbase; /* Reset variable stack. */ - ls->fs = fs->prev; - lua_assert(ls->fs != NULL || ls->tok == TK_eof); - return pt; -} - -/* Initialize a new FuncState. */ -static void fs_init(LexState *ls, FuncState *fs) -{ - lua_State *L = ls->L; - fs->prev = ls->fs; ls->fs = fs; /* Append to list. */ - fs->ls = ls; - fs->vbase = ls->vtop; - fs->L = L; - fs->pc = 0; - fs->lasttarget = 0; - fs->jpc = NO_JMP; - fs->freereg = 0; - fs->nkgc = 0; - fs->nkn = 0; - fs->nactvar = 0; - fs->nuv = 0; - fs->bl = NULL; - fs->flags = 0; - fs->framesize = 1; /* Minimum frame size. */ - fs->kt = lj_tab_new(L, 0, 0); - /* Anchor table of constants in stack to avoid being collected. */ - settabV(L, L->top, fs->kt); - incr_top(L); -} - -/* -- Expressions --------------------------------------------------------- */ - -/* Forward declaration. */ -static void expr(LexState *ls, ExpDesc *v); - -/* Return string expression. */ -static void expr_str(LexState *ls, ExpDesc *e) -{ - expr_init(e, VKSTR, 0); - e->u.sval = lex_str(ls); -} - -/* Return index expression. */ -static void expr_index(FuncState *fs, ExpDesc *t, ExpDesc *e) -{ - /* Already called: expr_toval(fs, e). */ - t->k = VINDEXED; - if (expr_isnumk(e)) { -#if LJ_DUALNUM - if (tvisint(expr_numtv(e))) { - int32_t k = intV(expr_numtv(e)); - if (checku8(k)) { - t->u.s.aux = BCMAX_C+1+(uint32_t)k; /* 256..511: const byte key */ - return; - } - } -#else - lua_Number n = expr_numberV(e); - int32_t k = lj_num2int(n); - if (checku8(k) && n == (lua_Number)k) { - t->u.s.aux = BCMAX_C+1+(uint32_t)k; /* 256..511: const byte key */ - return; - } -#endif - } else if (expr_isstrk(e)) { - BCReg idx = const_str(fs, e); - if (idx <= BCMAX_C) { - t->u.s.aux = ~idx; /* -256..-1: const string key */ - return; - } - } - t->u.s.aux = expr_toanyreg(fs, e); /* 0..255: register */ -} - -/* Parse index expression with named field. */ -static void expr_field(LexState *ls, ExpDesc *v) -{ - FuncState *fs = ls->fs; - ExpDesc key; - expr_toanyreg(fs, v); - lj_lex_next(ls); /* Skip dot or colon. */ - expr_str(ls, &key); - expr_index(fs, v, &key); -} - -/* Parse index expression with brackets. */ -static void expr_bracket(LexState *ls, ExpDesc *v) -{ - lj_lex_next(ls); /* Skip '['. */ - expr(ls, v); - expr_toval(ls->fs, v); - lex_check(ls, ']'); -} - -/* Get value of constant expression. */ -static void expr_kvalue(TValue *v, ExpDesc *e) -{ - if (e->k <= VKTRUE) { - setpriV(v, ~(uint32_t)e->k); - } else if (e->k == VKSTR) { - setgcVraw(v, obj2gco(e->u.sval), LJ_TSTR); - } else { - lua_assert(tvisnumber(expr_numtv(e))); - *v = *expr_numtv(e); - } -} - -/* Parse table constructor expression. */ -static void expr_table(LexState *ls, ExpDesc *e) -{ - FuncState *fs = ls->fs; - BCLine line = ls->linenumber; - GCtab *t = NULL; - int vcall = 0, needarr = 0, fixt = 0; - uint32_t narr = 1; /* First array index. */ - uint32_t nhash = 0; /* Number of hash entries. */ - BCReg freg = fs->freereg; - BCPos pc = bcemit_AD(fs, BC_TNEW, freg, 0); - expr_init(e, VNONRELOC, freg); - bcreg_reserve(fs, 1); - freg++; - lex_check(ls, '{'); - while (ls->tok != '}') { - ExpDesc key, val; - vcall = 0; - if (ls->tok == '[') { - expr_bracket(ls, &key); /* Already calls expr_toval. */ - if (!expr_isk(&key)) expr_index(fs, e, &key); - if (expr_isnumk(&key) && expr_numiszero(&key)) needarr = 1; else nhash++; - lex_check(ls, '='); - } else if ((ls->tok == TK_name || (!LJ_52 && ls->tok == TK_goto)) && - lj_lex_lookahead(ls) == '=') { - expr_str(ls, &key); - lex_check(ls, '='); - nhash++; - } else { - expr_init(&key, VKNUM, 0); - setintV(&key.u.nval, (int)narr); - narr++; - needarr = vcall = 1; - } - expr(ls, &val); - if (expr_isk(&key) && key.k != VKNIL && - (key.k == VKSTR || expr_isk_nojump(&val))) { - TValue k, *v; - if (!t) { /* Create template table on demand. */ - BCReg kidx; - t = lj_tab_new(fs->L, needarr ? narr : 0, hsize2hbits(nhash)); - kidx = const_gc(fs, obj2gco(t), LJ_TTAB); - fs->bcbase[pc].ins = BCINS_AD(BC_TDUP, freg-1, kidx); - } - vcall = 0; - expr_kvalue(&k, &key); - v = lj_tab_set(fs->L, t, &k); - lj_gc_anybarriert(fs->L, t); - if (expr_isk_nojump(&val)) { /* Add const key/value to template table. */ - expr_kvalue(v, &val); - } else { /* Otherwise create dummy string key (avoids lj_tab_newkey). */ - settabV(fs->L, v, t); /* Preserve key with table itself as value. */ - fixt = 1; /* Fix this later, after all resizes. */ - goto nonconst; - } - } else { - nonconst: - if (val.k != VCALL) { expr_toanyreg(fs, &val); vcall = 0; } - if (expr_isk(&key)) expr_index(fs, e, &key); - bcemit_store(fs, e, &val); - } - fs->freereg = freg; - if (!lex_opt(ls, ',') && !lex_opt(ls, ';')) break; - } - lex_match(ls, '}', '{', line); - if (vcall) { - BCInsLine *ilp = &fs->bcbase[fs->pc-1]; - ExpDesc en; - lua_assert(bc_a(ilp->ins) == freg && - bc_op(ilp->ins) == (narr > 256 ? BC_TSETV : BC_TSETB)); - expr_init(&en, VKNUM, 0); - en.u.nval.u32.lo = narr-1; - en.u.nval.u32.hi = 0x43300000; /* Biased integer to avoid denormals. */ - if (narr > 256) { fs->pc--; ilp--; } - ilp->ins = BCINS_AD(BC_TSETM, freg, const_num(fs, &en)); - setbc_b(&ilp[-1].ins, 0); - } - if (pc == fs->pc-1) { /* Make expr relocable if possible. */ - e->u.s.info = pc; - fs->freereg--; - e->k = VRELOCABLE; - } else { - e->k = VNONRELOC; /* May have been changed by expr_index. */ - } - if (!t) { /* Construct TNEW RD: hhhhhaaaaaaaaaaa. */ - BCIns *ip = &fs->bcbase[pc].ins; - if (!needarr) narr = 0; - else if (narr < 3) narr = 3; - else if (narr > 0x7ff) narr = 0x7ff; - setbc_d(ip, narr|(hsize2hbits(nhash)<<11)); - } else { - if (needarr && t->asize < narr) - lj_tab_reasize(fs->L, t, narr-1); - if (fixt) { /* Fix value for dummy keys in template table. */ - Node *node = noderef(t->node); - uint32_t i, hmask = t->hmask; - for (i = 0; i <= hmask; i++) { - Node *n = &node[i]; - if (tvistab(&n->val)) { - lua_assert(tabV(&n->val) == t); - setnilV(&n->val); /* Turn value into nil. */ - } - } - } - lj_gc_check(fs->L); - } -} - -/* Parse function parameters. */ -static BCReg parse_params(LexState *ls, int needself) -{ - FuncState *fs = ls->fs; - BCReg nparams = 0; - lex_check(ls, '('); - if (needself) - var_new_lit(ls, nparams++, "self"); - if (ls->tok != ')') { - do { - if (ls->tok == TK_name || (!LJ_52 && ls->tok == TK_goto)) { - var_new(ls, nparams++, lex_str(ls)); - } else if (ls->tok == TK_dots) { - lj_lex_next(ls); - fs->flags |= PROTO_VARARG; - break; - } else { - err_syntax(ls, LJ_ERR_XPARAM); - } - } while (lex_opt(ls, ',')); - } - var_add(ls, nparams); - lua_assert(fs->nactvar == nparams); - bcreg_reserve(fs, nparams); - lex_check(ls, ')'); - return nparams; -} - -/* Forward declaration. */ -static void parse_chunk(LexState *ls); - -/* Parse body of a function. */ -static void parse_body(LexState *ls, ExpDesc *e, int needself, BCLine line) -{ - FuncState fs, *pfs = ls->fs; - FuncScope bl; - GCproto *pt; - ptrdiff_t oldbase = pfs->bcbase - ls->bcstack; - fs_init(ls, &fs); - fscope_begin(&fs, &bl, 0); - fs.linedefined = line; - fs.numparams = (uint8_t)parse_params(ls, needself); - fs.bcbase = pfs->bcbase + pfs->pc; - fs.bclim = pfs->bclim - pfs->pc; - bcemit_AD(&fs, BC_FUNCF, 0, 0); /* Placeholder. */ - parse_chunk(ls); - if (ls->tok != TK_end) lex_match(ls, TK_end, TK_function, line); - pt = fs_finish(ls, (ls->lastline = ls->linenumber)); - pfs->bcbase = ls->bcstack + oldbase; /* May have been reallocated. */ - pfs->bclim = (BCPos)(ls->sizebcstack - oldbase); - /* Store new prototype in the constant array of the parent. */ - expr_init(e, VRELOCABLE, - bcemit_AD(pfs, BC_FNEW, 0, const_gc(pfs, obj2gco(pt), LJ_TPROTO))); -#if LJ_HASFFI - pfs->flags |= (fs.flags & PROTO_FFI); -#endif - if (!(pfs->flags & PROTO_CHILD)) { - if (pfs->flags & PROTO_HAS_RETURN) - pfs->flags |= PROTO_FIXUP_RETURN; - pfs->flags |= PROTO_CHILD; - } - lj_lex_next(ls); -} - -/* Parse expression list. Last expression is left open. */ -static BCReg expr_list(LexState *ls, ExpDesc *v) -{ - BCReg n = 1; - expr(ls, v); - while (lex_opt(ls, ',')) { - expr_tonextreg(ls->fs, v); - expr(ls, v); - n++; - } - return n; -} - -/* Parse function argument list. */ -static void parse_args(LexState *ls, ExpDesc *e) -{ - FuncState *fs = ls->fs; - ExpDesc args; - BCIns ins; - BCReg base; - BCLine line = ls->linenumber; - if (ls->tok == '(') { -#if !LJ_52 - if (line != ls->lastline) - err_syntax(ls, LJ_ERR_XAMBIG); -#endif - lj_lex_next(ls); - if (ls->tok == ')') { /* f(). */ - args.k = VVOID; - } else { - expr_list(ls, &args); - if (args.k == VCALL) /* f(a, b, g()) or f(a, b, ...). */ - setbc_b(bcptr(fs, &args), 0); /* Pass on multiple results. */ - } - lex_match(ls, ')', '(', line); - } else if (ls->tok == '{') { - expr_table(ls, &args); - } else if (ls->tok == TK_string) { - expr_init(&args, VKSTR, 0); - args.u.sval = strV(&ls->tokval); - lj_lex_next(ls); - } else { - err_syntax(ls, LJ_ERR_XFUNARG); - return; /* Silence compiler. */ - } - lua_assert(e->k == VNONRELOC); - base = e->u.s.info; /* Base register for call. */ - if (args.k == VCALL) { - ins = BCINS_ABC(BC_CALLM, base, 2, args.u.s.aux - base - 1 - LJ_FR2); - } else { - if (args.k != VVOID) - expr_tonextreg(fs, &args); - ins = BCINS_ABC(BC_CALL, base, 2, fs->freereg - base - LJ_FR2); - } - expr_init(e, VCALL, bcemit_INS(fs, ins)); - e->u.s.aux = base; - fs->bcbase[fs->pc - 1].line = line; - fs->freereg = base+1; /* Leave one result by default. */ -} - -/* Parse primary expression. */ -static void expr_primary(LexState *ls, ExpDesc *v) -{ - FuncState *fs = ls->fs; - /* Parse prefix expression. */ - if (ls->tok == '(') { - BCLine line = ls->linenumber; - lj_lex_next(ls); - expr(ls, v); - lex_match(ls, ')', '(', line); - expr_discharge(ls->fs, v); - } else if (ls->tok == TK_name || (!LJ_52 && ls->tok == TK_goto)) { - var_lookup(ls, v); - } else { - err_syntax(ls, LJ_ERR_XSYMBOL); - } - for (;;) { /* Parse multiple expression suffixes. */ - if (ls->tok == '.') { - expr_field(ls, v); - } else if (ls->tok == '[') { - ExpDesc key; - expr_toanyreg(fs, v); - expr_bracket(ls, &key); - expr_index(fs, v, &key); - } else if (ls->tok == ':') { - ExpDesc key; - lj_lex_next(ls); - expr_str(ls, &key); - bcemit_method(fs, v, &key); - parse_args(ls, v); - } else if (ls->tok == '(' || ls->tok == TK_string || ls->tok == '{') { - expr_tonextreg(fs, v); - if (LJ_FR2) bcreg_reserve(fs, 1); - parse_args(ls, v); - } else { - break; - } - } -} - -/* Parse simple expression. */ -static void expr_simple(LexState *ls, ExpDesc *v) -{ - switch (ls->tok) { - case TK_number: - expr_init(v, (LJ_HASFFI && tviscdata(&ls->tokval)) ? VKCDATA : VKNUM, 0); - copyTV(ls->L, &v->u.nval, &ls->tokval); - break; - case TK_string: - expr_init(v, VKSTR, 0); - v->u.sval = strV(&ls->tokval); - break; - case TK_nil: - expr_init(v, VKNIL, 0); - break; - case TK_true: - expr_init(v, VKTRUE, 0); - break; - case TK_false: - expr_init(v, VKFALSE, 0); - break; - case TK_dots: { /* Vararg. */ - FuncState *fs = ls->fs; - BCReg base; - checkcond(ls, fs->flags & PROTO_VARARG, LJ_ERR_XDOTS); - bcreg_reserve(fs, 1); - base = fs->freereg-1; - expr_init(v, VCALL, bcemit_ABC(fs, BC_VARG, base, 2, fs->numparams)); - v->u.s.aux = base; - break; - } - case '{': /* Table constructor. */ - expr_table(ls, v); - return; - case TK_function: - lj_lex_next(ls); - parse_body(ls, v, 0, ls->linenumber); - return; - default: - expr_primary(ls, v); - return; - } - lj_lex_next(ls); -} - -/* Manage syntactic levels to avoid blowing up the stack. */ -static void synlevel_begin(LexState *ls) -{ - if (++ls->level >= LJ_MAX_XLEVEL) - lj_lex_error(ls, 0, LJ_ERR_XLEVELS); -} - -#define synlevel_end(ls) ((ls)->level--) - -/* Convert token to binary operator. */ -static BinOpr token2binop(LexToken tok) -{ - switch (tok) { - case '+': return OPR_ADD; - case '-': return OPR_SUB; - case '*': return OPR_MUL; - case '/': return OPR_DIV; - case '%': return OPR_MOD; - case '^': return OPR_POW; - case TK_concat: return OPR_CONCAT; - case TK_ne: return OPR_NE; - case TK_eq: return OPR_EQ; - case '<': return OPR_LT; - case TK_le: return OPR_LE; - case '>': return OPR_GT; - case TK_ge: return OPR_GE; - case TK_and: return OPR_AND; - case TK_or: return OPR_OR; - default: return OPR_NOBINOPR; - } -} - -/* Priorities for each binary operator. ORDER OPR. */ -static const struct { - uint8_t left; /* Left priority. */ - uint8_t right; /* Right priority. */ -} priority[] = { - {6,6}, {6,6}, {7,7}, {7,7}, {7,7}, /* ADD SUB MUL DIV MOD */ - {10,9}, {5,4}, /* POW CONCAT (right associative) */ - {3,3}, {3,3}, /* EQ NE */ - {3,3}, {3,3}, {3,3}, {3,3}, /* LT GE GT LE */ - {2,2}, {1,1} /* AND OR */ -}; - -#define UNARY_PRIORITY 8 /* Priority for unary operators. */ - -/* Forward declaration. */ -static BinOpr expr_binop(LexState *ls, ExpDesc *v, uint32_t limit); - -/* Parse unary expression. */ -static void expr_unop(LexState *ls, ExpDesc *v) -{ - BCOp op; - if (ls->tok == TK_not) { - op = BC_NOT; - } else if (ls->tok == '-') { - op = BC_UNM; - } else if (ls->tok == '#') { - op = BC_LEN; - } else { - expr_simple(ls, v); - return; - } - lj_lex_next(ls); - expr_binop(ls, v, UNARY_PRIORITY); - bcemit_unop(ls->fs, op, v); -} - -/* Parse binary expressions with priority higher than the limit. */ -static BinOpr expr_binop(LexState *ls, ExpDesc *v, uint32_t limit) -{ - BinOpr op; - synlevel_begin(ls); - expr_unop(ls, v); - op = token2binop(ls->tok); - while (op != OPR_NOBINOPR && priority[op].left > limit) { - ExpDesc v2; - BinOpr nextop; - lj_lex_next(ls); - bcemit_binop_left(ls->fs, op, v); - /* Parse binary expression with higher priority. */ - nextop = expr_binop(ls, &v2, priority[op].right); - bcemit_binop(ls->fs, op, v, &v2); - op = nextop; - } - synlevel_end(ls); - return op; /* Return unconsumed binary operator (if any). */ -} - -/* Parse expression. */ -static void expr(LexState *ls, ExpDesc *v) -{ - expr_binop(ls, v, 0); /* Priority 0: parse whole expression. */ -} - -/* Assign expression to the next register. */ -static void expr_next(LexState *ls) -{ - ExpDesc e; - expr(ls, &e); - expr_tonextreg(ls->fs, &e); -} - -/* Parse conditional expression. */ -static BCPos expr_cond(LexState *ls) -{ - ExpDesc v; - expr(ls, &v); - if (v.k == VKNIL) v.k = VKFALSE; - bcemit_branch_t(ls->fs, &v); - return v.f; -} - -/* -- Assignments --------------------------------------------------------- */ - -/* List of LHS variables. */ -typedef struct LHSVarList { - ExpDesc v; /* LHS variable. */ - struct LHSVarList *prev; /* Link to previous LHS variable. */ -} LHSVarList; - -/* Eliminate write-after-read hazards for local variable assignment. */ -static void assign_hazard(LexState *ls, LHSVarList *lh, const ExpDesc *v) -{ - FuncState *fs = ls->fs; - BCReg reg = v->u.s.info; /* Check against this variable. */ - BCReg tmp = fs->freereg; /* Rename to this temp. register (if needed). */ - int hazard = 0; - for (; lh; lh = lh->prev) { - if (lh->v.k == VINDEXED) { - if (lh->v.u.s.info == reg) { /* t[i], t = 1, 2 */ - hazard = 1; - lh->v.u.s.info = tmp; - } - if (lh->v.u.s.aux == reg) { /* t[i], i = 1, 2 */ - hazard = 1; - lh->v.u.s.aux = tmp; - } - } - } - if (hazard) { - bcemit_AD(fs, BC_MOV, tmp, reg); /* Rename conflicting variable. */ - bcreg_reserve(fs, 1); - } -} - -/* Adjust LHS/RHS of an assignment. */ -static void assign_adjust(LexState *ls, BCReg nvars, BCReg nexps, ExpDesc *e) -{ - FuncState *fs = ls->fs; - int32_t extra = (int32_t)nvars - (int32_t)nexps; - if (e->k == VCALL) { - extra++; /* Compensate for the VCALL itself. */ - if (extra < 0) extra = 0; - setbc_b(bcptr(fs, e), extra+1); /* Fixup call results. */ - if (extra > 1) bcreg_reserve(fs, (BCReg)extra-1); - } else { - if (e->k != VVOID) - expr_tonextreg(fs, e); /* Close last expression. */ - if (extra > 0) { /* Leftover LHS are set to nil. */ - BCReg reg = fs->freereg; - bcreg_reserve(fs, (BCReg)extra); - bcemit_nil(fs, reg, (BCReg)extra); - } - } - if (nexps > nvars) - ls->fs->freereg -= nexps - nvars; /* Drop leftover regs. */ -} - -/* Recursively parse assignment statement. */ -static void parse_assignment(LexState *ls, LHSVarList *lh, BCReg nvars) -{ - ExpDesc e; - checkcond(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED, LJ_ERR_XSYNTAX); - if (lex_opt(ls, ',')) { /* Collect LHS list and recurse upwards. */ - LHSVarList vl; - vl.prev = lh; - expr_primary(ls, &vl.v); - if (vl.v.k == VLOCAL) - assign_hazard(ls, lh, &vl.v); - checklimit(ls->fs, ls->level + nvars, LJ_MAX_XLEVEL, "variable names"); - parse_assignment(ls, &vl, nvars+1); - } else { /* Parse RHS. */ - BCReg nexps; - lex_check(ls, '='); - nexps = expr_list(ls, &e); - if (nexps == nvars) { - if (e.k == VCALL) { - if (bc_op(*bcptr(ls->fs, &e)) == BC_VARG) { /* Vararg assignment. */ - ls->fs->freereg--; - e.k = VRELOCABLE; - } else { /* Multiple call results. */ - e.u.s.info = e.u.s.aux; /* Base of call is not relocatable. */ - e.k = VNONRELOC; - } - } - bcemit_store(ls->fs, &lh->v, &e); - return; - } - assign_adjust(ls, nvars, nexps, &e); - } - /* Assign RHS to LHS and recurse downwards. */ - expr_init(&e, VNONRELOC, ls->fs->freereg-1); - bcemit_store(ls->fs, &lh->v, &e); -} - -/* Parse call statement or assignment. */ -static void parse_call_assign(LexState *ls) -{ - FuncState *fs = ls->fs; - LHSVarList vl; - expr_primary(ls, &vl.v); - if (vl.v.k == VCALL) { /* Function call statement. */ - setbc_b(bcptr(fs, &vl.v), 1); /* No results. */ - } else { /* Start of an assignment. */ - vl.prev = NULL; - parse_assignment(ls, &vl, 1); - } -} - -/* Parse 'local' statement. */ -static void parse_local(LexState *ls) -{ - if (lex_opt(ls, TK_function)) { /* Local function declaration. */ - ExpDesc v, b; - FuncState *fs = ls->fs; - var_new(ls, 0, lex_str(ls)); - expr_init(&v, VLOCAL, fs->freereg); - v.u.s.aux = fs->varmap[fs->freereg]; - bcreg_reserve(fs, 1); - var_add(ls, 1); - parse_body(ls, &b, 0, ls->linenumber); - /* bcemit_store(fs, &v, &b) without setting VSTACK_VAR_RW. */ - expr_free(fs, &b); - expr_toreg(fs, &b, v.u.s.info); - /* The upvalue is in scope, but the local is only valid after the store. */ - var_get(ls, fs, fs->nactvar - 1).startpc = fs->pc; - } else { /* Local variable declaration. */ - ExpDesc e; - BCReg nexps, nvars = 0; - do { /* Collect LHS. */ - var_new(ls, nvars++, lex_str(ls)); - } while (lex_opt(ls, ',')); - if (lex_opt(ls, '=')) { /* Optional RHS. */ - nexps = expr_list(ls, &e); - } else { /* Or implicitly set to nil. */ - e.k = VVOID; - nexps = 0; - } - assign_adjust(ls, nvars, nexps, &e); - var_add(ls, nvars); - } -} - -/* Parse 'function' statement. */ -static void parse_func(LexState *ls, BCLine line) -{ - FuncState *fs; - ExpDesc v, b; - int needself = 0; - lj_lex_next(ls); /* Skip 'function'. */ - /* Parse function name. */ - var_lookup(ls, &v); - while (ls->tok == '.') /* Multiple dot-separated fields. */ - expr_field(ls, &v); - if (ls->tok == ':') { /* Optional colon to signify method call. */ - needself = 1; - expr_field(ls, &v); - } - parse_body(ls, &b, needself, line); - fs = ls->fs; - bcemit_store(fs, &v, &b); - fs->bcbase[fs->pc - 1].line = line; /* Set line for the store. */ -} - -/* -- Control transfer statements ----------------------------------------- */ - -/* Check for end of block. */ -static int parse_isend(LexToken tok) -{ - switch (tok) { - case TK_else: case TK_elseif: case TK_end: case TK_until: case TK_eof: - return 1; - default: - return 0; - } -} - -/* Parse 'return' statement. */ -static void parse_return(LexState *ls) -{ - BCIns ins; - FuncState *fs = ls->fs; - lj_lex_next(ls); /* Skip 'return'. */ - fs->flags |= PROTO_HAS_RETURN; - if (parse_isend(ls->tok) || ls->tok == ';') { /* Bare return. */ - ins = BCINS_AD(BC_RET0, 0, 1); - } else { /* Return with one or more values. */ - ExpDesc e; /* Receives the _last_ expression in the list. */ - BCReg nret = expr_list(ls, &e); - if (nret == 1) { /* Return one result. */ - if (e.k == VCALL) { /* Check for tail call. */ - BCIns *ip = bcptr(fs, &e); - /* It doesn't pay off to add BC_VARGT just for 'return ...'. */ - if (bc_op(*ip) == BC_VARG) goto notailcall; - fs->pc--; - ins = BCINS_AD(bc_op(*ip)-BC_CALL+BC_CALLT, bc_a(*ip), bc_c(*ip)); - } else { /* Can return the result from any register. */ - ins = BCINS_AD(BC_RET1, expr_toanyreg(fs, &e), 2); - } - } else { - if (e.k == VCALL) { /* Append all results from a call. */ - notailcall: - setbc_b(bcptr(fs, &e), 0); - ins = BCINS_AD(BC_RETM, fs->nactvar, e.u.s.aux - fs->nactvar); - } else { - expr_tonextreg(fs, &e); /* Force contiguous registers. */ - ins = BCINS_AD(BC_RET, fs->nactvar, nret+1); - } - } - } - if (fs->flags & PROTO_CHILD) - bcemit_AJ(fs, BC_UCLO, 0, 0); /* May need to close upvalues first. */ - bcemit_INS(fs, ins); -} - -/* Parse 'break' statement. */ -static void parse_break(LexState *ls) -{ - ls->fs->bl->flags |= FSCOPE_BREAK; - gola_new(ls, NAME_BREAK, VSTACK_GOTO, bcemit_jmp(ls->fs)); -} - -/* Parse 'goto' statement. */ -static void parse_goto(LexState *ls) -{ - FuncState *fs = ls->fs; - GCstr *name = lex_str(ls); - VarInfo *vl = gola_findlabel(ls, name); - if (vl) /* Treat backwards goto within same scope like a loop. */ - bcemit_AJ(fs, BC_LOOP, vl->slot, -1); /* No BC range check. */ - fs->bl->flags |= FSCOPE_GOLA; - gola_new(ls, name, VSTACK_GOTO, bcemit_jmp(fs)); -} - -/* Parse label. */ -static void parse_label(LexState *ls) -{ - FuncState *fs = ls->fs; - GCstr *name; - MSize idx; - fs->lasttarget = fs->pc; - fs->bl->flags |= FSCOPE_GOLA; - lj_lex_next(ls); /* Skip '::'. */ - name = lex_str(ls); - if (gola_findlabel(ls, name)) - lj_lex_error(ls, 0, LJ_ERR_XLDUP, strdata(name)); - idx = gola_new(ls, name, VSTACK_LABEL, fs->pc); - lex_check(ls, TK_label); - /* Recursively parse trailing statements: labels and ';' (Lua 5.2 only). */ - for (;;) { - if (ls->tok == TK_label) { - synlevel_begin(ls); - parse_label(ls); - synlevel_end(ls); - } else if (LJ_52 && ls->tok == ';') { - lj_lex_next(ls); - } else { - break; - } - } - /* Trailing label is considered to be outside of scope. */ - if (parse_isend(ls->tok) && ls->tok != TK_until) - ls->vstack[idx].slot = fs->bl->nactvar; - gola_resolve(ls, fs->bl, idx); -} - -/* -- Blocks, loops and conditional statements ---------------------------- */ - -/* Parse a block. */ -static void parse_block(LexState *ls) -{ - FuncState *fs = ls->fs; - FuncScope bl; - fscope_begin(fs, &bl, 0); - parse_chunk(ls); - fscope_end(fs); -} - -/* Parse 'while' statement. */ -static void parse_while(LexState *ls, BCLine line) -{ - FuncState *fs = ls->fs; - BCPos start, loop, condexit; - FuncScope bl; - lj_lex_next(ls); /* Skip 'while'. */ - start = fs->lasttarget = fs->pc; - condexit = expr_cond(ls); - fscope_begin(fs, &bl, FSCOPE_LOOP); - lex_check(ls, TK_do); - loop = bcemit_AD(fs, BC_LOOP, fs->nactvar, 0); - parse_block(ls); - jmp_patch(fs, bcemit_jmp(fs), start); - lex_match(ls, TK_end, TK_while, line); - fscope_end(fs); - jmp_tohere(fs, condexit); - jmp_patchins(fs, loop, fs->pc); -} - -/* Parse 'repeat' statement. */ -static void parse_repeat(LexState *ls, BCLine line) -{ - FuncState *fs = ls->fs; - BCPos loop = fs->lasttarget = fs->pc; - BCPos condexit; - FuncScope bl1, bl2; - fscope_begin(fs, &bl1, FSCOPE_LOOP); /* Breakable loop scope. */ - fscope_begin(fs, &bl2, 0); /* Inner scope. */ - lj_lex_next(ls); /* Skip 'repeat'. */ - bcemit_AD(fs, BC_LOOP, fs->nactvar, 0); - parse_chunk(ls); - lex_match(ls, TK_until, TK_repeat, line); - condexit = expr_cond(ls); /* Parse condition (still inside inner scope). */ - if (!(bl2.flags & FSCOPE_UPVAL)) { /* No upvalues? Just end inner scope. */ - fscope_end(fs); - } else { /* Otherwise generate: cond: UCLO+JMP out, !cond: UCLO+JMP loop. */ - parse_break(ls); /* Break from loop and close upvalues. */ - jmp_tohere(fs, condexit); - fscope_end(fs); /* End inner scope and close upvalues. */ - condexit = bcemit_jmp(fs); - } - jmp_patch(fs, condexit, loop); /* Jump backwards if !cond. */ - jmp_patchins(fs, loop, fs->pc); - fscope_end(fs); /* End loop scope. */ -} - -/* Parse numeric 'for'. */ -static void parse_for_num(LexState *ls, GCstr *varname, BCLine line) -{ - FuncState *fs = ls->fs; - BCReg base = fs->freereg; - FuncScope bl; - BCPos loop, loopend; - /* Hidden control variables. */ - var_new_fixed(ls, FORL_IDX, VARNAME_FOR_IDX); - var_new_fixed(ls, FORL_STOP, VARNAME_FOR_STOP); - var_new_fixed(ls, FORL_STEP, VARNAME_FOR_STEP); - /* Visible copy of index variable. */ - var_new(ls, FORL_EXT, varname); - lex_check(ls, '='); - expr_next(ls); - lex_check(ls, ','); - expr_next(ls); - if (lex_opt(ls, ',')) { - expr_next(ls); - } else { - bcemit_AD(fs, BC_KSHORT, fs->freereg, 1); /* Default step is 1. */ - bcreg_reserve(fs, 1); - } - var_add(ls, 3); /* Hidden control variables. */ - lex_check(ls, TK_do); - loop = bcemit_AJ(fs, BC_FORI, base, NO_JMP); - fscope_begin(fs, &bl, 0); /* Scope for visible variables. */ - var_add(ls, 1); - bcreg_reserve(fs, 1); - parse_block(ls); - fscope_end(fs); - /* Perform loop inversion. Loop control instructions are at the end. */ - loopend = bcemit_AJ(fs, BC_FORL, base, NO_JMP); - fs->bcbase[loopend].line = line; /* Fix line for control ins. */ - jmp_patchins(fs, loopend, loop+1); - jmp_patchins(fs, loop, fs->pc); -} - -/* Try to predict whether the iterator is next() and specialize the bytecode. -** Detecting next() and pairs() by name is simplistic, but quite effective. -** The interpreter backs off if the check for the closure fails at runtime. -*/ -static int predict_next(LexState *ls, FuncState *fs, BCPos pc) -{ - BCIns ins = fs->bcbase[pc].ins; - GCstr *name; - cTValue *o; - switch (bc_op(ins)) { - case BC_MOV: - name = gco2str(gcref(var_get(ls, fs, bc_d(ins)).name)); - break; - case BC_UGET: - name = gco2str(gcref(ls->vstack[fs->uvmap[bc_d(ins)]].name)); - break; - case BC_GGET: - /* There's no inverse index (yet), so lookup the strings. */ - o = lj_tab_getstr(fs->kt, lj_str_newlit(ls->L, "pairs")); - if (o && tvhaskslot(o) && tvkslot(o) == bc_d(ins)) - return 1; - o = lj_tab_getstr(fs->kt, lj_str_newlit(ls->L, "next")); - if (o && tvhaskslot(o) && tvkslot(o) == bc_d(ins)) - return 1; - return 0; - default: - return 0; - } - return (name->len == 5 && !strcmp(strdata(name), "pairs")) || - (name->len == 4 && !strcmp(strdata(name), "next")); -} - -/* Parse 'for' iterator. */ -static void parse_for_iter(LexState *ls, GCstr *indexname) -{ - FuncState *fs = ls->fs; - ExpDesc e; - BCReg nvars = 0; - BCLine line; - BCReg base = fs->freereg + 3; - BCPos loop, loopend, exprpc = fs->pc; - FuncScope bl; - int isnext; - /* Hidden control variables. */ - var_new_fixed(ls, nvars++, VARNAME_FOR_GEN); - var_new_fixed(ls, nvars++, VARNAME_FOR_STATE); - var_new_fixed(ls, nvars++, VARNAME_FOR_CTL); - /* Visible variables returned from iterator. */ - var_new(ls, nvars++, indexname); - while (lex_opt(ls, ',')) - var_new(ls, nvars++, lex_str(ls)); - lex_check(ls, TK_in); - line = ls->linenumber; - assign_adjust(ls, 3, expr_list(ls, &e), &e); - /* The iterator needs another 3 [4] slots (func [pc] | state ctl). */ - bcreg_bump(fs, 3+LJ_FR2); - isnext = (nvars <= 5 && predict_next(ls, fs, exprpc)); - var_add(ls, 3); /* Hidden control variables. */ - lex_check(ls, TK_do); - loop = bcemit_AJ(fs, isnext ? BC_ISNEXT : BC_JMP, base, NO_JMP); - fscope_begin(fs, &bl, 0); /* Scope for visible variables. */ - var_add(ls, nvars-3); - bcreg_reserve(fs, nvars-3); - parse_block(ls); - fscope_end(fs); - /* Perform loop inversion. Loop control instructions are at the end. */ - jmp_patchins(fs, loop, fs->pc); - bcemit_ABC(fs, isnext ? BC_ITERN : BC_ITERC, base, nvars-3+1, 2+1); - loopend = bcemit_AJ(fs, BC_ITERL, base, NO_JMP); - fs->bcbase[loopend-1].line = line; /* Fix line for control ins. */ - fs->bcbase[loopend].line = line; - jmp_patchins(fs, loopend, loop+1); -} - -/* Parse 'for' statement. */ -static void parse_for(LexState *ls, BCLine line) -{ - FuncState *fs = ls->fs; - GCstr *varname; - FuncScope bl; - fscope_begin(fs, &bl, FSCOPE_LOOP); - lj_lex_next(ls); /* Skip 'for'. */ - varname = lex_str(ls); /* Get first variable name. */ - if (ls->tok == '=') - parse_for_num(ls, varname, line); - else if (ls->tok == ',' || ls->tok == TK_in) - parse_for_iter(ls, varname); - else - err_syntax(ls, LJ_ERR_XFOR); - lex_match(ls, TK_end, TK_for, line); - fscope_end(fs); /* Resolve break list. */ -} - -/* Parse condition and 'then' block. */ -static BCPos parse_then(LexState *ls) -{ - BCPos condexit; - lj_lex_next(ls); /* Skip 'if' or 'elseif'. */ - condexit = expr_cond(ls); - lex_check(ls, TK_then); - parse_block(ls); - return condexit; -} - -/* Parse 'if' statement. */ -static void parse_if(LexState *ls, BCLine line) -{ - FuncState *fs = ls->fs; - BCPos flist; - BCPos escapelist = NO_JMP; - flist = parse_then(ls); - while (ls->tok == TK_elseif) { /* Parse multiple 'elseif' blocks. */ - jmp_append(fs, &escapelist, bcemit_jmp(fs)); - jmp_tohere(fs, flist); - flist = parse_then(ls); - } - if (ls->tok == TK_else) { /* Parse optional 'else' block. */ - jmp_append(fs, &escapelist, bcemit_jmp(fs)); - jmp_tohere(fs, flist); - lj_lex_next(ls); /* Skip 'else'. */ - parse_block(ls); - } else { - jmp_append(fs, &escapelist, flist); - } - jmp_tohere(fs, escapelist); - lex_match(ls, TK_end, TK_if, line); -} - -/* -- Parse statements ---------------------------------------------------- */ - -/* Parse a statement. Returns 1 if it must be the last one in a chunk. */ -static int parse_stmt(LexState *ls) -{ - BCLine line = ls->linenumber; - switch (ls->tok) { - case TK_if: - parse_if(ls, line); - break; - case TK_while: - parse_while(ls, line); - break; - case TK_do: - lj_lex_next(ls); - parse_block(ls); - lex_match(ls, TK_end, TK_do, line); - break; - case TK_for: - parse_for(ls, line); - break; - case TK_repeat: - parse_repeat(ls, line); - break; - case TK_function: - parse_func(ls, line); - break; - case TK_local: - lj_lex_next(ls); - parse_local(ls); - break; - case TK_return: - parse_return(ls); - return 1; /* Must be last. */ - case TK_break: - lj_lex_next(ls); - parse_break(ls); - return !LJ_52; /* Must be last in Lua 5.1. */ -#if LJ_52 - case ';': - lj_lex_next(ls); - break; -#endif - case TK_label: - parse_label(ls); - break; - case TK_goto: - if (LJ_52 || lj_lex_lookahead(ls) == TK_name) { - lj_lex_next(ls); - parse_goto(ls); - break; - } - /* fallthrough */ - default: - parse_call_assign(ls); - break; - } - return 0; -} - -/* A chunk is a list of statements optionally separated by semicolons. */ -static void parse_chunk(LexState *ls) -{ - int islast = 0; - synlevel_begin(ls); - while (!islast && !parse_isend(ls->tok)) { - islast = parse_stmt(ls); - lex_opt(ls, ';'); - lua_assert(ls->fs->framesize >= ls->fs->freereg && - ls->fs->freereg >= ls->fs->nactvar); - ls->fs->freereg = ls->fs->nactvar; /* Free registers after each stmt. */ - } - synlevel_end(ls); -} - -/* Entry point of bytecode parser. */ -GCproto *lj_parse(LexState *ls) -{ - FuncState fs; - FuncScope bl; - GCproto *pt; - lua_State *L = ls->L; -#ifdef LUAJIT_DISABLE_DEBUGINFO - ls->chunkname = lj_str_newlit(L, "="); -#else - ls->chunkname = lj_str_newz(L, ls->chunkarg); -#endif - setstrV(L, L->top, ls->chunkname); /* Anchor chunkname string. */ - incr_top(L); - ls->level = 0; - fs_init(ls, &fs); - fs.linedefined = 0; - fs.numparams = 0; - fs.bcbase = NULL; - fs.bclim = 0; - fs.flags |= PROTO_VARARG; /* Main chunk is always a vararg func. */ - fscope_begin(&fs, &bl, 0); - bcemit_AD(&fs, BC_FUNCV, 0, 0); /* Placeholder. */ - lj_lex_next(ls); /* Read-ahead first token. */ - parse_chunk(ls); - if (ls->tok != TK_eof) - err_token(ls, TK_eof); - pt = fs_finish(ls, ls->linenumber); - L->top--; /* Drop chunkname. */ - lua_assert(fs.prev == NULL); - lua_assert(ls->fs == NULL); - lua_assert(pt->sizeuv == 0); - return pt; -} - diff --git a/lib/LuaJIT/src/lj_parse.h b/lib/LuaJIT/src/lj_parse.h deleted file mode 100644 index ceeab69..0000000 --- a/lib/LuaJIT/src/lj_parse.h +++ /dev/null @@ -1,18 +0,0 @@ -/* -** Lua parser (source code -> bytecode). -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_PARSE_H -#define _LJ_PARSE_H - -#include "lj_obj.h" -#include "lj_lex.h" - -LJ_FUNC GCproto *lj_parse(LexState *ls); -LJ_FUNC GCstr *lj_parse_keepstr(LexState *ls, const char *str, size_t l); -#if LJ_HASFFI -LJ_FUNC void lj_parse_keepcdata(LexState *ls, TValue *tv, GCcdata *cd); -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_profile.c b/lib/LuaJIT/src/lj_profile.c deleted file mode 100644 index 3223697..0000000 --- a/lib/LuaJIT/src/lj_profile.c +++ /dev/null @@ -1,368 +0,0 @@ -/* -** Low-overhead profiling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_profile_c -#define LUA_CORE - -#include "lj_obj.h" - -#if LJ_HASPROFILE - -#include "lj_buf.h" -#include "lj_frame.h" -#include "lj_debug.h" -#include "lj_dispatch.h" -#if LJ_HASJIT -#include "lj_jit.h" -#include "lj_trace.h" -#endif -#include "lj_profile.h" - -#include "luajit.h" - -#if LJ_PROFILE_SIGPROF - -#include -#include -#define profile_lock(ps) UNUSED(ps) -#define profile_unlock(ps) UNUSED(ps) - -#elif LJ_PROFILE_PTHREAD - -#include -#include -#if LJ_TARGET_PS3 -#include -#endif -#define profile_lock(ps) pthread_mutex_lock(&ps->lock) -#define profile_unlock(ps) pthread_mutex_unlock(&ps->lock) - -#elif LJ_PROFILE_WTHREAD - -#define WIN32_LEAN_AND_MEAN -#if LJ_TARGET_XBOX360 -#include -#include -#else -#include -#endif -typedef unsigned int (WINAPI *WMM_TPFUNC)(unsigned int); -#define profile_lock(ps) EnterCriticalSection(&ps->lock) -#define profile_unlock(ps) LeaveCriticalSection(&ps->lock) - -#endif - -/* Profiler state. */ -typedef struct ProfileState { - global_State *g; /* VM state that started the profiler. */ - luaJIT_profile_callback cb; /* Profiler callback. */ - void *data; /* Profiler callback data. */ - SBuf sb; /* String buffer for stack dumps. */ - int interval; /* Sample interval in milliseconds. */ - int samples; /* Number of samples for next callback. */ - int vmstate; /* VM state when profile timer triggered. */ -#if LJ_PROFILE_SIGPROF - struct sigaction oldsa; /* Previous SIGPROF state. */ -#elif LJ_PROFILE_PTHREAD - pthread_mutex_t lock; /* g->hookmask update lock. */ - pthread_t thread; /* Timer thread. */ - int abort; /* Abort timer thread. */ -#elif LJ_PROFILE_WTHREAD -#if LJ_TARGET_WINDOWS - HINSTANCE wmm; /* WinMM library handle. */ - WMM_TPFUNC wmm_tbp; /* WinMM timeBeginPeriod function. */ - WMM_TPFUNC wmm_tep; /* WinMM timeEndPeriod function. */ -#endif - CRITICAL_SECTION lock; /* g->hookmask update lock. */ - HANDLE thread; /* Timer thread. */ - int abort; /* Abort timer thread. */ -#endif -} ProfileState; - -/* Sadly, we have to use a static profiler state. -** -** The SIGPROF variant needs a static pointer to the global state, anyway. -** And it would be hard to extend for multiple threads. You can still use -** multiple VMs in multiple threads, but only profile one at a time. -*/ -static ProfileState profile_state; - -/* Default sample interval in milliseconds. */ -#define LJ_PROFILE_INTERVAL_DEFAULT 10 - -/* -- Profiler/hook interaction ------------------------------------------- */ - -#if !LJ_PROFILE_SIGPROF -void LJ_FASTCALL lj_profile_hook_enter(global_State *g) -{ - ProfileState *ps = &profile_state; - if (ps->g) { - profile_lock(ps); - hook_enter(g); - profile_unlock(ps); - } else { - hook_enter(g); - } -} - -void LJ_FASTCALL lj_profile_hook_leave(global_State *g) -{ - ProfileState *ps = &profile_state; - if (ps->g) { - profile_lock(ps); - hook_leave(g); - profile_unlock(ps); - } else { - hook_leave(g); - } -} -#endif - -/* -- Profile callbacks --------------------------------------------------- */ - -/* Callback from profile hook (HOOK_PROFILE already cleared). */ -void LJ_FASTCALL lj_profile_interpreter(lua_State *L) -{ - ProfileState *ps = &profile_state; - global_State *g = G(L); - uint8_t mask; - profile_lock(ps); - mask = (g->hookmask & ~HOOK_PROFILE); - if (!(mask & HOOK_VMEVENT)) { - int samples = ps->samples; - ps->samples = 0; - g->hookmask = HOOK_VMEVENT; - lj_dispatch_update(g); - profile_unlock(ps); - ps->cb(ps->data, L, samples, ps->vmstate); /* Invoke user callback. */ - profile_lock(ps); - mask |= (g->hookmask & HOOK_PROFILE); - } - g->hookmask = mask; - lj_dispatch_update(g); - profile_unlock(ps); -} - -/* Trigger profile hook. Asynchronous call from OS-specific profile timer. */ -static void profile_trigger(ProfileState *ps) -{ - global_State *g = ps->g; - uint8_t mask; - profile_lock(ps); - ps->samples++; /* Always increment number of samples. */ - mask = g->hookmask; - if (!(mask & (HOOK_PROFILE|HOOK_VMEVENT))) { /* Set profile hook. */ - int st = g->vmstate; - ps->vmstate = st >= 0 ? 'N' : - st == ~LJ_VMST_INTERP ? 'I' : - st == ~LJ_VMST_C ? 'C' : - st == ~LJ_VMST_GC ? 'G' : 'J'; - g->hookmask = (mask | HOOK_PROFILE); - lj_dispatch_update(g); - } - profile_unlock(ps); -} - -/* -- OS-specific profile timer handling ---------------------------------- */ - -#if LJ_PROFILE_SIGPROF - -/* SIGPROF handler. */ -static void profile_signal(int sig) -{ - UNUSED(sig); - profile_trigger(&profile_state); -} - -/* Start profiling timer. */ -static void profile_timer_start(ProfileState *ps) -{ - int interval = ps->interval; - struct itimerval tm; - struct sigaction sa; - tm.it_value.tv_sec = tm.it_interval.tv_sec = interval / 1000; - tm.it_value.tv_usec = tm.it_interval.tv_usec = (interval % 1000) * 1000; - setitimer(ITIMER_PROF, &tm, NULL); - sa.sa_flags = SA_RESTART; - sa.sa_handler = profile_signal; - sigemptyset(&sa.sa_mask); - sigaction(SIGPROF, &sa, &ps->oldsa); -} - -/* Stop profiling timer. */ -static void profile_timer_stop(ProfileState *ps) -{ - struct itimerval tm; - tm.it_value.tv_sec = tm.it_interval.tv_sec = 0; - tm.it_value.tv_usec = tm.it_interval.tv_usec = 0; - setitimer(ITIMER_PROF, &tm, NULL); - sigaction(SIGPROF, &ps->oldsa, NULL); -} - -#elif LJ_PROFILE_PTHREAD - -/* POSIX timer thread. */ -static void *profile_thread(ProfileState *ps) -{ - int interval = ps->interval; -#if !LJ_TARGET_PS3 - struct timespec ts; - ts.tv_sec = interval / 1000; - ts.tv_nsec = (interval % 1000) * 1000000; -#endif - while (1) { -#if LJ_TARGET_PS3 - sys_timer_usleep(interval * 1000); -#else - nanosleep(&ts, NULL); -#endif - if (ps->abort) break; - profile_trigger(ps); - } - return NULL; -} - -/* Start profiling timer thread. */ -static void profile_timer_start(ProfileState *ps) -{ - pthread_mutex_init(&ps->lock, 0); - ps->abort = 0; - pthread_create(&ps->thread, NULL, (void *(*)(void *))profile_thread, ps); -} - -/* Stop profiling timer thread. */ -static void profile_timer_stop(ProfileState *ps) -{ - ps->abort = 1; - pthread_join(ps->thread, NULL); - pthread_mutex_destroy(&ps->lock); -} - -#elif LJ_PROFILE_WTHREAD - -/* Windows timer thread. */ -static DWORD WINAPI profile_thread(void *psx) -{ - ProfileState *ps = (ProfileState *)psx; - int interval = ps->interval; -#if LJ_TARGET_WINDOWS && !LJ_TARGET_UWP - ps->wmm_tbp(interval); -#endif - while (1) { - Sleep(interval); - if (ps->abort) break; - profile_trigger(ps); - } -#if LJ_TARGET_WINDOWS && !LJ_TARGET_UWP - ps->wmm_tep(interval); -#endif - return 0; -} - -/* Start profiling timer thread. */ -static void profile_timer_start(ProfileState *ps) -{ -#if LJ_TARGET_WINDOWS && !LJ_TARGET_UWP - if (!ps->wmm) { /* Load WinMM library on-demand. */ - ps->wmm = LJ_WIN_LOADLIBA("winmm.dll"); - if (ps->wmm) { - ps->wmm_tbp = (WMM_TPFUNC)GetProcAddress(ps->wmm, "timeBeginPeriod"); - ps->wmm_tep = (WMM_TPFUNC)GetProcAddress(ps->wmm, "timeEndPeriod"); - if (!ps->wmm_tbp || !ps->wmm_tep) { - ps->wmm = NULL; - return; - } - } - } -#endif - InitializeCriticalSection(&ps->lock); - ps->abort = 0; - ps->thread = CreateThread(NULL, 0, profile_thread, ps, 0, NULL); -} - -/* Stop profiling timer thread. */ -static void profile_timer_stop(ProfileState *ps) -{ - ps->abort = 1; - WaitForSingleObject(ps->thread, INFINITE); - DeleteCriticalSection(&ps->lock); -} - -#endif - -/* -- Public profiling API ------------------------------------------------ */ - -/* Start profiling. */ -LUA_API void luaJIT_profile_start(lua_State *L, const char *mode, - luaJIT_profile_callback cb, void *data) -{ - ProfileState *ps = &profile_state; - int interval = LJ_PROFILE_INTERVAL_DEFAULT; - while (*mode) { - int m = *mode++; - switch (m) { - case 'i': - interval = 0; - while (*mode >= '0' && *mode <= '9') - interval = interval * 10 + (*mode++ - '0'); - if (interval <= 0) interval = 1; - break; -#if LJ_HASJIT - case 'l': case 'f': - L2J(L)->prof_mode = m; - lj_trace_flushall(L); - break; -#endif - default: /* Ignore unknown mode chars. */ - break; - } - } - if (ps->g) { - luaJIT_profile_stop(L); - if (ps->g) return; /* Profiler in use by another VM. */ - } - ps->g = G(L); - ps->interval = interval; - ps->cb = cb; - ps->data = data; - ps->samples = 0; - lj_buf_init(L, &ps->sb); - profile_timer_start(ps); -} - -/* Stop profiling. */ -LUA_API void luaJIT_profile_stop(lua_State *L) -{ - ProfileState *ps = &profile_state; - global_State *g = ps->g; - if (G(L) == g) { /* Only stop profiler if started by this VM. */ - profile_timer_stop(ps); - g->hookmask &= ~HOOK_PROFILE; - lj_dispatch_update(g); -#if LJ_HASJIT - G2J(g)->prof_mode = 0; - lj_trace_flushall(L); -#endif - lj_buf_free(g, &ps->sb); - setmref(ps->sb.b, NULL); - setmref(ps->sb.e, NULL); - ps->g = NULL; - } -} - -/* Return a compact stack dump. */ -LUA_API const char *luaJIT_profile_dumpstack(lua_State *L, const char *fmt, - int depth, size_t *len) -{ - ProfileState *ps = &profile_state; - SBuf *sb = &ps->sb; - setsbufL(sb, L); - lj_buf_reset(sb); - lj_debug_dumpstack(L, sb, fmt, depth); - *len = (size_t)sbuflen(sb); - return sbufB(sb); -} - -#endif diff --git a/lib/LuaJIT/src/lj_profile.h b/lib/LuaJIT/src/lj_profile.h deleted file mode 100644 index 0cccfd7..0000000 --- a/lib/LuaJIT/src/lj_profile.h +++ /dev/null @@ -1,21 +0,0 @@ -/* -** Low-overhead profiling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_PROFILE_H -#define _LJ_PROFILE_H - -#include "lj_obj.h" - -#if LJ_HASPROFILE - -LJ_FUNC void LJ_FASTCALL lj_profile_interpreter(lua_State *L); -#if !LJ_PROFILE_SIGPROF -LJ_FUNC void LJ_FASTCALL lj_profile_hook_enter(global_State *g); -LJ_FUNC void LJ_FASTCALL lj_profile_hook_leave(global_State *g); -#endif - -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_record.c b/lib/LuaJIT/src/lj_record.c deleted file mode 100644 index 7f37d6c..0000000 --- a/lib/LuaJIT/src/lj_record.c +++ /dev/null @@ -1,2649 +0,0 @@ -/* -** Trace recorder (bytecode -> SSA IR). -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_record_c -#define LUA_CORE - -#include "lj_obj.h" - -#if LJ_HASJIT - -#include "lj_err.h" -#include "lj_str.h" -#include "lj_tab.h" -#include "lj_meta.h" -#include "lj_frame.h" -#if LJ_HASFFI -#include "lj_ctype.h" -#endif -#include "lj_bc.h" -#include "lj_ff.h" -#if LJ_HASPROFILE -#include "lj_debug.h" -#endif -#include "lj_ir.h" -#include "lj_jit.h" -#include "lj_ircall.h" -#include "lj_iropt.h" -#include "lj_trace.h" -#include "lj_record.h" -#include "lj_ffrecord.h" -#include "lj_snap.h" -#include "lj_dispatch.h" -#include "lj_vm.h" - -/* Some local macros to save typing. Undef'd at the end. */ -#define IR(ref) (&J->cur.ir[(ref)]) - -/* Pass IR on to next optimization in chain (FOLD). */ -#define emitir(ot, a, b) (lj_ir_set(J, (ot), (a), (b)), lj_opt_fold(J)) - -/* Emit raw IR without passing through optimizations. */ -#define emitir_raw(ot, a, b) (lj_ir_set(J, (ot), (a), (b)), lj_ir_emit(J)) - -/* -- Sanity checks ------------------------------------------------------- */ - -#ifdef LUA_USE_ASSERT -/* Sanity check the whole IR -- sloooow. */ -static void rec_check_ir(jit_State *J) -{ - IRRef i, nins = J->cur.nins, nk = J->cur.nk; - lua_assert(nk <= REF_BIAS && nins >= REF_BIAS && nins < 65536); - for (i = nk; i < nins; i++) { - IRIns *ir = IR(i); - uint32_t mode = lj_ir_mode[ir->o]; - IRRef op1 = ir->op1; - IRRef op2 = ir->op2; - switch (irm_op1(mode)) { - case IRMnone: lua_assert(op1 == 0); break; - case IRMref: lua_assert(op1 >= nk); - lua_assert(i >= REF_BIAS ? op1 < i : op1 > i); break; - case IRMlit: break; - case IRMcst: lua_assert(i < REF_BIAS); - if (irt_is64(ir->t) && ir->o != IR_KNULL) - i++; - continue; - } - switch (irm_op2(mode)) { - case IRMnone: lua_assert(op2 == 0); break; - case IRMref: lua_assert(op2 >= nk); - lua_assert(i >= REF_BIAS ? op2 < i : op2 > i); break; - case IRMlit: break; - case IRMcst: lua_assert(0); break; - } - if (ir->prev) { - lua_assert(ir->prev >= nk); - lua_assert(i >= REF_BIAS ? ir->prev < i : ir->prev > i); - lua_assert(ir->o == IR_NOP || IR(ir->prev)->o == ir->o); - } - } -} - -/* Compare stack slots and frames of the recorder and the VM. */ -static void rec_check_slots(jit_State *J) -{ - BCReg s, nslots = J->baseslot + J->maxslot; - int32_t depth = 0; - cTValue *base = J->L->base - J->baseslot; - lua_assert(J->baseslot >= 1+LJ_FR2); - lua_assert(J->baseslot == 1+LJ_FR2 || (J->slot[J->baseslot-1] & TREF_FRAME)); - lua_assert(nslots <= LJ_MAX_JSLOTS); - for (s = 0; s < nslots; s++) { - TRef tr = J->slot[s]; - if (tr) { - cTValue *tv = &base[s]; - IRRef ref = tref_ref(tr); - IRIns *ir = NULL; /* Silence compiler. */ - if (!LJ_FR2 || ref || !(tr & (TREF_FRAME | TREF_CONT))) { - lua_assert(ref >= J->cur.nk && ref < J->cur.nins); - ir = IR(ref); - lua_assert(irt_t(ir->t) == tref_t(tr)); - } - if (s == 0) { - lua_assert(tref_isfunc(tr)); -#if LJ_FR2 - } else if (s == 1) { - lua_assert((tr & ~TREF_FRAME) == 0); -#endif - } else if ((tr & TREF_FRAME)) { - GCfunc *fn = gco2func(frame_gc(tv)); - BCReg delta = (BCReg)(tv - frame_prev(tv)); -#if LJ_FR2 - if (ref) - lua_assert(ir_knum(ir)->u64 == tv->u64); - tr = J->slot[s-1]; - ir = IR(tref_ref(tr)); -#endif - lua_assert(tref_isfunc(tr)); - if (tref_isk(tr)) lua_assert(fn == ir_kfunc(ir)); - lua_assert(s > delta + LJ_FR2 ? (J->slot[s-delta] & TREF_FRAME) - : (s == delta + LJ_FR2)); - depth++; - } else if ((tr & TREF_CONT)) { -#if LJ_FR2 - if (ref) - lua_assert(ir_knum(ir)->u64 == tv->u64); -#else - lua_assert(ir_kptr(ir) == gcrefp(tv->gcr, void)); -#endif - lua_assert((J->slot[s+1+LJ_FR2] & TREF_FRAME)); - depth++; - } else { - if (tvisnumber(tv)) - lua_assert(tref_isnumber(tr)); /* Could be IRT_INT etc., too. */ - else - lua_assert(itype2irt(tv) == tref_type(tr)); - if (tref_isk(tr)) { /* Compare constants. */ - TValue tvk; - lj_ir_kvalue(J->L, &tvk, ir); - if (!(tvisnum(&tvk) && tvisnan(&tvk))) - lua_assert(lj_obj_equal(tv, &tvk)); - else - lua_assert(tvisnum(tv) && tvisnan(tv)); - } - } - } - } - lua_assert(J->framedepth == depth); -} -#endif - -/* -- Type handling and specialization ------------------------------------ */ - -/* Note: these functions return tagged references (TRef). */ - -/* Specialize a slot to a specific type. Note: slot can be negative! */ -static TRef sloadt(jit_State *J, int32_t slot, IRType t, int mode) -{ - /* Caller may set IRT_GUARD in t. */ - TRef ref = emitir_raw(IRT(IR_SLOAD, t), (int32_t)J->baseslot+slot, mode); - J->base[slot] = ref; - return ref; -} - -/* Specialize a slot to the runtime type. Note: slot can be negative! */ -static TRef sload(jit_State *J, int32_t slot) -{ - IRType t = itype2irt(&J->L->base[slot]); - TRef ref = emitir_raw(IRTG(IR_SLOAD, t), (int32_t)J->baseslot+slot, - IRSLOAD_TYPECHECK); - if (irtype_ispri(t)) ref = TREF_PRI(t); /* Canonicalize primitive refs. */ - J->base[slot] = ref; - return ref; -} - -/* Get TRef from slot. Load slot and specialize if not done already. */ -#define getslot(J, s) (J->base[(s)] ? J->base[(s)] : sload(J, (int32_t)(s))) - -/* Get TRef for current function. */ -static TRef getcurrf(jit_State *J) -{ - if (J->base[-1-LJ_FR2]) - return J->base[-1-LJ_FR2]; - lua_assert(J->baseslot == 1+LJ_FR2); - return sloadt(J, -1-LJ_FR2, IRT_FUNC, IRSLOAD_READONLY); -} - -/* Compare for raw object equality. -** Returns 0 if the objects are the same. -** Returns 1 if they are different, but the same type. -** Returns 2 for two different types. -** Comparisons between primitives always return 1 -- no caller cares about it. -*/ -int lj_record_objcmp(jit_State *J, TRef a, TRef b, cTValue *av, cTValue *bv) -{ - int diff = !lj_obj_equal(av, bv); - if (!tref_isk2(a, b)) { /* Shortcut, also handles primitives. */ - IRType ta = tref_isinteger(a) ? IRT_INT : tref_type(a); - IRType tb = tref_isinteger(b) ? IRT_INT : tref_type(b); - if (ta != tb) { - /* Widen mixed number/int comparisons to number/number comparison. */ - if (ta == IRT_INT && tb == IRT_NUM) { - a = emitir(IRTN(IR_CONV), a, IRCONV_NUM_INT); - ta = IRT_NUM; - } else if (ta == IRT_NUM && tb == IRT_INT) { - b = emitir(IRTN(IR_CONV), b, IRCONV_NUM_INT); - } else { - return 2; /* Two different types are never equal. */ - } - } - emitir(IRTG(diff ? IR_NE : IR_EQ, ta), a, b); - } - return diff; -} - -/* Constify a value. Returns 0 for non-representable object types. */ -TRef lj_record_constify(jit_State *J, cTValue *o) -{ - if (tvisgcv(o)) - return lj_ir_kgc(J, gcV(o), itype2irt(o)); - else if (tvisint(o)) - return lj_ir_kint(J, intV(o)); - else if (tvisnum(o)) - return lj_ir_knumint(J, numV(o)); - else if (tvisbool(o)) - return TREF_PRI(itype2irt(o)); - else - return 0; /* Can't represent lightuserdata (pointless). */ -} - -/* -- Record loop ops ----------------------------------------------------- */ - -/* Loop event. */ -typedef enum { - LOOPEV_LEAVE, /* Loop is left or not entered. */ - LOOPEV_ENTERLO, /* Loop is entered with a low iteration count left. */ - LOOPEV_ENTER /* Loop is entered. */ -} LoopEvent; - -/* Canonicalize slots: convert integers to numbers. */ -static void canonicalize_slots(jit_State *J) -{ - BCReg s; - if (LJ_DUALNUM) return; - for (s = J->baseslot+J->maxslot-1; s >= 1; s--) { - TRef tr = J->slot[s]; - if (tref_isinteger(tr)) { - IRIns *ir = IR(tref_ref(tr)); - if (!(ir->o == IR_SLOAD && (ir->op2 & IRSLOAD_READONLY))) - J->slot[s] = emitir(IRTN(IR_CONV), tr, IRCONV_NUM_INT); - } - } -} - -/* Stop recording. */ -void lj_record_stop(jit_State *J, TraceLink linktype, TraceNo lnk) -{ -#ifdef LUAJIT_ENABLE_TABLE_BUMP - if (J->retryrec) - lj_trace_err(J, LJ_TRERR_RETRY); -#endif - lj_trace_end(J); - J->cur.linktype = (uint8_t)linktype; - J->cur.link = (uint16_t)lnk; - /* Looping back at the same stack level? */ - if (lnk == J->cur.traceno && J->framedepth + J->retdepth == 0) { - if ((J->flags & JIT_F_OPT_LOOP)) /* Shall we try to create a loop? */ - goto nocanon; /* Do not canonicalize or we lose the narrowing. */ - if (J->cur.root) /* Otherwise ensure we always link to the root trace. */ - J->cur.link = J->cur.root; - } - canonicalize_slots(J); -nocanon: - /* Note: all loop ops must set J->pc to the following instruction! */ - lj_snap_add(J); /* Add loop snapshot. */ - J->needsnap = 0; - J->mergesnap = 1; /* In case recording continues. */ -} - -/* Search bytecode backwards for a int/num constant slot initializer. */ -static TRef find_kinit(jit_State *J, const BCIns *endpc, BCReg slot, IRType t) -{ - /* This algorithm is rather simplistic and assumes quite a bit about - ** how the bytecode is generated. It works fine for FORI initializers, - ** but it won't necessarily work in other cases (e.g. iterator arguments). - ** It doesn't do anything fancy, either (like backpropagating MOVs). - */ - const BCIns *pc, *startpc = proto_bc(J->pt); - for (pc = endpc-1; pc > startpc; pc--) { - BCIns ins = *pc; - BCOp op = bc_op(ins); - /* First try to find the last instruction that stores to this slot. */ - if (bcmode_a(op) == BCMbase && bc_a(ins) <= slot) { - return 0; /* Multiple results, e.g. from a CALL or KNIL. */ - } else if (bcmode_a(op) == BCMdst && bc_a(ins) == slot) { - if (op == BC_KSHORT || op == BC_KNUM) { /* Found const. initializer. */ - /* Now try to verify there's no forward jump across it. */ - const BCIns *kpc = pc; - for (; pc > startpc; pc--) - if (bc_op(*pc) == BC_JMP) { - const BCIns *target = pc+bc_j(*pc)+1; - if (target > kpc && target <= endpc) - return 0; /* Conditional assignment. */ - } - if (op == BC_KSHORT) { - int32_t k = (int32_t)(int16_t)bc_d(ins); - return t == IRT_INT ? lj_ir_kint(J, k) : lj_ir_knum(J, (lua_Number)k); - } else { - cTValue *tv = proto_knumtv(J->pt, bc_d(ins)); - if (t == IRT_INT) { - int32_t k = numberVint(tv); - if (tvisint(tv) || numV(tv) == (lua_Number)k) /* -0 is ok here. */ - return lj_ir_kint(J, k); - return 0; /* Type mismatch. */ - } else { - return lj_ir_knum(J, numberVnum(tv)); - } - } - } - return 0; /* Non-constant initializer. */ - } - } - return 0; /* No assignment to this slot found? */ -} - -/* Load and optionally convert a FORI argument from a slot. */ -static TRef fori_load(jit_State *J, BCReg slot, IRType t, int mode) -{ - int conv = (tvisint(&J->L->base[slot]) != (t==IRT_INT)) ? IRSLOAD_CONVERT : 0; - return sloadt(J, (int32_t)slot, - t + (((mode & IRSLOAD_TYPECHECK) || - (conv && t == IRT_INT && !(mode >> 16))) ? - IRT_GUARD : 0), - mode + conv); -} - -/* Peek before FORI to find a const initializer. Otherwise load from slot. */ -static TRef fori_arg(jit_State *J, const BCIns *fori, BCReg slot, - IRType t, int mode) -{ - TRef tr = J->base[slot]; - if (!tr) { - tr = find_kinit(J, fori, slot, t); - if (!tr) - tr = fori_load(J, slot, t, mode); - } - return tr; -} - -/* Return the direction of the FOR loop iterator. -** It's important to exactly reproduce the semantics of the interpreter. -*/ -static int rec_for_direction(cTValue *o) -{ - return (tvisint(o) ? intV(o) : (int32_t)o->u32.hi) >= 0; -} - -/* Simulate the runtime behavior of the FOR loop iterator. */ -static LoopEvent rec_for_iter(IROp *op, cTValue *o, int isforl) -{ - lua_Number stopv = numberVnum(&o[FORL_STOP]); - lua_Number idxv = numberVnum(&o[FORL_IDX]); - lua_Number stepv = numberVnum(&o[FORL_STEP]); - if (isforl) - idxv += stepv; - if (rec_for_direction(&o[FORL_STEP])) { - if (idxv <= stopv) { - *op = IR_LE; - return idxv + 2*stepv > stopv ? LOOPEV_ENTERLO : LOOPEV_ENTER; - } - *op = IR_GT; return LOOPEV_LEAVE; - } else { - if (stopv <= idxv) { - *op = IR_GE; - return idxv + 2*stepv < stopv ? LOOPEV_ENTERLO : LOOPEV_ENTER; - } - *op = IR_LT; return LOOPEV_LEAVE; - } -} - -/* Record checks for FOR loop overflow and step direction. */ -static void rec_for_check(jit_State *J, IRType t, int dir, - TRef stop, TRef step, int init) -{ - if (!tref_isk(step)) { - /* Non-constant step: need a guard for the direction. */ - TRef zero = (t == IRT_INT) ? lj_ir_kint(J, 0) : lj_ir_knum_zero(J); - emitir(IRTG(dir ? IR_GE : IR_LT, t), step, zero); - /* Add hoistable overflow checks for a narrowed FORL index. */ - if (init && t == IRT_INT) { - if (tref_isk(stop)) { - /* Constant stop: optimize check away or to a range check for step. */ - int32_t k = IR(tref_ref(stop))->i; - if (dir) { - if (k > 0) - emitir(IRTGI(IR_LE), step, lj_ir_kint(J, (int32_t)0x7fffffff-k)); - } else { - if (k < 0) - emitir(IRTGI(IR_GE), step, lj_ir_kint(J, (int32_t)0x80000000-k)); - } - } else { - /* Stop+step variable: need full overflow check. */ - TRef tr = emitir(IRTGI(IR_ADDOV), step, stop); - emitir(IRTI(IR_USE), tr, 0); /* ADDOV is weak. Avoid dead result. */ - } - } - } else if (init && t == IRT_INT && !tref_isk(stop)) { - /* Constant step: optimize overflow check to a range check for stop. */ - int32_t k = IR(tref_ref(step))->i; - k = (int32_t)(dir ? 0x7fffffff : 0x80000000) - k; - emitir(IRTGI(dir ? IR_LE : IR_GE), stop, lj_ir_kint(J, k)); - } -} - -/* Record a FORL instruction. */ -static void rec_for_loop(jit_State *J, const BCIns *fori, ScEvEntry *scev, - int init) -{ - BCReg ra = bc_a(*fori); - cTValue *tv = &J->L->base[ra]; - TRef idx = J->base[ra+FORL_IDX]; - IRType t = idx ? tref_type(idx) : - (init || LJ_DUALNUM) ? lj_opt_narrow_forl(J, tv) : IRT_NUM; - int mode = IRSLOAD_INHERIT + - ((!LJ_DUALNUM || tvisint(tv) == (t == IRT_INT)) ? IRSLOAD_READONLY : 0); - TRef stop = fori_arg(J, fori, ra+FORL_STOP, t, mode); - TRef step = fori_arg(J, fori, ra+FORL_STEP, t, mode); - int tc, dir = rec_for_direction(&tv[FORL_STEP]); - lua_assert(bc_op(*fori) == BC_FORI || bc_op(*fori) == BC_JFORI); - scev->t.irt = t; - scev->dir = dir; - scev->stop = tref_ref(stop); - scev->step = tref_ref(step); - rec_for_check(J, t, dir, stop, step, init); - scev->start = tref_ref(find_kinit(J, fori, ra+FORL_IDX, IRT_INT)); - tc = (LJ_DUALNUM && - !(scev->start && irref_isk(scev->stop) && irref_isk(scev->step) && - tvisint(&tv[FORL_IDX]) == (t == IRT_INT))) ? - IRSLOAD_TYPECHECK : 0; - if (tc) { - J->base[ra+FORL_STOP] = stop; - J->base[ra+FORL_STEP] = step; - } - if (!idx) - idx = fori_load(J, ra+FORL_IDX, t, - IRSLOAD_INHERIT + tc + (J->scev.start << 16)); - if (!init) - J->base[ra+FORL_IDX] = idx = emitir(IRT(IR_ADD, t), idx, step); - J->base[ra+FORL_EXT] = idx; - scev->idx = tref_ref(idx); - setmref(scev->pc, fori); - J->maxslot = ra+FORL_EXT+1; -} - -/* Record FORL/JFORL or FORI/JFORI. */ -static LoopEvent rec_for(jit_State *J, const BCIns *fori, int isforl) -{ - BCReg ra = bc_a(*fori); - TValue *tv = &J->L->base[ra]; - TRef *tr = &J->base[ra]; - IROp op; - LoopEvent ev; - TRef stop; - IRType t; - if (isforl) { /* Handle FORL/JFORL opcodes. */ - TRef idx = tr[FORL_IDX]; - if (mref(J->scev.pc, const BCIns) == fori && tref_ref(idx) == J->scev.idx) { - t = J->scev.t.irt; - stop = J->scev.stop; - idx = emitir(IRT(IR_ADD, t), idx, J->scev.step); - tr[FORL_EXT] = tr[FORL_IDX] = idx; - } else { - ScEvEntry scev; - rec_for_loop(J, fori, &scev, 0); - t = scev.t.irt; - stop = scev.stop; - } - } else { /* Handle FORI/JFORI opcodes. */ - BCReg i; - lj_meta_for(J->L, tv); - t = (LJ_DUALNUM || tref_isint(tr[FORL_IDX])) ? lj_opt_narrow_forl(J, tv) : - IRT_NUM; - for (i = FORL_IDX; i <= FORL_STEP; i++) { - if (!tr[i]) sload(J, ra+i); - lua_assert(tref_isnumber_str(tr[i])); - if (tref_isstr(tr[i])) - tr[i] = emitir(IRTG(IR_STRTO, IRT_NUM), tr[i], 0); - if (t == IRT_INT) { - if (!tref_isinteger(tr[i])) - tr[i] = emitir(IRTGI(IR_CONV), tr[i], IRCONV_INT_NUM|IRCONV_CHECK); - } else { - if (!tref_isnum(tr[i])) - tr[i] = emitir(IRTN(IR_CONV), tr[i], IRCONV_NUM_INT); - } - } - tr[FORL_EXT] = tr[FORL_IDX]; - stop = tr[FORL_STOP]; - rec_for_check(J, t, rec_for_direction(&tv[FORL_STEP]), - stop, tr[FORL_STEP], 1); - } - - ev = rec_for_iter(&op, tv, isforl); - if (ev == LOOPEV_LEAVE) { - J->maxslot = ra+FORL_EXT+1; - J->pc = fori+1; - } else { - J->maxslot = ra; - J->pc = fori+bc_j(*fori)+1; - } - lj_snap_add(J); - - emitir(IRTG(op, t), tr[FORL_IDX], stop); - - if (ev == LOOPEV_LEAVE) { - J->maxslot = ra; - J->pc = fori+bc_j(*fori)+1; - } else { - J->maxslot = ra+FORL_EXT+1; - J->pc = fori+1; - } - J->needsnap = 1; - return ev; -} - -/* Record ITERL/JITERL. */ -static LoopEvent rec_iterl(jit_State *J, const BCIns iterins) -{ - BCReg ra = bc_a(iterins); - if (!tref_isnil(getslot(J, ra))) { /* Looping back? */ - J->base[ra-1] = J->base[ra]; /* Copy result of ITERC to control var. */ - J->maxslot = ra-1+bc_b(J->pc[-1]); - J->pc += bc_j(iterins)+1; - return LOOPEV_ENTER; - } else { - J->maxslot = ra-3; - J->pc++; - return LOOPEV_LEAVE; - } -} - -/* Record LOOP/JLOOP. Now, that was easy. */ -static LoopEvent rec_loop(jit_State *J, BCReg ra) -{ - if (ra < J->maxslot) J->maxslot = ra; - J->pc++; - return LOOPEV_ENTER; -} - -/* Check if a loop repeatedly failed to trace because it didn't loop back. */ -static int innerloopleft(jit_State *J, const BCIns *pc) -{ - ptrdiff_t i; - for (i = 0; i < PENALTY_SLOTS; i++) - if (mref(J->penalty[i].pc, const BCIns) == pc) { - if ((J->penalty[i].reason == LJ_TRERR_LLEAVE || - J->penalty[i].reason == LJ_TRERR_LINNER) && - J->penalty[i].val >= 2*PENALTY_MIN) - return 1; - break; - } - return 0; -} - -/* Handle the case when an interpreted loop op is hit. */ -static void rec_loop_interp(jit_State *J, const BCIns *pc, LoopEvent ev) -{ - if (J->parent == 0 && J->exitno == 0) { - if (pc == J->startpc && J->framedepth + J->retdepth == 0) { - /* Same loop? */ - if (ev == LOOPEV_LEAVE) /* Must loop back to form a root trace. */ - lj_trace_err(J, LJ_TRERR_LLEAVE); - lj_record_stop(J, LJ_TRLINK_LOOP, J->cur.traceno); /* Looping trace. */ - } else if (ev != LOOPEV_LEAVE) { /* Entering inner loop? */ - /* It's usually better to abort here and wait until the inner loop - ** is traced. But if the inner loop repeatedly didn't loop back, - ** this indicates a low trip count. In this case try unrolling - ** an inner loop even in a root trace. But it's better to be a bit - ** more conservative here and only do it for very short loops. - */ - if (bc_j(*pc) != -1 && !innerloopleft(J, pc)) - lj_trace_err(J, LJ_TRERR_LINNER); /* Root trace hit an inner loop. */ - if ((ev != LOOPEV_ENTERLO && - J->loopref && J->cur.nins - J->loopref > 24) || --J->loopunroll < 0) - lj_trace_err(J, LJ_TRERR_LUNROLL); /* Limit loop unrolling. */ - J->loopref = J->cur.nins; - } - } else if (ev != LOOPEV_LEAVE) { /* Side trace enters an inner loop. */ - J->loopref = J->cur.nins; - if (--J->loopunroll < 0) - lj_trace_err(J, LJ_TRERR_LUNROLL); /* Limit loop unrolling. */ - } /* Side trace continues across a loop that's left or not entered. */ -} - -/* Handle the case when an already compiled loop op is hit. */ -static void rec_loop_jit(jit_State *J, TraceNo lnk, LoopEvent ev) -{ - if (J->parent == 0 && J->exitno == 0) { /* Root trace hit an inner loop. */ - /* Better let the inner loop spawn a side trace back here. */ - lj_trace_err(J, LJ_TRERR_LINNER); - } else if (ev != LOOPEV_LEAVE) { /* Side trace enters a compiled loop. */ - J->instunroll = 0; /* Cannot continue across a compiled loop op. */ - if (J->pc == J->startpc && J->framedepth + J->retdepth == 0) - lj_record_stop(J, LJ_TRLINK_LOOP, J->cur.traceno); /* Form extra loop. */ - else - lj_record_stop(J, LJ_TRLINK_ROOT, lnk); /* Link to the loop. */ - } /* Side trace continues across a loop that's left or not entered. */ -} - -/* -- Record profiler hook checks ----------------------------------------- */ - -#if LJ_HASPROFILE - -/* Need to insert profiler hook check? */ -static int rec_profile_need(jit_State *J, GCproto *pt, const BCIns *pc) -{ - GCproto *ppt; - lua_assert(J->prof_mode == 'f' || J->prof_mode == 'l'); - if (!pt) - return 0; - ppt = J->prev_pt; - J->prev_pt = pt; - if (pt != ppt && ppt) { - J->prev_line = -1; - return 1; - } - if (J->prof_mode == 'l') { - BCLine line = lj_debug_line(pt, proto_bcpos(pt, pc)); - BCLine pline = J->prev_line; - J->prev_line = line; - if (pline != line) - return 1; - } - return 0; -} - -static void rec_profile_ins(jit_State *J, const BCIns *pc) -{ - if (J->prof_mode && rec_profile_need(J, J->pt, pc)) { - emitir(IRTG(IR_PROF, IRT_NIL), 0, 0); - lj_snap_add(J); - } -} - -static void rec_profile_ret(jit_State *J) -{ - if (J->prof_mode == 'f') { - emitir(IRTG(IR_PROF, IRT_NIL), 0, 0); - J->prev_pt = NULL; - lj_snap_add(J); - } -} - -#endif - -/* -- Record calls and returns -------------------------------------------- */ - -/* Specialize to the runtime value of the called function or its prototype. */ -static TRef rec_call_specialize(jit_State *J, GCfunc *fn, TRef tr) -{ - TRef kfunc; - if (isluafunc(fn)) { - GCproto *pt = funcproto(fn); - /* Too many closures created? Probably not a monomorphic function. */ - if (pt->flags >= PROTO_CLC_POLY) { /* Specialize to prototype instead. */ - TRef trpt = emitir(IRT(IR_FLOAD, IRT_PGC), tr, IRFL_FUNC_PC); - emitir(IRTG(IR_EQ, IRT_PGC), trpt, lj_ir_kptr(J, proto_bc(pt))); - (void)lj_ir_kgc(J, obj2gco(pt), IRT_PROTO); /* Prevent GC of proto. */ - return tr; - } - } else { - /* Don't specialize to non-monomorphic builtins. */ - switch (fn->c.ffid) { - case FF_coroutine_wrap_aux: - case FF_string_gmatch_aux: - /* NYI: io_file_iter doesn't have an ffid, yet. */ - { /* Specialize to the ffid. */ - TRef trid = emitir(IRT(IR_FLOAD, IRT_U8), tr, IRFL_FUNC_FFID); - emitir(IRTG(IR_EQ, IRT_INT), trid, lj_ir_kint(J, fn->c.ffid)); - } - return tr; - default: - /* NYI: don't specialize to non-monomorphic C functions. */ - break; - } - } - /* Otherwise specialize to the function (closure) value itself. */ - kfunc = lj_ir_kfunc(J, fn); - emitir(IRTG(IR_EQ, IRT_FUNC), tr, kfunc); - return kfunc; -} - -/* Record call setup. */ -static void rec_call_setup(jit_State *J, BCReg func, ptrdiff_t nargs) -{ - RecordIndex ix; - TValue *functv = &J->L->base[func]; - TRef kfunc, *fbase = &J->base[func]; - ptrdiff_t i; - (void)getslot(J, func); /* Ensure func has a reference. */ - for (i = 1; i <= nargs; i++) - (void)getslot(J, func+LJ_FR2+i); /* Ensure all args have a reference. */ - if (!tref_isfunc(fbase[0])) { /* Resolve __call metamethod. */ - ix.tab = fbase[0]; - copyTV(J->L, &ix.tabv, functv); - if (!lj_record_mm_lookup(J, &ix, MM_call) || !tref_isfunc(ix.mobj)) - lj_trace_err(J, LJ_TRERR_NOMM); - for (i = ++nargs; i > LJ_FR2; i--) /* Shift arguments up. */ - fbase[i+LJ_FR2] = fbase[i+LJ_FR2-1]; -#if LJ_FR2 - fbase[2] = fbase[0]; -#endif - fbase[0] = ix.mobj; /* Replace function. */ - functv = &ix.mobjv; - } - kfunc = rec_call_specialize(J, funcV(functv), fbase[0]); -#if LJ_FR2 - fbase[0] = kfunc; - fbase[1] = TREF_FRAME; -#else - fbase[0] = kfunc | TREF_FRAME; -#endif - J->maxslot = (BCReg)nargs; -} - -/* Record call. */ -void lj_record_call(jit_State *J, BCReg func, ptrdiff_t nargs) -{ - rec_call_setup(J, func, nargs); - /* Bump frame. */ - J->framedepth++; - J->base += func+1+LJ_FR2; - J->baseslot += func+1+LJ_FR2; - if (J->baseslot + J->maxslot >= LJ_MAX_JSLOTS) - lj_trace_err(J, LJ_TRERR_STACKOV); -} - -/* Record tail call. */ -void lj_record_tailcall(jit_State *J, BCReg func, ptrdiff_t nargs) -{ - rec_call_setup(J, func, nargs); - if (frame_isvarg(J->L->base - 1)) { - BCReg cbase = (BCReg)frame_delta(J->L->base - 1); - if (--J->framedepth < 0) - lj_trace_err(J, LJ_TRERR_NYIRETL); - J->baseslot -= (BCReg)cbase; - J->base -= cbase; - func += cbase; - } - /* Move func + args down. */ - if (LJ_FR2 && J->baseslot == 2) - J->base[func+1] = TREF_FRAME; - memmove(&J->base[-1-LJ_FR2], &J->base[func], sizeof(TRef)*(J->maxslot+1+LJ_FR2)); - /* Note: the new TREF_FRAME is now at J->base[-1] (even for slot #0). */ - /* Tailcalls can form a loop, so count towards the loop unroll limit. */ - if (++J->tailcalled > J->loopunroll) - lj_trace_err(J, LJ_TRERR_LUNROLL); -} - -/* Check unroll limits for down-recursion. */ -static int check_downrec_unroll(jit_State *J, GCproto *pt) -{ - IRRef ptref; - for (ptref = J->chain[IR_KGC]; ptref; ptref = IR(ptref)->prev) - if (ir_kgc(IR(ptref)) == obj2gco(pt)) { - int count = 0; - IRRef ref; - for (ref = J->chain[IR_RETF]; ref; ref = IR(ref)->prev) - if (IR(ref)->op1 == ptref) - count++; - if (count) { - if (J->pc == J->startpc) { - if (count + J->tailcalled > J->param[JIT_P_recunroll]) - return 1; - } else { - lj_trace_err(J, LJ_TRERR_DOWNREC); - } - } - } - return 0; -} - -static TRef rec_cat(jit_State *J, BCReg baseslot, BCReg topslot); - -/* Record return. */ -void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) -{ - TValue *frame = J->L->base - 1; - ptrdiff_t i; - for (i = 0; i < gotresults; i++) - (void)getslot(J, rbase+i); /* Ensure all results have a reference. */ - while (frame_ispcall(frame)) { /* Immediately resolve pcall() returns. */ - BCReg cbase = (BCReg)frame_delta(frame); - if (--J->framedepth <= 0) - lj_trace_err(J, LJ_TRERR_NYIRETL); - lua_assert(J->baseslot > 1+LJ_FR2); - gotresults++; - rbase += cbase; - J->baseslot -= (BCReg)cbase; - J->base -= cbase; - J->base[--rbase] = TREF_TRUE; /* Prepend true to results. */ - frame = frame_prevd(frame); - } - /* Return to lower frame via interpreter for unhandled cases. */ - if (J->framedepth == 0 && J->pt && bc_isret(bc_op(*J->pc)) && - (!frame_islua(frame) || - (J->parent == 0 && J->exitno == 0 && - !bc_isret(bc_op(J->cur.startins))))) { - /* NYI: specialize to frame type and return directly, not via RET*. */ - for (i = 0; i < (ptrdiff_t)rbase; i++) - J->base[i] = 0; /* Purge dead slots. */ - J->maxslot = rbase + (BCReg)gotresults; - lj_record_stop(J, LJ_TRLINK_RETURN, 0); /* Return to interpreter. */ - return; - } - if (frame_isvarg(frame)) { - BCReg cbase = (BCReg)frame_delta(frame); - if (--J->framedepth < 0) /* NYI: return of vararg func to lower frame. */ - lj_trace_err(J, LJ_TRERR_NYIRETL); - lua_assert(J->baseslot > 1+LJ_FR2); - rbase += cbase; - J->baseslot -= (BCReg)cbase; - J->base -= cbase; - frame = frame_prevd(frame); - } - if (frame_islua(frame)) { /* Return to Lua frame. */ - BCIns callins = *(frame_pc(frame)-1); - ptrdiff_t nresults = bc_b(callins) ? (ptrdiff_t)bc_b(callins)-1 :gotresults; - BCReg cbase = bc_a(callins); - GCproto *pt = funcproto(frame_func(frame - (cbase+1+LJ_FR2))); - if ((pt->flags & PROTO_NOJIT)) - lj_trace_err(J, LJ_TRERR_CJITOFF); - if (J->framedepth == 0 && J->pt && frame == J->L->base - 1) { - if (check_downrec_unroll(J, pt)) { - J->maxslot = (BCReg)(rbase + gotresults); - lj_snap_purge(J); - lj_record_stop(J, LJ_TRLINK_DOWNREC, J->cur.traceno); /* Down-rec. */ - return; - } - lj_snap_add(J); - } - for (i = 0; i < nresults; i++) /* Adjust results. */ - J->base[i-1-LJ_FR2] = i < gotresults ? J->base[rbase+i] : TREF_NIL; - J->maxslot = cbase+(BCReg)nresults; - if (J->framedepth > 0) { /* Return to a frame that is part of the trace. */ - J->framedepth--; - lua_assert(J->baseslot > cbase+1+LJ_FR2); - J->baseslot -= cbase+1+LJ_FR2; - J->base -= cbase+1+LJ_FR2; - } else if (J->parent == 0 && J->exitno == 0 && - !bc_isret(bc_op(J->cur.startins))) { - /* Return to lower frame would leave the loop in a root trace. */ - lj_trace_err(J, LJ_TRERR_LLEAVE); - } else if (J->needsnap) { /* Tailcalled to ff with side-effects. */ - lj_trace_err(J, LJ_TRERR_NYIRETL); /* No way to insert snapshot here. */ - } else { /* Return to lower frame. Guard for the target we return to. */ - TRef trpt = lj_ir_kgc(J, obj2gco(pt), IRT_PROTO); - TRef trpc = lj_ir_kptr(J, (void *)frame_pc(frame)); - emitir(IRTG(IR_RETF, IRT_PGC), trpt, trpc); - J->retdepth++; - J->needsnap = 1; - lua_assert(J->baseslot == 1+LJ_FR2); - /* Shift result slots up and clear the slots of the new frame below. */ - memmove(J->base + cbase, J->base-1-LJ_FR2, sizeof(TRef)*nresults); - memset(J->base-1-LJ_FR2, 0, sizeof(TRef)*(cbase+1+LJ_FR2)); - } - } else if (frame_iscont(frame)) { /* Return to continuation frame. */ - ASMFunction cont = frame_contf(frame); - BCReg cbase = (BCReg)frame_delta(frame); - if ((J->framedepth -= 2) < 0) - lj_trace_err(J, LJ_TRERR_NYIRETL); - J->baseslot -= (BCReg)cbase; - J->base -= cbase; - J->maxslot = cbase-(2<base[dst] = gotresults ? J->base[cbase+rbase] : TREF_NIL; - if (dst >= J->maxslot) { - J->maxslot = dst+1; - } - } else if (cont == lj_cont_nop) { - /* Nothing to do here. */ - } else if (cont == lj_cont_cat) { - BCReg bslot = bc_b(*(frame_contpc(frame)-1)); - TRef tr = gotresults ? J->base[cbase+rbase] : TREF_NIL; - if (bslot != J->maxslot) { /* Concatenate the remainder. */ - TValue *b = J->L->base, save; /* Simulate lower frame and result. */ - J->base[J->maxslot] = tr; - copyTV(J->L, &save, b-(2<L, b-(2<L->base = b - cbase; - tr = rec_cat(J, bslot, cbase-(2<L->base + cbase; /* Undo. */ - J->L->base = b; - copyTV(J->L, b-(2<base[dst] = tr; - if (dst >= J->maxslot) { - J->maxslot = dst+1; - } - } /* Otherwise continue with another __concat call. */ - } else { - /* Result type already specialized. */ - lua_assert(cont == lj_cont_condf || cont == lj_cont_condt); - } - } else { - lj_trace_err(J, LJ_TRERR_NYIRETL); /* NYI: handle return to C frame. */ - } - lua_assert(J->baseslot >= 1+LJ_FR2); -} - -/* -- Metamethod handling ------------------------------------------------- */ - -/* Prepare to record call to metamethod. */ -static BCReg rec_mm_prep(jit_State *J, ASMFunction cont) -{ - BCReg s, top = cont == lj_cont_cat ? J->maxslot : curr_proto(J->L)->framesize; -#if LJ_FR2 - J->base[top] = lj_ir_k64(J, IR_KNUM, u64ptr(contptr(cont))); - J->base[top+1] = TREF_CONT; -#else - J->base[top] = lj_ir_kptr(J, contptr(cont)) | TREF_CONT; -#endif - J->framedepth++; - for (s = J->maxslot; s < top; s++) - J->base[s] = 0; /* Clear frame gap to avoid resurrecting previous refs. */ - return top+1+LJ_FR2; -} - -/* Record metamethod lookup. */ -int lj_record_mm_lookup(jit_State *J, RecordIndex *ix, MMS mm) -{ - RecordIndex mix; - GCtab *mt; - if (tref_istab(ix->tab)) { - mt = tabref(tabV(&ix->tabv)->metatable); - mix.tab = emitir(IRT(IR_FLOAD, IRT_TAB), ix->tab, IRFL_TAB_META); - } else if (tref_isudata(ix->tab)) { - int udtype = udataV(&ix->tabv)->udtype; - mt = tabref(udataV(&ix->tabv)->metatable); - /* The metatables of special userdata objects are treated as immutable. */ - if (udtype != UDTYPE_USERDATA) { - cTValue *mo; - if (LJ_HASFFI && udtype == UDTYPE_FFI_CLIB) { - /* Specialize to the C library namespace object. */ - emitir(IRTG(IR_EQ, IRT_PGC), ix->tab, lj_ir_kptr(J, udataV(&ix->tabv))); - } else { - /* Specialize to the type of userdata. */ - TRef tr = emitir(IRT(IR_FLOAD, IRT_U8), ix->tab, IRFL_UDATA_UDTYPE); - emitir(IRTGI(IR_EQ), tr, lj_ir_kint(J, udtype)); - } - immutable_mt: - mo = lj_tab_getstr(mt, mmname_str(J2G(J), mm)); - if (!mo || tvisnil(mo)) - return 0; /* No metamethod. */ - /* Treat metamethod or index table as immutable, too. */ - if (!(tvisfunc(mo) || tvistab(mo))) - lj_trace_err(J, LJ_TRERR_BADTYPE); - copyTV(J->L, &ix->mobjv, mo); - ix->mobj = lj_ir_kgc(J, gcV(mo), tvisfunc(mo) ? IRT_FUNC : IRT_TAB); - ix->mtv = mt; - ix->mt = TREF_NIL; /* Dummy value for comparison semantics. */ - return 1; /* Got metamethod or index table. */ - } - mix.tab = emitir(IRT(IR_FLOAD, IRT_TAB), ix->tab, IRFL_UDATA_META); - } else { - /* Specialize to base metatable. Must flush mcode in lua_setmetatable(). */ - mt = tabref(basemt_obj(J2G(J), &ix->tabv)); - if (mt == NULL) { - ix->mt = TREF_NIL; - return 0; /* No metamethod. */ - } - /* The cdata metatable is treated as immutable. */ - if (LJ_HASFFI && tref_iscdata(ix->tab)) goto immutable_mt; -#if LJ_GC64 - /* TODO: fix ARM32 asm_fload(), so we can use this for all archs. */ - ix->mt = mix.tab = lj_ir_ggfload(J, IRT_TAB, - GG_OFS(g.gcroot[GCROOT_BASEMT+itypemap(&ix->tabv)])); -#else - ix->mt = mix.tab = lj_ir_ktab(J, mt); -#endif - goto nocheck; - } - ix->mt = mt ? mix.tab : TREF_NIL; - emitir(IRTG(mt ? IR_NE : IR_EQ, IRT_TAB), mix.tab, lj_ir_knull(J, IRT_TAB)); -nocheck: - if (mt) { - GCstr *mmstr = mmname_str(J2G(J), mm); - cTValue *mo = lj_tab_getstr(mt, mmstr); - if (mo && !tvisnil(mo)) - copyTV(J->L, &ix->mobjv, mo); - ix->mtv = mt; - settabV(J->L, &mix.tabv, mt); - setstrV(J->L, &mix.keyv, mmstr); - mix.key = lj_ir_kstr(J, mmstr); - mix.val = 0; - mix.idxchain = 0; - ix->mobj = lj_record_idx(J, &mix); - return !tref_isnil(ix->mobj); /* 1 if metamethod found, 0 if not. */ - } - return 0; /* No metamethod. */ -} - -/* Record call to arithmetic metamethod. */ -static TRef rec_mm_arith(jit_State *J, RecordIndex *ix, MMS mm) -{ - /* Set up metamethod call first to save ix->tab and ix->tabv. */ - BCReg func = rec_mm_prep(J, mm == MM_concat ? lj_cont_cat : lj_cont_ra); - TRef *base = J->base + func; - TValue *basev = J->L->base + func; - base[1+LJ_FR2] = ix->tab; base[2+LJ_FR2] = ix->key; - copyTV(J->L, basev+1+LJ_FR2, &ix->tabv); - copyTV(J->L, basev+2+LJ_FR2, &ix->keyv); - if (!lj_record_mm_lookup(J, ix, mm)) { /* Lookup mm on 1st operand. */ - if (mm != MM_unm) { - ix->tab = ix->key; - copyTV(J->L, &ix->tabv, &ix->keyv); - if (lj_record_mm_lookup(J, ix, mm)) /* Lookup mm on 2nd operand. */ - goto ok; - } - lj_trace_err(J, LJ_TRERR_NOMM); - } -ok: - base[0] = ix->mobj; -#if LJ_FR2 - base[1] = 0; -#endif - copyTV(J->L, basev+0, &ix->mobjv); - lj_record_call(J, func, 2); - return 0; /* No result yet. */ -} - -/* Record call to __len metamethod. */ -static TRef rec_mm_len(jit_State *J, TRef tr, TValue *tv) -{ - RecordIndex ix; - ix.tab = tr; - copyTV(J->L, &ix.tabv, tv); - if (lj_record_mm_lookup(J, &ix, MM_len)) { - BCReg func = rec_mm_prep(J, lj_cont_ra); - TRef *base = J->base + func; - TValue *basev = J->L->base + func; - base[0] = ix.mobj; copyTV(J->L, basev+0, &ix.mobjv); - base += LJ_FR2; - basev += LJ_FR2; - base[1] = tr; copyTV(J->L, basev+1, tv); -#if LJ_52 - base[2] = tr; copyTV(J->L, basev+2, tv); -#else - base[2] = TREF_NIL; setnilV(basev+2); -#endif - lj_record_call(J, func, 2); - } else { - if (LJ_52 && tref_istab(tr)) - return lj_ir_call(J, IRCALL_lj_tab_len, tr); - lj_trace_err(J, LJ_TRERR_NOMM); - } - return 0; /* No result yet. */ -} - -/* Call a comparison metamethod. */ -static void rec_mm_callcomp(jit_State *J, RecordIndex *ix, int op) -{ - BCReg func = rec_mm_prep(J, (op&1) ? lj_cont_condf : lj_cont_condt); - TRef *base = J->base + func + LJ_FR2; - TValue *tv = J->L->base + func + LJ_FR2; - base[-LJ_FR2] = ix->mobj; base[1] = ix->val; base[2] = ix->key; - copyTV(J->L, tv-LJ_FR2, &ix->mobjv); - copyTV(J->L, tv+1, &ix->valv); - copyTV(J->L, tv+2, &ix->keyv); - lj_record_call(J, func, 2); -} - -/* Record call to equality comparison metamethod (for tab and udata only). */ -static void rec_mm_equal(jit_State *J, RecordIndex *ix, int op) -{ - ix->tab = ix->val; - copyTV(J->L, &ix->tabv, &ix->valv); - if (lj_record_mm_lookup(J, ix, MM_eq)) { /* Lookup mm on 1st operand. */ - cTValue *bv; - TRef mo1 = ix->mobj; - TValue mo1v; - copyTV(J->L, &mo1v, &ix->mobjv); - /* Avoid the 2nd lookup and the objcmp if the metatables are equal. */ - bv = &ix->keyv; - if (tvistab(bv) && tabref(tabV(bv)->metatable) == ix->mtv) { - TRef mt2 = emitir(IRT(IR_FLOAD, IRT_TAB), ix->key, IRFL_TAB_META); - emitir(IRTG(IR_EQ, IRT_TAB), mt2, ix->mt); - } else if (tvisudata(bv) && tabref(udataV(bv)->metatable) == ix->mtv) { - TRef mt2 = emitir(IRT(IR_FLOAD, IRT_TAB), ix->key, IRFL_UDATA_META); - emitir(IRTG(IR_EQ, IRT_TAB), mt2, ix->mt); - } else { /* Lookup metamethod on 2nd operand and compare both. */ - ix->tab = ix->key; - copyTV(J->L, &ix->tabv, bv); - if (!lj_record_mm_lookup(J, ix, MM_eq) || - lj_record_objcmp(J, mo1, ix->mobj, &mo1v, &ix->mobjv)) - return; - } - rec_mm_callcomp(J, ix, op); - } -} - -/* Record call to ordered comparison metamethods (for arbitrary objects). */ -static void rec_mm_comp(jit_State *J, RecordIndex *ix, int op) -{ - ix->tab = ix->val; - copyTV(J->L, &ix->tabv, &ix->valv); - while (1) { - MMS mm = (op & 2) ? MM_le : MM_lt; /* Try __le + __lt or only __lt. */ -#if LJ_52 - if (!lj_record_mm_lookup(J, ix, mm)) { /* Lookup mm on 1st operand. */ - ix->tab = ix->key; - copyTV(J->L, &ix->tabv, &ix->keyv); - if (!lj_record_mm_lookup(J, ix, mm)) /* Lookup mm on 2nd operand. */ - goto nomatch; - } - rec_mm_callcomp(J, ix, op); - return; -#else - if (lj_record_mm_lookup(J, ix, mm)) { /* Lookup mm on 1st operand. */ - cTValue *bv; - TRef mo1 = ix->mobj; - TValue mo1v; - copyTV(J->L, &mo1v, &ix->mobjv); - /* Avoid the 2nd lookup and the objcmp if the metatables are equal. */ - bv = &ix->keyv; - if (tvistab(bv) && tabref(tabV(bv)->metatable) == ix->mtv) { - TRef mt2 = emitir(IRT(IR_FLOAD, IRT_TAB), ix->key, IRFL_TAB_META); - emitir(IRTG(IR_EQ, IRT_TAB), mt2, ix->mt); - } else if (tvisudata(bv) && tabref(udataV(bv)->metatable) == ix->mtv) { - TRef mt2 = emitir(IRT(IR_FLOAD, IRT_TAB), ix->key, IRFL_UDATA_META); - emitir(IRTG(IR_EQ, IRT_TAB), mt2, ix->mt); - } else { /* Lookup metamethod on 2nd operand and compare both. */ - ix->tab = ix->key; - copyTV(J->L, &ix->tabv, bv); - if (!lj_record_mm_lookup(J, ix, mm) || - lj_record_objcmp(J, mo1, ix->mobj, &mo1v, &ix->mobjv)) - goto nomatch; - } - rec_mm_callcomp(J, ix, op); - return; - } -#endif - nomatch: - /* Lookup failed. Retry with __lt and swapped operands. */ - if (!(op & 2)) break; /* Already at __lt. Interpreter will throw. */ - ix->tab = ix->key; ix->key = ix->val; ix->val = ix->tab; - copyTV(J->L, &ix->tabv, &ix->keyv); - copyTV(J->L, &ix->keyv, &ix->valv); - copyTV(J->L, &ix->valv, &ix->tabv); - op ^= 3; - } -} - -#if LJ_HASFFI -/* Setup call to cdata comparison metamethod. */ -static void rec_mm_comp_cdata(jit_State *J, RecordIndex *ix, int op, MMS mm) -{ - lj_snap_add(J); - if (tref_iscdata(ix->val)) { - ix->tab = ix->val; - copyTV(J->L, &ix->tabv, &ix->valv); - } else { - lua_assert(tref_iscdata(ix->key)); - ix->tab = ix->key; - copyTV(J->L, &ix->tabv, &ix->keyv); - } - lj_record_mm_lookup(J, ix, mm); - rec_mm_callcomp(J, ix, op); -} -#endif - -/* -- Indexed access ------------------------------------------------------ */ - -#ifdef LUAJIT_ENABLE_TABLE_BUMP -/* Bump table allocations in bytecode when they grow during recording. */ -static void rec_idx_bump(jit_State *J, RecordIndex *ix) -{ - RBCHashEntry *rbc = &J->rbchash[(ix->tab & (RBCHASH_SLOTS-1))]; - if (tref_ref(ix->tab) == rbc->ref) { - const BCIns *pc = mref(rbc->pc, const BCIns); - GCtab *tb = tabV(&ix->tabv); - uint32_t nhbits; - IRIns *ir; - if (!tvisnil(&ix->keyv)) - (void)lj_tab_set(J->L, tb, &ix->keyv); /* Grow table right now. */ - nhbits = tb->hmask > 0 ? lj_fls(tb->hmask)+1 : 0; - ir = IR(tref_ref(ix->tab)); - if (ir->o == IR_TNEW) { - uint32_t ah = bc_d(*pc); - uint32_t asize = ah & 0x7ff, hbits = ah >> 11; - if (nhbits > hbits) hbits = nhbits; - if (tb->asize > asize) { - asize = tb->asize <= 0x7ff ? tb->asize : 0x7ff; - } - if ((asize | (hbits<<11)) != ah) { /* Has the size changed? */ - /* Patch bytecode, but continue recording (for more patching). */ - setbc_d(pc, (asize | (hbits<<11))); - /* Patching TNEW operands is only safe if the trace is aborted. */ - ir->op1 = asize; ir->op2 = hbits; - J->retryrec = 1; /* Abort the trace at the end of recording. */ - } - } else if (ir->o == IR_TDUP) { - GCtab *tpl = gco2tab(proto_kgc(&gcref(rbc->pt)->pt, ~(ptrdiff_t)bc_d(*pc))); - /* Grow template table, but preserve keys with nil values. */ - if ((tb->asize > tpl->asize && (1u << nhbits)-1 == tpl->hmask) || - (tb->asize == tpl->asize && (1u << nhbits)-1 > tpl->hmask)) { - Node *node = noderef(tpl->node); - uint32_t i, hmask = tpl->hmask, asize; - TValue *array; - for (i = 0; i <= hmask; i++) { - if (!tvisnil(&node[i].key) && tvisnil(&node[i].val)) - settabV(J->L, &node[i].val, tpl); - } - if (!tvisnil(&ix->keyv) && tref_isk(ix->key)) { - TValue *o = lj_tab_set(J->L, tpl, &ix->keyv); - if (tvisnil(o)) settabV(J->L, o, tpl); - } - lj_tab_resize(J->L, tpl, tb->asize, nhbits); - node = noderef(tpl->node); - hmask = tpl->hmask; - for (i = 0; i <= hmask; i++) { - /* This is safe, since template tables only hold immutable values. */ - if (tvistab(&node[i].val)) - setnilV(&node[i].val); - } - /* The shape of the table may have changed. Clean up array part, too. */ - asize = tpl->asize; - array = tvref(tpl->array); - for (i = 0; i < asize; i++) { - if (tvistab(&array[i])) - setnilV(&array[i]); - } - J->retryrec = 1; /* Abort the trace at the end of recording. */ - } - } - } -} -#endif - -/* Record bounds-check. */ -static void rec_idx_abc(jit_State *J, TRef asizeref, TRef ikey, uint32_t asize) -{ - /* Try to emit invariant bounds checks. */ - if ((J->flags & (JIT_F_OPT_LOOP|JIT_F_OPT_ABC)) == - (JIT_F_OPT_LOOP|JIT_F_OPT_ABC)) { - IRRef ref = tref_ref(ikey); - IRIns *ir = IR(ref); - int32_t ofs = 0; - IRRef ofsref = 0; - /* Handle constant offsets. */ - if (ir->o == IR_ADD && irref_isk(ir->op2)) { - ofsref = ir->op2; - ofs = IR(ofsref)->i; - ref = ir->op1; - ir = IR(ref); - } - /* Got scalar evolution analysis results for this reference? */ - if (ref == J->scev.idx) { - int32_t stop; - lua_assert(irt_isint(J->scev.t) && ir->o == IR_SLOAD); - stop = numberVint(&(J->L->base - J->baseslot)[ir->op1 + FORL_STOP]); - /* Runtime value for stop of loop is within bounds? */ - if ((uint64_t)stop + ofs < (uint64_t)asize) { - /* Emit invariant bounds check for stop. */ - emitir(IRTG(IR_ABC, IRT_P32), asizeref, ofs == 0 ? J->scev.stop : - emitir(IRTI(IR_ADD), J->scev.stop, ofsref)); - /* Emit invariant bounds check for start, if not const or negative. */ - if (!(J->scev.dir && J->scev.start && - (int64_t)IR(J->scev.start)->i + ofs >= 0)) - emitir(IRTG(IR_ABC, IRT_P32), asizeref, ikey); - return; - } - } - } - emitir(IRTGI(IR_ABC), asizeref, ikey); /* Emit regular bounds check. */ -} - -/* Record indexed key lookup. */ -static TRef rec_idx_key(jit_State *J, RecordIndex *ix, IRRef *rbref, - IRType1 *rbguard) -{ - TRef key; - GCtab *t = tabV(&ix->tabv); - ix->oldv = lj_tab_get(J->L, t, &ix->keyv); /* Lookup previous value. */ - *rbref = 0; - rbguard->irt = 0; - - /* Integer keys are looked up in the array part first. */ - key = ix->key; - if (tref_isnumber(key)) { - int32_t k = numberVint(&ix->keyv); - if (!tvisint(&ix->keyv) && numV(&ix->keyv) != (lua_Number)k) - k = LJ_MAX_ASIZE; - if ((MSize)k < LJ_MAX_ASIZE) { /* Potential array key? */ - TRef ikey = lj_opt_narrow_index(J, key); - TRef asizeref = emitir(IRTI(IR_FLOAD), ix->tab, IRFL_TAB_ASIZE); - if ((MSize)k < t->asize) { /* Currently an array key? */ - TRef arrayref; - rec_idx_abc(J, asizeref, ikey, t->asize); - arrayref = emitir(IRT(IR_FLOAD, IRT_PGC), ix->tab, IRFL_TAB_ARRAY); - return emitir(IRT(IR_AREF, IRT_PGC), arrayref, ikey); - } else { /* Currently not in array (may be an array extension)? */ - emitir(IRTGI(IR_ULE), asizeref, ikey); /* Inv. bounds check. */ - if (k == 0 && tref_isk(key)) - key = lj_ir_knum_zero(J); /* Canonicalize 0 or +-0.0 to +0.0. */ - /* And continue with the hash lookup. */ - } - } else if (!tref_isk(key)) { - /* We can rule out const numbers which failed the integerness test - ** above. But all other numbers are potential array keys. - */ - if (t->asize == 0) { /* True sparse tables have an empty array part. */ - /* Guard that the array part stays empty. */ - TRef tmp = emitir(IRTI(IR_FLOAD), ix->tab, IRFL_TAB_ASIZE); - emitir(IRTGI(IR_EQ), tmp, lj_ir_kint(J, 0)); - } else { - lj_trace_err(J, LJ_TRERR_NYITMIX); - } - } - } - - /* Otherwise the key is located in the hash part. */ - if (t->hmask == 0) { /* Shortcut for empty hash part. */ - /* Guard that the hash part stays empty. */ - TRef tmp = emitir(IRTI(IR_FLOAD), ix->tab, IRFL_TAB_HMASK); - emitir(IRTGI(IR_EQ), tmp, lj_ir_kint(J, 0)); - return lj_ir_kkptr(J, niltvg(J2G(J))); - } - if (tref_isinteger(key)) /* Hash keys are based on numbers, not ints. */ - key = emitir(IRTN(IR_CONV), key, IRCONV_NUM_INT); - if (tref_isk(key)) { - /* Optimize lookup of constant hash keys. */ - MSize hslot = (MSize)((char *)ix->oldv - (char *)&noderef(t->node)[0].val); - if (t->hmask > 0 && hslot <= t->hmask*(MSize)sizeof(Node) && - hslot <= 65535*(MSize)sizeof(Node)) { - TRef node, kslot, hm; - *rbref = J->cur.nins; /* Mark possible rollback point. */ - *rbguard = J->guardemit; - hm = emitir(IRTI(IR_FLOAD), ix->tab, IRFL_TAB_HMASK); - emitir(IRTGI(IR_EQ), hm, lj_ir_kint(J, (int32_t)t->hmask)); - node = emitir(IRT(IR_FLOAD, IRT_PGC), ix->tab, IRFL_TAB_NODE); - kslot = lj_ir_kslot(J, key, hslot / sizeof(Node)); - return emitir(IRTG(IR_HREFK, IRT_PGC), node, kslot); - } - } - /* Fall back to a regular hash lookup. */ - return emitir(IRT(IR_HREF, IRT_PGC), ix->tab, key); -} - -/* Determine whether a key is NOT one of the fast metamethod names. */ -static int nommstr(jit_State *J, TRef key) -{ - if (tref_isstr(key)) { - if (tref_isk(key)) { - GCstr *str = ir_kstr(IR(tref_ref(key))); - uint32_t mm; - for (mm = 0; mm <= MM_FAST; mm++) - if (mmname_str(J2G(J), mm) == str) - return 0; /* MUST be one the fast metamethod names. */ - } else { - return 0; /* Variable string key MAY be a metamethod name. */ - } - } - return 1; /* CANNOT be a metamethod name. */ -} - -/* Record indexed load/store. */ -TRef lj_record_idx(jit_State *J, RecordIndex *ix) -{ - TRef xref; - IROp xrefop, loadop; - IRRef rbref; - IRType1 rbguard; - cTValue *oldv; - - while (!tref_istab(ix->tab)) { /* Handle non-table lookup. */ - /* Never call raw lj_record_idx() on non-table. */ - lua_assert(ix->idxchain != 0); - if (!lj_record_mm_lookup(J, ix, ix->val ? MM_newindex : MM_index)) - lj_trace_err(J, LJ_TRERR_NOMM); - handlemm: - if (tref_isfunc(ix->mobj)) { /* Handle metamethod call. */ - BCReg func = rec_mm_prep(J, ix->val ? lj_cont_nop : lj_cont_ra); - TRef *base = J->base + func + LJ_FR2; - TValue *tv = J->L->base + func + LJ_FR2; - base[-LJ_FR2] = ix->mobj; base[1] = ix->tab; base[2] = ix->key; - setfuncV(J->L, tv-LJ_FR2, funcV(&ix->mobjv)); - copyTV(J->L, tv+1, &ix->tabv); - copyTV(J->L, tv+2, &ix->keyv); - if (ix->val) { - base[3] = ix->val; - copyTV(J->L, tv+3, &ix->valv); - lj_record_call(J, func, 3); /* mobj(tab, key, val) */ - return 0; - } else { - lj_record_call(J, func, 2); /* res = mobj(tab, key) */ - return 0; /* No result yet. */ - } - } - /* Otherwise retry lookup with metaobject. */ - ix->tab = ix->mobj; - copyTV(J->L, &ix->tabv, &ix->mobjv); - if (--ix->idxchain == 0) - lj_trace_err(J, LJ_TRERR_IDXLOOP); - } - - /* First catch nil and NaN keys for tables. */ - if (tvisnil(&ix->keyv) || (tvisnum(&ix->keyv) && tvisnan(&ix->keyv))) { - if (ix->val) /* Better fail early. */ - lj_trace_err(J, LJ_TRERR_STORENN); - if (tref_isk(ix->key)) { - if (ix->idxchain && lj_record_mm_lookup(J, ix, MM_index)) - goto handlemm; - return TREF_NIL; - } - } - - /* Record the key lookup. */ - xref = rec_idx_key(J, ix, &rbref, &rbguard); - xrefop = IR(tref_ref(xref))->o; - loadop = xrefop == IR_AREF ? IR_ALOAD : IR_HLOAD; - /* The lj_meta_tset() inconsistency is gone, but better play safe. */ - oldv = xrefop == IR_KKPTR ? (cTValue *)ir_kptr(IR(tref_ref(xref))) : ix->oldv; - - if (ix->val == 0) { /* Indexed load */ - IRType t = itype2irt(oldv); - TRef res; - if (oldv == niltvg(J2G(J))) { - emitir(IRTG(IR_EQ, IRT_PGC), xref, lj_ir_kkptr(J, niltvg(J2G(J)))); - res = TREF_NIL; - } else { - res = emitir(IRTG(loadop, t), xref, 0); - } - if (tref_ref(res) < rbref) { /* HREFK + load forwarded? */ - lj_ir_rollback(J, rbref); /* Rollback to eliminate hmask guard. */ - J->guardemit = rbguard; - } - if (t == IRT_NIL && ix->idxchain && lj_record_mm_lookup(J, ix, MM_index)) - goto handlemm; - if (irtype_ispri(t)) res = TREF_PRI(t); /* Canonicalize primitives. */ - return res; - } else { /* Indexed store. */ - GCtab *mt = tabref(tabV(&ix->tabv)->metatable); - int keybarrier = tref_isgcv(ix->key) && !tref_isnil(ix->val); - if (tref_ref(xref) < rbref) { /* HREFK forwarded? */ - lj_ir_rollback(J, rbref); /* Rollback to eliminate hmask guard. */ - J->guardemit = rbguard; - } - if (tvisnil(oldv)) { /* Previous value was nil? */ - /* Need to duplicate the hasmm check for the early guards. */ - int hasmm = 0; - if (ix->idxchain && mt) { - cTValue *mo = lj_tab_getstr(mt, mmname_str(J2G(J), MM_newindex)); - hasmm = mo && !tvisnil(mo); - } - if (hasmm) - emitir(IRTG(loadop, IRT_NIL), xref, 0); /* Guard for nil value. */ - else if (xrefop == IR_HREF) - emitir(IRTG(oldv == niltvg(J2G(J)) ? IR_EQ : IR_NE, IRT_PGC), - xref, lj_ir_kkptr(J, niltvg(J2G(J)))); - if (ix->idxchain && lj_record_mm_lookup(J, ix, MM_newindex)) { - lua_assert(hasmm); - goto handlemm; - } - lua_assert(!hasmm); - if (oldv == niltvg(J2G(J))) { /* Need to insert a new key. */ - TRef key = ix->key; - if (tref_isinteger(key)) /* NEWREF needs a TValue as a key. */ - key = emitir(IRTN(IR_CONV), key, IRCONV_NUM_INT); - xref = emitir(IRT(IR_NEWREF, IRT_PGC), ix->tab, key); - keybarrier = 0; /* NEWREF already takes care of the key barrier. */ -#ifdef LUAJIT_ENABLE_TABLE_BUMP - if ((J->flags & JIT_F_OPT_SINK)) /* Avoid a separate flag. */ - rec_idx_bump(J, ix); -#endif - } - } else if (!lj_opt_fwd_wasnonnil(J, loadop, tref_ref(xref))) { - /* Cannot derive that the previous value was non-nil, must do checks. */ - if (xrefop == IR_HREF) /* Guard against store to niltv. */ - emitir(IRTG(IR_NE, IRT_PGC), xref, lj_ir_kkptr(J, niltvg(J2G(J)))); - if (ix->idxchain) { /* Metamethod lookup required? */ - /* A check for NULL metatable is cheaper (hoistable) than a load. */ - if (!mt) { - TRef mtref = emitir(IRT(IR_FLOAD, IRT_TAB), ix->tab, IRFL_TAB_META); - emitir(IRTG(IR_EQ, IRT_TAB), mtref, lj_ir_knull(J, IRT_TAB)); - } else { - IRType t = itype2irt(oldv); - emitir(IRTG(loadop, t), xref, 0); /* Guard for non-nil value. */ - } - } - } else { - keybarrier = 0; /* Previous non-nil value kept the key alive. */ - } - /* Convert int to number before storing. */ - if (!LJ_DUALNUM && tref_isinteger(ix->val)) - ix->val = emitir(IRTN(IR_CONV), ix->val, IRCONV_NUM_INT); - emitir(IRT(loadop+IRDELTA_L2S, tref_type(ix->val)), xref, ix->val); - if (keybarrier || tref_isgcv(ix->val)) - emitir(IRT(IR_TBAR, IRT_NIL), ix->tab, 0); - /* Invalidate neg. metamethod cache for stores with certain string keys. */ - if (!nommstr(J, ix->key)) { - TRef fref = emitir(IRT(IR_FREF, IRT_PGC), ix->tab, IRFL_TAB_NOMM); - emitir(IRT(IR_FSTORE, IRT_U8), fref, lj_ir_kint(J, 0)); - } - J->needsnap = 1; - return 0; - } -} - -static void rec_tsetm(jit_State *J, BCReg ra, BCReg rn, int32_t i) -{ - RecordIndex ix; - cTValue *basev = J->L->base; - GCtab *t = tabV(&basev[ra-1]); - settabV(J->L, &ix.tabv, t); - ix.tab = getslot(J, ra-1); - ix.idxchain = 0; -#ifdef LUAJIT_ENABLE_TABLE_BUMP - if ((J->flags & JIT_F_OPT_SINK)) { - if (t->asize < i+rn-ra) - lj_tab_reasize(J->L, t, i+rn-ra); - setnilV(&ix.keyv); - rec_idx_bump(J, &ix); - } -#endif - for (; ra < rn; i++, ra++) { - setintV(&ix.keyv, i); - ix.key = lj_ir_kint(J, i); - copyTV(J->L, &ix.valv, &basev[ra]); - ix.val = getslot(J, ra); - lj_record_idx(J, &ix); - } -} - -/* -- Upvalue access ------------------------------------------------------ */ - -/* Check whether upvalue is immutable and ok to constify. */ -static int rec_upvalue_constify(jit_State *J, GCupval *uvp) -{ - if (uvp->immutable) { - cTValue *o = uvval(uvp); - /* Don't constify objects that may retain large amounts of memory. */ -#if LJ_HASFFI - if (tviscdata(o)) { - GCcdata *cd = cdataV(o); - if (!cdataisv(cd) && !(cd->marked & LJ_GC_CDATA_FIN)) { - CType *ct = ctype_raw(ctype_ctsG(J2G(J)), cd->ctypeid); - if (!ctype_hassize(ct->info) || ct->size <= 16) - return 1; - } - return 0; - } -#else - UNUSED(J); -#endif - if (!(tvistab(o) || tvisudata(o) || tvisthread(o))) - return 1; - } - return 0; -} - -/* Record upvalue load/store. */ -static TRef rec_upvalue(jit_State *J, uint32_t uv, TRef val) -{ - GCupval *uvp = &gcref(J->fn->l.uvptr[uv])->uv; - TRef fn = getcurrf(J); - IRRef uref; - int needbarrier = 0; - if (rec_upvalue_constify(J, uvp)) { /* Try to constify immutable upvalue. */ - TRef tr, kfunc; - lua_assert(val == 0); - if (!tref_isk(fn)) { /* Late specialization of current function. */ - if (J->pt->flags >= PROTO_CLC_POLY) - goto noconstify; - kfunc = lj_ir_kfunc(J, J->fn); - emitir(IRTG(IR_EQ, IRT_FUNC), fn, kfunc); -#if LJ_FR2 - J->base[-2] = kfunc; -#else - J->base[-1] = kfunc | TREF_FRAME; -#endif - fn = kfunc; - } - tr = lj_record_constify(J, uvval(uvp)); - if (tr) - return tr; - } -noconstify: - /* Note: this effectively limits LJ_MAX_UPVAL to 127. */ - uv = (uv << 8) | (hashrot(uvp->dhash, uvp->dhash + HASH_BIAS) & 0xff); - if (!uvp->closed) { - uref = tref_ref(emitir(IRTG(IR_UREFO, IRT_PGC), fn, uv)); - /* In current stack? */ - if (uvval(uvp) >= tvref(J->L->stack) && - uvval(uvp) < tvref(J->L->maxstack)) { - int32_t slot = (int32_t)(uvval(uvp) - (J->L->base - J->baseslot)); - if (slot >= 0) { /* Aliases an SSA slot? */ - emitir(IRTG(IR_EQ, IRT_PGC), - REF_BASE, - emitir(IRT(IR_ADD, IRT_PGC), uref, - lj_ir_kint(J, (slot - 1 - LJ_FR2) * -8))); - slot -= (int32_t)J->baseslot; /* Note: slot number may be negative! */ - if (val == 0) { - return getslot(J, slot); - } else { - J->base[slot] = val; - if (slot >= (int32_t)J->maxslot) J->maxslot = (BCReg)(slot+1); - return 0; - } - } - } - emitir(IRTG(IR_UGT, IRT_PGC), - emitir(IRT(IR_SUB, IRT_PGC), uref, REF_BASE), - lj_ir_kint(J, (J->baseslot + J->maxslot) * 8)); - } else { - needbarrier = 1; - uref = tref_ref(emitir(IRTG(IR_UREFC, IRT_PGC), fn, uv)); - } - if (val == 0) { /* Upvalue load */ - IRType t = itype2irt(uvval(uvp)); - TRef res = emitir(IRTG(IR_ULOAD, t), uref, 0); - if (irtype_ispri(t)) res = TREF_PRI(t); /* Canonicalize primitive refs. */ - return res; - } else { /* Upvalue store. */ - /* Convert int to number before storing. */ - if (!LJ_DUALNUM && tref_isinteger(val)) - val = emitir(IRTN(IR_CONV), val, IRCONV_NUM_INT); - emitir(IRT(IR_USTORE, tref_type(val)), uref, val); - if (needbarrier && tref_isgcv(val)) - emitir(IRT(IR_OBAR, IRT_NIL), uref, val); - J->needsnap = 1; - return 0; - } -} - -/* -- Record calls to Lua functions --------------------------------------- */ - -/* Check unroll limits for calls. */ -static void check_call_unroll(jit_State *J, TraceNo lnk) -{ - cTValue *frame = J->L->base - 1; - void *pc = mref(frame_func(frame)->l.pc, void); - int32_t depth = J->framedepth; - int32_t count = 0; - if ((J->pt->flags & PROTO_VARARG)) depth--; /* Vararg frame still missing. */ - for (; depth > 0; depth--) { /* Count frames with same prototype. */ - if (frame_iscont(frame)) depth--; - frame = frame_prev(frame); - if (mref(frame_func(frame)->l.pc, void) == pc) - count++; - } - if (J->pc == J->startpc) { - if (count + J->tailcalled > J->param[JIT_P_recunroll]) { - J->pc++; - if (J->framedepth + J->retdepth == 0) - lj_record_stop(J, LJ_TRLINK_TAILREC, J->cur.traceno); /* Tail-rec. */ - else - lj_record_stop(J, LJ_TRLINK_UPREC, J->cur.traceno); /* Up-recursion. */ - } - } else { - if (count > J->param[JIT_P_callunroll]) { - if (lnk) { /* Possible tail- or up-recursion. */ - lj_trace_flush(J, lnk); /* Flush trace that only returns. */ - /* Set a small, pseudo-random hotcount for a quick retry of JFUNC*. */ - hotcount_set(J2GG(J), J->pc+1, LJ_PRNG_BITS(J, 4)); - } - lj_trace_err(J, LJ_TRERR_CUNROLL); - } - } -} - -/* Record Lua function setup. */ -static void rec_func_setup(jit_State *J) -{ - GCproto *pt = J->pt; - BCReg s, numparams = pt->numparams; - if ((pt->flags & PROTO_NOJIT)) - lj_trace_err(J, LJ_TRERR_CJITOFF); - if (J->baseslot + pt->framesize >= LJ_MAX_JSLOTS) - lj_trace_err(J, LJ_TRERR_STACKOV); - /* Fill up missing parameters with nil. */ - for (s = J->maxslot; s < numparams; s++) - J->base[s] = TREF_NIL; - /* The remaining slots should never be read before they are written. */ - J->maxslot = numparams; -} - -/* Record Lua vararg function setup. */ -static void rec_func_vararg(jit_State *J) -{ - GCproto *pt = J->pt; - BCReg s, fixargs, vframe = J->maxslot+1+LJ_FR2; - lua_assert((pt->flags & PROTO_VARARG)); - if (J->baseslot + vframe + pt->framesize >= LJ_MAX_JSLOTS) - lj_trace_err(J, LJ_TRERR_STACKOV); - J->base[vframe-1-LJ_FR2] = J->base[-1-LJ_FR2]; /* Copy function up. */ -#if LJ_FR2 - J->base[vframe-1] = TREF_FRAME; -#endif - /* Copy fixarg slots up and set their original slots to nil. */ - fixargs = pt->numparams < J->maxslot ? pt->numparams : J->maxslot; - for (s = 0; s < fixargs; s++) { - J->base[vframe+s] = J->base[s]; - J->base[s] = TREF_NIL; - } - J->maxslot = fixargs; - J->framedepth++; - J->base += vframe; - J->baseslot += vframe; -} - -/* Record entry to a Lua function. */ -static void rec_func_lua(jit_State *J) -{ - rec_func_setup(J); - check_call_unroll(J, 0); -} - -/* Record entry to an already compiled function. */ -static void rec_func_jit(jit_State *J, TraceNo lnk) -{ - GCtrace *T; - rec_func_setup(J); - T = traceref(J, lnk); - if (T->linktype == LJ_TRLINK_RETURN) { /* Trace returns to interpreter? */ - check_call_unroll(J, lnk); - /* Temporarily unpatch JFUNC* to continue recording across function. */ - J->patchins = *J->pc; - J->patchpc = (BCIns *)J->pc; - *J->patchpc = T->startins; - return; - } - J->instunroll = 0; /* Cannot continue across a compiled function. */ - if (J->pc == J->startpc && J->framedepth + J->retdepth == 0) - lj_record_stop(J, LJ_TRLINK_TAILREC, J->cur.traceno); /* Extra tail-rec. */ - else - lj_record_stop(J, LJ_TRLINK_ROOT, lnk); /* Link to the function. */ -} - -/* -- Vararg handling ----------------------------------------------------- */ - -/* Detect y = select(x, ...) idiom. */ -static int select_detect(jit_State *J) -{ - BCIns ins = J->pc[1]; - if (bc_op(ins) == BC_CALLM && bc_b(ins) == 2 && bc_c(ins) == 1) { - cTValue *func = &J->L->base[bc_a(ins)]; - if (tvisfunc(func) && funcV(func)->c.ffid == FF_select) { - TRef kfunc = lj_ir_kfunc(J, funcV(func)); - emitir(IRTG(IR_EQ, IRT_FUNC), getslot(J, bc_a(ins)), kfunc); - return 1; - } - } - return 0; -} - -/* Record vararg instruction. */ -static void rec_varg(jit_State *J, BCReg dst, ptrdiff_t nresults) -{ - int32_t numparams = J->pt->numparams; - ptrdiff_t nvararg = frame_delta(J->L->base-1) - numparams - 1 - LJ_FR2; - lua_assert(frame_isvarg(J->L->base-1)); - if (LJ_FR2 && dst > J->maxslot) - J->base[dst-1] = 0; /* Prevent resurrection of unrelated slot. */ - if (J->framedepth > 0) { /* Simple case: varargs defined on-trace. */ - ptrdiff_t i; - if (nvararg < 0) nvararg = 0; - if (nresults == -1) { - nresults = nvararg; - J->maxslot = dst + (BCReg)nvararg; - } else if (dst + nresults > J->maxslot) { - J->maxslot = dst + (BCReg)nresults; - } - for (i = 0; i < nresults; i++) - J->base[dst+i] = i < nvararg ? getslot(J, i - nvararg - 1 - LJ_FR2) : TREF_NIL; - } else { /* Unknown number of varargs passed to trace. */ - TRef fr = emitir(IRTI(IR_SLOAD), LJ_FR2, IRSLOAD_READONLY|IRSLOAD_FRAME); - int32_t frofs = 8*(1+LJ_FR2+numparams)+FRAME_VARG; - if (nresults >= 0) { /* Known fixed number of results. */ - ptrdiff_t i; - if (nvararg > 0) { - ptrdiff_t nload = nvararg >= nresults ? nresults : nvararg; - TRef vbase; - if (nvararg >= nresults) - emitir(IRTGI(IR_GE), fr, lj_ir_kint(J, frofs+8*(int32_t)nresults)); - else - emitir(IRTGI(IR_EQ), fr, - lj_ir_kint(J, (int32_t)frame_ftsz(J->L->base-1))); - vbase = emitir(IRT(IR_SUB, IRT_IGC), REF_BASE, fr); - vbase = emitir(IRT(IR_ADD, IRT_PGC), vbase, lj_ir_kint(J, frofs-8)); - for (i = 0; i < nload; i++) { - IRType t = itype2irt(&J->L->base[i-1-LJ_FR2-nvararg]); - TRef aref = emitir(IRT(IR_AREF, IRT_PGC), - vbase, lj_ir_kint(J, (int32_t)i)); - TRef tr = emitir(IRTG(IR_VLOAD, t), aref, 0); - if (irtype_ispri(t)) tr = TREF_PRI(t); /* Canonicalize primitives. */ - J->base[dst+i] = tr; - } - } else { - emitir(IRTGI(IR_LE), fr, lj_ir_kint(J, frofs)); - nvararg = 0; - } - for (i = nvararg; i < nresults; i++) - J->base[dst+i] = TREF_NIL; - if (dst + (BCReg)nresults > J->maxslot) - J->maxslot = dst + (BCReg)nresults; - } else if (select_detect(J)) { /* y = select(x, ...) */ - TRef tridx = J->base[dst-1]; - TRef tr = TREF_NIL; - ptrdiff_t idx = lj_ffrecord_select_mode(J, tridx, &J->L->base[dst-1]); - if (idx < 0) goto nyivarg; - if (idx != 0 && !tref_isinteger(tridx)) - tridx = emitir(IRTGI(IR_CONV), tridx, IRCONV_INT_NUM|IRCONV_INDEX); - if (idx != 0 && tref_isk(tridx)) { - emitir(IRTGI(idx <= nvararg ? IR_GE : IR_LT), - fr, lj_ir_kint(J, frofs+8*(int32_t)idx)); - frofs -= 8; /* Bias for 1-based index. */ - } else if (idx <= nvararg) { /* Compute size. */ - TRef tmp = emitir(IRTI(IR_ADD), fr, lj_ir_kint(J, -frofs)); - if (numparams) - emitir(IRTGI(IR_GE), tmp, lj_ir_kint(J, 0)); - tr = emitir(IRTI(IR_BSHR), tmp, lj_ir_kint(J, 3)); - if (idx != 0) { - tridx = emitir(IRTI(IR_ADD), tridx, lj_ir_kint(J, -1)); - rec_idx_abc(J, tr, tridx, (uint32_t)nvararg); - } - } else { - TRef tmp = lj_ir_kint(J, frofs); - if (idx != 0) { - TRef tmp2 = emitir(IRTI(IR_BSHL), tridx, lj_ir_kint(J, 3)); - tmp = emitir(IRTI(IR_ADD), tmp2, tmp); - } else { - tr = lj_ir_kint(J, 0); - } - emitir(IRTGI(IR_LT), fr, tmp); - } - if (idx != 0 && idx <= nvararg) { - IRType t; - TRef aref, vbase = emitir(IRT(IR_SUB, IRT_IGC), REF_BASE, fr); - vbase = emitir(IRT(IR_ADD, IRT_PGC), vbase, - lj_ir_kint(J, frofs-(8<L->base[idx-2-LJ_FR2-nvararg]); - aref = emitir(IRT(IR_AREF, IRT_PGC), vbase, tridx); - tr = emitir(IRTG(IR_VLOAD, t), aref, 0); - if (irtype_ispri(t)) tr = TREF_PRI(t); /* Canonicalize primitives. */ - } - J->base[dst-2-LJ_FR2] = tr; - J->maxslot = dst-1-LJ_FR2; - J->bcskip = 2; /* Skip CALLM + select. */ - } else { - nyivarg: - setintV(&J->errinfo, BC_VARG); - lj_trace_err_info(J, LJ_TRERR_NYIBC); - } - } -} - -/* -- Record allocations -------------------------------------------------- */ - -static TRef rec_tnew(jit_State *J, uint32_t ah) -{ - uint32_t asize = ah & 0x7ff; - uint32_t hbits = ah >> 11; - TRef tr; - if (asize == 0x7ff) asize = 0x801; - tr = emitir(IRTG(IR_TNEW, IRT_TAB), asize, hbits); -#ifdef LUAJIT_ENABLE_TABLE_BUMP - J->rbchash[(tr & (RBCHASH_SLOTS-1))].ref = tref_ref(tr); - setmref(J->rbchash[(tr & (RBCHASH_SLOTS-1))].pc, J->pc); - setgcref(J->rbchash[(tr & (RBCHASH_SLOTS-1))].pt, obj2gco(J->pt)); -#endif - return tr; -} - -/* -- Concatenation ------------------------------------------------------- */ - -static TRef rec_cat(jit_State *J, BCReg baseslot, BCReg topslot) -{ - TRef *top = &J->base[topslot]; - TValue savetv[5]; - BCReg s; - RecordIndex ix; - lua_assert(baseslot < topslot); - for (s = baseslot; s <= topslot; s++) - (void)getslot(J, s); /* Ensure all arguments have a reference. */ - if (tref_isnumber_str(top[0]) && tref_isnumber_str(top[-1])) { - TRef tr, hdr, *trp, *xbase, *base = &J->base[baseslot]; - /* First convert numbers to strings. */ - for (trp = top; trp >= base; trp--) { - if (tref_isnumber(*trp)) - *trp = emitir(IRT(IR_TOSTR, IRT_STR), *trp, - tref_isnum(*trp) ? IRTOSTR_NUM : IRTOSTR_INT); - else if (!tref_isstr(*trp)) - break; - } - xbase = ++trp; - tr = hdr = emitir(IRT(IR_BUFHDR, IRT_PGC), - lj_ir_kptr(J, &J2G(J)->tmpbuf), IRBUFHDR_RESET); - do { - tr = emitir(IRT(IR_BUFPUT, IRT_PGC), tr, *trp++); - } while (trp <= top); - tr = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr); - J->maxslot = (BCReg)(xbase - J->base); - if (xbase == base) return tr; /* Return simple concatenation result. */ - /* Pass partial result. */ - topslot = J->maxslot--; - *xbase = tr; - top = xbase; - setstrV(J->L, &ix.keyv, &J2G(J)->strempty); /* Simulate string result. */ - } else { - J->maxslot = topslot-1; - copyTV(J->L, &ix.keyv, &J->L->base[topslot]); - } - copyTV(J->L, &ix.tabv, &J->L->base[topslot-1]); - ix.tab = top[-1]; - ix.key = top[0]; - memcpy(savetv, &J->L->base[topslot-1], sizeof(savetv)); /* Save slots. */ - rec_mm_arith(J, &ix, MM_concat); /* Call __concat metamethod. */ - memcpy(&J->L->base[topslot-1], savetv, sizeof(savetv)); /* Restore slots. */ - return 0; /* No result yet. */ -} - -/* -- Record bytecode ops ------------------------------------------------- */ - -/* Prepare for comparison. */ -static void rec_comp_prep(jit_State *J) -{ - /* Prevent merging with snapshot #0 (GC exit) since we fixup the PC. */ - if (J->cur.nsnap == 1 && J->cur.snap[0].ref == J->cur.nins) - emitir_raw(IRT(IR_NOP, IRT_NIL), 0, 0); - lj_snap_add(J); -} - -/* Fixup comparison. */ -static void rec_comp_fixup(jit_State *J, const BCIns *pc, int cond) -{ - BCIns jmpins = pc[1]; - const BCIns *npc = pc + 2 + (cond ? bc_j(jmpins) : 0); - SnapShot *snap = &J->cur.snap[J->cur.nsnap-1]; - /* Set PC to opposite target to avoid re-recording the comp. in side trace. */ -#if LJ_FR2 - SnapEntry *flink = &J->cur.snapmap[snap->mapofs + snap->nent]; - uint64_t pcbase; - memcpy(&pcbase, flink, sizeof(uint64_t)); - pcbase = (pcbase & 0xff) | (u64ptr(npc) << 8); - memcpy(flink, &pcbase, sizeof(uint64_t)); -#else - J->cur.snapmap[snap->mapofs + snap->nent] = SNAP_MKPC(npc); -#endif - J->needsnap = 1; - if (bc_a(jmpins) < J->maxslot) J->maxslot = bc_a(jmpins); - lj_snap_shrink(J); /* Shrink last snapshot if possible. */ -} - -/* Record the next bytecode instruction (_before_ it's executed). */ -void lj_record_ins(jit_State *J) -{ - cTValue *lbase; - RecordIndex ix; - const BCIns *pc; - BCIns ins; - BCOp op; - TRef ra, rb, rc; - - /* Perform post-processing action before recording the next instruction. */ - if (LJ_UNLIKELY(J->postproc != LJ_POST_NONE)) { - switch (J->postproc) { - case LJ_POST_FIXCOMP: /* Fixup comparison. */ - pc = (const BCIns *)(uintptr_t)J2G(J)->tmptv.u64; - rec_comp_fixup(J, pc, (!tvistruecond(&J2G(J)->tmptv2) ^ (bc_op(*pc)&1))); - /* fallthrough */ - case LJ_POST_FIXGUARD: /* Fixup and emit pending guard. */ - case LJ_POST_FIXGUARDSNAP: /* Fixup and emit pending guard and snapshot. */ - if (!tvistruecond(&J2G(J)->tmptv2)) { - J->fold.ins.o ^= 1; /* Flip guard to opposite. */ - if (J->postproc == LJ_POST_FIXGUARDSNAP) { - SnapShot *snap = &J->cur.snap[J->cur.nsnap-1]; - J->cur.snapmap[snap->mapofs+snap->nent-1]--; /* False -> true. */ - } - } - lj_opt_fold(J); /* Emit pending guard. */ - /* fallthrough */ - case LJ_POST_FIXBOOL: - if (!tvistruecond(&J2G(J)->tmptv2)) { - BCReg s; - TValue *tv = J->L->base; - for (s = 0; s < J->maxslot; s++) /* Fixup stack slot (if any). */ - if (J->base[s] == TREF_TRUE && tvisfalse(&tv[s])) { - J->base[s] = TREF_FALSE; - break; - } - } - break; - case LJ_POST_FIXCONST: - { - BCReg s; - TValue *tv = J->L->base; - for (s = 0; s < J->maxslot; s++) /* Constify stack slots (if any). */ - if (J->base[s] == TREF_NIL && !tvisnil(&tv[s])) - J->base[s] = lj_record_constify(J, &tv[s]); - } - break; - case LJ_POST_FFRETRY: /* Suppress recording of retried fast function. */ - if (bc_op(*J->pc) >= BC__MAX) - return; - break; - default: lua_assert(0); break; - } - J->postproc = LJ_POST_NONE; - } - - /* Need snapshot before recording next bytecode (e.g. after a store). */ - if (J->needsnap) { - J->needsnap = 0; - lj_snap_purge(J); - lj_snap_add(J); - J->mergesnap = 1; - } - - /* Skip some bytecodes. */ - if (LJ_UNLIKELY(J->bcskip > 0)) { - J->bcskip--; - return; - } - - /* Record only closed loops for root traces. */ - pc = J->pc; - if (J->framedepth == 0 && - (MSize)((char *)pc - (char *)J->bc_min) >= J->bc_extent) - lj_trace_err(J, LJ_TRERR_LLEAVE); - -#ifdef LUA_USE_ASSERT - rec_check_slots(J); - rec_check_ir(J); -#endif - -#if LJ_HASPROFILE - rec_profile_ins(J, pc); -#endif - - /* Keep a copy of the runtime values of var/num/str operands. */ -#define rav (&ix.valv) -#define rbv (&ix.tabv) -#define rcv (&ix.keyv) - - lbase = J->L->base; - ins = *pc; - op = bc_op(ins); - ra = bc_a(ins); - ix.val = 0; - switch (bcmode_a(op)) { - case BCMvar: - copyTV(J->L, rav, &lbase[ra]); ix.val = ra = getslot(J, ra); break; - default: break; /* Handled later. */ - } - rb = bc_b(ins); - rc = bc_c(ins); - switch (bcmode_b(op)) { - case BCMnone: rb = 0; rc = bc_d(ins); break; /* Upgrade rc to 'rd'. */ - case BCMvar: - copyTV(J->L, rbv, &lbase[rb]); ix.tab = rb = getslot(J, rb); break; - default: break; /* Handled later. */ - } - switch (bcmode_c(op)) { - case BCMvar: - copyTV(J->L, rcv, &lbase[rc]); ix.key = rc = getslot(J, rc); break; - case BCMpri: setpriV(rcv, ~rc); ix.key = rc = TREF_PRI(IRT_NIL+rc); break; - case BCMnum: { cTValue *tv = proto_knumtv(J->pt, rc); - copyTV(J->L, rcv, tv); ix.key = rc = tvisint(tv) ? lj_ir_kint(J, intV(tv)) : - lj_ir_knumint(J, numV(tv)); } break; - case BCMstr: { GCstr *s = gco2str(proto_kgc(J->pt, ~(ptrdiff_t)rc)); - setstrV(J->L, rcv, s); ix.key = rc = lj_ir_kstr(J, s); } break; - default: break; /* Handled later. */ - } - - switch (op) { - - /* -- Comparison ops ---------------------------------------------------- */ - - case BC_ISLT: case BC_ISGE: case BC_ISLE: case BC_ISGT: -#if LJ_HASFFI - if (tref_iscdata(ra) || tref_iscdata(rc)) { - rec_mm_comp_cdata(J, &ix, op, ((int)op & 2) ? MM_le : MM_lt); - break; - } -#endif - /* Emit nothing for two numeric or string consts. */ - if (!(tref_isk2(ra,rc) && tref_isnumber_str(ra) && tref_isnumber_str(rc))) { - IRType ta = tref_isinteger(ra) ? IRT_INT : tref_type(ra); - IRType tc = tref_isinteger(rc) ? IRT_INT : tref_type(rc); - int irop; - if (ta != tc) { - /* Widen mixed number/int comparisons to number/number comparison. */ - if (ta == IRT_INT && tc == IRT_NUM) { - ra = emitir(IRTN(IR_CONV), ra, IRCONV_NUM_INT); - ta = IRT_NUM; - } else if (ta == IRT_NUM && tc == IRT_INT) { - rc = emitir(IRTN(IR_CONV), rc, IRCONV_NUM_INT); - } else if (LJ_52) { - ta = IRT_NIL; /* Force metamethod for different types. */ - } else if (!((ta == IRT_FALSE || ta == IRT_TRUE) && - (tc == IRT_FALSE || tc == IRT_TRUE))) { - break; /* Interpreter will throw for two different types. */ - } - } - rec_comp_prep(J); - irop = (int)op - (int)BC_ISLT + (int)IR_LT; - if (ta == IRT_NUM) { - if ((irop & 1)) irop ^= 4; /* ISGE/ISGT are unordered. */ - if (!lj_ir_numcmp(numberVnum(rav), numberVnum(rcv), (IROp)irop)) - irop ^= 5; - } else if (ta == IRT_INT) { - if (!lj_ir_numcmp(numberVnum(rav), numberVnum(rcv), (IROp)irop)) - irop ^= 1; - } else if (ta == IRT_STR) { - if (!lj_ir_strcmp(strV(rav), strV(rcv), (IROp)irop)) irop ^= 1; - ra = lj_ir_call(J, IRCALL_lj_str_cmp, ra, rc); - rc = lj_ir_kint(J, 0); - ta = IRT_INT; - } else { - rec_mm_comp(J, &ix, (int)op); - break; - } - emitir(IRTG(irop, ta), ra, rc); - rec_comp_fixup(J, J->pc, ((int)op ^ irop) & 1); - } - break; - - case BC_ISEQV: case BC_ISNEV: - case BC_ISEQS: case BC_ISNES: - case BC_ISEQN: case BC_ISNEN: - case BC_ISEQP: case BC_ISNEP: -#if LJ_HASFFI - if (tref_iscdata(ra) || tref_iscdata(rc)) { - rec_mm_comp_cdata(J, &ix, op, MM_eq); - break; - } -#endif - /* Emit nothing for two non-table, non-udata consts. */ - if (!(tref_isk2(ra, rc) && !(tref_istab(ra) || tref_isudata(ra)))) { - int diff; - rec_comp_prep(J); - diff = lj_record_objcmp(J, ra, rc, rav, rcv); - if (diff == 2 || !(tref_istab(ra) || tref_isudata(ra))) - rec_comp_fixup(J, J->pc, ((int)op & 1) == !diff); - else if (diff == 1) /* Only check __eq if different, but same type. */ - rec_mm_equal(J, &ix, (int)op); - } - break; - - /* -- Unary test and copy ops ------------------------------------------- */ - - case BC_ISTC: case BC_ISFC: - if ((op & 1) == tref_istruecond(rc)) - rc = 0; /* Don't store if condition is not true. */ - /* fallthrough */ - case BC_IST: case BC_ISF: /* Type specialization suffices. */ - if (bc_a(pc[1]) < J->maxslot) - J->maxslot = bc_a(pc[1]); /* Shrink used slots. */ - break; - - case BC_ISTYPE: case BC_ISNUM: - /* These coercions need to correspond with lj_meta_istype(). */ - if (LJ_DUALNUM && rc == ~LJ_TNUMX+1) - ra = lj_opt_narrow_toint(J, ra); - else if (rc == ~LJ_TNUMX+2) - ra = lj_ir_tonum(J, ra); - else if (rc == ~LJ_TSTR+1) - ra = lj_ir_tostr(J, ra); - /* else: type specialization suffices. */ - J->base[bc_a(ins)] = ra; - break; - - /* -- Unary ops --------------------------------------------------------- */ - - case BC_NOT: - /* Type specialization already forces const result. */ - rc = tref_istruecond(rc) ? TREF_FALSE : TREF_TRUE; - break; - - case BC_LEN: - if (tref_isstr(rc)) - rc = emitir(IRTI(IR_FLOAD), rc, IRFL_STR_LEN); - else if (!LJ_52 && tref_istab(rc)) - rc = lj_ir_call(J, IRCALL_lj_tab_len, rc); - else - rc = rec_mm_len(J, rc, rcv); - break; - - /* -- Arithmetic ops ---------------------------------------------------- */ - - case BC_UNM: - if (tref_isnumber_str(rc)) { - rc = lj_opt_narrow_unm(J, rc, rcv); - } else { - ix.tab = rc; - copyTV(J->L, &ix.tabv, rcv); - rc = rec_mm_arith(J, &ix, MM_unm); - } - break; - - case BC_ADDNV: case BC_SUBNV: case BC_MULNV: case BC_DIVNV: case BC_MODNV: - /* Swap rb/rc and rbv/rcv. rav is temp. */ - ix.tab = rc; ix.key = rc = rb; rb = ix.tab; - copyTV(J->L, rav, rbv); - copyTV(J->L, rbv, rcv); - copyTV(J->L, rcv, rav); - if (op == BC_MODNV) - goto recmod; - /* fallthrough */ - case BC_ADDVN: case BC_SUBVN: case BC_MULVN: case BC_DIVVN: - case BC_ADDVV: case BC_SUBVV: case BC_MULVV: case BC_DIVVV: { - MMS mm = bcmode_mm(op); - if (tref_isnumber_str(rb) && tref_isnumber_str(rc)) - rc = lj_opt_narrow_arith(J, rb, rc, rbv, rcv, - (int)mm - (int)MM_add + (int)IR_ADD); - else - rc = rec_mm_arith(J, &ix, mm); - break; - } - - case BC_MODVN: case BC_MODVV: - recmod: - if (tref_isnumber_str(rb) && tref_isnumber_str(rc)) - rc = lj_opt_narrow_mod(J, rb, rc, rbv, rcv); - else - rc = rec_mm_arith(J, &ix, MM_mod); - break; - - case BC_POW: - if (tref_isnumber_str(rb) && tref_isnumber_str(rc)) - rc = lj_opt_narrow_pow(J, rb, rc, rbv, rcv); - else - rc = rec_mm_arith(J, &ix, MM_pow); - break; - - /* -- Miscellaneous ops ------------------------------------------------- */ - - case BC_CAT: - rc = rec_cat(J, rb, rc); - break; - - /* -- Constant and move ops --------------------------------------------- */ - - case BC_MOV: - /* Clear gap of method call to avoid resurrecting previous refs. */ - if (ra > J->maxslot) { -#if LJ_FR2 - memset(J->base + J->maxslot, 0, (ra - J->maxslot) * sizeof(TRef)); -#else - J->base[ra-1] = 0; -#endif - } - break; - case BC_KSTR: case BC_KNUM: case BC_KPRI: - break; - case BC_KSHORT: - rc = lj_ir_kint(J, (int32_t)(int16_t)rc); - break; - case BC_KNIL: - if (LJ_FR2 && ra > J->maxslot) - J->base[ra-1] = 0; - while (ra <= rc) - J->base[ra++] = TREF_NIL; - if (rc >= J->maxslot) J->maxslot = rc+1; - break; -#if LJ_HASFFI - case BC_KCDATA: - rc = lj_ir_kgc(J, proto_kgc(J->pt, ~(ptrdiff_t)rc), IRT_CDATA); - break; -#endif - - /* -- Upvalue and function ops ------------------------------------------ */ - - case BC_UGET: - rc = rec_upvalue(J, rc, 0); - break; - case BC_USETV: case BC_USETS: case BC_USETN: case BC_USETP: - rec_upvalue(J, ra, rc); - break; - - /* -- Table ops --------------------------------------------------------- */ - - case BC_GGET: case BC_GSET: - settabV(J->L, &ix.tabv, tabref(J->fn->l.env)); - ix.tab = emitir(IRT(IR_FLOAD, IRT_TAB), getcurrf(J), IRFL_FUNC_ENV); - ix.idxchain = LJ_MAX_IDXCHAIN; - rc = lj_record_idx(J, &ix); - break; - - case BC_TGETB: case BC_TSETB: - setintV(&ix.keyv, (int32_t)rc); - ix.key = lj_ir_kint(J, (int32_t)rc); - /* fallthrough */ - case BC_TGETV: case BC_TGETS: case BC_TSETV: case BC_TSETS: - ix.idxchain = LJ_MAX_IDXCHAIN; - rc = lj_record_idx(J, &ix); - break; - case BC_TGETR: case BC_TSETR: - ix.idxchain = 0; - rc = lj_record_idx(J, &ix); - break; - - case BC_TSETM: - rec_tsetm(J, ra, (BCReg)(J->L->top - J->L->base), (int32_t)rcv->u32.lo); - break; - - case BC_TNEW: - rc = rec_tnew(J, rc); - break; - case BC_TDUP: - rc = emitir(IRTG(IR_TDUP, IRT_TAB), - lj_ir_ktab(J, gco2tab(proto_kgc(J->pt, ~(ptrdiff_t)rc))), 0); -#ifdef LUAJIT_ENABLE_TABLE_BUMP - J->rbchash[(rc & (RBCHASH_SLOTS-1))].ref = tref_ref(rc); - setmref(J->rbchash[(rc & (RBCHASH_SLOTS-1))].pc, pc); - setgcref(J->rbchash[(rc & (RBCHASH_SLOTS-1))].pt, obj2gco(J->pt)); -#endif - break; - - /* -- Calls and vararg handling ----------------------------------------- */ - - case BC_ITERC: - J->base[ra] = getslot(J, ra-3); - J->base[ra+1+LJ_FR2] = getslot(J, ra-2); - J->base[ra+2+LJ_FR2] = getslot(J, ra-1); - { /* Do the actual copy now because lj_record_call needs the values. */ - TValue *b = &J->L->base[ra]; - copyTV(J->L, b, b-3); - copyTV(J->L, b+1+LJ_FR2, b-2); - copyTV(J->L, b+2+LJ_FR2, b-1); - } - lj_record_call(J, ra, (ptrdiff_t)rc-1); - break; - - /* L->top is set to L->base+ra+rc+NARGS-1+1. See lj_dispatch_ins(). */ - case BC_CALLM: - rc = (BCReg)(J->L->top - J->L->base) - ra - LJ_FR2; - /* fallthrough */ - case BC_CALL: - lj_record_call(J, ra, (ptrdiff_t)rc-1); - break; - - case BC_CALLMT: - rc = (BCReg)(J->L->top - J->L->base) - ra - LJ_FR2; - /* fallthrough */ - case BC_CALLT: - lj_record_tailcall(J, ra, (ptrdiff_t)rc-1); - break; - - case BC_VARG: - rec_varg(J, ra, (ptrdiff_t)rb-1); - break; - - /* -- Returns ----------------------------------------------------------- */ - - case BC_RETM: - /* L->top is set to L->base+ra+rc+NRESULTS-1, see lj_dispatch_ins(). */ - rc = (BCReg)(J->L->top - J->L->base) - ra + 1; - /* fallthrough */ - case BC_RET: case BC_RET0: case BC_RET1: -#if LJ_HASPROFILE - rec_profile_ret(J); -#endif - lj_record_ret(J, ra, (ptrdiff_t)rc-1); - break; - - /* -- Loops and branches ------------------------------------------------ */ - - case BC_FORI: - if (rec_for(J, pc, 0) != LOOPEV_LEAVE) - J->loopref = J->cur.nins; - break; - case BC_JFORI: - lua_assert(bc_op(pc[(ptrdiff_t)rc-BCBIAS_J]) == BC_JFORL); - if (rec_for(J, pc, 0) != LOOPEV_LEAVE) /* Link to existing loop. */ - lj_record_stop(J, LJ_TRLINK_ROOT, bc_d(pc[(ptrdiff_t)rc-BCBIAS_J])); - /* Continue tracing if the loop is not entered. */ - break; - - case BC_FORL: - rec_loop_interp(J, pc, rec_for(J, pc+((ptrdiff_t)rc-BCBIAS_J), 1)); - break; - case BC_ITERL: - rec_loop_interp(J, pc, rec_iterl(J, *pc)); - break; - case BC_LOOP: - rec_loop_interp(J, pc, rec_loop(J, ra)); - break; - - case BC_JFORL: - rec_loop_jit(J, rc, rec_for(J, pc+bc_j(traceref(J, rc)->startins), 1)); - break; - case BC_JITERL: - rec_loop_jit(J, rc, rec_iterl(J, traceref(J, rc)->startins)); - break; - case BC_JLOOP: - rec_loop_jit(J, rc, rec_loop(J, ra)); - break; - - case BC_IFORL: - case BC_IITERL: - case BC_ILOOP: - case BC_IFUNCF: - case BC_IFUNCV: - lj_trace_err(J, LJ_TRERR_BLACKL); - break; - - case BC_JMP: - if (ra < J->maxslot) - J->maxslot = ra; /* Shrink used slots. */ - break; - - /* -- Function headers -------------------------------------------------- */ - - case BC_FUNCF: - rec_func_lua(J); - break; - case BC_JFUNCF: - rec_func_jit(J, rc); - break; - - case BC_FUNCV: - rec_func_vararg(J); - rec_func_lua(J); - break; - case BC_JFUNCV: - lua_assert(0); /* Cannot happen. No hotcall counting for varag funcs. */ - break; - - case BC_FUNCC: - case BC_FUNCCW: - lj_ffrecord_func(J); - break; - - default: - if (op >= BC__MAX) { - lj_ffrecord_func(J); - break; - } - /* fallthrough */ - case BC_ITERN: - case BC_ISNEXT: - case BC_UCLO: - case BC_FNEW: - setintV(&J->errinfo, (int32_t)op); - lj_trace_err_info(J, LJ_TRERR_NYIBC); - break; - } - - /* rc == 0 if we have no result yet, e.g. pending __index metamethod call. */ - if (bcmode_a(op) == BCMdst && rc) { - J->base[ra] = rc; - if (ra >= J->maxslot) { -#if LJ_FR2 - if (ra > J->maxslot) J->base[ra-1] = 0; -#endif - J->maxslot = ra+1; - } - } - -#undef rav -#undef rbv -#undef rcv - - /* Limit the number of recorded IR instructions and constants. */ - if (J->cur.nins > REF_FIRST+(IRRef)J->param[JIT_P_maxrecord] || - J->cur.nk < REF_BIAS-(IRRef)J->param[JIT_P_maxirconst]) - lj_trace_err(J, LJ_TRERR_TRACEOV); -} - -/* -- Recording setup ----------------------------------------------------- */ - -/* Setup recording for a root trace started by a hot loop. */ -static const BCIns *rec_setup_root(jit_State *J) -{ - /* Determine the next PC and the bytecode range for the loop. */ - const BCIns *pcj, *pc = J->pc; - BCIns ins = *pc; - BCReg ra = bc_a(ins); - switch (bc_op(ins)) { - case BC_FORL: - J->bc_extent = (MSize)(-bc_j(ins))*sizeof(BCIns); - pc += 1+bc_j(ins); - J->bc_min = pc; - break; - case BC_ITERL: - lua_assert(bc_op(pc[-1]) == BC_ITERC); - J->maxslot = ra + bc_b(pc[-1]) - 1; - J->bc_extent = (MSize)(-bc_j(ins))*sizeof(BCIns); - pc += 1+bc_j(ins); - lua_assert(bc_op(pc[-1]) == BC_JMP); - J->bc_min = pc; - break; - case BC_LOOP: - /* Only check BC range for real loops, but not for "repeat until true". */ - pcj = pc + bc_j(ins); - ins = *pcj; - if (bc_op(ins) == BC_JMP && bc_j(ins) < 0) { - J->bc_min = pcj+1 + bc_j(ins); - J->bc_extent = (MSize)(-bc_j(ins))*sizeof(BCIns); - } - J->maxslot = ra; - pc++; - break; - case BC_RET: - case BC_RET0: - case BC_RET1: - /* No bytecode range check for down-recursive root traces. */ - J->maxslot = ra + bc_d(ins) - 1; - break; - case BC_FUNCF: - /* No bytecode range check for root traces started by a hot call. */ - J->maxslot = J->pt->numparams; - pc++; - break; - case BC_CALLM: - case BC_CALL: - case BC_ITERC: - /* No bytecode range check for stitched traces. */ - pc++; - break; - default: - lua_assert(0); - break; - } - return pc; -} - -/* Setup for recording a new trace. */ -void lj_record_setup(jit_State *J) -{ - uint32_t i; - - /* Initialize state related to current trace. */ - memset(J->slot, 0, sizeof(J->slot)); - memset(J->chain, 0, sizeof(J->chain)); -#ifdef LUAJIT_ENABLE_TABLE_BUMP - memset(J->rbchash, 0, sizeof(J->rbchash)); -#endif - memset(J->bpropcache, 0, sizeof(J->bpropcache)); - J->scev.idx = REF_NIL; - setmref(J->scev.pc, NULL); - - J->baseslot = 1+LJ_FR2; /* Invoking function is at base[-1-LJ_FR2]. */ - J->base = J->slot + J->baseslot; - J->maxslot = 0; - J->framedepth = 0; - J->retdepth = 0; - - J->instunroll = J->param[JIT_P_instunroll]; - J->loopunroll = J->param[JIT_P_loopunroll]; - J->tailcalled = 0; - J->loopref = 0; - - J->bc_min = NULL; /* Means no limit. */ - J->bc_extent = ~(MSize)0; - - /* Emit instructions for fixed references. Also triggers initial IR alloc. */ - emitir_raw(IRT(IR_BASE, IRT_PGC), J->parent, J->exitno); - for (i = 0; i <= 2; i++) { - IRIns *ir = IR(REF_NIL-i); - ir->i = 0; - ir->t.irt = (uint8_t)(IRT_NIL+i); - ir->o = IR_KPRI; - ir->prev = 0; - } - J->cur.nk = REF_TRUE; - - J->startpc = J->pc; - setmref(J->cur.startpc, J->pc); - if (J->parent) { /* Side trace. */ - GCtrace *T = traceref(J, J->parent); - TraceNo root = T->root ? T->root : J->parent; - J->cur.root = (uint16_t)root; - J->cur.startins = BCINS_AD(BC_JMP, 0, 0); - /* Check whether we could at least potentially form an extra loop. */ - if (J->exitno == 0 && T->snap[0].nent == 0) { - /* We can narrow a FORL for some side traces, too. */ - if (J->pc > proto_bc(J->pt) && bc_op(J->pc[-1]) == BC_JFORI && - bc_d(J->pc[bc_j(J->pc[-1])-1]) == root) { - lj_snap_add(J); - rec_for_loop(J, J->pc-1, &J->scev, 1); - goto sidecheck; - } - } else { - J->startpc = NULL; /* Prevent forming an extra loop. */ - } - lj_snap_replay(J, T); - sidecheck: - if (traceref(J, J->cur.root)->nchild >= J->param[JIT_P_maxside] || - T->snap[J->exitno].count >= J->param[JIT_P_hotexit] + - J->param[JIT_P_tryside]) { - lj_record_stop(J, LJ_TRLINK_INTERP, 0); - } - } else { /* Root trace. */ - J->cur.root = 0; - J->cur.startins = *J->pc; - J->pc = rec_setup_root(J); - /* Note: the loop instruction itself is recorded at the end and not - ** at the start! So snapshot #0 needs to point to the *next* instruction. - */ - lj_snap_add(J); - if (bc_op(J->cur.startins) == BC_FORL) - rec_for_loop(J, J->pc-1, &J->scev, 1); - else if (bc_op(J->cur.startins) == BC_ITERC) - J->startpc = NULL; - if (1 + J->pt->framesize >= LJ_MAX_JSLOTS) - lj_trace_err(J, LJ_TRERR_STACKOV); - } -#if LJ_HASPROFILE - J->prev_pt = NULL; - J->prev_line = -1; -#endif -#ifdef LUAJIT_ENABLE_CHECKHOOK - /* Regularly check for instruction/line hooks from compiled code and - ** exit to the interpreter if the hooks are set. - ** - ** This is a compile-time option and disabled by default, since the - ** hook checks may be quite expensive in tight loops. - ** - ** Note this is only useful if hooks are *not* set most of the time. - ** Use this only if you want to *asynchronously* interrupt the execution. - ** - ** You can set the instruction hook via lua_sethook() with a count of 1 - ** from a signal handler or another native thread. Please have a look - ** at the first few functions in luajit.c for an example (Ctrl-C handler). - */ - { - TRef tr = emitir(IRT(IR_XLOAD, IRT_U8), - lj_ir_kptr(J, &J2G(J)->hookmask), IRXLOAD_VOLATILE); - tr = emitir(IRTI(IR_BAND), tr, lj_ir_kint(J, (LUA_MASKLINE|LUA_MASKCOUNT))); - emitir(IRTGI(IR_EQ), tr, lj_ir_kint(J, 0)); - } -#endif -} - -#undef IR -#undef emitir_raw -#undef emitir - -#endif diff --git a/lib/LuaJIT/src/lj_record.h b/lib/LuaJIT/src/lj_record.h deleted file mode 100644 index 93d374d..0000000 --- a/lib/LuaJIT/src/lj_record.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -** Trace recorder (bytecode -> SSA IR). -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_RECORD_H -#define _LJ_RECORD_H - -#include "lj_obj.h" -#include "lj_jit.h" - -#if LJ_HASJIT -/* Context for recording an indexed load/store. */ -typedef struct RecordIndex { - TValue tabv; /* Runtime value of table (or indexed object). */ - TValue keyv; /* Runtime value of key. */ - TValue valv; /* Runtime value of stored value. */ - TValue mobjv; /* Runtime value of metamethod object. */ - GCtab *mtv; /* Runtime value of metatable object. */ - cTValue *oldv; /* Runtime value of previously stored value. */ - TRef tab; /* Table (or indexed object) reference. */ - TRef key; /* Key reference. */ - TRef val; /* Value reference for a store or 0 for a load. */ - TRef mt; /* Metatable reference. */ - TRef mobj; /* Metamethod object reference. */ - int idxchain; /* Index indirections left or 0 for raw lookup. */ -} RecordIndex; - -LJ_FUNC int lj_record_objcmp(jit_State *J, TRef a, TRef b, - cTValue *av, cTValue *bv); -LJ_FUNC void lj_record_stop(jit_State *J, TraceLink linktype, TraceNo lnk); -LJ_FUNC TRef lj_record_constify(jit_State *J, cTValue *o); - -LJ_FUNC void lj_record_call(jit_State *J, BCReg func, ptrdiff_t nargs); -LJ_FUNC void lj_record_tailcall(jit_State *J, BCReg func, ptrdiff_t nargs); -LJ_FUNC void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults); - -LJ_FUNC int lj_record_mm_lookup(jit_State *J, RecordIndex *ix, MMS mm); -LJ_FUNC TRef lj_record_idx(jit_State *J, RecordIndex *ix); - -LJ_FUNC void lj_record_ins(jit_State *J); -LJ_FUNC void lj_record_setup(jit_State *J); -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_snap.c b/lib/LuaJIT/src/lj_snap.c deleted file mode 100644 index ceaf2ca..0000000 --- a/lib/LuaJIT/src/lj_snap.c +++ /dev/null @@ -1,916 +0,0 @@ -/* -** Snapshot handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_snap_c -#define LUA_CORE - -#include "lj_obj.h" - -#if LJ_HASJIT - -#include "lj_gc.h" -#include "lj_tab.h" -#include "lj_state.h" -#include "lj_frame.h" -#include "lj_bc.h" -#include "lj_ir.h" -#include "lj_jit.h" -#include "lj_iropt.h" -#include "lj_trace.h" -#include "lj_snap.h" -#include "lj_target.h" -#if LJ_HASFFI -#include "lj_ctype.h" -#include "lj_cdata.h" -#endif - -/* Pass IR on to next optimization in chain (FOLD). */ -#define emitir(ot, a, b) (lj_ir_set(J, (ot), (a), (b)), lj_opt_fold(J)) - -/* Emit raw IR without passing through optimizations. */ -#define emitir_raw(ot, a, b) (lj_ir_set(J, (ot), (a), (b)), lj_ir_emit(J)) - -/* -- Snapshot buffer allocation ------------------------------------------ */ - -/* Grow snapshot buffer. */ -void lj_snap_grow_buf_(jit_State *J, MSize need) -{ - MSize maxsnap = (MSize)J->param[JIT_P_maxsnap]; - if (need > maxsnap) - lj_trace_err(J, LJ_TRERR_SNAPOV); - lj_mem_growvec(J->L, J->snapbuf, J->sizesnap, maxsnap, SnapShot); - J->cur.snap = J->snapbuf; -} - -/* Grow snapshot map buffer. */ -void lj_snap_grow_map_(jit_State *J, MSize need) -{ - if (need < 2*J->sizesnapmap) - need = 2*J->sizesnapmap; - else if (need < 64) - need = 64; - J->snapmapbuf = (SnapEntry *)lj_mem_realloc(J->L, J->snapmapbuf, - J->sizesnapmap*sizeof(SnapEntry), need*sizeof(SnapEntry)); - J->cur.snapmap = J->snapmapbuf; - J->sizesnapmap = need; -} - -/* -- Snapshot generation ------------------------------------------------- */ - -/* Add all modified slots to the snapshot. */ -static MSize snapshot_slots(jit_State *J, SnapEntry *map, BCReg nslots) -{ - IRRef retf = J->chain[IR_RETF]; /* Limits SLOAD restore elimination. */ - BCReg s; - MSize n = 0; - for (s = 0; s < nslots; s++) { - TRef tr = J->slot[s]; - IRRef ref = tref_ref(tr); -#if LJ_FR2 - if (s == 1) { /* Ignore slot 1 in LJ_FR2 mode, except if tailcalled. */ - if ((tr & TREF_FRAME)) - map[n++] = SNAP(1, SNAP_FRAME | SNAP_NORESTORE, REF_NIL); - continue; - } - if ((tr & (TREF_FRAME | TREF_CONT)) && !ref) { - cTValue *base = J->L->base - J->baseslot; - tr = J->slot[s] = (tr & 0xff0000) | lj_ir_k64(J, IR_KNUM, base[s].u64); - ref = tref_ref(tr); - } -#endif - if (ref) { - SnapEntry sn = SNAP_TR(s, tr); - IRIns *ir = &J->cur.ir[ref]; - if ((LJ_FR2 || !(sn & (SNAP_CONT|SNAP_FRAME))) && - ir->o == IR_SLOAD && ir->op1 == s && ref > retf) { - /* No need to snapshot unmodified non-inherited slots. */ - if (!(ir->op2 & IRSLOAD_INHERIT)) - continue; - /* No need to restore readonly slots and unmodified non-parent slots. */ - if (!(LJ_DUALNUM && (ir->op2 & IRSLOAD_CONVERT)) && - (ir->op2 & (IRSLOAD_READONLY|IRSLOAD_PARENT)) != IRSLOAD_PARENT) - sn |= SNAP_NORESTORE; - } - if (LJ_SOFTFP32 && irt_isnum(ir->t)) - sn |= SNAP_SOFTFPNUM; - map[n++] = sn; - } - } - return n; -} - -/* Add frame links at the end of the snapshot. */ -static MSize snapshot_framelinks(jit_State *J, SnapEntry *map, uint8_t *topslot) -{ - cTValue *frame = J->L->base - 1; - cTValue *lim = J->L->base - J->baseslot + LJ_FR2; - GCfunc *fn = frame_func(frame); - cTValue *ftop = isluafunc(fn) ? (frame+funcproto(fn)->framesize) : J->L->top; -#if LJ_FR2 - uint64_t pcbase = (u64ptr(J->pc) << 8) | (J->baseslot - 2); - lua_assert(2 <= J->baseslot && J->baseslot <= 257); - memcpy(map, &pcbase, sizeof(uint64_t)); -#else - MSize f = 0; - map[f++] = SNAP_MKPC(J->pc); /* The current PC is always the first entry. */ -#endif - while (frame > lim) { /* Backwards traversal of all frames above base. */ - if (frame_islua(frame)) { -#if !LJ_FR2 - map[f++] = SNAP_MKPC(frame_pc(frame)); -#endif - frame = frame_prevl(frame); - } else if (frame_iscont(frame)) { -#if !LJ_FR2 - map[f++] = SNAP_MKFTSZ(frame_ftsz(frame)); - map[f++] = SNAP_MKPC(frame_contpc(frame)); -#endif - frame = frame_prevd(frame); - } else { - lua_assert(!frame_isc(frame)); -#if !LJ_FR2 - map[f++] = SNAP_MKFTSZ(frame_ftsz(frame)); -#endif - frame = frame_prevd(frame); - continue; - } - if (frame + funcproto(frame_func(frame))->framesize > ftop) - ftop = frame + funcproto(frame_func(frame))->framesize; - } - *topslot = (uint8_t)(ftop - lim); -#if LJ_FR2 - lua_assert(sizeof(SnapEntry) * 2 == sizeof(uint64_t)); - return 2; -#else - lua_assert(f == (MSize)(1 + J->framedepth)); - return f; -#endif -} - -/* Take a snapshot of the current stack. */ -static void snapshot_stack(jit_State *J, SnapShot *snap, MSize nsnapmap) -{ - BCReg nslots = J->baseslot + J->maxslot; - MSize nent; - SnapEntry *p; - /* Conservative estimate. */ - lj_snap_grow_map(J, nsnapmap + nslots + (MSize)(LJ_FR2?2:J->framedepth+1)); - p = &J->cur.snapmap[nsnapmap]; - nent = snapshot_slots(J, p, nslots); - snap->nent = (uint8_t)nent; - nent += snapshot_framelinks(J, p + nent, &snap->topslot); - snap->mapofs = (uint32_t)nsnapmap; - snap->ref = (IRRef1)J->cur.nins; - snap->nslots = (uint8_t)nslots; - snap->count = 0; - J->cur.nsnapmap = (uint32_t)(nsnapmap + nent); -} - -/* Add or merge a snapshot. */ -void lj_snap_add(jit_State *J) -{ - MSize nsnap = J->cur.nsnap; - MSize nsnapmap = J->cur.nsnapmap; - /* Merge if no ins. inbetween or if requested and no guard inbetween. */ - if ((nsnap > 0 && J->cur.snap[nsnap-1].ref == J->cur.nins) || - (J->mergesnap && !irt_isguard(J->guardemit))) { - if (nsnap == 1) { /* But preserve snap #0 PC. */ - emitir_raw(IRT(IR_NOP, IRT_NIL), 0, 0); - goto nomerge; - } - nsnapmap = J->cur.snap[--nsnap].mapofs; - } else { - nomerge: - lj_snap_grow_buf(J, nsnap+1); - J->cur.nsnap = (uint16_t)(nsnap+1); - } - J->mergesnap = 0; - J->guardemit.irt = 0; - snapshot_stack(J, &J->cur.snap[nsnap], nsnapmap); -} - -/* -- Snapshot modification ----------------------------------------------- */ - -#define SNAP_USEDEF_SLOTS (LJ_MAX_JSLOTS+LJ_STACK_EXTRA) - -/* Find unused slots with reaching-definitions bytecode data-flow analysis. */ -static BCReg snap_usedef(jit_State *J, uint8_t *udf, - const BCIns *pc, BCReg maxslot) -{ - BCReg s; - GCobj *o; - - if (maxslot == 0) return 0; -#ifdef LUAJIT_USE_VALGRIND - /* Avoid errors for harmless reads beyond maxslot. */ - memset(udf, 1, SNAP_USEDEF_SLOTS); -#else - memset(udf, 1, maxslot); -#endif - - /* Treat open upvalues as used. */ - o = gcref(J->L->openupval); - while (o) { - if (uvval(gco2uv(o)) < J->L->base) break; - udf[uvval(gco2uv(o)) - J->L->base] = 0; - o = gcref(o->gch.nextgc); - } - -#define USE_SLOT(s) udf[(s)] &= ~1 -#define DEF_SLOT(s) udf[(s)] *= 3 - - /* Scan through following bytecode and check for uses/defs. */ - lua_assert(pc >= proto_bc(J->pt) && pc < proto_bc(J->pt) + J->pt->sizebc); - for (;;) { - BCIns ins = *pc++; - BCOp op = bc_op(ins); - switch (bcmode_b(op)) { - case BCMvar: USE_SLOT(bc_b(ins)); break; - default: break; - } - switch (bcmode_c(op)) { - case BCMvar: USE_SLOT(bc_c(ins)); break; - case BCMrbase: - lua_assert(op == BC_CAT); - for (s = bc_b(ins); s <= bc_c(ins); s++) USE_SLOT(s); - for (; s < maxslot; s++) DEF_SLOT(s); - break; - case BCMjump: - handle_jump: { - BCReg minslot = bc_a(ins); - if (op >= BC_FORI && op <= BC_JFORL) minslot += FORL_EXT; - else if (op >= BC_ITERL && op <= BC_JITERL) minslot += bc_b(pc[-2])-1; - else if (op == BC_UCLO) { pc += bc_j(ins); break; } - for (s = minslot; s < maxslot; s++) DEF_SLOT(s); - return minslot < maxslot ? minslot : maxslot; - } - case BCMlit: - if (op == BC_JFORL || op == BC_JITERL || op == BC_JLOOP) { - goto handle_jump; - } else if (bc_isret(op)) { - BCReg top = op == BC_RETM ? maxslot : (bc_a(ins) + bc_d(ins)-1); - for (s = 0; s < bc_a(ins); s++) DEF_SLOT(s); - for (; s < top; s++) USE_SLOT(s); - for (; s < maxslot; s++) DEF_SLOT(s); - return 0; - } - break; - case BCMfunc: return maxslot; /* NYI: will abort, anyway. */ - default: break; - } - switch (bcmode_a(op)) { - case BCMvar: USE_SLOT(bc_a(ins)); break; - case BCMdst: - if (!(op == BC_ISTC || op == BC_ISFC)) DEF_SLOT(bc_a(ins)); - break; - case BCMbase: - if (op >= BC_CALLM && op <= BC_VARG) { - BCReg top = (op == BC_CALLM || op == BC_CALLMT || bc_c(ins) == 0) ? - maxslot : (bc_a(ins) + bc_c(ins)+LJ_FR2); - if (LJ_FR2) DEF_SLOT(bc_a(ins)+1); - s = bc_a(ins) - ((op == BC_ITERC || op == BC_ITERN) ? 3 : 0); - for (; s < top; s++) USE_SLOT(s); - for (; s < maxslot; s++) DEF_SLOT(s); - if (op == BC_CALLT || op == BC_CALLMT) { - for (s = 0; s < bc_a(ins); s++) DEF_SLOT(s); - return 0; - } - } else if (op == BC_KNIL) { - for (s = bc_a(ins); s <= bc_d(ins); s++) DEF_SLOT(s); - } else if (op == BC_TSETM) { - for (s = bc_a(ins)-1; s < maxslot; s++) USE_SLOT(s); - } - break; - default: break; - } - lua_assert(pc >= proto_bc(J->pt) && pc < proto_bc(J->pt) + J->pt->sizebc); - } - -#undef USE_SLOT -#undef DEF_SLOT - - return 0; /* unreachable */ -} - -/* Purge dead slots before the next snapshot. */ -void lj_snap_purge(jit_State *J) -{ - uint8_t udf[SNAP_USEDEF_SLOTS]; - BCReg maxslot = J->maxslot; - BCReg s = snap_usedef(J, udf, J->pc, maxslot); - for (; s < maxslot; s++) - if (udf[s] != 0) - J->base[s] = 0; /* Purge dead slots. */ -} - -/* Shrink last snapshot. */ -void lj_snap_shrink(jit_State *J) -{ - SnapShot *snap = &J->cur.snap[J->cur.nsnap-1]; - SnapEntry *map = &J->cur.snapmap[snap->mapofs]; - MSize n, m, nlim, nent = snap->nent; - uint8_t udf[SNAP_USEDEF_SLOTS]; - BCReg maxslot = J->maxslot; - BCReg baseslot = J->baseslot; - BCReg minslot = snap_usedef(J, udf, snap_pc(&map[nent]), maxslot); - maxslot += baseslot; - minslot += baseslot; - snap->nslots = (uint8_t)maxslot; - for (n = m = 0; n < nent; n++) { /* Remove unused slots from snapshot. */ - BCReg s = snap_slot(map[n]); - if (s < minslot || (s < maxslot && udf[s-baseslot] == 0)) - map[m++] = map[n]; /* Only copy used slots. */ - } - snap->nent = (uint8_t)m; - nlim = J->cur.nsnapmap - snap->mapofs - 1; - while (n <= nlim) map[m++] = map[n++]; /* Move PC + frame links down. */ - J->cur.nsnapmap = (uint32_t)(snap->mapofs + m); /* Free up space in map. */ -} - -/* -- Snapshot access ----------------------------------------------------- */ - -/* Initialize a Bloom Filter with all renamed refs. -** There are very few renames (often none), so the filter has -** very few bits set. This makes it suitable for negative filtering. -*/ -static BloomFilter snap_renamefilter(GCtrace *T, SnapNo lim) -{ - BloomFilter rfilt = 0; - IRIns *ir; - for (ir = &T->ir[T->nins-1]; ir->o == IR_RENAME; ir--) - if (ir->op2 <= lim) - bloomset(rfilt, ir->op1); - return rfilt; -} - -/* Process matching renames to find the original RegSP. */ -static RegSP snap_renameref(GCtrace *T, SnapNo lim, IRRef ref, RegSP rs) -{ - IRIns *ir; - for (ir = &T->ir[T->nins-1]; ir->o == IR_RENAME; ir--) - if (ir->op1 == ref && ir->op2 <= lim) - rs = ir->prev; - return rs; -} - -/* Copy RegSP from parent snapshot to the parent links of the IR. */ -IRIns *lj_snap_regspmap(GCtrace *T, SnapNo snapno, IRIns *ir) -{ - SnapShot *snap = &T->snap[snapno]; - SnapEntry *map = &T->snapmap[snap->mapofs]; - BloomFilter rfilt = snap_renamefilter(T, snapno); - MSize n = 0; - IRRef ref = 0; - for ( ; ; ir++) { - uint32_t rs; - if (ir->o == IR_SLOAD) { - if (!(ir->op2 & IRSLOAD_PARENT)) break; - for ( ; ; n++) { - lua_assert(n < snap->nent); - if (snap_slot(map[n]) == ir->op1) { - ref = snap_ref(map[n++]); - break; - } - } - } else if (LJ_SOFTFP32 && ir->o == IR_HIOP) { - ref++; - } else if (ir->o == IR_PVAL) { - ref = ir->op1 + REF_BIAS; - } else { - break; - } - rs = T->ir[ref].prev; - if (bloomtest(rfilt, ref)) - rs = snap_renameref(T, snapno, ref, rs); - ir->prev = (uint16_t)rs; - lua_assert(regsp_used(rs)); - } - return ir; -} - -/* -- Snapshot replay ----------------------------------------------------- */ - -/* Replay constant from parent trace. */ -static TRef snap_replay_const(jit_State *J, IRIns *ir) -{ - /* Only have to deal with constants that can occur in stack slots. */ - switch ((IROp)ir->o) { - case IR_KPRI: return TREF_PRI(irt_type(ir->t)); - case IR_KINT: return lj_ir_kint(J, ir->i); - case IR_KGC: return lj_ir_kgc(J, ir_kgc(ir), irt_t(ir->t)); - case IR_KNUM: case IR_KINT64: - return lj_ir_k64(J, (IROp)ir->o, ir_k64(ir)->u64); - case IR_KPTR: return lj_ir_kptr(J, ir_kptr(ir)); /* Continuation. */ - default: lua_assert(0); return TREF_NIL; break; - } -} - -/* De-duplicate parent reference. */ -static TRef snap_dedup(jit_State *J, SnapEntry *map, MSize nmax, IRRef ref) -{ - MSize j; - for (j = 0; j < nmax; j++) - if (snap_ref(map[j]) == ref) - return J->slot[snap_slot(map[j])] & ~(SNAP_CONT|SNAP_FRAME); - return 0; -} - -/* Emit parent reference with de-duplication. */ -static TRef snap_pref(jit_State *J, GCtrace *T, SnapEntry *map, MSize nmax, - BloomFilter seen, IRRef ref) -{ - IRIns *ir = &T->ir[ref]; - TRef tr; - if (irref_isk(ref)) - tr = snap_replay_const(J, ir); - else if (!regsp_used(ir->prev)) - tr = 0; - else if (!bloomtest(seen, ref) || (tr = snap_dedup(J, map, nmax, ref)) == 0) - tr = emitir(IRT(IR_PVAL, irt_type(ir->t)), ref - REF_BIAS, 0); - return tr; -} - -/* Check whether a sunk store corresponds to an allocation. Slow path. */ -static int snap_sunk_store2(GCtrace *T, IRIns *ira, IRIns *irs) -{ - if (irs->o == IR_ASTORE || irs->o == IR_HSTORE || - irs->o == IR_FSTORE || irs->o == IR_XSTORE) { - IRIns *irk = &T->ir[irs->op1]; - if (irk->o == IR_AREF || irk->o == IR_HREFK) - irk = &T->ir[irk->op1]; - return (&T->ir[irk->op1] == ira); - } - return 0; -} - -/* Check whether a sunk store corresponds to an allocation. Fast path. */ -static LJ_AINLINE int snap_sunk_store(GCtrace *T, IRIns *ira, IRIns *irs) -{ - if (irs->s != 255) - return (ira + irs->s == irs); /* Fast check. */ - return snap_sunk_store2(T, ira, irs); -} - -/* Replay snapshot state to setup side trace. */ -void lj_snap_replay(jit_State *J, GCtrace *T) -{ - SnapShot *snap = &T->snap[J->exitno]; - SnapEntry *map = &T->snapmap[snap->mapofs]; - MSize n, nent = snap->nent; - BloomFilter seen = 0; - int pass23 = 0; - J->framedepth = 0; - /* Emit IR for slots inherited from parent snapshot. */ - for (n = 0; n < nent; n++) { - SnapEntry sn = map[n]; - BCReg s = snap_slot(sn); - IRRef ref = snap_ref(sn); - IRIns *ir = &T->ir[ref]; - TRef tr; - /* The bloom filter avoids O(nent^2) overhead for de-duping slots. */ - if (bloomtest(seen, ref) && (tr = snap_dedup(J, map, n, ref)) != 0) - goto setslot; - bloomset(seen, ref); - if (irref_isk(ref)) { - /* See special treatment of LJ_FR2 slot 1 in snapshot_slots() above. */ - if (LJ_FR2 && (sn == SNAP(1, SNAP_FRAME | SNAP_NORESTORE, REF_NIL))) - tr = 0; - else - tr = snap_replay_const(J, ir); - } else if (!regsp_used(ir->prev)) { - pass23 = 1; - lua_assert(s != 0); - tr = s; - } else { - IRType t = irt_type(ir->t); - uint32_t mode = IRSLOAD_INHERIT|IRSLOAD_PARENT; - if (LJ_SOFTFP32 && (sn & SNAP_SOFTFPNUM)) t = IRT_NUM; - if (ir->o == IR_SLOAD) mode |= (ir->op2 & IRSLOAD_READONLY); - tr = emitir_raw(IRT(IR_SLOAD, t), s, mode); - } - setslot: - J->slot[s] = tr | (sn&(SNAP_CONT|SNAP_FRAME)); /* Same as TREF_* flags. */ - J->framedepth += ((sn & (SNAP_CONT|SNAP_FRAME)) && (s != LJ_FR2)); - if ((sn & SNAP_FRAME)) - J->baseslot = s+1; - } - if (pass23) { - IRIns *irlast = &T->ir[snap->ref]; - pass23 = 0; - /* Emit dependent PVALs. */ - for (n = 0; n < nent; n++) { - SnapEntry sn = map[n]; - IRRef refp = snap_ref(sn); - IRIns *ir = &T->ir[refp]; - if (regsp_reg(ir->r) == RID_SUNK) { - if (J->slot[snap_slot(sn)] != snap_slot(sn)) continue; - pass23 = 1; - lua_assert(ir->o == IR_TNEW || ir->o == IR_TDUP || - ir->o == IR_CNEW || ir->o == IR_CNEWI); - if (ir->op1 >= T->nk) snap_pref(J, T, map, nent, seen, ir->op1); - if (ir->op2 >= T->nk) snap_pref(J, T, map, nent, seen, ir->op2); - if (LJ_HASFFI && ir->o == IR_CNEWI) { - if (LJ_32 && refp+1 < T->nins && (ir+1)->o == IR_HIOP) - snap_pref(J, T, map, nent, seen, (ir+1)->op2); - } else { - IRIns *irs; - for (irs = ir+1; irs < irlast; irs++) - if (irs->r == RID_SINK && snap_sunk_store(T, ir, irs)) { - if (snap_pref(J, T, map, nent, seen, irs->op2) == 0) - snap_pref(J, T, map, nent, seen, T->ir[irs->op2].op1); - else if ((LJ_SOFTFP32 || (LJ_32 && LJ_HASFFI)) && - irs+1 < irlast && (irs+1)->o == IR_HIOP) - snap_pref(J, T, map, nent, seen, (irs+1)->op2); - } - } - } else if (!irref_isk(refp) && !regsp_used(ir->prev)) { - lua_assert(ir->o == IR_CONV && ir->op2 == IRCONV_NUM_INT); - J->slot[snap_slot(sn)] = snap_pref(J, T, map, nent, seen, ir->op1); - } - } - /* Replay sunk instructions. */ - for (n = 0; pass23 && n < nent; n++) { - SnapEntry sn = map[n]; - IRRef refp = snap_ref(sn); - IRIns *ir = &T->ir[refp]; - if (regsp_reg(ir->r) == RID_SUNK) { - TRef op1, op2; - if (J->slot[snap_slot(sn)] != snap_slot(sn)) { /* De-dup allocs. */ - J->slot[snap_slot(sn)] = J->slot[J->slot[snap_slot(sn)]]; - continue; - } - op1 = ir->op1; - if (op1 >= T->nk) op1 = snap_pref(J, T, map, nent, seen, op1); - op2 = ir->op2; - if (op2 >= T->nk) op2 = snap_pref(J, T, map, nent, seen, op2); - if (LJ_HASFFI && ir->o == IR_CNEWI) { - if (LJ_32 && refp+1 < T->nins && (ir+1)->o == IR_HIOP) { - lj_needsplit(J); /* Emit joining HIOP. */ - op2 = emitir_raw(IRT(IR_HIOP, IRT_I64), op2, - snap_pref(J, T, map, nent, seen, (ir+1)->op2)); - } - J->slot[snap_slot(sn)] = emitir(ir->ot & ~(IRT_MARK|IRT_ISPHI), op1, op2); - } else { - IRIns *irs; - TRef tr = emitir(ir->ot, op1, op2); - J->slot[snap_slot(sn)] = tr; - for (irs = ir+1; irs < irlast; irs++) - if (irs->r == RID_SINK && snap_sunk_store(T, ir, irs)) { - IRIns *irr = &T->ir[irs->op1]; - TRef val, key = irr->op2, tmp = tr; - if (irr->o != IR_FREF) { - IRIns *irk = &T->ir[key]; - if (irr->o == IR_HREFK) - key = lj_ir_kslot(J, snap_replay_const(J, &T->ir[irk->op1]), - irk->op2); - else - key = snap_replay_const(J, irk); - if (irr->o == IR_HREFK || irr->o == IR_AREF) { - IRIns *irf = &T->ir[irr->op1]; - tmp = emitir(irf->ot, tmp, irf->op2); - } - } - tmp = emitir(irr->ot, tmp, key); - val = snap_pref(J, T, map, nent, seen, irs->op2); - if (val == 0) { - IRIns *irc = &T->ir[irs->op2]; - lua_assert(irc->o == IR_CONV && irc->op2 == IRCONV_NUM_INT); - val = snap_pref(J, T, map, nent, seen, irc->op1); - val = emitir(IRTN(IR_CONV), val, IRCONV_NUM_INT); - } else if ((LJ_SOFTFP32 || (LJ_32 && LJ_HASFFI)) && - irs+1 < irlast && (irs+1)->o == IR_HIOP) { - IRType t = IRT_I64; - if (LJ_SOFTFP32 && irt_type((irs+1)->t) == IRT_SOFTFP) - t = IRT_NUM; - lj_needsplit(J); - if (irref_isk(irs->op2) && irref_isk((irs+1)->op2)) { - uint64_t k = (uint32_t)T->ir[irs->op2].i + - ((uint64_t)T->ir[(irs+1)->op2].i << 32); - val = lj_ir_k64(J, t == IRT_I64 ? IR_KINT64 : IR_KNUM, k); - } else { - val = emitir_raw(IRT(IR_HIOP, t), val, - snap_pref(J, T, map, nent, seen, (irs+1)->op2)); - } - tmp = emitir(IRT(irs->o, t), tmp, val); - continue; - } - tmp = emitir(irs->ot, tmp, val); - } else if (LJ_HASFFI && irs->o == IR_XBAR && ir->o == IR_CNEW) { - emitir(IRT(IR_XBAR, IRT_NIL), 0, 0); - } - } - } - } - } - J->base = J->slot + J->baseslot; - J->maxslot = snap->nslots - J->baseslot; - lj_snap_add(J); - if (pass23) /* Need explicit GC step _after_ initial snapshot. */ - emitir_raw(IRTG(IR_GCSTEP, IRT_NIL), 0, 0); -} - -/* -- Snapshot restore ---------------------------------------------------- */ - -static void snap_unsink(jit_State *J, GCtrace *T, ExitState *ex, - SnapNo snapno, BloomFilter rfilt, - IRIns *ir, TValue *o); - -/* Restore a value from the trace exit state. */ -static void snap_restoreval(jit_State *J, GCtrace *T, ExitState *ex, - SnapNo snapno, BloomFilter rfilt, - IRRef ref, TValue *o) -{ - IRIns *ir = &T->ir[ref]; - IRType1 t = ir->t; - RegSP rs = ir->prev; - if (irref_isk(ref)) { /* Restore constant slot. */ - lj_ir_kvalue(J->L, o, ir); - return; - } - if (LJ_UNLIKELY(bloomtest(rfilt, ref))) - rs = snap_renameref(T, snapno, ref, rs); - if (ra_hasspill(regsp_spill(rs))) { /* Restore from spill slot. */ - int32_t *sps = &ex->spill[regsp_spill(rs)]; - if (irt_isinteger(t)) { - setintV(o, *sps); -#if !LJ_SOFTFP32 - } else if (irt_isnum(t)) { - o->u64 = *(uint64_t *)sps; -#endif -#if LJ_64 && !LJ_GC64 - } else if (irt_islightud(t)) { - /* 64 bit lightuserdata which may escape already has the tag bits. */ - o->u64 = *(uint64_t *)sps; -#endif - } else { - lua_assert(!irt_ispri(t)); /* PRI refs never have a spill slot. */ - setgcV(J->L, o, (GCobj *)(uintptr_t)*(GCSize *)sps, irt_toitype(t)); - } - } else { /* Restore from register. */ - Reg r = regsp_reg(rs); - if (ra_noreg(r)) { - lua_assert(ir->o == IR_CONV && ir->op2 == IRCONV_NUM_INT); - snap_restoreval(J, T, ex, snapno, rfilt, ir->op1, o); - if (LJ_DUALNUM) setnumV(o, (lua_Number)intV(o)); - return; - } else if (irt_isinteger(t)) { - setintV(o, (int32_t)ex->gpr[r-RID_MIN_GPR]); -#if !LJ_SOFTFP - } else if (irt_isnum(t)) { - setnumV(o, ex->fpr[r-RID_MIN_FPR]); -#elif LJ_64 /* && LJ_SOFTFP */ - } else if (irt_isnum(t)) { - o->u64 = ex->gpr[r-RID_MIN_GPR]; -#endif -#if LJ_64 && !LJ_GC64 - } else if (irt_is64(t)) { - /* 64 bit values that already have the tag bits. */ - o->u64 = ex->gpr[r-RID_MIN_GPR]; -#endif - } else if (irt_ispri(t)) { - setpriV(o, irt_toitype(t)); - } else { - setgcV(J->L, o, (GCobj *)ex->gpr[r-RID_MIN_GPR], irt_toitype(t)); - } - } -} - -#if LJ_HASFFI -/* Restore raw data from the trace exit state. */ -static void snap_restoredata(GCtrace *T, ExitState *ex, - SnapNo snapno, BloomFilter rfilt, - IRRef ref, void *dst, CTSize sz) -{ - IRIns *ir = &T->ir[ref]; - RegSP rs = ir->prev; - int32_t *src; - uint64_t tmp; - if (irref_isk(ref)) { - if (ir->o == IR_KNUM || ir->o == IR_KINT64) { - src = (int32_t *)&ir[1]; - } else if (sz == 8) { - tmp = (uint64_t)(uint32_t)ir->i; - src = (int32_t *)&tmp; - } else { - src = &ir->i; - } - } else { - if (LJ_UNLIKELY(bloomtest(rfilt, ref))) - rs = snap_renameref(T, snapno, ref, rs); - if (ra_hasspill(regsp_spill(rs))) { - src = &ex->spill[regsp_spill(rs)]; - if (sz == 8 && !irt_is64(ir->t)) { - tmp = (uint64_t)(uint32_t)*src; - src = (int32_t *)&tmp; - } - } else { - Reg r = regsp_reg(rs); - if (ra_noreg(r)) { - /* Note: this assumes CNEWI is never used for SOFTFP split numbers. */ - lua_assert(sz == 8 && ir->o == IR_CONV && ir->op2 == IRCONV_NUM_INT); - snap_restoredata(T, ex, snapno, rfilt, ir->op1, dst, 4); - *(lua_Number *)dst = (lua_Number)*(int32_t *)dst; - return; - } - src = (int32_t *)&ex->gpr[r-RID_MIN_GPR]; -#if !LJ_SOFTFP - if (r >= RID_MAX_GPR) { - src = (int32_t *)&ex->fpr[r-RID_MIN_FPR]; -#if LJ_TARGET_PPC - if (sz == 4) { /* PPC FPRs are always doubles. */ - *(float *)dst = (float)*(double *)src; - return; - } -#else - if (LJ_BE && sz == 4) src++; -#endif - } else -#endif - if (LJ_64 && LJ_BE && sz == 4) src++; - } - } - lua_assert(sz == 1 || sz == 2 || sz == 4 || sz == 8); - if (sz == 4) *(int32_t *)dst = *src; - else if (sz == 8) *(int64_t *)dst = *(int64_t *)src; - else if (sz == 1) *(int8_t *)dst = (int8_t)*src; - else *(int16_t *)dst = (int16_t)*src; -} -#endif - -/* Unsink allocation from the trace exit state. Unsink sunk stores. */ -static void snap_unsink(jit_State *J, GCtrace *T, ExitState *ex, - SnapNo snapno, BloomFilter rfilt, - IRIns *ir, TValue *o) -{ - lua_assert(ir->o == IR_TNEW || ir->o == IR_TDUP || - ir->o == IR_CNEW || ir->o == IR_CNEWI); -#if LJ_HASFFI - if (ir->o == IR_CNEW || ir->o == IR_CNEWI) { - CTState *cts = ctype_cts(J->L); - CTypeID id = (CTypeID)T->ir[ir->op1].i; - CTSize sz; - CTInfo info = lj_ctype_info(cts, id, &sz); - GCcdata *cd = lj_cdata_newx(cts, id, sz, info); - setcdataV(J->L, o, cd); - if (ir->o == IR_CNEWI) { - uint8_t *p = (uint8_t *)cdataptr(cd); - lua_assert(sz == 4 || sz == 8); - if (LJ_32 && sz == 8 && ir+1 < T->ir + T->nins && (ir+1)->o == IR_HIOP) { - snap_restoredata(T, ex, snapno, rfilt, (ir+1)->op2, LJ_LE?p+4:p, 4); - if (LJ_BE) p += 4; - sz = 4; - } - snap_restoredata(T, ex, snapno, rfilt, ir->op2, p, sz); - } else { - IRIns *irs, *irlast = &T->ir[T->snap[snapno].ref]; - for (irs = ir+1; irs < irlast; irs++) - if (irs->r == RID_SINK && snap_sunk_store(T, ir, irs)) { - IRIns *iro = &T->ir[T->ir[irs->op1].op2]; - uint8_t *p = (uint8_t *)cd; - CTSize szs; - lua_assert(irs->o == IR_XSTORE && T->ir[irs->op1].o == IR_ADD); - lua_assert(iro->o == IR_KINT || iro->o == IR_KINT64); - if (irt_is64(irs->t)) szs = 8; - else if (irt_isi8(irs->t) || irt_isu8(irs->t)) szs = 1; - else if (irt_isi16(irs->t) || irt_isu16(irs->t)) szs = 2; - else szs = 4; - if (LJ_64 && iro->o == IR_KINT64) - p += (int64_t)ir_k64(iro)->u64; - else - p += iro->i; - lua_assert(p >= (uint8_t *)cdataptr(cd) && - p + szs <= (uint8_t *)cdataptr(cd) + sz); - if (LJ_32 && irs+1 < T->ir + T->nins && (irs+1)->o == IR_HIOP) { - lua_assert(szs == 4); - snap_restoredata(T, ex, snapno, rfilt, (irs+1)->op2, LJ_LE?p+4:p,4); - if (LJ_BE) p += 4; - } - snap_restoredata(T, ex, snapno, rfilt, irs->op2, p, szs); - } - } - } else -#endif - { - IRIns *irs, *irlast; - GCtab *t = ir->o == IR_TNEW ? lj_tab_new(J->L, ir->op1, ir->op2) : - lj_tab_dup(J->L, ir_ktab(&T->ir[ir->op1])); - settabV(J->L, o, t); - irlast = &T->ir[T->snap[snapno].ref]; - for (irs = ir+1; irs < irlast; irs++) - if (irs->r == RID_SINK && snap_sunk_store(T, ir, irs)) { - IRIns *irk = &T->ir[irs->op1]; - TValue tmp, *val; - lua_assert(irs->o == IR_ASTORE || irs->o == IR_HSTORE || - irs->o == IR_FSTORE); - if (irk->o == IR_FREF) { - lua_assert(irk->op2 == IRFL_TAB_META); - snap_restoreval(J, T, ex, snapno, rfilt, irs->op2, &tmp); - /* NOBARRIER: The table is new (marked white). */ - setgcref(t->metatable, obj2gco(tabV(&tmp))); - } else { - irk = &T->ir[irk->op2]; - if (irk->o == IR_KSLOT) irk = &T->ir[irk->op1]; - lj_ir_kvalue(J->L, &tmp, irk); - val = lj_tab_set(J->L, t, &tmp); - /* NOBARRIER: The table is new (marked white). */ - snap_restoreval(J, T, ex, snapno, rfilt, irs->op2, val); - if (LJ_SOFTFP32 && irs+1 < T->ir + T->nins && (irs+1)->o == IR_HIOP) { - snap_restoreval(J, T, ex, snapno, rfilt, (irs+1)->op2, &tmp); - val->u32.hi = tmp.u32.lo; - } - } - } - } -} - -/* Restore interpreter state from exit state with the help of a snapshot. */ -const BCIns *lj_snap_restore(jit_State *J, void *exptr) -{ - ExitState *ex = (ExitState *)exptr; - SnapNo snapno = J->exitno; /* For now, snapno == exitno. */ - GCtrace *T = traceref(J, J->parent); - SnapShot *snap = &T->snap[snapno]; - MSize n, nent = snap->nent; - SnapEntry *map = &T->snapmap[snap->mapofs]; -#if !LJ_FR2 || defined(LUA_USE_ASSERT) - SnapEntry *flinks = &T->snapmap[snap_nextofs(T, snap)-1-LJ_FR2]; -#endif -#if !LJ_FR2 - ptrdiff_t ftsz0; -#endif - TValue *frame; - BloomFilter rfilt = snap_renamefilter(T, snapno); - const BCIns *pc = snap_pc(&map[nent]); - lua_State *L = J->L; - - /* Set interpreter PC to the next PC to get correct error messages. */ - setcframe_pc(cframe_raw(L->cframe), pc+1); - - /* Make sure the stack is big enough for the slots from the snapshot. */ - if (LJ_UNLIKELY(L->base + snap->topslot >= tvref(L->maxstack))) { - L->top = curr_topL(L); - lj_state_growstack(L, snap->topslot - curr_proto(L)->framesize); - } - - /* Fill stack slots with data from the registers and spill slots. */ - frame = L->base-1-LJ_FR2; -#if !LJ_FR2 - ftsz0 = frame_ftsz(frame); /* Preserve link to previous frame in slot #0. */ -#endif - for (n = 0; n < nent; n++) { - SnapEntry sn = map[n]; - if (!(sn & SNAP_NORESTORE)) { - TValue *o = &frame[snap_slot(sn)]; - IRRef ref = snap_ref(sn); - IRIns *ir = &T->ir[ref]; - if (ir->r == RID_SUNK) { - MSize j; - for (j = 0; j < n; j++) - if (snap_ref(map[j]) == ref) { /* De-duplicate sunk allocations. */ - copyTV(L, o, &frame[snap_slot(map[j])]); - goto dupslot; - } - snap_unsink(J, T, ex, snapno, rfilt, ir, o); - dupslot: - continue; - } - snap_restoreval(J, T, ex, snapno, rfilt, ref, o); - if (LJ_SOFTFP32 && (sn & SNAP_SOFTFPNUM) && tvisint(o)) { - TValue tmp; - snap_restoreval(J, T, ex, snapno, rfilt, ref+1, &tmp); - o->u32.hi = tmp.u32.lo; -#if !LJ_FR2 - } else if ((sn & (SNAP_CONT|SNAP_FRAME))) { - /* Overwrite tag with frame link. */ - setframe_ftsz(o, snap_slot(sn) != 0 ? (int32_t)*flinks-- : ftsz0); - L->base = o+1; -#endif - } - } - } -#if LJ_FR2 - L->base += (map[nent+LJ_BE] & 0xff); -#endif - lua_assert(map + nent == flinks); - - /* Compute current stack top. */ - switch (bc_op(*pc)) { - default: - if (bc_op(*pc) < BC_FUNCF) { - L->top = curr_topL(L); - break; - } - /* fallthrough */ - case BC_CALLM: case BC_CALLMT: case BC_RETM: case BC_TSETM: - L->top = frame + snap->nslots; - break; - } - return pc; -} - -#undef emitir_raw -#undef emitir - -#endif diff --git a/lib/LuaJIT/src/lj_snap.h b/lib/LuaJIT/src/lj_snap.h deleted file mode 100644 index 2c9ae3d..0000000 --- a/lib/LuaJIT/src/lj_snap.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -** Snapshot handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_SNAP_H -#define _LJ_SNAP_H - -#include "lj_obj.h" -#include "lj_jit.h" - -#if LJ_HASJIT -LJ_FUNC void lj_snap_add(jit_State *J); -LJ_FUNC void lj_snap_purge(jit_State *J); -LJ_FUNC void lj_snap_shrink(jit_State *J); -LJ_FUNC IRIns *lj_snap_regspmap(GCtrace *T, SnapNo snapno, IRIns *ir); -LJ_FUNC void lj_snap_replay(jit_State *J, GCtrace *T); -LJ_FUNC const BCIns *lj_snap_restore(jit_State *J, void *exptr); -LJ_FUNC void lj_snap_grow_buf_(jit_State *J, MSize need); -LJ_FUNC void lj_snap_grow_map_(jit_State *J, MSize need); - -static LJ_AINLINE void lj_snap_grow_buf(jit_State *J, MSize need) -{ - if (LJ_UNLIKELY(need > J->sizesnap)) lj_snap_grow_buf_(J, need); -} - -static LJ_AINLINE void lj_snap_grow_map(jit_State *J, MSize need) -{ - if (LJ_UNLIKELY(need > J->sizesnapmap)) lj_snap_grow_map_(J, need); -} - -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_state.c b/lib/LuaJIT/src/lj_state.c deleted file mode 100644 index 632dd07..0000000 --- a/lib/LuaJIT/src/lj_state.c +++ /dev/null @@ -1,300 +0,0 @@ -/* -** State and stack handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Portions taken verbatim or adapted from the Lua interpreter. -** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h -*/ - -#define lj_state_c -#define LUA_CORE - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_buf.h" -#include "lj_str.h" -#include "lj_tab.h" -#include "lj_func.h" -#include "lj_meta.h" -#include "lj_state.h" -#include "lj_frame.h" -#if LJ_HASFFI -#include "lj_ctype.h" -#endif -#include "lj_trace.h" -#include "lj_dispatch.h" -#include "lj_vm.h" -#include "lj_lex.h" -#include "lj_alloc.h" -#include "luajit.h" - -/* -- Stack handling ------------------------------------------------------ */ - -/* Stack sizes. */ -#define LJ_STACK_MIN LUA_MINSTACK /* Min. stack size. */ -#define LJ_STACK_MAX LUAI_MAXSTACK /* Max. stack size. */ -#define LJ_STACK_START (2*LJ_STACK_MIN) /* Starting stack size. */ -#define LJ_STACK_MAXEX (LJ_STACK_MAX + 1 + LJ_STACK_EXTRA) - -/* Explanation of LJ_STACK_EXTRA: -** -** Calls to metamethods store their arguments beyond the current top -** without checking for the stack limit. This avoids stack resizes which -** would invalidate passed TValue pointers. The stack check is performed -** later by the function header. This can safely resize the stack or raise -** an error. Thus we need some extra slots beyond the current stack limit. -** -** Most metamethods need 4 slots above top (cont, mobj, arg1, arg2) plus -** one extra slot if mobj is not a function. Only lj_meta_tset needs 5 -** slots above top, but then mobj is always a function. So we can get by -** with 5 extra slots. -** LJ_FR2: We need 2 more slots for the frame PC and the continuation PC. -*/ - -/* Resize stack slots and adjust pointers in state. */ -static void resizestack(lua_State *L, MSize n) -{ - TValue *st, *oldst = tvref(L->stack); - ptrdiff_t delta; - MSize oldsize = L->stacksize; - MSize realsize = n + 1 + LJ_STACK_EXTRA; - GCobj *up; - lua_assert((MSize)(tvref(L->maxstack)-oldst)==L->stacksize-LJ_STACK_EXTRA-1); - st = (TValue *)lj_mem_realloc(L, tvref(L->stack), - (MSize)(oldsize*sizeof(TValue)), - (MSize)(realsize*sizeof(TValue))); - setmref(L->stack, st); - delta = (char *)st - (char *)oldst; - setmref(L->maxstack, st + n); - while (oldsize < realsize) /* Clear new slots. */ - setnilV(st + oldsize++); - L->stacksize = realsize; - if ((size_t)(mref(G(L)->jit_base, char) - (char *)oldst) < oldsize) - setmref(G(L)->jit_base, mref(G(L)->jit_base, char) + delta); - L->base = (TValue *)((char *)L->base + delta); - L->top = (TValue *)((char *)L->top + delta); - for (up = gcref(L->openupval); up != NULL; up = gcnext(up)) - setmref(gco2uv(up)->v, (TValue *)((char *)uvval(gco2uv(up)) + delta)); -} - -/* Relimit stack after error, in case the limit was overdrawn. */ -void lj_state_relimitstack(lua_State *L) -{ - if (L->stacksize > LJ_STACK_MAXEX && L->top-tvref(L->stack) < LJ_STACK_MAX-1) - resizestack(L, LJ_STACK_MAX); -} - -/* Try to shrink the stack (called from GC). */ -void lj_state_shrinkstack(lua_State *L, MSize used) -{ - if (L->stacksize > LJ_STACK_MAXEX) - return; /* Avoid stack shrinking while handling stack overflow. */ - if (4*used < L->stacksize && - 2*(LJ_STACK_START+LJ_STACK_EXTRA) < L->stacksize && - /* Don't shrink stack of live trace. */ - (tvref(G(L)->jit_base) == NULL || obj2gco(L) != gcref(G(L)->cur_L))) - resizestack(L, L->stacksize >> 1); -} - -/* Try to grow stack. */ -void LJ_FASTCALL lj_state_growstack(lua_State *L, MSize need) -{ - MSize n; - if (L->stacksize > LJ_STACK_MAXEX) /* Overflow while handling overflow? */ - lj_err_throw(L, LUA_ERRERR); - n = L->stacksize + need; - if (n > LJ_STACK_MAX) { - n += 2*LUA_MINSTACK; - } else if (n < 2*L->stacksize) { - n = 2*L->stacksize; - if (n >= LJ_STACK_MAX) - n = LJ_STACK_MAX; - } - resizestack(L, n); - if (L->stacksize > LJ_STACK_MAXEX) - lj_err_msg(L, LJ_ERR_STKOV); -} - -void LJ_FASTCALL lj_state_growstack1(lua_State *L) -{ - lj_state_growstack(L, 1); -} - -/* Allocate basic stack for new state. */ -static void stack_init(lua_State *L1, lua_State *L) -{ - TValue *stend, *st = lj_mem_newvec(L, LJ_STACK_START+LJ_STACK_EXTRA, TValue); - setmref(L1->stack, st); - L1->stacksize = LJ_STACK_START + LJ_STACK_EXTRA; - stend = st + L1->stacksize; - setmref(L1->maxstack, stend - LJ_STACK_EXTRA - 1); - setthreadV(L1, st++, L1); /* Needed for curr_funcisL() on empty stack. */ - if (LJ_FR2) setnilV(st++); - L1->base = L1->top = st; - while (st < stend) /* Clear new slots. */ - setnilV(st++); -} - -/* -- State handling ------------------------------------------------------ */ - -/* Open parts that may cause memory-allocation errors. */ -static TValue *cpluaopen(lua_State *L, lua_CFunction dummy, void *ud) -{ - global_State *g = G(L); - UNUSED(dummy); - UNUSED(ud); - stack_init(L, L); - /* NOBARRIER: State initialization, all objects are white. */ - setgcref(L->env, obj2gco(lj_tab_new(L, 0, LJ_MIN_GLOBAL))); - settabV(L, registry(L), lj_tab_new(L, 0, LJ_MIN_REGISTRY)); - lj_str_resize(L, LJ_MIN_STRTAB-1); - lj_meta_init(L); - lj_lex_init(L); - fixstring(lj_err_str(L, LJ_ERR_ERRMEM)); /* Preallocate memory error msg. */ - g->gc.threshold = 4*g->gc.total; - lj_trace_initstate(g); - return NULL; -} - -static void close_state(lua_State *L) -{ - global_State *g = G(L); - lj_func_closeuv(L, tvref(L->stack)); - lj_gc_freeall(g); - lua_assert(gcref(g->gc.root) == obj2gco(L)); - lua_assert(g->strnum == 0); - lj_trace_freestate(g); -#if LJ_HASFFI - lj_ctype_freestate(g); -#endif - lj_mem_freevec(g, g->strhash, g->strmask+1, GCRef); - lj_buf_free(g, &g->tmpbuf); - lj_mem_freevec(g, tvref(L->stack), L->stacksize, TValue); - lua_assert(g->gc.total == sizeof(GG_State)); -#ifndef LUAJIT_USE_SYSMALLOC - if (g->allocf == lj_alloc_f) - lj_alloc_destroy(g->allocd); - else -#endif - g->allocf(g->allocd, G2GG(g), sizeof(GG_State), 0); -} - -#if LJ_64 && !LJ_GC64 && !(defined(LUAJIT_USE_VALGRIND) && defined(LUAJIT_USE_SYSMALLOC)) -lua_State *lj_state_newstate(lua_Alloc f, void *ud) -#else -LUA_API lua_State *lua_newstate(lua_Alloc f, void *ud) -#endif -{ - GG_State *GG = (GG_State *)f(ud, NULL, 0, sizeof(GG_State)); - lua_State *L = &GG->L; - global_State *g = &GG->g; - if (GG == NULL || !checkptrGC(GG)) return NULL; - memset(GG, 0, sizeof(GG_State)); - L->gct = ~LJ_TTHREAD; - L->marked = LJ_GC_WHITE0 | LJ_GC_FIXED | LJ_GC_SFIXED; /* Prevent free. */ - L->dummy_ffid = FF_C; - setmref(L->glref, g); - g->gc.currentwhite = LJ_GC_WHITE0 | LJ_GC_FIXED; - g->strempty.marked = LJ_GC_WHITE0; - g->strempty.gct = ~LJ_TSTR; - g->allocf = f; - g->allocd = ud; - setgcref(g->mainthref, obj2gco(L)); - setgcref(g->uvhead.prev, obj2gco(&g->uvhead)); - setgcref(g->uvhead.next, obj2gco(&g->uvhead)); - g->strmask = ~(MSize)0; - setnilV(registry(L)); - setnilV(&g->nilnode.val); - setnilV(&g->nilnode.key); -#if !LJ_GC64 - setmref(g->nilnode.freetop, &g->nilnode); -#endif - lj_buf_init(NULL, &g->tmpbuf); - g->gc.state = GCSpause; - setgcref(g->gc.root, obj2gco(L)); - setmref(g->gc.sweep, &g->gc.root); - g->gc.total = sizeof(GG_State); - g->gc.pause = LUAI_GCPAUSE; - g->gc.stepmul = LUAI_GCMUL; - lj_dispatch_init((GG_State *)L); - L->status = LUA_ERRERR+1; /* Avoid touching the stack upon memory error. */ - if (lj_vm_cpcall(L, NULL, NULL, cpluaopen) != 0) { - /* Memory allocation error: free partial state. */ - close_state(L); - return NULL; - } - L->status = LUA_OK; - return L; -} - -static TValue *cpfinalize(lua_State *L, lua_CFunction dummy, void *ud) -{ - UNUSED(dummy); - UNUSED(ud); - lj_gc_finalize_cdata(L); - lj_gc_finalize_udata(L); - /* Frame pop omitted. */ - return NULL; -} - -LUA_API void lua_close(lua_State *L) -{ - global_State *g = G(L); - int i; - L = mainthread(g); /* Only the main thread can be closed. */ -#if LJ_HASPROFILE - luaJIT_profile_stop(L); -#endif - setgcrefnull(g->cur_L); - lj_func_closeuv(L, tvref(L->stack)); - lj_gc_separateudata(g, 1); /* Separate udata which have GC metamethods. */ -#if LJ_HASJIT - G2J(g)->flags &= ~JIT_F_ON; - G2J(g)->state = LJ_TRACE_IDLE; - lj_dispatch_update(g); -#endif - for (i = 0;;) { - hook_enter(g); - L->status = LUA_OK; - L->base = L->top = tvref(L->stack) + 1 + LJ_FR2; - L->cframe = NULL; - if (lj_vm_cpcall(L, NULL, NULL, cpfinalize) == LUA_OK) { - if (++i >= 10) break; - lj_gc_separateudata(g, 1); /* Separate udata again. */ - if (gcref(g->gc.mmudata) == NULL) /* Until nothing is left to do. */ - break; - } - } - close_state(L); -} - -lua_State *lj_state_new(lua_State *L) -{ - lua_State *L1 = lj_mem_newobj(L, lua_State); - L1->gct = ~LJ_TTHREAD; - L1->dummy_ffid = FF_C; - L1->status = LUA_OK; - L1->stacksize = 0; - setmref(L1->stack, NULL); - L1->cframe = NULL; - /* NOBARRIER: The lua_State is new (marked white). */ - setgcrefnull(L1->openupval); - setmrefr(L1->glref, L->glref); - setgcrefr(L1->env, L->env); - stack_init(L1, L); /* init stack */ - lua_assert(iswhite(obj2gco(L1))); - return L1; -} - -void LJ_FASTCALL lj_state_free(global_State *g, lua_State *L) -{ - lua_assert(L != mainthread(g)); - if (obj2gco(L) == gcref(g->cur_L)) - setgcrefnull(g->cur_L); - lj_func_closeuv(L, tvref(L->stack)); - lua_assert(gcref(L->openupval) == NULL); - lj_mem_freevec(g, tvref(L->stack), L->stacksize, TValue); - lj_mem_freet(g, L); -} - diff --git a/lib/LuaJIT/src/lj_state.h b/lib/LuaJIT/src/lj_state.h deleted file mode 100644 index 02a0eaf..0000000 --- a/lib/LuaJIT/src/lj_state.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -** State and stack handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_STATE_H -#define _LJ_STATE_H - -#include "lj_obj.h" - -#define incr_top(L) \ - (++L->top >= tvref(L->maxstack) && (lj_state_growstack1(L), 0)) - -#define savestack(L, p) ((char *)(p) - mref(L->stack, char)) -#define restorestack(L, n) ((TValue *)(mref(L->stack, char) + (n))) - -LJ_FUNC void lj_state_relimitstack(lua_State *L); -LJ_FUNC void lj_state_shrinkstack(lua_State *L, MSize used); -LJ_FUNCA void LJ_FASTCALL lj_state_growstack(lua_State *L, MSize need); -LJ_FUNC void LJ_FASTCALL lj_state_growstack1(lua_State *L); - -static LJ_AINLINE void lj_state_checkstack(lua_State *L, MSize need) -{ - if ((mref(L->maxstack, char) - (char *)L->top) <= - (ptrdiff_t)need*(ptrdiff_t)sizeof(TValue)) - lj_state_growstack(L, need); -} - -LJ_FUNC lua_State *lj_state_new(lua_State *L); -LJ_FUNC void LJ_FASTCALL lj_state_free(global_State *g, lua_State *L); -#if LJ_64 && !LJ_GC64 && !(defined(LUAJIT_USE_VALGRIND) && defined(LUAJIT_USE_SYSMALLOC)) -LJ_FUNC lua_State *lj_state_newstate(lua_Alloc f, void *ud); -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_str.c b/lib/LuaJIT/src/lj_str.c deleted file mode 100644 index 264dedc..0000000 --- a/lib/LuaJIT/src/lj_str.c +++ /dev/null @@ -1,197 +0,0 @@ -/* -** String handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_str_c -#define LUA_CORE - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_str.h" -#include "lj_char.h" - -/* -- String helpers ------------------------------------------------------ */ - -/* Ordered compare of strings. Assumes string data is 4-byte aligned. */ -int32_t LJ_FASTCALL lj_str_cmp(GCstr *a, GCstr *b) -{ - MSize i, n = a->len > b->len ? b->len : a->len; - for (i = 0; i < n; i += 4) { - /* Note: innocuous access up to end of string + 3. */ - uint32_t va = *(const uint32_t *)(strdata(a)+i); - uint32_t vb = *(const uint32_t *)(strdata(b)+i); - if (va != vb) { -#if LJ_LE - va = lj_bswap(va); vb = lj_bswap(vb); -#endif - i -= n; - if ((int32_t)i >= -3) { - va >>= 32+(i<<3); vb >>= 32+(i<<3); - if (va == vb) break; - } - return va < vb ? -1 : 1; - } - } - return (int32_t)(a->len - b->len); -} - -/* Fast string data comparison. Caveat: unaligned access to 1st string! */ -static LJ_AINLINE int str_fastcmp(const char *a, const char *b, MSize len) -{ - MSize i = 0; - lua_assert(len > 0); - lua_assert((((uintptr_t)a+len-1) & (LJ_PAGESIZE-1)) <= LJ_PAGESIZE-4); - do { /* Note: innocuous access up to end of string + 3. */ - uint32_t v = lj_getu32(a+i) ^ *(const uint32_t *)(b+i); - if (v) { - i -= len; -#if LJ_LE - return (int32_t)i >= -3 ? (v << (32+(i<<3))) : 1; -#else - return (int32_t)i >= -3 ? (v >> (32+(i<<3))) : 1; -#endif - } - i += 4; - } while (i < len); - return 0; -} - -/* Find fixed string p inside string s. */ -const char *lj_str_find(const char *s, const char *p, MSize slen, MSize plen) -{ - if (plen <= slen) { - if (plen == 0) { - return s; - } else { - int c = *(const uint8_t *)p++; - plen--; slen -= plen; - while (slen) { - const char *q = (const char *)memchr(s, c, slen); - if (!q) break; - if (memcmp(q+1, p, plen) == 0) return q; - q++; slen -= (MSize)(q-s); s = q; - } - } - } - return NULL; -} - -/* Check whether a string has a pattern matching character. */ -int lj_str_haspattern(GCstr *s) -{ - const char *p = strdata(s), *q = p + s->len; - while (p < q) { - int c = *(const uint8_t *)p++; - if (lj_char_ispunct(c) && strchr("^$*+?.([%-", c)) - return 1; /* Found a pattern matching char. */ - } - return 0; /* No pattern matching chars found. */ -} - -/* -- String interning ---------------------------------------------------- */ - -/* Resize the string hash table (grow and shrink). */ -void lj_str_resize(lua_State *L, MSize newmask) -{ - global_State *g = G(L); - GCRef *newhash; - MSize i; - if (g->gc.state == GCSsweepstring || newmask >= LJ_MAX_STRTAB-1) - return; /* No resizing during GC traversal or if already too big. */ - newhash = lj_mem_newvec(L, newmask+1, GCRef); - memset(newhash, 0, (newmask+1)*sizeof(GCRef)); - for (i = g->strmask; i != ~(MSize)0; i--) { /* Rehash old table. */ - GCobj *p = gcref(g->strhash[i]); - while (p) { /* Follow each hash chain and reinsert all strings. */ - MSize h = gco2str(p)->hash & newmask; - GCobj *next = gcnext(p); - /* NOBARRIER: The string table is a GC root. */ - setgcrefr(p->gch.nextgc, newhash[h]); - setgcref(newhash[h], p); - p = next; - } - } - lj_mem_freevec(g, g->strhash, g->strmask+1, GCRef); - g->strmask = newmask; - g->strhash = newhash; -} - -/* Intern a string and return string object. */ -GCstr *lj_str_new(lua_State *L, const char *str, size_t lenx) -{ - global_State *g; - GCstr *s; - GCobj *o; - MSize len = (MSize)lenx; - MSize a, b, h = len; - if (lenx >= LJ_MAX_STR) - lj_err_msg(L, LJ_ERR_STROV); - g = G(L); - /* Compute string hash. Constants taken from lookup3 hash by Bob Jenkins. */ - if (len >= 4) { /* Caveat: unaligned access! */ - a = lj_getu32(str); - h ^= lj_getu32(str+len-4); - b = lj_getu32(str+(len>>1)-2); - h ^= b; h -= lj_rol(b, 14); - b += lj_getu32(str+(len>>2)-1); - } else if (len > 0) { - a = *(const uint8_t *)str; - h ^= *(const uint8_t *)(str+len-1); - b = *(const uint8_t *)(str+(len>>1)); - h ^= b; h -= lj_rol(b, 14); - } else { - return &g->strempty; - } - a ^= h; a -= lj_rol(h, 11); - b ^= a; b -= lj_rol(a, 25); - h ^= b; h -= lj_rol(b, 16); - /* Check if the string has already been interned. */ - o = gcref(g->strhash[h & g->strmask]); - if (LJ_LIKELY((((uintptr_t)str+len-1) & (LJ_PAGESIZE-1)) <= LJ_PAGESIZE-4)) { - while (o != NULL) { - GCstr *sx = gco2str(o); - if (sx->len == len && str_fastcmp(str, strdata(sx), len) == 0) { - /* Resurrect if dead. Can only happen with fixstring() (keywords). */ - if (isdead(g, o)) flipwhite(o); - return sx; /* Return existing string. */ - } - o = gcnext(o); - } - } else { /* Slow path: end of string is too close to a page boundary. */ - while (o != NULL) { - GCstr *sx = gco2str(o); - if (sx->len == len && memcmp(str, strdata(sx), len) == 0) { - /* Resurrect if dead. Can only happen with fixstring() (keywords). */ - if (isdead(g, o)) flipwhite(o); - return sx; /* Return existing string. */ - } - o = gcnext(o); - } - } - /* Nope, create a new string. */ - s = lj_mem_newt(L, sizeof(GCstr)+len+1, GCstr); - newwhite(g, s); - s->gct = ~LJ_TSTR; - s->len = len; - s->hash = h; - s->reserved = 0; - memcpy(strdatawr(s), str, len); - strdatawr(s)[len] = '\0'; /* Zero-terminate string. */ - /* Add it to string hash table. */ - h &= g->strmask; - s->nextgc = g->strhash[h]; - /* NOBARRIER: The string table is a GC root. */ - setgcref(g->strhash[h], obj2gco(s)); - if (g->strnum++ > g->strmask) /* Allow a 100% load factor. */ - lj_str_resize(L, (g->strmask<<1)+1); /* Grow string table. */ - return s; /* Return newly interned string. */ -} - -void LJ_FASTCALL lj_str_free(global_State *g, GCstr *s) -{ - g->strnum--; - lj_mem_free(g, s, sizestring(s)); -} - diff --git a/lib/LuaJIT/src/lj_str.h b/lib/LuaJIT/src/lj_str.h deleted file mode 100644 index 85c1e40..0000000 --- a/lib/LuaJIT/src/lj_str.h +++ /dev/null @@ -1,27 +0,0 @@ -/* -** String handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_STR_H -#define _LJ_STR_H - -#include - -#include "lj_obj.h" - -/* String helpers. */ -LJ_FUNC int32_t LJ_FASTCALL lj_str_cmp(GCstr *a, GCstr *b); -LJ_FUNC const char *lj_str_find(const char *s, const char *f, - MSize slen, MSize flen); -LJ_FUNC int lj_str_haspattern(GCstr *s); - -/* String interning. */ -LJ_FUNC void lj_str_resize(lua_State *L, MSize newmask); -LJ_FUNCA GCstr *lj_str_new(lua_State *L, const char *str, size_t len); -LJ_FUNC void LJ_FASTCALL lj_str_free(global_State *g, GCstr *s); - -#define lj_str_newz(L, s) (lj_str_new(L, s, strlen(s))) -#define lj_str_newlit(L, s) (lj_str_new(L, "" s, sizeof(s)-1)) - -#endif diff --git a/lib/LuaJIT/src/lj_strfmt.c b/lib/LuaJIT/src/lj_strfmt.c deleted file mode 100644 index d7893ce..0000000 --- a/lib/LuaJIT/src/lj_strfmt.c +++ /dev/null @@ -1,472 +0,0 @@ -/* -** String formatting. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#include - -#define lj_strfmt_c -#define LUA_CORE - -#include "lj_obj.h" -#include "lj_buf.h" -#include "lj_str.h" -#include "lj_state.h" -#include "lj_char.h" -#include "lj_strfmt.h" - -/* -- Format parser ------------------------------------------------------- */ - -static const uint8_t strfmt_map[('x'-'A')+1] = { - STRFMT_A,0,0,0,STRFMT_E,STRFMT_F,STRFMT_G,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,STRFMT_X,0,0, - 0,0,0,0,0,0, - STRFMT_A,0,STRFMT_C,STRFMT_D,STRFMT_E,STRFMT_F,STRFMT_G,0,STRFMT_I,0,0,0,0, - 0,STRFMT_O,STRFMT_P,STRFMT_Q,0,STRFMT_S,0,STRFMT_U,0,0,STRFMT_X -}; - -SFormat LJ_FASTCALL lj_strfmt_parse(FormatState *fs) -{ - const uint8_t *p = fs->p, *e = fs->e; - fs->str = (const char *)p; - for (; p < e; p++) { - if (*p == '%') { /* Escape char? */ - if (p[1] == '%') { /* '%%'? */ - fs->p = ++p+1; - goto retlit; - } else { - SFormat sf = 0; - uint32_t c; - if (p != (const uint8_t *)fs->str) - break; - for (p++; (uint32_t)*p - ' ' <= (uint32_t)('0' - ' '); p++) { - /* Parse flags. */ - if (*p == '-') sf |= STRFMT_F_LEFT; - else if (*p == '+') sf |= STRFMT_F_PLUS; - else if (*p == '0') sf |= STRFMT_F_ZERO; - else if (*p == ' ') sf |= STRFMT_F_SPACE; - else if (*p == '#') sf |= STRFMT_F_ALT; - else break; - } - if ((uint32_t)*p - '0' < 10) { /* Parse width. */ - uint32_t width = (uint32_t)*p++ - '0'; - if ((uint32_t)*p - '0' < 10) - width = (uint32_t)*p++ - '0' + width*10; - sf |= (width << STRFMT_SH_WIDTH); - } - if (*p == '.') { /* Parse precision. */ - uint32_t prec = 0; - p++; - if ((uint32_t)*p - '0' < 10) { - prec = (uint32_t)*p++ - '0'; - if ((uint32_t)*p - '0' < 10) - prec = (uint32_t)*p++ - '0' + prec*10; - } - sf |= ((prec+1) << STRFMT_SH_PREC); - } - /* Parse conversion. */ - c = (uint32_t)*p - 'A'; - if (LJ_LIKELY(c <= (uint32_t)('x' - 'A'))) { - uint32_t sx = strfmt_map[c]; - if (sx) { - fs->p = p+1; - return (sf | sx | ((c & 0x20) ? 0 : STRFMT_F_UPPER)); - } - } - /* Return error location. */ - if (*p >= 32) p++; - fs->len = (MSize)(p - (const uint8_t *)fs->str); - fs->p = fs->e; - return STRFMT_ERR; - } - } - } - fs->p = p; -retlit: - fs->len = (MSize)(p - (const uint8_t *)fs->str); - return fs->len ? STRFMT_LIT : STRFMT_EOF; -} - -/* -- Raw conversions ----------------------------------------------------- */ - -#define WINT_R(x, sh, sc) \ - { uint32_t d = (x*(((1<>sh; x -= d*sc; *p++ = (char)('0'+d); } - -/* Write integer to buffer. */ -char * LJ_FASTCALL lj_strfmt_wint(char *p, int32_t k) -{ - uint32_t u = (uint32_t)k; - if (k < 0) { u = (uint32_t)-k; *p++ = '-'; } - if (u < 10000) { - if (u < 10) goto dig1; - if (u < 100) goto dig2; - if (u < 1000) goto dig3; - } else { - uint32_t v = u / 10000; u -= v * 10000; - if (v < 10000) { - if (v < 10) goto dig5; - if (v < 100) goto dig6; - if (v < 1000) goto dig7; - } else { - uint32_t w = v / 10000; v -= w * 10000; - if (w >= 10) WINT_R(w, 10, 10) - *p++ = (char)('0'+w); - } - WINT_R(v, 23, 1000) - dig7: WINT_R(v, 12, 100) - dig6: WINT_R(v, 10, 10) - dig5: *p++ = (char)('0'+v); - } - WINT_R(u, 23, 1000) - dig3: WINT_R(u, 12, 100) - dig2: WINT_R(u, 10, 10) - dig1: *p++ = (char)('0'+u); - return p; -} -#undef WINT_R - -/* Write pointer to buffer. */ -char * LJ_FASTCALL lj_strfmt_wptr(char *p, const void *v) -{ - ptrdiff_t x = (ptrdiff_t)v; - MSize i, n = STRFMT_MAXBUF_PTR; - if (x == 0) { - *p++ = 'N'; *p++ = 'U'; *p++ = 'L'; *p++ = 'L'; - return p; - } -#if LJ_64 - /* Shorten output for 64 bit pointers. */ - n = 2+2*4+((x >> 32) ? 2+2*(lj_fls((uint32_t)(x >> 32))>>3) : 0); -#endif - p[0] = '0'; - p[1] = 'x'; - for (i = n-1; i >= 2; i--, x >>= 4) - p[i] = "0123456789abcdef"[(x & 15)]; - return p+n; -} - -/* Write ULEB128 to buffer. */ -char * LJ_FASTCALL lj_strfmt_wuleb128(char *p, uint32_t v) -{ - for (; v >= 0x80; v >>= 7) - *p++ = (char)((v & 0x7f) | 0x80); - *p++ = (char)v; - return p; -} - -/* Return string or write number to tmp buffer and return pointer to start. */ -const char *lj_strfmt_wstrnum(lua_State *L, cTValue *o, MSize *lenp) -{ - SBuf *sb; - if (tvisstr(o)) { - *lenp = strV(o)->len; - return strVdata(o); - } else if (tvisint(o)) { - sb = lj_strfmt_putint(lj_buf_tmp_(L), intV(o)); - } else if (tvisnum(o)) { - sb = lj_strfmt_putfnum(lj_buf_tmp_(L), STRFMT_G14, o->n); - } else { - return NULL; - } - *lenp = sbuflen(sb); - return sbufB(sb); -} - -/* -- Unformatted conversions to buffer ----------------------------------- */ - -/* Add integer to buffer. */ -SBuf * LJ_FASTCALL lj_strfmt_putint(SBuf *sb, int32_t k) -{ - setsbufP(sb, lj_strfmt_wint(lj_buf_more(sb, STRFMT_MAXBUF_INT), k)); - return sb; -} - -#if LJ_HASJIT -/* Add number to buffer. */ -SBuf * LJ_FASTCALL lj_strfmt_putnum(SBuf *sb, cTValue *o) -{ - return lj_strfmt_putfnum(sb, STRFMT_G14, o->n); -} -#endif - -SBuf * LJ_FASTCALL lj_strfmt_putptr(SBuf *sb, const void *v) -{ - setsbufP(sb, lj_strfmt_wptr(lj_buf_more(sb, STRFMT_MAXBUF_PTR), v)); - return sb; -} - -/* Add quoted string to buffer. */ -SBuf * LJ_FASTCALL lj_strfmt_putquoted(SBuf *sb, GCstr *str) -{ - const char *s = strdata(str); - MSize len = str->len; - lj_buf_putb(sb, '"'); - while (len--) { - uint32_t c = (uint32_t)(uint8_t)*s++; - char *p = lj_buf_more(sb, 4); - if (c == '"' || c == '\\' || c == '\n') { - *p++ = '\\'; - } else if (lj_char_iscntrl(c)) { /* This can only be 0-31 or 127. */ - uint32_t d; - *p++ = '\\'; - if (c >= 100 || lj_char_isdigit((uint8_t)*s)) { - *p++ = (char)('0'+(c >= 100)); if (c >= 100) c -= 100; - goto tens; - } else if (c >= 10) { - tens: - d = (c * 205) >> 11; c -= d * 10; *p++ = (char)('0'+d); - } - c += '0'; - } - *p++ = (char)c; - setsbufP(sb, p); - } - lj_buf_putb(sb, '"'); - return sb; -} - -/* -- Formatted conversions to buffer ------------------------------------- */ - -/* Add formatted char to buffer. */ -SBuf *lj_strfmt_putfchar(SBuf *sb, SFormat sf, int32_t c) -{ - MSize width = STRFMT_WIDTH(sf); - char *p = lj_buf_more(sb, width > 1 ? width : 1); - if ((sf & STRFMT_F_LEFT)) *p++ = (char)c; - while (width-- > 1) *p++ = ' '; - if (!(sf & STRFMT_F_LEFT)) *p++ = (char)c; - setsbufP(sb, p); - return sb; -} - -/* Add formatted string to buffer. */ -SBuf *lj_strfmt_putfstr(SBuf *sb, SFormat sf, GCstr *str) -{ - MSize len = str->len <= STRFMT_PREC(sf) ? str->len : STRFMT_PREC(sf); - MSize width = STRFMT_WIDTH(sf); - char *p = lj_buf_more(sb, width > len ? width : len); - if ((sf & STRFMT_F_LEFT)) p = lj_buf_wmem(p, strdata(str), len); - while (width-- > len) *p++ = ' '; - if (!(sf & STRFMT_F_LEFT)) p = lj_buf_wmem(p, strdata(str), len); - setsbufP(sb, p); - return sb; -} - -/* Add formatted signed/unsigned integer to buffer. */ -SBuf *lj_strfmt_putfxint(SBuf *sb, SFormat sf, uint64_t k) -{ - char buf[STRFMT_MAXBUF_XINT], *q = buf + sizeof(buf), *p; -#ifdef LUA_USE_ASSERT - char *ps; -#endif - MSize prefix = 0, len, prec, pprec, width, need; - - /* Figure out signed prefixes. */ - if (STRFMT_TYPE(sf) == STRFMT_INT) { - if ((int64_t)k < 0) { - k = (uint64_t)-(int64_t)k; - prefix = 256 + '-'; - } else if ((sf & STRFMT_F_PLUS)) { - prefix = 256 + '+'; - } else if ((sf & STRFMT_F_SPACE)) { - prefix = 256 + ' '; - } - } - - /* Convert number and store to fixed-size buffer in reverse order. */ - prec = STRFMT_PREC(sf); - if ((int32_t)prec >= 0) sf &= ~STRFMT_F_ZERO; - if (k == 0) { /* Special-case zero argument. */ - if (prec != 0 || - (sf & (STRFMT_T_OCT|STRFMT_F_ALT)) == (STRFMT_T_OCT|STRFMT_F_ALT)) - *--q = '0'; - } else if (!(sf & (STRFMT_T_HEX|STRFMT_T_OCT))) { /* Decimal. */ - uint32_t k2; - while ((k >> 32)) { *--q = (char)('0' + k % 10); k /= 10; } - k2 = (uint32_t)k; - do { *--q = (char)('0' + k2 % 10); k2 /= 10; } while (k2); - } else if ((sf & STRFMT_T_HEX)) { /* Hex. */ - const char *hexdig = (sf & STRFMT_F_UPPER) ? "0123456789ABCDEF" : - "0123456789abcdef"; - do { *--q = hexdig[(k & 15)]; k >>= 4; } while (k); - if ((sf & STRFMT_F_ALT)) prefix = 512 + ((sf & STRFMT_F_UPPER) ? 'X' : 'x'); - } else { /* Octal. */ - do { *--q = (char)('0' + (uint32_t)(k & 7)); k >>= 3; } while (k); - if ((sf & STRFMT_F_ALT)) *--q = '0'; - } - - /* Calculate sizes. */ - len = (MSize)(buf + sizeof(buf) - q); - if ((int32_t)len >= (int32_t)prec) prec = len; - width = STRFMT_WIDTH(sf); - pprec = prec + (prefix >> 8); - need = width > pprec ? width : pprec; - p = lj_buf_more(sb, need); -#ifdef LUA_USE_ASSERT - ps = p; -#endif - - /* Format number with leading/trailing whitespace and zeros. */ - if ((sf & (STRFMT_F_LEFT|STRFMT_F_ZERO)) == 0) - while (width-- > pprec) *p++ = ' '; - if (prefix) { - if ((char)prefix >= 'X') *p++ = '0'; - *p++ = (char)prefix; - } - if ((sf & (STRFMT_F_LEFT|STRFMT_F_ZERO)) == STRFMT_F_ZERO) - while (width-- > pprec) *p++ = '0'; - while (prec-- > len) *p++ = '0'; - while (q < buf + sizeof(buf)) *p++ = *q++; /* Add number itself. */ - if ((sf & STRFMT_F_LEFT)) - while (width-- > pprec) *p++ = ' '; - - lua_assert(need == (MSize)(p - ps)); - setsbufP(sb, p); - return sb; -} - -/* Add number formatted as signed integer to buffer. */ -SBuf *lj_strfmt_putfnum_int(SBuf *sb, SFormat sf, lua_Number n) -{ - int64_t k = (int64_t)n; - if (checki32(k) && sf == STRFMT_INT) - return lj_strfmt_putint(sb, (int32_t)k); /* Shortcut for plain %d. */ - else - return lj_strfmt_putfxint(sb, sf, (uint64_t)k); -} - -/* Add number formatted as unsigned integer to buffer. */ -SBuf *lj_strfmt_putfnum_uint(SBuf *sb, SFormat sf, lua_Number n) -{ - int64_t k; - if (n >= 9223372036854775808.0) - k = (int64_t)(n - 18446744073709551616.0); - else - k = (int64_t)n; - return lj_strfmt_putfxint(sb, sf, (uint64_t)k); -} - -/* -- Conversions to strings ---------------------------------------------- */ - -/* Convert integer to string. */ -GCstr * LJ_FASTCALL lj_strfmt_int(lua_State *L, int32_t k) -{ - char buf[STRFMT_MAXBUF_INT]; - MSize len = (MSize)(lj_strfmt_wint(buf, k) - buf); - return lj_str_new(L, buf, len); -} - -/* Convert integer or number to string. */ -GCstr * LJ_FASTCALL lj_strfmt_number(lua_State *L, cTValue *o) -{ - return tvisint(o) ? lj_strfmt_int(L, intV(o)) : lj_strfmt_num(L, o); -} - -#if LJ_HASJIT -/* Convert char value to string. */ -GCstr * LJ_FASTCALL lj_strfmt_char(lua_State *L, int c) -{ - char buf[1]; - buf[0] = c; - return lj_str_new(L, buf, 1); -} -#endif - -/* Raw conversion of object to string. */ -GCstr * LJ_FASTCALL lj_strfmt_obj(lua_State *L, cTValue *o) -{ - if (tvisstr(o)) { - return strV(o); - } else if (tvisnumber(o)) { - return lj_strfmt_number(L, o); - } else if (tvisnil(o)) { - return lj_str_newlit(L, "nil"); - } else if (tvisfalse(o)) { - return lj_str_newlit(L, "false"); - } else if (tvistrue(o)) { - return lj_str_newlit(L, "true"); - } else { - char buf[8+2+2+16], *p = buf; - p = lj_buf_wmem(p, lj_typename(o), (MSize)strlen(lj_typename(o))); - *p++ = ':'; *p++ = ' '; - if (tvisfunc(o) && isffunc(funcV(o))) { - p = lj_buf_wmem(p, "builtin#", 8); - p = lj_strfmt_wint(p, funcV(o)->c.ffid); - } else { - p = lj_strfmt_wptr(p, lj_obj_ptr(o)); - } - return lj_str_new(L, buf, (size_t)(p - buf)); - } -} - -/* -- Internal string formatting ------------------------------------------ */ - -/* -** These functions are only used for lua_pushfstring(), lua_pushvfstring() -** and for internal string formatting (e.g. error messages). Caveat: unlike -** string.format(), only a limited subset of formats and flags are supported! -** -** LuaJIT has support for a couple more formats than Lua 5.1/5.2: -** - %d %u %o %x with full formatting, 32 bit integers only. -** - %f and other FP formats are really %.14g. -** - %s %c %p without formatting. -*/ - -/* Push formatted message as a string object to Lua stack. va_list variant. */ -const char *lj_strfmt_pushvf(lua_State *L, const char *fmt, va_list argp) -{ - SBuf *sb = lj_buf_tmp_(L); - FormatState fs; - SFormat sf; - GCstr *str; - lj_strfmt_init(&fs, fmt, (MSize)strlen(fmt)); - while ((sf = lj_strfmt_parse(&fs)) != STRFMT_EOF) { - switch (STRFMT_TYPE(sf)) { - case STRFMT_LIT: - lj_buf_putmem(sb, fs.str, fs.len); - break; - case STRFMT_INT: - lj_strfmt_putfxint(sb, sf, va_arg(argp, int32_t)); - break; - case STRFMT_UINT: - lj_strfmt_putfxint(sb, sf, va_arg(argp, uint32_t)); - break; - case STRFMT_NUM: - lj_strfmt_putfnum(sb, STRFMT_G14, va_arg(argp, lua_Number)); - break; - case STRFMT_STR: { - const char *s = va_arg(argp, char *); - if (s == NULL) s = "(null)"; - lj_buf_putmem(sb, s, (MSize)strlen(s)); - break; - } - case STRFMT_CHAR: - lj_buf_putb(sb, va_arg(argp, int)); - break; - case STRFMT_PTR: - lj_strfmt_putptr(sb, va_arg(argp, void *)); - break; - case STRFMT_ERR: - default: - lj_buf_putb(sb, '?'); - lua_assert(0); - break; - } - } - str = lj_buf_str(L, sb); - setstrV(L, L->top, str); - incr_top(L); - return strdata(str); -} - -/* Push formatted message as a string object to Lua stack. Vararg variant. */ -const char *lj_strfmt_pushf(lua_State *L, const char *fmt, ...) -{ - const char *msg; - va_list argp; - va_start(argp, fmt); - msg = lj_strfmt_pushvf(L, fmt, argp); - va_end(argp); - return msg; -} - diff --git a/lib/LuaJIT/src/lj_strfmt.h b/lib/LuaJIT/src/lj_strfmt.h deleted file mode 100644 index 6e1d901..0000000 --- a/lib/LuaJIT/src/lj_strfmt.h +++ /dev/null @@ -1,125 +0,0 @@ -/* -** String formatting. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_STRFMT_H -#define _LJ_STRFMT_H - -#include "lj_obj.h" - -typedef uint32_t SFormat; /* Format indicator. */ - -/* Format parser state. */ -typedef struct FormatState { - const uint8_t *p; /* Current format string pointer. */ - const uint8_t *e; /* End of format string. */ - const char *str; /* Returned literal string. */ - MSize len; /* Size of literal string. */ -} FormatState; - -/* Format types (max. 16). */ -typedef enum FormatType { - STRFMT_EOF, STRFMT_ERR, STRFMT_LIT, - STRFMT_INT, STRFMT_UINT, STRFMT_NUM, STRFMT_STR, STRFMT_CHAR, STRFMT_PTR -} FormatType; - -/* Format subtypes (bits are reused). */ -#define STRFMT_T_HEX 0x0010 /* STRFMT_UINT */ -#define STRFMT_T_OCT 0x0020 /* STRFMT_UINT */ -#define STRFMT_T_FP_A 0x0000 /* STRFMT_NUM */ -#define STRFMT_T_FP_E 0x0010 /* STRFMT_NUM */ -#define STRFMT_T_FP_F 0x0020 /* STRFMT_NUM */ -#define STRFMT_T_FP_G 0x0030 /* STRFMT_NUM */ -#define STRFMT_T_QUOTED 0x0010 /* STRFMT_STR */ - -/* Format flags. */ -#define STRFMT_F_LEFT 0x0100 -#define STRFMT_F_PLUS 0x0200 -#define STRFMT_F_ZERO 0x0400 -#define STRFMT_F_SPACE 0x0800 -#define STRFMT_F_ALT 0x1000 -#define STRFMT_F_UPPER 0x2000 - -/* Format indicator fields. */ -#define STRFMT_SH_WIDTH 16 -#define STRFMT_SH_PREC 24 - -#define STRFMT_TYPE(sf) ((FormatType)((sf) & 15)) -#define STRFMT_WIDTH(sf) (((sf) >> STRFMT_SH_WIDTH) & 255u) -#define STRFMT_PREC(sf) ((((sf) >> STRFMT_SH_PREC) & 255u) - 1u) -#define STRFMT_FP(sf) (((sf) >> 4) & 3) - -/* Formats for conversion characters. */ -#define STRFMT_A (STRFMT_NUM|STRFMT_T_FP_A) -#define STRFMT_C (STRFMT_CHAR) -#define STRFMT_D (STRFMT_INT) -#define STRFMT_E (STRFMT_NUM|STRFMT_T_FP_E) -#define STRFMT_F (STRFMT_NUM|STRFMT_T_FP_F) -#define STRFMT_G (STRFMT_NUM|STRFMT_T_FP_G) -#define STRFMT_I STRFMT_D -#define STRFMT_O (STRFMT_UINT|STRFMT_T_OCT) -#define STRFMT_P (STRFMT_PTR) -#define STRFMT_Q (STRFMT_STR|STRFMT_T_QUOTED) -#define STRFMT_S (STRFMT_STR) -#define STRFMT_U (STRFMT_UINT) -#define STRFMT_X (STRFMT_UINT|STRFMT_T_HEX) -#define STRFMT_G14 (STRFMT_G | ((14+1) << STRFMT_SH_PREC)) - -/* Maximum buffer sizes for conversions. */ -#define STRFMT_MAXBUF_XINT (1+22) /* '0' prefix + uint64_t in octal. */ -#define STRFMT_MAXBUF_INT (1+10) /* Sign + int32_t in decimal. */ -#define STRFMT_MAXBUF_NUM 32 /* Must correspond with STRFMT_G14. */ -#define STRFMT_MAXBUF_PTR (2+2*sizeof(ptrdiff_t)) /* "0x" + hex ptr. */ - -/* Format parser. */ -LJ_FUNC SFormat LJ_FASTCALL lj_strfmt_parse(FormatState *fs); - -static LJ_AINLINE void lj_strfmt_init(FormatState *fs, const char *p, MSize len) -{ - fs->p = (const uint8_t *)p; - fs->e = (const uint8_t *)p + len; - lua_assert(*fs->e == 0); /* Must be NUL-terminated (may have NULs inside). */ -} - -/* Raw conversions. */ -LJ_FUNC char * LJ_FASTCALL lj_strfmt_wint(char *p, int32_t k); -LJ_FUNC char * LJ_FASTCALL lj_strfmt_wptr(char *p, const void *v); -LJ_FUNC char * LJ_FASTCALL lj_strfmt_wuleb128(char *p, uint32_t v); -LJ_FUNC const char *lj_strfmt_wstrnum(lua_State *L, cTValue *o, MSize *lenp); - -/* Unformatted conversions to buffer. */ -LJ_FUNC SBuf * LJ_FASTCALL lj_strfmt_putint(SBuf *sb, int32_t k); -#if LJ_HASJIT -LJ_FUNC SBuf * LJ_FASTCALL lj_strfmt_putnum(SBuf *sb, cTValue *o); -#endif -LJ_FUNC SBuf * LJ_FASTCALL lj_strfmt_putptr(SBuf *sb, const void *v); -LJ_FUNC SBuf * LJ_FASTCALL lj_strfmt_putquoted(SBuf *sb, GCstr *str); - -/* Formatted conversions to buffer. */ -LJ_FUNC SBuf *lj_strfmt_putfxint(SBuf *sb, SFormat sf, uint64_t k); -LJ_FUNC SBuf *lj_strfmt_putfnum_int(SBuf *sb, SFormat sf, lua_Number n); -LJ_FUNC SBuf *lj_strfmt_putfnum_uint(SBuf *sb, SFormat sf, lua_Number n); -LJ_FUNC SBuf *lj_strfmt_putfnum(SBuf *sb, SFormat, lua_Number n); -LJ_FUNC SBuf *lj_strfmt_putfchar(SBuf *sb, SFormat, int32_t c); -LJ_FUNC SBuf *lj_strfmt_putfstr(SBuf *sb, SFormat, GCstr *str); - -/* Conversions to strings. */ -LJ_FUNC GCstr * LJ_FASTCALL lj_strfmt_int(lua_State *L, int32_t k); -LJ_FUNCA GCstr * LJ_FASTCALL lj_strfmt_num(lua_State *L, cTValue *o); -LJ_FUNCA GCstr * LJ_FASTCALL lj_strfmt_number(lua_State *L, cTValue *o); -#if LJ_HASJIT -LJ_FUNC GCstr * LJ_FASTCALL lj_strfmt_char(lua_State *L, int c); -#endif -LJ_FUNC GCstr * LJ_FASTCALL lj_strfmt_obj(lua_State *L, cTValue *o); - -/* Internal string formatting. */ -LJ_FUNC const char *lj_strfmt_pushvf(lua_State *L, const char *fmt, - va_list argp); -LJ_FUNC const char *lj_strfmt_pushf(lua_State *L, const char *fmt, ...) -#ifdef __GNUC__ - __attribute__ ((format (printf, 2, 3))) -#endif - ; - -#endif diff --git a/lib/LuaJIT/src/lj_strfmt_num.c b/lib/LuaJIT/src/lj_strfmt_num.c deleted file mode 100644 index 9271f68..0000000 --- a/lib/LuaJIT/src/lj_strfmt_num.c +++ /dev/null @@ -1,592 +0,0 @@ -/* -** String formatting for floating-point numbers. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** Contributed by Peter Cawley. -*/ - -#include - -#define lj_strfmt_num_c -#define LUA_CORE - -#include "lj_obj.h" -#include "lj_buf.h" -#include "lj_str.h" -#include "lj_strfmt.h" - -/* -- Precomputed tables -------------------------------------------------- */ - -/* Rescale factors to push the exponent of a number towards zero. */ -#define RESCALE_EXPONENTS(P, N) \ - P(308), P(289), P(270), P(250), P(231), P(212), P(193), P(173), P(154), \ - P(135), P(115), P(96), P(77), P(58), P(38), P(0), P(0), P(0), N(39), N(58), \ - N(77), N(96), N(116), N(135), N(154), N(174), N(193), N(212), N(231), \ - N(251), N(270), N(289) - -#define ONE_E_P(X) 1e+0 ## X -#define ONE_E_N(X) 1e-0 ## X -static const int16_t rescale_e[] = { RESCALE_EXPONENTS(-, +) }; -static const double rescale_n[] = { RESCALE_EXPONENTS(ONE_E_P, ONE_E_N) }; -#undef ONE_E_N -#undef ONE_E_P - -/* -** For p in range -70 through 57, this table encodes pairs (m, e) such that -** 4*2^p <= (uint8_t)m*10^e, and is the smallest value for which this holds. -*/ -static const int8_t four_ulp_m_e[] = { - 34, -21, 68, -21, 14, -20, 28, -20, 55, -20, 2, -19, 3, -19, 5, -19, 9, -19, - -82, -18, 35, -18, 7, -17, -117, -17, 28, -17, 56, -17, 112, -16, -33, -16, - 45, -16, 89, -16, -78, -15, 36, -15, 72, -15, -113, -14, 29, -14, 57, -14, - 114, -13, -28, -13, 46, -13, 91, -12, -74, -12, 37, -12, 73, -12, 15, -11, 3, - -11, 59, -11, 2, -10, 3, -10, 5, -10, 1, -9, -69, -9, 38, -9, 75, -9, 15, -7, - 3, -7, 6, -7, 12, -6, -17, -7, 48, -7, 96, -7, -65, -6, 39, -6, 77, -6, -103, - -5, 31, -5, 62, -5, 123, -4, -11, -4, 49, -4, 98, -4, -60, -3, 4, -2, 79, -3, - 16, -2, 32, -2, 63, -2, 2, -1, 25, 0, 5, 1, 1, 2, 2, 2, 4, 2, 8, 2, 16, 2, - 32, 2, 64, 2, -128, 2, 26, 2, 52, 2, 103, 3, -51, 3, 41, 4, 82, 4, -92, 4, - 33, 4, 66, 4, -124, 5, 27, 5, 53, 5, 105, 6, 21, 6, 42, 6, 84, 6, 17, 7, 34, - 7, 68, 7, 2, 8, 3, 8, 6, 8, 108, 9, -41, 9, 43, 10, 86, 9, -84, 10, 35, 10, - 69, 10, -118, 11, 28, 11, 55, 12, 11, 13, 22, 13, 44, 13, 88, 13, -80, 13, - 36, 13, 71, 13, -115, 14, 29, 14, 57, 14, 113, 15, -30, 15, 46, 15, 91, 15, - 19, 16, 37, 16, 73, 16, 2, 17, 3, 17, 6, 17 -}; - -/* min(2^32-1, 10^e-1) for e in range 0 through 10 */ -static uint32_t ndigits_dec_threshold[] = { - 0, 9U, 99U, 999U, 9999U, 99999U, 999999U, - 9999999U, 99999999U, 999999999U, 0xffffffffU -}; - -/* -- Helper functions ---------------------------------------------------- */ - -/* Compute the number of digits in the decimal representation of x. */ -static MSize ndigits_dec(uint32_t x) -{ - MSize t = ((lj_fls(x | 1) * 77) >> 8) + 1; /* 2^8/77 is roughly log2(10) */ - return t + (x > ndigits_dec_threshold[t]); -} - -#define WINT_R(x, sh, sc) \ - { uint32_t d = (x*(((1<>sh; x -= d*sc; *p++ = (char)('0'+d); } - -/* Write 9-digit unsigned integer to buffer. */ -static char *lj_strfmt_wuint9(char *p, uint32_t u) -{ - uint32_t v = u / 10000, w; - u -= v * 10000; - w = v / 10000; - v -= w * 10000; - *p++ = (char)('0'+w); - WINT_R(v, 23, 1000) - WINT_R(v, 12, 100) - WINT_R(v, 10, 10) - *p++ = (char)('0'+v); - WINT_R(u, 23, 1000) - WINT_R(u, 12, 100) - WINT_R(u, 10, 10) - *p++ = (char)('0'+u); - return p; -} -#undef WINT_R - -/* -- Extended precision arithmetic --------------------------------------- */ - -/* -** The "nd" format is a fixed-precision decimal representation for numbers. It -** consists of up to 64 uint32_t values, with each uint32_t storing a value -** in the range [0, 1e9). A number in "nd" format consists of three variables: -** -** uint32_t nd[64]; -** uint32_t ndlo; -** uint32_t ndhi; -** -** The integral part of the number is stored in nd[0 ... ndhi], the value of -** which is sum{i in [0, ndhi] | nd[i] * 10^(9*i)}. If the fractional part of -** the number is zero, ndlo is zero. Otherwise, the fractional part is stored -** in nd[ndlo ... 63], the value of which is taken to be -** sum{i in [ndlo, 63] | nd[i] * 10^(9*(i-64))}. -** -** If the array part had 128 elements rather than 64, then every double would -** have an exact representation in "nd" format. With 64 elements, all integral -** doubles have an exact representation, and all non-integral doubles have -** enough digits to make both %.99e and %.99f do the right thing. -*/ - -#if LJ_64 -#define ND_MUL2K_MAX_SHIFT 29 -#define ND_MUL2K_DIV1E9(val) ((uint32_t)((val) / 1000000000)) -#else -#define ND_MUL2K_MAX_SHIFT 11 -#define ND_MUL2K_DIV1E9(val) ((uint32_t)((val) >> 9) / 1953125) -#endif - -/* Multiply nd by 2^k and add carry_in (ndlo is assumed to be zero). */ -static uint32_t nd_mul2k(uint32_t* nd, uint32_t ndhi, uint32_t k, - uint32_t carry_in, SFormat sf) -{ - uint32_t i, ndlo = 0, start = 1; - /* Performance hacks. */ - if (k > ND_MUL2K_MAX_SHIFT*2 && STRFMT_FP(sf) != STRFMT_FP(STRFMT_T_FP_F)) { - start = ndhi - (STRFMT_PREC(sf) + 17) / 8; - } - /* Real logic. */ - while (k >= ND_MUL2K_MAX_SHIFT) { - for (i = ndlo; i <= ndhi; i++) { - uint64_t val = ((uint64_t)nd[i] << ND_MUL2K_MAX_SHIFT) | carry_in; - carry_in = ND_MUL2K_DIV1E9(val); - nd[i] = (uint32_t)val - carry_in * 1000000000; - } - if (carry_in) { - nd[++ndhi] = carry_in; carry_in = 0; - if (start++ == ndlo) ++ndlo; - } - k -= ND_MUL2K_MAX_SHIFT; - } - if (k) { - for (i = ndlo; i <= ndhi; i++) { - uint64_t val = ((uint64_t)nd[i] << k) | carry_in; - carry_in = ND_MUL2K_DIV1E9(val); - nd[i] = (uint32_t)val - carry_in * 1000000000; - } - if (carry_in) nd[++ndhi] = carry_in; - } - return ndhi; -} - -/* Divide nd by 2^k (ndlo is assumed to be zero). */ -static uint32_t nd_div2k(uint32_t* nd, uint32_t ndhi, uint32_t k, SFormat sf) -{ - uint32_t ndlo = 0, stop1 = ~0, stop2 = ~0; - /* Performance hacks. */ - if (!ndhi) { - if (!nd[0]) { - return 0; - } else { - uint32_t s = lj_ffs(nd[0]); - if (s >= k) { nd[0] >>= k; return 0; } - nd[0] >>= s; k -= s; - } - } - if (k > 18) { - if (STRFMT_FP(sf) == STRFMT_FP(STRFMT_T_FP_F)) { - stop1 = 63 - (int32_t)STRFMT_PREC(sf) / 9; - } else { - int32_t floorlog2 = ndhi * 29 + lj_fls(nd[ndhi]) - k; - int32_t floorlog10 = (int32_t)(floorlog2 * 0.30102999566398114); - stop1 = 62 + (floorlog10 - (int32_t)STRFMT_PREC(sf)) / 9; - stop2 = 61 + ndhi - (int32_t)STRFMT_PREC(sf) / 8; - } - } - /* Real logic. */ - while (k >= 9) { - uint32_t i = ndhi, carry = 0; - for (;;) { - uint32_t val = nd[i]; - nd[i] = (val >> 9) + carry; - carry = (val & 0x1ff) * 1953125; - if (i == ndlo) break; - i = (i - 1) & 0x3f; - } - if (ndlo != stop1 && ndlo != stop2) { - if (carry) { ndlo = (ndlo - 1) & 0x3f; nd[ndlo] = carry; } - if (!nd[ndhi]) { ndhi = (ndhi - 1) & 0x3f; stop2--; } - } else if (!nd[ndhi]) { - if (ndhi != ndlo) { ndhi = (ndhi - 1) & 0x3f; stop2--; } - else return ndlo; - } - k -= 9; - } - if (k) { - uint32_t mask = (1U << k) - 1, mul = 1000000000 >> k, i = ndhi, carry = 0; - for (;;) { - uint32_t val = nd[i]; - nd[i] = (val >> k) + carry; - carry = (val & mask) * mul; - if (i == ndlo) break; - i = (i - 1) & 0x3f; - } - if (carry) { ndlo = (ndlo - 1) & 0x3f; nd[ndlo] = carry; } - } - return ndlo; -} - -/* Add m*10^e to nd (assumes ndlo <= e/9 <= ndhi and 0 <= m <= 9). */ -static uint32_t nd_add_m10e(uint32_t* nd, uint32_t ndhi, uint8_t m, int32_t e) -{ - uint32_t i, carry; - if (e >= 0) { - i = (uint32_t)e/9; - carry = m * (ndigits_dec_threshold[e - (int32_t)i*9] + 1); - } else { - int32_t f = (e-8)/9; - i = (uint32_t)(64 + f); - carry = m * (ndigits_dec_threshold[e - f*9] + 1); - } - for (;;) { - uint32_t val = nd[i] + carry; - if (LJ_UNLIKELY(val >= 1000000000)) { - val -= 1000000000; - nd[i] = val; - if (LJ_UNLIKELY(i == ndhi)) { - ndhi = (ndhi + 1) & 0x3f; - nd[ndhi] = 1; - break; - } - carry = 1; - i = (i + 1) & 0x3f; - } else { - nd[i] = val; - break; - } - } - return ndhi; -} - -/* Test whether two "nd" values are equal in their most significant digits. */ -static int nd_similar(uint32_t* nd, uint32_t ndhi, uint32_t* ref, MSize hilen, - MSize prec) -{ - char nd9[9], ref9[9]; - if (hilen <= prec) { - if (LJ_UNLIKELY(nd[ndhi] != *ref)) return 0; - prec -= hilen; ref--; ndhi = (ndhi - 1) & 0x3f; - if (prec >= 9) { - if (LJ_UNLIKELY(nd[ndhi] != *ref)) return 0; - prec -= 9; ref--; ndhi = (ndhi - 1) & 0x3f; - } - } else { - prec -= hilen - 9; - } - lua_assert(prec < 9); - lj_strfmt_wuint9(nd9, nd[ndhi]); - lj_strfmt_wuint9(ref9, *ref); - return !memcmp(nd9, ref9, prec) && (nd9[prec] < '5') == (ref9[prec] < '5'); -} - -/* -- Formatted conversions to buffer ------------------------------------- */ - -/* Write formatted floating-point number to either sb or p. */ -static char *lj_strfmt_wfnum(SBuf *sb, SFormat sf, lua_Number n, char *p) -{ - MSize width = STRFMT_WIDTH(sf), prec = STRFMT_PREC(sf), len; - TValue t; - t.n = n; - if (LJ_UNLIKELY((t.u32.hi << 1) >= 0xffe00000)) { - /* Handle non-finite values uniformly for %a, %e, %f, %g. */ - int prefix = 0, ch = (sf & STRFMT_F_UPPER) ? 0x202020 : 0; - if (((t.u32.hi & 0x000fffff) | t.u32.lo) != 0) { - ch ^= ('n' << 16) | ('a' << 8) | 'n'; - if ((sf & STRFMT_F_SPACE)) prefix = ' '; - } else { - ch ^= ('i' << 16) | ('n' << 8) | 'f'; - if ((t.u32.hi & 0x80000000)) prefix = '-'; - else if ((sf & STRFMT_F_PLUS)) prefix = '+'; - else if ((sf & STRFMT_F_SPACE)) prefix = ' '; - } - len = 3 + (prefix != 0); - if (!p) p = lj_buf_more(sb, width > len ? width : len); - if (!(sf & STRFMT_F_LEFT)) while (width-- > len) *p++ = ' '; - if (prefix) *p++ = prefix; - *p++ = (char)(ch >> 16); *p++ = (char)(ch >> 8); *p++ = (char)ch; - } else if (STRFMT_FP(sf) == STRFMT_FP(STRFMT_T_FP_A)) { - /* %a */ - const char *hexdig = (sf & STRFMT_F_UPPER) ? "0123456789ABCDEFPX" - : "0123456789abcdefpx"; - int32_t e = (t.u32.hi >> 20) & 0x7ff; - char prefix = 0, eprefix = '+'; - if (t.u32.hi & 0x80000000) prefix = '-'; - else if ((sf & STRFMT_F_PLUS)) prefix = '+'; - else if ((sf & STRFMT_F_SPACE)) prefix = ' '; - t.u32.hi &= 0xfffff; - if (e) { - t.u32.hi |= 0x100000; - e -= 1023; - } else if (t.u32.lo | t.u32.hi) { - /* Non-zero denormal - normalise it. */ - uint32_t shift = t.u32.hi ? 20-lj_fls(t.u32.hi) : 52-lj_fls(t.u32.lo); - e = -1022 - shift; - t.u64 <<= shift; - } - /* abs(n) == t.u64 * 2^(e - 52) */ - /* If n != 0, bit 52 of t.u64 is set, and is the highest set bit. */ - if ((int32_t)prec < 0) { - /* Default precision: use smallest precision giving exact result. */ - prec = t.u32.lo ? 13-lj_ffs(t.u32.lo)/4 : 5-lj_ffs(t.u32.hi|0x100000)/4; - } else if (prec < 13) { - /* Precision is sufficiently low as to maybe require rounding. */ - t.u64 += (((uint64_t)1) << (51 - prec*4)); - } - if (e < 0) { - eprefix = '-'; - e = -e; - } - len = 5 + ndigits_dec((uint32_t)e) + prec + (prefix != 0) - + ((prec | (sf & STRFMT_F_ALT)) != 0); - if (!p) p = lj_buf_more(sb, width > len ? width : len); - if (!(sf & (STRFMT_F_LEFT | STRFMT_F_ZERO))) { - while (width-- > len) *p++ = ' '; - } - if (prefix) *p++ = prefix; - *p++ = '0'; - *p++ = hexdig[17]; /* x or X */ - if ((sf & (STRFMT_F_LEFT | STRFMT_F_ZERO)) == STRFMT_F_ZERO) { - while (width-- > len) *p++ = '0'; - } - *p++ = '0' + (t.u32.hi >> 20); /* Usually '1', sometimes '0' or '2'. */ - if ((prec | (sf & STRFMT_F_ALT))) { - /* Emit fractional part. */ - char *q = p + 1 + prec; - *p = '.'; - if (prec < 13) t.u64 >>= (52 - prec*4); - else while (prec > 13) p[prec--] = '0'; - while (prec) { p[prec--] = hexdig[t.u64 & 15]; t.u64 >>= 4; } - p = q; - } - *p++ = hexdig[16]; /* p or P */ - *p++ = eprefix; /* + or - */ - p = lj_strfmt_wint(p, e); - } else { - /* %e or %f or %g - begin by converting n to "nd" format. */ - uint32_t nd[64]; - uint32_t ndhi = 0, ndlo, i; - int32_t e = (t.u32.hi >> 20) & 0x7ff, ndebias = 0; - char prefix = 0, *q; - if (t.u32.hi & 0x80000000) prefix = '-'; - else if ((sf & STRFMT_F_PLUS)) prefix = '+'; - else if ((sf & STRFMT_F_SPACE)) prefix = ' '; - prec += ((int32_t)prec >> 31) & 7; /* Default precision is 6. */ - if (STRFMT_FP(sf) == STRFMT_FP(STRFMT_T_FP_G)) { - /* %g - decrement precision if non-zero (to make it like %e). */ - prec--; - prec ^= (uint32_t)((int32_t)prec >> 31); - } - if ((sf & STRFMT_T_FP_E) && prec < 14 && n != 0) { - /* Precision is sufficiently low that rescaling will probably work. */ - if ((ndebias = rescale_e[e >> 6])) { - t.n = n * rescale_n[e >> 6]; - if (LJ_UNLIKELY(!e)) t.n *= 1e10, ndebias -= 10; - t.u64 -= 2; /* Convert 2ulp below (later we convert 2ulp above). */ - nd[0] = 0x100000 | (t.u32.hi & 0xfffff); - e = ((t.u32.hi >> 20) & 0x7ff) - 1075 - (ND_MUL2K_MAX_SHIFT < 29); - goto load_t_lo; rescale_failed: - t.n = n; - e = (t.u32.hi >> 20) & 0x7ff; - ndebias = ndhi = 0; - } - } - nd[0] = t.u32.hi & 0xfffff; - if (e == 0) e++; else nd[0] |= 0x100000; - e -= 1043; - if (t.u32.lo) { - e -= 32 + (ND_MUL2K_MAX_SHIFT < 29); load_t_lo: -#if ND_MUL2K_MAX_SHIFT >= 29 - nd[0] = (nd[0] << 3) | (t.u32.lo >> 29); - ndhi = nd_mul2k(nd, ndhi, 29, t.u32.lo & 0x1fffffff, sf); -#elif ND_MUL2K_MAX_SHIFT >= 11 - ndhi = nd_mul2k(nd, ndhi, 11, t.u32.lo >> 21, sf); - ndhi = nd_mul2k(nd, ndhi, 11, (t.u32.lo >> 10) & 0x7ff, sf); - ndhi = nd_mul2k(nd, ndhi, 11, (t.u32.lo << 1) & 0x7ff, sf); -#else -#error "ND_MUL2K_MAX_SHIFT too small" -#endif - } - if (e >= 0) { - ndhi = nd_mul2k(nd, ndhi, (uint32_t)e, 0, sf); - ndlo = 0; - } else { - ndlo = nd_div2k(nd, ndhi, (uint32_t)-e, sf); - if (ndhi && !nd[ndhi]) ndhi--; - } - /* abs(n) == nd * 10^ndebias (for slightly loose interpretation of ==) */ - if ((sf & STRFMT_T_FP_E)) { - /* %e or %g - assume %e and start by calculating nd's exponent (nde). */ - char eprefix = '+'; - int32_t nde = -1; - MSize hilen; - if (ndlo && !nd[ndhi]) { - ndhi = 64; do {} while (!nd[--ndhi]); - nde -= 64 * 9; - } - hilen = ndigits_dec(nd[ndhi]); - nde += ndhi * 9 + hilen; - if (ndebias) { - /* - ** Rescaling was performed, but this introduced some error, and might - ** have pushed us across a rounding boundary. We check whether this - ** error affected the result by introducing even more error (2ulp in - ** either direction), and seeing whether a roundary boundary was - ** crossed. Having already converted the -2ulp case, we save off its - ** most significant digits, convert the +2ulp case, and compare them. - */ - int32_t eidx = e + 70 + (ND_MUL2K_MAX_SHIFT < 29) - + (t.u32.lo >= 0xfffffffe && !(~t.u32.hi << 12)); - const int8_t *m_e = four_ulp_m_e + eidx * 2; - lua_assert(0 <= eidx && eidx < 128); - nd[33] = nd[ndhi]; - nd[32] = nd[(ndhi - 1) & 0x3f]; - nd[31] = nd[(ndhi - 2) & 0x3f]; - nd_add_m10e(nd, ndhi, (uint8_t)*m_e, m_e[1]); - if (LJ_UNLIKELY(!nd_similar(nd, ndhi, nd + 33, hilen, prec + 1))) { - goto rescale_failed; - } - } - if ((int32_t)(prec - nde) < (0x3f & -(int32_t)ndlo) * 9) { - /* Precision is sufficiently low as to maybe require rounding. */ - ndhi = nd_add_m10e(nd, ndhi, 5, nde - prec - 1); - nde += (hilen != ndigits_dec(nd[ndhi])); - } - nde += ndebias; - if ((sf & STRFMT_T_FP_F)) { - /* %g */ - if ((int32_t)prec >= nde && nde >= -4) { - if (nde < 0) ndhi = 0; - prec -= nde; - goto g_format_like_f; - } else if (!(sf & STRFMT_F_ALT) && prec && width > 5) { - /* Decrease precision in order to strip trailing zeroes. */ - char tail[9]; - uint32_t maxprec = hilen - 1 + ((ndhi - ndlo) & 0x3f) * 9; - if (prec >= maxprec) prec = maxprec; - else ndlo = (ndhi - (((int32_t)(prec - hilen) + 9) / 9)) & 0x3f; - i = prec - hilen - (((ndhi - ndlo) & 0x3f) * 9) + 10; - lj_strfmt_wuint9(tail, nd[ndlo]); - while (prec && tail[--i] == '0') { - prec--; - if (!i) { - if (ndlo == ndhi) { prec = 0; break; } - lj_strfmt_wuint9(tail, nd[++ndlo]); - i = 9; - } - } - } - } - if (nde < 0) { - /* Make nde non-negative. */ - eprefix = '-'; - nde = -nde; - } - len = 3 + prec + (prefix != 0) + ndigits_dec((uint32_t)nde) + (nde < 10) - + ((prec | (sf & STRFMT_F_ALT)) != 0); - if (!p) p = lj_buf_more(sb, (width > len ? width : len) + 5); - if (!(sf & (STRFMT_F_LEFT | STRFMT_F_ZERO))) { - while (width-- > len) *p++ = ' '; - } - if (prefix) *p++ = prefix; - if ((sf & (STRFMT_F_LEFT | STRFMT_F_ZERO)) == STRFMT_F_ZERO) { - while (width-- > len) *p++ = '0'; - } - q = lj_strfmt_wint(p + 1, nd[ndhi]); - p[0] = p[1]; /* Put leading digit in the correct place. */ - if ((prec | (sf & STRFMT_F_ALT))) { - /* Emit fractional part. */ - p[1] = '.'; p += 2; - prec -= (MSize)(q - p); p = q; /* Account for digits already emitted. */ - /* Then emit chunks of 9 digits (this may emit 8 digits too many). */ - for (i = ndhi; (int32_t)prec > 0 && i != ndlo; prec -= 9) { - i = (i - 1) & 0x3f; - p = lj_strfmt_wuint9(p, nd[i]); - } - if ((sf & STRFMT_T_FP_F) && !(sf & STRFMT_F_ALT)) { - /* %g (and not %#g) - strip trailing zeroes. */ - p += (int32_t)prec & ((int32_t)prec >> 31); - while (p[-1] == '0') p--; - if (p[-1] == '.') p--; - } else { - /* %e (or %#g) - emit trailing zeroes. */ - while ((int32_t)prec > 0) { *p++ = '0'; prec--; } - p += (int32_t)prec; - } - } else { - p++; - } - *p++ = (sf & STRFMT_F_UPPER) ? 'E' : 'e'; - *p++ = eprefix; /* + or - */ - if (nde < 10) *p++ = '0'; /* Always at least two digits of exponent. */ - p = lj_strfmt_wint(p, nde); - } else { - /* %f (or, shortly, %g in %f style) */ - if (prec < (MSize)(0x3f & -(int32_t)ndlo) * 9) { - /* Precision is sufficiently low as to maybe require rounding. */ - ndhi = nd_add_m10e(nd, ndhi, 5, 0 - prec - 1); - } - g_format_like_f: - if ((sf & STRFMT_T_FP_E) && !(sf & STRFMT_F_ALT) && prec && width) { - /* Decrease precision in order to strip trailing zeroes. */ - if (ndlo) { - /* nd has a fractional part; we need to look at its digits. */ - char tail[9]; - uint32_t maxprec = (64 - ndlo) * 9; - if (prec >= maxprec) prec = maxprec; - else ndlo = 64 - (prec + 8) / 9; - i = prec - ((63 - ndlo) * 9); - lj_strfmt_wuint9(tail, nd[ndlo]); - while (prec && tail[--i] == '0') { - prec--; - if (!i) { - if (ndlo == 63) { prec = 0; break; } - lj_strfmt_wuint9(tail, nd[++ndlo]); - i = 9; - } - } - } else { - /* nd has no fractional part, so precision goes straight to zero. */ - prec = 0; - } - } - len = ndhi * 9 + ndigits_dec(nd[ndhi]) + prec + (prefix != 0) - + ((prec | (sf & STRFMT_F_ALT)) != 0); - if (!p) p = lj_buf_more(sb, (width > len ? width : len) + 8); - if (!(sf & (STRFMT_F_LEFT | STRFMT_F_ZERO))) { - while (width-- > len) *p++ = ' '; - } - if (prefix) *p++ = prefix; - if ((sf & (STRFMT_F_LEFT | STRFMT_F_ZERO)) == STRFMT_F_ZERO) { - while (width-- > len) *p++ = '0'; - } - /* Emit integer part. */ - p = lj_strfmt_wint(p, nd[ndhi]); - i = ndhi; - while (i) p = lj_strfmt_wuint9(p, nd[--i]); - if ((prec | (sf & STRFMT_F_ALT))) { - /* Emit fractional part. */ - *p++ = '.'; - /* Emit chunks of 9 digits (this may emit 8 digits too many). */ - while ((int32_t)prec > 0 && i != ndlo) { - i = (i - 1) & 0x3f; - p = lj_strfmt_wuint9(p, nd[i]); - prec -= 9; - } - if ((sf & STRFMT_T_FP_E) && !(sf & STRFMT_F_ALT)) { - /* %g (and not %#g) - strip trailing zeroes. */ - p += (int32_t)prec & ((int32_t)prec >> 31); - while (p[-1] == '0') p--; - if (p[-1] == '.') p--; - } else { - /* %f (or %#g) - emit trailing zeroes. */ - while ((int32_t)prec > 0) { *p++ = '0'; prec--; } - p += (int32_t)prec; - } - } - } - } - if ((sf & STRFMT_F_LEFT)) while (width-- > len) *p++ = ' '; - return p; -} - -/* Add formatted floating-point number to buffer. */ -SBuf *lj_strfmt_putfnum(SBuf *sb, SFormat sf, lua_Number n) -{ - setsbufP(sb, lj_strfmt_wfnum(sb, sf, n, NULL)); - return sb; -} - -/* -- Conversions to strings ---------------------------------------------- */ - -/* Convert number to string. */ -GCstr * LJ_FASTCALL lj_strfmt_num(lua_State *L, cTValue *o) -{ - char buf[STRFMT_MAXBUF_NUM]; - MSize len = (MSize)(lj_strfmt_wfnum(NULL, STRFMT_G14, o->n, buf) - buf); - return lj_str_new(L, buf, len); -} - diff --git a/lib/LuaJIT/src/lj_strscan.c b/lib/LuaJIT/src/lj_strscan.c deleted file mode 100644 index f5f35c9..0000000 --- a/lib/LuaJIT/src/lj_strscan.c +++ /dev/null @@ -1,547 +0,0 @@ -/* -** String scanning. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#include - -#define lj_strscan_c -#define LUA_CORE - -#include "lj_obj.h" -#include "lj_char.h" -#include "lj_strscan.h" - -/* -- Scanning numbers ---------------------------------------------------- */ - -/* -** Rationale for the builtin string to number conversion library: -** -** It removes a dependency on libc's strtod(), which is a true portability -** nightmare. Mainly due to the plethora of supported OS and toolchain -** combinations. Sadly, the various implementations -** a) are often buggy, incomplete (no hex floats) and/or imprecise, -** b) sometimes crash or hang on certain inputs, -** c) return non-standard NaNs that need to be filtered out, and -** d) fail if the locale-specific decimal separator is not a dot, -** which can only be fixed with atrocious workarounds. -** -** Also, most of the strtod() implementations are hopelessly bloated, -** which is not just an I-cache hog, but a problem for static linkage -** on embedded systems, too. -** -** OTOH the builtin conversion function is very compact. Even though it -** does a lot more, like parsing long longs, octal or imaginary numbers -** and returning the result in different formats: -** a) It needs less than 3 KB (!) of machine code (on x64 with -Os), -** b) it doesn't perform any dynamic allocation and, -** c) it needs only around 600 bytes of stack space. -** -** The builtin function is faster than strtod() for typical inputs, e.g. -** "123", "1.5" or "1e6". Arguably, it's slower for very large exponents, -** which are not very common (this could be fixed, if needed). -** -** And most importantly, the builtin function is equally precise on all -** platforms. It correctly converts and rounds any input to a double. -** If this is not the case, please send a bug report -- but PLEASE verify -** that the implementation you're comparing to is not the culprit! -** -** The implementation quickly pre-scans the entire string first and -** handles simple integers on-the-fly. Otherwise, it dispatches to the -** base-specific parser. Hex and octal is straightforward. -** -** Decimal to binary conversion uses a fixed-length circular buffer in -** base 100. Some simple cases are handled directly. For other cases, the -** number in the buffer is up-scaled or down-scaled until the integer part -** is in the proper range. Then the integer part is rounded and converted -** to a double which is finally rescaled to the result. Denormals need -** special treatment to prevent incorrect 'double rounding'. -*/ - -/* Definitions for circular decimal digit buffer (base 100 = 2 digits/byte). */ -#define STRSCAN_DIG 1024 -#define STRSCAN_MAXDIG 800 /* 772 + extra are sufficient. */ -#define STRSCAN_DDIG (STRSCAN_DIG/2) -#define STRSCAN_DMASK (STRSCAN_DDIG-1) - -/* Helpers for circular buffer. */ -#define DNEXT(a) (((a)+1) & STRSCAN_DMASK) -#define DPREV(a) (((a)-1) & STRSCAN_DMASK) -#define DLEN(lo, hi) ((int32_t)(((lo)-(hi)) & STRSCAN_DMASK)) - -#define casecmp(c, k) (((c) | 0x20) == k) - -/* Final conversion to double. */ -static void strscan_double(uint64_t x, TValue *o, int32_t ex2, int32_t neg) -{ - double n; - - /* Avoid double rounding for denormals. */ - if (LJ_UNLIKELY(ex2 <= -1075 && x != 0)) { - /* NYI: all of this generates way too much code on 32 bit CPUs. */ -#if defined(__GNUC__) && LJ_64 - int32_t b = (int32_t)(__builtin_clzll(x)^63); -#else - int32_t b = (x>>32) ? 32+(int32_t)lj_fls((uint32_t)(x>>32)) : - (int32_t)lj_fls((uint32_t)x); -#endif - if ((int32_t)b + ex2 <= -1023 && (int32_t)b + ex2 >= -1075) { - uint64_t rb = (uint64_t)1 << (-1075-ex2); - if ((x & rb) && ((x & (rb+rb+rb-1)))) x += rb+rb; - x = (x & ~(rb+rb-1)); - } - } - - /* Convert to double using a signed int64_t conversion, then rescale. */ - lua_assert((int64_t)x >= 0); - n = (double)(int64_t)x; - if (neg) n = -n; - if (ex2) n = ldexp(n, ex2); - o->n = n; -} - -/* Parse hexadecimal number. */ -static StrScanFmt strscan_hex(const uint8_t *p, TValue *o, - StrScanFmt fmt, uint32_t opt, - int32_t ex2, int32_t neg, uint32_t dig) -{ - uint64_t x = 0; - uint32_t i; - - /* Scan hex digits. */ - for (i = dig > 16 ? 16 : dig ; i; i--, p++) { - uint32_t d = (*p != '.' ? *p : *++p); if (d > '9') d += 9; - x = (x << 4) + (d & 15); - } - - /* Summarize rounding-effect of excess digits. */ - for (i = 16; i < dig; i++, p++) - x |= ((*p != '.' ? *p : *++p) != '0'), ex2 += 4; - - /* Format-specific handling. */ - switch (fmt) { - case STRSCAN_INT: - if (!(opt & STRSCAN_OPT_TONUM) && x < 0x80000000u+neg) { - o->i = neg ? -(int32_t)x : (int32_t)x; - return STRSCAN_INT; /* Fast path for 32 bit integers. */ - } - if (!(opt & STRSCAN_OPT_C)) { fmt = STRSCAN_NUM; break; } - /* fallthrough */ - case STRSCAN_U32: - if (dig > 8) return STRSCAN_ERROR; - o->i = neg ? -(int32_t)x : (int32_t)x; - return STRSCAN_U32; - case STRSCAN_I64: - case STRSCAN_U64: - if (dig > 16) return STRSCAN_ERROR; - o->u64 = neg ? (uint64_t)-(int64_t)x : x; - return fmt; - default: - break; - } - - /* Reduce range, then convert to double. */ - if ((x & U64x(c0000000,0000000))) { x = (x >> 2) | (x & 3); ex2 += 2; } - strscan_double(x, o, ex2, neg); - return fmt; -} - -/* Parse octal number. */ -static StrScanFmt strscan_oct(const uint8_t *p, TValue *o, - StrScanFmt fmt, int32_t neg, uint32_t dig) -{ - uint64_t x = 0; - - /* Scan octal digits. */ - if (dig > 22 || (dig == 22 && *p > '1')) return STRSCAN_ERROR; - while (dig-- > 0) { - if (!(*p >= '0' && *p <= '7')) return STRSCAN_ERROR; - x = (x << 3) + (*p++ & 7); - } - - /* Format-specific handling. */ - switch (fmt) { - case STRSCAN_INT: - if (x >= 0x80000000u+neg) fmt = STRSCAN_U32; - /* fallthrough */ - case STRSCAN_U32: - if ((x >> 32)) return STRSCAN_ERROR; - o->i = neg ? -(int32_t)x : (int32_t)x; - break; - default: - case STRSCAN_I64: - case STRSCAN_U64: - o->u64 = neg ? (uint64_t)-(int64_t)x : x; - break; - } - return fmt; -} - -/* Parse decimal number. */ -static StrScanFmt strscan_dec(const uint8_t *p, TValue *o, - StrScanFmt fmt, uint32_t opt, - int32_t ex10, int32_t neg, uint32_t dig) -{ - uint8_t xi[STRSCAN_DDIG], *xip = xi; - - if (dig) { - uint32_t i = dig; - if (i > STRSCAN_MAXDIG) { - ex10 += (int32_t)(i - STRSCAN_MAXDIG); - i = STRSCAN_MAXDIG; - } - /* Scan unaligned leading digit. */ - if (((ex10^i) & 1)) - *xip++ = ((*p != '.' ? *p : *++p) & 15), i--, p++; - /* Scan aligned double-digits. */ - for ( ; i > 1; i -= 2) { - uint32_t d = 10 * ((*p != '.' ? *p : *++p) & 15); p++; - *xip++ = d + ((*p != '.' ? *p : *++p) & 15); p++; - } - /* Scan and realign trailing digit. */ - if (i) *xip++ = 10 * ((*p != '.' ? *p : *++p) & 15), ex10--, dig++, p++; - - /* Summarize rounding-effect of excess digits. */ - if (dig > STRSCAN_MAXDIG) { - do { - if ((*p != '.' ? *p : *++p) != '0') { xip[-1] |= 1; break; } - p++; - } while (--dig > STRSCAN_MAXDIG); - dig = STRSCAN_MAXDIG; - } else { /* Simplify exponent. */ - while (ex10 > 0 && dig <= 18) *xip++ = 0, ex10 -= 2, dig += 2; - } - } else { /* Only got zeros. */ - ex10 = 0; - xi[0] = 0; - } - - /* Fast path for numbers in integer format (but handles e.g. 1e6, too). */ - if (dig <= 20 && ex10 == 0) { - uint8_t *xis; - uint64_t x = xi[0]; - double n; - for (xis = xi+1; xis < xip; xis++) x = x * 100 + *xis; - if (!(dig == 20 && (xi[0] > 18 || (int64_t)x >= 0))) { /* No overflow? */ - /* Format-specific handling. */ - switch (fmt) { - case STRSCAN_INT: - if (!(opt & STRSCAN_OPT_TONUM) && x < 0x80000000u+neg) { - o->i = neg ? -(int32_t)x : (int32_t)x; - return STRSCAN_INT; /* Fast path for 32 bit integers. */ - } - if (!(opt & STRSCAN_OPT_C)) { fmt = STRSCAN_NUM; goto plainnumber; } - /* fallthrough */ - case STRSCAN_U32: - if ((x >> 32) != 0) return STRSCAN_ERROR; - o->i = neg ? -(int32_t)x : (int32_t)x; - return STRSCAN_U32; - case STRSCAN_I64: - case STRSCAN_U64: - o->u64 = neg ? (uint64_t)-(int64_t)x : x; - return fmt; - default: - plainnumber: /* Fast path for plain numbers < 2^63. */ - if ((int64_t)x < 0) break; - n = (double)(int64_t)x; - if (neg) n = -n; - o->n = n; - return fmt; - } - } - } - - /* Slow non-integer path. */ - if (fmt == STRSCAN_INT) { - if ((opt & STRSCAN_OPT_C)) return STRSCAN_ERROR; - fmt = STRSCAN_NUM; - } else if (fmt > STRSCAN_INT) { - return STRSCAN_ERROR; - } - { - uint32_t hi = 0, lo = (uint32_t)(xip-xi); - int32_t ex2 = 0, idig = (int32_t)lo + (ex10 >> 1); - - lua_assert(lo > 0 && (ex10 & 1) == 0); - - /* Handle simple overflow/underflow. */ - if (idig > 310/2) { if (neg) setminfV(o); else setpinfV(o); return fmt; } - else if (idig < -326/2) { o->n = neg ? -0.0 : 0.0; return fmt; } - - /* Scale up until we have at least 17 or 18 integer part digits. */ - while (idig < 9 && idig < DLEN(lo, hi)) { - uint32_t i, cy = 0; - ex2 -= 6; - for (i = DPREV(lo); ; i = DPREV(i)) { - uint32_t d = (xi[i] << 6) + cy; - cy = (((d >> 2) * 5243) >> 17); d = d - cy * 100; /* Div/mod 100. */ - xi[i] = (uint8_t)d; - if (i == hi) break; - if (d == 0 && i == DPREV(lo)) lo = i; - } - if (cy) { - hi = DPREV(hi); - if (xi[DPREV(lo)] == 0) lo = DPREV(lo); - else if (hi == lo) { lo = DPREV(lo); xi[DPREV(lo)] |= xi[lo]; } - xi[hi] = (uint8_t)cy; idig++; - } - } - - /* Scale down until no more than 17 or 18 integer part digits remain. */ - while (idig > 9) { - uint32_t i = hi, cy = 0; - ex2 += 6; - do { - cy += xi[i]; - xi[i] = (cy >> 6); - cy = 100 * (cy & 0x3f); - if (xi[i] == 0 && i == hi) hi = DNEXT(hi), idig--; - i = DNEXT(i); - } while (i != lo); - while (cy) { - if (hi == lo) { xi[DPREV(lo)] |= 1; break; } - xi[lo] = (cy >> 6); lo = DNEXT(lo); - cy = 100 * (cy & 0x3f); - } - } - - /* Collect integer part digits and convert to rescaled double. */ - { - uint64_t x = xi[hi]; - uint32_t i; - for (i = DNEXT(hi); --idig > 0 && i != lo; i = DNEXT(i)) - x = x * 100 + xi[i]; - if (i == lo) { - while (--idig >= 0) x = x * 100; - } else { /* Gather round bit from remaining digits. */ - x <<= 1; ex2--; - do { - if (xi[i]) { x |= 1; break; } - i = DNEXT(i); - } while (i != lo); - } - strscan_double(x, o, ex2, neg); - } - } - return fmt; -} - -/* Parse binary number. */ -static StrScanFmt strscan_bin(const uint8_t *p, TValue *o, - StrScanFmt fmt, uint32_t opt, - int32_t ex2, int32_t neg, uint32_t dig) -{ - uint64_t x = 0; - uint32_t i; - - if (ex2 || dig > 64) return STRSCAN_ERROR; - - /* Scan binary digits. */ - for (i = dig; i; i--, p++) { - if ((*p & ~1) != '0') return STRSCAN_ERROR; - x = (x << 1) | (*p & 1); - } - - /* Format-specific handling. */ - switch (fmt) { - case STRSCAN_INT: - if (!(opt & STRSCAN_OPT_TONUM) && x < 0x80000000u+neg) { - o->i = neg ? -(int32_t)x : (int32_t)x; - return STRSCAN_INT; /* Fast path for 32 bit integers. */ - } - if (!(opt & STRSCAN_OPT_C)) { fmt = STRSCAN_NUM; break; } - /* fallthrough */ - case STRSCAN_U32: - if (dig > 32) return STRSCAN_ERROR; - o->i = neg ? -(int32_t)x : (int32_t)x; - return STRSCAN_U32; - case STRSCAN_I64: - case STRSCAN_U64: - o->u64 = neg ? (uint64_t)-(int64_t)x : x; - return fmt; - default: - break; - } - - /* Reduce range, then convert to double. */ - if ((x & U64x(c0000000,0000000))) { x = (x >> 2) | (x & 3); ex2 += 2; } - strscan_double(x, o, ex2, neg); - return fmt; -} - -/* Scan string containing a number. Returns format. Returns value in o. */ -StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt) -{ - int32_t neg = 0; - - /* Remove leading space, parse sign and non-numbers. */ - if (LJ_UNLIKELY(!lj_char_isdigit(*p))) { - while (lj_char_isspace(*p)) p++; - if (*p == '+' || *p == '-') neg = (*p++ == '-'); - if (LJ_UNLIKELY(*p >= 'A')) { /* Parse "inf", "infinity" or "nan". */ - TValue tmp; - setnanV(&tmp); - if (casecmp(p[0],'i') && casecmp(p[1],'n') && casecmp(p[2],'f')) { - if (neg) setminfV(&tmp); else setpinfV(&tmp); - p += 3; - if (casecmp(p[0],'i') && casecmp(p[1],'n') && casecmp(p[2],'i') && - casecmp(p[3],'t') && casecmp(p[4],'y')) p += 5; - } else if (casecmp(p[0],'n') && casecmp(p[1],'a') && casecmp(p[2],'n')) { - p += 3; - } - while (lj_char_isspace(*p)) p++; - if (*p) return STRSCAN_ERROR; - o->u64 = tmp.u64; - return STRSCAN_NUM; - } - } - - /* Parse regular number. */ - { - StrScanFmt fmt = STRSCAN_INT; - int cmask = LJ_CHAR_DIGIT; - int base = (opt & STRSCAN_OPT_C) && *p == '0' ? 0 : 10; - const uint8_t *sp, *dp = NULL; - uint32_t dig = 0, hasdig = 0, x = 0; - int32_t ex = 0; - - /* Determine base and skip leading zeros. */ - if (LJ_UNLIKELY(*p <= '0')) { - if (*p == '0') { - if (casecmp(p[1], 'x')) - base = 16, cmask = LJ_CHAR_XDIGIT, p += 2; - else if (casecmp(p[1], 'b')) - base = 2, cmask = LJ_CHAR_DIGIT, p += 2; - } - for ( ; ; p++) { - if (*p == '0') { - hasdig = 1; - } else if (*p == '.') { - if (dp) return STRSCAN_ERROR; - dp = p; - } else { - break; - } - } - } - - /* Preliminary digit and decimal point scan. */ - for (sp = p; ; p++) { - if (LJ_LIKELY(lj_char_isa(*p, cmask))) { - x = x * 10 + (*p & 15); /* For fast path below. */ - dig++; - } else if (*p == '.') { - if (dp) return STRSCAN_ERROR; - dp = p; - } else { - break; - } - } - if (!(hasdig | dig)) return STRSCAN_ERROR; - - /* Handle decimal point. */ - if (dp) { - fmt = STRSCAN_NUM; - if (dig) { - ex = (int32_t)(dp-(p-1)); dp = p-1; - while (ex < 0 && *dp-- == '0') ex++, dig--; /* Skip trailing zeros. */ - if (base == 16) ex *= 4; - } - } - - /* Parse exponent. */ - if (base >= 10 && casecmp(*p, (uint32_t)(base == 16 ? 'p' : 'e'))) { - uint32_t xx; - int negx = 0; - fmt = STRSCAN_NUM; p++; - if (*p == '+' || *p == '-') negx = (*p++ == '-'); - if (!lj_char_isdigit(*p)) return STRSCAN_ERROR; - xx = (*p++ & 15); - while (lj_char_isdigit(*p)) { - if (xx < 65536) xx = xx * 10 + (*p & 15); - p++; - } - ex += negx ? -(int32_t)xx : (int32_t)xx; - } - - /* Parse suffix. */ - if (*p) { - /* I (IMAG), U (U32), LL (I64), ULL/LLU (U64), L (long), UL/LU (ulong). */ - /* NYI: f (float). Not needed until cp_number() handles non-integers. */ - if (casecmp(*p, 'i')) { - if (!(opt & STRSCAN_OPT_IMAG)) return STRSCAN_ERROR; - p++; fmt = STRSCAN_IMAG; - } else if (fmt == STRSCAN_INT) { - if (casecmp(*p, 'u')) p++, fmt = STRSCAN_U32; - if (casecmp(*p, 'l')) { - p++; - if (casecmp(*p, 'l')) p++, fmt += STRSCAN_I64 - STRSCAN_INT; - else if (!(opt & STRSCAN_OPT_C)) return STRSCAN_ERROR; - else if (sizeof(long) == 8) fmt += STRSCAN_I64 - STRSCAN_INT; - } - if (casecmp(*p, 'u') && (fmt == STRSCAN_INT || fmt == STRSCAN_I64)) - p++, fmt += STRSCAN_U32 - STRSCAN_INT; - if ((fmt == STRSCAN_U32 && !(opt & STRSCAN_OPT_C)) || - (fmt >= STRSCAN_I64 && !(opt & STRSCAN_OPT_LL))) - return STRSCAN_ERROR; - } - while (lj_char_isspace(*p)) p++; - if (*p) return STRSCAN_ERROR; - } - - /* Fast path for decimal 32 bit integers. */ - if (fmt == STRSCAN_INT && base == 10 && - (dig < 10 || (dig == 10 && *sp <= '2' && x < 0x80000000u+neg))) { - int32_t y = neg ? -(int32_t)x : (int32_t)x; - if ((opt & STRSCAN_OPT_TONUM)) { - o->n = (double)y; - return STRSCAN_NUM; - } else { - o->i = y; - return STRSCAN_INT; - } - } - - /* Dispatch to base-specific parser. */ - if (base == 0 && !(fmt == STRSCAN_NUM || fmt == STRSCAN_IMAG)) - return strscan_oct(sp, o, fmt, neg, dig); - if (base == 16) - fmt = strscan_hex(sp, o, fmt, opt, ex, neg, dig); - else if (base == 2) - fmt = strscan_bin(sp, o, fmt, opt, ex, neg, dig); - else - fmt = strscan_dec(sp, o, fmt, opt, ex, neg, dig); - - /* Try to convert number to integer, if requested. */ - if (fmt == STRSCAN_NUM && (opt & STRSCAN_OPT_TOINT)) { - double n = o->n; - int32_t i = lj_num2int(n); - if (n == (lua_Number)i) { o->i = i; return STRSCAN_INT; } - } - return fmt; - } -} - -int LJ_FASTCALL lj_strscan_num(GCstr *str, TValue *o) -{ - StrScanFmt fmt = lj_strscan_scan((const uint8_t *)strdata(str), o, - STRSCAN_OPT_TONUM); - lua_assert(fmt == STRSCAN_ERROR || fmt == STRSCAN_NUM); - return (fmt != STRSCAN_ERROR); -} - -#if LJ_DUALNUM -int LJ_FASTCALL lj_strscan_number(GCstr *str, TValue *o) -{ - StrScanFmt fmt = lj_strscan_scan((const uint8_t *)strdata(str), o, - STRSCAN_OPT_TOINT); - lua_assert(fmt == STRSCAN_ERROR || fmt == STRSCAN_NUM || fmt == STRSCAN_INT); - if (fmt == STRSCAN_INT) setitype(o, LJ_TISNUM); - return (fmt != STRSCAN_ERROR); -} -#endif - -#undef DNEXT -#undef DPREV -#undef DLEN - diff --git a/lib/LuaJIT/src/lj_strscan.h b/lib/LuaJIT/src/lj_strscan.h deleted file mode 100644 index 6fb0dda..0000000 --- a/lib/LuaJIT/src/lj_strscan.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -** String scanning. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_STRSCAN_H -#define _LJ_STRSCAN_H - -#include "lj_obj.h" - -/* Options for accepted/returned formats. */ -#define STRSCAN_OPT_TOINT 0x01 /* Convert to int32_t, if possible. */ -#define STRSCAN_OPT_TONUM 0x02 /* Always convert to double. */ -#define STRSCAN_OPT_IMAG 0x04 -#define STRSCAN_OPT_LL 0x08 -#define STRSCAN_OPT_C 0x10 - -/* Returned format. */ -typedef enum { - STRSCAN_ERROR, - STRSCAN_NUM, STRSCAN_IMAG, - STRSCAN_INT, STRSCAN_U32, STRSCAN_I64, STRSCAN_U64, -} StrScanFmt; - -LJ_FUNC StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt); -LJ_FUNC int LJ_FASTCALL lj_strscan_num(GCstr *str, TValue *o); -#if LJ_DUALNUM -LJ_FUNC int LJ_FASTCALL lj_strscan_number(GCstr *str, TValue *o); -#else -#define lj_strscan_number(s, o) lj_strscan_num((s), (o)) -#endif - -/* Check for number or convert string to number/int in-place (!). */ -static LJ_AINLINE int lj_strscan_numberobj(TValue *o) -{ - return tvisnumber(o) || (tvisstr(o) && lj_strscan_number(strV(o), o)); -} - -#endif diff --git a/lib/LuaJIT/src/lj_tab.c b/lib/LuaJIT/src/lj_tab.c deleted file mode 100644 index c51666d..0000000 --- a/lib/LuaJIT/src/lj_tab.c +++ /dev/null @@ -1,688 +0,0 @@ -/* -** Table handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Major portions taken verbatim or adapted from the Lua interpreter. -** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h -*/ - -#define lj_tab_c -#define LUA_CORE - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_tab.h" - -/* -- Object hashing ------------------------------------------------------ */ - -/* Hash values are masked with the table hash mask and used as an index. */ -static LJ_AINLINE Node *hashmask(const GCtab *t, uint32_t hash) -{ - Node *n = noderef(t->node); - return &n[hash & t->hmask]; -} - -/* String hashes are precomputed when they are interned. */ -#define hashstr(t, s) hashmask(t, (s)->hash) - -#define hashlohi(t, lo, hi) hashmask((t), hashrot((lo), (hi))) -#define hashnum(t, o) hashlohi((t), (o)->u32.lo, ((o)->u32.hi << 1)) -#if LJ_GC64 -#define hashgcref(t, r) \ - hashlohi((t), (uint32_t)gcrefu(r), (uint32_t)(gcrefu(r) >> 32)) -#else -#define hashgcref(t, r) hashlohi((t), gcrefu(r), gcrefu(r) + HASH_BIAS) -#endif - -/* Hash an arbitrary key and return its anchor position in the hash table. */ -static Node *hashkey(const GCtab *t, cTValue *key) -{ - lua_assert(!tvisint(key)); - if (tvisstr(key)) - return hashstr(t, strV(key)); - else if (tvisnum(key)) - return hashnum(t, key); - else if (tvisbool(key)) - return hashmask(t, boolV(key)); - else - return hashgcref(t, key->gcr); - /* Only hash 32 bits of lightuserdata on a 64 bit CPU. Good enough? */ -} - -/* -- Table creation and destruction -------------------------------------- */ - -/* Create new hash part for table. */ -static LJ_AINLINE void newhpart(lua_State *L, GCtab *t, uint32_t hbits) -{ - uint32_t hsize; - Node *node; - lua_assert(hbits != 0); - if (hbits > LJ_MAX_HBITS) - lj_err_msg(L, LJ_ERR_TABOV); - hsize = 1u << hbits; - node = lj_mem_newvec(L, hsize, Node); - setmref(t->node, node); - setfreetop(t, node, &node[hsize]); - t->hmask = hsize-1; -} - -/* -** Q: Why all of these copies of t->hmask, t->node etc. to local variables? -** A: Because alias analysis for C is _really_ tough. -** Even state-of-the-art C compilers won't produce good code without this. -*/ - -/* Clear hash part of table. */ -static LJ_AINLINE void clearhpart(GCtab *t) -{ - uint32_t i, hmask = t->hmask; - Node *node = noderef(t->node); - lua_assert(t->hmask != 0); - for (i = 0; i <= hmask; i++) { - Node *n = &node[i]; - setmref(n->next, NULL); - setnilV(&n->key); - setnilV(&n->val); - } -} - -/* Clear array part of table. */ -static LJ_AINLINE void clearapart(GCtab *t) -{ - uint32_t i, asize = t->asize; - TValue *array = tvref(t->array); - for (i = 0; i < asize; i++) - setnilV(&array[i]); -} - -/* Create a new table. Note: the slots are not initialized (yet). */ -static GCtab *newtab(lua_State *L, uint32_t asize, uint32_t hbits) -{ - GCtab *t; - /* First try to colocate the array part. */ - if (LJ_MAX_COLOSIZE != 0 && asize > 0 && asize <= LJ_MAX_COLOSIZE) { - Node *nilnode; - lua_assert((sizeof(GCtab) & 7) == 0); - t = (GCtab *)lj_mem_newgco(L, sizetabcolo(asize)); - t->gct = ~LJ_TTAB; - t->nomm = (uint8_t)~0; - t->colo = (int8_t)asize; - setmref(t->array, (TValue *)((char *)t + sizeof(GCtab))); - setgcrefnull(t->metatable); - t->asize = asize; - t->hmask = 0; - nilnode = &G(L)->nilnode; - setmref(t->node, nilnode); -#if LJ_GC64 - setmref(t->freetop, nilnode); -#endif - } else { /* Otherwise separately allocate the array part. */ - Node *nilnode; - t = lj_mem_newobj(L, GCtab); - t->gct = ~LJ_TTAB; - t->nomm = (uint8_t)~0; - t->colo = 0; - setmref(t->array, NULL); - setgcrefnull(t->metatable); - t->asize = 0; /* In case the array allocation fails. */ - t->hmask = 0; - nilnode = &G(L)->nilnode; - setmref(t->node, nilnode); -#if LJ_GC64 - setmref(t->freetop, nilnode); -#endif - if (asize > 0) { - if (asize > LJ_MAX_ASIZE) - lj_err_msg(L, LJ_ERR_TABOV); - setmref(t->array, lj_mem_newvec(L, asize, TValue)); - t->asize = asize; - } - } - if (hbits) - newhpart(L, t, hbits); - return t; -} - -/* Create a new table. -** -** IMPORTANT NOTE: The API differs from lua_createtable()! -** -** The array size is non-inclusive. E.g. asize=128 creates array slots -** for 0..127, but not for 128. If you need slots 1..128, pass asize=129 -** (slot 0 is wasted in this case). -** -** The hash size is given in hash bits. hbits=0 means no hash part. -** hbits=1 creates 2 hash slots, hbits=2 creates 4 hash slots and so on. -*/ -GCtab *lj_tab_new(lua_State *L, uint32_t asize, uint32_t hbits) -{ - GCtab *t = newtab(L, asize, hbits); - clearapart(t); - if (t->hmask > 0) clearhpart(t); - return t; -} - -/* The API of this function conforms to lua_createtable(). */ -GCtab *lj_tab_new_ah(lua_State *L, int32_t a, int32_t h) -{ - return lj_tab_new(L, (uint32_t)(a > 0 ? a+1 : 0), hsize2hbits(h)); -} - -#if LJ_HASJIT -GCtab * LJ_FASTCALL lj_tab_new1(lua_State *L, uint32_t ahsize) -{ - GCtab *t = newtab(L, ahsize & 0xffffff, ahsize >> 24); - clearapart(t); - if (t->hmask > 0) clearhpart(t); - return t; -} -#endif - -/* Duplicate a table. */ -GCtab * LJ_FASTCALL lj_tab_dup(lua_State *L, const GCtab *kt) -{ - GCtab *t; - uint32_t asize, hmask; - t = newtab(L, kt->asize, kt->hmask > 0 ? lj_fls(kt->hmask)+1 : 0); - lua_assert(kt->asize == t->asize && kt->hmask == t->hmask); - t->nomm = 0; /* Keys with metamethod names may be present. */ - asize = kt->asize; - if (asize > 0) { - TValue *array = tvref(t->array); - TValue *karray = tvref(kt->array); - if (asize < 64) { /* An inlined loop beats memcpy for < 512 bytes. */ - uint32_t i; - for (i = 0; i < asize; i++) - copyTV(L, &array[i], &karray[i]); - } else { - memcpy(array, karray, asize*sizeof(TValue)); - } - } - hmask = kt->hmask; - if (hmask > 0) { - uint32_t i; - Node *node = noderef(t->node); - Node *knode = noderef(kt->node); - ptrdiff_t d = (char *)node - (char *)knode; - setfreetop(t, node, (Node *)((char *)getfreetop(kt, knode) + d)); - for (i = 0; i <= hmask; i++) { - Node *kn = &knode[i]; - Node *n = &node[i]; - Node *next = nextnode(kn); - /* Don't use copyTV here, since it asserts on a copy of a dead key. */ - n->val = kn->val; n->key = kn->key; - setmref(n->next, next == NULL? next : (Node *)((char *)next + d)); - } - } - return t; -} - -/* Clear a table. */ -void LJ_FASTCALL lj_tab_clear(GCtab *t) -{ - clearapart(t); - if (t->hmask > 0) { - Node *node = noderef(t->node); - setfreetop(t, node, &node[t->hmask+1]); - clearhpart(t); - } -} - -/* Free a table. */ -void LJ_FASTCALL lj_tab_free(global_State *g, GCtab *t) -{ - if (t->hmask > 0) - lj_mem_freevec(g, noderef(t->node), t->hmask+1, Node); - if (t->asize > 0 && LJ_MAX_COLOSIZE != 0 && t->colo <= 0) - lj_mem_freevec(g, tvref(t->array), t->asize, TValue); - if (LJ_MAX_COLOSIZE != 0 && t->colo) - lj_mem_free(g, t, sizetabcolo((uint32_t)t->colo & 0x7f)); - else - lj_mem_freet(g, t); -} - -/* -- Table resizing ------------------------------------------------------ */ - -/* Resize a table to fit the new array/hash part sizes. */ -void lj_tab_resize(lua_State *L, GCtab *t, uint32_t asize, uint32_t hbits) -{ - Node *oldnode = noderef(t->node); - uint32_t oldasize = t->asize; - uint32_t oldhmask = t->hmask; - if (asize > oldasize) { /* Array part grows? */ - TValue *array; - uint32_t i; - if (asize > LJ_MAX_ASIZE) - lj_err_msg(L, LJ_ERR_TABOV); - if (LJ_MAX_COLOSIZE != 0 && t->colo > 0) { - /* A colocated array must be separated and copied. */ - TValue *oarray = tvref(t->array); - array = lj_mem_newvec(L, asize, TValue); - t->colo = (int8_t)(t->colo | 0x80); /* Mark as separated (colo < 0). */ - for (i = 0; i < oldasize; i++) - copyTV(L, &array[i], &oarray[i]); - } else { - array = (TValue *)lj_mem_realloc(L, tvref(t->array), - oldasize*sizeof(TValue), asize*sizeof(TValue)); - } - setmref(t->array, array); - t->asize = asize; - for (i = oldasize; i < asize; i++) /* Clear newly allocated slots. */ - setnilV(&array[i]); - } - /* Create new (empty) hash part. */ - if (hbits) { - newhpart(L, t, hbits); - clearhpart(t); - } else { - global_State *g = G(L); - setmref(t->node, &g->nilnode); -#if LJ_GC64 - setmref(t->freetop, &g->nilnode); -#endif - t->hmask = 0; - } - if (asize < oldasize) { /* Array part shrinks? */ - TValue *array = tvref(t->array); - uint32_t i; - t->asize = asize; /* Note: This 'shrinks' even colocated arrays. */ - for (i = asize; i < oldasize; i++) /* Reinsert old array values. */ - if (!tvisnil(&array[i])) - copyTV(L, lj_tab_setinth(L, t, (int32_t)i), &array[i]); - /* Physically shrink only separated arrays. */ - if (LJ_MAX_COLOSIZE != 0 && t->colo <= 0) - setmref(t->array, lj_mem_realloc(L, array, - oldasize*sizeof(TValue), asize*sizeof(TValue))); - } - if (oldhmask > 0) { /* Reinsert pairs from old hash part. */ - global_State *g; - uint32_t i; - for (i = 0; i <= oldhmask; i++) { - Node *n = &oldnode[i]; - if (!tvisnil(&n->val)) - copyTV(L, lj_tab_set(L, t, &n->key), &n->val); - } - g = G(L); - lj_mem_freevec(g, oldnode, oldhmask+1, Node); - } -} - -static uint32_t countint(cTValue *key, uint32_t *bins) -{ - lua_assert(!tvisint(key)); - if (tvisnum(key)) { - lua_Number nk = numV(key); - int32_t k = lj_num2int(nk); - if ((uint32_t)k < LJ_MAX_ASIZE && nk == (lua_Number)k) { - bins[(k > 2 ? lj_fls((uint32_t)(k-1)) : 0)]++; - return 1; - } - } - return 0; -} - -static uint32_t countarray(const GCtab *t, uint32_t *bins) -{ - uint32_t na, b, i; - if (t->asize == 0) return 0; - for (na = i = b = 0; b < LJ_MAX_ABITS; b++) { - uint32_t n, top = 2u << b; - TValue *array; - if (top >= t->asize) { - top = t->asize-1; - if (i > top) - break; - } - array = tvref(t->array); - for (n = 0; i <= top; i++) - if (!tvisnil(&array[i])) - n++; - bins[b] += n; - na += n; - } - return na; -} - -static uint32_t counthash(const GCtab *t, uint32_t *bins, uint32_t *narray) -{ - uint32_t total, na, i, hmask = t->hmask; - Node *node = noderef(t->node); - for (total = na = 0, i = 0; i <= hmask; i++) { - Node *n = &node[i]; - if (!tvisnil(&n->val)) { - na += countint(&n->key, bins); - total++; - } - } - *narray += na; - return total; -} - -static uint32_t bestasize(uint32_t bins[], uint32_t *narray) -{ - uint32_t b, sum, na = 0, sz = 0, nn = *narray; - for (b = 0, sum = 0; 2*nn > (1u< 0 && 2*(sum += bins[b]) > (1u<hmask > 0 ? lj_fls(t->hmask)+1 : 0); -} - -/* -- Table getters ------------------------------------------------------- */ - -cTValue * LJ_FASTCALL lj_tab_getinth(GCtab *t, int32_t key) -{ - TValue k; - Node *n; - k.n = (lua_Number)key; - n = hashnum(t, &k); - do { - if (tvisnum(&n->key) && n->key.n == k.n) - return &n->val; - } while ((n = nextnode(n))); - return NULL; -} - -cTValue *lj_tab_getstr(GCtab *t, GCstr *key) -{ - Node *n = hashstr(t, key); - do { - if (tvisstr(&n->key) && strV(&n->key) == key) - return &n->val; - } while ((n = nextnode(n))); - return NULL; -} - -cTValue *lj_tab_get(lua_State *L, GCtab *t, cTValue *key) -{ - if (tvisstr(key)) { - cTValue *tv = lj_tab_getstr(t, strV(key)); - if (tv) - return tv; - } else if (tvisint(key)) { - cTValue *tv = lj_tab_getint(t, intV(key)); - if (tv) - return tv; - } else if (tvisnum(key)) { - lua_Number nk = numV(key); - int32_t k = lj_num2int(nk); - if (nk == (lua_Number)k) { - cTValue *tv = lj_tab_getint(t, k); - if (tv) - return tv; - } else { - goto genlookup; /* Else use the generic lookup. */ - } - } else if (!tvisnil(key)) { - Node *n; - genlookup: - n = hashkey(t, key); - do { - if (lj_obj_equal(&n->key, key)) - return &n->val; - } while ((n = nextnode(n))); - } - return niltv(L); -} - -/* -- Table setters ------------------------------------------------------- */ - -/* Insert new key. Use Brent's variation to optimize the chain length. */ -TValue *lj_tab_newkey(lua_State *L, GCtab *t, cTValue *key) -{ - Node *n = hashkey(t, key); - if (!tvisnil(&n->val) || t->hmask == 0) { - Node *nodebase = noderef(t->node); - Node *collide, *freenode = getfreetop(t, nodebase); - lua_assert(freenode >= nodebase && freenode <= nodebase+t->hmask+1); - do { - if (freenode == nodebase) { /* No free node found? */ - rehashtab(L, t, key); /* Rehash table. */ - return lj_tab_set(L, t, key); /* Retry key insertion. */ - } - } while (!tvisnil(&(--freenode)->key)); - setfreetop(t, nodebase, freenode); - lua_assert(freenode != &G(L)->nilnode); - collide = hashkey(t, &n->key); - if (collide != n) { /* Colliding node not the main node? */ - while (noderef(collide->next) != n) /* Find predecessor. */ - collide = nextnode(collide); - setmref(collide->next, freenode); /* Relink chain. */ - /* Copy colliding node into free node and free main node. */ - freenode->val = n->val; - freenode->key = n->key; - freenode->next = n->next; - setmref(n->next, NULL); - setnilV(&n->val); - /* Rechain pseudo-resurrected string keys with colliding hashes. */ - while (nextnode(freenode)) { - Node *nn = nextnode(freenode); - if (tvisstr(&nn->key) && !tvisnil(&nn->val) && - hashstr(t, strV(&nn->key)) == n) { - freenode->next = nn->next; - nn->next = n->next; - setmref(n->next, nn); - /* - ** Rechaining a resurrected string key creates a new dilemma: - ** Another string key may have originally been resurrected via - ** _any_ of the previous nodes as a chain anchor. Including - ** a node that had to be moved, which makes them unreachable. - ** It's not feasible to check for all previous nodes, so rechain - ** any string key that's currently in a non-main positions. - */ - while ((nn = nextnode(freenode))) { - if (tvisstr(&nn->key) && !tvisnil(&nn->val)) { - Node *mn = hashstr(t, strV(&nn->key)); - if (mn != freenode) { - freenode->next = nn->next; - nn->next = mn->next; - setmref(mn->next, nn); - } else { - freenode = nn; - } - } else { - freenode = nn; - } - } - break; - } else { - freenode = nn; - } - } - } else { /* Otherwise use free node. */ - setmrefr(freenode->next, n->next); /* Insert into chain. */ - setmref(n->next, freenode); - n = freenode; - } - } - n->key.u64 = key->u64; - if (LJ_UNLIKELY(tvismzero(&n->key))) - n->key.u64 = 0; - lj_gc_anybarriert(L, t); - lua_assert(tvisnil(&n->val)); - return &n->val; -} - -TValue *lj_tab_setinth(lua_State *L, GCtab *t, int32_t key) -{ - TValue k; - Node *n; - k.n = (lua_Number)key; - n = hashnum(t, &k); - do { - if (tvisnum(&n->key) && n->key.n == k.n) - return &n->val; - } while ((n = nextnode(n))); - return lj_tab_newkey(L, t, &k); -} - -TValue *lj_tab_setstr(lua_State *L, GCtab *t, GCstr *key) -{ - TValue k; - Node *n = hashstr(t, key); - do { - if (tvisstr(&n->key) && strV(&n->key) == key) - return &n->val; - } while ((n = nextnode(n))); - setstrV(L, &k, key); - return lj_tab_newkey(L, t, &k); -} - -TValue *lj_tab_set(lua_State *L, GCtab *t, cTValue *key) -{ - Node *n; - t->nomm = 0; /* Invalidate negative metamethod cache. */ - if (tvisstr(key)) { - return lj_tab_setstr(L, t, strV(key)); - } else if (tvisint(key)) { - return lj_tab_setint(L, t, intV(key)); - } else if (tvisnum(key)) { - lua_Number nk = numV(key); - int32_t k = lj_num2int(nk); - if (nk == (lua_Number)k) - return lj_tab_setint(L, t, k); - if (tvisnan(key)) - lj_err_msg(L, LJ_ERR_NANIDX); - /* Else use the generic lookup. */ - } else if (tvisnil(key)) { - lj_err_msg(L, LJ_ERR_NILIDX); - } - n = hashkey(t, key); - do { - if (lj_obj_equal(&n->key, key)) - return &n->val; - } while ((n = nextnode(n))); - return lj_tab_newkey(L, t, key); -} - -/* -- Table traversal ----------------------------------------------------- */ - -/* Get the traversal index of a key. */ -static uint32_t keyindex(lua_State *L, GCtab *t, cTValue *key) -{ - TValue tmp; - if (tvisint(key)) { - int32_t k = intV(key); - if ((uint32_t)k < t->asize) - return (uint32_t)k; /* Array key indexes: [0..t->asize-1] */ - setnumV(&tmp, (lua_Number)k); - key = &tmp; - } else if (tvisnum(key)) { - lua_Number nk = numV(key); - int32_t k = lj_num2int(nk); - if ((uint32_t)k < t->asize && nk == (lua_Number)k) - return (uint32_t)k; /* Array key indexes: [0..t->asize-1] */ - } - if (!tvisnil(key)) { - Node *n = hashkey(t, key); - do { - if (lj_obj_equal(&n->key, key)) - return t->asize + (uint32_t)(n - noderef(t->node)); - /* Hash key indexes: [t->asize..t->asize+t->nmask] */ - } while ((n = nextnode(n))); - if (key->u32.hi == 0xfffe7fff) /* ITERN was despecialized while running. */ - return key->u32.lo - 1; - lj_err_msg(L, LJ_ERR_NEXTIDX); - return 0; /* unreachable */ - } - return ~0u; /* A nil key starts the traversal. */ -} - -/* Advance to the next step in a table traversal. */ -int lj_tab_next(lua_State *L, GCtab *t, TValue *key) -{ - uint32_t i = keyindex(L, t, key); /* Find predecessor key index. */ - for (i++; i < t->asize; i++) /* First traverse the array keys. */ - if (!tvisnil(arrayslot(t, i))) { - setintV(key, i); - copyTV(L, key+1, arrayslot(t, i)); - return 1; - } - for (i -= t->asize; i <= t->hmask; i++) { /* Then traverse the hash keys. */ - Node *n = &noderef(t->node)[i]; - if (!tvisnil(&n->val)) { - copyTV(L, key, &n->key); - copyTV(L, key+1, &n->val); - return 1; - } - } - return 0; /* End of traversal. */ -} - -/* -- Table length calculation -------------------------------------------- */ - -static MSize unbound_search(GCtab *t, MSize j) -{ - cTValue *tv; - MSize i = j; /* i is zero or a present index */ - j++; - /* find `i' and `j' such that i is present and j is not */ - while ((tv = lj_tab_getint(t, (int32_t)j)) && !tvisnil(tv)) { - i = j; - j *= 2; - if (j > (MSize)(INT_MAX-2)) { /* overflow? */ - /* table was built with bad purposes: resort to linear search */ - i = 1; - while ((tv = lj_tab_getint(t, (int32_t)i)) && !tvisnil(tv)) i++; - return i - 1; - } - } - /* now do a binary search between them */ - while (j - i > 1) { - MSize m = (i+j)/2; - cTValue *tvb = lj_tab_getint(t, (int32_t)m); - if (tvb && !tvisnil(tvb)) i = m; else j = m; - } - return i; -} - -/* -** Try to find a boundary in table `t'. A `boundary' is an integer index -** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). -*/ -MSize LJ_FASTCALL lj_tab_len(GCtab *t) -{ - MSize j = (MSize)t->asize; - if (j > 1 && tvisnil(arrayslot(t, j-1))) { - MSize i = 1; - while (j - i > 1) { - MSize m = (i+j)/2; - if (tvisnil(arrayslot(t, m-1))) j = m; else i = m; - } - return i-1; - } - if (j) j--; - if (t->hmask <= 0) - return j; - return unbound_search(t, j); -} - diff --git a/lib/LuaJIT/src/lj_tab.h b/lib/LuaJIT/src/lj_tab.h deleted file mode 100644 index 71e3494..0000000 --- a/lib/LuaJIT/src/lj_tab.h +++ /dev/null @@ -1,73 +0,0 @@ -/* -** Table handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_TAB_H -#define _LJ_TAB_H - -#include "lj_obj.h" - -/* Hash constants. Tuned using a brute force search. */ -#define HASH_BIAS (-0x04c11db7) -#define HASH_ROT1 14 -#define HASH_ROT2 5 -#define HASH_ROT3 13 - -/* Scramble the bits of numbers and pointers. */ -static LJ_AINLINE uint32_t hashrot(uint32_t lo, uint32_t hi) -{ -#if LJ_TARGET_X86ORX64 - /* Prefer variant that compiles well for a 2-operand CPU. */ - lo ^= hi; hi = lj_rol(hi, HASH_ROT1); - lo -= hi; hi = lj_rol(hi, HASH_ROT2); - hi ^= lo; hi -= lj_rol(lo, HASH_ROT3); -#else - lo ^= hi; - lo = lo - lj_rol(hi, HASH_ROT1); - hi = lo ^ lj_rol(hi, HASH_ROT1 + HASH_ROT2); - hi = hi - lj_rol(lo, HASH_ROT3); -#endif - return hi; -} - -#define hsize2hbits(s) ((s) ? ((s)==1 ? 1 : 1+lj_fls((uint32_t)((s)-1))) : 0) - -LJ_FUNCA GCtab *lj_tab_new(lua_State *L, uint32_t asize, uint32_t hbits); -LJ_FUNC GCtab *lj_tab_new_ah(lua_State *L, int32_t a, int32_t h); -#if LJ_HASJIT -LJ_FUNC GCtab * LJ_FASTCALL lj_tab_new1(lua_State *L, uint32_t ahsize); -#endif -LJ_FUNCA GCtab * LJ_FASTCALL lj_tab_dup(lua_State *L, const GCtab *kt); -LJ_FUNC void LJ_FASTCALL lj_tab_clear(GCtab *t); -LJ_FUNC void LJ_FASTCALL lj_tab_free(global_State *g, GCtab *t); -#if LJ_HASFFI -LJ_FUNC void lj_tab_rehash(lua_State *L, GCtab *t); -#endif -LJ_FUNC void lj_tab_resize(lua_State *L, GCtab *t, uint32_t asize, uint32_t hbits); -LJ_FUNCA void lj_tab_reasize(lua_State *L, GCtab *t, uint32_t nasize); - -/* Caveat: all getters except lj_tab_get() can return NULL! */ - -LJ_FUNCA cTValue * LJ_FASTCALL lj_tab_getinth(GCtab *t, int32_t key); -LJ_FUNC cTValue *lj_tab_getstr(GCtab *t, GCstr *key); -LJ_FUNCA cTValue *lj_tab_get(lua_State *L, GCtab *t, cTValue *key); - -/* Caveat: all setters require a write barrier for the stored value. */ - -LJ_FUNCA TValue *lj_tab_newkey(lua_State *L, GCtab *t, cTValue *key); -LJ_FUNCA TValue *lj_tab_setinth(lua_State *L, GCtab *t, int32_t key); -LJ_FUNC TValue *lj_tab_setstr(lua_State *L, GCtab *t, GCstr *key); -LJ_FUNC TValue *lj_tab_set(lua_State *L, GCtab *t, cTValue *key); - -#define inarray(t, key) ((MSize)(key) < (MSize)(t)->asize) -#define arrayslot(t, i) (&tvref((t)->array)[(i)]) -#define lj_tab_getint(t, key) \ - (inarray((t), (key)) ? arrayslot((t), (key)) : lj_tab_getinth((t), (key))) -#define lj_tab_setint(L, t, key) \ - (inarray((t), (key)) ? arrayslot((t), (key)) : lj_tab_setinth(L, (t), (key))) - -LJ_FUNCA int lj_tab_next(lua_State *L, GCtab *t, TValue *key); -LJ_FUNCA MSize LJ_FASTCALL lj_tab_len(GCtab *t); - -#endif diff --git a/lib/LuaJIT/src/lj_target.h b/lib/LuaJIT/src/lj_target.h deleted file mode 100644 index 8dcae95..0000000 --- a/lib/LuaJIT/src/lj_target.h +++ /dev/null @@ -1,164 +0,0 @@ -/* -** Definitions for target CPU. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_TARGET_H -#define _LJ_TARGET_H - -#include "lj_def.h" -#include "lj_arch.h" - -/* -- Registers and spill slots ------------------------------------------- */ - -/* Register type (uint8_t in ir->r). */ -typedef uint32_t Reg; - -/* The hi-bit is NOT set for an allocated register. This means the value -** can be directly used without masking. The hi-bit is set for a register -** allocation hint or for RID_INIT, RID_SINK or RID_SUNK. -*/ -#define RID_NONE 0x80 -#define RID_MASK 0x7f -#define RID_INIT (RID_NONE|RID_MASK) -#define RID_SINK (RID_INIT-1) -#define RID_SUNK (RID_INIT-2) - -#define ra_noreg(r) ((r) & RID_NONE) -#define ra_hasreg(r) (!((r) & RID_NONE)) - -/* The ra_hashint() macro assumes a previous test for ra_noreg(). */ -#define ra_hashint(r) ((r) < RID_SUNK) -#define ra_gethint(r) ((Reg)((r) & RID_MASK)) -#define ra_sethint(rr, r) rr = (uint8_t)((r)|RID_NONE) -#define ra_samehint(r1, r2) (ra_gethint((r1)^(r2)) == 0) - -/* Spill slot 0 means no spill slot has been allocated. */ -#define SPS_NONE 0 - -#define ra_hasspill(s) ((s) != SPS_NONE) - -/* Combined register and spill slot (uint16_t in ir->prev). */ -typedef uint32_t RegSP; - -#define REGSP(r, s) ((r) + ((s) << 8)) -#define REGSP_HINT(r) ((r)|RID_NONE) -#define REGSP_INIT REGSP(RID_INIT, 0) - -#define regsp_reg(rs) ((rs) & 255) -#define regsp_spill(rs) ((rs) >> 8) -#define regsp_used(rs) \ - (((rs) & ~REGSP(RID_MASK, 0)) != REGSP(RID_NONE, 0)) - -/* -- Register sets ------------------------------------------------------- */ - -/* Bitset for registers. 32 registers suffice for most architectures. -** Note that one set holds bits for both GPRs and FPRs. -*/ -#if LJ_TARGET_PPC || LJ_TARGET_MIPS || LJ_TARGET_ARM64 -typedef uint64_t RegSet; -#else -typedef uint32_t RegSet; -#endif - -#define RID2RSET(r) (((RegSet)1) << (r)) -#define RSET_EMPTY ((RegSet)0) -#define RSET_RANGE(lo, hi) ((RID2RSET((hi)-(lo))-1) << (lo)) - -#define rset_test(rs, r) ((int)((rs) >> (r)) & 1) -#define rset_set(rs, r) (rs |= RID2RSET(r)) -#define rset_clear(rs, r) (rs &= ~RID2RSET(r)) -#define rset_exclude(rs, r) (rs & ~RID2RSET(r)) -#if LJ_TARGET_PPC || LJ_TARGET_MIPS || LJ_TARGET_ARM64 -#define rset_picktop(rs) ((Reg)(__builtin_clzll(rs)^63)) -#define rset_pickbot(rs) ((Reg)__builtin_ctzll(rs)) -#else -#define rset_picktop(rs) ((Reg)lj_fls(rs)) -#define rset_pickbot(rs) ((Reg)lj_ffs(rs)) -#endif - -/* -- Register allocation cost -------------------------------------------- */ - -/* The register allocation heuristic keeps track of the cost for allocating -** a specific register: -** -** A free register (obviously) has a cost of 0 and a 1-bit in the free mask. -** -** An already allocated register has the (non-zero) IR reference in the lowest -** bits and the result of a blended cost-model in the higher bits. -** -** The allocator first checks the free mask for a hit. Otherwise an (unrolled) -** linear search for the minimum cost is used. The search doesn't need to -** keep track of the position of the minimum, which makes it very fast. -** The lowest bits of the minimum cost show the desired IR reference whose -** register is the one to evict. -** -** Without the cost-model this degenerates to the standard heuristics for -** (reverse) linear-scan register allocation. Since code generation is done -** in reverse, a live interval extends from the last use to the first def. -** For an SSA IR the IR reference is the first (and only) def and thus -** trivially marks the end of the interval. The LSRA heuristics says to pick -** the register whose live interval has the furthest extent, i.e. the lowest -** IR reference in our case. -** -** A cost-model should take into account other factors, like spill-cost and -** restore- or rematerialization-cost, which depend on the kind of instruction. -** E.g. constants have zero spill costs, variant instructions have higher -** costs than invariants and PHIs should preferably never be spilled. -** -** Here's a first cut at simple, but effective blended cost-model for R-LSRA: -** - Due to careful design of the IR, constants already have lower IR -** references than invariants and invariants have lower IR references -** than variants. -** - The cost in the upper 16 bits is the sum of the IR reference and a -** weighted score. The score currently only takes into account whether -** the IRT_ISPHI bit is set in the instruction type. -** - The PHI weight is the minimum distance (in IR instructions) a PHI -** reference has to be further apart from a non-PHI reference to be spilled. -** - It should be a power of two (for speed) and must be between 2 and 32768. -** Good values for the PHI weight seem to be between 40 and 150. -** - Further study is required. -*/ -#define REGCOST_PHI_WEIGHT 64 - -/* Cost for allocating a specific register. */ -typedef uint32_t RegCost; - -/* Note: assumes 16 bit IRRef1. */ -#define REGCOST(cost, ref) ((RegCost)(ref) + ((RegCost)(cost) << 16)) -#define regcost_ref(rc) ((IRRef1)(rc)) - -#define REGCOST_T(t) \ - ((RegCost)((t)&IRT_ISPHI) * (((RegCost)(REGCOST_PHI_WEIGHT)<<16)/IRT_ISPHI)) -#define REGCOST_REF_T(ref, t) (REGCOST((ref), (ref)) + REGCOST_T((t))) - -/* -- Target-specific definitions ----------------------------------------- */ - -#if LJ_TARGET_X86ORX64 -#include "lj_target_x86.h" -#elif LJ_TARGET_ARM -#include "lj_target_arm.h" -#elif LJ_TARGET_ARM64 -#include "lj_target_arm64.h" -#elif LJ_TARGET_PPC -#include "lj_target_ppc.h" -#elif LJ_TARGET_MIPS -#include "lj_target_mips.h" -#else -#error "Missing include for target CPU" -#endif - -#ifdef EXITSTUBS_PER_GROUP -/* Return the address of an exit stub. */ -static LJ_AINLINE char *exitstub_addr_(char **group, uint32_t exitno) -{ - lua_assert(group[exitno / EXITSTUBS_PER_GROUP] != NULL); - return (char *)group[exitno / EXITSTUBS_PER_GROUP] + - EXITSTUB_SPACING*(exitno % EXITSTUBS_PER_GROUP); -} -/* Avoid dependence on lj_jit.h if only including lj_target.h. */ -#define exitstub_addr(J, exitno) \ - ((MCode *)exitstub_addr_((char **)((J)->exitstubgroup), (exitno))) -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_target_arm.h b/lib/LuaJIT/src/lj_target_arm.h deleted file mode 100644 index 5551b1f..0000000 --- a/lib/LuaJIT/src/lj_target_arm.h +++ /dev/null @@ -1,270 +0,0 @@ -/* -** Definitions for ARM CPUs. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_TARGET_ARM_H -#define _LJ_TARGET_ARM_H - -/* -- Registers IDs ------------------------------------------------------- */ - -#define GPRDEF(_) \ - _(R0) _(R1) _(R2) _(R3) _(R4) _(R5) _(R6) _(R7) \ - _(R8) _(R9) _(R10) _(R11) _(R12) _(SP) _(LR) _(PC) -#if LJ_SOFTFP -#define FPRDEF(_) -#else -#define FPRDEF(_) \ - _(D0) _(D1) _(D2) _(D3) _(D4) _(D5) _(D6) _(D7) \ - _(D8) _(D9) _(D10) _(D11) _(D12) _(D13) _(D14) _(D15) -#endif -#define VRIDDEF(_) - -#define RIDENUM(name) RID_##name, - -enum { - GPRDEF(RIDENUM) /* General-purpose registers (GPRs). */ - FPRDEF(RIDENUM) /* Floating-point registers (FPRs). */ - RID_MAX, - RID_TMP = RID_LR, - - /* Calling conventions. */ - RID_RET = RID_R0, - RID_RETLO = RID_R0, - RID_RETHI = RID_R1, -#if LJ_SOFTFP - RID_FPRET = RID_R0, -#else - RID_FPRET = RID_D0, -#endif - - /* These definitions must match with the *.dasc file(s): */ - RID_BASE = RID_R9, /* Interpreter BASE. */ - RID_LPC = RID_R6, /* Interpreter PC. */ - RID_DISPATCH = RID_R7, /* Interpreter DISPATCH table. */ - RID_LREG = RID_R8, /* Interpreter L. */ - - /* Register ranges [min, max) and number of registers. */ - RID_MIN_GPR = RID_R0, - RID_MAX_GPR = RID_PC+1, - RID_MIN_FPR = RID_MAX_GPR, -#if LJ_SOFTFP - RID_MAX_FPR = RID_MIN_FPR, -#else - RID_MAX_FPR = RID_D15+1, -#endif - RID_NUM_GPR = RID_MAX_GPR - RID_MIN_GPR, - RID_NUM_FPR = RID_MAX_FPR - RID_MIN_FPR -}; - -#define RID_NUM_KREF RID_NUM_GPR -#define RID_MIN_KREF RID_R0 - -/* -- Register sets ------------------------------------------------------- */ - -/* Make use of all registers, except sp, lr and pc. */ -#define RSET_GPR (RSET_RANGE(RID_MIN_GPR, RID_R12+1)) -#define RSET_GPREVEN \ - (RID2RSET(RID_R0)|RID2RSET(RID_R2)|RID2RSET(RID_R4)|RID2RSET(RID_R6)| \ - RID2RSET(RID_R8)|RID2RSET(RID_R10)) -#define RSET_GPRODD \ - (RID2RSET(RID_R1)|RID2RSET(RID_R3)|RID2RSET(RID_R5)|RID2RSET(RID_R7)| \ - RID2RSET(RID_R9)|RID2RSET(RID_R11)) -#if LJ_SOFTFP -#define RSET_FPR 0 -#else -#define RSET_FPR (RSET_RANGE(RID_MIN_FPR, RID_MAX_FPR)) -#endif -#define RSET_ALL (RSET_GPR|RSET_FPR) -#define RSET_INIT RSET_ALL - -/* ABI-specific register sets. lr is an implicit scratch register. */ -#define RSET_SCRATCH_GPR_ (RSET_RANGE(RID_R0, RID_R3+1)|RID2RSET(RID_R12)) -#ifdef __APPLE__ -#define RSET_SCRATCH_GPR (RSET_SCRATCH_GPR_|RID2RSET(RID_R9)) -#else -#define RSET_SCRATCH_GPR RSET_SCRATCH_GPR_ -#endif -#if LJ_SOFTFP -#define RSET_SCRATCH_FPR 0 -#else -#define RSET_SCRATCH_FPR (RSET_RANGE(RID_D0, RID_D7+1)) -#endif -#define RSET_SCRATCH (RSET_SCRATCH_GPR|RSET_SCRATCH_FPR) -#define REGARG_FIRSTGPR RID_R0 -#define REGARG_LASTGPR RID_R3 -#define REGARG_NUMGPR 4 -#if LJ_ABI_SOFTFP -#define REGARG_FIRSTFPR 0 -#define REGARG_LASTFPR 0 -#define REGARG_NUMFPR 0 -#else -#define REGARG_FIRSTFPR RID_D0 -#define REGARG_LASTFPR RID_D7 -#define REGARG_NUMFPR 8 -#endif - -/* -- Spill slots --------------------------------------------------------- */ - -/* Spill slots are 32 bit wide. An even/odd pair is used for FPRs. -** -** SPS_FIXED: Available fixed spill slots in interpreter frame. -** This definition must match with the *.dasc file(s). -** -** SPS_FIRST: First spill slot for general use. Reserve min. two 32 bit slots. -*/ -#define SPS_FIXED 2 -#define SPS_FIRST 2 - -#define SPOFS_TMP 0 - -#define sps_scale(slot) (4 * (int32_t)(slot)) -#define sps_align(slot) (((slot) - SPS_FIXED + 1) & ~1) - -/* -- Exit state ---------------------------------------------------------- */ - -/* This definition must match with the *.dasc file(s). */ -typedef struct { -#if !LJ_SOFTFP - lua_Number fpr[RID_NUM_FPR]; /* Floating-point registers. */ -#endif - int32_t gpr[RID_NUM_GPR]; /* General-purpose registers. */ - int32_t spill[256]; /* Spill slots. */ -} ExitState; - -/* PC after instruction that caused an exit. Used to find the trace number. */ -#define EXITSTATE_PCREG RID_PC -/* Highest exit + 1 indicates stack check. */ -#define EXITSTATE_CHECKEXIT 1 - -#define EXITSTUB_SPACING 4 -#define EXITSTUBS_PER_GROUP 32 - -/* -- Instructions -------------------------------------------------------- */ - -/* Instruction fields. */ -#define ARMF_CC(ai, cc) (((ai) ^ ARMI_CCAL) | ((cc) << 28)) -#define ARMF_N(r) ((r) << 16) -#define ARMF_D(r) ((r) << 12) -#define ARMF_S(r) ((r) << 8) -#define ARMF_M(r) (r) -#define ARMF_SH(sh, n) (((sh) << 5) | ((n) << 7)) -#define ARMF_RSH(sh, r) (0x10 | ((sh) << 5) | ARMF_S(r)) - -typedef enum ARMIns { - ARMI_CCAL = 0xe0000000, - ARMI_S = 0x000100000, - ARMI_K12 = 0x02000000, - ARMI_KNEG = 0x00200000, - ARMI_LS_W = 0x00200000, - ARMI_LS_U = 0x00800000, - ARMI_LS_P = 0x01000000, - ARMI_LS_R = 0x02000000, - ARMI_LSX_I = 0x00400000, - - ARMI_AND = 0xe0000000, - ARMI_EOR = 0xe0200000, - ARMI_SUB = 0xe0400000, - ARMI_RSB = 0xe0600000, - ARMI_ADD = 0xe0800000, - ARMI_ADC = 0xe0a00000, - ARMI_SBC = 0xe0c00000, - ARMI_RSC = 0xe0e00000, - ARMI_TST = 0xe1100000, - ARMI_TEQ = 0xe1300000, - ARMI_CMP = 0xe1500000, - ARMI_CMN = 0xe1700000, - ARMI_ORR = 0xe1800000, - ARMI_MOV = 0xe1a00000, - ARMI_BIC = 0xe1c00000, - ARMI_MVN = 0xe1e00000, - - ARMI_NOP = 0xe1a00000, - - ARMI_MUL = 0xe0000090, - ARMI_SMULL = 0xe0c00090, - - ARMI_LDR = 0xe4100000, - ARMI_LDRB = 0xe4500000, - ARMI_LDRH = 0xe01000b0, - ARMI_LDRSB = 0xe01000d0, - ARMI_LDRSH = 0xe01000f0, - ARMI_LDRD = 0xe00000d0, - ARMI_STR = 0xe4000000, - ARMI_STRB = 0xe4400000, - ARMI_STRH = 0xe00000b0, - ARMI_STRD = 0xe00000f0, - ARMI_PUSH = 0xe92d0000, - - ARMI_B = 0xea000000, - ARMI_BL = 0xeb000000, - ARMI_BLX = 0xfa000000, - ARMI_BLXr = 0xe12fff30, - - /* ARMv6 */ - ARMI_REV = 0xe6bf0f30, - ARMI_SXTB = 0xe6af0070, - ARMI_SXTH = 0xe6bf0070, - ARMI_UXTB = 0xe6ef0070, - ARMI_UXTH = 0xe6ff0070, - - /* ARMv6T2 */ - ARMI_MOVW = 0xe3000000, - ARMI_MOVT = 0xe3400000, - - /* VFP */ - ARMI_VMOV_D = 0xeeb00b40, - ARMI_VMOV_S = 0xeeb00a40, - ARMI_VMOVI_D = 0xeeb00b00, - - ARMI_VMOV_R_S = 0xee100a10, - ARMI_VMOV_S_R = 0xee000a10, - ARMI_VMOV_RR_D = 0xec500b10, - ARMI_VMOV_D_RR = 0xec400b10, - - ARMI_VADD_D = 0xee300b00, - ARMI_VSUB_D = 0xee300b40, - ARMI_VMUL_D = 0xee200b00, - ARMI_VMLA_D = 0xee000b00, - ARMI_VMLS_D = 0xee000b40, - ARMI_VNMLS_D = 0xee100b00, - ARMI_VDIV_D = 0xee800b00, - - ARMI_VABS_D = 0xeeb00bc0, - ARMI_VNEG_D = 0xeeb10b40, - ARMI_VSQRT_D = 0xeeb10bc0, - - ARMI_VCMP_D = 0xeeb40b40, - ARMI_VCMPZ_D = 0xeeb50b40, - - ARMI_VMRS = 0xeef1fa10, - - ARMI_VCVT_S32_F32 = 0xeebd0ac0, - ARMI_VCVT_S32_F64 = 0xeebd0bc0, - ARMI_VCVT_U32_F32 = 0xeebc0ac0, - ARMI_VCVT_U32_F64 = 0xeebc0bc0, - ARMI_VCVT_F32_S32 = 0xeeb80ac0, - ARMI_VCVT_F64_S32 = 0xeeb80bc0, - ARMI_VCVT_F32_U32 = 0xeeb80a40, - ARMI_VCVT_F64_U32 = 0xeeb80b40, - ARMI_VCVT_F32_F64 = 0xeeb70bc0, - ARMI_VCVT_F64_F32 = 0xeeb70ac0, - - ARMI_VLDR_S = 0xed100a00, - ARMI_VLDR_D = 0xed100b00, - ARMI_VSTR_S = 0xed000a00, - ARMI_VSTR_D = 0xed000b00, -} ARMIns; - -typedef enum ARMShift { - ARMSH_LSL, ARMSH_LSR, ARMSH_ASR, ARMSH_ROR -} ARMShift; - -/* ARM condition codes. */ -typedef enum ARMCC { - CC_EQ, CC_NE, CC_CS, CC_CC, CC_MI, CC_PL, CC_VS, CC_VC, - CC_HI, CC_LS, CC_GE, CC_LT, CC_GT, CC_LE, CC_AL, - CC_HS = CC_CS, CC_LO = CC_CC -} ARMCC; - -#endif diff --git a/lib/LuaJIT/src/lj_target_arm64.h b/lib/LuaJIT/src/lj_target_arm64.h deleted file mode 100644 index a207a2b..0000000 --- a/lib/LuaJIT/src/lj_target_arm64.h +++ /dev/null @@ -1,332 +0,0 @@ -/* -** Definitions for ARM64 CPUs. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_TARGET_ARM64_H -#define _LJ_TARGET_ARM64_H - -/* -- Registers IDs ------------------------------------------------------- */ - -#define GPRDEF(_) \ - _(X0) _(X1) _(X2) _(X3) _(X4) _(X5) _(X6) _(X7) \ - _(X8) _(X9) _(X10) _(X11) _(X12) _(X13) _(X14) _(X15) \ - _(X16) _(X17) _(X18) _(X19) _(X20) _(X21) _(X22) _(X23) \ - _(X24) _(X25) _(X26) _(X27) _(X28) _(FP) _(LR) _(SP) -#define FPRDEF(_) \ - _(D0) _(D1) _(D2) _(D3) _(D4) _(D5) _(D6) _(D7) \ - _(D8) _(D9) _(D10) _(D11) _(D12) _(D13) _(D14) _(D15) \ - _(D16) _(D17) _(D18) _(D19) _(D20) _(D21) _(D22) _(D23) \ - _(D24) _(D25) _(D26) _(D27) _(D28) _(D29) _(D30) _(D31) -#define VRIDDEF(_) - -#define RIDENUM(name) RID_##name, - -enum { - GPRDEF(RIDENUM) /* General-purpose registers (GPRs). */ - FPRDEF(RIDENUM) /* Floating-point registers (FPRs). */ - RID_MAX, - RID_TMP = RID_LR, - RID_ZERO = RID_SP, - - /* Calling conventions. */ - RID_RET = RID_X0, - RID_FPRET = RID_D0, - - /* These definitions must match with the *.dasc file(s): */ - RID_BASE = RID_X19, /* Interpreter BASE. */ - RID_LPC = RID_X21, /* Interpreter PC. */ - RID_GL = RID_X22, /* Interpreter GL. */ - RID_LREG = RID_X23, /* Interpreter L. */ - - /* Register ranges [min, max) and number of registers. */ - RID_MIN_GPR = RID_X0, - RID_MAX_GPR = RID_SP+1, - RID_MIN_FPR = RID_MAX_GPR, - RID_MAX_FPR = RID_D31+1, - RID_NUM_GPR = RID_MAX_GPR - RID_MIN_GPR, - RID_NUM_FPR = RID_MAX_FPR - RID_MIN_FPR -}; - -#define RID_NUM_KREF RID_NUM_GPR -#define RID_MIN_KREF RID_X0 - -/* -- Register sets ------------------------------------------------------- */ - -/* Make use of all registers, except for x18, fp, lr and sp. */ -#define RSET_FIXED \ - (RID2RSET(RID_X18)|RID2RSET(RID_FP)|RID2RSET(RID_LR)|RID2RSET(RID_SP)|\ - RID2RSET(RID_GL)) -#define RSET_GPR (RSET_RANGE(RID_MIN_GPR, RID_MAX_GPR) - RSET_FIXED) -#define RSET_FPR RSET_RANGE(RID_MIN_FPR, RID_MAX_FPR) -#define RSET_ALL (RSET_GPR|RSET_FPR) -#define RSET_INIT RSET_ALL - -/* lr is an implicit scratch register. */ -#define RSET_SCRATCH_GPR (RSET_RANGE(RID_X0, RID_X17+1)) -#define RSET_SCRATCH_FPR \ - (RSET_RANGE(RID_D0, RID_D7+1)|RSET_RANGE(RID_D16, RID_D31+1)) -#define RSET_SCRATCH (RSET_SCRATCH_GPR|RSET_SCRATCH_FPR) -#define REGARG_FIRSTGPR RID_X0 -#define REGARG_LASTGPR RID_X7 -#define REGARG_NUMGPR 8 -#define REGARG_FIRSTFPR RID_D0 -#define REGARG_LASTFPR RID_D7 -#define REGARG_NUMFPR 8 - -/* -- Spill slots --------------------------------------------------------- */ - -/* Spill slots are 32 bit wide. An even/odd pair is used for FPRs. -** -** SPS_FIXED: Available fixed spill slots in interpreter frame. -** This definition must match with the vm_arm64.dasc file. -** Pre-allocate some slots to avoid sp adjust in every root trace. -** -** SPS_FIRST: First spill slot for general use. Reserve min. two 32 bit slots. -*/ -#define SPS_FIXED 4 -#define SPS_FIRST 2 - -#define SPOFS_TMP 0 - -#define sps_scale(slot) (4 * (int32_t)(slot)) -#define sps_align(slot) (((slot) - SPS_FIXED + 3) & ~3) - -/* -- Exit state ---------------------------------------------------------- */ - -/* This definition must match with the *.dasc file(s). */ -typedef struct { - lua_Number fpr[RID_NUM_FPR]; /* Floating-point registers. */ - intptr_t gpr[RID_NUM_GPR]; /* General-purpose registers. */ - int32_t spill[256]; /* Spill slots. */ -} ExitState; - -/* Highest exit + 1 indicates stack check. */ -#define EXITSTATE_CHECKEXIT 1 - -/* Return the address of a per-trace exit stub. */ -static LJ_AINLINE uint32_t *exitstub_trace_addr_(uint32_t *p, uint32_t exitno) -{ - while (*p == (LJ_LE ? 0xd503201f : 0x1f2003d5)) p++; /* Skip A64I_NOP. */ - return p + 3 + exitno; -} -/* Avoid dependence on lj_jit.h if only including lj_target.h. */ -#define exitstub_trace_addr(T, exitno) \ - exitstub_trace_addr_((MCode *)((char *)(T)->mcode + (T)->szmcode), (exitno)) - -/* -- Instructions -------------------------------------------------------- */ - -/* ARM64 instructions are always little-endian. Swap for ARM64BE. */ -#if LJ_BE -#define A64I_LE(x) (lj_bswap(x)) -#else -#define A64I_LE(x) (x) -#endif - -/* Instruction fields. */ -#define A64F_D(r) (r) -#define A64F_N(r) ((r) << 5) -#define A64F_A(r) ((r) << 10) -#define A64F_M(r) ((r) << 16) -#define A64F_IMMS(x) ((x) << 10) -#define A64F_IMMR(x) ((x) << 16) -#define A64F_U16(x) ((x) << 5) -#define A64F_U12(x) ((x) << 10) -#define A64F_S26(x) (((uint32_t)(x) & 0x03ffffffu)) -#define A64F_S19(x) (((uint32_t)(x) & 0x7ffffu) << 5) -#define A64F_S14(x) (((uint32_t)(x) & 0x3fffu) << 5) -#define A64F_S9(x) ((x) << 12) -#define A64F_BIT(x) ((x) << 19) -#define A64F_SH(sh, x) (((sh) << 22) | ((x) << 10)) -#define A64F_EX(ex) (A64I_EX | ((ex) << 13)) -#define A64F_EXSH(ex,x) (A64I_EX | ((ex) << 13) | ((x) << 10)) -#define A64F_FP8(x) ((x) << 13) -#define A64F_CC(cc) ((cc) << 12) -#define A64F_LSL16(x) (((x) / 16) << 21) -#define A64F_BSH(sh) ((sh) << 10) - -/* Check for valid field range. */ -#define A64F_S_OK(x, b) ((((x) + (1 << (b-1))) >> (b)) == 0) - -typedef enum A64Ins { - A64I_S = 0x20000000, - A64I_X = 0x80000000, - A64I_EX = 0x00200000, - A64I_ON = 0x00200000, - A64I_K12 = 0x1a000000, - A64I_K13 = 0x18000000, - A64I_LS_U = 0x01000000, - A64I_LS_S = 0x00800000, - A64I_LS_R = 0x01200800, - A64I_LS_SH = 0x00001000, - A64I_LS_UXTWx = 0x00004000, - A64I_LS_SXTWx = 0x0000c000, - A64I_LS_SXTXx = 0x0000e000, - A64I_LS_LSLx = 0x00006000, - - A64I_ADDw = 0x0b000000, - A64I_ADDx = 0x8b000000, - A64I_ADDSw = 0x2b000000, - A64I_ADDSx = 0xab000000, - A64I_NEGw = 0x4b0003e0, - A64I_NEGx = 0xcb0003e0, - A64I_SUBw = 0x4b000000, - A64I_SUBx = 0xcb000000, - A64I_SUBSw = 0x6b000000, - A64I_SUBSx = 0xeb000000, - - A64I_MULw = 0x1b007c00, - A64I_MULx = 0x9b007c00, - A64I_SMULL = 0x9b207c00, - - A64I_ANDw = 0x0a000000, - A64I_ANDx = 0x8a000000, - A64I_ANDSw = 0x6a000000, - A64I_ANDSx = 0xea000000, - A64I_EORw = 0x4a000000, - A64I_EORx = 0xca000000, - A64I_ORRw = 0x2a000000, - A64I_ORRx = 0xaa000000, - A64I_TSTw = 0x6a00001f, - A64I_TSTx = 0xea00001f, - - A64I_CMPw = 0x6b00001f, - A64I_CMPx = 0xeb00001f, - A64I_CMNw = 0x2b00001f, - A64I_CMNx = 0xab00001f, - A64I_CCMPw = 0x7a400000, - A64I_CCMPx = 0xfa400000, - A64I_CSELw = 0x1a800000, - A64I_CSELx = 0x9a800000, - - A64I_ASRw = 0x13007c00, - A64I_ASRx = 0x9340fc00, - A64I_LSLx = 0xd3400000, - A64I_LSRx = 0xd340fc00, - A64I_SHRw = 0x1ac02000, - A64I_SHRx = 0x9ac02000, /* lsl/lsr/asr/ror x0, x0, x0 */ - A64I_REVw = 0x5ac00800, - A64I_REVx = 0xdac00c00, - - A64I_EXTRw = 0x13800000, - A64I_EXTRx = 0x93c00000, - A64I_SBFMw = 0x13000000, - A64I_SBFMx = 0x93400000, - A64I_SXTBw = 0x13001c00, - A64I_SXTHw = 0x13003c00, - A64I_SXTW = 0x93407c00, - A64I_UBFMw = 0x53000000, - A64I_UBFMx = 0xd3400000, - A64I_UXTBw = 0x53001c00, - A64I_UXTHw = 0x53003c00, - - A64I_MOVw = 0x2a0003e0, - A64I_MOVx = 0xaa0003e0, - A64I_MVNw = 0x2a2003e0, - A64I_MVNx = 0xaa2003e0, - A64I_MOVKw = 0x72800000, - A64I_MOVKx = 0xf2800000, - A64I_MOVZw = 0x52800000, - A64I_MOVZx = 0xd2800000, - A64I_MOVNw = 0x12800000, - A64I_MOVNx = 0x92800000, - - A64I_LDRB = 0x39400000, - A64I_LDRH = 0x79400000, - A64I_LDRw = 0xb9400000, - A64I_LDRx = 0xf9400000, - A64I_LDRLw = 0x18000000, - A64I_LDRLx = 0x58000000, - A64I_STRB = 0x39000000, - A64I_STRH = 0x79000000, - A64I_STRw = 0xb9000000, - A64I_STRx = 0xf9000000, - A64I_STPw = 0x29000000, - A64I_STPx = 0xa9000000, - A64I_LDPw = 0x29400000, - A64I_LDPx = 0xa9400000, - - A64I_B = 0x14000000, - A64I_BCC = 0x54000000, - A64I_BL = 0x94000000, - A64I_BR = 0xd61f0000, - A64I_BLR = 0xd63f0000, - A64I_TBZ = 0x36000000, - A64I_TBNZ = 0x37000000, - A64I_CBZ = 0x34000000, - A64I_CBNZ = 0x35000000, - - A64I_NOP = 0xd503201f, - - /* FP */ - A64I_FADDd = 0x1e602800, - A64I_FSUBd = 0x1e603800, - A64I_FMADDd = 0x1f400000, - A64I_FMSUBd = 0x1f408000, - A64I_FNMADDd = 0x1f600000, - A64I_FNMSUBd = 0x1f608000, - A64I_FMULd = 0x1e600800, - A64I_FDIVd = 0x1e601800, - A64I_FNEGd = 0x1e614000, - A64I_FABS = 0x1e60c000, - A64I_FSQRTd = 0x1e61c000, - A64I_LDRs = 0xbd400000, - A64I_LDRd = 0xfd400000, - A64I_STRs = 0xbd000000, - A64I_STRd = 0xfd000000, - A64I_LDPs = 0x2d400000, - A64I_LDPd = 0x6d400000, - A64I_STPs = 0x2d000000, - A64I_STPd = 0x6d000000, - A64I_FCMPd = 0x1e602000, - A64I_FCMPZd = 0x1e602008, - A64I_FCSELd = 0x1e600c00, - A64I_FRINTMd = 0x1e654000, - A64I_FRINTPd = 0x1e64c000, - A64I_FRINTZd = 0x1e65c000, - - A64I_FCVT_F32_F64 = 0x1e624000, - A64I_FCVT_F64_F32 = 0x1e22c000, - A64I_FCVT_F32_S32 = 0x1e220000, - A64I_FCVT_F64_S32 = 0x1e620000, - A64I_FCVT_F32_U32 = 0x1e230000, - A64I_FCVT_F64_U32 = 0x1e630000, - A64I_FCVT_F32_S64 = 0x9e220000, - A64I_FCVT_F64_S64 = 0x9e620000, - A64I_FCVT_F32_U64 = 0x9e230000, - A64I_FCVT_F64_U64 = 0x9e630000, - A64I_FCVT_S32_F64 = 0x1e780000, - A64I_FCVT_S32_F32 = 0x1e380000, - A64I_FCVT_U32_F64 = 0x1e790000, - A64I_FCVT_U32_F32 = 0x1e390000, - A64I_FCVT_S64_F64 = 0x9e780000, - A64I_FCVT_S64_F32 = 0x9e380000, - A64I_FCVT_U64_F64 = 0x9e790000, - A64I_FCVT_U64_F32 = 0x9e390000, - - A64I_FMOV_S = 0x1e204000, - A64I_FMOV_D = 0x1e604000, - A64I_FMOV_R_S = 0x1e260000, - A64I_FMOV_S_R = 0x1e270000, - A64I_FMOV_R_D = 0x9e660000, - A64I_FMOV_D_R = 0x9e670000, - A64I_FMOV_DI = 0x1e601000, -} A64Ins; - -typedef enum A64Shift { - A64SH_LSL, A64SH_LSR, A64SH_ASR, A64SH_ROR -} A64Shift; - -typedef enum A64Extend { - A64EX_UXTB, A64EX_UXTH, A64EX_UXTW, A64EX_UXTX, - A64EX_SXTB, A64EX_SXTH, A64EX_SXTW, A64EX_SXTX, -} A64Extend; - -/* ARM condition codes. */ -typedef enum A64CC { - CC_EQ, CC_NE, CC_CS, CC_CC, CC_MI, CC_PL, CC_VS, CC_VC, - CC_HI, CC_LS, CC_GE, CC_LT, CC_GT, CC_LE, CC_AL, - CC_HS = CC_CS, CC_LO = CC_CC -} A64CC; - -#endif diff --git a/lib/LuaJIT/src/lj_target_mips.h b/lib/LuaJIT/src/lj_target_mips.h deleted file mode 100644 index 740687b..0000000 --- a/lib/LuaJIT/src/lj_target_mips.h +++ /dev/null @@ -1,377 +0,0 @@ -/* -** Definitions for MIPS CPUs. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_TARGET_MIPS_H -#define _LJ_TARGET_MIPS_H - -/* -- Registers IDs ------------------------------------------------------- */ - -#define GPRDEF(_) \ - _(R0) _(R1) _(R2) _(R3) _(R4) _(R5) _(R6) _(R7) \ - _(R8) _(R9) _(R10) _(R11) _(R12) _(R13) _(R14) _(R15) \ - _(R16) _(R17) _(R18) _(R19) _(R20) _(R21) _(R22) _(R23) \ - _(R24) _(R25) _(SYS1) _(SYS2) _(R28) _(SP) _(R30) _(RA) -#if LJ_SOFTFP -#define FPRDEF(_) -#else -#define FPRDEF(_) \ - _(F0) _(F1) _(F2) _(F3) _(F4) _(F5) _(F6) _(F7) \ - _(F8) _(F9) _(F10) _(F11) _(F12) _(F13) _(F14) _(F15) \ - _(F16) _(F17) _(F18) _(F19) _(F20) _(F21) _(F22) _(F23) \ - _(F24) _(F25) _(F26) _(F27) _(F28) _(F29) _(F30) _(F31) -#endif -#define VRIDDEF(_) - -#define RIDENUM(name) RID_##name, - -enum { - GPRDEF(RIDENUM) /* General-purpose registers (GPRs). */ - FPRDEF(RIDENUM) /* Floating-point registers (FPRs). */ - RID_MAX, - RID_ZERO = RID_R0, - RID_TMP = RID_RA, - RID_GP = RID_R28, - - /* Calling conventions. */ - RID_RET = RID_R2, -#if LJ_LE - RID_RETHI = RID_R3, - RID_RETLO = RID_R2, -#else - RID_RETHI = RID_R2, - RID_RETLO = RID_R3, -#endif -#if LJ_SOFTFP - RID_FPRET = RID_R2, -#else - RID_FPRET = RID_F0, -#endif - RID_CFUNCADDR = RID_R25, - - /* These definitions must match with the *.dasc file(s): */ - RID_BASE = RID_R16, /* Interpreter BASE. */ - RID_LPC = RID_R18, /* Interpreter PC. */ - RID_DISPATCH = RID_R19, /* Interpreter DISPATCH table. */ - RID_LREG = RID_R20, /* Interpreter L. */ - RID_JGL = RID_R30, /* On-trace: global_State + 32768. */ - - /* Register ranges [min, max) and number of registers. */ - RID_MIN_GPR = RID_R0, - RID_MAX_GPR = RID_RA+1, - RID_MIN_FPR = RID_MAX_GPR, -#if LJ_SOFTFP - RID_MAX_FPR = RID_MIN_FPR, -#else - RID_MAX_FPR = RID_F31+1, -#endif - RID_NUM_GPR = RID_MAX_GPR - RID_MIN_GPR, - RID_NUM_FPR = RID_MAX_FPR - RID_MIN_FPR /* Only even regs are used. */ -}; - -#define RID_NUM_KREF RID_NUM_GPR -#define RID_MIN_KREF RID_R0 - -/* -- Register sets ------------------------------------------------------- */ - -/* Make use of all registers, except ZERO, TMP, SP, SYS1, SYS2, JGL and GP. */ -#define RSET_FIXED \ - (RID2RSET(RID_ZERO)|RID2RSET(RID_TMP)|RID2RSET(RID_SP)|\ - RID2RSET(RID_SYS1)|RID2RSET(RID_SYS2)|RID2RSET(RID_JGL)|RID2RSET(RID_GP)) -#define RSET_GPR (RSET_RANGE(RID_MIN_GPR, RID_MAX_GPR) - RSET_FIXED) -#if LJ_SOFTFP -#define RSET_FPR 0 -#else -#if LJ_32 -#define RSET_FPR \ - (RID2RSET(RID_F0)|RID2RSET(RID_F2)|RID2RSET(RID_F4)|RID2RSET(RID_F6)|\ - RID2RSET(RID_F8)|RID2RSET(RID_F10)|RID2RSET(RID_F12)|RID2RSET(RID_F14)|\ - RID2RSET(RID_F16)|RID2RSET(RID_F18)|RID2RSET(RID_F20)|RID2RSET(RID_F22)|\ - RID2RSET(RID_F24)|RID2RSET(RID_F26)|RID2RSET(RID_F28)|RID2RSET(RID_F30)) -#else -#define RSET_FPR RSET_RANGE(RID_MIN_FPR, RID_MAX_FPR) -#endif -#endif -#define RSET_ALL (RSET_GPR|RSET_FPR) -#define RSET_INIT RSET_ALL - -#define RSET_SCRATCH_GPR \ - (RSET_RANGE(RID_R1, RID_R15+1)|\ - RID2RSET(RID_R24)|RID2RSET(RID_R25)) -#if LJ_SOFTFP -#define RSET_SCRATCH_FPR 0 -#else -#if LJ_32 -#define RSET_SCRATCH_FPR \ - (RID2RSET(RID_F0)|RID2RSET(RID_F2)|RID2RSET(RID_F4)|RID2RSET(RID_F6)|\ - RID2RSET(RID_F8)|RID2RSET(RID_F10)|RID2RSET(RID_F12)|RID2RSET(RID_F14)|\ - RID2RSET(RID_F16)|RID2RSET(RID_F18)) -#else -#define RSET_SCRATCH_FPR RSET_RANGE(RID_F0, RID_F24) -#endif -#endif -#define RSET_SCRATCH (RSET_SCRATCH_GPR|RSET_SCRATCH_FPR) -#define REGARG_FIRSTGPR RID_R4 -#if LJ_32 -#define REGARG_LASTGPR RID_R7 -#define REGARG_NUMGPR 4 -#else -#define REGARG_LASTGPR RID_R11 -#define REGARG_NUMGPR 8 -#endif -#if LJ_ABI_SOFTFP -#define REGARG_FIRSTFPR 0 -#define REGARG_LASTFPR 0 -#define REGARG_NUMFPR 0 -#else -#define REGARG_FIRSTFPR RID_F12 -#if LJ_32 -#define REGARG_LASTFPR RID_F14 -#define REGARG_NUMFPR 2 -#else -#define REGARG_LASTFPR RID_F19 -#define REGARG_NUMFPR 8 -#endif -#endif - -/* -- Spill slots --------------------------------------------------------- */ - -/* Spill slots are 32 bit wide. An even/odd pair is used for FPRs. -** -** SPS_FIXED: Available fixed spill slots in interpreter frame. -** This definition must match with the *.dasc file(s). -** -** SPS_FIRST: First spill slot for general use. -*/ -#if LJ_32 -#define SPS_FIXED 5 -#else -#define SPS_FIXED 4 -#endif -#define SPS_FIRST 4 - -#define SPOFS_TMP 0 - -#define sps_scale(slot) (4 * (int32_t)(slot)) -#define sps_align(slot) (((slot) - SPS_FIXED + 1) & ~1) - -/* -- Exit state ---------------------------------------------------------- */ - -/* This definition must match with the *.dasc file(s). */ -typedef struct { -#if !LJ_SOFTFP - lua_Number fpr[RID_NUM_FPR]; /* Floating-point registers. */ -#endif - intptr_t gpr[RID_NUM_GPR]; /* General-purpose registers. */ - int32_t spill[256]; /* Spill slots. */ -} ExitState; - -/* Highest exit + 1 indicates stack check. */ -#define EXITSTATE_CHECKEXIT 1 - -/* Return the address of a per-trace exit stub. */ -static LJ_AINLINE uint32_t *exitstub_trace_addr_(uint32_t *p) -{ - while (*p == 0x00000000) p++; /* Skip MIPSI_NOP. */ - return p; -} -/* Avoid dependence on lj_jit.h if only including lj_target.h. */ -#define exitstub_trace_addr(T, exitno) \ - exitstub_trace_addr_((MCode *)((char *)(T)->mcode + (T)->szmcode)) - -/* -- Instructions -------------------------------------------------------- */ - -/* Instruction fields. */ -#define MIPSF_S(r) ((r) << 21) -#define MIPSF_T(r) ((r) << 16) -#define MIPSF_D(r) ((r) << 11) -#define MIPSF_R(r) ((r) << 21) -#define MIPSF_H(r) ((r) << 16) -#define MIPSF_G(r) ((r) << 11) -#define MIPSF_F(r) ((r) << 6) -#define MIPSF_A(n) ((n) << 6) -#define MIPSF_M(n) ((n) << 11) -#define MIPSF_L(n) ((n) << 6) - -typedef enum MIPSIns { - MIPSI_D = 0x38, - MIPSI_DV = 0x10, - MIPSI_D32 = 0x3c, - /* Integer instructions. */ - MIPSI_MOVE = 0x00000025, - MIPSI_NOP = 0x00000000, - - MIPSI_LI = 0x24000000, - MIPSI_LU = 0x34000000, - MIPSI_LUI = 0x3c000000, - - MIPSI_AND = 0x00000024, - MIPSI_ANDI = 0x30000000, - MIPSI_OR = 0x00000025, - MIPSI_ORI = 0x34000000, - MIPSI_XOR = 0x00000026, - MIPSI_XORI = 0x38000000, - MIPSI_NOR = 0x00000027, - - MIPSI_SLT = 0x0000002a, - MIPSI_SLTU = 0x0000002b, - MIPSI_SLTI = 0x28000000, - MIPSI_SLTIU = 0x2c000000, - - MIPSI_ADDU = 0x00000021, - MIPSI_ADDIU = 0x24000000, - MIPSI_SUB = 0x00000022, - MIPSI_SUBU = 0x00000023, - MIPSI_MUL = 0x70000002, - MIPSI_DIV = 0x0000001a, - MIPSI_DIVU = 0x0000001b, - - MIPSI_MOVZ = 0x0000000a, - MIPSI_MOVN = 0x0000000b, - MIPSI_MFHI = 0x00000010, - MIPSI_MFLO = 0x00000012, - MIPSI_MULT = 0x00000018, - - MIPSI_SLL = 0x00000000, - MIPSI_SRL = 0x00000002, - MIPSI_SRA = 0x00000003, - MIPSI_ROTR = 0x00200002, /* MIPSXXR2 */ - MIPSI_DROTR = 0x0020003a, - MIPSI_DROTR32 = 0x0020003e, - MIPSI_SLLV = 0x00000004, - MIPSI_SRLV = 0x00000006, - MIPSI_SRAV = 0x00000007, - MIPSI_ROTRV = 0x00000046, /* MIPSXXR2 */ - MIPSI_DROTRV = 0x00000056, - - MIPSI_SEB = 0x7c000420, /* MIPSXXR2 */ - MIPSI_SEH = 0x7c000620, /* MIPSXXR2 */ - MIPSI_WSBH = 0x7c0000a0, /* MIPSXXR2 */ - MIPSI_DSBH = 0x7c0000a4, - - MIPSI_B = 0x10000000, - MIPSI_J = 0x08000000, - MIPSI_JAL = 0x0c000000, - MIPSI_JALX = 0x74000000, - MIPSI_JR = 0x00000008, - MIPSI_JALR = 0x0000f809, - - MIPSI_BEQ = 0x10000000, - MIPSI_BNE = 0x14000000, - MIPSI_BLEZ = 0x18000000, - MIPSI_BGTZ = 0x1c000000, - MIPSI_BLTZ = 0x04000000, - MIPSI_BGEZ = 0x04010000, - - /* Load/store instructions. */ - MIPSI_LW = 0x8c000000, - MIPSI_LD = 0xdc000000, - MIPSI_SW = 0xac000000, - MIPSI_SD = 0xfc000000, - MIPSI_LB = 0x80000000, - MIPSI_SB = 0xa0000000, - MIPSI_LH = 0x84000000, - MIPSI_SH = 0xa4000000, - MIPSI_LBU = 0x90000000, - MIPSI_LHU = 0x94000000, - MIPSI_LWC1 = 0xc4000000, - MIPSI_SWC1 = 0xe4000000, - MIPSI_LDC1 = 0xd4000000, - MIPSI_SDC1 = 0xf4000000, - - /* MIPS64 instructions. */ - MIPSI_DADD = 0x0000002c, - MIPSI_DADDI = 0x60000000, - MIPSI_DADDU = 0x0000002d, - MIPSI_DADDIU = 0x64000000, - MIPSI_DSUB = 0x0000002e, - MIPSI_DSUBU = 0x0000002f, - MIPSI_DDIV = 0x0000001e, - MIPSI_DDIVU = 0x0000001f, - MIPSI_DMULT = 0x0000001c, - MIPSI_DMULTU = 0x0000001d, - - MIPSI_DSLL = 0x00000038, - MIPSI_DSRL = 0x0000003a, - MIPSI_DSLLV = 0x00000014, - MIPSI_DSRLV = 0x00000016, - MIPSI_DSRA = 0x0000003b, - MIPSI_DSRAV = 0x00000017, - MIPSI_DSRA32 = 0x0000003f, - MIPSI_DSLL32 = 0x0000003c, - MIPSI_DSRL32 = 0x0000003e, - MIPSI_DSHD = 0x7c000164, - - MIPSI_AADDU = LJ_32 ? MIPSI_ADDU : MIPSI_DADDU, - MIPSI_AADDIU = LJ_32 ? MIPSI_ADDIU : MIPSI_DADDIU, - MIPSI_ASUBU = LJ_32 ? MIPSI_SUBU : MIPSI_DSUBU, - MIPSI_AL = LJ_32 ? MIPSI_LW : MIPSI_LD, - MIPSI_AS = LJ_32 ? MIPSI_SW : MIPSI_SD, - - /* Extract/insert instructions. */ - MIPSI_DEXTM = 0x7c000001, - MIPSI_DEXTU = 0x7c000002, - MIPSI_DEXT = 0x7c000003, - MIPSI_DINSM = 0x7c000005, - MIPSI_DINSU = 0x7c000006, - MIPSI_DINS = 0x7c000007, - - MIPSI_RINT_D = 0x4620001a, - MIPSI_RINT_S = 0x4600001a, - MIPSI_RINT = 0x4400001a, - MIPSI_FLOOR_D = 0x4620000b, - MIPSI_CEIL_D = 0x4620000a, - MIPSI_ROUND_D = 0x46200008, - - /* FP instructions. */ - MIPSI_MOV_S = 0x46000006, - MIPSI_MOV_D = 0x46200006, - MIPSI_MOVT_D = 0x46210011, - MIPSI_MOVF_D = 0x46200011, - - MIPSI_ABS_D = 0x46200005, - MIPSI_NEG_D = 0x46200007, - - MIPSI_ADD_D = 0x46200000, - MIPSI_SUB_D = 0x46200001, - MIPSI_MUL_D = 0x46200002, - MIPSI_DIV_D = 0x46200003, - MIPSI_SQRT_D = 0x46200004, - - MIPSI_ADD_S = 0x46000000, - MIPSI_SUB_S = 0x46000001, - - MIPSI_CVT_D_S = 0x46000021, - MIPSI_CVT_W_S = 0x46000024, - MIPSI_CVT_S_D = 0x46200020, - MIPSI_CVT_W_D = 0x46200024, - MIPSI_CVT_S_W = 0x46800020, - MIPSI_CVT_D_W = 0x46800021, - MIPSI_CVT_S_L = 0x46a00020, - MIPSI_CVT_D_L = 0x46a00021, - - MIPSI_TRUNC_W_S = 0x4600000d, - MIPSI_TRUNC_W_D = 0x4620000d, - MIPSI_TRUNC_L_S = 0x46000009, - MIPSI_TRUNC_L_D = 0x46200009, - MIPSI_FLOOR_W_S = 0x4600000f, - MIPSI_FLOOR_W_D = 0x4620000f, - - MIPSI_MFC1 = 0x44000000, - MIPSI_MTC1 = 0x44800000, - MIPSI_DMTC1 = 0x44a00000, - MIPSI_DMFC1 = 0x44200000, - - MIPSI_BC1F = 0x45000000, - MIPSI_BC1T = 0x45010000, - - MIPSI_C_EQ_D = 0x46200032, - MIPSI_C_OLT_S = 0x46000034, - MIPSI_C_OLT_D = 0x46200034, - MIPSI_C_ULT_D = 0x46200035, - MIPSI_C_OLE_D = 0x46200036, - MIPSI_C_ULE_D = 0x46200037, -} MIPSIns; - -#endif diff --git a/lib/LuaJIT/src/lj_target_ppc.h b/lib/LuaJIT/src/lj_target_ppc.h deleted file mode 100644 index c5c991a..0000000 --- a/lib/LuaJIT/src/lj_target_ppc.h +++ /dev/null @@ -1,280 +0,0 @@ -/* -** Definitions for PPC CPUs. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_TARGET_PPC_H -#define _LJ_TARGET_PPC_H - -/* -- Registers IDs ------------------------------------------------------- */ - -#define GPRDEF(_) \ - _(R0) _(SP) _(SYS1) _(R3) _(R4) _(R5) _(R6) _(R7) \ - _(R8) _(R9) _(R10) _(R11) _(R12) _(SYS2) _(R14) _(R15) \ - _(R16) _(R17) _(R18) _(R19) _(R20) _(R21) _(R22) _(R23) \ - _(R24) _(R25) _(R26) _(R27) _(R28) _(R29) _(R30) _(R31) -#define FPRDEF(_) \ - _(F0) _(F1) _(F2) _(F3) _(F4) _(F5) _(F6) _(F7) \ - _(F8) _(F9) _(F10) _(F11) _(F12) _(F13) _(F14) _(F15) \ - _(F16) _(F17) _(F18) _(F19) _(F20) _(F21) _(F22) _(F23) \ - _(F24) _(F25) _(F26) _(F27) _(F28) _(F29) _(F30) _(F31) -#define VRIDDEF(_) - -#define RIDENUM(name) RID_##name, - -enum { - GPRDEF(RIDENUM) /* General-purpose registers (GPRs). */ - FPRDEF(RIDENUM) /* Floating-point registers (FPRs). */ - RID_MAX, - RID_TMP = RID_R0, - - /* Calling conventions. */ - RID_RET = RID_R3, - RID_RETHI = RID_R3, - RID_RETLO = RID_R4, - RID_FPRET = RID_F1, - - /* These definitions must match with the *.dasc file(s): */ - RID_BASE = RID_R14, /* Interpreter BASE. */ - RID_LPC = RID_R16, /* Interpreter PC. */ - RID_DISPATCH = RID_R17, /* Interpreter DISPATCH table. */ - RID_LREG = RID_R18, /* Interpreter L. */ - RID_JGL = RID_R31, /* On-trace: global_State + 32768. */ - - /* Register ranges [min, max) and number of registers. */ - RID_MIN_GPR = RID_R0, - RID_MAX_GPR = RID_R31+1, - RID_MIN_FPR = RID_F0, - RID_MAX_FPR = RID_F31+1, - RID_NUM_GPR = RID_MAX_GPR - RID_MIN_GPR, - RID_NUM_FPR = RID_MAX_FPR - RID_MIN_FPR -}; - -#define RID_NUM_KREF RID_NUM_GPR -#define RID_MIN_KREF RID_R0 - -/* -- Register sets ------------------------------------------------------- */ - -/* Make use of all registers, except TMP, SP, SYS1, SYS2 and JGL. */ -#define RSET_FIXED \ - (RID2RSET(RID_TMP)|RID2RSET(RID_SP)|RID2RSET(RID_SYS1)|\ - RID2RSET(RID_SYS2)|RID2RSET(RID_JGL)) -#define RSET_GPR (RSET_RANGE(RID_MIN_GPR, RID_MAX_GPR) - RSET_FIXED) -#define RSET_FPR RSET_RANGE(RID_MIN_FPR, RID_MAX_FPR) -#define RSET_ALL (RSET_GPR|RSET_FPR) -#define RSET_INIT RSET_ALL - -#define RSET_SCRATCH_GPR (RSET_RANGE(RID_R3, RID_R12+1)) -#define RSET_SCRATCH_FPR (RSET_RANGE(RID_F0, RID_F13+1)) -#define RSET_SCRATCH (RSET_SCRATCH_GPR|RSET_SCRATCH_FPR) -#define REGARG_FIRSTGPR RID_R3 -#define REGARG_LASTGPR RID_R10 -#define REGARG_NUMGPR 8 -#define REGARG_FIRSTFPR RID_F1 -#define REGARG_LASTFPR RID_F8 -#define REGARG_NUMFPR 8 - -/* -- Spill slots --------------------------------------------------------- */ - -/* Spill slots are 32 bit wide. An even/odd pair is used for FPRs. -** -** SPS_FIXED: Available fixed spill slots in interpreter frame. -** This definition must match with the *.dasc file(s). -** -** SPS_FIRST: First spill slot for general use. -** [sp+12] tmplo word \ -** [sp+ 8] tmphi word / tmp dword, parameter area for callee -** [sp+ 4] tmpw, LR of callee -** [sp+ 0] stack chain -*/ -#define SPS_FIXED 7 -#define SPS_FIRST 4 - -/* Stack offsets for temporary slots. Used for FP<->int conversions etc. */ -#define SPOFS_TMPW 4 -#define SPOFS_TMP 8 -#define SPOFS_TMPHI 8 -#define SPOFS_TMPLO 12 - -#define sps_scale(slot) (4 * (int32_t)(slot)) -#define sps_align(slot) (((slot) - SPS_FIXED + 3) & ~3) - -/* -- Exit state ---------------------------------------------------------- */ - -/* This definition must match with the *.dasc file(s). */ -typedef struct { - lua_Number fpr[RID_NUM_FPR]; /* Floating-point registers. */ - intptr_t gpr[RID_NUM_GPR]; /* General-purpose registers. */ - int32_t spill[256]; /* Spill slots. */ -} ExitState; - -/* Highest exit + 1 indicates stack check. */ -#define EXITSTATE_CHECKEXIT 1 - -/* Return the address of a per-trace exit stub. */ -static LJ_AINLINE uint32_t *exitstub_trace_addr_(uint32_t *p, uint32_t exitno) -{ - while (*p == 0x60000000) p++; /* Skip PPCI_NOP. */ - return p + 3 + exitno; -} -/* Avoid dependence on lj_jit.h if only including lj_target.h. */ -#define exitstub_trace_addr(T, exitno) \ - exitstub_trace_addr_((MCode *)((char *)(T)->mcode + (T)->szmcode), (exitno)) - -/* -- Instructions -------------------------------------------------------- */ - -/* Instruction fields. */ -#define PPCF_CC(cc) ((((cc) & 3) << 16) | (((cc) & 4) << 22)) -#define PPCF_T(r) ((r) << 21) -#define PPCF_A(r) ((r) << 16) -#define PPCF_B(r) ((r) << 11) -#define PPCF_C(r) ((r) << 6) -#define PPCF_MB(n) ((n) << 6) -#define PPCF_ME(n) ((n) << 1) -#define PPCF_Y 0x00200000 -#define PPCF_DOT 0x00000001 - -typedef enum PPCIns { - /* Integer instructions. */ - PPCI_MR = 0x7c000378, - PPCI_NOP = 0x60000000, - - PPCI_LI = 0x38000000, - PPCI_LIS = 0x3c000000, - - PPCI_ADD = 0x7c000214, - PPCI_ADDC = 0x7c000014, - PPCI_ADDO = 0x7c000614, - PPCI_ADDE = 0x7c000114, - PPCI_ADDZE = 0x7c000194, - PPCI_ADDME = 0x7c0001d4, - PPCI_ADDI = 0x38000000, - PPCI_ADDIS = 0x3c000000, - PPCI_ADDIC = 0x30000000, - PPCI_ADDICDOT = 0x34000000, - - PPCI_SUBF = 0x7c000050, - PPCI_SUBFC = 0x7c000010, - PPCI_SUBFO = 0x7c000450, - PPCI_SUBFE = 0x7c000110, - PPCI_SUBFZE = 0x7c000190, - PPCI_SUBFME = 0x7c0001d0, - PPCI_SUBFIC = 0x20000000, - - PPCI_NEG = 0x7c0000d0, - - PPCI_AND = 0x7c000038, - PPCI_ANDC = 0x7c000078, - PPCI_NAND = 0x7c0003b8, - PPCI_ANDIDOT = 0x70000000, - PPCI_ANDISDOT = 0x74000000, - - PPCI_OR = 0x7c000378, - PPCI_NOR = 0x7c0000f8, - PPCI_ORI = 0x60000000, - PPCI_ORIS = 0x64000000, - - PPCI_XOR = 0x7c000278, - PPCI_EQV = 0x7c000238, - PPCI_XORI = 0x68000000, - PPCI_XORIS = 0x6c000000, - - PPCI_CMPW = 0x7c000000, - PPCI_CMPLW = 0x7c000040, - PPCI_CMPWI = 0x2c000000, - PPCI_CMPLWI = 0x28000000, - - PPCI_MULLW = 0x7c0001d6, - PPCI_MULLI = 0x1c000000, - PPCI_MULLWO = 0x7c0005d6, - - PPCI_EXTSB = 0x7c000774, - PPCI_EXTSH = 0x7c000734, - - PPCI_SLW = 0x7c000030, - PPCI_SRW = 0x7c000430, - PPCI_SRAW = 0x7c000630, - PPCI_SRAWI = 0x7c000670, - - PPCI_RLWNM = 0x5c000000, - PPCI_RLWINM = 0x54000000, - PPCI_RLWIMI = 0x50000000, - - PPCI_B = 0x48000000, - PPCI_BL = 0x48000001, - PPCI_BC = 0x40800000, - PPCI_BCL = 0x40800001, - PPCI_BCTR = 0x4e800420, - PPCI_BCTRL = 0x4e800421, - - PPCI_CRANDC = 0x4c000102, - PPCI_CRXOR = 0x4c000182, - PPCI_CRAND = 0x4c000202, - PPCI_CREQV = 0x4c000242, - PPCI_CRORC = 0x4c000342, - PPCI_CROR = 0x4c000382, - - PPCI_MFLR = 0x7c0802a6, - PPCI_MTCTR = 0x7c0903a6, - - PPCI_MCRXR = 0x7c000400, - - /* Load/store instructions. */ - PPCI_LWZ = 0x80000000, - PPCI_LBZ = 0x88000000, - PPCI_STW = 0x90000000, - PPCI_STB = 0x98000000, - PPCI_LHZ = 0xa0000000, - PPCI_LHA = 0xa8000000, - PPCI_STH = 0xb0000000, - - PPCI_STWU = 0x94000000, - - PPCI_LFS = 0xc0000000, - PPCI_LFD = 0xc8000000, - PPCI_STFS = 0xd0000000, - PPCI_STFD = 0xd8000000, - - PPCI_LWZX = 0x7c00002e, - PPCI_LBZX = 0x7c0000ae, - PPCI_STWX = 0x7c00012e, - PPCI_STBX = 0x7c0001ae, - PPCI_LHZX = 0x7c00022e, - PPCI_LHAX = 0x7c0002ae, - PPCI_STHX = 0x7c00032e, - - PPCI_LWBRX = 0x7c00042c, - PPCI_STWBRX = 0x7c00052c, - - PPCI_LFSX = 0x7c00042e, - PPCI_LFDX = 0x7c0004ae, - PPCI_STFSX = 0x7c00052e, - PPCI_STFDX = 0x7c0005ae, - - /* FP instructions. */ - PPCI_FMR = 0xfc000090, - PPCI_FNEG = 0xfc000050, - PPCI_FABS = 0xfc000210, - - PPCI_FRSP = 0xfc000018, - PPCI_FCTIWZ = 0xfc00001e, - - PPCI_FADD = 0xfc00002a, - PPCI_FSUB = 0xfc000028, - PPCI_FMUL = 0xfc000032, - PPCI_FDIV = 0xfc000024, - PPCI_FSQRT = 0xfc00002c, - - PPCI_FMADD = 0xfc00003a, - PPCI_FMSUB = 0xfc000038, - PPCI_FNMSUB = 0xfc00003c, - - PPCI_FCMPU = 0xfc000000, - PPCI_FSEL = 0xfc00002e, -} PPCIns; - -typedef enum PPCCC { - CC_GE, CC_LE, CC_NE, CC_NS, CC_LT, CC_GT, CC_EQ, CC_SO -} PPCCC; - -#endif diff --git a/lib/LuaJIT/src/lj_target_x86.h b/lib/LuaJIT/src/lj_target_x86.h deleted file mode 100644 index 356f792..0000000 --- a/lib/LuaJIT/src/lj_target_x86.h +++ /dev/null @@ -1,362 +0,0 @@ -/* -** Definitions for x86 and x64 CPUs. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_TARGET_X86_H -#define _LJ_TARGET_X86_H - -/* -- Registers IDs ------------------------------------------------------- */ - -#if LJ_64 -#define GPRDEF(_) \ - _(EAX) _(ECX) _(EDX) _(EBX) _(ESP) _(EBP) _(ESI) _(EDI) \ - _(R8D) _(R9D) _(R10D) _(R11D) _(R12D) _(R13D) _(R14D) _(R15D) -#define FPRDEF(_) \ - _(XMM0) _(XMM1) _(XMM2) _(XMM3) _(XMM4) _(XMM5) _(XMM6) _(XMM7) \ - _(XMM8) _(XMM9) _(XMM10) _(XMM11) _(XMM12) _(XMM13) _(XMM14) _(XMM15) -#else -#define GPRDEF(_) \ - _(EAX) _(ECX) _(EDX) _(EBX) _(ESP) _(EBP) _(ESI) _(EDI) -#define FPRDEF(_) \ - _(XMM0) _(XMM1) _(XMM2) _(XMM3) _(XMM4) _(XMM5) _(XMM6) _(XMM7) -#endif -#define VRIDDEF(_) \ - _(MRM) _(RIP) - -#define RIDENUM(name) RID_##name, - -enum { - GPRDEF(RIDENUM) /* General-purpose registers (GPRs). */ - FPRDEF(RIDENUM) /* Floating-point registers (FPRs). */ - RID_MAX, - RID_MRM = RID_MAX, /* Pseudo-id for ModRM operand. */ - RID_RIP = RID_MAX+5, /* Pseudo-id for RIP (x64 only), rm bits = 5. */ - - /* Calling conventions. */ - RID_SP = RID_ESP, - RID_RET = RID_EAX, -#if LJ_64 - RID_FPRET = RID_XMM0, -#else - RID_RETLO = RID_EAX, - RID_RETHI = RID_EDX, -#endif - - /* These definitions must match with the *.dasc file(s): */ - RID_BASE = RID_EDX, /* Interpreter BASE. */ -#if LJ_64 && !LJ_ABI_WIN - RID_LPC = RID_EBX, /* Interpreter PC. */ - RID_DISPATCH = RID_R14D, /* Interpreter DISPATCH table. */ -#else - RID_LPC = RID_ESI, /* Interpreter PC. */ - RID_DISPATCH = RID_EBX, /* Interpreter DISPATCH table. */ -#endif - - /* Register ranges [min, max) and number of registers. */ - RID_MIN_GPR = RID_EAX, - RID_MIN_FPR = RID_XMM0, - RID_MAX_GPR = RID_MIN_FPR, - RID_MAX_FPR = RID_MAX, - RID_NUM_GPR = RID_MAX_GPR - RID_MIN_GPR, - RID_NUM_FPR = RID_MAX_FPR - RID_MIN_FPR, -}; - -/* -- Register sets ------------------------------------------------------- */ - -/* Make use of all registers, except the stack pointer (and maybe DISPATCH). */ -#define RSET_GPR (RSET_RANGE(RID_MIN_GPR, RID_MAX_GPR) \ - - RID2RSET(RID_ESP) \ - - LJ_GC64*RID2RSET(RID_DISPATCH)) -#define RSET_FPR (RSET_RANGE(RID_MIN_FPR, RID_MAX_FPR)) -#define RSET_ALL (RSET_GPR|RSET_FPR) -#define RSET_INIT RSET_ALL - -#if LJ_64 -/* Note: this requires the use of FORCE_REX! */ -#define RSET_GPR8 RSET_GPR -#else -#define RSET_GPR8 (RSET_RANGE(RID_EAX, RID_EBX+1)) -#endif - -/* ABI-specific register sets. */ -#define RSET_ACD (RID2RSET(RID_EAX)|RID2RSET(RID_ECX)|RID2RSET(RID_EDX)) -#if LJ_64 -#if LJ_ABI_WIN -/* Windows x64 ABI. */ -#define RSET_SCRATCH \ - (RSET_ACD|RSET_RANGE(RID_R8D, RID_R11D+1)|RSET_RANGE(RID_XMM0, RID_XMM5+1)) -#define REGARG_GPRS \ - (RID_ECX|((RID_EDX|((RID_R8D|(RID_R9D<<5))<<5))<<5)) -#define REGARG_NUMGPR 4 -#define REGARG_NUMFPR 4 -#define REGARG_FIRSTFPR RID_XMM0 -#define REGARG_LASTFPR RID_XMM3 -#define STACKARG_OFS (4*8) -#else -/* The rest of the civilized x64 world has a common ABI. */ -#define RSET_SCRATCH \ - (RSET_ACD|RSET_RANGE(RID_ESI, RID_R11D+1)|RSET_FPR) -#define REGARG_GPRS \ - (RID_EDI|((RID_ESI|((RID_EDX|((RID_ECX|((RID_R8D|(RID_R9D \ - <<5))<<5))<<5))<<5))<<5)) -#define REGARG_NUMGPR 6 -#define REGARG_NUMFPR 8 -#define REGARG_FIRSTFPR RID_XMM0 -#define REGARG_LASTFPR RID_XMM7 -#define STACKARG_OFS 0 -#endif -#else -/* Common x86 ABI. */ -#define RSET_SCRATCH (RSET_ACD|RSET_FPR) -#define REGARG_GPRS (RID_ECX|(RID_EDX<<5)) /* Fastcall only. */ -#define REGARG_NUMGPR 2 /* Fastcall only. */ -#define REGARG_NUMFPR 0 -#define STACKARG_OFS 0 -#endif - -#if LJ_64 -/* Prefer the low 8 regs of each type to reduce REX prefixes. */ -#undef rset_picktop -#define rset_picktop(rs) (lj_fls(lj_bswap(rs)) ^ 0x18) -#endif - -/* -- Spill slots --------------------------------------------------------- */ - -/* Spill slots are 32 bit wide. An even/odd pair is used for FPRs. -** -** SPS_FIXED: Available fixed spill slots in interpreter frame. -** This definition must match with the *.dasc file(s). -** -** SPS_FIRST: First spill slot for general use. Reserve min. two 32 bit slots. -*/ -#if LJ_64 -#if LJ_ABI_WIN -#define SPS_FIXED (4*2) -#define SPS_FIRST (4*2) /* Don't use callee register save area. */ -#else -#if LJ_GC64 -#define SPS_FIXED 2 -#else -#define SPS_FIXED 4 -#endif -#define SPS_FIRST 2 -#endif -#else -#define SPS_FIXED 6 -#define SPS_FIRST 2 -#endif - -#define SPOFS_TMP 0 - -#define sps_scale(slot) (4 * (int32_t)(slot)) -#define sps_align(slot) (((slot) - SPS_FIXED + 3) & ~3) - -/* -- Exit state ---------------------------------------------------------- */ - -/* This definition must match with the *.dasc file(s). */ -typedef struct { - lua_Number fpr[RID_NUM_FPR]; /* Floating-point registers. */ - intptr_t gpr[RID_NUM_GPR]; /* General-purpose registers. */ - int32_t spill[256]; /* Spill slots. */ -} ExitState; - -/* Limited by the range of a short fwd jump (127): (2+2)*(32-1)-2 = 122. */ -#define EXITSTUB_SPACING (2+2) -#define EXITSTUBS_PER_GROUP 32 - -/* -- x86 ModRM operand encoding ------------------------------------------ */ - -typedef enum { - XM_OFS0 = 0x00, XM_OFS8 = 0x40, XM_OFS32 = 0x80, XM_REG = 0xc0, - XM_SCALE1 = 0x00, XM_SCALE2 = 0x40, XM_SCALE4 = 0x80, XM_SCALE8 = 0xc0, - XM_MASK = 0xc0 -} x86Mode; - -/* Structure to hold variable ModRM operand. */ -typedef struct { - int32_t ofs; /* Offset. */ - uint8_t base; /* Base register or RID_NONE. */ - uint8_t idx; /* Index register or RID_NONE. */ - uint8_t scale; /* Index scale (XM_SCALE1 .. XM_SCALE8). */ -} x86ModRM; - -/* -- Opcodes ------------------------------------------------------------- */ - -/* Macros to construct variable-length x86 opcodes. -(len+1) is in LSB. */ -#define XO_(o) ((uint32_t)(0x0000fe + (0x##o<<24))) -#define XO_FPU(a,b) ((uint32_t)(0x00fd + (0x##a<<16)+(0x##b<<24))) -#define XO_0f(o) ((uint32_t)(0x0f00fd + (0x##o<<24))) -#define XO_66(o) ((uint32_t)(0x6600fd + (0x##o<<24))) -#define XO_660f(o) ((uint32_t)(0x0f66fc + (0x##o<<24))) -#define XO_f20f(o) ((uint32_t)(0x0ff2fc + (0x##o<<24))) -#define XO_f30f(o) ((uint32_t)(0x0ff3fc + (0x##o<<24))) - -#define XV_660f38(o) ((uint32_t)(0x79e2c4 + (0x##o<<24))) -#define XV_f20f38(o) ((uint32_t)(0x7be2c4 + (0x##o<<24))) -#define XV_f20f3a(o) ((uint32_t)(0x7be3c4 + (0x##o<<24))) -#define XV_f30f38(o) ((uint32_t)(0x7ae2c4 + (0x##o<<24))) - -/* This list of x86 opcodes is not intended to be complete. Opcodes are only -** included when needed. Take a look at DynASM or jit.dis_x86 to see the -** whole mess. -*/ -typedef enum { - /* Fixed length opcodes. XI_* prefix. */ - XI_O16 = 0x66, - XI_NOP = 0x90, - XI_XCHGa = 0x90, - XI_CALL = 0xe8, - XI_JMP = 0xe9, - XI_JMPs = 0xeb, - XI_PUSH = 0x50, /* Really 50+r. */ - XI_JCCs = 0x70, /* Really 7x. */ - XI_JCCn = 0x80, /* Really 0f8x. */ - XI_LEA = 0x8d, - XI_MOVrib = 0xb0, /* Really b0+r. */ - XI_MOVri = 0xb8, /* Really b8+r. */ - XI_ARITHib = 0x80, - XI_ARITHi = 0x81, - XI_ARITHi8 = 0x83, - XI_PUSHi8 = 0x6a, - XI_TESTb = 0x84, - XI_TEST = 0x85, - XI_INT3 = 0xcc, - XI_MOVmi = 0xc7, - XI_GROUP5 = 0xff, - - /* Note: little-endian byte-order! */ - XI_FLDZ = 0xeed9, - XI_FLD1 = 0xe8d9, - XI_FLDLG2 = 0xecd9, - XI_FLDLN2 = 0xedd9, - XI_FDUP = 0xc0d9, /* Really fld st0. */ - XI_FPOP = 0xd8dd, /* Really fstp st0. */ - XI_FPOP1 = 0xd9dd, /* Really fstp st1. */ - XI_FRNDINT = 0xfcd9, - XI_FSIN = 0xfed9, - XI_FCOS = 0xffd9, - XI_FPTAN = 0xf2d9, - XI_FPATAN = 0xf3d9, - XI_FSCALE = 0xfdd9, - XI_FYL2X = 0xf1d9, - - /* VEX-encoded instructions. XV_* prefix. */ - XV_RORX = XV_f20f3a(f0), - XV_SARX = XV_f30f38(f7), - XV_SHLX = XV_660f38(f7), - XV_SHRX = XV_f20f38(f7), - - /* Variable-length opcodes. XO_* prefix. */ - XO_OR = XO_(0b), - XO_MOV = XO_(8b), - XO_MOVto = XO_(89), - XO_MOVtow = XO_66(89), - XO_MOVtob = XO_(88), - XO_MOVmi = XO_(c7), - XO_MOVmib = XO_(c6), - XO_LEA = XO_(8d), - XO_ARITHib = XO_(80), - XO_ARITHi = XO_(81), - XO_ARITHi8 = XO_(83), - XO_ARITHiw8 = XO_66(83), - XO_SHIFTi = XO_(c1), - XO_SHIFT1 = XO_(d1), - XO_SHIFTcl = XO_(d3), - XO_IMUL = XO_0f(af), - XO_IMULi = XO_(69), - XO_IMULi8 = XO_(6b), - XO_CMP = XO_(3b), - XO_TESTb = XO_(84), - XO_TEST = XO_(85), - XO_GROUP3b = XO_(f6), - XO_GROUP3 = XO_(f7), - XO_GROUP5b = XO_(fe), - XO_GROUP5 = XO_(ff), - XO_MOVZXb = XO_0f(b6), - XO_MOVZXw = XO_0f(b7), - XO_MOVSXb = XO_0f(be), - XO_MOVSXw = XO_0f(bf), - XO_MOVSXd = XO_(63), - XO_BSWAP = XO_0f(c8), - XO_CMOV = XO_0f(40), - - XO_MOVSD = XO_f20f(10), - XO_MOVSDto = XO_f20f(11), - XO_MOVSS = XO_f30f(10), - XO_MOVSSto = XO_f30f(11), - XO_MOVLPD = XO_660f(12), - XO_MOVAPS = XO_0f(28), - XO_XORPS = XO_0f(57), - XO_ANDPS = XO_0f(54), - XO_ADDSD = XO_f20f(58), - XO_SUBSD = XO_f20f(5c), - XO_MULSD = XO_f20f(59), - XO_DIVSD = XO_f20f(5e), - XO_SQRTSD = XO_f20f(51), - XO_MINSD = XO_f20f(5d), - XO_MAXSD = XO_f20f(5f), - XO_ROUNDSD = 0x0b3a0ffc, /* Really 66 0f 3a 0b. See asm_fpmath. */ - XO_UCOMISD = XO_660f(2e), - XO_CVTSI2SD = XO_f20f(2a), - XO_CVTTSD2SI= XO_f20f(2c), - XO_CVTSI2SS = XO_f30f(2a), - XO_CVTTSS2SI= XO_f30f(2c), - XO_CVTSS2SD = XO_f30f(5a), - XO_CVTSD2SS = XO_f20f(5a), - XO_ADDSS = XO_f30f(58), - XO_MOVD = XO_660f(6e), - XO_MOVDto = XO_660f(7e), - - XO_FLDd = XO_(d9), XOg_FLDd = 0, - XO_FLDq = XO_(dd), XOg_FLDq = 0, - XO_FILDd = XO_(db), XOg_FILDd = 0, - XO_FILDq = XO_(df), XOg_FILDq = 5, - XO_FSTPd = XO_(d9), XOg_FSTPd = 3, - XO_FSTPq = XO_(dd), XOg_FSTPq = 3, - XO_FISTPq = XO_(df), XOg_FISTPq = 7, - XO_FISTTPq = XO_(dd), XOg_FISTTPq = 1, - XO_FADDq = XO_(dc), XOg_FADDq = 0, - XO_FLDCW = XO_(d9), XOg_FLDCW = 5, - XO_FNSTCW = XO_(d9), XOg_FNSTCW = 7 -} x86Op; - -/* x86 opcode groups. */ -typedef uint32_t x86Group; - -#define XG_(i8, i, g) ((x86Group)(((i8) << 16) + ((i) << 8) + (g))) -#define XG_ARITHi(g) XG_(XI_ARITHi8, XI_ARITHi, g) -#define XG_TOXOi(xg) ((x86Op)(0x000000fe + (((xg)<<16) & 0xff000000))) -#define XG_TOXOi8(xg) ((x86Op)(0x000000fe + (((xg)<<8) & 0xff000000))) - -#define XO_ARITH(a) ((x86Op)(0x030000fe + ((a)<<27))) -#define XO_ARITHw(a) ((x86Op)(0x036600fd + ((a)<<27))) - -typedef enum { - XOg_ADD, XOg_OR, XOg_ADC, XOg_SBB, XOg_AND, XOg_SUB, XOg_XOR, XOg_CMP, - XOg_X_IMUL -} x86Arith; - -typedef enum { - XOg_ROL, XOg_ROR, XOg_RCL, XOg_RCR, XOg_SHL, XOg_SHR, XOg_SAL, XOg_SAR -} x86Shift; - -typedef enum { - XOg_TEST, XOg_TEST_, XOg_NOT, XOg_NEG, XOg_MUL, XOg_IMUL, XOg_DIV, XOg_IDIV -} x86Group3; - -typedef enum { - XOg_INC, XOg_DEC, XOg_CALL, XOg_CALLfar, XOg_JMP, XOg_JMPfar, XOg_PUSH -} x86Group5; - -/* x86 condition codes. */ -typedef enum { - CC_O, CC_NO, CC_B, CC_NB, CC_E, CC_NE, CC_BE, CC_NBE, - CC_S, CC_NS, CC_P, CC_NP, CC_L, CC_NL, CC_LE, CC_NLE, - CC_C = CC_B, CC_NAE = CC_C, CC_NC = CC_NB, CC_AE = CC_NB, - CC_Z = CC_E, CC_NZ = CC_NE, CC_NA = CC_BE, CC_A = CC_NBE, - CC_PE = CC_P, CC_PO = CC_NP, CC_NGE = CC_L, CC_GE = CC_NL, - CC_NG = CC_LE, CC_G = CC_NLE -} x86CC; - -#endif diff --git a/lib/LuaJIT/src/lj_trace.c b/lib/LuaJIT/src/lj_trace.c deleted file mode 100644 index d85b47f..0000000 --- a/lib/LuaJIT/src/lj_trace.c +++ /dev/null @@ -1,909 +0,0 @@ -/* -** Trace management. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_trace_c -#define LUA_CORE - -#include "lj_obj.h" - -#if LJ_HASJIT - -#include "lj_gc.h" -#include "lj_err.h" -#include "lj_debug.h" -#include "lj_str.h" -#include "lj_frame.h" -#include "lj_state.h" -#include "lj_bc.h" -#include "lj_ir.h" -#include "lj_jit.h" -#include "lj_iropt.h" -#include "lj_mcode.h" -#include "lj_trace.h" -#include "lj_snap.h" -#include "lj_gdbjit.h" -#include "lj_record.h" -#include "lj_asm.h" -#include "lj_dispatch.h" -#include "lj_vm.h" -#include "lj_vmevent.h" -#include "lj_target.h" - -/* -- Error handling ------------------------------------------------------ */ - -/* Synchronous abort with error message. */ -void lj_trace_err(jit_State *J, TraceError e) -{ - setnilV(&J->errinfo); /* No error info. */ - setintV(J->L->top++, (int32_t)e); - lj_err_throw(J->L, LUA_ERRRUN); -} - -/* Synchronous abort with error message and error info. */ -void lj_trace_err_info(jit_State *J, TraceError e) -{ - setintV(J->L->top++, (int32_t)e); - lj_err_throw(J->L, LUA_ERRRUN); -} - -/* -- Trace management ---------------------------------------------------- */ - -/* The current trace is first assembled in J->cur. The variable length -** arrays point to shared, growable buffers (J->irbuf etc.). When trace -** recording ends successfully, the current trace and its data structures -** are copied to a new (compact) GCtrace object. -*/ - -/* Find a free trace number. */ -static TraceNo trace_findfree(jit_State *J) -{ - MSize osz, lim; - if (J->freetrace == 0) - J->freetrace = 1; - for (; J->freetrace < J->sizetrace; J->freetrace++) - if (traceref(J, J->freetrace) == NULL) - return J->freetrace++; - /* Need to grow trace array. */ - lim = (MSize)J->param[JIT_P_maxtrace] + 1; - if (lim < 2) lim = 2; else if (lim > 65535) lim = 65535; - osz = J->sizetrace; - if (osz >= lim) - return 0; /* Too many traces. */ - lj_mem_growvec(J->L, J->trace, J->sizetrace, lim, GCRef); - for (; osz < J->sizetrace; osz++) - setgcrefnull(J->trace[osz]); - return J->freetrace; -} - -#define TRACE_APPENDVEC(field, szfield, tp) \ - T->field = (tp *)p; \ - memcpy(p, J->cur.field, J->cur.szfield*sizeof(tp)); \ - p += J->cur.szfield*sizeof(tp); - -#ifdef LUAJIT_USE_PERFTOOLS -/* -** Create symbol table of JIT-compiled code. For use with Linux perf tools. -** Example usage: -** perf record -f -e cycles luajit test.lua -** perf report -s symbol -** rm perf.data /tmp/perf-*.map -*/ -#include -#include - -static void perftools_addtrace(GCtrace *T) -{ - static FILE *fp; - GCproto *pt = &gcref(T->startpt)->pt; - const BCIns *startpc = mref(T->startpc, const BCIns); - const char *name = proto_chunknamestr(pt); - BCLine lineno; - if (name[0] == '@' || name[0] == '=') - name++; - else - name = "(string)"; - lua_assert(startpc >= proto_bc(pt) && startpc < proto_bc(pt) + pt->sizebc); - lineno = lj_debug_line(pt, proto_bcpos(pt, startpc)); - if (!fp) { - char fname[40]; - sprintf(fname, "/tmp/perf-%d.map", getpid()); - if (!(fp = fopen(fname, "w"))) return; - setlinebuf(fp); - } - fprintf(fp, "%lx %x TRACE_%d::%s:%u\n", - (long)T->mcode, T->szmcode, T->traceno, name, lineno); -} -#endif - -/* Allocate space for copy of T. */ -GCtrace * LJ_FASTCALL lj_trace_alloc(lua_State *L, GCtrace *T) -{ - size_t sztr = ((sizeof(GCtrace)+7)&~7); - size_t szins = (T->nins-T->nk)*sizeof(IRIns); - size_t sz = sztr + szins + - T->nsnap*sizeof(SnapShot) + - T->nsnapmap*sizeof(SnapEntry); - GCtrace *T2 = lj_mem_newt(L, (MSize)sz, GCtrace); - char *p = (char *)T2 + sztr; - T2->gct = ~LJ_TTRACE; - T2->marked = 0; - T2->traceno = 0; - T2->ir = (IRIns *)p - T->nk; - T2->nins = T->nins; - T2->nk = T->nk; - T2->nsnap = T->nsnap; - T2->nsnapmap = T->nsnapmap; - memcpy(p, T->ir + T->nk, szins); - return T2; -} - -/* Save current trace by copying and compacting it. */ -static void trace_save(jit_State *J, GCtrace *T) -{ - size_t sztr = ((sizeof(GCtrace)+7)&~7); - size_t szins = (J->cur.nins-J->cur.nk)*sizeof(IRIns); - char *p = (char *)T + sztr; - memcpy(T, &J->cur, sizeof(GCtrace)); - setgcrefr(T->nextgc, J2G(J)->gc.root); - setgcrefp(J2G(J)->gc.root, T); - newwhite(J2G(J), T); - T->gct = ~LJ_TTRACE; - T->ir = (IRIns *)p - J->cur.nk; /* The IR has already been copied above. */ - p += szins; - TRACE_APPENDVEC(snap, nsnap, SnapShot) - TRACE_APPENDVEC(snapmap, nsnapmap, SnapEntry) - J->cur.traceno = 0; - J->curfinal = NULL; - setgcrefp(J->trace[T->traceno], T); - lj_gc_barriertrace(J2G(J), T->traceno); - lj_gdbjit_addtrace(J, T); -#ifdef LUAJIT_USE_PERFTOOLS - perftools_addtrace(T); -#endif -} - -void LJ_FASTCALL lj_trace_free(global_State *g, GCtrace *T) -{ - jit_State *J = G2J(g); - if (T->traceno) { - lj_gdbjit_deltrace(J, T); - if (T->traceno < J->freetrace) - J->freetrace = T->traceno; - setgcrefnull(J->trace[T->traceno]); - } - lj_mem_free(g, T, - ((sizeof(GCtrace)+7)&~7) + (T->nins-T->nk)*sizeof(IRIns) + - T->nsnap*sizeof(SnapShot) + T->nsnapmap*sizeof(SnapEntry)); -} - -/* Re-enable compiling a prototype by unpatching any modified bytecode. */ -void lj_trace_reenableproto(GCproto *pt) -{ - if ((pt->flags & PROTO_ILOOP)) { - BCIns *bc = proto_bc(pt); - BCPos i, sizebc = pt->sizebc;; - pt->flags &= ~PROTO_ILOOP; - if (bc_op(bc[0]) == BC_IFUNCF) - setbc_op(&bc[0], BC_FUNCF); - for (i = 1; i < sizebc; i++) { - BCOp op = bc_op(bc[i]); - if (op == BC_IFORL || op == BC_IITERL || op == BC_ILOOP) - setbc_op(&bc[i], (int)op+(int)BC_LOOP-(int)BC_ILOOP); - } - } -} - -/* Unpatch the bytecode modified by a root trace. */ -static void trace_unpatch(jit_State *J, GCtrace *T) -{ - BCOp op = bc_op(T->startins); - BCIns *pc = mref(T->startpc, BCIns); - UNUSED(J); - if (op == BC_JMP) - return; /* No need to unpatch branches in parent traces (yet). */ - switch (bc_op(*pc)) { - case BC_JFORL: - lua_assert(traceref(J, bc_d(*pc)) == T); - *pc = T->startins; - pc += bc_j(T->startins); - lua_assert(bc_op(*pc) == BC_JFORI); - setbc_op(pc, BC_FORI); - break; - case BC_JITERL: - case BC_JLOOP: - lua_assert(op == BC_ITERL || op == BC_LOOP || bc_isret(op)); - *pc = T->startins; - break; - case BC_JMP: - lua_assert(op == BC_ITERL); - pc += bc_j(*pc)+2; - if (bc_op(*pc) == BC_JITERL) { - lua_assert(traceref(J, bc_d(*pc)) == T); - *pc = T->startins; - } - break; - case BC_JFUNCF: - lua_assert(op == BC_FUNCF); - *pc = T->startins; - break; - default: /* Already unpatched. */ - break; - } -} - -/* Flush a root trace. */ -static void trace_flushroot(jit_State *J, GCtrace *T) -{ - GCproto *pt = &gcref(T->startpt)->pt; - lua_assert(T->root == 0 && pt != NULL); - /* First unpatch any modified bytecode. */ - trace_unpatch(J, T); - /* Unlink root trace from chain anchored in prototype. */ - if (pt->trace == T->traceno) { /* Trace is first in chain. Easy. */ - pt->trace = T->nextroot; - } else if (pt->trace) { /* Otherwise search in chain of root traces. */ - GCtrace *T2 = traceref(J, pt->trace); - if (T2) { - for (; T2->nextroot; T2 = traceref(J, T2->nextroot)) - if (T2->nextroot == T->traceno) { - T2->nextroot = T->nextroot; /* Unlink from chain. */ - break; - } - } - } -} - -/* Flush a trace. Only root traces are considered. */ -void lj_trace_flush(jit_State *J, TraceNo traceno) -{ - if (traceno > 0 && traceno < J->sizetrace) { - GCtrace *T = traceref(J, traceno); - if (T && T->root == 0) - trace_flushroot(J, T); - } -} - -/* Flush all traces associated with a prototype. */ -void lj_trace_flushproto(global_State *g, GCproto *pt) -{ - while (pt->trace != 0) - trace_flushroot(G2J(g), traceref(G2J(g), pt->trace)); -} - -/* Flush all traces. */ -int lj_trace_flushall(lua_State *L) -{ - jit_State *J = L2J(L); - ptrdiff_t i; - if ((J2G(J)->hookmask & HOOK_GC)) - return 1; - for (i = (ptrdiff_t)J->sizetrace-1; i > 0; i--) { - GCtrace *T = traceref(J, i); - if (T) { - if (T->root == 0) - trace_flushroot(J, T); - lj_gdbjit_deltrace(J, T); - T->traceno = T->link = 0; /* Blacklist the link for cont_stitch. */ - setgcrefnull(J->trace[i]); - } - } - J->cur.traceno = 0; - J->freetrace = 0; - /* Clear penalty cache. */ - memset(J->penalty, 0, sizeof(J->penalty)); - /* Free the whole machine code and invalidate all exit stub groups. */ - lj_mcode_free(J); - memset(J->exitstubgroup, 0, sizeof(J->exitstubgroup)); - lj_vmevent_send(L, TRACE, - setstrV(L, L->top++, lj_str_newlit(L, "flush")); - ); - return 0; -} - -/* Initialize JIT compiler state. */ -void lj_trace_initstate(global_State *g) -{ - jit_State *J = G2J(g); - TValue *tv; - - /* Initialize aligned SIMD constants. */ - tv = LJ_KSIMD(J, LJ_KSIMD_ABS); - tv[0].u64 = U64x(7fffffff,ffffffff); - tv[1].u64 = U64x(7fffffff,ffffffff); - tv = LJ_KSIMD(J, LJ_KSIMD_NEG); - tv[0].u64 = U64x(80000000,00000000); - tv[1].u64 = U64x(80000000,00000000); - - /* Initialize 32/64 bit constants. */ -#if LJ_TARGET_X86ORX64 - J->k64[LJ_K64_TOBIT].u64 = U64x(43380000,00000000); -#if LJ_32 - J->k64[LJ_K64_M2P64_31].u64 = U64x(c1e00000,00000000); -#endif - J->k64[LJ_K64_2P64].u64 = U64x(43f00000,00000000); - J->k32[LJ_K32_M2P64_31] = LJ_64 ? 0xdf800000 : 0xcf000000; -#endif -#if LJ_TARGET_X86ORX64 || LJ_TARGET_MIPS64 - J->k64[LJ_K64_M2P64].u64 = U64x(c3f00000,00000000); -#endif -#if LJ_TARGET_PPC - J->k32[LJ_K32_2P52_2P31] = 0x59800004; - J->k32[LJ_K32_2P52] = 0x59800000; -#endif -#if LJ_TARGET_PPC || LJ_TARGET_MIPS - J->k32[LJ_K32_2P31] = 0x4f000000; -#endif -#if LJ_TARGET_MIPS - J->k64[LJ_K64_2P31].u64 = U64x(41e00000,00000000); -#if LJ_64 - J->k64[LJ_K64_2P63].u64 = U64x(43e00000,00000000); - J->k32[LJ_K32_2P63] = 0x5f000000; - J->k32[LJ_K32_M2P64] = 0xdf800000; -#endif -#endif -} - -/* Free everything associated with the JIT compiler state. */ -void lj_trace_freestate(global_State *g) -{ - jit_State *J = G2J(g); -#ifdef LUA_USE_ASSERT - { /* This assumes all traces have already been freed. */ - ptrdiff_t i; - for (i = 1; i < (ptrdiff_t)J->sizetrace; i++) - lua_assert(i == (ptrdiff_t)J->cur.traceno || traceref(J, i) == NULL); - } -#endif - lj_mcode_free(J); - lj_mem_freevec(g, J->snapmapbuf, J->sizesnapmap, SnapEntry); - lj_mem_freevec(g, J->snapbuf, J->sizesnap, SnapShot); - lj_mem_freevec(g, J->irbuf + J->irbotlim, J->irtoplim - J->irbotlim, IRIns); - lj_mem_freevec(g, J->trace, J->sizetrace, GCRef); -} - -/* -- Penalties and blacklisting ------------------------------------------ */ - -/* Blacklist a bytecode instruction. */ -static void blacklist_pc(GCproto *pt, BCIns *pc) -{ - setbc_op(pc, (int)bc_op(*pc)+(int)BC_ILOOP-(int)BC_LOOP); - pt->flags |= PROTO_ILOOP; -} - -/* Penalize a bytecode instruction. */ -static void penalty_pc(jit_State *J, GCproto *pt, BCIns *pc, TraceError e) -{ - uint32_t i, val = PENALTY_MIN; - for (i = 0; i < PENALTY_SLOTS; i++) - if (mref(J->penalty[i].pc, const BCIns) == pc) { /* Cache slot found? */ - /* First try to bump its hotcount several times. */ - val = ((uint32_t)J->penalty[i].val << 1) + - LJ_PRNG_BITS(J, PENALTY_RNDBITS); - if (val > PENALTY_MAX) { - blacklist_pc(pt, pc); /* Blacklist it, if that didn't help. */ - return; - } - goto setpenalty; - } - /* Assign a new penalty cache slot. */ - i = J->penaltyslot; - J->penaltyslot = (J->penaltyslot + 1) & (PENALTY_SLOTS-1); - setmref(J->penalty[i].pc, pc); -setpenalty: - J->penalty[i].val = (uint16_t)val; - J->penalty[i].reason = e; - hotcount_set(J2GG(J), pc+1, val); -} - -/* -- Trace compiler state machine ---------------------------------------- */ - -/* Start tracing. */ -static void trace_start(jit_State *J) -{ - lua_State *L; - TraceNo traceno; - - if ((J->pt->flags & PROTO_NOJIT)) { /* JIT disabled for this proto? */ - if (J->parent == 0 && J->exitno == 0) { - /* Lazy bytecode patching to disable hotcount events. */ - lua_assert(bc_op(*J->pc) == BC_FORL || bc_op(*J->pc) == BC_ITERL || - bc_op(*J->pc) == BC_LOOP || bc_op(*J->pc) == BC_FUNCF); - setbc_op(J->pc, (int)bc_op(*J->pc)+(int)BC_ILOOP-(int)BC_LOOP); - J->pt->flags |= PROTO_ILOOP; - } - J->state = LJ_TRACE_IDLE; /* Silently ignored. */ - return; - } - - /* Get a new trace number. */ - traceno = trace_findfree(J); - if (LJ_UNLIKELY(traceno == 0)) { /* No free trace? */ - lua_assert((J2G(J)->hookmask & HOOK_GC) == 0); - lj_trace_flushall(J->L); - J->state = LJ_TRACE_IDLE; /* Silently ignored. */ - return; - } - setgcrefp(J->trace[traceno], &J->cur); - - /* Setup enough of the current trace to be able to send the vmevent. */ - memset(&J->cur, 0, sizeof(GCtrace)); - J->cur.traceno = traceno; - J->cur.nins = J->cur.nk = REF_BASE; - J->cur.ir = J->irbuf; - J->cur.snap = J->snapbuf; - J->cur.snapmap = J->snapmapbuf; - J->mergesnap = 0; - J->needsnap = 0; - J->bcskip = 0; - J->guardemit.irt = 0; - J->postproc = LJ_POST_NONE; - lj_resetsplit(J); - J->retryrec = 0; - J->ktrace = 0; - setgcref(J->cur.startpt, obj2gco(J->pt)); - - L = J->L; - lj_vmevent_send(L, TRACE, - setstrV(L, L->top++, lj_str_newlit(L, "start")); - setintV(L->top++, traceno); - setfuncV(L, L->top++, J->fn); - setintV(L->top++, proto_bcpos(J->pt, J->pc)); - if (J->parent) { - setintV(L->top++, J->parent); - setintV(L->top++, J->exitno); - } else { - BCOp op = bc_op(*J->pc); - if (op == BC_CALLM || op == BC_CALL || op == BC_ITERC) { - setintV(L->top++, J->exitno); /* Parent of stitched trace. */ - setintV(L->top++, -1); - } - } - ); - lj_record_setup(J); -} - -/* Stop tracing. */ -static void trace_stop(jit_State *J) -{ - BCIns *pc = mref(J->cur.startpc, BCIns); - BCOp op = bc_op(J->cur.startins); - GCproto *pt = &gcref(J->cur.startpt)->pt; - TraceNo traceno = J->cur.traceno; - GCtrace *T = J->curfinal; - lua_State *L; - - switch (op) { - case BC_FORL: - setbc_op(pc+bc_j(J->cur.startins), BC_JFORI); /* Patch FORI, too. */ - /* fallthrough */ - case BC_LOOP: - case BC_ITERL: - case BC_FUNCF: - /* Patch bytecode of starting instruction in root trace. */ - setbc_op(pc, (int)op+(int)BC_JLOOP-(int)BC_LOOP); - setbc_d(pc, traceno); - addroot: - /* Add to root trace chain in prototype. */ - J->cur.nextroot = pt->trace; - pt->trace = (TraceNo1)traceno; - break; - case BC_RET: - case BC_RET0: - case BC_RET1: - *pc = BCINS_AD(BC_JLOOP, J->cur.snap[0].nslots, traceno); - goto addroot; - case BC_JMP: - /* Patch exit branch in parent to side trace entry. */ - lua_assert(J->parent != 0 && J->cur.root != 0); - lj_asm_patchexit(J, traceref(J, J->parent), J->exitno, J->cur.mcode); - /* Avoid compiling a side trace twice (stack resizing uses parent exit). */ - traceref(J, J->parent)->snap[J->exitno].count = SNAPCOUNT_DONE; - /* Add to side trace chain in root trace. */ - { - GCtrace *root = traceref(J, J->cur.root); - root->nchild++; - J->cur.nextside = root->nextside; - root->nextside = (TraceNo1)traceno; - } - break; - case BC_CALLM: - case BC_CALL: - case BC_ITERC: - /* Trace stitching: patch link of previous trace. */ - traceref(J, J->exitno)->link = traceno; - break; - default: - lua_assert(0); - break; - } - - /* Commit new mcode only after all patching is done. */ - lj_mcode_commit(J, J->cur.mcode); - J->postproc = LJ_POST_NONE; - trace_save(J, T); - - L = J->L; - lj_vmevent_send(L, TRACE, - setstrV(L, L->top++, lj_str_newlit(L, "stop")); - setintV(L->top++, traceno); - setfuncV(L, L->top++, J->fn); - ); -} - -/* Start a new root trace for down-recursion. */ -static int trace_downrec(jit_State *J) -{ - /* Restart recording at the return instruction. */ - lua_assert(J->pt != NULL); - lua_assert(bc_isret(bc_op(*J->pc))); - if (bc_op(*J->pc) == BC_RETM) - return 0; /* NYI: down-recursion with RETM. */ - J->parent = 0; - J->exitno = 0; - J->state = LJ_TRACE_RECORD; - trace_start(J); - return 1; -} - -/* Abort tracing. */ -static int trace_abort(jit_State *J) -{ - lua_State *L = J->L; - TraceError e = LJ_TRERR_RECERR; - TraceNo traceno; - - J->postproc = LJ_POST_NONE; - lj_mcode_abort(J); - if (J->curfinal) { - lj_trace_free(J2G(J), J->curfinal); - J->curfinal = NULL; - } - if (tvisnumber(L->top-1)) - e = (TraceError)numberVint(L->top-1); - if (e == LJ_TRERR_MCODELM) { - L->top--; /* Remove error object */ - J->state = LJ_TRACE_ASM; - return 1; /* Retry ASM with new MCode area. */ - } - /* Penalize or blacklist starting bytecode instruction. */ - if (J->parent == 0 && !bc_isret(bc_op(J->cur.startins))) { - if (J->exitno == 0) { - BCIns *startpc = mref(J->cur.startpc, BCIns); - if (e == LJ_TRERR_RETRY) - hotcount_set(J2GG(J), startpc+1, 1); /* Immediate retry. */ - else - penalty_pc(J, &gcref(J->cur.startpt)->pt, startpc, e); - } else { - traceref(J, J->exitno)->link = J->exitno; /* Self-link is blacklisted. */ - } - } - - /* Is there anything to abort? */ - traceno = J->cur.traceno; - if (traceno) { - ptrdiff_t errobj = savestack(L, L->top-1); /* Stack may be resized. */ - J->cur.link = 0; - J->cur.linktype = LJ_TRLINK_NONE; - lj_vmevent_send(L, TRACE, - TValue *frame; - const BCIns *pc; - GCfunc *fn; - setstrV(L, L->top++, lj_str_newlit(L, "abort")); - setintV(L->top++, traceno); - /* Find original Lua function call to generate a better error message. */ - frame = J->L->base-1; - pc = J->pc; - while (!isluafunc(frame_func(frame))) { - pc = (frame_iscont(frame) ? frame_contpc(frame) : frame_pc(frame)) - 1; - frame = frame_prev(frame); - } - fn = frame_func(frame); - setfuncV(L, L->top++, fn); - setintV(L->top++, proto_bcpos(funcproto(fn), pc)); - copyTV(L, L->top++, restorestack(L, errobj)); - copyTV(L, L->top++, &J->errinfo); - ); - /* Drop aborted trace after the vmevent (which may still access it). */ - setgcrefnull(J->trace[traceno]); - if (traceno < J->freetrace) - J->freetrace = traceno; - J->cur.traceno = 0; - } - L->top--; /* Remove error object */ - if (e == LJ_TRERR_DOWNREC) - return trace_downrec(J); - else if (e == LJ_TRERR_MCODEAL) - lj_trace_flushall(L); - return 0; -} - -/* Perform pending re-patch of a bytecode instruction. */ -static LJ_AINLINE void trace_pendpatch(jit_State *J, int force) -{ - if (LJ_UNLIKELY(J->patchpc)) { - if (force || J->bcskip == 0) { - *J->patchpc = J->patchins; - J->patchpc = NULL; - } else { - J->bcskip = 0; - } - } -} - -/* State machine for the trace compiler. Protected callback. */ -static TValue *trace_state(lua_State *L, lua_CFunction dummy, void *ud) -{ - jit_State *J = (jit_State *)ud; - UNUSED(dummy); - do { - retry: - switch (J->state) { - case LJ_TRACE_START: - J->state = LJ_TRACE_RECORD; /* trace_start() may change state. */ - trace_start(J); - lj_dispatch_update(J2G(J)); - break; - - case LJ_TRACE_RECORD: - trace_pendpatch(J, 0); - setvmstate(J2G(J), RECORD); - lj_vmevent_send_(L, RECORD, - /* Save/restore tmptv state for trace recorder. */ - TValue savetv = J2G(J)->tmptv; - TValue savetv2 = J2G(J)->tmptv2; - setintV(L->top++, J->cur.traceno); - setfuncV(L, L->top++, J->fn); - setintV(L->top++, J->pt ? (int32_t)proto_bcpos(J->pt, J->pc) : -1); - setintV(L->top++, J->framedepth); - , - J2G(J)->tmptv = savetv; - J2G(J)->tmptv2 = savetv2; - ); - lj_record_ins(J); - break; - - case LJ_TRACE_END: - trace_pendpatch(J, 1); - J->loopref = 0; - if ((J->flags & JIT_F_OPT_LOOP) && - J->cur.link == J->cur.traceno && J->framedepth + J->retdepth == 0) { - setvmstate(J2G(J), OPT); - lj_opt_dce(J); - if (lj_opt_loop(J)) { /* Loop optimization failed? */ - J->cur.link = 0; - J->cur.linktype = LJ_TRLINK_NONE; - J->loopref = J->cur.nins; - J->state = LJ_TRACE_RECORD; /* Try to continue recording. */ - break; - } - J->loopref = J->chain[IR_LOOP]; /* Needed by assembler. */ - } - lj_opt_split(J); - lj_opt_sink(J); - if (!J->loopref) J->cur.snap[J->cur.nsnap-1].count = SNAPCOUNT_DONE; - J->state = LJ_TRACE_ASM; - break; - - case LJ_TRACE_ASM: - setvmstate(J2G(J), ASM); - lj_asm_trace(J, &J->cur); - trace_stop(J); - setvmstate(J2G(J), INTERP); - J->state = LJ_TRACE_IDLE; - lj_dispatch_update(J2G(J)); - return NULL; - - default: /* Trace aborted asynchronously. */ - setintV(L->top++, (int32_t)LJ_TRERR_RECERR); - /* fallthrough */ - case LJ_TRACE_ERR: - trace_pendpatch(J, 1); - if (trace_abort(J)) - goto retry; - setvmstate(J2G(J), INTERP); - J->state = LJ_TRACE_IDLE; - lj_dispatch_update(J2G(J)); - return NULL; - } - } while (J->state > LJ_TRACE_RECORD); - return NULL; -} - -/* -- Event handling ------------------------------------------------------ */ - -/* A bytecode instruction is about to be executed. Record it. */ -void lj_trace_ins(jit_State *J, const BCIns *pc) -{ - /* Note: J->L must already be set. pc is the true bytecode PC here. */ - J->pc = pc; - J->fn = curr_func(J->L); - J->pt = isluafunc(J->fn) ? funcproto(J->fn) : NULL; - while (lj_vm_cpcall(J->L, NULL, (void *)J, trace_state) != 0) - J->state = LJ_TRACE_ERR; -} - -/* A hotcount triggered. Start recording a root trace. */ -void LJ_FASTCALL lj_trace_hot(jit_State *J, const BCIns *pc) -{ - /* Note: pc is the interpreter bytecode PC here. It's offset by 1. */ - ERRNO_SAVE - /* Reset hotcount. */ - hotcount_set(J2GG(J), pc, J->param[JIT_P_hotloop]*HOTCOUNT_LOOP); - /* Only start a new trace if not recording or inside __gc call or vmevent. */ - if (J->state == LJ_TRACE_IDLE && - !(J2G(J)->hookmask & (HOOK_GC|HOOK_VMEVENT))) { - J->parent = 0; /* Root trace. */ - J->exitno = 0; - J->state = LJ_TRACE_START; - lj_trace_ins(J, pc-1); - } - ERRNO_RESTORE -} - -/* Check for a hot side exit. If yes, start recording a side trace. */ -static void trace_hotside(jit_State *J, const BCIns *pc) -{ - SnapShot *snap = &traceref(J, J->parent)->snap[J->exitno]; - if (!(J2G(J)->hookmask & (HOOK_GC|HOOK_VMEVENT)) && - isluafunc(curr_func(J->L)) && - snap->count != SNAPCOUNT_DONE && - ++snap->count >= J->param[JIT_P_hotexit]) { - lua_assert(J->state == LJ_TRACE_IDLE); - /* J->parent is non-zero for a side trace. */ - J->state = LJ_TRACE_START; - lj_trace_ins(J, pc); - } -} - -/* Stitch a new trace to the previous trace. */ -void LJ_FASTCALL lj_trace_stitch(jit_State *J, const BCIns *pc) -{ - /* Only start a new trace if not recording or inside __gc call or vmevent. */ - if (J->state == LJ_TRACE_IDLE && - !(J2G(J)->hookmask & (HOOK_GC|HOOK_VMEVENT))) { - J->parent = 0; /* Have to treat it like a root trace. */ - /* J->exitno is set to the invoking trace. */ - J->state = LJ_TRACE_START; - lj_trace_ins(J, pc); - } -} - - -/* Tiny struct to pass data to protected call. */ -typedef struct ExitDataCP { - jit_State *J; - void *exptr; /* Pointer to exit state. */ - const BCIns *pc; /* Restart interpreter at this PC. */ -} ExitDataCP; - -/* Need to protect lj_snap_restore because it may throw. */ -static TValue *trace_exit_cp(lua_State *L, lua_CFunction dummy, void *ud) -{ - ExitDataCP *exd = (ExitDataCP *)ud; - cframe_errfunc(L->cframe) = -1; /* Inherit error function. */ - exd->pc = lj_snap_restore(exd->J, exd->exptr); - UNUSED(dummy); - return NULL; -} - -#ifndef LUAJIT_DISABLE_VMEVENT -/* Push all registers from exit state. */ -static void trace_exit_regs(lua_State *L, ExitState *ex) -{ - int32_t i; - setintV(L->top++, RID_NUM_GPR); - setintV(L->top++, RID_NUM_FPR); - for (i = 0; i < RID_NUM_GPR; i++) { - if (sizeof(ex->gpr[i]) == sizeof(int32_t)) - setintV(L->top++, (int32_t)ex->gpr[i]); - else - setnumV(L->top++, (lua_Number)ex->gpr[i]); - } -#if !LJ_SOFTFP - for (i = 0; i < RID_NUM_FPR; i++) { - setnumV(L->top, ex->fpr[i]); - if (LJ_UNLIKELY(tvisnan(L->top))) - setnanV(L->top); - L->top++; - } -#endif -} -#endif - -#ifdef EXITSTATE_PCREG -/* Determine trace number from pc of exit instruction. */ -static TraceNo trace_exit_find(jit_State *J, MCode *pc) -{ - TraceNo traceno; - for (traceno = 1; traceno < J->sizetrace; traceno++) { - GCtrace *T = traceref(J, traceno); - if (T && pc >= T->mcode && pc < (MCode *)((char *)T->mcode + T->szmcode)) - return traceno; - } - lua_assert(0); - return 0; -} -#endif - -/* A trace exited. Restore interpreter state. */ -int LJ_FASTCALL lj_trace_exit(jit_State *J, void *exptr) -{ - ERRNO_SAVE - lua_State *L = J->L; - ExitState *ex = (ExitState *)exptr; - ExitDataCP exd; - int errcode; - const BCIns *pc; - void *cf; - GCtrace *T; -#ifdef EXITSTATE_PCREG - J->parent = trace_exit_find(J, (MCode *)(intptr_t)ex->gpr[EXITSTATE_PCREG]); -#endif - T = traceref(J, J->parent); UNUSED(T); -#ifdef EXITSTATE_CHECKEXIT - if (J->exitno == T->nsnap) { /* Treat stack check like a parent exit. */ - lua_assert(T->root != 0); - J->exitno = T->ir[REF_BASE].op2; - J->parent = T->ir[REF_BASE].op1; - T = traceref(J, J->parent); - } -#endif - lua_assert(T != NULL && J->exitno < T->nsnap); - exd.J = J; - exd.exptr = exptr; - errcode = lj_vm_cpcall(L, NULL, &exd, trace_exit_cp); - if (errcode) - return -errcode; /* Return negated error code. */ - - if (!(LJ_HASPROFILE && (G(L)->hookmask & HOOK_PROFILE))) - lj_vmevent_send(L, TEXIT, - lj_state_checkstack(L, 4+RID_NUM_GPR+RID_NUM_FPR+LUA_MINSTACK); - setintV(L->top++, J->parent); - setintV(L->top++, J->exitno); - trace_exit_regs(L, ex); - ); - - pc = exd.pc; - cf = cframe_raw(L->cframe); - setcframe_pc(cf, pc); - if (LJ_HASPROFILE && (G(L)->hookmask & HOOK_PROFILE)) { - /* Just exit to interpreter. */ - } else if (G(L)->gc.state == GCSatomic || G(L)->gc.state == GCSfinalize) { - if (!(G(L)->hookmask & HOOK_GC)) - lj_gc_step(L); /* Exited because of GC: drive GC forward. */ - } else { - trace_hotside(J, pc); - } - if (bc_op(*pc) == BC_JLOOP) { - BCIns *retpc = &traceref(J, bc_d(*pc))->startins; - if (bc_isret(bc_op(*retpc))) { - if (J->state == LJ_TRACE_RECORD) { - J->patchins = *pc; - J->patchpc = (BCIns *)pc; - *J->patchpc = *retpc; - J->bcskip = 1; - } else { - pc = retpc; - setcframe_pc(cf, pc); - } - } - } - /* Return MULTRES or 0. */ - ERRNO_RESTORE - switch (bc_op(*pc)) { - case BC_CALLM: case BC_CALLMT: - return (int)((BCReg)(L->top - L->base) - bc_a(*pc) - bc_c(*pc) - LJ_FR2); - case BC_RETM: - return (int)((BCReg)(L->top - L->base) + 1 - bc_a(*pc) - bc_d(*pc)); - case BC_TSETM: - return (int)((BCReg)(L->top - L->base) + 1 - bc_a(*pc)); - default: - if (bc_op(*pc) >= BC_FUNCF) - return (int)((BCReg)(L->top - L->base) + 1); - return 0; - } -} - -#endif diff --git a/lib/LuaJIT/src/lj_trace.h b/lib/LuaJIT/src/lj_trace.h deleted file mode 100644 index 22cae74..0000000 --- a/lib/LuaJIT/src/lj_trace.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -** Trace management. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_TRACE_H -#define _LJ_TRACE_H - -#include "lj_obj.h" - -#if LJ_HASJIT -#include "lj_jit.h" -#include "lj_dispatch.h" - -/* Trace errors. */ -typedef enum { -#define TREDEF(name, msg) LJ_TRERR_##name, -#include "lj_traceerr.h" - LJ_TRERR__MAX -} TraceError; - -LJ_FUNC_NORET void lj_trace_err(jit_State *J, TraceError e); -LJ_FUNC_NORET void lj_trace_err_info(jit_State *J, TraceError e); - -/* Trace management. */ -LJ_FUNC GCtrace * LJ_FASTCALL lj_trace_alloc(lua_State *L, GCtrace *T); -LJ_FUNC void LJ_FASTCALL lj_trace_free(global_State *g, GCtrace *T); -LJ_FUNC void lj_trace_reenableproto(GCproto *pt); -LJ_FUNC void lj_trace_flushproto(global_State *g, GCproto *pt); -LJ_FUNC void lj_trace_flush(jit_State *J, TraceNo traceno); -LJ_FUNC int lj_trace_flushall(lua_State *L); -LJ_FUNC void lj_trace_initstate(global_State *g); -LJ_FUNC void lj_trace_freestate(global_State *g); - -/* Event handling. */ -LJ_FUNC void lj_trace_ins(jit_State *J, const BCIns *pc); -LJ_FUNCA void LJ_FASTCALL lj_trace_hot(jit_State *J, const BCIns *pc); -LJ_FUNCA void LJ_FASTCALL lj_trace_stitch(jit_State *J, const BCIns *pc); -LJ_FUNCA int LJ_FASTCALL lj_trace_exit(jit_State *J, void *exptr); - -/* Signal asynchronous abort of trace or end of trace. */ -#define lj_trace_abort(g) (G2J(g)->state &= ~LJ_TRACE_ACTIVE) -#define lj_trace_end(J) (J->state = LJ_TRACE_END) - -#else - -#define lj_trace_flushall(L) (UNUSED(L), 0) -#define lj_trace_initstate(g) UNUSED(g) -#define lj_trace_freestate(g) UNUSED(g) -#define lj_trace_abort(g) UNUSED(g) -#define lj_trace_end(J) UNUSED(J) - -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_traceerr.h b/lib/LuaJIT/src/lj_traceerr.h deleted file mode 100644 index 1363c4f..0000000 --- a/lib/LuaJIT/src/lj_traceerr.h +++ /dev/null @@ -1,61 +0,0 @@ -/* -** Trace compiler error messages. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -/* This file may be included multiple times with different TREDEF macros. */ - -/* Recording. */ -TREDEF(RECERR, "error thrown or hook called during recording") -TREDEF(TRACEUV, "trace too short") -TREDEF(TRACEOV, "trace too long") -TREDEF(STACKOV, "trace too deep") -TREDEF(SNAPOV, "too many snapshots") -TREDEF(BLACKL, "blacklisted") -TREDEF(RETRY, "retry recording") -TREDEF(NYIBC, "NYI: bytecode %d") - -/* Recording loop ops. */ -TREDEF(LLEAVE, "leaving loop in root trace") -TREDEF(LINNER, "inner loop in root trace") -TREDEF(LUNROLL, "loop unroll limit reached") - -/* Recording calls/returns. */ -TREDEF(BADTYPE, "bad argument type") -TREDEF(CJITOFF, "JIT compilation disabled for function") -TREDEF(CUNROLL, "call unroll limit reached") -TREDEF(DOWNREC, "down-recursion, restarting") -TREDEF(NYIFFU, "NYI: unsupported variant of FastFunc %s") -TREDEF(NYIRETL, "NYI: return to lower frame") - -/* Recording indexed load/store. */ -TREDEF(STORENN, "store with nil or NaN key") -TREDEF(NOMM, "missing metamethod") -TREDEF(IDXLOOP, "looping index lookup") -TREDEF(NYITMIX, "NYI: mixed sparse/dense table") - -/* Recording C data operations. */ -TREDEF(NOCACHE, "symbol not in cache") -TREDEF(NYICONV, "NYI: unsupported C type conversion") -TREDEF(NYICALL, "NYI: unsupported C function type") - -/* Optimizations. */ -TREDEF(GFAIL, "guard would always fail") -TREDEF(PHIOV, "too many PHIs") -TREDEF(TYPEINS, "persistent type instability") - -/* Assembler. */ -TREDEF(MCODEAL, "failed to allocate mcode memory") -TREDEF(MCODEOV, "machine code too long") -TREDEF(MCODELM, "hit mcode limit (retrying)") -TREDEF(SPILLOV, "too many spill slots") -TREDEF(BADRA, "inconsistent register allocation") -TREDEF(NYIIR, "NYI: cannot assemble IR instruction %d") -TREDEF(NYIPHI, "NYI: PHI shuffling too complex") -TREDEF(NYICOAL, "NYI: register coalescing too complex") - -#undef TREDEF - -/* Detecting unused error messages: - awk -F, '/^TREDEF/ { gsub(/TREDEF./, ""); printf "grep -q LJ_TRERR_%s *.[ch] || echo %s\n", $1, $1}' lj_traceerr.h | sh -*/ diff --git a/lib/LuaJIT/src/lj_udata.c b/lib/LuaJIT/src/lj_udata.c deleted file mode 100644 index bd0321b..0000000 --- a/lib/LuaJIT/src/lj_udata.c +++ /dev/null @@ -1,34 +0,0 @@ -/* -** Userdata handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_udata_c -#define LUA_CORE - -#include "lj_obj.h" -#include "lj_gc.h" -#include "lj_udata.h" - -GCudata *lj_udata_new(lua_State *L, MSize sz, GCtab *env) -{ - GCudata *ud = lj_mem_newt(L, sizeof(GCudata) + sz, GCudata); - global_State *g = G(L); - newwhite(g, ud); /* Not finalized. */ - ud->gct = ~LJ_TUDATA; - ud->udtype = UDTYPE_USERDATA; - ud->len = sz; - /* NOBARRIER: The GCudata is new (marked white). */ - setgcrefnull(ud->metatable); - setgcref(ud->env, obj2gco(env)); - /* Chain to userdata list (after main thread). */ - setgcrefr(ud->nextgc, mainthread(g)->nextgc); - setgcref(mainthread(g)->nextgc, obj2gco(ud)); - return ud; -} - -void LJ_FASTCALL lj_udata_free(global_State *g, GCudata *ud) -{ - lj_mem_free(g, ud, sizeudata(ud)); -} - diff --git a/lib/LuaJIT/src/lj_udata.h b/lib/LuaJIT/src/lj_udata.h deleted file mode 100644 index f271a42..0000000 --- a/lib/LuaJIT/src/lj_udata.h +++ /dev/null @@ -1,14 +0,0 @@ -/* -** Userdata handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_UDATA_H -#define _LJ_UDATA_H - -#include "lj_obj.h" - -LJ_FUNC GCudata *lj_udata_new(lua_State *L, MSize sz, GCtab *env); -LJ_FUNC void LJ_FASTCALL lj_udata_free(global_State *g, GCudata *ud); - -#endif diff --git a/lib/LuaJIT/src/lj_vm.h b/lib/LuaJIT/src/lj_vm.h deleted file mode 100644 index 1cc7eed..0000000 --- a/lib/LuaJIT/src/lj_vm.h +++ /dev/null @@ -1,120 +0,0 @@ -/* -** Assembler VM interface definitions. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_VM_H -#define _LJ_VM_H - -#include "lj_obj.h" - -/* Entry points for ASM parts of VM. */ -LJ_ASMF void lj_vm_call(lua_State *L, TValue *base, int nres1); -LJ_ASMF int lj_vm_pcall(lua_State *L, TValue *base, int nres1, ptrdiff_t ef); -typedef TValue *(*lua_CPFunction)(lua_State *L, lua_CFunction func, void *ud); -LJ_ASMF int lj_vm_cpcall(lua_State *L, lua_CFunction func, void *ud, - lua_CPFunction cp); -LJ_ASMF int lj_vm_resume(lua_State *L, TValue *base, int nres1, ptrdiff_t ef); -LJ_ASMF_NORET void LJ_FASTCALL lj_vm_unwind_c(void *cframe, int errcode); -LJ_ASMF_NORET void LJ_FASTCALL lj_vm_unwind_ff(void *cframe); -#if LJ_ABI_WIN && LJ_TARGET_X86 -LJ_ASMF_NORET void LJ_FASTCALL lj_vm_rtlunwind(void *cframe, void *excptrec, - void *unwinder, int errcode); -#endif -LJ_ASMF void lj_vm_unwind_c_eh(void); -LJ_ASMF void lj_vm_unwind_ff_eh(void); -#if LJ_TARGET_X86ORX64 -LJ_ASMF void lj_vm_unwind_rethrow(void); -#endif - -/* Miscellaneous functions. */ -#if LJ_TARGET_X86ORX64 -LJ_ASMF int lj_vm_cpuid(uint32_t f, uint32_t res[4]); -#endif -#if LJ_TARGET_PPC -void lj_vm_cachesync(void *start, void *end); -#endif -LJ_ASMF double lj_vm_foldarith(double x, double y, int op); -#if LJ_HASJIT -LJ_ASMF double lj_vm_foldfpm(double x, int op); -#endif -#if !LJ_ARCH_HASFPU -/* Declared in lj_obj.h: LJ_ASMF int32_t lj_vm_tobit(double x); */ -#endif - -/* Dispatch targets for recording and hooks. */ -LJ_ASMF void lj_vm_record(void); -LJ_ASMF void lj_vm_inshook(void); -LJ_ASMF void lj_vm_rethook(void); -LJ_ASMF void lj_vm_callhook(void); -LJ_ASMF void lj_vm_profhook(void); - -/* Trace exit handling. */ -LJ_ASMF void lj_vm_exit_handler(void); -LJ_ASMF void lj_vm_exit_interp(void); - -/* Internal math helper functions. */ -#if LJ_TARGET_PPC || LJ_TARGET_ARM64 || (LJ_TARGET_MIPS && LJ_ABI_SOFTFP) -#define lj_vm_floor floor -#define lj_vm_ceil ceil -#else -LJ_ASMF double lj_vm_floor(double); -LJ_ASMF double lj_vm_ceil(double); -#if LJ_TARGET_ARM -LJ_ASMF double lj_vm_floor_sf(double); -LJ_ASMF double lj_vm_ceil_sf(double); -#endif -#endif -#ifdef LUAJIT_NO_LOG2 -LJ_ASMF double lj_vm_log2(double); -#else -#define lj_vm_log2 log2 -#endif -#if !(defined(_LJ_DISPATCH_H) && LJ_TARGET_MIPS) -LJ_ASMF int32_t LJ_FASTCALL lj_vm_modi(int32_t, int32_t); -#endif - -#if LJ_HASJIT -#if LJ_TARGET_X86ORX64 -LJ_ASMF void lj_vm_floor_sse(void); -LJ_ASMF void lj_vm_ceil_sse(void); -LJ_ASMF void lj_vm_trunc_sse(void); -LJ_ASMF void lj_vm_powi_sse(void); -#define lj_vm_powi NULL -#else -LJ_ASMF double lj_vm_powi(double, int32_t); -#endif -#if LJ_TARGET_PPC || LJ_TARGET_ARM64 -#define lj_vm_trunc trunc -#else -LJ_ASMF double lj_vm_trunc(double); -#if LJ_TARGET_ARM -LJ_ASMF double lj_vm_trunc_sf(double); -#endif -#endif -#ifdef LUAJIT_NO_EXP2 -LJ_ASMF double lj_vm_exp2(double); -#else -#define lj_vm_exp2 exp2 -#endif -#if LJ_HASFFI -LJ_ASMF int lj_vm_errno(void); -#endif -#endif - -/* Continuations for metamethods. */ -LJ_ASMF void lj_cont_cat(void); /* Continue with concatenation. */ -LJ_ASMF void lj_cont_ra(void); /* Store result in RA from instruction. */ -LJ_ASMF void lj_cont_nop(void); /* Do nothing, just continue execution. */ -LJ_ASMF void lj_cont_condt(void); /* Branch if result is true. */ -LJ_ASMF void lj_cont_condf(void); /* Branch if result is false. */ -LJ_ASMF void lj_cont_hook(void); /* Continue from hook yield. */ -LJ_ASMF void lj_cont_stitch(void); /* Trace stitching. */ - -/* Start of the ASM code. */ -LJ_ASMF char lj_vm_asm_begin[]; - -/* Bytecode offsets are relative to lj_vm_asm_begin. */ -#define makeasmfunc(ofs) ((ASMFunction)(lj_vm_asm_begin + (ofs))) - -#endif diff --git a/lib/LuaJIT/src/lj_vmevent.c b/lib/LuaJIT/src/lj_vmevent.c deleted file mode 100644 index 8664080..0000000 --- a/lib/LuaJIT/src/lj_vmevent.c +++ /dev/null @@ -1,58 +0,0 @@ -/* -** VM event handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#include - -#define lj_vmevent_c -#define LUA_CORE - -#include "lj_obj.h" -#include "lj_str.h" -#include "lj_tab.h" -#include "lj_state.h" -#include "lj_dispatch.h" -#include "lj_vm.h" -#include "lj_vmevent.h" - -ptrdiff_t lj_vmevent_prepare(lua_State *L, VMEvent ev) -{ - global_State *g = G(L); - GCstr *s = lj_str_newlit(L, LJ_VMEVENTS_REGKEY); - cTValue *tv = lj_tab_getstr(tabV(registry(L)), s); - if (tvistab(tv)) { - int hash = VMEVENT_HASH(ev); - tv = lj_tab_getint(tabV(tv), hash); - if (tv && tvisfunc(tv)) { - lj_state_checkstack(L, LUA_MINSTACK); - setfuncV(L, L->top++, funcV(tv)); - if (LJ_FR2) setnilV(L->top++); - return savestack(L, L->top); - } - } - g->vmevmask &= ~VMEVENT_MASK(ev); /* No handler: cache this fact. */ - return 0; -} - -void lj_vmevent_call(lua_State *L, ptrdiff_t argbase) -{ - global_State *g = G(L); - uint8_t oldmask = g->vmevmask; - uint8_t oldh = hook_save(g); - int status; - g->vmevmask = 0; /* Disable all events. */ - hook_vmevent(g); - status = lj_vm_pcall(L, restorestack(L, argbase), 0+1, 0); - if (LJ_UNLIKELY(status)) { - /* Really shouldn't use stderr here, but where else to complain? */ - L->top--; - fputs("VM handler failed: ", stderr); - fputs(tvisstr(L->top) ? strVdata(L->top) : "?", stderr); - fputc('\n', stderr); - } - hook_restore(g, oldh); - if (g->vmevmask != VMEVENT_NOCACHE) - g->vmevmask = oldmask; /* Restore event mask, but not if not modified. */ -} - diff --git a/lib/LuaJIT/src/lj_vmevent.h b/lib/LuaJIT/src/lj_vmevent.h deleted file mode 100644 index 050fb4d..0000000 --- a/lib/LuaJIT/src/lj_vmevent.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -** VM event handling. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LJ_VMEVENT_H -#define _LJ_VMEVENT_H - -#include "lj_obj.h" - -/* Registry key for VM event handler table. */ -#define LJ_VMEVENTS_REGKEY "_VMEVENTS" -#define LJ_VMEVENTS_HSIZE 4 - -#define VMEVENT_MASK(ev) ((uint8_t)1 << ((int)(ev) & 7)) -#define VMEVENT_HASH(ev) ((int)(ev) & ~7) -#define VMEVENT_HASHIDX(h) ((int)(h) << 3) -#define VMEVENT_NOCACHE 255 - -#define VMEVENT_DEF(name, hash) \ - LJ_VMEVENT_##name##_, \ - LJ_VMEVENT_##name = ((LJ_VMEVENT_##name##_) & 7)|((hash) << 3) - -/* VM event IDs. */ -typedef enum { - VMEVENT_DEF(BC, 0x00003883), - VMEVENT_DEF(TRACE, 0xb2d91467), - VMEVENT_DEF(RECORD, 0x9284bf4f), - VMEVENT_DEF(TEXIT, 0xb29df2b0), - LJ_VMEVENT__MAX -} VMEvent; - -#ifdef LUAJIT_DISABLE_VMEVENT -#define lj_vmevent_send(L, ev, args) UNUSED(L) -#define lj_vmevent_send_(L, ev, args, post) UNUSED(L) -#else -#define lj_vmevent_send(L, ev, args) \ - if (G(L)->vmevmask & VMEVENT_MASK(LJ_VMEVENT_##ev)) { \ - ptrdiff_t argbase = lj_vmevent_prepare(L, LJ_VMEVENT_##ev); \ - if (argbase) { \ - args \ - lj_vmevent_call(L, argbase); \ - } \ - } -#define lj_vmevent_send_(L, ev, args, post) \ - if (G(L)->vmevmask & VMEVENT_MASK(LJ_VMEVENT_##ev)) { \ - ptrdiff_t argbase = lj_vmevent_prepare(L, LJ_VMEVENT_##ev); \ - if (argbase) { \ - args \ - lj_vmevent_call(L, argbase); \ - post \ - } \ - } - -LJ_FUNC ptrdiff_t lj_vmevent_prepare(lua_State *L, VMEvent ev); -LJ_FUNC void lj_vmevent_call(lua_State *L, ptrdiff_t argbase); -#endif - -#endif diff --git a/lib/LuaJIT/src/lj_vmmath.c b/lib/LuaJIT/src/lj_vmmath.c deleted file mode 100644 index b231d3e..0000000 --- a/lib/LuaJIT/src/lj_vmmath.c +++ /dev/null @@ -1,152 +0,0 @@ -/* -** Math helper functions for assembler VM. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#define lj_vmmath_c -#define LUA_CORE - -#include -#include - -#include "lj_obj.h" -#include "lj_ir.h" -#include "lj_vm.h" - -/* -- Wrapper functions --------------------------------------------------- */ - -#if LJ_TARGET_X86 && __ELF__ && __PIC__ -/* Wrapper functions to deal with the ELF/x86 PIC disaster. */ -LJ_FUNCA double lj_wrap_log(double x) { return log(x); } -LJ_FUNCA double lj_wrap_log10(double x) { return log10(x); } -LJ_FUNCA double lj_wrap_exp(double x) { return exp(x); } -LJ_FUNCA double lj_wrap_sin(double x) { return sin(x); } -LJ_FUNCA double lj_wrap_cos(double x) { return cos(x); } -LJ_FUNCA double lj_wrap_tan(double x) { return tan(x); } -LJ_FUNCA double lj_wrap_asin(double x) { return asin(x); } -LJ_FUNCA double lj_wrap_acos(double x) { return acos(x); } -LJ_FUNCA double lj_wrap_atan(double x) { return atan(x); } -LJ_FUNCA double lj_wrap_sinh(double x) { return sinh(x); } -LJ_FUNCA double lj_wrap_cosh(double x) { return cosh(x); } -LJ_FUNCA double lj_wrap_tanh(double x) { return tanh(x); } -LJ_FUNCA double lj_wrap_atan2(double x, double y) { return atan2(x, y); } -LJ_FUNCA double lj_wrap_pow(double x, double y) { return pow(x, y); } -LJ_FUNCA double lj_wrap_fmod(double x, double y) { return fmod(x, y); } -#endif - -/* -- Helper functions for generated machine code ------------------------- */ - -double lj_vm_foldarith(double x, double y, int op) -{ - switch (op) { - case IR_ADD - IR_ADD: return x+y; break; - case IR_SUB - IR_ADD: return x-y; break; - case IR_MUL - IR_ADD: return x*y; break; - case IR_DIV - IR_ADD: return x/y; break; - case IR_MOD - IR_ADD: return x-lj_vm_floor(x/y)*y; break; - case IR_POW - IR_ADD: return pow(x, y); break; - case IR_NEG - IR_ADD: return -x; break; - case IR_ABS - IR_ADD: return fabs(x); break; -#if LJ_HASJIT - case IR_ATAN2 - IR_ADD: return atan2(x, y); break; - case IR_LDEXP - IR_ADD: return ldexp(x, (int)y); break; - case IR_MIN - IR_ADD: return x > y ? y : x; break; - case IR_MAX - IR_ADD: return x < y ? y : x; break; -#endif - default: return x; - } -} - -#if (LJ_HASJIT && !(LJ_TARGET_ARM || LJ_TARGET_ARM64 || LJ_TARGET_PPC)) || LJ_TARGET_MIPS -int32_t LJ_FASTCALL lj_vm_modi(int32_t a, int32_t b) -{ - uint32_t y, ua, ub; - lua_assert(b != 0); /* This must be checked before using this function. */ - ua = a < 0 ? (uint32_t)-a : (uint32_t)a; - ub = b < 0 ? (uint32_t)-b : (uint32_t)b; - y = ua % ub; - if (y != 0 && (a^b) < 0) y = y - ub; - if (((int32_t)y^b) < 0) y = (uint32_t)-(int32_t)y; - return (int32_t)y; -} -#endif - -#if LJ_HASJIT - -#ifdef LUAJIT_NO_LOG2 -double lj_vm_log2(double a) -{ - return log(a) * 1.4426950408889634074; -} -#endif - -#ifdef LUAJIT_NO_EXP2 -double lj_vm_exp2(double a) -{ - return exp(a * 0.6931471805599453); -} -#endif - -#if !LJ_TARGET_X86ORX64 -/* Unsigned x^k. */ -static double lj_vm_powui(double x, uint32_t k) -{ - double y; - lua_assert(k != 0); - for (; (k & 1) == 0; k >>= 1) x *= x; - y = x; - if ((k >>= 1) != 0) { - for (;;) { - x *= x; - if (k == 1) break; - if (k & 1) y *= x; - k >>= 1; - } - y *= x; - } - return y; -} - -/* Signed x^k. */ -double lj_vm_powi(double x, int32_t k) -{ - if (k > 1) - return lj_vm_powui(x, (uint32_t)k); - else if (k == 1) - return x; - else if (k == 0) - return 1.0; - else - return 1.0 / lj_vm_powui(x, (uint32_t)-k); -} -#endif - -/* Computes fpm(x) for extended math functions. */ -double lj_vm_foldfpm(double x, int fpm) -{ - switch (fpm) { - case IRFPM_FLOOR: return lj_vm_floor(x); - case IRFPM_CEIL: return lj_vm_ceil(x); - case IRFPM_TRUNC: return lj_vm_trunc(x); - case IRFPM_SQRT: return sqrt(x); - case IRFPM_EXP: return exp(x); - case IRFPM_EXP2: return lj_vm_exp2(x); - case IRFPM_LOG: return log(x); - case IRFPM_LOG2: return lj_vm_log2(x); - case IRFPM_LOG10: return log10(x); - case IRFPM_SIN: return sin(x); - case IRFPM_COS: return cos(x); - case IRFPM_TAN: return tan(x); - default: lua_assert(0); - } - return 0; -} - -#if LJ_HASFFI -int lj_vm_errno(void) -{ - return errno; -} -#endif - -#endif diff --git a/lib/LuaJIT/src/ljamalg.c b/lib/LuaJIT/src/ljamalg.c deleted file mode 100644 index f1f2862..0000000 --- a/lib/LuaJIT/src/ljamalg.c +++ /dev/null @@ -1,97 +0,0 @@ -/* -** LuaJIT core and libraries amalgamation. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -/* -+--------------------------------------------------------------------------+ -| WARNING: Compiling the amalgamation needs a lot of virtual memory | -| (around 300 MB with GCC 4.x)! If you don't have enough physical memory | -| your machine will start swapping to disk and the compile will not finish | -| within a reasonable amount of time. | -| So either compile on a bigger machine or use the non-amalgamated build. | -+--------------------------------------------------------------------------+ -*/ - -#define ljamalg_c -#define LUA_CORE - -/* To get the mremap prototype. Must be defined before any system includes. */ -#if defined(__linux__) && !defined(_GNU_SOURCE) -#define _GNU_SOURCE -#endif - -#ifndef WINVER -#define WINVER 0x0501 -#endif - -#include "lua.h" -#include "lauxlib.h" - -#include "lj_gc.c" -#include "lj_err.c" -#include "lj_char.c" -#include "lj_bc.c" -#include "lj_obj.c" -#include "lj_buf.c" -#include "lj_str.c" -#include "lj_tab.c" -#include "lj_func.c" -#include "lj_udata.c" -#include "lj_meta.c" -#include "lj_debug.c" -#include "lj_state.c" -#include "lj_dispatch.c" -#include "lj_vmevent.c" -#include "lj_vmmath.c" -#include "lj_strscan.c" -#include "lj_strfmt.c" -#include "lj_strfmt_num.c" -#include "lj_api.c" -#include "lj_profile.c" -#include "lj_lex.c" -#include "lj_parse.c" -#include "lj_bcread.c" -#include "lj_bcwrite.c" -#include "lj_load.c" -#include "lj_ctype.c" -#include "lj_cdata.c" -#include "lj_cconv.c" -#include "lj_ccall.c" -#include "lj_ccallback.c" -#include "lj_carith.c" -#include "lj_clib.c" -#include "lj_cparse.c" -#include "lj_lib.c" -#include "lj_ir.c" -#include "lj_opt_mem.c" -#include "lj_opt_fold.c" -#include "lj_opt_narrow.c" -#include "lj_opt_dce.c" -#include "lj_opt_loop.c" -#include "lj_opt_split.c" -#include "lj_opt_sink.c" -#include "lj_mcode.c" -#include "lj_snap.c" -#include "lj_record.c" -#include "lj_crecord.c" -#include "lj_ffrecord.c" -#include "lj_asm.c" -#include "lj_trace.c" -#include "lj_gdbjit.c" -#include "lj_alloc.c" - -#include "lib_aux.c" -#include "lib_base.c" -#include "lib_math.c" -#include "lib_string.c" -#include "lib_table.c" -#include "lib_io.c" -#include "lib_os.c" -#include "lib_package.c" -#include "lib_debug.c" -#include "lib_bit.c" -#include "lib_jit.c" -#include "lib_ffi.c" -#include "lib_init.c" - diff --git a/lib/LuaJIT/src/lua.h b/lib/LuaJIT/src/lua.h deleted file mode 100644 index 850bd79..0000000 --- a/lib/LuaJIT/src/lua.h +++ /dev/null @@ -1,402 +0,0 @@ -/* -** $Id: lua.h,v 1.218.1.5 2008/08/06 13:30:12 roberto Exp $ -** Lua - An Extensible Extension Language -** Lua.org, PUC-Rio, Brazil (http://www.lua.org) -** See Copyright Notice at the end of this file -*/ - - -#ifndef lua_h -#define lua_h - -#include -#include - - -#include "luaconf.h" - - -#define LUA_VERSION "Lua 5.1" -#define LUA_RELEASE "Lua 5.1.4" -#define LUA_VERSION_NUM 501 -#define LUA_COPYRIGHT "Copyright (C) 1994-2008 Lua.org, PUC-Rio" -#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" - - -/* mark for precompiled code (`Lua') */ -#define LUA_SIGNATURE "\033Lua" - -/* option for multiple returns in `lua_pcall' and `lua_call' */ -#define LUA_MULTRET (-1) - - -/* -** pseudo-indices -*/ -#define LUA_REGISTRYINDEX (-10000) -#define LUA_ENVIRONINDEX (-10001) -#define LUA_GLOBALSINDEX (-10002) -#define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i)) - - -/* thread status */ -#define LUA_OK 0 -#define LUA_YIELD 1 -#define LUA_ERRRUN 2 -#define LUA_ERRSYNTAX 3 -#define LUA_ERRMEM 4 -#define LUA_ERRERR 5 - - -typedef struct lua_State lua_State; - -typedef int (*lua_CFunction) (lua_State *L); - - -/* -** functions that read/write blocks when loading/dumping Lua chunks -*/ -typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); - -typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud); - - -/* -** prototype for memory-allocation functions -*/ -typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); - - -/* -** basic types -*/ -#define LUA_TNONE (-1) - -#define LUA_TNIL 0 -#define LUA_TBOOLEAN 1 -#define LUA_TLIGHTUSERDATA 2 -#define LUA_TNUMBER 3 -#define LUA_TSTRING 4 -#define LUA_TTABLE 5 -#define LUA_TFUNCTION 6 -#define LUA_TUSERDATA 7 -#define LUA_TTHREAD 8 - - - -/* minimum Lua stack available to a C function */ -#define LUA_MINSTACK 20 - - -/* -** generic extra include file -*/ -#if defined(LUA_USER_H) -#include LUA_USER_H -#endif - - -/* type of numbers in Lua */ -typedef LUA_NUMBER lua_Number; - - -/* type for integer functions */ -typedef LUA_INTEGER lua_Integer; - - - -/* -** state manipulation -*/ -LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); -LUA_API void (lua_close) (lua_State *L); -LUA_API lua_State *(lua_newthread) (lua_State *L); - -LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); - - -/* -** basic stack manipulation -*/ -LUA_API int (lua_gettop) (lua_State *L); -LUA_API void (lua_settop) (lua_State *L, int idx); -LUA_API void (lua_pushvalue) (lua_State *L, int idx); -LUA_API void (lua_remove) (lua_State *L, int idx); -LUA_API void (lua_insert) (lua_State *L, int idx); -LUA_API void (lua_replace) (lua_State *L, int idx); -LUA_API int (lua_checkstack) (lua_State *L, int sz); - -LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); - - -/* -** access functions (stack -> C) -*/ - -LUA_API int (lua_isnumber) (lua_State *L, int idx); -LUA_API int (lua_isstring) (lua_State *L, int idx); -LUA_API int (lua_iscfunction) (lua_State *L, int idx); -LUA_API int (lua_isuserdata) (lua_State *L, int idx); -LUA_API int (lua_type) (lua_State *L, int idx); -LUA_API const char *(lua_typename) (lua_State *L, int tp); - -LUA_API int (lua_equal) (lua_State *L, int idx1, int idx2); -LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); -LUA_API int (lua_lessthan) (lua_State *L, int idx1, int idx2); - -LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx); -LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx); -LUA_API int (lua_toboolean) (lua_State *L, int idx); -LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); -LUA_API size_t (lua_objlen) (lua_State *L, int idx); -LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); -LUA_API void *(lua_touserdata) (lua_State *L, int idx); -LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); -LUA_API const void *(lua_topointer) (lua_State *L, int idx); - - -/* -** push functions (C -> stack) -*/ -LUA_API void (lua_pushnil) (lua_State *L); -LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); -LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); -LUA_API void (lua_pushlstring) (lua_State *L, const char *s, size_t l); -LUA_API void (lua_pushstring) (lua_State *L, const char *s); -LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, - va_list argp); -LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); -LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); -LUA_API void (lua_pushboolean) (lua_State *L, int b); -LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p); -LUA_API int (lua_pushthread) (lua_State *L); - - -/* -** get functions (Lua -> stack) -*/ -LUA_API void (lua_gettable) (lua_State *L, int idx); -LUA_API void (lua_getfield) (lua_State *L, int idx, const char *k); -LUA_API void (lua_rawget) (lua_State *L, int idx); -LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n); -LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); -LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); -LUA_API int (lua_getmetatable) (lua_State *L, int objindex); -LUA_API void (lua_getfenv) (lua_State *L, int idx); - - -/* -** set functions (stack -> Lua) -*/ -LUA_API void (lua_settable) (lua_State *L, int idx); -LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); -LUA_API void (lua_rawset) (lua_State *L, int idx); -LUA_API void (lua_rawseti) (lua_State *L, int idx, int n); -LUA_API int (lua_setmetatable) (lua_State *L, int objindex); -LUA_API int (lua_setfenv) (lua_State *L, int idx); - - -/* -** `load' and `call' functions (load and run Lua code) -*/ -LUA_API void (lua_call) (lua_State *L, int nargs, int nresults); -LUA_API int (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc); -LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); -LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, - const char *chunkname); - -LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data); - - -/* -** coroutine functions -*/ -LUA_API int (lua_yield) (lua_State *L, int nresults); -LUA_API int (lua_resume) (lua_State *L, int narg); -LUA_API int (lua_status) (lua_State *L); - -/* -** garbage-collection function and options -*/ - -#define LUA_GCSTOP 0 -#define LUA_GCRESTART 1 -#define LUA_GCCOLLECT 2 -#define LUA_GCCOUNT 3 -#define LUA_GCCOUNTB 4 -#define LUA_GCSTEP 5 -#define LUA_GCSETPAUSE 6 -#define LUA_GCSETSTEPMUL 7 -#define LUA_GCISRUNNING 9 - -LUA_API int (lua_gc) (lua_State *L, int what, int data); - - -/* -** miscellaneous functions -*/ - -LUA_API int (lua_error) (lua_State *L); - -LUA_API int (lua_next) (lua_State *L, int idx); - -LUA_API void (lua_concat) (lua_State *L, int n); - -LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); -LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud); - - - -/* -** =============================================================== -** some useful macros -** =============================================================== -*/ - -#define lua_pop(L,n) lua_settop(L, -(n)-1) - -#define lua_newtable(L) lua_createtable(L, 0, 0) - -#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) - -#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) - -#define lua_strlen(L,i) lua_objlen(L, (i)) - -#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) -#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) -#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) -#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL) -#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN) -#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD) -#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE) -#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0) - -#define lua_pushliteral(L, s) \ - lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1) - -#define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, (s)) -#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s)) - -#define lua_tostring(L,i) lua_tolstring(L, (i), NULL) - - - -/* -** compatibility macros and functions -*/ - -#define lua_open() luaL_newstate() - -#define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX) - -#define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0) - -#define lua_Chunkreader lua_Reader -#define lua_Chunkwriter lua_Writer - - -/* hack */ -LUA_API void lua_setlevel (lua_State *from, lua_State *to); - - -/* -** {====================================================================== -** Debug API -** ======================================================================= -*/ - - -/* -** Event codes -*/ -#define LUA_HOOKCALL 0 -#define LUA_HOOKRET 1 -#define LUA_HOOKLINE 2 -#define LUA_HOOKCOUNT 3 -#define LUA_HOOKTAILRET 4 - - -/* -** Event masks -*/ -#define LUA_MASKCALL (1 << LUA_HOOKCALL) -#define LUA_MASKRET (1 << LUA_HOOKRET) -#define LUA_MASKLINE (1 << LUA_HOOKLINE) -#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) - -typedef struct lua_Debug lua_Debug; /* activation record */ - - -/* Functions to be called by the debuger in specific events */ -typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); - - -LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar); -LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar); -LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n); -LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n); -LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n); -LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n); -LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count); -LUA_API lua_Hook lua_gethook (lua_State *L); -LUA_API int lua_gethookmask (lua_State *L); -LUA_API int lua_gethookcount (lua_State *L); - -/* From Lua 5.2. */ -LUA_API void *lua_upvalueid (lua_State *L, int idx, int n); -LUA_API void lua_upvaluejoin (lua_State *L, int idx1, int n1, int idx2, int n2); -LUA_API int lua_loadx (lua_State *L, lua_Reader reader, void *dt, - const char *chunkname, const char *mode); -LUA_API const lua_Number *lua_version (lua_State *L); -LUA_API void lua_copy (lua_State *L, int fromidx, int toidx); -LUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *isnum); -LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *isnum); - -/* From Lua 5.3. */ -LUA_API int lua_isyieldable (lua_State *L); - - -struct lua_Debug { - int event; - const char *name; /* (n) */ - const char *namewhat; /* (n) `global', `local', `field', `method' */ - const char *what; /* (S) `Lua', `C', `main', `tail' */ - const char *source; /* (S) */ - int currentline; /* (l) */ - int nups; /* (u) number of upvalues */ - int linedefined; /* (S) */ - int lastlinedefined; /* (S) */ - char short_src[LUA_IDSIZE]; /* (S) */ - /* private part */ - int i_ci; /* active function */ -}; - -/* }====================================================================== */ - - -/****************************************************************************** -* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be -* included in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -******************************************************************************/ - - -#endif diff --git a/lib/LuaJIT/src/lua.hpp b/lib/LuaJIT/src/lua.hpp deleted file mode 100644 index 07e9002..0000000 --- a/lib/LuaJIT/src/lua.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// C++ wrapper for LuaJIT header files. - -extern "C" { -#include "lua.h" -#include "lauxlib.h" -#include "lualib.h" -#include "luajit.h" -} - diff --git a/lib/LuaJIT/src/luaconf.h b/lib/LuaJIT/src/luaconf.h deleted file mode 100644 index c2d29d9..0000000 --- a/lib/LuaJIT/src/luaconf.h +++ /dev/null @@ -1,152 +0,0 @@ -/* -** Configuration header. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef luaconf_h -#define luaconf_h - -#ifndef WINVER -#define WINVER 0x0501 -#endif -#include -#include - -/* Default path for loading Lua and C modules with require(). */ -#if defined(_WIN32) -/* -** In Windows, any exclamation mark ('!') in the path is replaced by the -** path of the directory of the executable file of the current process. -*/ -#define LUA_LDIR "!\\lua\\" -#define LUA_CDIR "!\\" -#define LUA_PATH_DEFAULT \ - ".\\?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" -#define LUA_CPATH_DEFAULT \ - ".\\?.dll;" LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll" -#else -/* -** Note to distribution maintainers: do NOT patch the following lines! -** Please read ../doc/install.html#distro and pass PREFIX=/usr instead. -*/ -#ifndef LUA_MULTILIB -#define LUA_MULTILIB "lib" -#endif -#ifndef LUA_LMULTILIB -#define LUA_LMULTILIB "lib" -#endif -#define LUA_LROOT "/usr/local" -#define LUA_LUADIR "/lua/5.1/" -#define LUA_LJDIR "/luajit-2.1.0-beta3/" - -#ifdef LUA_ROOT -#define LUA_JROOT LUA_ROOT -#define LUA_RLDIR LUA_ROOT "/share" LUA_LUADIR -#define LUA_RCDIR LUA_ROOT "/" LUA_MULTILIB LUA_LUADIR -#define LUA_RLPATH ";" LUA_RLDIR "?.lua;" LUA_RLDIR "?/init.lua" -#define LUA_RCPATH ";" LUA_RCDIR "?.so" -#else -#define LUA_JROOT LUA_LROOT -#define LUA_RLPATH -#define LUA_RCPATH -#endif - -#define LUA_JPATH ";" LUA_JROOT "/share" LUA_LJDIR "?.lua" -#define LUA_LLDIR LUA_LROOT "/share" LUA_LUADIR -#define LUA_LCDIR LUA_LROOT "/" LUA_LMULTILIB LUA_LUADIR -#define LUA_LLPATH ";" LUA_LLDIR "?.lua;" LUA_LLDIR "?/init.lua" -#define LUA_LCPATH1 ";" LUA_LCDIR "?.so" -#define LUA_LCPATH2 ";" LUA_LCDIR "loadall.so" - -#define LUA_PATH_DEFAULT "./?.lua" LUA_JPATH LUA_LLPATH LUA_RLPATH -#define LUA_CPATH_DEFAULT "./?.so" LUA_LCPATH1 LUA_RCPATH LUA_LCPATH2 -#endif - -/* Environment variable names for path overrides and initialization code. */ -#define LUA_PATH "LUA_PATH" -#define LUA_CPATH "LUA_CPATH" -#define LUA_INIT "LUA_INIT" - -/* Special file system characters. */ -#if defined(_WIN32) -#define LUA_DIRSEP "\\" -#else -#define LUA_DIRSEP "/" -#endif -#define LUA_PATHSEP ";" -#define LUA_PATH_MARK "?" -#define LUA_EXECDIR "!" -#define LUA_IGMARK "-" -#define LUA_PATH_CONFIG \ - LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" \ - LUA_EXECDIR "\n" LUA_IGMARK "\n" - -/* Quoting in error messages. */ -#define LUA_QL(x) "'" x "'" -#define LUA_QS LUA_QL("%s") - -/* Various tunables. */ -#define LUAI_MAXSTACK 65500 /* Max. # of stack slots for a thread (<64K). */ -#define LUAI_MAXCSTACK 8000 /* Max. # of stack slots for a C func (<10K). */ -#define LUAI_GCPAUSE 200 /* Pause GC until memory is at 200%. */ -#define LUAI_GCMUL 200 /* Run GC at 200% of allocation speed. */ -#define LUA_MAXCAPTURES 32 /* Max. pattern captures. */ - -/* Configuration for the frontend (the luajit executable). */ -#if defined(luajit_c) -#define LUA_PROGNAME "luajit" /* Fallback frontend name. */ -#define LUA_PROMPT "> " /* Interactive prompt. */ -#define LUA_PROMPT2 ">> " /* Continuation prompt. */ -#define LUA_MAXINPUT 512 /* Max. input line length. */ -#endif - -/* Note: changing the following defines breaks the Lua 5.1 ABI. */ -#define LUA_INTEGER ptrdiff_t -#define LUA_IDSIZE 60 /* Size of lua_Debug.short_src. */ -/* -** Size of lauxlib and io.* on-stack buffers. Weird workaround to avoid using -** unreasonable amounts of stack space, but still retain ABI compatibility. -** Blame Lua for depending on BUFSIZ in the ABI, blame **** for wrecking it. -*/ -#define LUAL_BUFFERSIZE (BUFSIZ > 16384 ? 8192 : BUFSIZ) - -/* The following defines are here only for compatibility with luaconf.h -** from the standard Lua distribution. They must not be changed for LuaJIT. -*/ -#define LUA_NUMBER_DOUBLE -#define LUA_NUMBER double -#define LUAI_UACNUMBER double -#define LUA_NUMBER_SCAN "%lf" -#define LUA_NUMBER_FMT "%.14g" -#define lua_number2str(s, n) sprintf((s), LUA_NUMBER_FMT, (n)) -#define LUAI_MAXNUMBER2STR 32 -#define LUA_INTFRMLEN "l" -#define LUA_INTFRM_T long - -/* Linkage of public API functions. */ -#if defined(LUA_BUILD_AS_DLL) -#if defined(LUA_CORE) || defined(LUA_LIB) -#define LUA_API __declspec(dllexport) -#else -#define LUA_API __declspec(dllimport) -#endif -#else -#define LUA_API extern -#endif - -#define LUALIB_API LUA_API - -/* Support for internal assertions. */ -#if defined(LUA_USE_ASSERT) || defined(LUA_USE_APICHECK) -#include -#endif -#ifdef LUA_USE_ASSERT -#define lua_assert(x) assert(x) -#endif -#ifdef LUA_USE_APICHECK -#define luai_apicheck(L, o) { (void)L; assert(o); } -#else -#define luai_apicheck(L, o) { (void)L; } -#endif - -#endif diff --git a/lib/LuaJIT/src/luajit.c b/lib/LuaJIT/src/luajit.c deleted file mode 100644 index 86134ef..0000000 --- a/lib/LuaJIT/src/luajit.c +++ /dev/null @@ -1,587 +0,0 @@ -/* -** LuaJIT frontend. Runs commands, scripts, read-eval-print (REPL) etc. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Major portions taken verbatim or adapted from the Lua interpreter. -** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h -*/ - -#include -#include -#include - -#define luajit_c - -#include "lua.h" -#include "lauxlib.h" -#include "lualib.h" -#include "luajit.h" - -#include "lj_arch.h" - -#if LJ_TARGET_POSIX -#include -#define lua_stdin_is_tty() isatty(0) -#elif LJ_TARGET_WINDOWS -#include -#ifdef __BORLANDC__ -#define lua_stdin_is_tty() isatty(_fileno(stdin)) -#else -#define lua_stdin_is_tty() _isatty(_fileno(stdin)) -#endif -#else -#define lua_stdin_is_tty() 1 -#endif - -#if !LJ_TARGET_CONSOLE -#include -#endif - -static lua_State *globalL = NULL; -static const char *progname = LUA_PROGNAME; - -#if !LJ_TARGET_CONSOLE -static void lstop(lua_State *L, lua_Debug *ar) -{ - (void)ar; /* unused arg. */ - lua_sethook(L, NULL, 0, 0); - /* Avoid luaL_error -- a C hook doesn't add an extra frame. */ - luaL_where(L, 0); - lua_pushfstring(L, "%sinterrupted!", lua_tostring(L, -1)); - lua_error(L); -} - -static void laction(int i) -{ - signal(i, SIG_DFL); /* if another SIGINT happens before lstop, - terminate process (default action) */ - lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); -} -#endif - -static void print_usage(void) -{ - fputs("usage: ", stderr); - fputs(progname, stderr); - fputs(" [options]... [script [args]...].\n" - "Available options are:\n" - " -e chunk Execute string " LUA_QL("chunk") ".\n" - " -l name Require library " LUA_QL("name") ".\n" - " -b ... Save or list bytecode.\n" - " -j cmd Perform LuaJIT control command.\n" - " -O[opt] Control LuaJIT optimizations.\n" - " -i Enter interactive mode after executing " LUA_QL("script") ".\n" - " -v Show version information.\n" - " -E Ignore environment variables.\n" - " -- Stop handling options.\n" - " - Execute stdin and stop handling options.\n", stderr); - fflush(stderr); -} - -static void l_message(const char *pname, const char *msg) -{ - if (pname) { fputs(pname, stderr); fputc(':', stderr); fputc(' ', stderr); } - fputs(msg, stderr); fputc('\n', stderr); - fflush(stderr); -} - -static int report(lua_State *L, int status) -{ - if (status && !lua_isnil(L, -1)) { - const char *msg = lua_tostring(L, -1); - if (msg == NULL) msg = "(error object is not a string)"; - l_message(progname, msg); - lua_pop(L, 1); - } - return status; -} - -static int traceback(lua_State *L) -{ - if (!lua_isstring(L, 1)) { /* Non-string error object? Try metamethod. */ - if (lua_isnoneornil(L, 1) || - !luaL_callmeta(L, 1, "__tostring") || - !lua_isstring(L, -1)) - return 1; /* Return non-string error object. */ - lua_remove(L, 1); /* Replace object by result of __tostring metamethod. */ - } - luaL_traceback(L, L, lua_tostring(L, 1), 1); - return 1; -} - -static int docall(lua_State *L, int narg, int clear) -{ - int status; - int base = lua_gettop(L) - narg; /* function index */ - lua_pushcfunction(L, traceback); /* push traceback function */ - lua_insert(L, base); /* put it under chunk and args */ -#if !LJ_TARGET_CONSOLE - signal(SIGINT, laction); -#endif - status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base); -#if !LJ_TARGET_CONSOLE - signal(SIGINT, SIG_DFL); -#endif - lua_remove(L, base); /* remove traceback function */ - /* force a complete garbage collection in case of errors */ - if (status != LUA_OK) lua_gc(L, LUA_GCCOLLECT, 0); - return status; -} - -static void print_version(void) -{ - fputs(LUAJIT_VERSION " -- " LUAJIT_COPYRIGHT ". " LUAJIT_URL "\n", stdout); -} - -static void print_jit_status(lua_State *L) -{ - int n; - const char *s; - lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); - lua_getfield(L, -1, "jit"); /* Get jit.* module table. */ - lua_remove(L, -2); - lua_getfield(L, -1, "status"); - lua_remove(L, -2); - n = lua_gettop(L); - lua_call(L, 0, LUA_MULTRET); - fputs(lua_toboolean(L, n) ? "JIT: ON" : "JIT: OFF", stdout); - for (n++; (s = lua_tostring(L, n)); n++) { - putc(' ', stdout); - fputs(s, stdout); - } - putc('\n', stdout); - lua_settop(L, 0); /* clear stack */ -} - -static void createargtable(lua_State *L, char **argv, int argc, int argf) -{ - int i; - lua_createtable(L, argc - argf, argf); - for (i = 0; i < argc; i++) { - lua_pushstring(L, argv[i]); - lua_rawseti(L, -2, i - argf); - } - lua_setglobal(L, "arg"); -} - -static int dofile(lua_State *L, const char *name) -{ - int status = luaL_loadfile(L, name) || docall(L, 0, 1); - return report(L, status); -} - -static int dostring(lua_State *L, const char *s, const char *name) -{ - int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1); - return report(L, status); -} - -static int dolibrary(lua_State *L, const char *name) -{ - lua_getglobal(L, "require"); - lua_pushstring(L, name); - return report(L, docall(L, 1, 1)); -} - -static void write_prompt(lua_State *L, int firstline) -{ - const char *p; - lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2"); - p = lua_tostring(L, -1); - if (p == NULL) p = firstline ? LUA_PROMPT : LUA_PROMPT2; - fputs(p, stdout); - fflush(stdout); - lua_pop(L, 1); /* remove global */ -} - -static int incomplete(lua_State *L, int status) -{ - if (status == LUA_ERRSYNTAX) { - size_t lmsg; - const char *msg = lua_tolstring(L, -1, &lmsg); - const char *tp = msg + lmsg - (sizeof(LUA_QL("")) - 1); - if (strstr(msg, LUA_QL("")) == tp) { - lua_pop(L, 1); - return 1; - } - } - return 0; /* else... */ -} - -static int pushline(lua_State *L, int firstline) -{ - char buf[LUA_MAXINPUT]; - write_prompt(L, firstline); - if (fgets(buf, LUA_MAXINPUT, stdin)) { - size_t len = strlen(buf); - if (len > 0 && buf[len-1] == '\n') - buf[len-1] = '\0'; - if (firstline && buf[0] == '=') - lua_pushfstring(L, "return %s", buf+1); - else - lua_pushstring(L, buf); - return 1; - } - return 0; -} - -static int loadline(lua_State *L) -{ - int status; - lua_settop(L, 0); - if (!pushline(L, 1)) - return -1; /* no input */ - for (;;) { /* repeat until gets a complete line */ - status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); - if (!incomplete(L, status)) break; /* cannot try to add lines? */ - if (!pushline(L, 0)) /* no more input? */ - return -1; - lua_pushliteral(L, "\n"); /* add a new line... */ - lua_insert(L, -2); /* ...between the two lines */ - lua_concat(L, 3); /* join them */ - } - lua_remove(L, 1); /* remove line */ - return status; -} - -static void dotty(lua_State *L) -{ - int status; - const char *oldprogname = progname; - progname = NULL; - while ((status = loadline(L)) != -1) { - if (status == LUA_OK) status = docall(L, 0, 0); - report(L, status); - if (status == LUA_OK && lua_gettop(L) > 0) { /* any result to print? */ - lua_getglobal(L, "print"); - lua_insert(L, 1); - if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) - l_message(progname, - lua_pushfstring(L, "error calling " LUA_QL("print") " (%s)", - lua_tostring(L, -1))); - } - } - lua_settop(L, 0); /* clear stack */ - fputs("\n", stdout); - fflush(stdout); - progname = oldprogname; -} - -static int handle_script(lua_State *L, char **argx) -{ - int status; - const char *fname = argx[0]; - if (strcmp(fname, "-") == 0 && strcmp(argx[-1], "--") != 0) - fname = NULL; /* stdin */ - status = luaL_loadfile(L, fname); - if (status == LUA_OK) { - /* Fetch args from arg table. LUA_INIT or -e might have changed them. */ - int narg = 0; - lua_getglobal(L, "arg"); - if (lua_istable(L, -1)) { - do { - narg++; - lua_rawgeti(L, -narg, narg); - } while (!lua_isnil(L, -1)); - lua_pop(L, 1); - lua_remove(L, -narg); - narg--; - } else { - lua_pop(L, 1); - } - status = docall(L, narg, 0); - } - return report(L, status); -} - -/* Load add-on module. */ -static int loadjitmodule(lua_State *L) -{ - lua_getglobal(L, "require"); - lua_pushliteral(L, "jit."); - lua_pushvalue(L, -3); - lua_concat(L, 2); - if (lua_pcall(L, 1, 1, 0)) { - const char *msg = lua_tostring(L, -1); - if (msg && !strncmp(msg, "module ", 7)) - goto nomodule; - return report(L, 1); - } - lua_getfield(L, -1, "start"); - if (lua_isnil(L, -1)) { - nomodule: - l_message(progname, - "unknown luaJIT command or jit.* modules not installed"); - return 1; - } - lua_remove(L, -2); /* Drop module table. */ - return 0; -} - -/* Run command with options. */ -static int runcmdopt(lua_State *L, const char *opt) -{ - int narg = 0; - if (opt && *opt) { - for (;;) { /* Split arguments. */ - const char *p = strchr(opt, ','); - narg++; - if (!p) break; - if (p == opt) - lua_pushnil(L); - else - lua_pushlstring(L, opt, (size_t)(p - opt)); - opt = p + 1; - } - if (*opt) - lua_pushstring(L, opt); - else - lua_pushnil(L); - } - return report(L, lua_pcall(L, narg, 0, 0)); -} - -/* JIT engine control command: try jit library first or load add-on module. */ -static int dojitcmd(lua_State *L, const char *cmd) -{ - const char *opt = strchr(cmd, '='); - lua_pushlstring(L, cmd, opt ? (size_t)(opt - cmd) : strlen(cmd)); - lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); - lua_getfield(L, -1, "jit"); /* Get jit.* module table. */ - lua_remove(L, -2); - lua_pushvalue(L, -2); - lua_gettable(L, -2); /* Lookup library function. */ - if (!lua_isfunction(L, -1)) { - lua_pop(L, 2); /* Drop non-function and jit.* table, keep module name. */ - if (loadjitmodule(L)) - return 1; - } else { - lua_remove(L, -2); /* Drop jit.* table. */ - } - lua_remove(L, -2); /* Drop module name. */ - return runcmdopt(L, opt ? opt+1 : opt); -} - -/* Optimization flags. */ -static int dojitopt(lua_State *L, const char *opt) -{ - lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); - lua_getfield(L, -1, "jit.opt"); /* Get jit.opt.* module table. */ - lua_remove(L, -2); - lua_getfield(L, -1, "start"); - lua_remove(L, -2); - return runcmdopt(L, opt); -} - -/* Save or list bytecode. */ -static int dobytecode(lua_State *L, char **argv) -{ - int narg = 0; - lua_pushliteral(L, "bcsave"); - if (loadjitmodule(L)) - return 1; - if (argv[0][2]) { - narg++; - argv[0][1] = '-'; - lua_pushstring(L, argv[0]+1); - } - for (argv++; *argv != NULL; narg++, argv++) - lua_pushstring(L, *argv); - report(L, lua_pcall(L, narg, 0, 0)); - return -1; -} - -/* check that argument has no extra characters at the end */ -#define notail(x) {if ((x)[2] != '\0') return -1;} - -#define FLAGS_INTERACTIVE 1 -#define FLAGS_VERSION 2 -#define FLAGS_EXEC 4 -#define FLAGS_OPTION 8 -#define FLAGS_NOENV 16 - -static int collectargs(char **argv, int *flags) -{ - int i; - for (i = 1; argv[i] != NULL; i++) { - if (argv[i][0] != '-') /* Not an option? */ - return i; - switch (argv[i][1]) { /* Check option. */ - case '-': - notail(argv[i]); - return i+1; - case '\0': - return i; - case 'i': - notail(argv[i]); - *flags |= FLAGS_INTERACTIVE; - /* fallthrough */ - case 'v': - notail(argv[i]); - *flags |= FLAGS_VERSION; - break; - case 'e': - *flags |= FLAGS_EXEC; - /* fallthrough */ - case 'j': /* LuaJIT extension */ - case 'l': - *flags |= FLAGS_OPTION; - if (argv[i][2] == '\0') { - i++; - if (argv[i] == NULL) return -1; - } - break; - case 'O': break; /* LuaJIT extension */ - case 'b': /* LuaJIT extension */ - if (*flags) return -1; - *flags |= FLAGS_EXEC; - return i+1; - case 'E': - *flags |= FLAGS_NOENV; - break; - default: return -1; /* invalid option */ - } - } - return i; -} - -static int runargs(lua_State *L, char **argv, int argn) -{ - int i; - for (i = 1; i < argn; i++) { - if (argv[i] == NULL) continue; - lua_assert(argv[i][0] == '-'); - switch (argv[i][1]) { - case 'e': { - const char *chunk = argv[i] + 2; - if (*chunk == '\0') chunk = argv[++i]; - lua_assert(chunk != NULL); - if (dostring(L, chunk, "=(command line)") != 0) - return 1; - break; - } - case 'l': { - const char *filename = argv[i] + 2; - if (*filename == '\0') filename = argv[++i]; - lua_assert(filename != NULL); - if (dolibrary(L, filename)) - return 1; - break; - } - case 'j': { /* LuaJIT extension. */ - const char *cmd = argv[i] + 2; - if (*cmd == '\0') cmd = argv[++i]; - lua_assert(cmd != NULL); - if (dojitcmd(L, cmd)) - return 1; - break; - } - case 'O': /* LuaJIT extension. */ - if (dojitopt(L, argv[i] + 2)) - return 1; - break; - case 'b': /* LuaJIT extension. */ - return dobytecode(L, argv+i); - default: break; - } - } - return LUA_OK; -} - -static int handle_luainit(lua_State *L) -{ -#if LJ_TARGET_CONSOLE - const char *init = NULL; -#else - const char *init = getenv(LUA_INIT); -#endif - if (init == NULL) - return LUA_OK; - else if (init[0] == '@') - return dofile(L, init+1); - else - return dostring(L, init, "=" LUA_INIT); -} - -static struct Smain { - char **argv; - int argc; - int status; -} smain; - -static int pmain(lua_State *L) -{ - struct Smain *s = &smain; - char **argv = s->argv; - int argn; - int flags = 0; - globalL = L; - if (argv[0] && argv[0][0]) progname = argv[0]; - - LUAJIT_VERSION_SYM(); /* Linker-enforced version check. */ - - argn = collectargs(argv, &flags); - if (argn < 0) { /* Invalid args? */ - print_usage(); - s->status = 1; - return 0; - } - - if ((flags & FLAGS_NOENV)) { - lua_pushboolean(L, 1); - lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); - } - - /* Stop collector during library initialization. */ - lua_gc(L, LUA_GCSTOP, 0); - luaL_openlibs(L); - lua_gc(L, LUA_GCRESTART, -1); - - createargtable(L, argv, s->argc, argn); - - if (!(flags & FLAGS_NOENV)) { - s->status = handle_luainit(L); - if (s->status != LUA_OK) return 0; - } - - if ((flags & FLAGS_VERSION)) print_version(); - - s->status = runargs(L, argv, argn); - if (s->status != LUA_OK) return 0; - - if (s->argc > argn) { - s->status = handle_script(L, argv + argn); - if (s->status != LUA_OK) return 0; - } - - if ((flags & FLAGS_INTERACTIVE)) { - print_jit_status(L); - dotty(L); - } else if (s->argc == argn && !(flags & (FLAGS_EXEC|FLAGS_VERSION))) { - if (lua_stdin_is_tty()) { - print_version(); - print_jit_status(L); - dotty(L); - } else { - dofile(L, NULL); /* Executes stdin as a file. */ - } - } - return 0; -} - -int main(int argc, char **argv) -{ - int status; - lua_State *L = lua_open(); - if (L == NULL) { - l_message(argv[0], "cannot create state: not enough memory"); - return EXIT_FAILURE; - } - smain.argc = argc; - smain.argv = argv; - status = lua_cpcall(L, pmain, NULL); - report(L, status); - lua_close(L); - return (status || smain.status > 0) ? EXIT_FAILURE : EXIT_SUCCESS; -} - diff --git a/lib/LuaJIT/src/luajit.h b/lib/LuaJIT/src/luajit.h deleted file mode 100644 index 708a5a1..0000000 --- a/lib/LuaJIT/src/luajit.h +++ /dev/null @@ -1,79 +0,0 @@ -/* -** LuaJIT -- a Just-In-Time Compiler for Lua. http://luajit.org/ -** -** Copyright (C) 2005-2017 Mike Pall. All rights reserved. -** -** Permission is hereby granted, free of charge, to any person obtaining -** a copy of this software and associated documentation files (the -** "Software"), to deal in the Software without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Software, and to -** permit persons to whom the Software is furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be -** included in all copies or substantial portions of the Software. -** -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -** -** [ MIT license: http://www.opensource.org/licenses/mit-license.php ] -*/ - -#ifndef _LUAJIT_H -#define _LUAJIT_H - -#include "lua.h" - -#define LUAJIT_VERSION "LuaJIT 2.1.0-beta3" -#define LUAJIT_VERSION_NUM 20100 /* Version 2.1.0 = 02.01.00. */ -#define LUAJIT_VERSION_SYM luaJIT_version_2_1_0_beta3 -#define LUAJIT_COPYRIGHT "Copyright (C) 2005-2017 Mike Pall" -#define LUAJIT_URL "http://luajit.org/" - -/* Modes for luaJIT_setmode. */ -#define LUAJIT_MODE_MASK 0x00ff - -enum { - LUAJIT_MODE_ENGINE, /* Set mode for whole JIT engine. */ - LUAJIT_MODE_DEBUG, /* Set debug mode (idx = level). */ - - LUAJIT_MODE_FUNC, /* Change mode for a function. */ - LUAJIT_MODE_ALLFUNC, /* Recurse into subroutine protos. */ - LUAJIT_MODE_ALLSUBFUNC, /* Change only the subroutines. */ - - LUAJIT_MODE_TRACE, /* Flush a compiled trace. */ - - LUAJIT_MODE_WRAPCFUNC = 0x10, /* Set wrapper mode for C function calls. */ - - LUAJIT_MODE_MAX -}; - -/* Flags or'ed in to the mode. */ -#define LUAJIT_MODE_OFF 0x0000 /* Turn feature off. */ -#define LUAJIT_MODE_ON 0x0100 /* Turn feature on. */ -#define LUAJIT_MODE_FLUSH 0x0200 /* Flush JIT-compiled code. */ - -/* LuaJIT public C API. */ - -/* Control the JIT engine. */ -LUA_API int luaJIT_setmode(lua_State *L, int idx, int mode); - -/* Low-overhead profiling API. */ -typedef void (*luaJIT_profile_callback)(void *data, lua_State *L, - int samples, int vmstate); -LUA_API void luaJIT_profile_start(lua_State *L, const char *mode, - luaJIT_profile_callback cb, void *data); -LUA_API void luaJIT_profile_stop(lua_State *L); -LUA_API const char *luaJIT_profile_dumpstack(lua_State *L, const char *fmt, - int depth, size_t *len); - -/* Enforce (dynamic) linker error for version mismatches. Call from main. */ -LUA_API void LUAJIT_VERSION_SYM(void); - -#endif diff --git a/lib/LuaJIT/src/lualib.h b/lib/LuaJIT/src/lualib.h deleted file mode 100644 index bfc130a..0000000 --- a/lib/LuaJIT/src/lualib.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -** Standard library header. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -*/ - -#ifndef _LUALIB_H -#define _LUALIB_H - -#include "lua.h" - -#define LUA_FILEHANDLE "FILE*" - -#define LUA_COLIBNAME "coroutine" -#define LUA_MATHLIBNAME "math" -#define LUA_STRLIBNAME "string" -#define LUA_TABLIBNAME "table" -#define LUA_IOLIBNAME "io" -#define LUA_OSLIBNAME "os" -#define LUA_LOADLIBNAME "package" -#define LUA_DBLIBNAME "debug" -#define LUA_BITLIBNAME "bit" -#define LUA_JITLIBNAME "jit" -#define LUA_FFILIBNAME "ffi" - -LUALIB_API int luaopen_base(lua_State *L); -LUALIB_API int luaopen_math(lua_State *L); -LUALIB_API int luaopen_string(lua_State *L); -LUALIB_API int luaopen_table(lua_State *L); -LUALIB_API int luaopen_io(lua_State *L); -LUALIB_API int luaopen_os(lua_State *L); -LUALIB_API int luaopen_package(lua_State *L); -LUALIB_API int luaopen_debug(lua_State *L); -LUALIB_API int luaopen_bit(lua_State *L); -LUALIB_API int luaopen_jit(lua_State *L); -LUALIB_API int luaopen_ffi(lua_State *L); - -LUALIB_API void luaL_openlibs(lua_State *L); - -#ifndef lua_assert -#define lua_assert(x) ((void)0) -#endif - -#endif diff --git a/lib/LuaJIT/src/msvcbuild.bat b/lib/LuaJIT/src/msvcbuild.bat deleted file mode 100644 index 71bde75..0000000 --- a/lib/LuaJIT/src/msvcbuild.bat +++ /dev/null @@ -1,122 +0,0 @@ -@rem Script to build LuaJIT with MSVC. -@rem Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -@rem -@rem Either open a "Visual Studio .NET Command Prompt" -@rem (Note that the Express Edition does not contain an x64 compiler) -@rem -or- -@rem Open a "Windows SDK Command Shell" and set the compiler environment: -@rem setenv /release /x86 -@rem -or- -@rem setenv /release /x64 -@rem -@rem Then cd to this directory and run this script. - -@if not defined INCLUDE goto :FAIL - -@setlocal -@set LJCOMPILE=cl /nologo /c /O2 /W3 /D_CRT_SECURE_NO_DEPRECATE /D_CRT_STDIO_INLINE=__declspec(dllexport)__inline -@set LJLINK=link /nologo -@set LJMT=mt /nologo -@set LJLIB=lib /nologo /nodefaultlib -@set DASMDIR=..\dynasm -@set DASM=%DASMDIR%\dynasm.lua -@set DASC=vm_x86.dasc -@set LJDLLNAME=lua51.dll -@set LJLIBNAME=lua51.lib -@set ALL_LIB=lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c - -%LJCOMPILE% host\minilua.c -@if errorlevel 1 goto :BAD -%LJLINK% /out:minilua.exe minilua.obj -@if errorlevel 1 goto :BAD -if exist minilua.exe.manifest^ - %LJMT% -manifest minilua.exe.manifest -outputresource:minilua.exe - -@set DASMFLAGS=-D WIN -D JIT -D FFI -D P64 -@set LJARCH=x64 -@minilua -@if errorlevel 8 goto :X64 -@set DASMFLAGS=-D WIN -D JIT -D FFI -@set LJARCH=x86 -@set LJCOMPILE=%LJCOMPILE% /arch:SSE2 -:X64 -@if "%1" neq "gc64" goto :NOGC64 -@shift -@set DASC=vm_x64.dasc -@set LJCOMPILE=%LJCOMPILE% /DLUAJIT_ENABLE_GC64 -:NOGC64 -minilua %DASM% -LN %DASMFLAGS% -o host\buildvm_arch.h %DASC% -@if errorlevel 1 goto :BAD - -%LJCOMPILE% /I "." /I %DASMDIR% host\buildvm*.c -@if errorlevel 1 goto :BAD -%LJLINK% /out:buildvm.exe buildvm*.obj -@if errorlevel 1 goto :BAD -if exist buildvm.exe.manifest^ - %LJMT% -manifest buildvm.exe.manifest -outputresource:buildvm.exe - -buildvm -m peobj -o lj_vm.obj -@if errorlevel 1 goto :BAD -buildvm -m bcdef -o lj_bcdef.h %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m ffdef -o lj_ffdef.h %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m libdef -o lj_libdef.h %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m recdef -o lj_recdef.h %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m vmdef -o jit\vmdef.lua %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m folddef -o lj_folddef.h lj_opt_fold.c -@if errorlevel 1 goto :BAD - -@if "%1" neq "debug" goto :NODEBUG -@shift -@set LJCOMPILE=%LJCOMPILE% /Zi -@set LJLINK=%LJLINK% /debug /opt:ref /opt:icf /incremental:no -:NODEBUG -@if "%1"=="amalg" goto :AMALGDLL -@if "%1"=="static" goto :STATIC -%LJCOMPILE% /MD /DLUA_BUILD_AS_DLL lj_*.c lib_*.c -@if errorlevel 1 goto :BAD -%LJLINK% /DLL /out:%LJDLLNAME% lj_*.obj lib_*.obj -@if errorlevel 1 goto :BAD -@goto :MTDLL -:STATIC -%LJCOMPILE% lj_*.c lib_*.c -@if errorlevel 1 goto :BAD -%LJLIB% /OUT:%LJLIBNAME% lj_*.obj lib_*.obj -@if errorlevel 1 goto :BAD -@goto :MTDLL -:AMALGDLL -%LJCOMPILE% /MD /DLUA_BUILD_AS_DLL ljamalg.c -@if errorlevel 1 goto :BAD -%LJLINK% /DLL /out:%LJDLLNAME% ljamalg.obj lj_vm.obj -@if errorlevel 1 goto :BAD -:MTDLL -if exist %LJDLLNAME%.manifest^ - %LJMT% -manifest %LJDLLNAME%.manifest -outputresource:%LJDLLNAME%;2 - -%LJCOMPILE% luajit.c -@if errorlevel 1 goto :BAD -%LJLINK% /out:luajit.exe luajit.obj %LJLIBNAME% -@if errorlevel 1 goto :BAD -if exist luajit.exe.manifest^ - %LJMT% -manifest luajit.exe.manifest -outputresource:luajit.exe - -@del *.obj *.manifest minilua.exe buildvm.exe -@del host\buildvm_arch.h -@del lj_bcdef.h lj_ffdef.h lj_libdef.h lj_recdef.h lj_folddef.h -@echo. -@echo === Successfully built LuaJIT for Windows/%LJARCH% === - -@goto :END -:BAD -@echo. -@echo ******************************************************* -@echo *** Build FAILED -- Please check the error messages *** -@echo ******************************************************* -@goto :END -:FAIL -@echo You must open a "Visual Studio .NET Command Prompt" to run this script -:END diff --git a/lib/LuaJIT/src/ps4build.bat b/lib/LuaJIT/src/ps4build.bat deleted file mode 100644 index e4a7def..0000000 --- a/lib/LuaJIT/src/ps4build.bat +++ /dev/null @@ -1,123 +0,0 @@ -@rem Script to build LuaJIT with the PS4 SDK. -@rem Donated to the public domain. -@rem -@rem Open a "Visual Studio .NET Command Prompt" (64 bit host compiler) -@rem or "VS2015 x64 Native Tools Command Prompt". -@rem -@rem Then cd to this directory and run this script. -@rem -@rem Recommended invocation: -@rem -@rem ps4build release build, amalgamated, 64-bit GC -@rem ps4build debug debug build, amalgamated, 64-bit GC -@rem -@rem Additional command-line options (not generally recommended): -@rem -@rem gc32 (before debug) 32-bit GC -@rem noamalg (after debug) non-amalgamated build - -@if not defined INCLUDE goto :FAIL -@if not defined SCE_ORBIS_SDK_DIR goto :FAIL - -@setlocal -@rem ---- Host compiler ---- -@set LJCOMPILE=cl /nologo /c /MD /O2 /W3 /D_CRT_SECURE_NO_DEPRECATE -@set LJLINK=link /nologo -@set LJMT=mt /nologo -@set DASMDIR=..\dynasm -@set DASM=%DASMDIR%\dynasm.lua -@set ALL_LIB=lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c -@set GC64=-DLUAJIT_ENABLE_GC64 -@set DASC=vm_x64.dasc - -@if "%1" neq "gc32" goto :NOGC32 -@shift -@set GC64= -@set DASC=vm_x86.dasc -:NOGC32 - -%LJCOMPILE% host\minilua.c -@if errorlevel 1 goto :BAD -%LJLINK% /out:minilua.exe minilua.obj -@if errorlevel 1 goto :BAD -if exist minilua.exe.manifest^ - %LJMT% -manifest minilua.exe.manifest -outputresource:minilua.exe - -@rem Check for 64 bit host compiler. -@minilua -@if not errorlevel 8 goto :FAIL - -@set DASMFLAGS=-D P64 -D NO_UNWIND -minilua %DASM% -LN %DASMFLAGS% -o host\buildvm_arch.h %DASC% -@if errorlevel 1 goto :BAD - -%LJCOMPILE% /I "." /I %DASMDIR% %GC64% -DLUAJIT_TARGET=LUAJIT_ARCH_X64 -DLUAJIT_OS=LUAJIT_OS_OTHER -DLUAJIT_DISABLE_JIT -DLUAJIT_DISABLE_FFI -DLUAJIT_NO_UNWIND host\buildvm*.c -@if errorlevel 1 goto :BAD -%LJLINK% /out:buildvm.exe buildvm*.obj -@if errorlevel 1 goto :BAD -if exist buildvm.exe.manifest^ - %LJMT% -manifest buildvm.exe.manifest -outputresource:buildvm.exe - -buildvm -m elfasm -o lj_vm.s -@if errorlevel 1 goto :BAD -buildvm -m bcdef -o lj_bcdef.h %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m ffdef -o lj_ffdef.h %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m libdef -o lj_libdef.h %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m recdef -o lj_recdef.h %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m vmdef -o jit\vmdef.lua %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m folddef -o lj_folddef.h lj_opt_fold.c -@if errorlevel 1 goto :BAD - -@rem ---- Cross compiler ---- -@set LJCOMPILE="%SCE_ORBIS_SDK_DIR%\host_tools\bin\orbis-clang" -c -Wall -DLUAJIT_DISABLE_FFI %GC64% -@set LJLIB="%SCE_ORBIS_SDK_DIR%\host_tools\bin\orbis-ar" rcus -@set INCLUDE="" - -orbis-as -o lj_vm.o lj_vm.s - -@if "%1" neq "debug" goto :NODEBUG -@shift -@set LJCOMPILE=%LJCOMPILE% -g -O0 -@set TARGETLIB=libluajitD_ps4.a -goto :BUILD -:NODEBUG -@set LJCOMPILE=%LJCOMPILE% -O2 -@set TARGETLIB=libluajit_ps4.a -:BUILD -del %TARGETLIB% -@if "%1" neq "noamalg" goto :AMALG -for %%f in (lj_*.c lib_*.c) do ( - %LJCOMPILE% %%f - @if errorlevel 1 goto :BAD -) - -%LJLIB% %TARGETLIB% lj_*.o lib_*.o -@if errorlevel 1 goto :BAD -@goto :NOAMALG -:AMALG -%LJCOMPILE% ljamalg.c -@if errorlevel 1 goto :BAD -%LJLIB% %TARGETLIB% ljamalg.o lj_vm.o -@if errorlevel 1 goto :BAD -:NOAMALG - -@del *.o *.obj *.manifest minilua.exe buildvm.exe -@echo. -@echo === Successfully built LuaJIT for PS4 === - -@goto :END -:BAD -@echo. -@echo ******************************************************* -@echo *** Build FAILED -- Please check the error messages *** -@echo ******************************************************* -@goto :END -:FAIL -@echo To run this script you must open a "Visual Studio .NET Command Prompt" -@echo (64 bit host compiler). The PS4 Orbis SDK must be installed, too. -:END diff --git a/lib/LuaJIT/src/psvitabuild.bat b/lib/LuaJIT/src/psvitabuild.bat deleted file mode 100644 index 3991dc6..0000000 --- a/lib/LuaJIT/src/psvitabuild.bat +++ /dev/null @@ -1,93 +0,0 @@ -@rem Script to build LuaJIT with the PS Vita SDK. -@rem Donated to the public domain. -@rem -@rem Open a "Visual Studio .NET Command Prompt" (32 bit host compiler) -@rem Then cd to this directory and run this script. - -@if not defined INCLUDE goto :FAIL -@if not defined SCE_PSP2_SDK_DIR goto :FAIL - -@setlocal -@rem ---- Host compiler ---- -@set LJCOMPILE=cl /nologo /c /MD /O2 /W3 /D_CRT_SECURE_NO_DEPRECATE -@set LJLINK=link /nologo -@set LJMT=mt /nologo -@set DASMDIR=..\dynasm -@set DASM=%DASMDIR%\dynasm.lua -@set ALL_LIB=lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c - -%LJCOMPILE% host\minilua.c -@if errorlevel 1 goto :BAD -%LJLINK% /out:minilua.exe minilua.obj -@if errorlevel 1 goto :BAD -if exist minilua.exe.manifest^ - %LJMT% -manifest minilua.exe.manifest -outputresource:minilua.exe - -@rem Check for 32 bit host compiler. -@minilua -@if errorlevel 8 goto :FAIL - -@set DASMFLAGS=-D FPU -D HFABI -minilua %DASM% -LN %DASMFLAGS% -o host\buildvm_arch.h vm_arm.dasc -@if errorlevel 1 goto :BAD - -%LJCOMPILE% /I "." /I %DASMDIR% -DLUAJIT_TARGET=LUAJIT_ARCH_ARM -DLUAJIT_OS=LUAJIT_OS_OTHER -DLUAJIT_DISABLE_JIT -DLUAJIT_DISABLE_FFI -DLJ_TARGET_PSVITA=1 host\buildvm*.c -@if errorlevel 1 goto :BAD -%LJLINK% /out:buildvm.exe buildvm*.obj -@if errorlevel 1 goto :BAD -if exist buildvm.exe.manifest^ - %LJMT% -manifest buildvm.exe.manifest -outputresource:buildvm.exe - -buildvm -m elfasm -o lj_vm.s -@if errorlevel 1 goto :BAD -buildvm -m bcdef -o lj_bcdef.h %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m ffdef -o lj_ffdef.h %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m libdef -o lj_libdef.h %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m recdef -o lj_recdef.h %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m vmdef -o jit\vmdef.lua %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m folddef -o lj_folddef.h lj_opt_fold.c -@if errorlevel 1 goto :BAD - -@rem ---- Cross compiler ---- -@set LJCOMPILE="%SCE_PSP2_SDK_DIR%\host_tools\build\bin\psp2snc" -c -w -DLUAJIT_DISABLE_FFI -DLUAJIT_USE_SYSMALLOC -@set LJLIB="%SCE_PSP2_SDK_DIR%\host_tools\build\bin\psp2ld32" -r --output= -@set INCLUDE="" - -"%SCE_PSP2_SDK_DIR%\host_tools\build\bin\psp2as" -o lj_vm.o lj_vm.s - -@if "%1" neq "debug" goto :NODEBUG -@shift -@set LJCOMPILE=%LJCOMPILE% -g -O0 -@set TARGETLIB=libluajitD.a -goto :BUILD -:NODEBUG -@set LJCOMPILE=%LJCOMPILE% -O2 -@set TARGETLIB=libluajit.a -:BUILD -del %TARGETLIB% - -%LJCOMPILE% ljamalg.c -@if errorlevel 1 goto :BAD -%LJLIB%%TARGETLIB% ljamalg.o lj_vm.o -@if errorlevel 1 goto :BAD - -@del *.o *.obj *.manifest minilua.exe buildvm.exe -@echo. -@echo === Successfully built LuaJIT for PS Vita === - -@goto :END -:BAD -@echo. -@echo ******************************************************* -@echo *** Build FAILED -- Please check the error messages *** -@echo ******************************************************* -@goto :END -:FAIL -@echo To run this script you must open a "Visual Studio .NET Command Prompt" -@echo (32 bit host compiler). The PS Vita SDK must be installed, too. -:END diff --git a/lib/LuaJIT/src/vm_arm.dasc b/lib/LuaJIT/src/vm_arm.dasc deleted file mode 100644 index 780cc16..0000000 --- a/lib/LuaJIT/src/vm_arm.dasc +++ /dev/null @@ -1,4593 +0,0 @@ -|// Low-level VM code for ARM CPUs. -|// Bytecode interpreter, fast functions and helper functions. -|// Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -| -|.arch arm -|.section code_op, code_sub -| -|.actionlist build_actionlist -|.globals GLOB_ -|.globalnames globnames -|.externnames extnames -| -|// Note: The ragged indentation of the instructions is intentional. -|// The starting columns indicate data dependencies. -| -|//----------------------------------------------------------------------- -| -|// Fixed register assignments for the interpreter. -| -|// The following must be C callee-save. -|.define MASKR8, r4 // 255*8 constant for fast bytecode decoding. -|.define KBASE, r5 // Constants of current Lua function. -|.define PC, r6 // Next PC. -|.define DISPATCH, r7 // Opcode dispatch table. -|.define LREG, r8 // Register holding lua_State (also in SAVE_L). -| -|// C callee-save in EABI, but often refetched. Temporary in iOS 3.0+. -|.define BASE, r9 // Base of current Lua stack frame. -| -|// The following temporaries are not saved across C calls, except for RA/RC. -|.define RA, r10 // Callee-save. -|.define RC, r11 // Callee-save. -|.define RB, r12 -|.define OP, r12 // Overlaps RB, must not be lr. -|.define INS, lr -| -|// Calling conventions. Also used as temporaries. -|.define CARG1, r0 -|.define CARG2, r1 -|.define CARG3, r2 -|.define CARG4, r3 -|.define CARG12, r0 // For 1st soft-fp double. -|.define CARG34, r2 // For 2nd soft-fp double. -| -|.define CRET1, r0 -|.define CRET2, r1 -| -|// Stack layout while in interpreter. Must match with lj_frame.h. -|.define SAVE_R4, [sp, #28] -|.define CFRAME_SPACE, #28 -|.define SAVE_ERRF, [sp, #24] -|.define SAVE_NRES, [sp, #20] -|.define SAVE_CFRAME, [sp, #16] -|.define SAVE_L, [sp, #12] -|.define SAVE_PC, [sp, #8] -|.define SAVE_MULTRES, [sp, #4] -|.define ARG5, [sp] -| -|.define TMPDhi, [sp, #4] -|.define TMPDlo, [sp] -|.define TMPD, [sp] -|.define TMPDp, sp -| -|.if FPU -|.macro saveregs -| push {r5, r6, r7, r8, r9, r10, r11, lr} -| vpush {d8-d15} -| sub sp, sp, CFRAME_SPACE+4 -| str r4, SAVE_R4 -|.endmacro -|.macro restoreregs_ret -| ldr r4, SAVE_R4 -| add sp, sp, CFRAME_SPACE+4 -| vpop {d8-d15} -| pop {r5, r6, r7, r8, r9, r10, r11, pc} -|.endmacro -|.else -|.macro saveregs -| push {r4, r5, r6, r7, r8, r9, r10, r11, lr} -| sub sp, sp, CFRAME_SPACE -|.endmacro -|.macro restoreregs_ret -| add sp, sp, CFRAME_SPACE -| pop {r4, r5, r6, r7, r8, r9, r10, r11, pc} -|.endmacro -|.endif -| -|// Type definitions. Some of these are only used for documentation. -|.type L, lua_State, LREG -|.type GL, global_State -|.type TVALUE, TValue -|.type GCOBJ, GCobj -|.type STR, GCstr -|.type TAB, GCtab -|.type LFUNC, GCfuncL -|.type CFUNC, GCfuncC -|.type PROTO, GCproto -|.type UPVAL, GCupval -|.type NODE, Node -|.type NARGS8, int -|.type TRACE, GCtrace -|.type SBUF, SBuf -| -|//----------------------------------------------------------------------- -| -|// Trap for not-yet-implemented parts. -|.macro NYI; ud; .endmacro -| -|//----------------------------------------------------------------------- -| -|// Access to frame relative to BASE. -|.define FRAME_FUNC, #-8 -|.define FRAME_PC, #-4 -| -|.macro decode_RA8, dst, ins; and dst, MASKR8, ins, lsr #5; .endmacro -|.macro decode_RB8, dst, ins; and dst, MASKR8, ins, lsr #21; .endmacro -|.macro decode_RC8, dst, ins; and dst, MASKR8, ins, lsr #13; .endmacro -|.macro decode_RD, dst, ins; lsr dst, ins, #16; .endmacro -|.macro decode_OP, dst, ins; and dst, ins, #255; .endmacro -| -|// Instruction fetch. -|.macro ins_NEXT1 -| ldrb OP, [PC] -|.endmacro -|.macro ins_NEXT2 -| ldr INS, [PC], #4 -|.endmacro -|// Instruction decode+dispatch. -|.macro ins_NEXT3 -| ldr OP, [DISPATCH, OP, lsl #2] -| decode_RA8 RA, INS -| decode_RD RC, INS -| bx OP -|.endmacro -|.macro ins_NEXT -| ins_NEXT1 -| ins_NEXT2 -| ins_NEXT3 -|.endmacro -| -|// Instruction footer. -|.if 1 -| // Replicated dispatch. Less unpredictable branches, but higher I-Cache use. -| .define ins_next, ins_NEXT -| .define ins_next_, ins_NEXT -| .define ins_next1, ins_NEXT1 -| .define ins_next2, ins_NEXT2 -| .define ins_next3, ins_NEXT3 -|.else -| // Common dispatch. Lower I-Cache use, only one (very) unpredictable branch. -| // Affects only certain kinds of benchmarks (and only with -j off). -| .macro ins_next -| b ->ins_next -| .endmacro -| .macro ins_next1 -| .endmacro -| .macro ins_next2 -| .endmacro -| .macro ins_next3 -| b ->ins_next -| .endmacro -| .macro ins_next_ -| ->ins_next: -| ins_NEXT -| .endmacro -|.endif -| -|// Avoid register name substitution for field name. -#define field_pc pc -| -|// Call decode and dispatch. -|.macro ins_callt -| // BASE = new base, CARG3 = LFUNC/CFUNC, RC = nargs*8, FRAME_PC(BASE) = PC -| ldr PC, LFUNC:CARG3->field_pc -| ldrb OP, [PC] // STALL: load PC. early PC. -| ldr INS, [PC], #4 -| ldr OP, [DISPATCH, OP, lsl #2] // STALL: load OP. early OP. -| decode_RA8 RA, INS -| add RA, RA, BASE -| bx OP -|.endmacro -| -|.macro ins_call -| // BASE = new base, CARG3 = LFUNC/CFUNC, RC = nargs*8, PC = caller PC -| str PC, [BASE, FRAME_PC] -| ins_callt // STALL: locked PC. -|.endmacro -| -|//----------------------------------------------------------------------- -| -|// Macros to test operand types. -|.macro checktp, reg, tp; cmn reg, #-tp; .endmacro -|.macro checktpeq, reg, tp; cmneq reg, #-tp; .endmacro -|.macro checktpne, reg, tp; cmnne reg, #-tp; .endmacro -|.macro checkstr, reg, target; checktp reg, LJ_TSTR; bne target; .endmacro -|.macro checktab, reg, target; checktp reg, LJ_TTAB; bne target; .endmacro -|.macro checkfunc, reg, target; checktp reg, LJ_TFUNC; bne target; .endmacro -| -|// Assumes DISPATCH is relative to GL. -#define DISPATCH_GL(field) (GG_DISP2G + (int)offsetof(global_State, field)) -#define DISPATCH_J(field) (GG_DISP2J + (int)offsetof(jit_State, field)) -| -#define PC2PROTO(field) ((int)offsetof(GCproto, field)-(int)sizeof(GCproto)) -| -|.macro hotcheck, delta -| lsr CARG1, PC, #1 -| and CARG1, CARG1, #126 -| sub CARG1, CARG1, #-GG_DISP2HOT -| ldrh CARG2, [DISPATCH, CARG1] -| subs CARG2, CARG2, #delta -| strh CARG2, [DISPATCH, CARG1] -|.endmacro -| -|.macro hotloop -| hotcheck HOTCOUNT_LOOP -| blo ->vm_hotloop -|.endmacro -| -|.macro hotcall -| hotcheck HOTCOUNT_CALL -| blo ->vm_hotcall -|.endmacro -| -|// Set current VM state. -|.macro mv_vmstate, reg, st; mvn reg, #LJ_VMST_..st; .endmacro -|.macro st_vmstate, reg; str reg, [DISPATCH, #DISPATCH_GL(vmstate)]; .endmacro -| -|// Move table write barrier back. Overwrites mark and tmp. -|.macro barrierback, tab, mark, tmp -| ldr tmp, [DISPATCH, #DISPATCH_GL(gc.grayagain)] -| bic mark, mark, #LJ_GC_BLACK // black2gray(tab) -| str tab, [DISPATCH, #DISPATCH_GL(gc.grayagain)] -| strb mark, tab->marked -| str tmp, tab->gclist -|.endmacro -| -|.macro .IOS, a, b -|.if IOS -| a, b -|.endif -|.endmacro -| -|//----------------------------------------------------------------------- - -#if !LJ_DUALNUM -#error "Only dual-number mode supported for ARM target" -#endif - -/* Generate subroutines used by opcodes and other parts of the VM. */ -/* The .code_sub section should be last to help static branch prediction. */ -static void build_subroutines(BuildCtx *ctx) -{ - |.code_sub - | - |//----------------------------------------------------------------------- - |//-- Return handling ---------------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_returnp: - | // See vm_return. Also: RB = previous base. - | tst PC, #FRAME_P - | beq ->cont_dispatch - | - | // Return from pcall or xpcall fast func. - | ldr PC, [RB, FRAME_PC] // Fetch PC of previous frame. - | mvn CARG2, #~LJ_TTRUE - | mov BASE, RB - | // Prepending may overwrite the pcall frame, so do it at the end. - | str CARG2, [RA, FRAME_PC] // Prepend true to results. - | sub RA, RA, #8 - | - |->vm_returnc: - | adds RC, RC, #8 // RC = (nresults+1)*8. - | mov CRET1, #LUA_YIELD - | beq ->vm_unwind_c_eh - | str RC, SAVE_MULTRES - | ands CARG1, PC, #FRAME_TYPE - | beq ->BC_RET_Z // Handle regular return to Lua. - | - |->vm_return: - | // BASE = base, RA = resultptr, RC/MULTRES = (nresults+1)*8, PC = return - | // CARG1 = PC & FRAME_TYPE - | bic RB, PC, #FRAME_TYPEP - | cmp CARG1, #FRAME_C - | sub RB, BASE, RB // RB = previous base. - | bne ->vm_returnp - | - | str RB, L->base - | ldr KBASE, SAVE_NRES - | mv_vmstate CARG4, C - | sub BASE, BASE, #8 - | subs CARG3, RC, #8 - | lsl KBASE, KBASE, #3 // KBASE = (nresults_wanted+1)*8 - | st_vmstate CARG4 - | beq >2 - |1: - | subs CARG3, CARG3, #8 - | ldrd CARG12, [RA], #8 - | strd CARG12, [BASE], #8 - | bne <1 - |2: - | cmp KBASE, RC // More/less results wanted? - | bne >6 - |3: - | str BASE, L->top // Store new top. - | - |->vm_leave_cp: - | ldr RC, SAVE_CFRAME // Restore previous C frame. - | mov CRET1, #0 // Ok return status for vm_pcall. - | str RC, L->cframe - | - |->vm_leave_unw: - | restoreregs_ret - | - |6: - | blt >7 // Less results wanted? - | // More results wanted. Check stack size and fill up results with nil. - | ldr CARG3, L->maxstack - | mvn CARG2, #~LJ_TNIL - | cmp BASE, CARG3 - | bhs >8 - | str CARG2, [BASE, #4] - | add RC, RC, #8 - | add BASE, BASE, #8 - | b <2 - | - |7: // Less results wanted. - | sub CARG1, RC, KBASE - | cmp KBASE, #0 // LUA_MULTRET+1 case? - | subne BASE, BASE, CARG1 // Either keep top or shrink it. - | b <3 - | - |8: // Corner case: need to grow stack for filling up results. - | // This can happen if: - | // - A C function grows the stack (a lot). - | // - The GC shrinks the stack in between. - | // - A return back from a lua_call() with (high) nresults adjustment. - | str BASE, L->top // Save current top held in BASE (yes). - | lsr CARG2, KBASE, #3 - | mov CARG1, L - | bl extern lj_state_growstack // (lua_State *L, int n) - | ldr BASE, L->top // Need the (realloced) L->top in BASE. - | b <2 - | - |->vm_unwind_c: // Unwind C stack, return from vm_pcall. - | // (void *cframe, int errcode) - | mov sp, CARG1 - | mov CRET1, CARG2 - |->vm_unwind_c_eh: // Landing pad for external unwinder. - | ldr L, SAVE_L - | mv_vmstate CARG4, C - | ldr GL:CARG3, L->glref - | str CARG4, GL:CARG3->vmstate - | b ->vm_leave_unw - | - |->vm_unwind_ff: // Unwind C stack, return from ff pcall. - | // (void *cframe) - | bic CARG1, CARG1, #~CFRAME_RAWMASK // Use two steps: bic sp is deprecated. - | mov sp, CARG1 - |->vm_unwind_ff_eh: // Landing pad for external unwinder. - | ldr L, SAVE_L - | mov MASKR8, #255 - | mov RC, #16 // 2 results: false + error message. - | lsl MASKR8, MASKR8, #3 // MASKR8 = 255*8. - | ldr BASE, L->base - | ldr DISPATCH, L->glref // Setup pointer to dispatch table. - | mvn CARG1, #~LJ_TFALSE - | sub RA, BASE, #8 // Results start at BASE-8. - | ldr PC, [BASE, FRAME_PC] // Fetch PC of previous frame. - | add DISPATCH, DISPATCH, #GG_G2DISP - | mv_vmstate CARG2, INTERP - | str CARG1, [BASE, #-4] // Prepend false to error message. - | st_vmstate CARG2 - | b ->vm_returnc - | - |->vm_unwind_ext: // Complete external unwind. -#if !LJ_NO_UNWIND - | push {r0, r1, r2, lr} - | bl extern _Unwind_Complete - | ldr r0, [sp] - | bl extern _Unwind_DeleteException - | pop {r0, r1, r2, lr} - | mov r0, r1 - | bx r2 -#endif - | - |//----------------------------------------------------------------------- - |//-- Grow stack for calls ----------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_growstack_c: // Grow stack for C function. - | // CARG1 = L - | mov CARG2, #LUA_MINSTACK - | b >2 - | - |->vm_growstack_l: // Grow stack for Lua function. - | // BASE = new base, RA = BASE+framesize*8, RC = nargs*8, PC = first PC - | add RC, BASE, RC - | sub RA, RA, BASE - | mov CARG1, L - | str BASE, L->base - | add PC, PC, #4 // Must point after first instruction. - | str RC, L->top - | lsr CARG2, RA, #3 - |2: - | // L->base = new base, L->top = top - | str PC, SAVE_PC - | bl extern lj_state_growstack // (lua_State *L, int n) - | ldr BASE, L->base - | ldr RC, L->top - | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] - | sub NARGS8:RC, RC, BASE - | // BASE = new base, RB = LFUNC/CFUNC, RC = nargs*8, FRAME_PC(BASE) = PC - | ins_callt // Just retry the call. - | - |//----------------------------------------------------------------------- - |//-- Entry points into the assembler VM --------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_resume: // Setup C frame and resume thread. - | // (lua_State *L, TValue *base, int nres1 = 0, ptrdiff_t ef = 0) - | saveregs - | mov L, CARG1 - | ldr DISPATCH, L:CARG1->glref // Setup pointer to dispatch table. - | mov BASE, CARG2 - | add DISPATCH, DISPATCH, #GG_G2DISP - | str L, SAVE_L - | mov PC, #FRAME_CP - | str CARG3, SAVE_NRES - | add CARG2, sp, #CFRAME_RESUME - | ldrb CARG1, L->status - | str CARG3, SAVE_ERRF - | str L, SAVE_PC // Any value outside of bytecode is ok. - | str CARG3, SAVE_CFRAME - | cmp CARG1, #0 - | str CARG2, L->cframe - | beq >3 - | - | // Resume after yield (like a return). - | str L, [DISPATCH, #DISPATCH_GL(cur_L)] - | mov RA, BASE - | ldr BASE, L->base - | ldr CARG1, L->top - | mov MASKR8, #255 - | strb CARG3, L->status - | sub RC, CARG1, BASE - | ldr PC, [BASE, FRAME_PC] - | lsl MASKR8, MASKR8, #3 // MASKR8 = 255*8. - | mv_vmstate CARG2, INTERP - | add RC, RC, #8 - | ands CARG1, PC, #FRAME_TYPE - | st_vmstate CARG2 - | str RC, SAVE_MULTRES - | beq ->BC_RET_Z - | b ->vm_return - | - |->vm_pcall: // Setup protected C frame and enter VM. - | // (lua_State *L, TValue *base, int nres1, ptrdiff_t ef) - | saveregs - | mov PC, #FRAME_CP - | str CARG4, SAVE_ERRF - | b >1 - | - |->vm_call: // Setup C frame and enter VM. - | // (lua_State *L, TValue *base, int nres1) - | saveregs - | mov PC, #FRAME_C - | - |1: // Entry point for vm_pcall above (PC = ftype). - | ldr RC, L:CARG1->cframe - | str CARG3, SAVE_NRES - | mov L, CARG1 - | str CARG1, SAVE_L - | ldr DISPATCH, L->glref // Setup pointer to dispatch table. - | mov BASE, CARG2 - | str CARG1, SAVE_PC // Any value outside of bytecode is ok. - | str RC, SAVE_CFRAME - | add DISPATCH, DISPATCH, #GG_G2DISP - | str sp, L->cframe // Add our C frame to cframe chain. - | - |3: // Entry point for vm_cpcall/vm_resume (BASE = base, PC = ftype). - | str L, [DISPATCH, #DISPATCH_GL(cur_L)] - | ldr RB, L->base // RB = old base (for vmeta_call). - | ldr CARG1, L->top - | mov MASKR8, #255 - | add PC, PC, BASE - | lsl MASKR8, MASKR8, #3 // MASKR8 = 255*8. - | sub PC, PC, RB // PC = frame delta + frame type - | mv_vmstate CARG2, INTERP - | sub NARGS8:RC, CARG1, BASE - | st_vmstate CARG2 - | - |->vm_call_dispatch: - | // RB = old base, BASE = new base, RC = nargs*8, PC = caller PC - | ldrd CARG34, [BASE, FRAME_FUNC] - | checkfunc CARG4, ->vmeta_call - | - |->vm_call_dispatch_f: - | ins_call - | // BASE = new base, CARG3 = func, RC = nargs*8, PC = caller PC - | - |->vm_cpcall: // Setup protected C frame, call C. - | // (lua_State *L, lua_CFunction func, void *ud, lua_CPFunction cp) - | saveregs - | mov L, CARG1 - | ldr RA, L:CARG1->stack - | str CARG1, SAVE_L - | ldr DISPATCH, L->glref // Setup pointer to dispatch table. - | ldr RB, L->top - | str CARG1, SAVE_PC // Any value outside of bytecode is ok. - | ldr RC, L->cframe - | add DISPATCH, DISPATCH, #GG_G2DISP - | sub RA, RA, RB // Compute -savestack(L, L->top). - | mov RB, #0 - | str RA, SAVE_NRES // Neg. delta means cframe w/o frame. - | str RB, SAVE_ERRF // No error function. - | str RC, SAVE_CFRAME - | str sp, L->cframe // Add our C frame to cframe chain. - | str L, [DISPATCH, #DISPATCH_GL(cur_L)] - | blx CARG4 // (lua_State *L, lua_CFunction func, void *ud) - | movs BASE, CRET1 - | mov PC, #FRAME_CP - | bne <3 // Else continue with the call. - | b ->vm_leave_cp // No base? Just remove C frame. - | - |//----------------------------------------------------------------------- - |//-- Metamethod handling ------------------------------------------------ - |//----------------------------------------------------------------------- - | - |//-- Continuation dispatch ---------------------------------------------- - | - |->cont_dispatch: - | // BASE = meta base, RA = resultptr, RC = (nresults+1)*8 - | ldr LFUNC:CARG3, [RB, FRAME_FUNC] - | ldr CARG1, [BASE, #-16] // Get continuation. - | mov CARG4, BASE - | mov BASE, RB // Restore caller BASE. - |.if FFI - | cmp CARG1, #1 - |.endif - | ldr PC, [CARG4, #-12] // Restore PC from [cont|PC]. - | ldr CARG3, LFUNC:CARG3->field_pc - | mvn INS, #~LJ_TNIL - | add CARG2, RA, RC - | str INS, [CARG2, #-4] // Ensure one valid arg. - |.if FFI - | bls >1 - |.endif - | ldr KBASE, [CARG3, #PC2PROTO(k)] - | // BASE = base, RA = resultptr, CARG4 = meta base - | bx CARG1 - | - |.if FFI - |1: - | beq ->cont_ffi_callback // cont = 1: return from FFI callback. - | // cont = 0: tailcall from C function. - | sub CARG4, CARG4, #16 - | sub RC, CARG4, BASE - | b ->vm_call_tail - |.endif - | - |->cont_cat: // RA = resultptr, CARG4 = meta base - | ldr INS, [PC, #-4] - | sub CARG2, CARG4, #16 - | ldrd CARG34, [RA] - | str BASE, L->base - | decode_RB8 RC, INS - | decode_RA8 RA, INS - | add CARG1, BASE, RC - | subs CARG1, CARG2, CARG1 - | strdne CARG34, [CARG2] - | movne CARG3, CARG1 - | bne ->BC_CAT_Z - | strd CARG34, [BASE, RA] - | b ->cont_nop - | - |//-- Table indexing metamethods ----------------------------------------- - | - |->vmeta_tgets1: - | add CARG2, BASE, RB - | b >2 - | - |->vmeta_tgets: - | sub CARG2, DISPATCH, #-DISPATCH_GL(tmptv) - | mvn CARG4, #~LJ_TTAB - | str TAB:RB, [CARG2] - | str CARG4, [CARG2, #4] - |2: - | mvn CARG4, #~LJ_TSTR - | str STR:RC, TMPDlo - | str CARG4, TMPDhi - | mov CARG3, TMPDp - | b >1 - | - |->vmeta_tgetb: // RC = index - | decode_RB8 RB, INS - | str RC, TMPDlo - | mvn CARG4, #~LJ_TISNUM - | add CARG2, BASE, RB - | str CARG4, TMPDhi - | mov CARG3, TMPDp - | b >1 - | - |->vmeta_tgetv: - | add CARG2, BASE, RB - | add CARG3, BASE, RC - |1: - | str BASE, L->base - | mov CARG1, L - | str PC, SAVE_PC - | bl extern lj_meta_tget // (lua_State *L, TValue *o, TValue *k) - | // Returns TValue * (finished) or NULL (metamethod). - | .IOS ldr BASE, L->base - | cmp CRET1, #0 - | beq >3 - | ldrd CARG34, [CRET1] - | ins_next1 - | ins_next2 - | strd CARG34, [BASE, RA] - | ins_next3 - | - |3: // Call __index metamethod. - | // BASE = base, L->top = new base, stack = cont/func/t/k - | rsb CARG1, BASE, #FRAME_CONT - | ldr BASE, L->top - | mov NARGS8:RC, #16 // 2 args for func(t, k). - | str PC, [BASE, #-12] // [cont|PC] - | add PC, CARG1, BASE - | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] // Guaranteed to be a function here. - | b ->vm_call_dispatch_f - | - |->vmeta_tgetr: - | .IOS mov RC, BASE - | bl extern lj_tab_getinth // (GCtab *t, int32_t key) - | // Returns cTValue * or NULL. - | .IOS mov BASE, RC - | cmp CRET1, #0 - | ldrdne CARG12, [CRET1] - | mvneq CARG2, #~LJ_TNIL - | b ->BC_TGETR_Z - | - |//----------------------------------------------------------------------- - | - |->vmeta_tsets1: - | add CARG2, BASE, RB - | b >2 - | - |->vmeta_tsets: - | sub CARG2, DISPATCH, #-DISPATCH_GL(tmptv) - | mvn CARG4, #~LJ_TTAB - | str TAB:RB, [CARG2] - | str CARG4, [CARG2, #4] - |2: - | mvn CARG4, #~LJ_TSTR - | str STR:RC, TMPDlo - | str CARG4, TMPDhi - | mov CARG3, TMPDp - | b >1 - | - |->vmeta_tsetb: // RC = index - | decode_RB8 RB, INS - | str RC, TMPDlo - | mvn CARG4, #~LJ_TISNUM - | add CARG2, BASE, RB - | str CARG4, TMPDhi - | mov CARG3, TMPDp - | b >1 - | - |->vmeta_tsetv: - | add CARG2, BASE, RB - | add CARG3, BASE, RC - |1: - | str BASE, L->base - | mov CARG1, L - | str PC, SAVE_PC - | bl extern lj_meta_tset // (lua_State *L, TValue *o, TValue *k) - | // Returns TValue * (finished) or NULL (metamethod). - | .IOS ldr BASE, L->base - | cmp CRET1, #0 - | ldrd CARG34, [BASE, RA] - | beq >3 - | ins_next1 - | // NOBARRIER: lj_meta_tset ensures the table is not black. - | strd CARG34, [CRET1] - | ins_next2 - | ins_next3 - | - |3: // Call __newindex metamethod. - | // BASE = base, L->top = new base, stack = cont/func/t/k/(v) - | rsb CARG1, BASE, #FRAME_CONT - | ldr BASE, L->top - | mov NARGS8:RC, #24 // 3 args for func(t, k, v). - | strd CARG34, [BASE, #16] // Copy value to third argument. - | str PC, [BASE, #-12] // [cont|PC] - | add PC, CARG1, BASE - | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] // Guaranteed to be a function here. - | b ->vm_call_dispatch_f - | - |->vmeta_tsetr: - | str BASE, L->base - | .IOS mov RC, BASE - | str PC, SAVE_PC - | bl extern lj_tab_setinth // (lua_State *L, GCtab *t, int32_t key) - | // Returns TValue *. - | .IOS mov BASE, RC - | b ->BC_TSETR_Z - | - |//-- Comparison metamethods --------------------------------------------- - | - |->vmeta_comp: - | mov CARG1, L - | sub PC, PC, #4 - | mov CARG2, RA - | str BASE, L->base - | mov CARG3, RC - | str PC, SAVE_PC - | decode_OP CARG4, INS - | bl extern lj_meta_comp // (lua_State *L, TValue *o1, *o2, int op) - | // Returns 0/1 or TValue * (metamethod). - |3: - | .IOS ldr BASE, L->base - | cmp CRET1, #1 - | bhi ->vmeta_binop - |4: - | ldrh RB, [PC, #2] - | add PC, PC, #4 - | add RB, PC, RB, lsl #2 - | subhs PC, RB, #0x20000 - |->cont_nop: - | ins_next - | - |->cont_ra: // RA = resultptr - | ldr INS, [PC, #-4] - | ldrd CARG12, [RA] - | decode_RA8 CARG3, INS - | strd CARG12, [BASE, CARG3] - | b ->cont_nop - | - |->cont_condt: // RA = resultptr - | ldr CARG2, [RA, #4] - | mvn CARG1, #~LJ_TTRUE - | cmp CARG1, CARG2 // Branch if result is true. - | b <4 - | - |->cont_condf: // RA = resultptr - | ldr CARG2, [RA, #4] - | checktp CARG2, LJ_TFALSE // Branch if result is false. - | b <4 - | - |->vmeta_equal: - | // CARG2, CARG3, CARG4 are already set by BC_ISEQV/BC_ISNEV. - | sub PC, PC, #4 - | str BASE, L->base - | mov CARG1, L - | str PC, SAVE_PC - | bl extern lj_meta_equal // (lua_State *L, GCobj *o1, *o2, int ne) - | // Returns 0/1 or TValue * (metamethod). - | b <3 - | - |->vmeta_equal_cd: - |.if FFI - | sub PC, PC, #4 - | str BASE, L->base - | mov CARG1, L - | mov CARG2, INS - | str PC, SAVE_PC - | bl extern lj_meta_equal_cd // (lua_State *L, BCIns op) - | // Returns 0/1 or TValue * (metamethod). - | b <3 - |.endif - | - |->vmeta_istype: - | sub PC, PC, #4 - | str BASE, L->base - | mov CARG1, L - | lsr CARG2, RA, #3 - | mov CARG3, RC - | str PC, SAVE_PC - | bl extern lj_meta_istype // (lua_State *L, BCReg ra, BCReg tp) - | .IOS ldr BASE, L->base - | b ->cont_nop - | - |//-- Arithmetic metamethods --------------------------------------------- - | - |->vmeta_arith_vn: - | decode_RB8 RB, INS - | decode_RC8 RC, INS - | add CARG3, BASE, RB - | add CARG4, KBASE, RC - | b >1 - | - |->vmeta_arith_nv: - | decode_RB8 RB, INS - | decode_RC8 RC, INS - | add CARG4, BASE, RB - | add CARG3, KBASE, RC - | b >1 - | - |->vmeta_unm: - | ldr INS, [PC, #-8] - | sub PC, PC, #4 - | add CARG3, BASE, RC - | add CARG4, BASE, RC - | b >1 - | - |->vmeta_arith_vv: - | decode_RB8 RB, INS - | decode_RC8 RC, INS - | add CARG3, BASE, RB - | add CARG4, BASE, RC - |1: - | decode_OP OP, INS - | add CARG2, BASE, RA - | str BASE, L->base - | mov CARG1, L - | str PC, SAVE_PC - | str OP, ARG5 - | bl extern lj_meta_arith // (lua_State *L, TValue *ra,*rb,*rc, BCReg op) - | // Returns NULL (finished) or TValue * (metamethod). - | .IOS ldr BASE, L->base - | cmp CRET1, #0 - | beq ->cont_nop - | - | // Call metamethod for binary op. - |->vmeta_binop: - | // BASE = old base, CRET1 = new base, stack = cont/func/o1/o2 - | sub CARG2, CRET1, BASE - | str PC, [CRET1, #-12] // [cont|PC] - | add PC, CARG2, #FRAME_CONT - | mov BASE, CRET1 - | mov NARGS8:RC, #16 // 2 args for func(o1, o2). - | b ->vm_call_dispatch - | - |->vmeta_len: - | add CARG2, BASE, RC - | str BASE, L->base - | mov CARG1, L - | str PC, SAVE_PC - | bl extern lj_meta_len // (lua_State *L, TValue *o) - | // Returns NULL (retry) or TValue * (metamethod base). - | .IOS ldr BASE, L->base -#if LJ_52 - | cmp CRET1, #0 - | bne ->vmeta_binop // Binop call for compatibility. - | ldr TAB:CARG1, [BASE, RC] - | b ->BC_LEN_Z -#else - | b ->vmeta_binop // Binop call for compatibility. -#endif - | - |//-- Call metamethod ---------------------------------------------------- - | - |->vmeta_call: // Resolve and call __call metamethod. - | // RB = old base, BASE = new base, RC = nargs*8 - | mov CARG1, L - | str RB, L->base // This is the callers base! - | sub CARG2, BASE, #8 - | str PC, SAVE_PC - | add CARG3, BASE, NARGS8:RC - | .IOS mov RA, BASE - | bl extern lj_meta_call // (lua_State *L, TValue *func, TValue *top) - | .IOS mov BASE, RA - | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] // Guaranteed to be a function here. - | add NARGS8:RC, NARGS8:RC, #8 // Got one more argument now. - | ins_call - | - |->vmeta_callt: // Resolve __call for BC_CALLT. - | // BASE = old base, RA = new base, RC = nargs*8 - | mov CARG1, L - | str BASE, L->base - | sub CARG2, RA, #8 - | str PC, SAVE_PC - | add CARG3, RA, NARGS8:RC - | bl extern lj_meta_call // (lua_State *L, TValue *func, TValue *top) - | .IOS ldr BASE, L->base - | ldr LFUNC:CARG3, [RA, FRAME_FUNC] // Guaranteed to be a function here. - | ldr PC, [BASE, FRAME_PC] - | add NARGS8:RC, NARGS8:RC, #8 // Got one more argument now. - | b ->BC_CALLT2_Z - | - |//-- Argument coercion for 'for' statement ------------------------------ - | - |->vmeta_for: - | mov CARG1, L - | str BASE, L->base - | mov CARG2, RA - | str PC, SAVE_PC - | bl extern lj_meta_for // (lua_State *L, TValue *base) - | .IOS ldr BASE, L->base - |.if JIT - | ldrb OP, [PC, #-4] - |.endif - | ldr INS, [PC, #-4] - |.if JIT - | cmp OP, #BC_JFORI - |.endif - | decode_RA8 RA, INS - | decode_RD RC, INS - |.if JIT - | beq =>BC_JFORI - |.endif - | b =>BC_FORI - | - |//----------------------------------------------------------------------- - |//-- Fast functions ----------------------------------------------------- - |//----------------------------------------------------------------------- - | - |.macro .ffunc, name - |->ff_ .. name: - |.endmacro - | - |.macro .ffunc_1, name - |->ff_ .. name: - | ldrd CARG12, [BASE] - | cmp NARGS8:RC, #8 - | blo ->fff_fallback - |.endmacro - | - |.macro .ffunc_2, name - |->ff_ .. name: - | ldrd CARG12, [BASE] - | ldrd CARG34, [BASE, #8] - | cmp NARGS8:RC, #16 - | blo ->fff_fallback - |.endmacro - | - |.macro .ffunc_n, name - | .ffunc_1 name - | checktp CARG2, LJ_TISNUM - | bhs ->fff_fallback - |.endmacro - | - |.macro .ffunc_nn, name - | .ffunc_2 name - | checktp CARG2, LJ_TISNUM - | cmnlo CARG4, #-LJ_TISNUM - | bhs ->fff_fallback - |.endmacro - | - |.macro .ffunc_d, name - | .ffunc name - | ldr CARG2, [BASE, #4] - | cmp NARGS8:RC, #8 - | vldr d0, [BASE] - | blo ->fff_fallback - | checktp CARG2, LJ_TISNUM - | bhs ->fff_fallback - |.endmacro - | - |.macro .ffunc_dd, name - | .ffunc name - | ldr CARG2, [BASE, #4] - | ldr CARG4, [BASE, #12] - | cmp NARGS8:RC, #16 - | vldr d0, [BASE] - | vldr d1, [BASE, #8] - | blo ->fff_fallback - | checktp CARG2, LJ_TISNUM - | cmnlo CARG4, #-LJ_TISNUM - | bhs ->fff_fallback - |.endmacro - | - |// Inlined GC threshold check. Caveat: uses CARG1 and CARG2. - |.macro ffgccheck - | ldr CARG1, [DISPATCH, #DISPATCH_GL(gc.total)] - | ldr CARG2, [DISPATCH, #DISPATCH_GL(gc.threshold)] - | cmp CARG1, CARG2 - | blge ->fff_gcstep - |.endmacro - | - |//-- Base library: checks ----------------------------------------------- - | - |.ffunc_1 assert - | checktp CARG2, LJ_TTRUE - | bhi ->fff_fallback - | ldr PC, [BASE, FRAME_PC] - | strd CARG12, [BASE, #-8] - | mov RB, BASE - | subs RA, NARGS8:RC, #8 - | add RC, NARGS8:RC, #8 // Compute (nresults+1)*8. - | beq ->fff_res // Done if exactly 1 argument. - |1: - | ldrd CARG12, [RB, #8] - | subs RA, RA, #8 - | strd CARG12, [RB], #8 - | bne <1 - | b ->fff_res - | - |.ffunc type - | ldr CARG2, [BASE, #4] - | cmp NARGS8:RC, #8 - | blo ->fff_fallback - | checktp CARG2, LJ_TISNUM - | mvnlo CARG2, #~LJ_TISNUM - | rsb CARG4, CARG2, #(int)(offsetof(GCfuncC, upvalue)>>3)-1 - | lsl CARG4, CARG4, #3 - | ldrd CARG12, [CFUNC:CARG3, CARG4] - | b ->fff_restv - | - |//-- Base library: getters and setters --------------------------------- - | - |.ffunc_1 getmetatable - | checktp CARG2, LJ_TTAB - | cmnne CARG2, #-LJ_TUDATA - | bne >6 - |1: // Field metatable must be at same offset for GCtab and GCudata! - | ldr TAB:RB, TAB:CARG1->metatable - |2: - | mvn CARG2, #~LJ_TNIL - | ldr STR:RC, [DISPATCH, #DISPATCH_GL(gcroot[GCROOT_MMNAME+MM_metatable])] - | cmp TAB:RB, #0 - | beq ->fff_restv - | ldr CARG3, TAB:RB->hmask - | ldr CARG4, STR:RC->hash - | ldr NODE:INS, TAB:RB->node - | and CARG3, CARG3, CARG4 // idx = str->hash & tab->hmask - | add CARG3, CARG3, CARG3, lsl #1 - | add NODE:INS, NODE:INS, CARG3, lsl #3 // node = tab->node + idx*3*8 - |3: // Rearranged logic, because we expect _not_ to find the key. - | ldrd CARG34, NODE:INS->key // STALL: early NODE:INS. - | ldrd CARG12, NODE:INS->val - | ldr NODE:INS, NODE:INS->next - | checktp CARG4, LJ_TSTR - | cmpeq CARG3, STR:RC - | beq >5 - | cmp NODE:INS, #0 - | bne <3 - |4: - | mov CARG1, RB // Use metatable as default result. - | mvn CARG2, #~LJ_TTAB - | b ->fff_restv - |5: - | checktp CARG2, LJ_TNIL - | bne ->fff_restv - | b <4 - | - |6: - | checktp CARG2, LJ_TISNUM - | mvnhs CARG2, CARG2 - | movlo CARG2, #~LJ_TISNUM - | add CARG4, DISPATCH, CARG2, lsl #2 - | ldr TAB:RB, [CARG4, #DISPATCH_GL(gcroot[GCROOT_BASEMT])] - | b <2 - | - |.ffunc_2 setmetatable - | // Fast path: no mt for table yet and not clearing the mt. - | checktp CARG2, LJ_TTAB - | ldreq TAB:RB, TAB:CARG1->metatable - | checktpeq CARG4, LJ_TTAB - | ldrbeq CARG4, TAB:CARG1->marked - | cmpeq TAB:RB, #0 - | bne ->fff_fallback - | tst CARG4, #LJ_GC_BLACK // isblack(table) - | str TAB:CARG3, TAB:CARG1->metatable - | beq ->fff_restv - | barrierback TAB:CARG1, CARG4, CARG3 - | b ->fff_restv - | - |.ffunc rawget - | ldrd CARG34, [BASE] - | cmp NARGS8:RC, #16 - | blo ->fff_fallback - | mov CARG2, CARG3 - | checktab CARG4, ->fff_fallback - | mov CARG1, L - | add CARG3, BASE, #8 - | .IOS mov RA, BASE - | bl extern lj_tab_get // (lua_State *L, GCtab *t, cTValue *key) - | // Returns cTValue *. - | .IOS mov BASE, RA - | ldrd CARG12, [CRET1] - | b ->fff_restv - | - |//-- Base library: conversions ------------------------------------------ - | - |.ffunc tonumber - | // Only handles the number case inline (without a base argument). - | ldrd CARG12, [BASE] - | cmp NARGS8:RC, #8 - | bne ->fff_fallback - | checktp CARG2, LJ_TISNUM - | bls ->fff_restv - | b ->fff_fallback - | - |.ffunc_1 tostring - | // Only handles the string or number case inline. - | checktp CARG2, LJ_TSTR - | // A __tostring method in the string base metatable is ignored. - | beq ->fff_restv - | // Handle numbers inline, unless a number base metatable is present. - | ldr CARG4, [DISPATCH, #DISPATCH_GL(gcroot[GCROOT_BASEMT_NUM])] - | str BASE, L->base - | checktp CARG2, LJ_TISNUM - | cmpls CARG4, #0 - | str PC, SAVE_PC // Redundant (but a defined value). - | bhi ->fff_fallback - | ffgccheck - | mov CARG1, L - | mov CARG2, BASE - | bl extern lj_strfmt_number // (lua_State *L, cTValue *o) - | // Returns GCstr *. - | ldr BASE, L->base - | mvn CARG2, #~LJ_TSTR - | b ->fff_restv - | - |//-- Base library: iterators ------------------------------------------- - | - |.ffunc_1 next - | mvn CARG4, #~LJ_TNIL - | checktab CARG2, ->fff_fallback - | strd CARG34, [BASE, NARGS8:RC] // Set missing 2nd arg to nil. - | ldr PC, [BASE, FRAME_PC] - | mov CARG2, CARG1 - | str BASE, L->base // Add frame since C call can throw. - | mov CARG1, L - | str BASE, L->top // Dummy frame length is ok. - | add CARG3, BASE, #8 - | str PC, SAVE_PC - | bl extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key) - | // Returns 0 at end of traversal. - | .IOS ldr BASE, L->base - | cmp CRET1, #0 - | mvneq CRET2, #~LJ_TNIL - | beq ->fff_restv // End of traversal: return nil. - | ldrd CARG12, [BASE, #8] // Copy key and value to results. - | ldrd CARG34, [BASE, #16] - | mov RC, #(2+1)*8 - | strd CARG12, [BASE, #-8] - | strd CARG34, [BASE] - | b ->fff_res - | - |.ffunc_1 pairs - | checktab CARG2, ->fff_fallback -#if LJ_52 - | ldr TAB:RB, TAB:CARG1->metatable -#endif - | ldrd CFUNC:CARG34, CFUNC:CARG3->upvalue[0] - | ldr PC, [BASE, FRAME_PC] -#if LJ_52 - | cmp TAB:RB, #0 - | bne ->fff_fallback -#endif - | mvn CARG2, #~LJ_TNIL - | mov RC, #(3+1)*8 - | strd CFUNC:CARG34, [BASE, #-8] - | str CARG2, [BASE, #12] - | b ->fff_res - | - |.ffunc_2 ipairs_aux - | checktp CARG2, LJ_TTAB - | checktpeq CARG4, LJ_TISNUM - | bne ->fff_fallback - | ldr RB, TAB:CARG1->asize - | ldr RC, TAB:CARG1->array - | add CARG3, CARG3, #1 - | ldr PC, [BASE, FRAME_PC] - | cmp CARG3, RB - | add RC, RC, CARG3, lsl #3 - | strd CARG34, [BASE, #-8] - | ldrdlo CARG12, [RC] - | mov RC, #(0+1)*8 - | bhs >2 // Not in array part? - |1: - | checktp CARG2, LJ_TNIL - | movne RC, #(2+1)*8 - | strdne CARG12, [BASE] - | b ->fff_res - |2: // Check for empty hash part first. Otherwise call C function. - | ldr RB, TAB:CARG1->hmask - | mov CARG2, CARG3 - | cmp RB, #0 - | beq ->fff_res - | .IOS mov RA, BASE - | bl extern lj_tab_getinth // (GCtab *t, int32_t key) - | // Returns cTValue * or NULL. - | .IOS mov BASE, RA - | cmp CRET1, #0 - | beq ->fff_res - | ldrd CARG12, [CRET1] - | b <1 - | - |.ffunc_1 ipairs - | checktab CARG2, ->fff_fallback -#if LJ_52 - | ldr TAB:RB, TAB:CARG1->metatable -#endif - | ldrd CFUNC:CARG34, CFUNC:CARG3->upvalue[0] - | ldr PC, [BASE, FRAME_PC] -#if LJ_52 - | cmp TAB:RB, #0 - | bne ->fff_fallback -#endif - | mov CARG1, #0 - | mvn CARG2, #~LJ_TISNUM - | mov RC, #(3+1)*8 - | strd CFUNC:CARG34, [BASE, #-8] - | strd CARG12, [BASE, #8] - | b ->fff_res - | - |//-- Base library: catch errors ---------------------------------------- - | - |.ffunc pcall - | ldrb RA, [DISPATCH, #DISPATCH_GL(hookmask)] - | cmp NARGS8:RC, #8 - | blo ->fff_fallback - | tst RA, #HOOK_ACTIVE // Remember active hook before pcall. - | mov RB, BASE - | add BASE, BASE, #8 - | moveq PC, #8+FRAME_PCALL - | movne PC, #8+FRAME_PCALLH - | sub NARGS8:RC, NARGS8:RC, #8 - | b ->vm_call_dispatch - | - |.ffunc_2 xpcall - | ldrb RA, [DISPATCH, #DISPATCH_GL(hookmask)] - | checkfunc CARG4, ->fff_fallback // Traceback must be a function. - | mov RB, BASE - | strd CARG12, [BASE, #8] // Swap function and traceback. - | strd CARG34, [BASE] - | tst RA, #HOOK_ACTIVE // Remember active hook before pcall. - | add BASE, BASE, #16 - | moveq PC, #16+FRAME_PCALL - | movne PC, #16+FRAME_PCALLH - | sub NARGS8:RC, NARGS8:RC, #16 - | b ->vm_call_dispatch - | - |//-- Coroutine library -------------------------------------------------- - | - |.macro coroutine_resume_wrap, resume - |.if resume - |.ffunc_1 coroutine_resume - | checktp CARG2, LJ_TTHREAD - | bne ->fff_fallback - |.else - |.ffunc coroutine_wrap_aux - | ldr L:CARG1, CFUNC:CARG3->upvalue[0].gcr - |.endif - | ldr PC, [BASE, FRAME_PC] - | str BASE, L->base - | ldr CARG2, L:CARG1->top - | ldrb RA, L:CARG1->status - | ldr RB, L:CARG1->base - | add CARG3, CARG2, NARGS8:RC - | add CARG4, CARG2, RA - | str PC, SAVE_PC - | cmp CARG4, RB - | beq ->fff_fallback - | ldr CARG4, L:CARG1->maxstack - | ldr RB, L:CARG1->cframe - | cmp RA, #LUA_YIELD - | cmpls CARG3, CARG4 - | cmpls RB, #0 - | bhi ->fff_fallback - |1: - |.if resume - | sub CARG3, CARG3, #8 // Keep resumed thread in stack for GC. - | add BASE, BASE, #8 - | sub NARGS8:RC, NARGS8:RC, #8 - |.endif - | str CARG3, L:CARG1->top - | str BASE, L->top - |2: // Move args to coroutine. - | ldrd CARG34, [BASE, RB] - | cmp RB, NARGS8:RC - | strdne CARG34, [CARG2, RB] - | add RB, RB, #8 - | bne <2 - | - | mov CARG3, #0 - | mov L:RA, L:CARG1 - | mov CARG4, #0 - | bl ->vm_resume // (lua_State *L, TValue *base, 0, 0) - | // Returns thread status. - |4: - | ldr CARG3, L:RA->base - | mv_vmstate CARG2, INTERP - | ldr CARG4, L:RA->top - | cmp CRET1, #LUA_YIELD - | ldr BASE, L->base - | str L, [DISPATCH, #DISPATCH_GL(cur_L)] - | st_vmstate CARG2 - | bhi >8 - | subs RC, CARG4, CARG3 - | ldr CARG1, L->maxstack - | add CARG2, BASE, RC - | beq >6 // No results? - | cmp CARG2, CARG1 - | mov RB, #0 - | bhi >9 // Need to grow stack? - | - | sub CARG4, RC, #8 - | str CARG3, L:RA->top // Clear coroutine stack. - |5: // Move results from coroutine. - | ldrd CARG12, [CARG3, RB] - | cmp RB, CARG4 - | strd CARG12, [BASE, RB] - | add RB, RB, #8 - | bne <5 - |6: - |.if resume - | mvn CARG3, #~LJ_TTRUE - | add RC, RC, #16 - |7: - | str CARG3, [BASE, #-4] // Prepend true/false to results. - | sub RA, BASE, #8 - |.else - | mov RA, BASE - | add RC, RC, #8 - |.endif - | ands CARG1, PC, #FRAME_TYPE - | str PC, SAVE_PC - | str RC, SAVE_MULTRES - | beq ->BC_RET_Z - | b ->vm_return - | - |8: // Coroutine returned with error (at co->top-1). - |.if resume - | ldrd CARG12, [CARG4, #-8]! - | mvn CARG3, #~LJ_TFALSE - | mov RC, #(2+1)*8 - | str CARG4, L:RA->top // Remove error from coroutine stack. - | strd CARG12, [BASE] // Copy error message. - | b <7 - |.else - | mov CARG1, L - | mov CARG2, L:RA - | bl extern lj_ffh_coroutine_wrap_err // (lua_State *L, lua_State *co) - | // Never returns. - |.endif - | - |9: // Handle stack expansion on return from yield. - | mov CARG1, L - | lsr CARG2, RC, #3 - | bl extern lj_state_growstack // (lua_State *L, int n) - | mov CRET1, #0 - | b <4 - |.endmacro - | - | coroutine_resume_wrap 1 // coroutine.resume - | coroutine_resume_wrap 0 // coroutine.wrap - | - |.ffunc coroutine_yield - | ldr CARG1, L->cframe - | add CARG2, BASE, NARGS8:RC - | str BASE, L->base - | tst CARG1, #CFRAME_RESUME - | str CARG2, L->top - | mov CRET1, #LUA_YIELD - | mov CARG3, #0 - | beq ->fff_fallback - | str CARG3, L->cframe - | strb CRET1, L->status - | b ->vm_leave_unw - | - |//-- Math library ------------------------------------------------------- - | - |.macro math_round, func - | .ffunc_1 math_ .. func - | checktp CARG2, LJ_TISNUM - | beq ->fff_restv - | bhi ->fff_fallback - | // Round FP value and normalize result. - | lsl CARG3, CARG2, #1 - | adds RB, CARG3, #0x00200000 - | bpl >2 // |x| < 1? - | mvn CARG4, #0x3e0 - | subs RB, CARG4, RB, asr #21 - | lsl CARG4, CARG2, #11 - | lsl CARG3, CARG1, #11 - | orr CARG4, CARG4, #0x80000000 - | rsb INS, RB, #32 - | orr CARG4, CARG4, CARG1, lsr #21 - | bls >3 // |x| >= 2^31? - | orr CARG3, CARG3, CARG4, lsl INS - | lsr CARG1, CARG4, RB - |.if "func" == "floor" - | tst CARG3, CARG2, asr #31 - | addne CARG1, CARG1, #1 - |.else - | bics CARG3, CARG3, CARG2, asr #31 - | addsne CARG1, CARG1, #1 - | ldrdvs CARG12, >9 - | bvs ->fff_restv - |.endif - | cmp CARG2, #0 - | rsblt CARG1, CARG1, #0 - |1: - | mvn CARG2, #~LJ_TISNUM - | b ->fff_restv - | - |2: // |x| < 1 - | bcs ->fff_restv // |x| is not finite. - | orr CARG3, CARG3, CARG1 // ztest = abs(hi) | lo - |.if "func" == "floor" - | tst CARG3, CARG2, asr #31 // return (ztest & sign) == 0 ? 0 : -1 - | moveq CARG1, #0 - | mvnne CARG1, #0 - |.else - | bics CARG3, CARG3, CARG2, asr #31 // return (ztest & ~sign) == 0 ? 0 : 1 - | moveq CARG1, #0 - | movne CARG1, #1 - |.endif - | mvn CARG2, #~LJ_TISNUM - | b ->fff_restv - | - |3: // |x| >= 2^31. Check for x == -(2^31). - | cmpeq CARG4, #0x80000000 - |.if "func" == "floor" - | cmpeq CARG3, #0 - |.endif - | bne >4 - | cmp CARG2, #0 - | movmi CARG1, #0x80000000 - | bmi <1 - |4: - | bl ->vm_..func.._sf - | b ->fff_restv - |.endmacro - | - | math_round floor - | math_round ceil - | - |.align 8 - |9: - | .long 0x00000000, 0x41e00000 // 2^31. - | - |.ffunc_1 math_abs - | checktp CARG2, LJ_TISNUM - | bhi ->fff_fallback - | bicne CARG2, CARG2, #0x80000000 - | bne ->fff_restv - | cmp CARG1, #0 - | rsbslt CARG1, CARG1, #0 - | ldrdvs CARG12, <9 - | // Fallthrough. - | - |->fff_restv: - | // CARG12 = TValue result. - | ldr PC, [BASE, FRAME_PC] - | strd CARG12, [BASE, #-8] - |->fff_res1: - | // PC = return. - | mov RC, #(1+1)*8 - |->fff_res: - | // RC = (nresults+1)*8, PC = return. - | ands CARG1, PC, #FRAME_TYPE - | ldreq INS, [PC, #-4] - | str RC, SAVE_MULTRES - | sub RA, BASE, #8 - | bne ->vm_return - | decode_RB8 RB, INS - |5: - | cmp RB, RC // More results expected? - | bhi >6 - | decode_RA8 CARG1, INS - | ins_next1 - | ins_next2 - | // Adjust BASE. KBASE is assumed to be set for the calling frame. - | sub BASE, RA, CARG1 - | ins_next3 - | - |6: // Fill up results with nil. - | add CARG2, RA, RC - | mvn CARG1, #~LJ_TNIL - | add RC, RC, #8 - | str CARG1, [CARG2, #-4] - | b <5 - | - |.macro math_extern, func - |.if HFABI - | .ffunc_d math_ .. func - |.else - | .ffunc_n math_ .. func - |.endif - | .IOS mov RA, BASE - | bl extern func - | .IOS mov BASE, RA - |.if HFABI - | b ->fff_resd - |.else - | b ->fff_restv - |.endif - |.endmacro - | - |.macro math_extern2, func - |.if HFABI - | .ffunc_dd math_ .. func - |.else - | .ffunc_nn math_ .. func - |.endif - | .IOS mov RA, BASE - | bl extern func - | .IOS mov BASE, RA - |.if HFABI - | b ->fff_resd - |.else - | b ->fff_restv - |.endif - |.endmacro - | - |.if FPU - | .ffunc_d math_sqrt - | vsqrt.f64 d0, d0 - |->fff_resd: - | ldr PC, [BASE, FRAME_PC] - | vstr d0, [BASE, #-8] - | b ->fff_res1 - |.else - | math_extern sqrt - |.endif - | - |.ffunc math_log - |.if HFABI - | ldr CARG2, [BASE, #4] - | cmp NARGS8:RC, #8 // Need exactly 1 argument. - | vldr d0, [BASE] - | bne ->fff_fallback - |.else - | ldrd CARG12, [BASE] - | cmp NARGS8:RC, #8 // Need exactly 1 argument. - | bne ->fff_fallback - |.endif - | checktp CARG2, LJ_TISNUM - | bhs ->fff_fallback - | .IOS mov RA, BASE - | bl extern log - | .IOS mov BASE, RA - |.if HFABI - | b ->fff_resd - |.else - | b ->fff_restv - |.endif - | - | math_extern log10 - | math_extern exp - | math_extern sin - | math_extern cos - | math_extern tan - | math_extern asin - | math_extern acos - | math_extern atan - | math_extern sinh - | math_extern cosh - | math_extern tanh - | math_extern2 pow - | math_extern2 atan2 - | math_extern2 fmod - | - |.if HFABI - | .ffunc math_ldexp - | ldr CARG4, [BASE, #4] - | ldrd CARG12, [BASE, #8] - | cmp NARGS8:RC, #16 - | blo ->fff_fallback - | vldr d0, [BASE] - | checktp CARG4, LJ_TISNUM - | bhs ->fff_fallback - | checktp CARG2, LJ_TISNUM - | bne ->fff_fallback - | .IOS mov RA, BASE - | bl extern ldexp // (double x, int exp) - | .IOS mov BASE, RA - | b ->fff_resd - |.else - |.ffunc_2 math_ldexp - | checktp CARG2, LJ_TISNUM - | bhs ->fff_fallback - | checktp CARG4, LJ_TISNUM - | bne ->fff_fallback - | .IOS mov RA, BASE - | bl extern ldexp // (double x, int exp) - | .IOS mov BASE, RA - | b ->fff_restv - |.endif - | - |.if HFABI - |.ffunc_d math_frexp - | mov CARG1, sp - | .IOS mov RA, BASE - | bl extern frexp - | .IOS mov BASE, RA - | ldr CARG3, [sp] - | mvn CARG4, #~LJ_TISNUM - | ldr PC, [BASE, FRAME_PC] - | vstr d0, [BASE, #-8] - | mov RC, #(2+1)*8 - | strd CARG34, [BASE] - | b ->fff_res - |.else - |.ffunc_n math_frexp - | mov CARG3, sp - | .IOS mov RA, BASE - | bl extern frexp - | .IOS mov BASE, RA - | ldr CARG3, [sp] - | mvn CARG4, #~LJ_TISNUM - | ldr PC, [BASE, FRAME_PC] - | strd CARG12, [BASE, #-8] - | mov RC, #(2+1)*8 - | strd CARG34, [BASE] - | b ->fff_res - |.endif - | - |.if HFABI - |.ffunc_d math_modf - | sub CARG1, BASE, #8 - | ldr PC, [BASE, FRAME_PC] - | .IOS mov RA, BASE - | bl extern modf - | .IOS mov BASE, RA - | mov RC, #(2+1)*8 - | vstr d0, [BASE] - | b ->fff_res - |.else - |.ffunc_n math_modf - | sub CARG3, BASE, #8 - | ldr PC, [BASE, FRAME_PC] - | .IOS mov RA, BASE - | bl extern modf - | .IOS mov BASE, RA - | mov RC, #(2+1)*8 - | strd CARG12, [BASE] - | b ->fff_res - |.endif - | - |.macro math_minmax, name, cond, fcond - |.if FPU - | .ffunc_1 name - | add RB, BASE, RC - | checktp CARG2, LJ_TISNUM - | add RA, BASE, #8 - | bne >4 - |1: // Handle integers. - | ldrd CARG34, [RA] - | cmp RA, RB - | bhs ->fff_restv - | checktp CARG4, LJ_TISNUM - | bne >3 - | cmp CARG1, CARG3 - | add RA, RA, #8 - | mov..cond CARG1, CARG3 - | b <1 - |3: // Convert intermediate result to number and continue below. - | vmov s4, CARG1 - | bhi ->fff_fallback - | vldr d1, [RA] - | vcvt.f64.s32 d0, s4 - | b >6 - | - |4: - | vldr d0, [BASE] - | bhi ->fff_fallback - |5: // Handle numbers. - | ldrd CARG34, [RA] - | vldr d1, [RA] - | cmp RA, RB - | bhs ->fff_resd - | checktp CARG4, LJ_TISNUM - | bhs >7 - |6: - | vcmp.f64 d0, d1 - | vmrs - | add RA, RA, #8 - | vmov..fcond.f64 d0, d1 - | b <5 - |7: // Convert integer to number and continue above. - | vmov s4, CARG3 - | bhi ->fff_fallback - | vcvt.f64.s32 d1, s4 - | b <6 - | - |.else - | - | .ffunc_1 name - | checktp CARG2, LJ_TISNUM - | mov RA, #8 - | bne >4 - |1: // Handle integers. - | ldrd CARG34, [BASE, RA] - | cmp RA, RC - | bhs ->fff_restv - | checktp CARG4, LJ_TISNUM - | bne >3 - | cmp CARG1, CARG3 - | add RA, RA, #8 - | mov..cond CARG1, CARG3 - | b <1 - |3: // Convert intermediate result to number and continue below. - | bhi ->fff_fallback - | bl extern __aeabi_i2d - | ldrd CARG34, [BASE, RA] - | b >6 - | - |4: - | bhi ->fff_fallback - |5: // Handle numbers. - | ldrd CARG34, [BASE, RA] - | cmp RA, RC - | bhs ->fff_restv - | checktp CARG4, LJ_TISNUM - | bhs >7 - |6: - | bl extern __aeabi_cdcmple - | add RA, RA, #8 - | mov..fcond CARG1, CARG3 - | mov..fcond CARG2, CARG4 - | b <5 - |7: // Convert integer to number and continue above. - | bhi ->fff_fallback - | strd CARG12, TMPD - | mov CARG1, CARG3 - | bl extern __aeabi_i2d - | ldrd CARG34, TMPD - | b <6 - |.endif - |.endmacro - | - | math_minmax math_min, gt, hi - | math_minmax math_max, lt, lo - | - |//-- String library ----------------------------------------------------- - | - |.ffunc string_byte // Only handle the 1-arg case here. - | ldrd CARG12, [BASE] - | ldr PC, [BASE, FRAME_PC] - | cmp NARGS8:RC, #8 - | checktpeq CARG2, LJ_TSTR // Need exactly 1 argument. - | bne ->fff_fallback - | ldr CARG3, STR:CARG1->len - | ldrb CARG1, STR:CARG1[1] // Access is always ok (NUL at end). - | mvn CARG2, #~LJ_TISNUM - | cmp CARG3, #0 - | moveq RC, #(0+1)*8 - | movne RC, #(1+1)*8 - | strd CARG12, [BASE, #-8] - | b ->fff_res - | - |.ffunc string_char // Only handle the 1-arg case here. - | ffgccheck - | ldrd CARG12, [BASE] - | ldr PC, [BASE, FRAME_PC] - | cmp NARGS8:RC, #8 // Need exactly 1 argument. - | checktpeq CARG2, LJ_TISNUM - | bicseq CARG4, CARG1, #255 - | mov CARG3, #1 - | bne ->fff_fallback - | str CARG1, TMPD - | mov CARG2, TMPDp // Points to stack. Little-endian. - |->fff_newstr: - | // CARG2 = str, CARG3 = len. - | str BASE, L->base - | mov CARG1, L - | str PC, SAVE_PC - | bl extern lj_str_new // (lua_State *L, char *str, size_t l) - |->fff_resstr: - | // Returns GCstr *. - | ldr BASE, L->base - | mvn CARG2, #~LJ_TSTR - | b ->fff_restv - | - |.ffunc string_sub - | ffgccheck - | ldrd CARG12, [BASE] - | ldrd CARG34, [BASE, #16] - | cmp NARGS8:RC, #16 - | mvn RB, #0 - | beq >1 - | blo ->fff_fallback - | checktp CARG4, LJ_TISNUM - | mov RB, CARG3 - | bne ->fff_fallback - |1: - | ldrd CARG34, [BASE, #8] - | checktp CARG2, LJ_TSTR - | ldreq CARG2, STR:CARG1->len - | checktpeq CARG4, LJ_TISNUM - | bne ->fff_fallback - | // CARG1 = str, CARG2 = str->len, CARG3 = start, RB = end - | add CARG4, CARG2, #1 - | cmp CARG3, #0 // if (start < 0) start += len+1 - | addlt CARG3, CARG3, CARG4 - | cmp CARG3, #1 // if (start < 1) start = 1 - | movlt CARG3, #1 - | cmp RB, #0 // if (end < 0) end += len+1 - | addlt RB, RB, CARG4 - | bic RB, RB, RB, asr #31 // if (end < 0) end = 0 - | cmp RB, CARG2 // if (end > len) end = len - | add CARG1, STR:CARG1, #sizeof(GCstr)-1 - | movgt RB, CARG2 - | add CARG2, CARG1, CARG3 - | subs CARG3, RB, CARG3 // len = end - start - | add CARG3, CARG3, #1 // len += 1 - | bge ->fff_newstr - |->fff_emptystr: - | sub STR:CARG1, DISPATCH, #-DISPATCH_GL(strempty) - | mvn CARG2, #~LJ_TSTR - | b ->fff_restv - | - |.macro ffstring_op, name - | .ffunc string_ .. name - | ffgccheck - | ldr CARG3, [BASE, #4] - | cmp NARGS8:RC, #8 - | ldr STR:CARG2, [BASE] - | blo ->fff_fallback - | sub SBUF:CARG1, DISPATCH, #-DISPATCH_GL(tmpbuf) - | checkstr CARG3, ->fff_fallback - | ldr CARG4, SBUF:CARG1->b - | str BASE, L->base - | str PC, SAVE_PC - | str L, SBUF:CARG1->L - | str CARG4, SBUF:CARG1->p - | bl extern lj_buf_putstr_ .. name - | bl extern lj_buf_tostr - | b ->fff_resstr - |.endmacro - | - |ffstring_op reverse - |ffstring_op lower - |ffstring_op upper - | - |//-- Bit library -------------------------------------------------------- - | - |// FP number to bit conversion for soft-float. Clobbers r0-r3. - |->vm_tobit_fb: - | bhi ->fff_fallback - |->vm_tobit: - | lsl RB, CARG2, #1 - | adds RB, RB, #0x00200000 - | movpl CARG1, #0 // |x| < 1? - | bxpl lr - | mvn CARG4, #0x3e0 - | subs RB, CARG4, RB, asr #21 - | bmi >1 // |x| >= 2^32? - | lsl CARG4, CARG2, #11 - | orr CARG4, CARG4, #0x80000000 - | orr CARG4, CARG4, CARG1, lsr #21 - | cmp CARG2, #0 - | lsr CARG1, CARG4, RB - | rsblt CARG1, CARG1, #0 - | bx lr - |1: - | add RB, RB, #21 - | lsr CARG4, CARG1, RB - | rsb RB, RB, #20 - | lsl CARG1, CARG2, #12 - | cmp CARG2, #0 - | orr CARG1, CARG4, CARG1, lsl RB - | rsblt CARG1, CARG1, #0 - | bx lr - | - |.macro .ffunc_bit, name - | .ffunc_1 bit_..name - | checktp CARG2, LJ_TISNUM - | blne ->vm_tobit_fb - |.endmacro - | - |.ffunc_bit tobit - | mvn CARG2, #~LJ_TISNUM - | b ->fff_restv - | - |.macro .ffunc_bit_op, name, ins - | .ffunc_bit name - | mov CARG3, CARG1 - | mov RA, #8 - |1: - | ldrd CARG12, [BASE, RA] - | cmp RA, NARGS8:RC - | add RA, RA, #8 - | bge >2 - | checktp CARG2, LJ_TISNUM - | blne ->vm_tobit_fb - | ins CARG3, CARG3, CARG1 - | b <1 - |.endmacro - | - |.ffunc_bit_op band, and - |.ffunc_bit_op bor, orr - |.ffunc_bit_op bxor, eor - | - |2: - | mvn CARG4, #~LJ_TISNUM - | ldr PC, [BASE, FRAME_PC] - | strd CARG34, [BASE, #-8] - | b ->fff_res1 - | - |.ffunc_bit bswap - | eor CARG3, CARG1, CARG1, ror #16 - | bic CARG3, CARG3, #0x00ff0000 - | ror CARG1, CARG1, #8 - | mvn CARG2, #~LJ_TISNUM - | eor CARG1, CARG1, CARG3, lsr #8 - | b ->fff_restv - | - |.ffunc_bit bnot - | mvn CARG1, CARG1 - | mvn CARG2, #~LJ_TISNUM - | b ->fff_restv - | - |.macro .ffunc_bit_sh, name, ins, shmod - | .ffunc bit_..name - | ldrd CARG12, [BASE, #8] - | cmp NARGS8:RC, #16 - | blo ->fff_fallback - | checktp CARG2, LJ_TISNUM - | blne ->vm_tobit_fb - |.if shmod == 0 - | and RA, CARG1, #31 - |.else - | rsb RA, CARG1, #0 - |.endif - | ldrd CARG12, [BASE] - | checktp CARG2, LJ_TISNUM - | blne ->vm_tobit_fb - | ins CARG1, CARG1, RA - | mvn CARG2, #~LJ_TISNUM - | b ->fff_restv - |.endmacro - | - |.ffunc_bit_sh lshift, lsl, 0 - |.ffunc_bit_sh rshift, lsr, 0 - |.ffunc_bit_sh arshift, asr, 0 - |.ffunc_bit_sh rol, ror, 1 - |.ffunc_bit_sh ror, ror, 0 - | - |//----------------------------------------------------------------------- - | - |->fff_fallback: // Call fast function fallback handler. - | // BASE = new base, RC = nargs*8 - | ldr CARG3, [BASE, FRAME_FUNC] - | ldr CARG2, L->maxstack - | add CARG1, BASE, NARGS8:RC - | ldr PC, [BASE, FRAME_PC] // Fallback may overwrite PC. - | str CARG1, L->top - | ldr CARG3, CFUNC:CARG3->f - | str BASE, L->base - | add CARG1, CARG1, #8*LUA_MINSTACK - | str PC, SAVE_PC // Redundant (but a defined value). - | cmp CARG1, CARG2 - | mov CARG1, L - | bhi >5 // Need to grow stack. - | blx CARG3 // (lua_State *L) - | // Either throws an error, or recovers and returns -1, 0 or nresults+1. - | ldr BASE, L->base - | cmp CRET1, #0 - | lsl RC, CRET1, #3 - | sub RA, BASE, #8 - | bgt ->fff_res // Returned nresults+1? - |1: // Returned 0 or -1: retry fast path. - | ldr CARG1, L->top - | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] - | sub NARGS8:RC, CARG1, BASE - | bne ->vm_call_tail // Returned -1? - | ins_callt // Returned 0: retry fast path. - | - |// Reconstruct previous base for vmeta_call during tailcall. - |->vm_call_tail: - | ands CARG1, PC, #FRAME_TYPE - | bic CARG2, PC, #FRAME_TYPEP - | ldreq INS, [PC, #-4] - | andeq CARG2, MASKR8, INS, lsr #5 // Conditional decode_RA8. - | addeq CARG2, CARG2, #8 - | sub RB, BASE, CARG2 - | b ->vm_call_dispatch // Resolve again for tailcall. - | - |5: // Grow stack for fallback handler. - | mov CARG2, #LUA_MINSTACK - | bl extern lj_state_growstack // (lua_State *L, int n) - | ldr BASE, L->base - | cmp CARG1, CARG1 // Set zero-flag to force retry. - | b <1 - | - |->fff_gcstep: // Call GC step function. - | // BASE = new base, RC = nargs*8 - | mov RA, lr - | str BASE, L->base - | add CARG2, BASE, NARGS8:RC - | str PC, SAVE_PC // Redundant (but a defined value). - | str CARG2, L->top - | mov CARG1, L - | bl extern lj_gc_step // (lua_State *L) - | ldr BASE, L->base - | mov lr, RA // Help return address predictor. - | ldr CFUNC:CARG3, [BASE, FRAME_FUNC] - | bx lr - | - |//----------------------------------------------------------------------- - |//-- Special dispatch targets ------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_record: // Dispatch target for recording phase. - |.if JIT - | ldrb CARG1, [DISPATCH, #DISPATCH_GL(hookmask)] - | tst CARG1, #HOOK_VMEVENT // No recording while in vmevent. - | bne >5 - | // Decrement the hookcount for consistency, but always do the call. - | ldr CARG2, [DISPATCH, #DISPATCH_GL(hookcount)] - | tst CARG1, #HOOK_ACTIVE - | bne >1 - | sub CARG2, CARG2, #1 - | tst CARG1, #LUA_MASKLINE|LUA_MASKCOUNT - | strne CARG2, [DISPATCH, #DISPATCH_GL(hookcount)] - | b >1 - |.endif - | - |->vm_rethook: // Dispatch target for return hooks. - | ldrb CARG1, [DISPATCH, #DISPATCH_GL(hookmask)] - | tst CARG1, #HOOK_ACTIVE // Hook already active? - | beq >1 - |5: // Re-dispatch to static ins. - | decode_OP OP, INS - | add OP, DISPATCH, OP, lsl #2 - | ldr pc, [OP, #GG_DISP2STATIC] - | - |->vm_inshook: // Dispatch target for instr/line hooks. - | ldrb CARG1, [DISPATCH, #DISPATCH_GL(hookmask)] - | ldr CARG2, [DISPATCH, #DISPATCH_GL(hookcount)] - | tst CARG1, #HOOK_ACTIVE // Hook already active? - | bne <5 - | tst CARG1, #LUA_MASKLINE|LUA_MASKCOUNT - | beq <5 - | subs CARG2, CARG2, #1 - | str CARG2, [DISPATCH, #DISPATCH_GL(hookcount)] - | beq >1 - | tst CARG1, #LUA_MASKLINE - | beq <5 - |1: - | mov CARG1, L - | str BASE, L->base - | mov CARG2, PC - | // SAVE_PC must hold the _previous_ PC. The callee updates it with PC. - | bl extern lj_dispatch_ins // (lua_State *L, const BCIns *pc) - |3: - | ldr BASE, L->base - |4: // Re-dispatch to static ins. - | ldrb OP, [PC, #-4] - | ldr INS, [PC, #-4] - | add OP, DISPATCH, OP, lsl #2 - | ldr OP, [OP, #GG_DISP2STATIC] - | decode_RA8 RA, INS - | decode_RD RC, INS - | bx OP - | - |->cont_hook: // Continue from hook yield. - | ldr CARG1, [CARG4, #-24] - | add PC, PC, #4 - | str CARG1, SAVE_MULTRES // Restore MULTRES for *M ins. - | b <4 - | - |->vm_hotloop: // Hot loop counter underflow. - |.if JIT - | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] // Same as curr_topL(L). - | sub CARG1, DISPATCH, #-GG_DISP2J - | str PC, SAVE_PC - | ldr CARG3, LFUNC:CARG3->field_pc - | mov CARG2, PC - | str L, [DISPATCH, #DISPATCH_J(L)] - | ldrb CARG3, [CARG3, #PC2PROTO(framesize)] - | str BASE, L->base - | add CARG3, BASE, CARG3, lsl #3 - | str CARG3, L->top - | bl extern lj_trace_hot // (jit_State *J, const BCIns *pc) - | b <3 - |.endif - | - |->vm_callhook: // Dispatch target for call hooks. - | mov CARG2, PC - |.if JIT - | b >1 - |.endif - | - |->vm_hotcall: // Hot call counter underflow. - |.if JIT - | orr CARG2, PC, #1 - |1: - |.endif - | add CARG4, BASE, RC - | str PC, SAVE_PC - | mov CARG1, L - | str BASE, L->base - | sub RA, RA, BASE - | str CARG4, L->top - | bl extern lj_dispatch_call // (lua_State *L, const BCIns *pc) - | // Returns ASMFunction. - | ldr BASE, L->base - | ldr CARG4, L->top - | mov CARG2, #0 - | add RA, BASE, RA - | sub NARGS8:RC, CARG4, BASE - | str CARG2, SAVE_PC // Invalidate for subsequent line hook. - | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] - | ldr INS, [PC, #-4] - | bx CRET1 - | - |->cont_stitch: // Trace stitching. - |.if JIT - | // RA = resultptr, CARG4 = meta base - | ldr RB, SAVE_MULTRES - | ldr INS, [PC, #-4] - | ldr TRACE:CARG3, [CARG4, #-24] // Save previous trace. - | subs RB, RB, #8 - | decode_RA8 RC, INS // Call base. - | beq >2 - |1: // Move results down. - | ldrd CARG12, [RA] - | add RA, RA, #8 - | subs RB, RB, #8 - | strd CARG12, [BASE, RC] - | add RC, RC, #8 - | bne <1 - |2: - | decode_RA8 RA, INS - | decode_RB8 RB, INS - | add RA, RA, RB - |3: - | cmp RA, RC - | mvn CARG2, #~LJ_TNIL - | bhi >9 // More results wanted? - | - | ldrh RA, TRACE:CARG3->traceno - | ldrh RC, TRACE:CARG3->link - | cmp RC, RA - | beq ->cont_nop // Blacklisted. - | cmp RC, #0 - | bne =>BC_JLOOP // Jump to stitched trace. - | - | // Stitch a new trace to the previous trace. - | str RA, [DISPATCH, #DISPATCH_J(exitno)] - | str L, [DISPATCH, #DISPATCH_J(L)] - | str BASE, L->base - | sub CARG1, DISPATCH, #-GG_DISP2J - | mov CARG2, PC - | bl extern lj_dispatch_stitch // (jit_State *J, const BCIns *pc) - | ldr BASE, L->base - | b ->cont_nop - | - |9: // Fill up results with nil. - | strd CARG12, [BASE, RC] - | add RC, RC, #8 - | b <3 - |.endif - | - |->vm_profhook: // Dispatch target for profiler hook. -#if LJ_HASPROFILE - | mov CARG1, L - | str BASE, L->base - | mov CARG2, PC - | bl extern lj_dispatch_profile // (lua_State *L, const BCIns *pc) - | // HOOK_PROFILE is off again, so re-dispatch to dynamic instruction. - | ldr BASE, L->base - | sub PC, PC, #4 - | b ->cont_nop -#endif - | - |//----------------------------------------------------------------------- - |//-- Trace exit handler ------------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_exit_handler: - |.if JIT - | sub sp, sp, #12 - | push {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12} - | ldr CARG1, [sp, #64] // Load original value of lr. - | ldr DISPATCH, [lr] // Load DISPATCH. - | add CARG3, sp, #64 // Recompute original value of sp. - | mv_vmstate CARG4, EXIT - | str CARG3, [sp, #52] // Store sp in RID_SP - | st_vmstate CARG4 - | ldr CARG2, [CARG1, #-4]! // Get exit instruction. - | str CARG1, [sp, #56] // Store exit pc in RID_LR and RID_PC. - | str CARG1, [sp, #60] - |.if FPU - | vpush {d0-d15} - |.endif - | lsl CARG2, CARG2, #8 - | add CARG1, CARG1, CARG2, asr #6 - | ldr CARG2, [lr, #4] // Load exit stub group offset. - | sub CARG1, CARG1, lr - | ldr L, [DISPATCH, #DISPATCH_GL(cur_L)] - | add CARG1, CARG2, CARG1, lsr #2 // Compute exit number. - | ldr BASE, [DISPATCH, #DISPATCH_GL(jit_base)] - | str CARG1, [DISPATCH, #DISPATCH_J(exitno)] - | mov CARG4, #0 - | str BASE, L->base - | str L, [DISPATCH, #DISPATCH_J(L)] - | str CARG4, [DISPATCH, #DISPATCH_GL(jit_base)] - | sub CARG1, DISPATCH, #-GG_DISP2J - | mov CARG2, sp - | bl extern lj_trace_exit // (jit_State *J, ExitState *ex) - | // Returns MULTRES (unscaled) or negated error code. - | ldr CARG2, L->cframe - | ldr BASE, L->base - | bic CARG2, CARG2, #~CFRAME_RAWMASK // Use two steps: bic sp is deprecated. - | mov sp, CARG2 - | ldr PC, SAVE_PC // Get SAVE_PC. - | str L, SAVE_L // Set SAVE_L (on-trace resume/yield). - | b >1 - |.endif - |->vm_exit_interp: - | // CARG1 = MULTRES or negated error code, BASE, PC and DISPATCH set. - |.if JIT - | ldr L, SAVE_L - |1: - | cmp CARG1, #0 - | blt >9 // Check for error from exit. - | lsl RC, CARG1, #3 - | ldr LFUNC:CARG2, [BASE, FRAME_FUNC] - | str RC, SAVE_MULTRES - | mov CARG3, #0 - | str BASE, L->base - | ldr CARG2, LFUNC:CARG2->field_pc - | str CARG3, [DISPATCH, #DISPATCH_GL(jit_base)] - | mv_vmstate CARG4, INTERP - | ldr KBASE, [CARG2, #PC2PROTO(k)] - | // Modified copy of ins_next which handles function header dispatch, too. - | ldrb OP, [PC] - | mov MASKR8, #255 - | ldr INS, [PC], #4 - | lsl MASKR8, MASKR8, #3 // MASKR8 = 255*8. - | st_vmstate CARG4 - | cmp OP, #BC_FUNCC+2 // Fast function? - | bhs >4 - |2: - | cmp OP, #BC_FUNCF // Function header? - | ldr OP, [DISPATCH, OP, lsl #2] - | decode_RA8 RA, INS - | lsrlo RC, INS, #16 // No: Decode operands A*8 and D. - | subhs RC, RC, #8 - | addhs RA, RA, BASE // Yes: RA = BASE+framesize*8, RC = nargs*8 - | ldrhs CARG3, [BASE, FRAME_FUNC] - | bx OP - | - |4: // Check frame below fast function. - | ldr CARG1, [BASE, FRAME_PC] - | ands CARG2, CARG1, #FRAME_TYPE - | bne <2 // Trace stitching continuation? - | // Otherwise set KBASE for Lua function below fast function. - | ldr CARG3, [CARG1, #-4] - | decode_RA8 CARG1, CARG3 - | sub CARG2, BASE, CARG1 - | ldr LFUNC:CARG3, [CARG2, #-16] - | ldr CARG3, LFUNC:CARG3->field_pc - | ldr KBASE, [CARG3, #PC2PROTO(k)] - | b <2 - | - |9: // Rethrow error from the right C frame. - | rsb CARG2, CARG1, #0 - | mov CARG1, L - | bl extern lj_err_throw // (lua_State *L, int errcode) - |.endif - | - |//----------------------------------------------------------------------- - |//-- Math helper functions ---------------------------------------------- - |//----------------------------------------------------------------------- - | - |// FP value rounding. Called from JIT code. - |// - |// double lj_vm_floor/ceil/trunc(double x); - |.macro vm_round, func, hf - |.if hf == 1 - | vmov CARG1, CARG2, d0 - |.endif - | lsl CARG3, CARG2, #1 - | adds RB, CARG3, #0x00200000 - | bpl >2 // |x| < 1? - | mvn CARG4, #0x3cc - | subs RB, CARG4, RB, asr #21 // 2^0: RB = 51, 2^51: RB = 0. - | bxlo lr // |x| >= 2^52: done. - | mvn CARG4, #1 - | bic CARG3, CARG1, CARG4, lsl RB // ztest = lo & ~lomask - | and CARG1, CARG1, CARG4, lsl RB // lo &= lomask - | subs RB, RB, #32 - | bicpl CARG4, CARG2, CARG4, lsl RB // |x| <= 2^20: ztest |= hi & ~himask - | orrpl CARG3, CARG3, CARG4 - | mvnpl CARG4, #1 - | andpl CARG2, CARG2, CARG4, lsl RB // |x| <= 2^20: hi &= himask - |.if "func" == "floor" - | tst CARG3, CARG2, asr #31 // iszero = ((ztest & signmask) == 0) - |.else - | bics CARG3, CARG3, CARG2, asr #31 // iszero = ((ztest & ~signmask) == 0) - |.endif - |.if hf == 1 - | vmoveq d0, CARG1, CARG2 - |.endif - | bxeq lr // iszero: done. - | mvn CARG4, #1 - | cmp RB, #0 - | lslpl CARG3, CARG4, RB - | mvnmi CARG3, #0 - | add RB, RB, #32 - | subs CARG1, CARG1, CARG4, lsl RB // lo = lo-lomask - | sbc CARG2, CARG2, CARG3 // hi = hi-himask+carry - |.if hf == 1 - | vmov d0, CARG1, CARG2 - |.endif - | bx lr - | - |2: // |x| < 1: - | bxcs lr // |x| is not finite. - | orr CARG3, CARG3, CARG1 // ztest = (2*hi) | lo - |.if "func" == "floor" - | tst CARG3, CARG2, asr #31 // iszero = ((ztest & signmask) == 0) - |.else - | bics CARG3, CARG3, CARG2, asr #31 // iszero = ((ztest & ~signmask) == 0) - |.endif - | mov CARG1, #0 // lo = 0 - | and CARG2, CARG2, #0x80000000 - | ldrne CARG4, <9 // hi = sign(x) | (iszero ? 0.0 : 1.0) - | orrne CARG2, CARG2, CARG4 - |.if hf == 1 - | vmov d0, CARG1, CARG2 - |.endif - | bx lr - |.endmacro - | - |9: - | .long 0x3ff00000 // hiword(+1.0) - | - |->vm_floor: - |.if HFABI - | vm_round floor, 1 - |.endif - |->vm_floor_sf: - | vm_round floor, 0 - | - |->vm_ceil: - |.if HFABI - | vm_round ceil, 1 - |.endif - |->vm_ceil_sf: - | vm_round ceil, 0 - | - |.macro vm_trunc, hf - |.if JIT - |.if hf == 1 - | vmov CARG1, CARG2, d0 - |.endif - | lsl CARG3, CARG2, #1 - | adds RB, CARG3, #0x00200000 - | andpl CARG2, CARG2, #0x80000000 // |x| < 1? hi = sign(x), lo = 0. - | movpl CARG1, #0 - |.if hf == 1 - | vmovpl d0, CARG1, CARG2 - |.endif - | bxpl lr - | mvn CARG4, #0x3cc - | subs RB, CARG4, RB, asr #21 // 2^0: RB = 51, 2^51: RB = 0. - | bxlo lr // |x| >= 2^52: already done. - | mvn CARG4, #1 - | and CARG1, CARG1, CARG4, lsl RB // lo &= lomask - | subs RB, RB, #32 - | andpl CARG2, CARG2, CARG4, lsl RB // |x| <= 2^20: hi &= himask - |.if hf == 1 - | vmov d0, CARG1, CARG2 - |.endif - | bx lr - |.endif - |.endmacro - | - |->vm_trunc: - |.if HFABI - | vm_trunc 1 - |.endif - |->vm_trunc_sf: - | vm_trunc 0 - | - | // double lj_vm_mod(double dividend, double divisor); - |->vm_mod: - |.if FPU - | // Special calling convention. Also, RC (r11) is not preserved. - | vdiv.f64 d0, d6, d7 - | mov RC, lr - | vmov CARG1, CARG2, d0 - | bl ->vm_floor_sf - | vmov d0, CARG1, CARG2 - | vmul.f64 d0, d0, d7 - | mov lr, RC - | vsub.f64 d6, d6, d0 - | bx lr - |.else - | push {r0, r1, r2, r3, r4, lr} - | bl extern __aeabi_ddiv - | bl ->vm_floor_sf - | ldrd CARG34, [sp, #8] - | bl extern __aeabi_dmul - | ldrd CARG34, [sp] - | eor CARG2, CARG2, #0x80000000 - | bl extern __aeabi_dadd - | add sp, sp, #20 - | pop {pc} - |.endif - | - | // int lj_vm_modi(int dividend, int divisor); - |->vm_modi: - | ands RB, CARG1, #0x80000000 - | rsbmi CARG1, CARG1, #0 // a = |dividend| - | eor RB, RB, CARG2, asr #1 // Keep signdiff and sign(divisor). - | cmp CARG2, #0 - | rsbmi CARG2, CARG2, #0 // b = |divisor| - | subs CARG4, CARG2, #1 - | cmpne CARG1, CARG2 - | moveq CARG1, #0 // if (b == 1 || a == b) a = 0 - | tsthi CARG2, CARG4 - | andeq CARG1, CARG1, CARG4 // else if ((b & (b-1)) == 0) a &= b-1 - | bls >1 - | // Use repeated subtraction to get the remainder. - | clz CARG3, CARG1 - | clz CARG4, CARG2 - | sub CARG4, CARG4, CARG3 - | rsbs CARG3, CARG4, #31 // entry = (31-(clz(b)-clz(a)))*8 - | addne pc, pc, CARG3, lsl #3 // Duff's device. - | nop - { - int i; - for (i = 31; i >= 0; i--) { - | cmp CARG1, CARG2, lsl #i - | subhs CARG1, CARG1, CARG2, lsl #i - } - } - |1: - | cmp CARG1, #0 - | cmpne RB, #0 - | submi CARG1, CARG1, CARG2 // if (y != 0 && signdiff) y = y - b - | eors CARG2, CARG1, RB, lsl #1 - | rsbmi CARG1, CARG1, #0 // if (sign(divisor) != sign(y)) y = -y - | bx lr - | - |//----------------------------------------------------------------------- - |//-- Miscellaneous functions -------------------------------------------- - |//----------------------------------------------------------------------- - | - |//----------------------------------------------------------------------- - |//-- FFI helper functions ----------------------------------------------- - |//----------------------------------------------------------------------- - | - |// Handler for callback functions. - |// Saveregs already performed. Callback slot number in [sp], g in r12. - |->vm_ffi_callback: - |.if FFI - |.type CTSTATE, CTState, PC - | ldr CTSTATE, GL:r12->ctype_state - | add DISPATCH, r12, #GG_G2DISP - |.if FPU - | str r4, SAVE_R4 - | add r4, sp, CFRAME_SPACE+4+8*8 - | vstmdb r4!, {d8-d15} - |.endif - |.if HFABI - | add r12, CTSTATE, #offsetof(CTState, cb.fpr[8]) - |.endif - | strd CARG34, CTSTATE->cb.gpr[2] - | strd CARG12, CTSTATE->cb.gpr[0] - |.if HFABI - | vstmdb r12!, {d0-d7} - |.endif - | ldr CARG4, [sp] - | add CARG3, sp, #CFRAME_SIZE - | mov CARG1, CTSTATE - | lsr CARG4, CARG4, #3 - | str CARG3, CTSTATE->cb.stack - | mov CARG2, sp - | str CARG4, CTSTATE->cb.slot - | str CTSTATE, SAVE_PC // Any value outside of bytecode is ok. - | bl extern lj_ccallback_enter // (CTState *cts, void *cf) - | // Returns lua_State *. - | ldr BASE, L:CRET1->base - | mv_vmstate CARG2, INTERP - | ldr RC, L:CRET1->top - | mov MASKR8, #255 - | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] - | mov L, CRET1 - | sub RC, RC, BASE - | lsl MASKR8, MASKR8, #3 // MASKR8 = 255*8. - | st_vmstate CARG2 - | ins_callt - |.endif - | - |->cont_ffi_callback: // Return from FFI callback. - |.if FFI - | ldr CTSTATE, [DISPATCH, #DISPATCH_GL(ctype_state)] - | str BASE, L->base - | str CARG4, L->top - | str L, CTSTATE->L - | mov CARG1, CTSTATE - | mov CARG2, RA - | bl extern lj_ccallback_leave // (CTState *cts, TValue *o) - | ldrd CARG12, CTSTATE->cb.gpr[0] - |.if HFABI - | vldr d0, CTSTATE->cb.fpr[0] - |.endif - | b ->vm_leave_unw - |.endif - | - |->vm_ffi_call: // Call C function via FFI. - | // Caveat: needs special frame unwinding, see below. - |.if FFI - | .type CCSTATE, CCallState, r4 - | push {CCSTATE, r5, r11, lr} - | mov CCSTATE, CARG1 - | ldr CARG1, CCSTATE:CARG1->spadj - | ldrb CARG2, CCSTATE->nsp - | add CARG3, CCSTATE, #offsetof(CCallState, stack) - |.if HFABI - | add RB, CCSTATE, #offsetof(CCallState, fpr[0]) - |.endif - | mov r11, sp - | sub sp, sp, CARG1 // Readjust stack. - | subs CARG2, CARG2, #1 - |.if HFABI - | vldm RB, {d0-d7} - |.endif - | ldr RB, CCSTATE->func - | bmi >2 - |1: // Copy stack slots. - | ldr CARG4, [CARG3, CARG2, lsl #2] - | str CARG4, [sp, CARG2, lsl #2] - | subs CARG2, CARG2, #1 - | bpl <1 - |2: - | ldrd CARG12, CCSTATE->gpr[0] - | ldrd CARG34, CCSTATE->gpr[2] - | blx RB - | mov sp, r11 - |.if HFABI - | add r12, CCSTATE, #offsetof(CCallState, fpr[4]) - |.endif - | strd CRET1, CCSTATE->gpr[0] - |.if HFABI - | vstmdb r12!, {d0-d3} - |.endif - | pop {CCSTATE, r5, r11, pc} - |.endif - |// Note: vm_ffi_call must be the last function in this object file! - | - |//----------------------------------------------------------------------- -} - -/* Generate the code for a single instruction. */ -static void build_ins(BuildCtx *ctx, BCOp op, int defop) -{ - int vk = 0; - |=>defop: - - switch (op) { - - /* -- Comparison ops ---------------------------------------------------- */ - - /* Remember: all ops branch for a true comparison, fall through otherwise. */ - - case BC_ISLT: case BC_ISGE: case BC_ISLE: case BC_ISGT: - | // RA = src1*8, RC = src2, JMP with RC = target - | lsl RC, RC, #3 - | ldrd CARG12, [RA, BASE]! - | ldrh RB, [PC, #2] - | ldrd CARG34, [RC, BASE]! - | add PC, PC, #4 - | add RB, PC, RB, lsl #2 - | checktp CARG2, LJ_TISNUM - | bne >3 - | checktp CARG4, LJ_TISNUM - | bne >4 - | cmp CARG1, CARG3 - if (op == BC_ISLT) { - | sublt PC, RB, #0x20000 - } else if (op == BC_ISGE) { - | subge PC, RB, #0x20000 - } else if (op == BC_ISLE) { - | suble PC, RB, #0x20000 - } else { - | subgt PC, RB, #0x20000 - } - |1: - | ins_next - | - |3: // CARG12 is not an integer. - |.if FPU - | vldr d0, [RA] - | bhi ->vmeta_comp - | // d0 is a number. - | checktp CARG4, LJ_TISNUM - | vldr d1, [RC] - | blo >5 - | bhi ->vmeta_comp - | // d0 is a number, CARG3 is an integer. - | vmov s4, CARG3 - | vcvt.f64.s32 d1, s4 - | b >5 - |4: // CARG1 is an integer, CARG34 is not an integer. - | vldr d1, [RC] - | bhi ->vmeta_comp - | // CARG1 is an integer, d1 is a number. - | vmov s4, CARG1 - | vcvt.f64.s32 d0, s4 - |5: // d0 and d1 are numbers. - | vcmp.f64 d0, d1 - | vmrs - | // To preserve NaN semantics GE/GT branch on unordered, but LT/LE don't. - if (op == BC_ISLT) { - | sublo PC, RB, #0x20000 - } else if (op == BC_ISGE) { - | subhs PC, RB, #0x20000 - } else if (op == BC_ISLE) { - | subls PC, RB, #0x20000 - } else { - | subhi PC, RB, #0x20000 - } - | b <1 - |.else - | bhi ->vmeta_comp - | // CARG12 is a number. - | checktp CARG4, LJ_TISNUM - | movlo RA, RB // Save RB. - | blo >5 - | bhi ->vmeta_comp - | // CARG12 is a number, CARG3 is an integer. - | mov CARG1, CARG3 - | mov RC, RA - | mov RA, RB // Save RB. - | bl extern __aeabi_i2d - | mov CARG3, CARG1 - | mov CARG4, CARG2 - | ldrd CARG12, [RC] // Restore first operand. - | b >5 - |4: // CARG1 is an integer, CARG34 is not an integer. - | bhi ->vmeta_comp - | // CARG1 is an integer, CARG34 is a number. - | mov RA, RB // Save RB. - | bl extern __aeabi_i2d - | ldrd CARG34, [RC] // Restore second operand. - |5: // CARG12 and CARG34 are numbers. - | bl extern __aeabi_cdcmple - | // To preserve NaN semantics GE/GT branch on unordered, but LT/LE don't. - if (op == BC_ISLT) { - | sublo PC, RA, #0x20000 - } else if (op == BC_ISGE) { - | subhs PC, RA, #0x20000 - } else if (op == BC_ISLE) { - | subls PC, RA, #0x20000 - } else { - | subhi PC, RA, #0x20000 - } - | b <1 - |.endif - break; - - case BC_ISEQV: case BC_ISNEV: - vk = op == BC_ISEQV; - | // RA = src1*8, RC = src2, JMP with RC = target - | lsl RC, RC, #3 - | ldrd CARG12, [RA, BASE]! - | ldrh RB, [PC, #2] - | ldrd CARG34, [RC, BASE]! - | add PC, PC, #4 - | add RB, PC, RB, lsl #2 - | checktp CARG2, LJ_TISNUM - | cmnls CARG4, #-LJ_TISNUM - if (vk) { - | bls ->BC_ISEQN_Z - } else { - | bls ->BC_ISNEN_Z - } - | // Either or both types are not numbers. - |.if FFI - | checktp CARG2, LJ_TCDATA - | checktpne CARG4, LJ_TCDATA - | beq ->vmeta_equal_cd - |.endif - | cmp CARG2, CARG4 // Compare types. - | bne >2 // Not the same type? - | checktp CARG2, LJ_TISPRI - | bhs >1 // Same type and primitive type? - | - | // Same types and not a primitive type. Compare GCobj or pvalue. - | cmp CARG1, CARG3 - if (vk) { - | bne >3 // Different GCobjs or pvalues? - |1: // Branch if same. - | sub PC, RB, #0x20000 - |2: // Different. - | ins_next - |3: - | checktp CARG2, LJ_TISTABUD - | bhi <2 // Different objects and not table/ud? - } else { - | beq >1 // Same GCobjs or pvalues? - | checktp CARG2, LJ_TISTABUD - | bhi >2 // Different objects and not table/ud? - } - | // Different tables or userdatas. Need to check __eq metamethod. - | // Field metatable must be at same offset for GCtab and GCudata! - | ldr TAB:RA, TAB:CARG1->metatable - | cmp TAB:RA, #0 - if (vk) { - | beq <2 // No metatable? - } else { - | beq >2 // No metatable? - } - | ldrb RA, TAB:RA->nomm - | mov CARG4, #1-vk // ne = 0 or 1. - | mov CARG2, CARG1 - | tst RA, #1<vmeta_equal // 'no __eq' flag not set? - if (vk) { - | b <2 - } else { - |2: // Branch if different. - | sub PC, RB, #0x20000 - |1: // Same. - | ins_next - } - break; - - case BC_ISEQS: case BC_ISNES: - vk = op == BC_ISEQS; - | // RA = src*8, RC = str_const (~), JMP with RC = target - | mvn RC, RC - | ldrd CARG12, [BASE, RA] - | ldrh RB, [PC, #2] - | ldr STR:CARG3, [KBASE, RC, lsl #2] - | add PC, PC, #4 - | add RB, PC, RB, lsl #2 - | checktp CARG2, LJ_TSTR - |.if FFI - | bne >7 - | cmp CARG1, CARG3 - |.else - | cmpeq CARG1, CARG3 - |.endif - if (vk) { - | subeq PC, RB, #0x20000 - |1: - } else { - |1: - | subne PC, RB, #0x20000 - } - | ins_next - | - |.if FFI - |7: - | checktp CARG2, LJ_TCDATA - | bne <1 - | b ->vmeta_equal_cd - |.endif - break; - - case BC_ISEQN: case BC_ISNEN: - vk = op == BC_ISEQN; - | // RA = src*8, RC = num_const (~), JMP with RC = target - | lsl RC, RC, #3 - | ldrd CARG12, [RA, BASE]! - | ldrh RB, [PC, #2] - | ldrd CARG34, [RC, KBASE]! - | add PC, PC, #4 - | add RB, PC, RB, lsl #2 - if (vk) { - |->BC_ISEQN_Z: - } else { - |->BC_ISNEN_Z: - } - | checktp CARG2, LJ_TISNUM - | bne >3 - | checktp CARG4, LJ_TISNUM - | bne >4 - | cmp CARG1, CARG3 - if (vk) { - | subeq PC, RB, #0x20000 - |1: - } else { - |1: - | subne PC, RB, #0x20000 - } - |2: - | ins_next - | - |3: // CARG12 is not an integer. - |.if FFI - | bhi >7 - |.else - if (!vk) { - | subhi PC, RB, #0x20000 - } - | bhi <2 - |.endif - |.if FPU - | checktp CARG4, LJ_TISNUM - | vmov s4, CARG3 - | vldr d0, [RA] - | vldrlo d1, [RC] - | vcvths.f64.s32 d1, s4 - | b >5 - |4: // CARG1 is an integer, d1 is a number. - | vmov s4, CARG1 - | vldr d1, [RC] - | vcvt.f64.s32 d0, s4 - |5: // d0 and d1 are numbers. - | vcmp.f64 d0, d1 - | vmrs - if (vk) { - | subeq PC, RB, #0x20000 - } else { - | subne PC, RB, #0x20000 - } - | b <2 - |.else - | // CARG12 is a number. - | checktp CARG4, LJ_TISNUM - | movlo RA, RB // Save RB. - | blo >5 - | // CARG12 is a number, CARG3 is an integer. - | mov CARG1, CARG3 - | mov RC, RA - |4: // CARG1 is an integer, CARG34 is a number. - | mov RA, RB // Save RB. - | bl extern __aeabi_i2d - | ldrd CARG34, [RC] // Restore other operand. - |5: // CARG12 and CARG34 are numbers. - | bl extern __aeabi_cdcmpeq - if (vk) { - | subeq PC, RA, #0x20000 - } else { - | subne PC, RA, #0x20000 - } - | b <2 - |.endif - | - |.if FFI - |7: - | checktp CARG2, LJ_TCDATA - | bne <1 - | b ->vmeta_equal_cd - |.endif - break; - - case BC_ISEQP: case BC_ISNEP: - vk = op == BC_ISEQP; - | // RA = src*8, RC = primitive_type (~), JMP with RC = target - | ldrd CARG12, [BASE, RA] - | ldrh RB, [PC, #2] - | add PC, PC, #4 - | mvn RC, RC - | add RB, PC, RB, lsl #2 - |.if FFI - | checktp CARG2, LJ_TCDATA - | beq ->vmeta_equal_cd - |.endif - | cmp CARG2, RC - if (vk) { - | subeq PC, RB, #0x20000 - } else { - | subne PC, RB, #0x20000 - } - | ins_next - break; - - /* -- Unary test and copy ops ------------------------------------------- */ - - case BC_ISTC: case BC_ISFC: case BC_IST: case BC_ISF: - | // RA = dst*8 or unused, RC = src, JMP with RC = target - | add RC, BASE, RC, lsl #3 - | ldrh RB, [PC, #2] - | ldrd CARG12, [RC] - | add PC, PC, #4 - | add RB, PC, RB, lsl #2 - | checktp CARG2, LJ_TTRUE - if (op == BC_ISTC || op == BC_IST) { - | subls PC, RB, #0x20000 - if (op == BC_ISTC) { - | strdls CARG12, [BASE, RA] - } - } else { - | subhi PC, RB, #0x20000 - if (op == BC_ISFC) { - | strdhi CARG12, [BASE, RA] - } - } - | ins_next - break; - - case BC_ISTYPE: - | // RA = src*8, RC = -type - | ldrd CARG12, [BASE, RA] - | ins_next1 - | cmn CARG2, RC - | ins_next2 - | bne ->vmeta_istype - | ins_next3 - break; - case BC_ISNUM: - | // RA = src*8, RC = -(TISNUM-1) - | ldrd CARG12, [BASE, RA] - | ins_next1 - | checktp CARG2, LJ_TISNUM - | ins_next2 - | bhs ->vmeta_istype - | ins_next3 - break; - - /* -- Unary ops --------------------------------------------------------- */ - - case BC_MOV: - | // RA = dst*8, RC = src - | lsl RC, RC, #3 - | ins_next1 - | ldrd CARG12, [BASE, RC] - | ins_next2 - | strd CARG12, [BASE, RA] - | ins_next3 - break; - case BC_NOT: - | // RA = dst*8, RC = src - | add RC, BASE, RC, lsl #3 - | ins_next1 - | ldr CARG1, [RC, #4] - | add RA, BASE, RA - | ins_next2 - | checktp CARG1, LJ_TTRUE - | mvnls CARG2, #~LJ_TFALSE - | mvnhi CARG2, #~LJ_TTRUE - | str CARG2, [RA, #4] - | ins_next3 - break; - case BC_UNM: - | // RA = dst*8, RC = src - | lsl RC, RC, #3 - | ldrd CARG12, [BASE, RC] - | ins_next1 - | ins_next2 - | checktp CARG2, LJ_TISNUM - | bhi ->vmeta_unm - | eorne CARG2, CARG2, #0x80000000 - | bne >5 - | rsbseq CARG1, CARG1, #0 - | ldrdvs CARG12, >9 - |5: - | strd CARG12, [BASE, RA] - | ins_next3 - | - |.align 8 - |9: - | .long 0x00000000, 0x41e00000 // 2^31. - break; - case BC_LEN: - | // RA = dst*8, RC = src - | lsl RC, RC, #3 - | ldrd CARG12, [BASE, RC] - | checkstr CARG2, >2 - | ldr CARG1, STR:CARG1->len - |1: - | mvn CARG2, #~LJ_TISNUM - | ins_next1 - | ins_next2 - | strd CARG12, [BASE, RA] - | ins_next3 - |2: - | checktab CARG2, ->vmeta_len -#if LJ_52 - | ldr TAB:CARG3, TAB:CARG1->metatable - | cmp TAB:CARG3, #0 - | bne >9 - |3: -#endif - |->BC_LEN_Z: - | .IOS mov RC, BASE - | bl extern lj_tab_len // (GCtab *t) - | // Returns uint32_t (but less than 2^31). - | .IOS mov BASE, RC - | b <1 -#if LJ_52 - |9: - | ldrb CARG4, TAB:CARG3->nomm - | tst CARG4, #1<vmeta_len -#endif - break; - - /* -- Binary ops -------------------------------------------------------- */ - - |.macro ins_arithcheck, cond, ncond, target - ||if (vk == 1) { - | cmn CARG4, #-LJ_TISNUM - | cmn..cond CARG2, #-LJ_TISNUM - ||} else { - | cmn CARG2, #-LJ_TISNUM - | cmn..cond CARG4, #-LJ_TISNUM - ||} - | b..ncond target - |.endmacro - |.macro ins_arithcheck_int, target - | ins_arithcheck eq, ne, target - |.endmacro - |.macro ins_arithcheck_num, target - | ins_arithcheck lo, hs, target - |.endmacro - | - |.macro ins_arithpre - | decode_RB8 RB, INS - | decode_RC8 RC, INS - | // RA = dst*8, RB = src1*8, RC = src2*8 | num_const*8 - ||vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN); - ||switch (vk) { - ||case 0: - | .if FPU - | ldrd CARG12, [RB, BASE]! - | ldrd CARG34, [RC, KBASE]! - | .else - | ldrd CARG12, [BASE, RB] - | ldrd CARG34, [KBASE, RC] - | .endif - || break; - ||case 1: - | .if FPU - | ldrd CARG34, [RB, BASE]! - | ldrd CARG12, [RC, KBASE]! - | .else - | ldrd CARG34, [BASE, RB] - | ldrd CARG12, [KBASE, RC] - | .endif - || break; - ||default: - | .if FPU - | ldrd CARG12, [RB, BASE]! - | ldrd CARG34, [RC, BASE]! - | .else - | ldrd CARG12, [BASE, RB] - | ldrd CARG34, [BASE, RC] - | .endif - || break; - ||} - |.endmacro - | - |.macro ins_arithpre_fpu, reg1, reg2 - |.if FPU - ||if (vk == 1) { - | vldr reg2, [RB] - | vldr reg1, [RC] - ||} else { - | vldr reg1, [RB] - | vldr reg2, [RC] - ||} - |.endif - |.endmacro - | - |.macro ins_arithpost_fpu, reg - | ins_next1 - | add RA, BASE, RA - | ins_next2 - | vstr reg, [RA] - | ins_next3 - |.endmacro - | - |.macro ins_arithfallback, ins - ||switch (vk) { - ||case 0: - | ins ->vmeta_arith_vn - || break; - ||case 1: - | ins ->vmeta_arith_nv - || break; - ||default: - | ins ->vmeta_arith_vv - || break; - ||} - |.endmacro - | - |.macro ins_arithdn, intins, fpins, fpcall - | ins_arithpre - |.if "intins" ~= "vm_modi" and not FPU - | ins_next1 - |.endif - | ins_arithcheck_int >5 - |.if "intins" == "smull" - | smull CARG1, RC, CARG3, CARG1 - | cmp RC, CARG1, asr #31 - | ins_arithfallback bne - |.elif "intins" == "vm_modi" - | movs CARG2, CARG3 - | ins_arithfallback beq - | bl ->vm_modi - | mvn CARG2, #~LJ_TISNUM - |.else - | intins CARG1, CARG1, CARG3 - | ins_arithfallback bvs - |.endif - |4: - |.if "intins" == "vm_modi" or FPU - | ins_next1 - |.endif - | ins_next2 - | strd CARG12, [BASE, RA] - | ins_next3 - |5: // FP variant. - | ins_arithpre_fpu d6, d7 - | ins_arithfallback ins_arithcheck_num - |.if FPU - |.if "intins" == "vm_modi" - | bl fpcall - |.else - | fpins d6, d6, d7 - |.endif - | ins_arithpost_fpu d6 - |.else - | bl fpcall - |.if "intins" ~= "vm_modi" - | ins_next1 - |.endif - | b <4 - |.endif - |.endmacro - | - |.macro ins_arithfp, fpins, fpcall - | ins_arithpre - |.if "fpins" ~= "extern" or HFABI - | ins_arithpre_fpu d0, d1 - |.endif - | ins_arithfallback ins_arithcheck_num - |.if "fpins" == "extern" - | .IOS mov RC, BASE - | bl fpcall - | .IOS mov BASE, RC - |.elif FPU - | fpins d0, d0, d1 - |.else - | bl fpcall - |.endif - |.if ("fpins" ~= "extern" or HFABI) and FPU - | ins_arithpost_fpu d0 - |.else - | ins_next1 - | ins_next2 - | strd CARG12, [BASE, RA] - | ins_next3 - |.endif - |.endmacro - - case BC_ADDVN: case BC_ADDNV: case BC_ADDVV: - | ins_arithdn adds, vadd.f64, extern __aeabi_dadd - break; - case BC_SUBVN: case BC_SUBNV: case BC_SUBVV: - | ins_arithdn subs, vsub.f64, extern __aeabi_dsub - break; - case BC_MULVN: case BC_MULNV: case BC_MULVV: - | ins_arithdn smull, vmul.f64, extern __aeabi_dmul - break; - case BC_DIVVN: case BC_DIVNV: case BC_DIVVV: - | ins_arithfp vdiv.f64, extern __aeabi_ddiv - break; - case BC_MODVN: case BC_MODNV: case BC_MODVV: - | ins_arithdn vm_modi, vm_mod, ->vm_mod - break; - case BC_POW: - | // NYI: (partial) integer arithmetic. - | ins_arithfp extern, extern pow - break; - - case BC_CAT: - | decode_RB8 RC, INS - | decode_RC8 RB, INS - | // RA = dst*8, RC = src_start*8, RB = src_end*8 (note: RB/RC swapped!) - | sub CARG3, RB, RC - | str BASE, L->base - | add CARG2, BASE, RB - |->BC_CAT_Z: - | // RA = dst*8, RC = src_start*8, CARG2 = top-1 - | mov CARG1, L - | str PC, SAVE_PC - | lsr CARG3, CARG3, #3 - | bl extern lj_meta_cat // (lua_State *L, TValue *top, int left) - | // Returns NULL (finished) or TValue * (metamethod). - | ldr BASE, L->base - | cmp CRET1, #0 - | bne ->vmeta_binop - | ldrd CARG34, [BASE, RC] - | ins_next1 - | ins_next2 - | strd CARG34, [BASE, RA] // Copy result to RA. - | ins_next3 - break; - - /* -- Constant ops ------------------------------------------------------ */ - - case BC_KSTR: - | // RA = dst*8, RC = str_const (~) - | mvn RC, RC - | ins_next1 - | ldr CARG1, [KBASE, RC, lsl #2] - | mvn CARG2, #~LJ_TSTR - | ins_next2 - | strd CARG12, [BASE, RA] - | ins_next3 - break; - case BC_KCDATA: - |.if FFI - | // RA = dst*8, RC = cdata_const (~) - | mvn RC, RC - | ins_next1 - | ldr CARG1, [KBASE, RC, lsl #2] - | mvn CARG2, #~LJ_TCDATA - | ins_next2 - | strd CARG12, [BASE, RA] - | ins_next3 - |.endif - break; - case BC_KSHORT: - | // RA = dst*8, (RC = int16_literal) - | mov CARG1, INS, asr #16 // Refetch sign-extended reg. - | mvn CARG2, #~LJ_TISNUM - | ins_next1 - | ins_next2 - | strd CARG12, [BASE, RA] - | ins_next3 - break; - case BC_KNUM: - | // RA = dst*8, RC = num_const - | lsl RC, RC, #3 - | ins_next1 - | ldrd CARG12, [KBASE, RC] - | ins_next2 - | strd CARG12, [BASE, RA] - | ins_next3 - break; - case BC_KPRI: - | // RA = dst*8, RC = primitive_type (~) - | add RA, BASE, RA - | mvn RC, RC - | ins_next1 - | ins_next2 - | str RC, [RA, #4] - | ins_next3 - break; - case BC_KNIL: - | // RA = base*8, RC = end - | add RA, BASE, RA - | add RC, BASE, RC, lsl #3 - | mvn CARG1, #~LJ_TNIL - | str CARG1, [RA, #4] - | add RA, RA, #8 - |1: - | str CARG1, [RA, #4] - | cmp RA, RC - | add RA, RA, #8 - | blt <1 - | ins_next_ - break; - - /* -- Upvalue and function ops ------------------------------------------ */ - - case BC_UGET: - | // RA = dst*8, RC = uvnum - | ldr LFUNC:CARG2, [BASE, FRAME_FUNC] - | lsl RC, RC, #2 - | add RC, RC, #offsetof(GCfuncL, uvptr) - | ldr UPVAL:CARG2, [LFUNC:CARG2, RC] - | ldr CARG2, UPVAL:CARG2->v - | ldrd CARG34, [CARG2] - | ins_next1 - | ins_next2 - | strd CARG34, [BASE, RA] - | ins_next3 - break; - case BC_USETV: - | // RA = uvnum*8, RC = src - | ldr LFUNC:CARG2, [BASE, FRAME_FUNC] - | lsr RA, RA, #1 - | add RA, RA, #offsetof(GCfuncL, uvptr) - | lsl RC, RC, #3 - | ldr UPVAL:CARG2, [LFUNC:CARG2, RA] - | ldrd CARG34, [BASE, RC] - | ldrb RB, UPVAL:CARG2->marked - | ldrb RC, UPVAL:CARG2->closed - | ldr CARG2, UPVAL:CARG2->v - | tst RB, #LJ_GC_BLACK // isblack(uv) - | add RB, CARG4, #-LJ_TISGCV - | cmpne RC, #0 - | strd CARG34, [CARG2] - | bne >2 // Upvalue is closed and black? - |1: - | ins_next - | - |2: // Check if new value is collectable. - | cmn RB, #-(LJ_TNUMX - LJ_TISGCV) - | ldrbhi RC, GCOBJ:CARG3->gch.marked - | bls <1 // tvisgcv(v) - | sub CARG1, DISPATCH, #-GG_DISP2G - | tst RC, #LJ_GC_WHITES - | // Crossed a write barrier. Move the barrier forward. - |.if IOS - | beq <1 - | mov RC, BASE - | bl extern lj_gc_barrieruv // (global_State *g, TValue *tv) - | mov BASE, RC - |.else - | blne extern lj_gc_barrieruv // (global_State *g, TValue *tv) - |.endif - | b <1 - break; - case BC_USETS: - | // RA = uvnum*8, RC = str_const (~) - | ldr LFUNC:CARG2, [BASE, FRAME_FUNC] - | lsr RA, RA, #1 - | add RA, RA, #offsetof(GCfuncL, uvptr) - | mvn RC, RC - | ldr UPVAL:CARG2, [LFUNC:CARG2, RA] - | ldr STR:CARG3, [KBASE, RC, lsl #2] - | ldrb RB, UPVAL:CARG2->marked - | ldrb RC, UPVAL:CARG2->closed - | ldr CARG2, UPVAL:CARG2->v - | mvn CARG4, #~LJ_TSTR - | tst RB, #LJ_GC_BLACK // isblack(uv) - | ldrb RB, STR:CARG3->marked - | strd CARG34, [CARG2] - | bne >2 - |1: - | ins_next - | - |2: // Check if string is white and ensure upvalue is closed. - | tst RB, #LJ_GC_WHITES // iswhite(str) - | cmpne RC, #0 - | sub CARG1, DISPATCH, #-GG_DISP2G - | // Crossed a write barrier. Move the barrier forward. - |.if IOS - | beq <1 - | mov RC, BASE - | bl extern lj_gc_barrieruv // (global_State *g, TValue *tv) - | mov BASE, RC - |.else - | blne extern lj_gc_barrieruv // (global_State *g, TValue *tv) - |.endif - | b <1 - break; - case BC_USETN: - | // RA = uvnum*8, RC = num_const - | ldr LFUNC:CARG2, [BASE, FRAME_FUNC] - | lsr RA, RA, #1 - | add RA, RA, #offsetof(GCfuncL, uvptr) - | lsl RC, RC, #3 - | ldr UPVAL:CARG2, [LFUNC:CARG2, RA] - | ldrd CARG34, [KBASE, RC] - | ldr CARG2, UPVAL:CARG2->v - | ins_next1 - | ins_next2 - | strd CARG34, [CARG2] - | ins_next3 - break; - case BC_USETP: - | // RA = uvnum*8, RC = primitive_type (~) - | ldr LFUNC:CARG2, [BASE, FRAME_FUNC] - | lsr RA, RA, #1 - | add RA, RA, #offsetof(GCfuncL, uvptr) - | ldr UPVAL:CARG2, [LFUNC:CARG2, RA] - | mvn RC, RC - | ldr CARG2, UPVAL:CARG2->v - | ins_next1 - | ins_next2 - | str RC, [CARG2, #4] - | ins_next3 - break; - - case BC_UCLO: - | // RA = level*8, RC = target - | ldr CARG3, L->openupval - | add RC, PC, RC, lsl #2 - | str BASE, L->base - | cmp CARG3, #0 - | sub PC, RC, #0x20000 - | beq >1 - | mov CARG1, L - | add CARG2, BASE, RA - | bl extern lj_func_closeuv // (lua_State *L, TValue *level) - | ldr BASE, L->base - |1: - | ins_next - break; - - case BC_FNEW: - | // RA = dst*8, RC = proto_const (~) (holding function prototype) - | mvn RC, RC - | str BASE, L->base - | ldr CARG2, [KBASE, RC, lsl #2] - | str PC, SAVE_PC - | ldr CARG3, [BASE, FRAME_FUNC] - | mov CARG1, L - | // (lua_State *L, GCproto *pt, GCfuncL *parent) - | bl extern lj_func_newL_gc - | // Returns GCfuncL *. - | ldr BASE, L->base - | mvn CARG2, #~LJ_TFUNC - | ins_next1 - | ins_next2 - | strd CARG12, [BASE, RA] - | ins_next3 - break; - - /* -- Table ops --------------------------------------------------------- */ - - case BC_TNEW: - case BC_TDUP: - | // RA = dst*8, RC = (hbits|asize) | tab_const (~) - if (op == BC_TDUP) { - | mvn RC, RC - } - | ldr CARG3, [DISPATCH, #DISPATCH_GL(gc.total)] - | ldr CARG4, [DISPATCH, #DISPATCH_GL(gc.threshold)] - | str BASE, L->base - | str PC, SAVE_PC - | cmp CARG3, CARG4 - | mov CARG1, L - | bhs >5 - |1: - if (op == BC_TNEW) { - | lsl CARG2, RC, #21 - | lsr CARG3, RC, #11 - | asr RC, CARG2, #21 - | lsr CARG2, CARG2, #21 - | cmn RC, #1 - | addeq CARG2, CARG2, #2 - | bl extern lj_tab_new // (lua_State *L, int32_t asize, uint32_t hbits) - | // Returns GCtab *. - } else { - | ldr CARG2, [KBASE, RC, lsl #2] - | bl extern lj_tab_dup // (lua_State *L, Table *kt) - | // Returns GCtab *. - } - | ldr BASE, L->base - | mvn CARG2, #~LJ_TTAB - | ins_next1 - | ins_next2 - | strd CARG12, [BASE, RA] - | ins_next3 - |5: - | bl extern lj_gc_step_fixtop // (lua_State *L) - | mov CARG1, L - | b <1 - break; - - case BC_GGET: - | // RA = dst*8, RC = str_const (~) - case BC_GSET: - | // RA = dst*8, RC = str_const (~) - | ldr LFUNC:CARG2, [BASE, FRAME_FUNC] - | mvn RC, RC - | ldr TAB:CARG1, LFUNC:CARG2->env - | ldr STR:RC, [KBASE, RC, lsl #2] - if (op == BC_GGET) { - | b ->BC_TGETS_Z - } else { - | b ->BC_TSETS_Z - } - break; - - case BC_TGETV: - | decode_RB8 RB, INS - | decode_RC8 RC, INS - | // RA = dst*8, RB = table*8, RC = key*8 - | ldrd TAB:CARG12, [BASE, RB] - | ldrd CARG34, [BASE, RC] - | checktab CARG2, ->vmeta_tgetv // STALL: load CARG12. - | checktp CARG4, LJ_TISNUM // Integer key? - | ldreq CARG4, TAB:CARG1->array - | ldreq CARG2, TAB:CARG1->asize - | bne >9 - | - | add CARG4, CARG4, CARG3, lsl #3 - | cmp CARG3, CARG2 // In array part? - | ldrdlo CARG34, [CARG4] - | bhs ->vmeta_tgetv - | ins_next1 // Overwrites RB! - | checktp CARG4, LJ_TNIL - | beq >5 - |1: - | ins_next2 - | strd CARG34, [BASE, RA] - | ins_next3 - | - |5: // Check for __index if table value is nil. - | ldr TAB:CARG2, TAB:CARG1->metatable - | cmp TAB:CARG2, #0 - | beq <1 // No metatable: done. - | ldrb CARG2, TAB:CARG2->nomm - | tst CARG2, #1<vmeta_tgetv - | - |9: - | checktp CARG4, LJ_TSTR // String key? - | moveq STR:RC, CARG3 - | beq ->BC_TGETS_Z - | b ->vmeta_tgetv - break; - case BC_TGETS: - | decode_RB8 RB, INS - | and RC, RC, #255 - | // RA = dst*8, RB = table*8, RC = str_const (~) - | ldrd CARG12, [BASE, RB] - | mvn RC, RC - | ldr STR:RC, [KBASE, RC, lsl #2] // STALL: early RC. - | checktab CARG2, ->vmeta_tgets1 - |->BC_TGETS_Z: - | // (TAB:RB =) TAB:CARG1 = GCtab *, STR:RC = GCstr *, RA = dst*8 - | ldr CARG3, TAB:CARG1->hmask - | ldr CARG4, STR:RC->hash - | ldr NODE:INS, TAB:CARG1->node - | mov TAB:RB, TAB:CARG1 - | and CARG3, CARG3, CARG4 // idx = str->hash & tab->hmask - | add CARG3, CARG3, CARG3, lsl #1 - | add NODE:INS, NODE:INS, CARG3, lsl #3 // node = tab->node + idx*3*8 - |1: - | ldrd CARG12, NODE:INS->key // STALL: early NODE:INS. - | ldrd CARG34, NODE:INS->val - | ldr NODE:INS, NODE:INS->next - | checktp CARG2, LJ_TSTR - | cmpeq CARG1, STR:RC - | bne >4 - | checktp CARG4, LJ_TNIL - | beq >5 - |3: - | ins_next1 - | ins_next2 - | strd CARG34, [BASE, RA] - | ins_next3 - | - |4: // Follow hash chain. - | cmp NODE:INS, #0 - | bne <1 - | // End of hash chain: key not found, nil result. - | - |5: // Check for __index if table value is nil. - | ldr TAB:CARG1, TAB:RB->metatable - | mov CARG3, #0 // Optional clear of undef. value (during load stall). - | mvn CARG4, #~LJ_TNIL - | cmp TAB:CARG1, #0 - | beq <3 // No metatable: done. - | ldrb CARG2, TAB:CARG1->nomm - | tst CARG2, #1<vmeta_tgets - break; - case BC_TGETB: - | decode_RB8 RB, INS - | and RC, RC, #255 - | // RA = dst*8, RB = table*8, RC = index - | ldrd CARG12, [BASE, RB] - | checktab CARG2, ->vmeta_tgetb // STALL: load CARG12. - | ldr CARG3, TAB:CARG1->asize - | ldr CARG4, TAB:CARG1->array - | lsl CARG2, RC, #3 - | cmp RC, CARG3 - | ldrdlo CARG34, [CARG4, CARG2] - | bhs ->vmeta_tgetb - | ins_next1 // Overwrites RB! - | checktp CARG4, LJ_TNIL - | beq >5 - |1: - | ins_next2 - | strd CARG34, [BASE, RA] - | ins_next3 - | - |5: // Check for __index if table value is nil. - | ldr TAB:CARG2, TAB:CARG1->metatable - | cmp TAB:CARG2, #0 - | beq <1 // No metatable: done. - | ldrb CARG2, TAB:CARG2->nomm - | tst CARG2, #1<vmeta_tgetb - break; - case BC_TGETR: - | decode_RB8 RB, INS - | decode_RC8 RC, INS - | // RA = dst*8, RB = table*8, RC = key*8 - | ldr TAB:CARG1, [BASE, RB] - | ldr CARG2, [BASE, RC] - | ldr CARG4, TAB:CARG1->array - | ldr CARG3, TAB:CARG1->asize - | add CARG4, CARG4, CARG2, lsl #3 - | cmp CARG2, CARG3 // In array part? - | bhs ->vmeta_tgetr - | ldrd CARG12, [CARG4] - |->BC_TGETR_Z: - | ins_next1 - | ins_next2 - | strd CARG12, [BASE, RA] - | ins_next3 - break; - - case BC_TSETV: - | decode_RB8 RB, INS - | decode_RC8 RC, INS - | // RA = src*8, RB = table*8, RC = key*8 - | ldrd TAB:CARG12, [BASE, RB] - | ldrd CARG34, [BASE, RC] - | checktab CARG2, ->vmeta_tsetv // STALL: load CARG12. - | checktp CARG4, LJ_TISNUM // Integer key? - | ldreq CARG2, TAB:CARG1->array - | ldreq CARG4, TAB:CARG1->asize - | bne >9 - | - | add CARG2, CARG2, CARG3, lsl #3 - | cmp CARG3, CARG4 // In array part? - | ldrlo INS, [CARG2, #4] - | bhs ->vmeta_tsetv - | ins_next1 // Overwrites RB! - | checktp INS, LJ_TNIL - | ldrb INS, TAB:CARG1->marked - | ldrd CARG34, [BASE, RA] - | beq >5 - |1: - | tst INS, #LJ_GC_BLACK // isblack(table) - | strd CARG34, [CARG2] - | bne >7 - |2: - | ins_next2 - | ins_next3 - | - |5: // Check for __newindex if previous value is nil. - | ldr TAB:RA, TAB:CARG1->metatable - | cmp TAB:RA, #0 - | beq <1 // No metatable: done. - | ldrb RA, TAB:RA->nomm - | tst RA, #1<vmeta_tsetv - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:CARG1, INS, CARG3 - | b <2 - | - |9: - | checktp CARG4, LJ_TSTR // String key? - | moveq STR:RC, CARG3 - | beq ->BC_TSETS_Z - | b ->vmeta_tsetv - break; - case BC_TSETS: - | decode_RB8 RB, INS - | and RC, RC, #255 - | // RA = src*8, RB = table*8, RC = str_const (~) - | ldrd CARG12, [BASE, RB] - | mvn RC, RC - | ldr STR:RC, [KBASE, RC, lsl #2] // STALL: early RC. - | checktab CARG2, ->vmeta_tsets1 - |->BC_TSETS_Z: - | // (TAB:RB =) TAB:CARG1 = GCtab *, STR:RC = GCstr *, RA = dst*8 - | ldr CARG3, TAB:CARG1->hmask - | ldr CARG4, STR:RC->hash - | ldr NODE:INS, TAB:CARG1->node - | mov TAB:RB, TAB:CARG1 - | and CARG3, CARG3, CARG4 // idx = str->hash & tab->hmask - | add CARG3, CARG3, CARG3, lsl #1 - | mov CARG4, #0 - | add NODE:INS, NODE:INS, CARG3, lsl #3 // node = tab->node + idx*3*8 - | strb CARG4, TAB:RB->nomm // Clear metamethod cache. - |1: - | ldrd CARG12, NODE:INS->key - | ldr CARG4, NODE:INS->val.it - | ldr NODE:CARG3, NODE:INS->next - | checktp CARG2, LJ_TSTR - | cmpeq CARG1, STR:RC - | bne >5 - | ldrb CARG2, TAB:RB->marked - | checktp CARG4, LJ_TNIL // Key found, but nil value? - | ldrd CARG34, [BASE, RA] - | beq >4 - |2: - | tst CARG2, #LJ_GC_BLACK // isblack(table) - | strd CARG34, NODE:INS->val - | bne >7 - |3: - | ins_next - | - |4: // Check for __newindex if previous value is nil. - | ldr TAB:CARG1, TAB:RB->metatable - | cmp TAB:CARG1, #0 - | beq <2 // No metatable: done. - | ldrb CARG1, TAB:CARG1->nomm - | tst CARG1, #1<vmeta_tsets - | - |5: // Follow hash chain. - | movs NODE:INS, NODE:CARG3 - | bne <1 - | // End of hash chain: key not found, add a new one. - | - | // But check for __newindex first. - | ldr TAB:CARG1, TAB:RB->metatable - | mov CARG3, TMPDp - | str PC, SAVE_PC - | cmp TAB:CARG1, #0 // No metatable: continue. - | str BASE, L->base - | ldrbne CARG2, TAB:CARG1->nomm - | mov CARG1, L - | beq >6 - | tst CARG2, #1<vmeta_tsets // 'no __newindex' flag NOT set: check. - |6: - | mvn CARG4, #~LJ_TSTR - | str STR:RC, TMPDlo - | mov CARG2, TAB:RB - | str CARG4, TMPDhi - | bl extern lj_tab_newkey // (lua_State *L, GCtab *t, TValue *k) - | // Returns TValue *. - | ldr BASE, L->base - | ldrd CARG34, [BASE, RA] - | strd CARG34, [CRET1] - | b <3 // No 2nd write barrier needed. - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:RB, CARG2, CARG3 - | b <3 - break; - case BC_TSETB: - | decode_RB8 RB, INS - | and RC, RC, #255 - | // RA = src*8, RB = table*8, RC = index - | ldrd CARG12, [BASE, RB] - | checktab CARG2, ->vmeta_tsetb // STALL: load CARG12. - | ldr CARG3, TAB:CARG1->asize - | ldr RB, TAB:CARG1->array - | lsl CARG2, RC, #3 - | cmp RC, CARG3 - | ldrdlo CARG34, [CARG2, RB]! - | bhs ->vmeta_tsetb - | ins_next1 // Overwrites RB! - | checktp CARG4, LJ_TNIL - | ldrb INS, TAB:CARG1->marked - | ldrd CARG34, [BASE, RA] - | beq >5 - |1: - | tst INS, #LJ_GC_BLACK // isblack(table) - | strd CARG34, [CARG2] - | bne >7 - |2: - | ins_next2 - | ins_next3 - | - |5: // Check for __newindex if previous value is nil. - | ldr TAB:RA, TAB:CARG1->metatable - | cmp TAB:RA, #0 - | beq <1 // No metatable: done. - | ldrb RA, TAB:RA->nomm - | tst RA, #1<vmeta_tsetb - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:CARG1, INS, CARG3 - | b <2 - break; - case BC_TSETR: - | decode_RB8 RB, INS - | decode_RC8 RC, INS - | // RA = src*8, RB = table*8, RC = key*8 - | ldr TAB:CARG2, [BASE, RB] - | ldr CARG3, [BASE, RC] - | ldrb INS, TAB:CARG2->marked - | ldr CARG1, TAB:CARG2->array - | ldr CARG4, TAB:CARG2->asize - | tst INS, #LJ_GC_BLACK // isblack(table) - | add CARG1, CARG1, CARG3, lsl #3 - | bne >7 - |2: - | cmp CARG3, CARG4 // In array part? - | bhs ->vmeta_tsetr - |->BC_TSETR_Z: - | ldrd CARG34, [BASE, RA] - | ins_next1 - | ins_next2 - | strd CARG34, [CARG1] - | ins_next3 - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:CARG2, INS, RB - | b <2 - break; - - case BC_TSETM: - | // RA = base*8 (table at base-1), RC = num_const (start index) - | add RA, BASE, RA - |1: - | ldr RB, SAVE_MULTRES - | ldr TAB:CARG2, [RA, #-8] // Guaranteed to be a table. - | ldr CARG1, [KBASE, RC, lsl #3] // Integer constant is in lo-word. - | subs RB, RB, #8 - | ldr CARG4, TAB:CARG2->asize - | beq >4 // Nothing to copy? - | add CARG3, CARG1, RB, lsr #3 - | cmp CARG3, CARG4 - | ldr CARG4, TAB:CARG2->array - | add RB, RA, RB - | bhi >5 - | add INS, CARG4, CARG1, lsl #3 - | ldrb CARG1, TAB:CARG2->marked - |3: // Copy result slots to table. - | ldrd CARG34, [RA], #8 - | strd CARG34, [INS], #8 - | cmp RA, RB - | blo <3 - | tst CARG1, #LJ_GC_BLACK // isblack(table) - | bne >7 - |4: - | ins_next - | - |5: // Need to resize array part. - | str BASE, L->base - | mov CARG1, L - | str PC, SAVE_PC - | bl extern lj_tab_reasize // (lua_State *L, GCtab *t, int nasize) - | // Must not reallocate the stack. - | .IOS ldr BASE, L->base - | b <1 - | - |7: // Possible table write barrier for any value. Skip valiswhite check. - | barrierback TAB:CARG2, CARG1, CARG3 - | b <4 - break; - - /* -- Calls and vararg handling ----------------------------------------- */ - - case BC_CALLM: - | // RA = base*8, (RB = nresults+1,) RC = extra_nargs - | ldr CARG1, SAVE_MULTRES - | decode_RC8 NARGS8:RC, INS - | add NARGS8:RC, NARGS8:RC, CARG1 - | b ->BC_CALL_Z - break; - case BC_CALL: - | decode_RC8 NARGS8:RC, INS - | // RA = base*8, (RB = nresults+1,) RC = (nargs+1)*8 - |->BC_CALL_Z: - | mov RB, BASE // Save old BASE for vmeta_call. - | ldrd CARG34, [BASE, RA]! - | sub NARGS8:RC, NARGS8:RC, #8 - | add BASE, BASE, #8 - | checkfunc CARG4, ->vmeta_call - | ins_call - break; - - case BC_CALLMT: - | // RA = base*8, (RB = 0,) RC = extra_nargs - | ldr CARG1, SAVE_MULTRES - | add NARGS8:RC, CARG1, RC, lsl #3 - | b ->BC_CALLT1_Z - break; - case BC_CALLT: - | lsl NARGS8:RC, RC, #3 - | // RA = base*8, (RB = 0,) RC = (nargs+1)*8 - |->BC_CALLT1_Z: - | ldrd LFUNC:CARG34, [RA, BASE]! - | sub NARGS8:RC, NARGS8:RC, #8 - | add RA, RA, #8 - | checkfunc CARG4, ->vmeta_callt - | ldr PC, [BASE, FRAME_PC] - |->BC_CALLT2_Z: - | mov RB, #0 - | ldrb CARG4, LFUNC:CARG3->ffid - | tst PC, #FRAME_TYPE - | bne >7 - |1: - | str LFUNC:CARG3, [BASE, FRAME_FUNC] // Copy function down, but keep PC. - | cmp NARGS8:RC, #0 - | beq >3 - |2: - | ldrd CARG12, [RA, RB] - | add INS, RB, #8 - | cmp INS, NARGS8:RC - | strd CARG12, [BASE, RB] - | mov RB, INS - | bne <2 - |3: - | cmp CARG4, #1 // (> FF_C) Calling a fast function? - | bhi >5 - |4: - | ins_callt - | - |5: // Tailcall to a fast function with a Lua frame below. - | ldr INS, [PC, #-4] - | decode_RA8 RA, INS - | sub CARG1, BASE, RA - | ldr LFUNC:CARG1, [CARG1, #-16] - | ldr CARG1, LFUNC:CARG1->field_pc - | ldr KBASE, [CARG1, #PC2PROTO(k)] - | b <4 - | - |7: // Tailcall from a vararg function. - | eor PC, PC, #FRAME_VARG - | tst PC, #FRAME_TYPEP // Vararg frame below? - | movne CARG4, #0 // Clear ffid if no Lua function below. - | bne <1 - | sub BASE, BASE, PC - | ldr PC, [BASE, FRAME_PC] - | tst PC, #FRAME_TYPE - | movne CARG4, #0 // Clear ffid if no Lua function below. - | b <1 - break; - - case BC_ITERC: - | // RA = base*8, (RB = nresults+1, RC = nargs+1 (2+1)) - | add RA, BASE, RA - | mov RB, BASE // Save old BASE for vmeta_call. - | ldrd CARG34, [RA, #-16] - | ldrd CARG12, [RA, #-8] - | add BASE, RA, #8 - | strd CARG34, [RA, #8] // Copy state. - | strd CARG12, [RA, #16] // Copy control var. - | // STALL: locked CARG34. - | ldrd LFUNC:CARG34, [RA, #-24] - | mov NARGS8:RC, #16 // Iterators get 2 arguments. - | // STALL: load CARG34. - | strd LFUNC:CARG34, [RA] // Copy callable. - | checkfunc CARG4, ->vmeta_call - | ins_call - break; - - case BC_ITERN: - | // RA = base*8, (RB = nresults+1, RC = nargs+1 (2+1)) - |.if JIT - | // NYI: add hotloop, record BC_ITERN. - |.endif - | add RA, BASE, RA - | ldr TAB:RB, [RA, #-16] - | ldr CARG1, [RA, #-8] // Get index from control var. - | ldr INS, TAB:RB->asize - | ldr CARG2, TAB:RB->array - | add PC, PC, #4 - |1: // Traverse array part. - | subs RC, CARG1, INS - | add CARG3, CARG2, CARG1, lsl #3 - | bhs >5 // Index points after array part? - | ldrd CARG34, [CARG3] - | checktp CARG4, LJ_TNIL - | addeq CARG1, CARG1, #1 // Skip holes in array part. - | beq <1 - | ldrh RC, [PC, #-2] - | mvn CARG2, #~LJ_TISNUM - | strd CARG34, [RA, #8] - | add RC, PC, RC, lsl #2 - | add RB, CARG1, #1 - | strd CARG12, [RA] - | sub PC, RC, #0x20000 - | str RB, [RA, #-8] // Update control var. - |3: - | ins_next - | - |5: // Traverse hash part. - | ldr CARG4, TAB:RB->hmask - | ldr NODE:RB, TAB:RB->node - |6: - | add CARG1, RC, RC, lsl #1 - | cmp RC, CARG4 // End of iteration? Branch to ITERL+1. - | add NODE:CARG3, NODE:RB, CARG1, lsl #3 // node = tab->node + idx*3*8 - | bhi <3 - | ldrd CARG12, NODE:CARG3->val - | checktp CARG2, LJ_TNIL - | add RC, RC, #1 - | beq <6 // Skip holes in hash part. - | ldrh RB, [PC, #-2] - | add RC, RC, INS - | ldrd CARG34, NODE:CARG3->key - | str RC, [RA, #-8] // Update control var. - | strd CARG12, [RA, #8] - | add RC, PC, RB, lsl #2 - | sub PC, RC, #0x20000 - | strd CARG34, [RA] - | b <3 - break; - - case BC_ISNEXT: - | // RA = base*8, RC = target (points to ITERN) - | add RA, BASE, RA - | add RC, PC, RC, lsl #2 - | ldrd CFUNC:CARG12, [RA, #-24] - | ldr CARG3, [RA, #-12] - | ldr CARG4, [RA, #-4] - | checktp CARG2, LJ_TFUNC - | ldrbeq CARG1, CFUNC:CARG1->ffid - | checktpeq CARG3, LJ_TTAB - | checktpeq CARG4, LJ_TNIL - | cmpeq CARG1, #FF_next_N - | subeq PC, RC, #0x20000 - | bne >5 - | ins_next1 - | ins_next2 - | mov CARG1, #0 - | mvn CARG2, #0x00018000 - | strd CARG1, [RA, #-8] // Initialize control var. - |1: - | ins_next3 - |5: // Despecialize bytecode if any of the checks fail. - | mov CARG1, #BC_JMP - | mov OP, #BC_ITERC - | strb CARG1, [PC, #-4] - | sub PC, RC, #0x20000 - | strb OP, [PC] // Subsumes ins_next1. - | ins_next2 - | b <1 - break; - - case BC_VARG: - | decode_RB8 RB, INS - | decode_RC8 RC, INS - | // RA = base*8, RB = (nresults+1)*8, RC = numparams*8 - | ldr CARG1, [BASE, FRAME_PC] - | add RC, BASE, RC - | add RA, BASE, RA - | add RC, RC, #FRAME_VARG - | add CARG4, RA, RB - | sub CARG3, BASE, #8 // CARG3 = vtop - | sub RC, RC, CARG1 // RC = vbase - | // Note: RC may now be even _above_ BASE if nargs was < numparams. - | cmp RB, #0 - | sub CARG1, CARG3, RC - | beq >5 // Copy all varargs? - | sub CARG4, CARG4, #16 - |1: // Copy vararg slots to destination slots. - | cmp RC, CARG3 - | ldrdlo CARG12, [RC], #8 - | mvnhs CARG2, #~LJ_TNIL - | cmp RA, CARG4 - | strd CARG12, [RA], #8 - | blo <1 - |2: - | ins_next - | - |5: // Copy all varargs. - | ldr CARG4, L->maxstack - | cmp CARG1, #0 - | movle RB, #8 // MULTRES = (0+1)*8 - | addgt RB, CARG1, #8 - | add CARG2, RA, CARG1 - | str RB, SAVE_MULTRES - | ble <2 - | cmp CARG2, CARG4 - | bhi >7 - |6: - | ldrd CARG12, [RC], #8 - | strd CARG12, [RA], #8 - | cmp RC, CARG3 - | blo <6 - | b <2 - | - |7: // Grow stack for varargs. - | lsr CARG2, CARG1, #3 - | str RA, L->top - | mov CARG1, L - | str BASE, L->base - | sub RC, RC, BASE // Need delta, because BASE may change. - | str PC, SAVE_PC - | sub RA, RA, BASE - | bl extern lj_state_growstack // (lua_State *L, int n) - | ldr BASE, L->base - | add RA, BASE, RA - | add RC, BASE, RC - | sub CARG3, BASE, #8 - | b <6 - break; - - /* -- Returns ----------------------------------------------------------- */ - - case BC_RETM: - | // RA = results*8, RC = extra results - | ldr CARG1, SAVE_MULTRES - | ldr PC, [BASE, FRAME_PC] - | add RA, BASE, RA - | add RC, CARG1, RC, lsl #3 - | b ->BC_RETM_Z - break; - - case BC_RET: - | // RA = results*8, RC = nresults+1 - | ldr PC, [BASE, FRAME_PC] - | lsl RC, RC, #3 - | add RA, BASE, RA - |->BC_RETM_Z: - | str RC, SAVE_MULTRES - |1: - | ands CARG1, PC, #FRAME_TYPE - | eor CARG2, PC, #FRAME_VARG - | bne ->BC_RETV2_Z - | - |->BC_RET_Z: - | // BASE = base, RA = resultptr, RC = (nresults+1)*8, PC = return - | ldr INS, [PC, #-4] - | subs CARG4, RC, #8 - | sub CARG3, BASE, #8 - | beq >3 - |2: - | ldrd CARG12, [RA], #8 - | add BASE, BASE, #8 - | subs CARG4, CARG4, #8 - | strd CARG12, [BASE, #-16] - | bne <2 - |3: - | decode_RA8 RA, INS - | sub CARG4, CARG3, RA - | decode_RB8 RB, INS - | ldr LFUNC:CARG1, [CARG4, FRAME_FUNC] - |5: - | cmp RB, RC // More results expected? - | bhi >6 - | mov BASE, CARG4 - | ldr CARG2, LFUNC:CARG1->field_pc - | ins_next1 - | ins_next2 - | ldr KBASE, [CARG2, #PC2PROTO(k)] - | ins_next3 - | - |6: // Fill up results with nil. - | mvn CARG2, #~LJ_TNIL - | add BASE, BASE, #8 - | add RC, RC, #8 - | str CARG2, [BASE, #-12] - | b <5 - | - |->BC_RETV1_Z: // Non-standard return case. - | add RA, BASE, RA - |->BC_RETV2_Z: - | tst CARG2, #FRAME_TYPEP - | bne ->vm_return - | // Return from vararg function: relocate BASE down. - | sub BASE, BASE, CARG2 - | ldr PC, [BASE, FRAME_PC] - | b <1 - break; - - case BC_RET0: case BC_RET1: - | // RA = results*8, RC = nresults+1 - | ldr PC, [BASE, FRAME_PC] - | lsl RC, RC, #3 - | str RC, SAVE_MULTRES - | ands CARG1, PC, #FRAME_TYPE - | eor CARG2, PC, #FRAME_VARG - | ldreq INS, [PC, #-4] - | bne ->BC_RETV1_Z - if (op == BC_RET1) { - | ldrd CARG12, [BASE, RA] - } - | sub CARG4, BASE, #8 - | decode_RA8 RA, INS - if (op == BC_RET1) { - | strd CARG12, [CARG4] - } - | sub BASE, CARG4, RA - | decode_RB8 RB, INS - | ldr LFUNC:CARG1, [BASE, FRAME_FUNC] - |5: - | cmp RB, RC - | bhi >6 - | ldr CARG2, LFUNC:CARG1->field_pc - | ins_next1 - | ins_next2 - | ldr KBASE, [CARG2, #PC2PROTO(k)] - | ins_next3 - | - |6: // Fill up results with nil. - | sub CARG2, CARG4, #4 - | mvn CARG3, #~LJ_TNIL - | str CARG3, [CARG2, RC] - | add RC, RC, #8 - | b <5 - break; - - /* -- Loops and branches ------------------------------------------------ */ - - |.define FOR_IDX, [RA]; .define FOR_TIDX, [RA, #4] - |.define FOR_STOP, [RA, #8]; .define FOR_TSTOP, [RA, #12] - |.define FOR_STEP, [RA, #16]; .define FOR_TSTEP, [RA, #20] - |.define FOR_EXT, [RA, #24]; .define FOR_TEXT, [RA, #28] - - case BC_FORL: - |.if JIT - | hotloop - |.endif - | // Fall through. Assumes BC_IFORL follows. - break; - - case BC_JFORI: - case BC_JFORL: -#if !LJ_HASJIT - break; -#endif - case BC_FORI: - case BC_IFORL: - | // RA = base*8, RC = target (after end of loop or start of loop) - vk = (op == BC_IFORL || op == BC_JFORL); - | ldrd CARG12, [RA, BASE]! - if (op != BC_JFORL) { - | add RC, PC, RC, lsl #2 - } - if (!vk) { - | ldrd CARG34, FOR_STOP - | checktp CARG2, LJ_TISNUM - | ldr RB, FOR_TSTEP - | bne >5 - | checktp CARG4, LJ_TISNUM - | ldr CARG4, FOR_STEP - | checktpeq RB, LJ_TISNUM - | bne ->vmeta_for - | cmp CARG4, #0 - | blt >4 - | cmp CARG1, CARG3 - } else { - | ldrd CARG34, FOR_STEP - | checktp CARG2, LJ_TISNUM - | bne >5 - | adds CARG1, CARG1, CARG3 - | ldr CARG4, FOR_STOP - if (op == BC_IFORL) { - | addvs RC, PC, #0x20000 // Overflow: prevent branch. - } else { - | bvs >2 // Overflow: do not enter mcode. - } - | cmp CARG3, #0 - | blt >4 - | cmp CARG1, CARG4 - } - |1: - if (op == BC_FORI) { - | subgt PC, RC, #0x20000 - } else if (op == BC_JFORI) { - | sub PC, RC, #0x20000 - | ldrhle RC, [PC, #-2] - } else if (op == BC_IFORL) { - | suble PC, RC, #0x20000 - } - if (vk) { - | strd CARG12, FOR_IDX - } - |2: - | ins_next1 - | ins_next2 - | strd CARG12, FOR_EXT - if (op == BC_JFORI || op == BC_JFORL) { - | ble =>BC_JLOOP - } - |3: - | ins_next3 - | - |4: // Invert check for negative step. - if (!vk) { - | cmp CARG3, CARG1 - } else { - | cmp CARG4, CARG1 - } - | b <1 - | - |5: // FP loop. - if (!vk) { - | cmnlo CARG4, #-LJ_TISNUM - | cmnlo RB, #-LJ_TISNUM - | bhs ->vmeta_for - |.if FPU - | vldr d0, FOR_IDX - | vldr d1, FOR_STOP - | cmp RB, #0 - | vstr d0, FOR_EXT - |.else - | cmp RB, #0 - | strd CARG12, FOR_EXT - | blt >8 - |.endif - } else { - |.if FPU - | vldr d0, FOR_IDX - | vldr d2, FOR_STEP - | vldr d1, FOR_STOP - | cmp CARG4, #0 - | vadd.f64 d0, d0, d2 - |.else - | cmp CARG4, #0 - | blt >8 - | bl extern __aeabi_dadd - | strd CARG12, FOR_IDX - | ldrd CARG34, FOR_STOP - | strd CARG12, FOR_EXT - |.endif - } - |6: - |.if FPU - | vcmpge.f64 d0, d1 - | vcmplt.f64 d1, d0 - | vmrs - |.else - | bl extern __aeabi_cdcmple - |.endif - if (vk) { - |.if FPU - | vstr d0, FOR_IDX - | vstr d0, FOR_EXT - |.endif - } - if (op == BC_FORI) { - | subhi PC, RC, #0x20000 - } else if (op == BC_JFORI) { - | sub PC, RC, #0x20000 - | ldrhls RC, [PC, #-2] - | bls =>BC_JLOOP - } else if (op == BC_IFORL) { - | subls PC, RC, #0x20000 - } else { - | bls =>BC_JLOOP - } - | ins_next1 - | ins_next2 - | b <3 - | - |.if not FPU - |8: // Invert check for negative step. - if (vk) { - | bl extern __aeabi_dadd - | strd CARG12, FOR_IDX - | strd CARG12, FOR_EXT - } - | mov CARG3, CARG1 - | mov CARG4, CARG2 - | ldrd CARG12, FOR_STOP - | b <6 - |.endif - break; - - case BC_ITERL: - |.if JIT - | hotloop - |.endif - | // Fall through. Assumes BC_IITERL follows. - break; - - case BC_JITERL: -#if !LJ_HASJIT - break; -#endif - case BC_IITERL: - | // RA = base*8, RC = target - | ldrd CARG12, [RA, BASE]! - if (op == BC_JITERL) { - | cmn CARG2, #-LJ_TNIL // Stop if iterator returned nil. - | strdne CARG12, [RA, #-8] - | bne =>BC_JLOOP - } else { - | add RC, PC, RC, lsl #2 - | // STALL: load CARG12. - | cmn CARG2, #-LJ_TNIL // Stop if iterator returned nil. - | subne PC, RC, #0x20000 // Otherwise save control var + branch. - | strdne CARG12, [RA, #-8] - } - | ins_next - break; - - case BC_LOOP: - | // RA = base*8, RC = target (loop extent) - | // Note: RA/RC is only used by trace recorder to determine scope/extent - | // This opcode does NOT jump, it's only purpose is to detect a hot loop. - |.if JIT - | hotloop - |.endif - | // Fall through. Assumes BC_ILOOP follows. - break; - - case BC_ILOOP: - | // RA = base*8, RC = target (loop extent) - | ins_next - break; - - case BC_JLOOP: - |.if JIT - | // RA = base (ignored), RC = traceno - | ldr CARG1, [DISPATCH, #DISPATCH_J(trace)] - | mov CARG2, #0 // Traces on ARM don't store the trace number, so use 0. - | ldr TRACE:RC, [CARG1, RC, lsl #2] - | st_vmstate CARG2 - | ldr RA, TRACE:RC->mcode - | str BASE, [DISPATCH, #DISPATCH_GL(jit_base)] - | str L, [DISPATCH, #DISPATCH_GL(tmpbuf.L)] - | bx RA - |.endif - break; - - case BC_JMP: - | // RA = base*8 (only used by trace recorder), RC = target - | add RC, PC, RC, lsl #2 - | sub PC, RC, #0x20000 - | ins_next - break; - - /* -- Function headers -------------------------------------------------- */ - - case BC_FUNCF: - |.if JIT - | hotcall - |.endif - case BC_FUNCV: /* NYI: compiled vararg functions. */ - | // Fall through. Assumes BC_IFUNCF/BC_IFUNCV follow. - break; - - case BC_JFUNCF: -#if !LJ_HASJIT - break; -#endif - case BC_IFUNCF: - | // BASE = new base, RA = BASE+framesize*8, CARG3 = LFUNC, RC = nargs*8 - | ldr CARG1, L->maxstack - | ldrb CARG2, [PC, #-4+PC2PROTO(numparams)] - | ldr KBASE, [PC, #-4+PC2PROTO(k)] - | cmp RA, CARG1 - | bhi ->vm_growstack_l - if (op != BC_JFUNCF) { - | ins_next1 - | ins_next2 - } - |2: - | cmp NARGS8:RC, CARG2, lsl #3 // Check for missing parameters. - | mvn CARG4, #~LJ_TNIL - | blo >3 - if (op == BC_JFUNCF) { - | decode_RD RC, INS - | b =>BC_JLOOP - } else { - | ins_next3 - } - | - |3: // Clear missing parameters. - | strd CARG34, [BASE, NARGS8:RC] - | add NARGS8:RC, NARGS8:RC, #8 - | b <2 - break; - - case BC_JFUNCV: -#if !LJ_HASJIT - break; -#endif - | NYI // NYI: compiled vararg functions - break; /* NYI: compiled vararg functions. */ - - case BC_IFUNCV: - | // BASE = new base, RA = BASE+framesize*8, CARG3 = LFUNC, RC = nargs*8 - | ldr CARG1, L->maxstack - | add CARG4, BASE, RC - | add RA, RA, RC - | str LFUNC:CARG3, [CARG4] // Store copy of LFUNC. - | add CARG2, RC, #8+FRAME_VARG - | ldr KBASE, [PC, #-4+PC2PROTO(k)] - | cmp RA, CARG1 - | str CARG2, [CARG4, #4] // Store delta + FRAME_VARG. - | bhs ->vm_growstack_l - | ldrb RB, [PC, #-4+PC2PROTO(numparams)] - | mov RA, BASE - | mov RC, CARG4 - | cmp RB, #0 - | add BASE, CARG4, #8 - | beq >3 - | mvn CARG3, #~LJ_TNIL - |1: - | cmp RA, RC // Less args than parameters? - | ldrdlo CARG12, [RA], #8 - | movhs CARG2, CARG3 - | strlo CARG3, [RA, #-4] // Clear old fixarg slot (help the GC). - |2: - | subs RB, RB, #1 - | strd CARG12, [CARG4, #8]! - | bne <1 - |3: - | ins_next - break; - - case BC_FUNCC: - case BC_FUNCCW: - | // BASE = new base, RA = BASE+framesize*8, CARG3 = CFUNC, RC = nargs*8 - if (op == BC_FUNCC) { - | ldr CARG4, CFUNC:CARG3->f - } else { - | ldr CARG4, [DISPATCH, #DISPATCH_GL(wrapf)] - } - | add CARG2, RA, NARGS8:RC - | ldr CARG1, L->maxstack - | add RC, BASE, NARGS8:RC - | str BASE, L->base - | cmp CARG2, CARG1 - | str RC, L->top - if (op == BC_FUNCCW) { - | ldr CARG2, CFUNC:CARG3->f - } - | mv_vmstate CARG3, C - | mov CARG1, L - | bhi ->vm_growstack_c // Need to grow stack. - | st_vmstate CARG3 - | blx CARG4 // (lua_State *L [, lua_CFunction f]) - | // Returns nresults. - | ldr BASE, L->base - | mv_vmstate CARG3, INTERP - | ldr CRET2, L->top - | str L, [DISPATCH, #DISPATCH_GL(cur_L)] - | lsl RC, CRET1, #3 - | st_vmstate CARG3 - | ldr PC, [BASE, FRAME_PC] - | sub RA, CRET2, RC // RA = L->top - nresults*8 - | b ->vm_returnc - break; - - /* ---------------------------------------------------------------------- */ - - default: - fprintf(stderr, "Error: undefined opcode BC_%s\n", bc_names[op]); - exit(2); - break; - } -} - -static int build_backend(BuildCtx *ctx) -{ - int op; - - dasm_growpc(Dst, BC__MAX); - - build_subroutines(ctx); - - |.code_op - for (op = 0; op < BC__MAX; op++) - build_ins(ctx, (BCOp)op, op); - - return BC__MAX; -} - -/* Emit pseudo frame-info for all assembler functions. */ -static void emit_asm_debug(BuildCtx *ctx) -{ - int fcofs = (int)((uint8_t *)ctx->glob[GLOB_vm_ffi_call] - ctx->code); - int i; - switch (ctx->mode) { - case BUILD_elfasm: - fprintf(ctx->fp, "\t.section .debug_frame,\"\",%%progbits\n"); - fprintf(ctx->fp, - ".Lframe0:\n" - "\t.long .LECIE0-.LSCIE0\n" - ".LSCIE0:\n" - "\t.long 0xffffffff\n" - "\t.byte 0x1\n" - "\t.string \"\"\n" - "\t.uleb128 0x1\n" - "\t.sleb128 -4\n" - "\t.byte 0xe\n" /* Return address is in lr. */ - "\t.byte 0xc\n\t.uleb128 0xd\n\t.uleb128 0\n" /* def_cfa sp */ - "\t.align 2\n" - ".LECIE0:\n\n"); - fprintf(ctx->fp, - ".LSFDE0:\n" - "\t.long .LEFDE0-.LASFDE0\n" - ".LASFDE0:\n" - "\t.long .Lframe0\n" - "\t.long .Lbegin\n" - "\t.long %d\n" - "\t.byte 0xe\n\t.uleb128 %d\n" /* def_cfa_offset */ - "\t.byte 0x8e\n\t.uleb128 1\n", /* offset lr */ - fcofs, CFRAME_SIZE); - for (i = 11; i >= (LJ_ARCH_HASFPU ? 5 : 4); i--) /* offset r4-r11 */ - fprintf(ctx->fp, "\t.byte %d\n\t.uleb128 %d\n", 0x80+i, 2+(11-i)); -#if LJ_ARCH_HASFPU - for (i = 15; i >= 8; i--) /* offset d8-d15 */ - fprintf(ctx->fp, "\t.byte 5\n\t.uleb128 %d, %d\n", - 64+2*i, 10+2*(15-i)); - fprintf(ctx->fp, "\t.byte 0x84\n\t.uleb128 %d\n", 25); /* offset r4 */ -#endif - fprintf(ctx->fp, - "\t.align 2\n" - ".LEFDE0:\n\n"); -#if LJ_HASFFI - fprintf(ctx->fp, - ".LSFDE1:\n" - "\t.long .LEFDE1-.LASFDE1\n" - ".LASFDE1:\n" - "\t.long .Lframe0\n" - "\t.long lj_vm_ffi_call\n" - "\t.long %d\n" - "\t.byte 0xe\n\t.uleb128 16\n" /* def_cfa_offset */ - "\t.byte 0x8e\n\t.uleb128 1\n" /* offset lr */ - "\t.byte 0x8b\n\t.uleb128 2\n" /* offset r11 */ - "\t.byte 0x85\n\t.uleb128 3\n" /* offset r5 */ - "\t.byte 0x84\n\t.uleb128 4\n" /* offset r4 */ - "\t.byte 0xd\n\t.uleb128 0xb\n" /* def_cfa_register r11 */ - "\t.align 2\n" - ".LEFDE1:\n\n", (int)ctx->codesz - fcofs); -#endif - break; - default: - break; - } -} - diff --git a/lib/LuaJIT/src/vm_arm64.dasc b/lib/LuaJIT/src/vm_arm64.dasc deleted file mode 100644 index fb226e3..0000000 --- a/lib/LuaJIT/src/vm_arm64.dasc +++ /dev/null @@ -1,3988 +0,0 @@ -|// Low-level VM code for ARM64 CPUs. -|// Bytecode interpreter, fast functions and helper functions. -|// Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -| -|.arch arm64 -|.section code_op, code_sub -| -|.actionlist build_actionlist -|.globals GLOB_ -|.globalnames globnames -|.externnames extnames -| -|// Note: The ragged indentation of the instructions is intentional. -|// The starting columns indicate data dependencies. -| -|//----------------------------------------------------------------------- -| -|// ARM64 registers and the AAPCS64 ABI 1.0 at a glance: -|// -|// x0-x17 temp, x19-x28 callee-saved, x29 fp, x30 lr -|// x18 is reserved on most platforms. Don't use it, save it or restore it. -|// x31 doesn't exist. Register number 31 either means xzr/wzr (zero) or sp, -|// depending on the instruction. -|// v0-v7 temp, v8-v15 callee-saved (only d8-d15 preserved), v16-v31 temp -|// -|// x0-x7/v0-v7 hold parameters and results. -| -|// Fixed register assignments for the interpreter. -| -|// The following must be C callee-save. -|.define BASE, x19 // Base of current Lua stack frame. -|.define KBASE, x20 // Constants of current Lua function. -|.define PC, x21 // Next PC. -|.define GLREG, x22 // Global state. -|.define LREG, x23 // Register holding lua_State (also in SAVE_L). -|.define TISNUM, x24 // Constant LJ_TISNUM << 47. -|.define TISNUMhi, x25 // Constant LJ_TISNUM << 15. -|.define TISNIL, x26 // Constant -1LL. -|.define fp, x29 // Yes, we have to maintain a frame pointer. -| -|.define ST_INTERP, w26 // Constant -1. -| -|// The following temporaries are not saved across C calls, except for RA/RC. -|.define RA, x27 -|.define RC, x28 -|.define RB, x17 -|.define RAw, w27 -|.define RCw, w28 -|.define RBw, w17 -|.define INS, x16 -|.define INSw, w16 -|.define ITYPE, x15 -|.define TMP0, x8 -|.define TMP1, x9 -|.define TMP2, x10 -|.define TMP3, x11 -|.define TMP0w, w8 -|.define TMP1w, w9 -|.define TMP2w, w10 -|.define TMP3w, w11 -| -|// Calling conventions. Also used as temporaries. -|.define CARG1, x0 -|.define CARG2, x1 -|.define CARG3, x2 -|.define CARG4, x3 -|.define CARG5, x4 -|.define CARG1w, w0 -|.define CARG2w, w1 -|.define CARG3w, w2 -|.define CARG4w, w3 -|.define CARG5w, w4 -| -|.define FARG1, d0 -|.define FARG2, d1 -| -|.define CRET1, x0 -|.define CRET1w, w0 -| -|// Stack layout while in interpreter. Must match with lj_frame.h. -| -|.define CFRAME_SPACE, 208 -|//----- 16 byte aligned, <-- sp entering interpreter -|// Unused [sp, #204] // 32 bit values -|.define SAVE_NRES, [sp, #200] -|.define SAVE_ERRF, [sp, #196] -|.define SAVE_MULTRES, [sp, #192] -|.define TMPD, [sp, #184] // 64 bit values -|.define SAVE_L, [sp, #176] -|.define SAVE_PC, [sp, #168] -|.define SAVE_CFRAME, [sp, #160] -|.define SAVE_FPR_, 96 // 96+8*8: 64 bit FPR saves -|.define SAVE_GPR_, 16 // 16+10*8: 64 bit GPR saves -|.define SAVE_LR, [sp, #8] -|.define SAVE_FP, [sp] -|//----- 16 byte aligned, <-- sp while in interpreter. -| -|.define TMPDofs, #184 -| -|.macro save_, gpr1, gpr2, fpr1, fpr2 -| stp d..fpr1, d..fpr2, [sp, # SAVE_FPR_+(fpr1-8)*8] -| stp x..gpr1, x..gpr2, [sp, # SAVE_GPR_+(gpr1-19)*8] -|.endmacro -|.macro rest_, gpr1, gpr2, fpr1, fpr2 -| ldp d..fpr1, d..fpr2, [sp, # SAVE_FPR_+(fpr1-8)*8] -| ldp x..gpr1, x..gpr2, [sp, # SAVE_GPR_+(gpr1-19)*8] -|.endmacro -| -|.macro saveregs -| stp fp, lr, [sp, #-CFRAME_SPACE]! -| add fp, sp, #0 -| stp x19, x20, [sp, # SAVE_GPR_] -| save_ 21, 22, 8, 9 -| save_ 23, 24, 10, 11 -| save_ 25, 26, 12, 13 -| save_ 27, 28, 14, 15 -|.endmacro -|.macro restoreregs -| ldp x19, x20, [sp, # SAVE_GPR_] -| rest_ 21, 22, 8, 9 -| rest_ 23, 24, 10, 11 -| rest_ 25, 26, 12, 13 -| rest_ 27, 28, 14, 15 -| ldp fp, lr, [sp], # CFRAME_SPACE -|.endmacro -| -|// Type definitions. Some of these are only used for documentation. -|.type L, lua_State, LREG -|.type GL, global_State, GLREG -|.type TVALUE, TValue -|.type GCOBJ, GCobj -|.type STR, GCstr -|.type TAB, GCtab -|.type LFUNC, GCfuncL -|.type CFUNC, GCfuncC -|.type PROTO, GCproto -|.type UPVAL, GCupval -|.type NODE, Node -|.type NARGS8, int -|.type TRACE, GCtrace -|.type SBUF, SBuf -| -|//----------------------------------------------------------------------- -| -|// Trap for not-yet-implemented parts. -|.macro NYI; brk; .endmacro -| -|//----------------------------------------------------------------------- -| -|// Access to frame relative to BASE. -|.define FRAME_FUNC, #-16 -|.define FRAME_PC, #-8 -| -|// Endian-specific defines. -|.if ENDIAN_LE -|.define LO, 0 -|.define OFS_RD, 2 -|.define OFS_RB, 3 -|.define OFS_RA, 1 -|.define OFS_OP, 0 -|.else -|.define LO, 4 -|.define OFS_RD, 0 -|.define OFS_RB, 0 -|.define OFS_RA, 2 -|.define OFS_OP, 3 -|.endif -| -|.macro decode_RA, dst, ins; ubfx dst, ins, #8, #8; .endmacro -|.macro decode_RB, dst, ins; ubfx dst, ins, #24, #8; .endmacro -|.macro decode_RC, dst, ins; ubfx dst, ins, #16, #8; .endmacro -|.macro decode_RD, dst, ins; ubfx dst, ins, #16, #16; .endmacro -|.macro decode_RC8RD, dst, src; ubfiz dst, src, #3, #8; .endmacro -| -|// Instruction decode+dispatch. -|.macro ins_NEXT -| ldr INSw, [PC], #4 -| add TMP1, GL, INS, uxtb #3 -| decode_RA RA, INS -| ldr TMP0, [TMP1, #GG_G2DISP] -| decode_RD RC, INS -| br TMP0 -|.endmacro -| -|// Instruction footer. -|.if 1 -| // Replicated dispatch. Less unpredictable branches, but higher I-Cache use. -| .define ins_next, ins_NEXT -| .define ins_next_, ins_NEXT -|.else -| // Common dispatch. Lower I-Cache use, only one (very) unpredictable branch. -| // Affects only certain kinds of benchmarks (and only with -j off). -| .macro ins_next -| b ->ins_next -| .endmacro -| .macro ins_next_ -| ->ins_next: -| ins_NEXT -| .endmacro -|.endif -| -|// Call decode and dispatch. -|.macro ins_callt -| // BASE = new base, CARG3 = LFUNC/CFUNC, RC = nargs*8, FRAME_PC(BASE) = PC -| ldr PC, LFUNC:CARG3->pc -| ldr INSw, [PC], #4 -| add TMP1, GL, INS, uxtb #3 -| decode_RA RA, INS -| ldr TMP0, [TMP1, #GG_G2DISP] -| add RA, BASE, RA, lsl #3 -| br TMP0 -|.endmacro -| -|.macro ins_call -| // BASE = new base, CARG3 = LFUNC/CFUNC, RC = nargs*8, PC = caller PC -| str PC, [BASE, FRAME_PC] -| ins_callt -|.endmacro -| -|//----------------------------------------------------------------------- -| -|// Macros to check the TValue type and extract the GCobj. Branch on failure. -|.macro checktp, reg, tp, target -| asr ITYPE, reg, #47 -| cmn ITYPE, #-tp -| and reg, reg, #LJ_GCVMASK -| bne target -|.endmacro -|.macro checktp, dst, reg, tp, target -| asr ITYPE, reg, #47 -| cmn ITYPE, #-tp -| and dst, reg, #LJ_GCVMASK -| bne target -|.endmacro -|.macro checkstr, reg, target; checktp reg, LJ_TSTR, target; .endmacro -|.macro checktab, reg, target; checktp reg, LJ_TTAB, target; .endmacro -|.macro checkfunc, reg, target; checktp reg, LJ_TFUNC, target; .endmacro -|.macro checkint, reg, target -| cmp TISNUMhi, reg, lsr #32 -| bne target -|.endmacro -|.macro checknum, reg, target -| cmp TISNUMhi, reg, lsr #32 -| bls target -|.endmacro -|.macro checknumber, reg, target -| cmp TISNUMhi, reg, lsr #32 -| blo target -|.endmacro -| -|.macro mov_false, reg; movn reg, #0x8000, lsl #32; .endmacro -|.macro mov_true, reg; movn reg, #0x0001, lsl #48; .endmacro -| -#define GL_J(field) (GG_G2J + (int)offsetof(jit_State, field)) -| -#define PC2PROTO(field) ((int)offsetof(GCproto, field)-(int)sizeof(GCproto)) -| -|.macro hotcheck, delta -| lsr CARG1, PC, #1 -| and CARG1, CARG1, #126 -| add CARG1, CARG1, #GG_G2DISP+GG_DISP2HOT -| ldrh CARG2w, [GL, CARG1] -| subs CARG2, CARG2, #delta -| strh CARG2w, [GL, CARG1] -|.endmacro -| -|.macro hotloop -| hotcheck HOTCOUNT_LOOP -| blo ->vm_hotloop -|.endmacro -| -|.macro hotcall -| hotcheck HOTCOUNT_CALL -| blo ->vm_hotcall -|.endmacro -| -|// Set current VM state. -|.macro mv_vmstate, reg, st; movn reg, #LJ_VMST_..st; .endmacro -|.macro st_vmstate, reg; str reg, GL->vmstate; .endmacro -| -|// Move table write barrier back. Overwrites mark and tmp. -|.macro barrierback, tab, mark, tmp -| ldr tmp, GL->gc.grayagain -| and mark, mark, #~LJ_GC_BLACK // black2gray(tab) -| str tab, GL->gc.grayagain -| strb mark, tab->marked -| str tmp, tab->gclist -|.endmacro -| -|//----------------------------------------------------------------------- - -#if !LJ_DUALNUM -#error "Only dual-number mode supported for ARM64 target" -#endif - -/* Generate subroutines used by opcodes and other parts of the VM. */ -/* The .code_sub section should be last to help static branch prediction. */ -static void build_subroutines(BuildCtx *ctx) -{ - |.code_sub - | - |//----------------------------------------------------------------------- - |//-- Return handling ---------------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_returnp: - | // See vm_return. Also: RB = previous base. - | tbz PC, #2, ->cont_dispatch // (PC & FRAME_P) == 0? - | - | // Return from pcall or xpcall fast func. - | ldr PC, [RB, FRAME_PC] // Fetch PC of previous frame. - | mov_true TMP0 - | mov BASE, RB - | // Prepending may overwrite the pcall frame, so do it at the end. - | str TMP0, [RA, #-8]! // Prepend true to results. - | - |->vm_returnc: - | adds RC, RC, #8 // RC = (nresults+1)*8. - | mov CRET1, #LUA_YIELD - | beq ->vm_unwind_c_eh - | str RCw, SAVE_MULTRES - | ands CARG1, PC, #FRAME_TYPE - | beq ->BC_RET_Z // Handle regular return to Lua. - | - |->vm_return: - | // BASE = base, RA = resultptr, RC/MULTRES = (nresults+1)*8, PC = return - | // CARG1 = PC & FRAME_TYPE - | and RB, PC, #~FRAME_TYPEP - | cmp CARG1, #FRAME_C - | sub RB, BASE, RB // RB = previous base. - | bne ->vm_returnp - | - | str RB, L->base - | ldrsw CARG2, SAVE_NRES // CARG2 = nresults+1. - | mv_vmstate TMP0w, C - | sub BASE, BASE, #16 - | subs TMP2, RC, #8 - | st_vmstate TMP0w - | beq >2 - |1: - | subs TMP2, TMP2, #8 - | ldr TMP0, [RA], #8 - | str TMP0, [BASE], #8 - | bne <1 - |2: - | cmp RC, CARG2, lsl #3 // More/less results wanted? - | bne >6 - |3: - | str BASE, L->top // Store new top. - | - |->vm_leave_cp: - | ldr RC, SAVE_CFRAME // Restore previous C frame. - | mov CRET1, #0 // Ok return status for vm_pcall. - | str RC, L->cframe - | - |->vm_leave_unw: - | restoreregs - | ret - | - |6: - | bgt >7 // Less results wanted? - | // More results wanted. Check stack size and fill up results with nil. - | ldr CARG3, L->maxstack - | cmp BASE, CARG3 - | bhs >8 - | str TISNIL, [BASE], #8 - | add RC, RC, #8 - | b <2 - | - |7: // Less results wanted. - | cbz CARG2, <3 // LUA_MULTRET+1 case? - | sub CARG1, RC, CARG2, lsl #3 - | sub BASE, BASE, CARG1 // Shrink top. - | b <3 - | - |8: // Corner case: need to grow stack for filling up results. - | // This can happen if: - | // - A C function grows the stack (a lot). - | // - The GC shrinks the stack in between. - | // - A return back from a lua_call() with (high) nresults adjustment. - | str BASE, L->top // Save current top held in BASE (yes). - | mov CARG1, L - | bl extern lj_state_growstack // (lua_State *L, int n) - | ldr BASE, L->top // Need the (realloced) L->top in BASE. - | ldrsw CARG2, SAVE_NRES - | b <2 - | - |->vm_unwind_c: // Unwind C stack, return from vm_pcall. - | // (void *cframe, int errcode) - | mov sp, CARG1 - | mov CRET1, CARG2 - |->vm_unwind_c_eh: // Landing pad for external unwinder. - | ldr L, SAVE_L - | mv_vmstate TMP0w, C - | ldr GL, L->glref - | st_vmstate TMP0w - | b ->vm_leave_unw - | - |->vm_unwind_ff: // Unwind C stack, return from ff pcall. - | // (void *cframe) - | and sp, CARG1, #CFRAME_RAWMASK - |->vm_unwind_ff_eh: // Landing pad for external unwinder. - | ldr L, SAVE_L - | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48 - | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16 - | movn TISNIL, #0 - | mov RC, #16 // 2 results: false + error message. - | ldr BASE, L->base - | ldr GL, L->glref // Setup pointer to global state. - | mov_false TMP0 - | sub RA, BASE, #8 // Results start at BASE-8. - | ldr PC, [BASE, FRAME_PC] // Fetch PC of previous frame. - | str TMP0, [BASE, #-8] // Prepend false to error message. - | st_vmstate ST_INTERP - | b ->vm_returnc - | - |//----------------------------------------------------------------------- - |//-- Grow stack for calls ----------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_growstack_c: // Grow stack for C function. - | // CARG1 = L - | mov CARG2, #LUA_MINSTACK - | b >2 - | - |->vm_growstack_l: // Grow stack for Lua function. - | // BASE = new base, RA = BASE+framesize*8, RC = nargs*8, PC = first PC - | add RC, BASE, RC - | sub RA, RA, BASE - | mov CARG1, L - | stp BASE, RC, L->base - | add PC, PC, #4 // Must point after first instruction. - | lsr CARG2, RA, #3 - |2: - | // L->base = new base, L->top = top - | str PC, SAVE_PC - | bl extern lj_state_growstack // (lua_State *L, int n) - | ldp BASE, RC, L->base - | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] - | sub NARGS8:RC, RC, BASE - | and LFUNC:CARG3, CARG3, #LJ_GCVMASK - | // BASE = new base, RB = LFUNC/CFUNC, RC = nargs*8, FRAME_PC(BASE) = PC - | ins_callt // Just retry the call. - | - |//----------------------------------------------------------------------- - |//-- Entry points into the assembler VM --------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_resume: // Setup C frame and resume thread. - | // (lua_State *L, TValue *base, int nres1 = 0, ptrdiff_t ef = 0) - | saveregs - | mov L, CARG1 - | ldr GL, L->glref // Setup pointer to global state. - | mov BASE, CARG2 - | str L, SAVE_L - | mov PC, #FRAME_CP - | str wzr, SAVE_NRES - | add TMP0, sp, #CFRAME_RESUME - | ldrb TMP1w, L->status - | str wzr, SAVE_ERRF - | str L, SAVE_PC // Any value outside of bytecode is ok. - | str xzr, SAVE_CFRAME - | str TMP0, L->cframe - | cbz TMP1w, >3 - | - | // Resume after yield (like a return). - | str L, GL->cur_L - | mov RA, BASE - | ldp BASE, CARG1, L->base - | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48 - | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16 - | ldr PC, [BASE, FRAME_PC] - | strb wzr, L->status - | movn TISNIL, #0 - | sub RC, CARG1, BASE - | ands CARG1, PC, #FRAME_TYPE - | add RC, RC, #8 - | st_vmstate ST_INTERP - | str RCw, SAVE_MULTRES - | beq ->BC_RET_Z - | b ->vm_return - | - |->vm_pcall: // Setup protected C frame and enter VM. - | // (lua_State *L, TValue *base, int nres1, ptrdiff_t ef) - | saveregs - | mov PC, #FRAME_CP - | str CARG4w, SAVE_ERRF - | b >1 - | - |->vm_call: // Setup C frame and enter VM. - | // (lua_State *L, TValue *base, int nres1) - | saveregs - | mov PC, #FRAME_C - | - |1: // Entry point for vm_pcall above (PC = ftype). - | ldr RC, L:CARG1->cframe - | str CARG3w, SAVE_NRES - | mov L, CARG1 - | str CARG1, SAVE_L - | ldr GL, L->glref // Setup pointer to global state. - | mov BASE, CARG2 - | str CARG1, SAVE_PC // Any value outside of bytecode is ok. - | str RC, SAVE_CFRAME - | str fp, L->cframe // Add our C frame to cframe chain. - | - |3: // Entry point for vm_cpcall/vm_resume (BASE = base, PC = ftype). - | str L, GL->cur_L - | ldp RB, CARG1, L->base // RB = old base (for vmeta_call). - | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48 - | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16 - | add PC, PC, BASE - | movn TISNIL, #0 - | sub PC, PC, RB // PC = frame delta + frame type - | sub NARGS8:RC, CARG1, BASE - | st_vmstate ST_INTERP - | - |->vm_call_dispatch: - | // RB = old base, BASE = new base, RC = nargs*8, PC = caller PC - | ldr CARG3, [BASE, FRAME_FUNC] - | checkfunc CARG3, ->vmeta_call - | - |->vm_call_dispatch_f: - | ins_call - | // BASE = new base, CARG3 = func, RC = nargs*8, PC = caller PC - | - |->vm_cpcall: // Setup protected C frame, call C. - | // (lua_State *L, lua_CFunction func, void *ud, lua_CPFunction cp) - | saveregs - | mov L, CARG1 - | ldr RA, L:CARG1->stack - | str CARG1, SAVE_L - | ldr GL, L->glref // Setup pointer to global state. - | ldr RB, L->top - | str CARG1, SAVE_PC // Any value outside of bytecode is ok. - | ldr RC, L->cframe - | sub RA, RA, RB // Compute -savestack(L, L->top). - | str RAw, SAVE_NRES // Neg. delta means cframe w/o frame. - | str wzr, SAVE_ERRF // No error function. - | str RC, SAVE_CFRAME - | str fp, L->cframe // Add our C frame to cframe chain. - | str L, GL->cur_L - | blr CARG4 // (lua_State *L, lua_CFunction func, void *ud) - | mov BASE, CRET1 - | mov PC, #FRAME_CP - | cbnz BASE, <3 // Else continue with the call. - | b ->vm_leave_cp // No base? Just remove C frame. - | - |//----------------------------------------------------------------------- - |//-- Metamethod handling ------------------------------------------------ - |//----------------------------------------------------------------------- - | - |//-- Continuation dispatch ---------------------------------------------- - | - |->cont_dispatch: - | // BASE = meta base, RA = resultptr, RC = (nresults+1)*8 - | ldr LFUNC:CARG3, [RB, FRAME_FUNC] - | ldr CARG1, [BASE, #-32] // Get continuation. - | mov CARG4, BASE - | mov BASE, RB // Restore caller BASE. - | and LFUNC:CARG3, CARG3, #LJ_GCVMASK - |.if FFI - | cmp CARG1, #1 - |.endif - | ldr PC, [CARG4, #-24] // Restore PC from [cont|PC]. - | ldr CARG3, LFUNC:CARG3->pc - | add TMP0, RA, RC - | str TISNIL, [TMP0, #-8] // Ensure one valid arg. - |.if FFI - | bls >1 - |.endif - | ldr KBASE, [CARG3, #PC2PROTO(k)] - | // BASE = base, RA = resultptr, CARG4 = meta base - | br CARG1 - | - |.if FFI - |1: - | beq ->cont_ffi_callback // cont = 1: return from FFI callback. - | // cont = 0: tailcall from C function. - | sub CARG4, CARG4, #32 - | sub RC, CARG4, BASE - | b ->vm_call_tail - |.endif - | - |->cont_cat: // RA = resultptr, CARG4 = meta base - | ldr INSw, [PC, #-4] - | sub CARG2, CARG4, #32 - | ldr TMP0, [RA] - | str BASE, L->base - | decode_RB RB, INS - | decode_RA RA, INS - | add TMP1, BASE, RB, lsl #3 - | subs TMP1, CARG2, TMP1 - | beq >1 - | str TMP0, [CARG2] - | lsr CARG3, TMP1, #3 - | b ->BC_CAT_Z - | - |1: - | str TMP0, [BASE, RA, lsl #3] - | b ->cont_nop - | - |//-- Table indexing metamethods ----------------------------------------- - | - |->vmeta_tgets1: - | movn CARG4, #~LJ_TSTR - | add CARG2, BASE, RB, lsl #3 - | add CARG4, STR:RC, CARG4, lsl #47 - | b >2 - | - |->vmeta_tgets: - | movk CARG2, #(LJ_TTAB>>1)&0xffff, lsl #48 - | str CARG2, GL->tmptv - | add CARG2, GL, #offsetof(global_State, tmptv) - |2: - | add CARG3, sp, TMPDofs - | str CARG4, TMPD - | b >1 - | - |->vmeta_tgetb: // RB = table, RC = index - | add RC, RC, TISNUM - | add CARG2, BASE, RB, lsl #3 - | add CARG3, sp, TMPDofs - | str RC, TMPD - | b >1 - | - |->vmeta_tgetv: // RB = table, RC = key - | add CARG2, BASE, RB, lsl #3 - | add CARG3, BASE, RC, lsl #3 - |1: - | str BASE, L->base - | mov CARG1, L - | str PC, SAVE_PC - | bl extern lj_meta_tget // (lua_State *L, TValue *o, TValue *k) - | // Returns TValue * (finished) or NULL (metamethod). - | cbz CRET1, >3 - | ldr TMP0, [CRET1] - | str TMP0, [BASE, RA, lsl #3] - | ins_next - | - |3: // Call __index metamethod. - | // BASE = base, L->top = new base, stack = cont/func/t/k - | sub TMP1, BASE, #FRAME_CONT - | ldr BASE, L->top - | mov NARGS8:RC, #16 // 2 args for func(t, k). - | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] // Guaranteed to be a function here. - | str PC, [BASE, #-24] // [cont|PC] - | sub PC, BASE, TMP1 - | and LFUNC:CARG3, CARG3, #LJ_GCVMASK - | b ->vm_call_dispatch_f - | - |->vmeta_tgetr: - | sxtw CARG2, TMP1w - | bl extern lj_tab_getinth // (GCtab *t, int32_t key) - | // Returns cTValue * or NULL. - | mov TMP0, TISNIL - | cbz CRET1, ->BC_TGETR_Z - | ldr TMP0, [CRET1] - | b ->BC_TGETR_Z - | - |//----------------------------------------------------------------------- - | - |->vmeta_tsets1: - | movn CARG4, #~LJ_TSTR - | add CARG2, BASE, RB, lsl #3 - | add CARG4, STR:RC, CARG4, lsl #47 - | b >2 - | - |->vmeta_tsets: - | movk CARG2, #(LJ_TTAB>>1)&0xffff, lsl #48 - | str CARG2, GL->tmptv - | add CARG2, GL, #offsetof(global_State, tmptv) - |2: - | add CARG3, sp, TMPDofs - | str CARG4, TMPD - | b >1 - | - |->vmeta_tsetb: // RB = table, RC = index - | add RC, RC, TISNUM - | add CARG2, BASE, RB, lsl #3 - | add CARG3, sp, TMPDofs - | str RC, TMPD - | b >1 - | - |->vmeta_tsetv: - | add CARG2, BASE, RB, lsl #3 - | add CARG3, BASE, RC, lsl #3 - |1: - | str BASE, L->base - | mov CARG1, L - | str PC, SAVE_PC - | bl extern lj_meta_tset // (lua_State *L, TValue *o, TValue *k) - | // Returns TValue * (finished) or NULL (metamethod). - | ldr TMP0, [BASE, RA, lsl #3] - | cbz CRET1, >3 - | // NOBARRIER: lj_meta_tset ensures the table is not black. - | str TMP0, [CRET1] - | ins_next - | - |3: // Call __newindex metamethod. - | // BASE = base, L->top = new base, stack = cont/func/t/k/(v) - | sub TMP1, BASE, #FRAME_CONT - | ldr BASE, L->top - | mov NARGS8:RC, #24 // 3 args for func(t, k, v). - | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] // Guaranteed to be a function here. - | str TMP0, [BASE, #16] // Copy value to third argument. - | str PC, [BASE, #-24] // [cont|PC] - | sub PC, BASE, TMP1 - | and LFUNC:CARG3, CARG3, #LJ_GCVMASK - | b ->vm_call_dispatch_f - | - |->vmeta_tsetr: - | sxtw CARG3, TMP1w - | str BASE, L->base - | str PC, SAVE_PC - | bl extern lj_tab_setinth // (lua_State *L, GCtab *t, int32_t key) - | // Returns TValue *. - | b ->BC_TSETR_Z - | - |//-- Comparison metamethods --------------------------------------------- - | - |->vmeta_comp: - | add CARG2, BASE, RA, lsl #3 - | sub PC, PC, #4 - | add CARG3, BASE, RC, lsl #3 - | str BASE, L->base - | mov CARG1, L - | str PC, SAVE_PC - | uxtb CARG4w, INSw - | bl extern lj_meta_comp // (lua_State *L, TValue *o1, *o2, int op) - | // Returns 0/1 or TValue * (metamethod). - |3: - | cmp CRET1, #1 - | bhi ->vmeta_binop - |4: - | ldrh RBw, [PC, # OFS_RD] - | add PC, PC, #4 - | add RB, PC, RB, lsl #2 - | sub RB, RB, #0x20000 - | csel PC, PC, RB, lo - |->cont_nop: - | ins_next - | - |->cont_ra: // RA = resultptr - | ldr INSw, [PC, #-4] - | ldr TMP0, [RA] - | decode_RA TMP1, INS - | str TMP0, [BASE, TMP1, lsl #3] - | b ->cont_nop - | - |->cont_condt: // RA = resultptr - | ldr TMP0, [RA] - | mov_true TMP1 - | cmp TMP1, TMP0 // Branch if result is true. - | b <4 - | - |->cont_condf: // RA = resultptr - | ldr TMP0, [RA] - | mov_false TMP1 - | cmp TMP0, TMP1 // Branch if result is false. - | b <4 - | - |->vmeta_equal: - | // CARG2, CARG3, CARG4 are already set by BC_ISEQV/BC_ISNEV. - | and TAB:CARG3, CARG3, #LJ_GCVMASK - | sub PC, PC, #4 - | str BASE, L->base - | mov CARG1, L - | str PC, SAVE_PC - | bl extern lj_meta_equal // (lua_State *L, GCobj *o1, *o2, int ne) - | // Returns 0/1 or TValue * (metamethod). - | b <3 - | - |->vmeta_equal_cd: - |.if FFI - | sub PC, PC, #4 - | str BASE, L->base - | mov CARG1, L - | mov CARG2, INS - | str PC, SAVE_PC - | bl extern lj_meta_equal_cd // (lua_State *L, BCIns op) - | // Returns 0/1 or TValue * (metamethod). - | b <3 - |.endif - | - |->vmeta_istype: - | sub PC, PC, #4 - | str BASE, L->base - | mov CARG1, L - | mov CARG2, RA - | mov CARG3, RC - | str PC, SAVE_PC - | bl extern lj_meta_istype // (lua_State *L, BCReg ra, BCReg tp) - | b ->cont_nop - | - |//-- Arithmetic metamethods --------------------------------------------- - | - |->vmeta_arith_vn: - | add CARG3, BASE, RB, lsl #3 - | add CARG4, KBASE, RC, lsl #3 - | b >1 - | - |->vmeta_arith_nv: - | add CARG4, BASE, RB, lsl #3 - | add CARG3, KBASE, RC, lsl #3 - | b >1 - | - |->vmeta_unm: - | add CARG3, BASE, RC, lsl #3 - | mov CARG4, CARG3 - | b >1 - | - |->vmeta_arith_vv: - | add CARG3, BASE, RB, lsl #3 - | add CARG4, BASE, RC, lsl #3 - |1: - | uxtb CARG5w, INSw - | add CARG2, BASE, RA, lsl #3 - | str BASE, L->base - | mov CARG1, L - | str PC, SAVE_PC - | bl extern lj_meta_arith // (lua_State *L, TValue *ra,*rb,*rc, BCReg op) - | // Returns NULL (finished) or TValue * (metamethod). - | cbz CRET1, ->cont_nop - | - | // Call metamethod for binary op. - |->vmeta_binop: - | // BASE = old base, CRET1 = new base, stack = cont/func/o1/o2 - | sub TMP1, CRET1, BASE - | str PC, [CRET1, #-24] // [cont|PC] - | add PC, TMP1, #FRAME_CONT - | mov BASE, CRET1 - | mov NARGS8:RC, #16 // 2 args for func(o1, o2). - | b ->vm_call_dispatch - | - |->vmeta_len: - | add CARG2, BASE, RC, lsl #3 -#if LJ_52 - | mov TAB:RC, TAB:CARG1 // Save table (ignored for other types). -#endif - | str BASE, L->base - | mov CARG1, L - | str PC, SAVE_PC - | bl extern lj_meta_len // (lua_State *L, TValue *o) - | // Returns NULL (retry) or TValue * (metamethod base). -#if LJ_52 - | cbnz CRET1, ->vmeta_binop // Binop call for compatibility. - | mov TAB:CARG1, TAB:RC - | b ->BC_LEN_Z -#else - | b ->vmeta_binop // Binop call for compatibility. -#endif - | - |//-- Call metamethod ---------------------------------------------------- - | - |->vmeta_call: // Resolve and call __call metamethod. - | // RB = old base, BASE = new base, RC = nargs*8 - | mov CARG1, L - | str RB, L->base // This is the callers base! - | sub CARG2, BASE, #16 - | str PC, SAVE_PC - | add CARG3, BASE, NARGS8:RC - | bl extern lj_meta_call // (lua_State *L, TValue *func, TValue *top) - | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] // Guaranteed to be a function here. - | add NARGS8:RC, NARGS8:RC, #8 // Got one more argument now. - | and LFUNC:CARG3, CARG3, #LJ_GCVMASK - | ins_call - | - |->vmeta_callt: // Resolve __call for BC_CALLT. - | // BASE = old base, RA = new base, RC = nargs*8 - | mov CARG1, L - | str BASE, L->base - | sub CARG2, RA, #16 - | str PC, SAVE_PC - | add CARG3, RA, NARGS8:RC - | bl extern lj_meta_call // (lua_State *L, TValue *func, TValue *top) - | ldr TMP1, [RA, FRAME_FUNC] // Guaranteed to be a function here. - | ldr PC, [BASE, FRAME_PC] - | add NARGS8:RC, NARGS8:RC, #8 // Got one more argument now. - | and LFUNC:CARG3, TMP1, #LJ_GCVMASK - | b ->BC_CALLT2_Z - | - |//-- Argument coercion for 'for' statement ------------------------------ - | - |->vmeta_for: - | mov CARG1, L - | str BASE, L->base - | mov CARG2, RA - | str PC, SAVE_PC - | bl extern lj_meta_for // (lua_State *L, TValue *base) - | ldr INSw, [PC, #-4] - |.if JIT - | uxtb TMP0w, INSw - |.endif - | decode_RA RA, INS - | decode_RD RC, INS - |.if JIT - | cmp TMP0, #BC_JFORI - | beq =>BC_JFORI - |.endif - | b =>BC_FORI - | - |//----------------------------------------------------------------------- - |//-- Fast functions ----------------------------------------------------- - |//----------------------------------------------------------------------- - | - |.macro .ffunc, name - |->ff_ .. name: - |.endmacro - | - |.macro .ffunc_1, name - |->ff_ .. name: - | ldr CARG1, [BASE] - | cmp NARGS8:RC, #8 - | blo ->fff_fallback - |.endmacro - | - |.macro .ffunc_2, name - |->ff_ .. name: - | ldp CARG1, CARG2, [BASE] - | cmp NARGS8:RC, #16 - | blo ->fff_fallback - |.endmacro - | - |.macro .ffunc_n, name - | .ffunc name - | ldr CARG1, [BASE] - | cmp NARGS8:RC, #8 - | ldr FARG1, [BASE] - | blo ->fff_fallback - | checknum CARG1, ->fff_fallback - |.endmacro - | - |.macro .ffunc_nn, name - | .ffunc name - | ldp CARG1, CARG2, [BASE] - | cmp NARGS8:RC, #16 - | ldp FARG1, FARG2, [BASE] - | blo ->fff_fallback - | checknum CARG1, ->fff_fallback - | checknum CARG2, ->fff_fallback - |.endmacro - | - |// Inlined GC threshold check. Caveat: uses CARG1 and CARG2. - |.macro ffgccheck - | ldp CARG1, CARG2, GL->gc.total // Assumes threshold follows total. - | cmp CARG1, CARG2 - | blt >1 - | bl ->fff_gcstep - |1: - |.endmacro - | - |//-- Base library: checks ----------------------------------------------- - | - |.ffunc_1 assert - | ldr PC, [BASE, FRAME_PC] - | mov_false TMP1 - | cmp CARG1, TMP1 - | bhs ->fff_fallback - | str CARG1, [BASE, #-16] - | sub RB, BASE, #8 - | subs RA, NARGS8:RC, #8 - | add RC, NARGS8:RC, #8 // Compute (nresults+1)*8. - | cbz RA, ->fff_res // Done if exactly 1 argument. - |1: - | ldr CARG1, [RB, #16] - | sub RA, RA, #8 - | str CARG1, [RB], #8 - | cbnz RA, <1 - | b ->fff_res - | - |.ffunc_1 type - | mov TMP0, #~LJ_TISNUM - | asr ITYPE, CARG1, #47 - | cmn ITYPE, #~LJ_TISNUM - | csinv TMP1, TMP0, ITYPE, lo - | add TMP1, TMP1, #offsetof(GCfuncC, upvalue)/8 - | ldr CARG1, [CFUNC:CARG3, TMP1, lsl #3] - | b ->fff_restv - | - |//-- Base library: getters and setters --------------------------------- - | - |.ffunc_1 getmetatable - | asr ITYPE, CARG1, #47 - | cmn ITYPE, #-LJ_TTAB - | ccmn ITYPE, #-LJ_TUDATA, #4, ne - | and TAB:CARG1, CARG1, #LJ_GCVMASK - | bne >6 - |1: // Field metatable must be at same offset for GCtab and GCudata! - | ldr TAB:RB, TAB:CARG1->metatable - |2: - | mov CARG1, TISNIL - | ldr STR:RC, GL->gcroot[GCROOT_MMNAME+MM_metatable] - | cbz TAB:RB, ->fff_restv - | ldr TMP1w, TAB:RB->hmask - | ldr TMP2w, STR:RC->hash - | ldr NODE:CARG3, TAB:RB->node - | and TMP1w, TMP1w, TMP2w // idx = str->hash & tab->hmask - | add TMP1, TMP1, TMP1, lsl #1 - | movn CARG4, #~LJ_TSTR - | add NODE:CARG3, NODE:CARG3, TMP1, lsl #3 // node = tab->node + idx*3*8 - | add CARG4, STR:RC, CARG4, lsl #47 // Tagged key to look for. - |3: // Rearranged logic, because we expect _not_ to find the key. - | ldp CARG1, TMP0, NODE:CARG3->val - | ldr NODE:CARG3, NODE:CARG3->next - | cmp TMP0, CARG4 - | beq >5 - | cbnz NODE:CARG3, <3 - |4: - | mov CARG1, RB // Use metatable as default result. - | movk CARG1, #(LJ_TTAB>>1)&0xffff, lsl #48 - | b ->fff_restv - |5: - | cmp TMP0, TISNIL - | bne ->fff_restv - | b <4 - | - |6: - | movn TMP0, #~LJ_TISNUM - | cmp ITYPE, TMP0 - | csel ITYPE, ITYPE, TMP0, hs - | sub TMP1, GL, ITYPE, lsl #3 - | ldr TAB:RB, [TMP1, #offsetof(global_State, gcroot[GCROOT_BASEMT])-8] - | b <2 - | - |.ffunc_2 setmetatable - | // Fast path: no mt for table yet and not clearing the mt. - | checktp TMP1, CARG1, LJ_TTAB, ->fff_fallback - | ldr TAB:TMP0, TAB:TMP1->metatable - | asr ITYPE, CARG2, #47 - | ldrb TMP2w, TAB:TMP1->marked - | cmn ITYPE, #-LJ_TTAB - | and TAB:CARG2, CARG2, #LJ_GCVMASK - | ccmp TAB:TMP0, #0, #0, eq - | bne ->fff_fallback - | str TAB:CARG2, TAB:TMP1->metatable - | tbz TMP2w, #2, ->fff_restv // isblack(table) - | barrierback TAB:TMP1, TMP2w, TMP0 - | b ->fff_restv - | - |.ffunc rawget - | ldr CARG2, [BASE] - | cmp NARGS8:RC, #16 - | blo ->fff_fallback - | checktab CARG2, ->fff_fallback - | mov CARG1, L - | add CARG3, BASE, #8 - | bl extern lj_tab_get // (lua_State *L, GCtab *t, cTValue *key) - | // Returns cTValue *. - | ldr CARG1, [CRET1] - | b ->fff_restv - | - |//-- Base library: conversions ------------------------------------------ - | - |.ffunc tonumber - | // Only handles the number case inline (without a base argument). - | ldr CARG1, [BASE] - | cmp NARGS8:RC, #8 - | bne ->fff_fallback - | checknumber CARG1, ->fff_fallback - | b ->fff_restv - | - |.ffunc_1 tostring - | // Only handles the string or number case inline. - | asr ITYPE, CARG1, #47 - | cmn ITYPE, #-LJ_TSTR - | // A __tostring method in the string base metatable is ignored. - | beq ->fff_restv - | // Handle numbers inline, unless a number base metatable is present. - | ldr TMP1, GL->gcroot[GCROOT_BASEMT_NUM] - | str BASE, L->base - | cmn ITYPE, #-LJ_TISNUM - | ccmp TMP1, #0, #0, ls - | str PC, SAVE_PC // Redundant (but a defined value). - | bne ->fff_fallback - | ffgccheck - | mov CARG1, L - | mov CARG2, BASE - | bl extern lj_strfmt_number // (lua_State *L, cTValue *o) - | // Returns GCstr *. - | movn TMP1, #~LJ_TSTR - | ldr BASE, L->base - | add CARG1, CARG1, TMP1, lsl #47 - | b ->fff_restv - | - |//-- Base library: iterators ------------------------------------------- - | - |.ffunc_1 next - | checktp CARG2, CARG1, LJ_TTAB, ->fff_fallback - | str TISNIL, [BASE, NARGS8:RC] // Set missing 2nd arg to nil. - | ldr PC, [BASE, FRAME_PC] - | stp BASE, BASE, L->base // Add frame since C call can throw. - | mov CARG1, L - | add CARG3, BASE, #8 - | str PC, SAVE_PC - | bl extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key) - | // Returns 0 at end of traversal. - | str TISNIL, [BASE, #-16] - | cbz CRET1, ->fff_res1 // End of traversal: return nil. - | ldp CARG1, CARG2, [BASE, #8] // Copy key and value to results. - | mov RC, #(2+1)*8 - | stp CARG1, CARG2, [BASE, #-16] - | b ->fff_res - | - |.ffunc_1 pairs - | checktp TMP1, CARG1, LJ_TTAB, ->fff_fallback -#if LJ_52 - | ldr TAB:CARG2, TAB:TMP1->metatable -#endif - | ldr CFUNC:CARG4, CFUNC:CARG3->upvalue[0] - | ldr PC, [BASE, FRAME_PC] -#if LJ_52 - | cbnz TAB:CARG2, ->fff_fallback -#endif - | mov RC, #(3+1)*8 - | stp CARG1, TISNIL, [BASE, #-8] - | str CFUNC:CARG4, [BASE, #-16] - | b ->fff_res - | - |.ffunc_2 ipairs_aux - | checktab CARG1, ->fff_fallback - | checkint CARG2, ->fff_fallback - | ldr TMP1w, TAB:CARG1->asize - | ldr CARG3, TAB:CARG1->array - | ldr TMP0w, TAB:CARG1->hmask - | add CARG2w, CARG2w, #1 - | cmp CARG2w, TMP1w - | ldr PC, [BASE, FRAME_PC] - | add TMP2, CARG2, TISNUM - | mov RC, #(0+1)*8 - | str TMP2, [BASE, #-16] - | bhs >2 // Not in array part? - | ldr TMP0, [CARG3, CARG2, lsl #3] - |1: - | mov TMP1, #(2+1)*8 - | cmp TMP0, TISNIL - | str TMP0, [BASE, #-8] - | csel RC, RC, TMP1, eq - | b ->fff_res - |2: // Check for empty hash part first. Otherwise call C function. - | cbz TMP0w, ->fff_res - | bl extern lj_tab_getinth // (GCtab *t, int32_t key) - | // Returns cTValue * or NULL. - | cbz CRET1, ->fff_res - | ldr TMP0, [CRET1] - | b <1 - | - |.ffunc_1 ipairs - | checktp TMP1, CARG1, LJ_TTAB, ->fff_fallback -#if LJ_52 - | ldr TAB:CARG2, TAB:TMP1->metatable -#endif - | ldr CFUNC:CARG4, CFUNC:CARG3->upvalue[0] - | ldr PC, [BASE, FRAME_PC] -#if LJ_52 - | cbnz TAB:CARG2, ->fff_fallback -#endif - | mov RC, #(3+1)*8 - | stp CARG1, TISNUM, [BASE, #-8] - | str CFUNC:CARG4, [BASE, #-16] - | b ->fff_res - | - |//-- Base library: catch errors ---------------------------------------- - | - |.ffunc pcall - | ldrb TMP0w, GL->hookmask - | subs NARGS8:RC, NARGS8:RC, #8 - | blo ->fff_fallback - | mov RB, BASE - | add BASE, BASE, #16 - | ubfx TMP0w, TMP0w, #HOOK_ACTIVE_SHIFT, #1 - | add PC, TMP0, #16+FRAME_PCALL - | beq ->vm_call_dispatch - |1: - | add TMP2, BASE, NARGS8:RC - |2: - | ldr TMP0, [TMP2, #-16] - | str TMP0, [TMP2, #-8]! - | cmp TMP2, BASE - | bne <2 - | b ->vm_call_dispatch - | - |.ffunc xpcall - | ldp CARG1, CARG2, [BASE] - | ldrb TMP0w, GL->hookmask - | subs NARGS8:TMP1, NARGS8:RC, #16 - | blo ->fff_fallback - | mov RB, BASE - | asr ITYPE, CARG2, #47 - | ubfx TMP0w, TMP0w, #HOOK_ACTIVE_SHIFT, #1 - | cmn ITYPE, #-LJ_TFUNC - | add PC, TMP0, #24+FRAME_PCALL - | bne ->fff_fallback // Traceback must be a function. - | mov NARGS8:RC, NARGS8:TMP1 - | add BASE, BASE, #24 - | stp CARG2, CARG1, [RB] // Swap function and traceback. - | cbz NARGS8:RC, ->vm_call_dispatch - | b <1 - | - |//-- Coroutine library -------------------------------------------------- - | - |.macro coroutine_resume_wrap, resume - |.if resume - |.ffunc_1 coroutine_resume - | checktp CARG1, LJ_TTHREAD, ->fff_fallback - |.else - |.ffunc coroutine_wrap_aux - | ldr L:CARG1, CFUNC:CARG3->upvalue[0].gcr - | and L:CARG1, CARG1, #LJ_GCVMASK - |.endif - | ldr PC, [BASE, FRAME_PC] - | str BASE, L->base - | ldp RB, CARG2, L:CARG1->base - | ldrb TMP1w, L:CARG1->status - | add TMP0, CARG2, TMP1 - | str PC, SAVE_PC - | cmp TMP0, RB - | beq ->fff_fallback - | cmp TMP1, #LUA_YIELD - | add TMP0, CARG2, #8 - | csel CARG2, CARG2, TMP0, hs - | ldr CARG4, L:CARG1->maxstack - | add CARG3, CARG2, NARGS8:RC - | ldr RB, L:CARG1->cframe - | ccmp CARG3, CARG4, #2, ls - | ccmp RB, #0, #2, ls - | bhi ->fff_fallback - |.if resume - | sub CARG3, CARG3, #8 // Keep resumed thread in stack for GC. - | add BASE, BASE, #8 - | sub NARGS8:RC, NARGS8:RC, #8 - |.endif - | str CARG3, L:CARG1->top - | str BASE, L->top - | cbz NARGS8:RC, >3 - |2: // Move args to coroutine. - | ldr TMP0, [BASE, RB] - | cmp RB, NARGS8:RC - | str TMP0, [CARG2, RB] - | add RB, RB, #8 - | bne <2 - |3: - | mov CARG3, #0 - | mov L:RA, L:CARG1 - | mov CARG4, #0 - | bl ->vm_resume // (lua_State *L, TValue *base, 0, 0) - | // Returns thread status. - |4: - | ldp CARG3, CARG4, L:RA->base - | cmp CRET1, #LUA_YIELD - | ldr BASE, L->base - | str L, GL->cur_L - | st_vmstate ST_INTERP - | bhi >8 - | sub RC, CARG4, CARG3 - | ldr CARG1, L->maxstack - | add CARG2, BASE, RC - | cbz RC, >6 // No results? - | cmp CARG2, CARG1 - | mov RB, #0 - | bhi >9 // Need to grow stack? - | - | sub CARG4, RC, #8 - | str CARG3, L:RA->top // Clear coroutine stack. - |5: // Move results from coroutine. - | ldr TMP0, [CARG3, RB] - | cmp RB, CARG4 - | str TMP0, [BASE, RB] - | add RB, RB, #8 - | bne <5 - |6: - |.if resume - | mov_true TMP1 - | add RC, RC, #16 - |7: - | str TMP1, [BASE, #-8] // Prepend true/false to results. - | sub RA, BASE, #8 - |.else - | mov RA, BASE - | add RC, RC, #8 - |.endif - | ands CARG1, PC, #FRAME_TYPE - | str PC, SAVE_PC - | str RCw, SAVE_MULTRES - | beq ->BC_RET_Z - | b ->vm_return - | - |8: // Coroutine returned with error (at co->top-1). - |.if resume - | ldr TMP0, [CARG4, #-8]! - | mov_false TMP1 - | mov RC, #(2+1)*8 - | str CARG4, L:RA->top // Remove error from coroutine stack. - | str TMP0, [BASE] // Copy error message. - | b <7 - |.else - | mov CARG1, L - | mov CARG2, L:RA - | bl extern lj_ffh_coroutine_wrap_err // (lua_State *L, lua_State *co) - | // Never returns. - |.endif - | - |9: // Handle stack expansion on return from yield. - | mov CARG1, L - | lsr CARG2, RC, #3 - | bl extern lj_state_growstack // (lua_State *L, int n) - | mov CRET1, #0 - | b <4 - |.endmacro - | - | coroutine_resume_wrap 1 // coroutine.resume - | coroutine_resume_wrap 0 // coroutine.wrap - | - |.ffunc coroutine_yield - | ldr TMP0, L->cframe - | add TMP1, BASE, NARGS8:RC - | mov CRET1, #LUA_YIELD - | stp BASE, TMP1, L->base - | tbz TMP0, #0, ->fff_fallback - | str xzr, L->cframe - | strb CRET1w, L->status - | b ->vm_leave_unw - | - |//-- Math library ------------------------------------------------------- - | - |.macro math_round, func, round - | .ffunc math_ .. func - | ldr CARG1, [BASE] - | cmp NARGS8:RC, #8 - | ldr d0, [BASE] - | blo ->fff_fallback - | cmp TISNUMhi, CARG1, lsr #32 - | beq ->fff_restv - | blo ->fff_fallback - | round d0, d0 - | b ->fff_resn - |.endmacro - | - | math_round floor, frintm - | math_round ceil, frintp - | - |.ffunc_1 math_abs - | checknumber CARG1, ->fff_fallback - | and CARG1, CARG1, #U64x(7fffffff,ffffffff) - | bne ->fff_restv - | eor CARG2w, CARG1w, CARG1w, asr #31 - | movz CARG3, #0x41e0, lsl #48 // 2^31. - | subs CARG1w, CARG2w, CARG1w, asr #31 - | add CARG1, CARG1, TISNUM - | csel CARG1, CARG1, CARG3, pl - | // Fallthrough. - | - |->fff_restv: - | // CARG1 = TValue result. - | ldr PC, [BASE, FRAME_PC] - | str CARG1, [BASE, #-16] - |->fff_res1: - | // PC = return. - | mov RC, #(1+1)*8 - |->fff_res: - | // RC = (nresults+1)*8, PC = return. - | ands CARG1, PC, #FRAME_TYPE - | str RCw, SAVE_MULTRES - | sub RA, BASE, #16 - | bne ->vm_return - | ldr INSw, [PC, #-4] - | decode_RB RB, INS - |5: - | cmp RC, RB, lsl #3 // More results expected? - | blo >6 - | decode_RA TMP1, INS - | // Adjust BASE. KBASE is assumed to be set for the calling frame. - | sub BASE, RA, TMP1, lsl #3 - | ins_next - | - |6: // Fill up results with nil. - | add TMP1, RA, RC - | add RC, RC, #8 - | str TISNIL, [TMP1, #-8] - | b <5 - | - |.macro math_extern, func - | .ffunc_n math_ .. func - | bl extern func - | b ->fff_resn - |.endmacro - | - |.macro math_extern2, func - | .ffunc_nn math_ .. func - | bl extern func - | b ->fff_resn - |.endmacro - | - |.ffunc_n math_sqrt - | fsqrt d0, d0 - |->fff_resn: - | ldr PC, [BASE, FRAME_PC] - | str d0, [BASE, #-16] - | b ->fff_res1 - | - |.ffunc math_log - | ldr CARG1, [BASE] - | cmp NARGS8:RC, #8 - | ldr FARG1, [BASE] - | bne ->fff_fallback // Need exactly 1 argument. - | checknum CARG1, ->fff_fallback - | bl extern log - | b ->fff_resn - | - | math_extern log10 - | math_extern exp - | math_extern sin - | math_extern cos - | math_extern tan - | math_extern asin - | math_extern acos - | math_extern atan - | math_extern sinh - | math_extern cosh - | math_extern tanh - | math_extern2 pow - | math_extern2 atan2 - | math_extern2 fmod - | - |.ffunc_2 math_ldexp - | ldr FARG1, [BASE] - | checknum CARG1, ->fff_fallback - | checkint CARG2, ->fff_fallback - | sxtw CARG1, CARG2w - | bl extern ldexp // (double x, int exp) - | b ->fff_resn - | - |.ffunc_n math_frexp - | add CARG1, sp, TMPDofs - | bl extern frexp - | ldr CARG2w, TMPD - | ldr PC, [BASE, FRAME_PC] - | str d0, [BASE, #-16] - | mov RC, #(2+1)*8 - | add CARG2, CARG2, TISNUM - | str CARG2, [BASE, #-8] - | b ->fff_res - | - |.ffunc_n math_modf - | sub CARG1, BASE, #16 - | ldr PC, [BASE, FRAME_PC] - | bl extern modf - | mov RC, #(2+1)*8 - | str d0, [BASE, #-8] - | b ->fff_res - | - |.macro math_minmax, name, cond, fcond - | .ffunc_1 name - | add RB, BASE, RC - | add RA, BASE, #8 - | checkint CARG1, >4 - |1: // Handle integers. - | ldr CARG2, [RA] - | cmp RA, RB - | bhs ->fff_restv - | checkint CARG2, >3 - | cmp CARG1w, CARG2w - | add RA, RA, #8 - | csel CARG1, CARG2, CARG1, cond - | b <1 - |3: // Convert intermediate result to number and continue below. - | scvtf d0, CARG1w - | blo ->fff_fallback - | ldr d1, [RA] - | b >6 - | - |4: - | ldr d0, [BASE] - | blo ->fff_fallback - |5: // Handle numbers. - | ldr CARG2, [RA] - | ldr d1, [RA] - | cmp RA, RB - | bhs ->fff_resn - | checknum CARG2, >7 - |6: - | fcmp d0, d1 - | add RA, RA, #8 - | fcsel d0, d1, d0, fcond - | b <5 - |7: // Convert integer to number and continue above. - | scvtf d1, CARG2w - | blo ->fff_fallback - | b <6 - |.endmacro - | - | math_minmax math_min, gt, hi - | math_minmax math_max, lt, lo - | - |//-- String library ----------------------------------------------------- - | - |.ffunc string_byte // Only handle the 1-arg case here. - | ldp PC, CARG1, [BASE, FRAME_PC] - | cmp NARGS8:RC, #8 - | asr ITYPE, CARG1, #47 - | ccmn ITYPE, #-LJ_TSTR, #0, eq - | and STR:CARG1, CARG1, #LJ_GCVMASK - | bne ->fff_fallback - | ldrb TMP0w, STR:CARG1[1] // Access is always ok (NUL at end). - | ldr CARG3w, STR:CARG1->len - | add TMP0, TMP0, TISNUM - | str TMP0, [BASE, #-16] - | mov RC, #(0+1)*8 - | cbz CARG3, ->fff_res - | b ->fff_res1 - | - |.ffunc string_char // Only handle the 1-arg case here. - | ffgccheck - | ldp PC, CARG1, [BASE, FRAME_PC] - | cmp CARG1w, #255 - | ccmp NARGS8:RC, #8, #0, ls // Need exactly 1 argument. - | bne ->fff_fallback - | checkint CARG1, ->fff_fallback - | mov CARG3, #1 - | // Point to the char inside the integer in the stack slot. - |.if ENDIAN_LE - | mov CARG2, BASE - |.else - | add CARG2, BASE, #7 - |.endif - |->fff_newstr: - | // CARG2 = str, CARG3 = len. - | str BASE, L->base - | mov CARG1, L - | str PC, SAVE_PC - | bl extern lj_str_new // (lua_State *L, char *str, size_t l) - |->fff_resstr: - | // Returns GCstr *. - | ldr BASE, L->base - | movn TMP1, #~LJ_TSTR - | add CARG1, CARG1, TMP1, lsl #47 - | b ->fff_restv - | - |.ffunc string_sub - | ffgccheck - | ldr CARG1, [BASE] - | ldr CARG3, [BASE, #16] - | cmp NARGS8:RC, #16 - | movn RB, #0 - | beq >1 - | blo ->fff_fallback - | checkint CARG3, ->fff_fallback - | sxtw RB, CARG3w - |1: - | ldr CARG2, [BASE, #8] - | checkstr CARG1, ->fff_fallback - | ldr TMP1w, STR:CARG1->len - | checkint CARG2, ->fff_fallback - | sxtw CARG2, CARG2w - | // CARG1 = str, TMP1 = str->len, CARG2 = start, RB = end - | add TMP2, RB, TMP1 - | cmp RB, #0 - | add TMP0, CARG2, TMP1 - | csinc RB, RB, TMP2, ge // if (end < 0) end += len+1 - | cmp CARG2, #0 - | csinc CARG2, CARG2, TMP0, ge // if (start < 0) start += len+1 - | cmp RB, #0 - | csel RB, RB, xzr, ge // if (end < 0) end = 0 - | cmp CARG2, #1 - | csinc CARG2, CARG2, xzr, ge // if (start < 1) start = 1 - | cmp RB, TMP1 - | csel RB, RB, TMP1, le // if (end > len) end = len - | add CARG1, STR:CARG1, #sizeof(GCstr)-1 - | subs CARG3, RB, CARG2 // len = end - start - | add CARG2, CARG1, CARG2 - | add CARG3, CARG3, #1 // len += 1 - | bge ->fff_newstr - | add STR:CARG1, GL, #offsetof(global_State, strempty) - | movn TMP1, #~LJ_TSTR - | add CARG1, CARG1, TMP1, lsl #47 - | b ->fff_restv - | - |.macro ffstring_op, name - | .ffunc string_ .. name - | ffgccheck - | ldr CARG2, [BASE] - | cmp NARGS8:RC, #8 - | asr ITYPE, CARG2, #47 - | ccmn ITYPE, #-LJ_TSTR, #0, hs - | and STR:CARG2, CARG2, #LJ_GCVMASK - | bne ->fff_fallback - | ldr TMP0, GL->tmpbuf.b - | add SBUF:CARG1, GL, #offsetof(global_State, tmpbuf) - | str BASE, L->base - | str PC, SAVE_PC - | str L, GL->tmpbuf.L - | str TMP0, GL->tmpbuf.p - | bl extern lj_buf_putstr_ .. name - | bl extern lj_buf_tostr - | b ->fff_resstr - |.endmacro - | - |ffstring_op reverse - |ffstring_op lower - |ffstring_op upper - | - |//-- Bit library -------------------------------------------------------- - | - |// FP number to bit conversion for soft-float. Clobbers CARG1-CARG3 - |->vm_tobit_fb: - | bls ->fff_fallback - | add CARG2, CARG1, CARG1 - | mov CARG3, #1076 - | sub CARG3, CARG3, CARG2, lsr #53 - | cmp CARG3, #53 - | bhi >1 - | and CARG2, CARG2, #U64x(001fffff,ffffffff) - | orr CARG2, CARG2, #U64x(00200000,00000000) - | cmp CARG1, #0 - | lsr CARG2, CARG2, CARG3 - | cneg CARG1w, CARG2w, mi - | br lr - |1: - | mov CARG1w, #0 - | br lr - | - |.macro .ffunc_bit, name - | .ffunc_1 bit_..name - | adr lr, >1 - | checkint CARG1, ->vm_tobit_fb - |1: - |.endmacro - | - |.macro .ffunc_bit_op, name, ins - | .ffunc_bit name - | mov RA, #8 - | mov TMP0w, CARG1w - | adr lr, >2 - |1: - | ldr CARG1, [BASE, RA] - | cmp RA, NARGS8:RC - | add RA, RA, #8 - | bge >9 - | checkint CARG1, ->vm_tobit_fb - |2: - | ins TMP0w, TMP0w, CARG1w - | b <1 - |.endmacro - | - |.ffunc_bit_op band, and - |.ffunc_bit_op bor, orr - |.ffunc_bit_op bxor, eor - | - |.ffunc_bit tobit - | mov TMP0w, CARG1w - |9: // Label reused by .ffunc_bit_op users. - | add CARG1, TMP0, TISNUM - | b ->fff_restv - | - |.ffunc_bit bswap - | rev TMP0w, CARG1w - | add CARG1, TMP0, TISNUM - | b ->fff_restv - | - |.ffunc_bit bnot - | mvn TMP0w, CARG1w - | add CARG1, TMP0, TISNUM - | b ->fff_restv - | - |.macro .ffunc_bit_sh, name, ins, shmod - | .ffunc bit_..name - | ldp TMP0, CARG1, [BASE] - | cmp NARGS8:RC, #16 - | blo ->fff_fallback - | adr lr, >1 - | checkint CARG1, ->vm_tobit_fb - |1: - |.if shmod == 0 - | mov TMP1, CARG1 - |.else - | neg TMP1, CARG1 - |.endif - | mov CARG1, TMP0 - | adr lr, >2 - | checkint CARG1, ->vm_tobit_fb - |2: - | ins TMP0w, CARG1w, TMP1w - | add CARG1, TMP0, TISNUM - | b ->fff_restv - |.endmacro - | - |.ffunc_bit_sh lshift, lsl, 0 - |.ffunc_bit_sh rshift, lsr, 0 - |.ffunc_bit_sh arshift, asr, 0 - |.ffunc_bit_sh rol, ror, 1 - |.ffunc_bit_sh ror, ror, 0 - | - |//----------------------------------------------------------------------- - | - |->fff_fallback: // Call fast function fallback handler. - | // BASE = new base, RC = nargs*8 - | ldp CFUNC:CARG3, PC, [BASE, FRAME_FUNC] // Fallback may overwrite PC. - | ldr TMP2, L->maxstack - | add TMP1, BASE, NARGS8:RC - | stp BASE, TMP1, L->base - | and CFUNC:CARG3, CARG3, #LJ_GCVMASK - | add TMP1, TMP1, #8*LUA_MINSTACK - | ldr CARG3, CFUNC:CARG3->f - | str PC, SAVE_PC // Redundant (but a defined value). - | cmp TMP1, TMP2 - | mov CARG1, L - | bhi >5 // Need to grow stack. - | blr CARG3 // (lua_State *L) - | // Either throws an error, or recovers and returns -1, 0 or nresults+1. - | ldr BASE, L->base - | cmp CRET1w, #0 - | lsl RC, CRET1, #3 - | sub RA, BASE, #16 - | bgt ->fff_res // Returned nresults+1? - |1: // Returned 0 or -1: retry fast path. - | ldr CARG1, L->top - | ldr CFUNC:CARG3, [BASE, FRAME_FUNC] - | sub NARGS8:RC, CARG1, BASE - | bne ->vm_call_tail // Returned -1? - | and CFUNC:CARG3, CARG3, #LJ_GCVMASK - | ins_callt // Returned 0: retry fast path. - | - |// Reconstruct previous base for vmeta_call during tailcall. - |->vm_call_tail: - | ands TMP0, PC, #FRAME_TYPE - | and TMP1, PC, #~FRAME_TYPEP - | bne >3 - | ldrb RAw, [PC, #-4+OFS_RA] - | lsl RA, RA, #3 - | add TMP1, RA, #16 - |3: - | sub RB, BASE, TMP1 - | b ->vm_call_dispatch // Resolve again for tailcall. - | - |5: // Grow stack for fallback handler. - | mov CARG2, #LUA_MINSTACK - | bl extern lj_state_growstack // (lua_State *L, int n) - | ldr BASE, L->base - | cmp CARG1, CARG1 // Set zero-flag to force retry. - | b <1 - | - |->fff_gcstep: // Call GC step function. - | // BASE = new base, RC = nargs*8 - | add CARG2, BASE, NARGS8:RC // Calculate L->top. - | mov RA, lr - | stp BASE, CARG2, L->base - | str PC, SAVE_PC // Redundant (but a defined value). - | mov CARG1, L - | bl extern lj_gc_step // (lua_State *L) - | ldp BASE, CARG2, L->base - | ldr CFUNC:CARG3, [BASE, FRAME_FUNC] - | mov lr, RA // Help return address predictor. - | sub NARGS8:RC, CARG2, BASE // Calculate nargs*8. - | and CFUNC:CARG3, CARG3, #LJ_GCVMASK - | ret - | - |//----------------------------------------------------------------------- - |//-- Special dispatch targets ------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_record: // Dispatch target for recording phase. - |.if JIT - | ldrb CARG1w, GL->hookmask - | tst CARG1, #HOOK_VMEVENT // No recording while in vmevent. - | bne >5 - | // Decrement the hookcount for consistency, but always do the call. - | ldr CARG2w, GL->hookcount - | tst CARG1, #HOOK_ACTIVE - | bne >1 - | sub CARG2w, CARG2w, #1 - | tst CARG1, #LUA_MASKLINE|LUA_MASKCOUNT - | beq >1 - | str CARG2w, GL->hookcount - | b >1 - |.endif - | - |->vm_rethook: // Dispatch target for return hooks. - | ldrb TMP2w, GL->hookmask - | tbz TMP2w, #HOOK_ACTIVE_SHIFT, >1 // Hook already active? - |5: // Re-dispatch to static ins. - | ldr TMP0, [TMP1, #GG_G2DISP+GG_DISP2STATIC] - | br TMP0 - | - |->vm_inshook: // Dispatch target for instr/line hooks. - | ldrb TMP2w, GL->hookmask - | ldr TMP3w, GL->hookcount - | tbnz TMP2w, #HOOK_ACTIVE_SHIFT, <5 // Hook already active? - | tst TMP2w, #LUA_MASKLINE|LUA_MASKCOUNT - | beq <5 - | sub TMP3w, TMP3w, #1 - | str TMP3w, GL->hookcount - | cbz TMP3w, >1 - | tbz TMP2w, #LUA_HOOKLINE, <5 - |1: - | mov CARG1, L - | str BASE, L->base - | mov CARG2, PC - | // SAVE_PC must hold the _previous_ PC. The callee updates it with PC. - | bl extern lj_dispatch_ins // (lua_State *L, const BCIns *pc) - |3: - | ldr BASE, L->base - |4: // Re-dispatch to static ins. - | ldr INSw, [PC, #-4] - | add TMP1, GL, INS, uxtb #3 - | decode_RA RA, INS - | ldr TMP0, [TMP1, #GG_G2DISP+GG_DISP2STATIC] - | decode_RD RC, INS - | br TMP0 - | - |->cont_hook: // Continue from hook yield. - | ldr CARG1, [CARG4, #-40] - | add PC, PC, #4 - | str CARG1w, SAVE_MULTRES // Restore MULTRES for *M ins. - | b <4 - | - |->vm_hotloop: // Hot loop counter underflow. - |.if JIT - | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] // Same as curr_topL(L). - | add CARG1, GL, #GG_G2DISP+GG_DISP2J - | and LFUNC:CARG3, CARG3, #LJ_GCVMASK - | str PC, SAVE_PC - | ldr CARG3, LFUNC:CARG3->pc - | mov CARG2, PC - | str L, [GL, #GL_J(L)] - | ldrb CARG3w, [CARG3, #PC2PROTO(framesize)] - | str BASE, L->base - | add CARG3, BASE, CARG3, lsl #3 - | str CARG3, L->top - | bl extern lj_trace_hot // (jit_State *J, const BCIns *pc) - | b <3 - |.endif - | - |->vm_callhook: // Dispatch target for call hooks. - | mov CARG2, PC - |.if JIT - | b >1 - |.endif - | - |->vm_hotcall: // Hot call counter underflow. - |.if JIT - | orr CARG2, PC, #1 - |1: - |.endif - | add TMP1, BASE, NARGS8:RC - | str PC, SAVE_PC - | mov CARG1, L - | sub RA, RA, BASE - | stp BASE, TMP1, L->base - | bl extern lj_dispatch_call // (lua_State *L, const BCIns *pc) - | // Returns ASMFunction. - | ldp BASE, TMP1, L->base - | str xzr, SAVE_PC // Invalidate for subsequent line hook. - | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] - | add RA, BASE, RA - | sub NARGS8:RC, TMP1, BASE - | ldr INSw, [PC, #-4] - | and LFUNC:CARG3, CARG3, #LJ_GCVMASK - | br CRET1 - | - |->cont_stitch: // Trace stitching. - |.if JIT - | // RA = resultptr, CARG4 = meta base - | ldr RBw, SAVE_MULTRES - | ldr INSw, [PC, #-4] - | ldr TRACE:CARG3, [CARG4, #-40] // Save previous trace. - | subs RB, RB, #8 - | decode_RA RC, INS // Call base. - | and CARG3, CARG3, #LJ_GCVMASK - | beq >2 - |1: // Move results down. - | ldr CARG1, [RA] - | add RA, RA, #8 - | subs RB, RB, #8 - | str CARG1, [BASE, RC, lsl #3] - | add RC, RC, #1 - | bne <1 - |2: - | decode_RA RA, INS - | decode_RB RB, INS - | add RA, RA, RB - |3: - | cmp RA, RC - | bhi >9 // More results wanted? - | - | ldrh RAw, TRACE:CARG3->traceno - | ldrh RCw, TRACE:CARG3->link - | cmp RCw, RAw - | beq ->cont_nop // Blacklisted. - | cmp RCw, #0 - | bne =>BC_JLOOP // Jump to stitched trace. - | - | // Stitch a new trace to the previous trace. - | mov CARG1, #GL_J(exitno) - | str RAw, [GL, CARG1] - | mov CARG1, #GL_J(L) - | str L, [GL, CARG1] - | str BASE, L->base - | add CARG1, GL, #GG_G2J - | mov CARG2, PC - | bl extern lj_dispatch_stitch // (jit_State *J, const BCIns *pc) - | ldr BASE, L->base - | b ->cont_nop - | - |9: // Fill up results with nil. - | str TISNIL, [BASE, RC, lsl #3] - | add RC, RC, #1 - | b <3 - |.endif - | - |->vm_profhook: // Dispatch target for profiler hook. -#if LJ_HASPROFILE - | mov CARG1, L - | str BASE, L->base - | mov CARG2, PC - | bl extern lj_dispatch_profile // (lua_State *L, const BCIns *pc) - | // HOOK_PROFILE is off again, so re-dispatch to dynamic instruction. - | ldr BASE, L->base - | sub PC, PC, #4 - | b ->cont_nop -#endif - | - |//----------------------------------------------------------------------- - |//-- Trace exit handler ------------------------------------------------- - |//----------------------------------------------------------------------- - | - |.macro savex_, a, b - | stp d..a, d..b, [sp, #a*8] - | stp x..a, x..b, [sp, #32*8+a*8] - |.endmacro - | - |->vm_exit_handler: - |.if JIT - | sub sp, sp, #(64*8) - | savex_, 0, 1 - | savex_, 2, 3 - | savex_, 4, 5 - | savex_, 6, 7 - | savex_, 8, 9 - | savex_, 10, 11 - | savex_, 12, 13 - | savex_, 14, 15 - | savex_, 16, 17 - | savex_, 18, 19 - | savex_, 20, 21 - | savex_, 22, 23 - | savex_, 24, 25 - | savex_, 26, 27 - | savex_, 28, 29 - | stp d30, d31, [sp, #30*8] - | ldr CARG1, [sp, #64*8] // Load original value of lr. - | add CARG3, sp, #64*8 // Recompute original value of sp. - | mv_vmstate CARG4w, EXIT - | stp xzr, CARG3, [sp, #62*8] // Store 0/sp in RID_LR/RID_SP. - | sub CARG1, CARG1, lr - | ldr L, GL->cur_L - | lsr CARG1, CARG1, #2 - | ldr BASE, GL->jit_base - | sub CARG1, CARG1, #2 - | ldr CARG2w, [lr] // Load trace number. - | st_vmstate CARG4w - |.if ENDIAN_BE - | rev32 CARG2, CARG2 - |.endif - | str BASE, L->base - | ubfx CARG2w, CARG2w, #5, #16 - | str CARG1w, [GL, #GL_J(exitno)] - | str CARG2w, [GL, #GL_J(parent)] - | str L, [GL, #GL_J(L)] - | str xzr, GL->jit_base - | add CARG1, GL, #GG_G2J - | mov CARG2, sp - | bl extern lj_trace_exit // (jit_State *J, ExitState *ex) - | // Returns MULTRES (unscaled) or negated error code. - | ldr CARG2, L->cframe - | ldr BASE, L->base - | and sp, CARG2, #CFRAME_RAWMASK - | ldr PC, SAVE_PC // Get SAVE_PC. - | str L, SAVE_L // Set SAVE_L (on-trace resume/yield). - | b >1 - |.endif - | - |->vm_exit_interp: - | // CARG1 = MULTRES or negated error code, BASE, PC and GL set. - |.if JIT - | ldr L, SAVE_L - |1: - | cmp CARG1w, #0 - | blt >9 // Check for error from exit. - | lsl RC, CARG1, #3 - | ldr LFUNC:CARG2, [BASE, FRAME_FUNC] - | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48 - | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16 - | movn TISNIL, #0 - | and LFUNC:CARG2, CARG2, #LJ_GCVMASK - | str RCw, SAVE_MULTRES - | str BASE, L->base - | ldr CARG2, LFUNC:CARG2->pc - | str xzr, GL->jit_base - | mv_vmstate CARG4w, INTERP - | ldr KBASE, [CARG2, #PC2PROTO(k)] - | // Modified copy of ins_next which handles function header dispatch, too. - | ldrb RBw, [PC, # OFS_OP] - | ldr INSw, [PC], #4 - | st_vmstate CARG4w - | cmp RBw, #BC_FUNCC+2 // Fast function? - | add TMP1, GL, INS, uxtb #3 - | bhs >4 - |2: - | cmp RBw, #BC_FUNCF // Function header? - | add TMP0, GL, RB, uxtb #3 - | ldr RB, [TMP0, #GG_G2DISP] - | decode_RA RA, INS - | lsr TMP0, INS, #16 - | csel RC, TMP0, RC, lo - | blo >5 - | ldr CARG3, [BASE, FRAME_FUNC] - | sub RC, RC, #8 - | add RA, BASE, RA, lsl #3 // Yes: RA = BASE+framesize*8, RC = nargs*8 - | and LFUNC:CARG3, CARG3, #LJ_GCVMASK - |5: - | br RB - | - |4: // Check frame below fast function. - | ldr CARG1, [BASE, FRAME_PC] - | ands CARG2, CARG1, #FRAME_TYPE - | bne <2 // Trace stitching continuation? - | // Otherwise set KBASE for Lua function below fast function. - | ldr CARG3w, [CARG1, #-4] - | decode_RA CARG1, CARG3 - | sub CARG2, BASE, CARG1, lsl #3 - | ldr LFUNC:CARG3, [CARG2, #-32] - | and LFUNC:CARG3, CARG3, #LJ_GCVMASK - | ldr CARG3, LFUNC:CARG3->pc - | ldr KBASE, [CARG3, #PC2PROTO(k)] - | b <2 - | - |9: // Rethrow error from the right C frame. - | neg CARG2, CARG1 - | mov CARG1, L - | bl extern lj_err_throw // (lua_State *L, int errcode) - |.endif - | - |//----------------------------------------------------------------------- - |//-- Math helper functions ---------------------------------------------- - |//----------------------------------------------------------------------- - | - | // int lj_vm_modi(int dividend, int divisor); - |->vm_modi: - | eor CARG4w, CARG1w, CARG2w - | cmp CARG4w, #0 - | eor CARG3w, CARG1w, CARG1w, asr #31 - | eor CARG4w, CARG2w, CARG2w, asr #31 - | sub CARG3w, CARG3w, CARG1w, asr #31 - | sub CARG4w, CARG4w, CARG2w, asr #31 - | udiv CARG1w, CARG3w, CARG4w - | msub CARG1w, CARG1w, CARG4w, CARG3w - | ccmp CARG1w, #0, #4, mi - | sub CARG3w, CARG1w, CARG4w - | csel CARG1w, CARG1w, CARG3w, eq - | eor CARG3w, CARG1w, CARG2w - | cmp CARG3w, #0 - | cneg CARG1w, CARG1w, mi - | ret - | - |//----------------------------------------------------------------------- - |//-- Miscellaneous functions -------------------------------------------- - |//----------------------------------------------------------------------- - | - |//----------------------------------------------------------------------- - |//-- FFI helper functions ----------------------------------------------- - |//----------------------------------------------------------------------- - | - |// Handler for callback functions. - |// Saveregs already performed. Callback slot number in [sp], g in r12. - |->vm_ffi_callback: - |.if FFI - |.type CTSTATE, CTState, PC - | saveregs - | ldr CTSTATE, GL:x10->ctype_state - | mov GL, x10 - | add x10, sp, # CFRAME_SPACE - | str w9, CTSTATE->cb.slot - | stp x0, x1, CTSTATE->cb.gpr[0] - | stp d0, d1, CTSTATE->cb.fpr[0] - | stp x2, x3, CTSTATE->cb.gpr[2] - | stp d2, d3, CTSTATE->cb.fpr[2] - | stp x4, x5, CTSTATE->cb.gpr[4] - | stp d4, d5, CTSTATE->cb.fpr[4] - | stp x6, x7, CTSTATE->cb.gpr[6] - | stp d6, d7, CTSTATE->cb.fpr[6] - | str x10, CTSTATE->cb.stack - | mov CARG1, CTSTATE - | str CTSTATE, SAVE_PC // Any value outside of bytecode is ok. - | mov CARG2, sp - | bl extern lj_ccallback_enter // (CTState *cts, void *cf) - | // Returns lua_State *. - | ldp BASE, RC, L:CRET1->base - | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48 - | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16 - | movn TISNIL, #0 - | mov L, CRET1 - | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] - | sub RC, RC, BASE - | st_vmstate ST_INTERP - | and LFUNC:CARG3, CARG3, #LJ_GCVMASK - | ins_callt - |.endif - | - |->cont_ffi_callback: // Return from FFI callback. - |.if FFI - | ldr CTSTATE, GL->ctype_state - | stp BASE, CARG4, L->base - | str L, CTSTATE->L - | mov CARG1, CTSTATE - | mov CARG2, RA - | bl extern lj_ccallback_leave // (CTState *cts, TValue *o) - | ldp x0, x1, CTSTATE->cb.gpr[0] - | ldp d0, d1, CTSTATE->cb.fpr[0] - | b ->vm_leave_unw - |.endif - | - |->vm_ffi_call: // Call C function via FFI. - | // Caveat: needs special frame unwinding, see below. - |.if FFI - | .type CCSTATE, CCallState, x19 - | stp fp, lr, [sp, #-32]! - | add fp, sp, #0 - | str CCSTATE, [sp, #16] - | mov CCSTATE, x0 - | ldr TMP0w, CCSTATE:x0->spadj - | ldrb TMP1w, CCSTATE->nsp - | add TMP2, CCSTATE, #offsetof(CCallState, stack) - | subs TMP1, TMP1, #1 - | ldr TMP3, CCSTATE->func - | sub sp, fp, TMP0 - | bmi >2 - |1: // Copy stack slots - | ldr TMP0, [TMP2, TMP1, lsl #3] - | str TMP0, [sp, TMP1, lsl #3] - | subs TMP1, TMP1, #1 - | bpl <1 - |2: - | ldp x0, x1, CCSTATE->gpr[0] - | ldp d0, d1, CCSTATE->fpr[0] - | ldp x2, x3, CCSTATE->gpr[2] - | ldp d2, d3, CCSTATE->fpr[2] - | ldp x4, x5, CCSTATE->gpr[4] - | ldp d4, d5, CCSTATE->fpr[4] - | ldp x6, x7, CCSTATE->gpr[6] - | ldp d6, d7, CCSTATE->fpr[6] - | ldr x8, CCSTATE->retp - | blr TMP3 - | mov sp, fp - | stp x0, x1, CCSTATE->gpr[0] - | stp d0, d1, CCSTATE->fpr[0] - | stp d2, d3, CCSTATE->fpr[2] - | ldr CCSTATE, [sp, #16] - | ldp fp, lr, [sp], #32 - | ret - |.endif - |// Note: vm_ffi_call must be the last function in this object file! - | - |//----------------------------------------------------------------------- -} - -/* Generate the code for a single instruction. */ -static void build_ins(BuildCtx *ctx, BCOp op, int defop) -{ - int vk = 0; - |=>defop: - - switch (op) { - - /* -- Comparison ops ---------------------------------------------------- */ - - /* Remember: all ops branch for a true comparison, fall through otherwise. */ - - case BC_ISLT: case BC_ISGE: case BC_ISLE: case BC_ISGT: - | // RA = src1, RC = src2, JMP with RC = target - | ldr CARG1, [BASE, RA, lsl #3] - | ldrh RBw, [PC, # OFS_RD] - | ldr CARG2, [BASE, RC, lsl #3] - | add PC, PC, #4 - | add RB, PC, RB, lsl #2 - | sub RB, RB, #0x20000 - | checkint CARG1, >3 - | checkint CARG2, >4 - | cmp CARG1w, CARG2w - if (op == BC_ISLT) { - | csel PC, RB, PC, lt - } else if (op == BC_ISGE) { - | csel PC, RB, PC, ge - } else if (op == BC_ISLE) { - | csel PC, RB, PC, le - } else { - | csel PC, RB, PC, gt - } - |1: - | ins_next - | - |3: // RA not int. - | ldr FARG1, [BASE, RA, lsl #3] - | blo ->vmeta_comp - | ldr FARG2, [BASE, RC, lsl #3] - | cmp TISNUMhi, CARG2, lsr #32 - | bhi >5 - | bne ->vmeta_comp - | // RA number, RC int. - | scvtf FARG2, CARG2w - | b >5 - | - |4: // RA int, RC not int - | ldr FARG2, [BASE, RC, lsl #3] - | blo ->vmeta_comp - | // RA int, RC number. - | scvtf FARG1, CARG1w - | - |5: // RA number, RC number - | fcmp FARG1, FARG2 - | // To preserve NaN semantics GE/GT branch on unordered, but LT/LE don't. - if (op == BC_ISLT) { - | csel PC, RB, PC, lo - } else if (op == BC_ISGE) { - | csel PC, RB, PC, hs - } else if (op == BC_ISLE) { - | csel PC, RB, PC, ls - } else { - | csel PC, RB, PC, hi - } - | b <1 - break; - - case BC_ISEQV: case BC_ISNEV: - vk = op == BC_ISEQV; - | // RA = src1, RC = src2, JMP with RC = target - | ldr CARG1, [BASE, RA, lsl #3] - | add RC, BASE, RC, lsl #3 - | ldrh RBw, [PC, # OFS_RD] - | ldr CARG3, [RC] - | add PC, PC, #4 - | add RB, PC, RB, lsl #2 - | sub RB, RB, #0x20000 - | asr ITYPE, CARG3, #47 - | cmn ITYPE, #-LJ_TISNUM - if (vk) { - | bls ->BC_ISEQN_Z - } else { - | bls ->BC_ISNEN_Z - } - | // RC is not a number. - | asr TMP0, CARG1, #47 - |.if FFI - | // Check if RC or RA is a cdata. - | cmn ITYPE, #-LJ_TCDATA - | ccmn TMP0, #-LJ_TCDATA, #4, ne - | beq ->vmeta_equal_cd - |.endif - | cmp CARG1, CARG3 - | bne >2 - | // Tag and value are equal. - if (vk) { - |->BC_ISEQV_Z: - | mov PC, RB // Perform branch. - } - |1: - | ins_next - | - |2: // Check if the tags are the same and it's a table or userdata. - | cmp ITYPE, TMP0 - | ccmn ITYPE, #-LJ_TISTABUD, #2, eq - if (vk) { - | bhi <1 - } else { - | bhi ->BC_ISEQV_Z // Reuse code from opposite instruction. - } - | // Different tables or userdatas. Need to check __eq metamethod. - | // Field metatable must be at same offset for GCtab and GCudata! - | and TAB:CARG2, CARG1, #LJ_GCVMASK - | ldr TAB:TMP2, TAB:CARG2->metatable - if (vk) { - | cbz TAB:TMP2, <1 // No metatable? - | ldrb TMP1w, TAB:TMP2->nomm - | mov CARG4, #0 // ne = 0 - | tbnz TMP1w, #MM_eq, <1 // 'no __eq' flag set: done. - } else { - | cbz TAB:TMP2, ->BC_ISEQV_Z // No metatable? - | ldrb TMP1w, TAB:TMP2->nomm - | mov CARG4, #1 // ne = 1. - | tbnz TMP1w, #MM_eq, ->BC_ISEQV_Z // 'no __eq' flag set: done. - } - | b ->vmeta_equal - break; - - case BC_ISEQS: case BC_ISNES: - vk = op == BC_ISEQS; - | // RA = src, RC = str_const (~), JMP with RC = target - | ldr CARG1, [BASE, RA, lsl #3] - | mvn RC, RC - | ldrh RBw, [PC, # OFS_RD] - | ldr CARG2, [KBASE, RC, lsl #3] - | add PC, PC, #4 - | movn TMP0, #~LJ_TSTR - |.if FFI - | asr ITYPE, CARG1, #47 - |.endif - | add RB, PC, RB, lsl #2 - | add CARG2, CARG2, TMP0, lsl #47 - | sub RB, RB, #0x20000 - |.if FFI - | cmn ITYPE, #-LJ_TCDATA - | beq ->vmeta_equal_cd - |.endif - | cmp CARG1, CARG2 - if (vk) { - | csel PC, RB, PC, eq - } else { - | csel PC, RB, PC, ne - } - | ins_next - break; - - case BC_ISEQN: case BC_ISNEN: - vk = op == BC_ISEQN; - | // RA = src, RC = num_const (~), JMP with RC = target - | ldr CARG1, [BASE, RA, lsl #3] - | add RC, KBASE, RC, lsl #3 - | ldrh RBw, [PC, # OFS_RD] - | ldr CARG3, [RC] - | add PC, PC, #4 - | add RB, PC, RB, lsl #2 - | sub RB, RB, #0x20000 - if (vk) { - |->BC_ISEQN_Z: - } else { - |->BC_ISNEN_Z: - } - | checkint CARG1, >4 - | checkint CARG3, >6 - | cmp CARG1w, CARG3w - |1: - if (vk) { - | csel PC, RB, PC, eq - |2: - } else { - |2: - | csel PC, RB, PC, ne - } - |3: - | ins_next - | - |4: // RA not int. - |.if FFI - | blo >7 - |.else - | blo <2 - |.endif - | ldr FARG1, [BASE, RA, lsl #3] - | ldr FARG2, [RC] - | cmp TISNUMhi, CARG3, lsr #32 - | bne >5 - | // RA number, RC int. - | scvtf FARG2, CARG3w - |5: - | // RA number, RC number. - | fcmp FARG1, FARG2 - | b <1 - | - |6: // RA int, RC number - | ldr FARG2, [RC] - | scvtf FARG1, CARG1w - | fcmp FARG1, FARG2 - | b <1 - | - |.if FFI - |7: - | asr ITYPE, CARG1, #47 - | cmn ITYPE, #-LJ_TCDATA - | bne <2 - | b ->vmeta_equal_cd - |.endif - break; - - case BC_ISEQP: case BC_ISNEP: - vk = op == BC_ISEQP; - | // RA = src, RC = primitive_type (~), JMP with RC = target - | ldr TMP0, [BASE, RA, lsl #3] - | ldrh RBw, [PC, # OFS_RD] - | add PC, PC, #4 - | add RC, RC, #1 - | add RB, PC, RB, lsl #2 - |.if FFI - | asr ITYPE, TMP0, #47 - | cmn ITYPE, #-LJ_TCDATA - | beq ->vmeta_equal_cd - | cmn RC, ITYPE - |.else - | cmn RC, TMP0, asr #47 - |.endif - | sub RB, RB, #0x20000 - if (vk) { - | csel PC, RB, PC, eq - } else { - | csel PC, RB, PC, ne - } - | ins_next - break; - - /* -- Unary test and copy ops ------------------------------------------- */ - - case BC_ISTC: case BC_ISFC: case BC_IST: case BC_ISF: - | // RA = dst or unused, RC = src, JMP with RC = target - | ldrh RBw, [PC, # OFS_RD] - | ldr TMP0, [BASE, RC, lsl #3] - | add PC, PC, #4 - | mov_false TMP1 - | add RB, PC, RB, lsl #2 - | cmp TMP0, TMP1 - | sub RB, RB, #0x20000 - if (op == BC_ISTC || op == BC_IST) { - if (op == BC_ISTC) { - | csel RA, RA, RC, lo - } - | csel PC, RB, PC, lo - } else { - if (op == BC_ISFC) { - | csel RA, RA, RC, hs - } - | csel PC, RB, PC, hs - } - if (op == BC_ISTC || op == BC_ISFC) { - | str TMP0, [BASE, RA, lsl #3] - } - | ins_next - break; - - case BC_ISTYPE: - | // RA = src, RC = -type - | ldr TMP0, [BASE, RA, lsl #3] - | cmn RC, TMP0, asr #47 - | bne ->vmeta_istype - | ins_next - break; - case BC_ISNUM: - | // RA = src, RC = -(TISNUM-1) - | ldr TMP0, [BASE, RA] - | checknum TMP0, ->vmeta_istype - | ins_next - break; - - /* -- Unary ops --------------------------------------------------------- */ - - case BC_MOV: - | // RA = dst, RC = src - | ldr TMP0, [BASE, RC, lsl #3] - | str TMP0, [BASE, RA, lsl #3] - | ins_next - break; - case BC_NOT: - | // RA = dst, RC = src - | ldr TMP0, [BASE, RC, lsl #3] - | mov_false TMP1 - | mov_true TMP2 - | cmp TMP0, TMP1 - | csel TMP0, TMP1, TMP2, lo - | str TMP0, [BASE, RA, lsl #3] - | ins_next - break; - case BC_UNM: - | // RA = dst, RC = src - | ldr TMP0, [BASE, RC, lsl #3] - | asr ITYPE, TMP0, #47 - | cmn ITYPE, #-LJ_TISNUM - | bhi ->vmeta_unm - | eor TMP0, TMP0, #U64x(80000000,00000000) - | bne >5 - | negs TMP0w, TMP0w - | movz CARG3, #0x41e0, lsl #48 // 2^31. - | add TMP0, TMP0, TISNUM - | csel TMP0, TMP0, CARG3, vc - |5: - | str TMP0, [BASE, RA, lsl #3] - | ins_next - break; - case BC_LEN: - | // RA = dst, RC = src - | ldr CARG1, [BASE, RC, lsl #3] - | asr ITYPE, CARG1, #47 - | cmn ITYPE, #-LJ_TSTR - | and CARG1, CARG1, #LJ_GCVMASK - | bne >2 - | ldr CARG1w, STR:CARG1->len - |1: - | add CARG1, CARG1, TISNUM - | str CARG1, [BASE, RA, lsl #3] - | ins_next - | - |2: - | cmn ITYPE, #-LJ_TTAB - | bne ->vmeta_len -#if LJ_52 - | ldr TAB:CARG2, TAB:CARG1->metatable - | cbnz TAB:CARG2, >9 - |3: -#endif - |->BC_LEN_Z: - | bl extern lj_tab_len // (GCtab *t) - | // Returns uint32_t (but less than 2^31). - | b <1 - | -#if LJ_52 - |9: - | ldrb TMP1w, TAB:CARG2->nomm - | tbnz TMP1w, #MM_len, <3 // 'no __len' flag set: done. - | b ->vmeta_len -#endif - break; - - /* -- Binary ops -------------------------------------------------------- */ - - |.macro ins_arithcheck_int, target - | checkint CARG1, target - | checkint CARG2, target - |.endmacro - | - |.macro ins_arithcheck_num, target - | checknum CARG1, target - | checknum CARG2, target - |.endmacro - | - |.macro ins_arithcheck_nzdiv, target - | cbz CARG2w, target - |.endmacro - | - |.macro ins_arithhead - ||vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN); - ||if (vk == 1) { - | and RC, RC, #255 - | decode_RB RB, INS - ||} else { - | decode_RB RB, INS - | and RC, RC, #255 - ||} - |.endmacro - | - |.macro ins_arithload, reg1, reg2 - | // RA = dst, RB = src1, RC = src2 | num_const - ||switch (vk) { - ||case 0: - | ldr reg1, [BASE, RB, lsl #3] - | ldr reg2, [KBASE, RC, lsl #3] - || break; - ||case 1: - | ldr reg1, [KBASE, RC, lsl #3] - | ldr reg2, [BASE, RB, lsl #3] - || break; - ||default: - | ldr reg1, [BASE, RB, lsl #3] - | ldr reg2, [BASE, RC, lsl #3] - || break; - ||} - |.endmacro - | - |.macro ins_arithfallback, ins - ||switch (vk) { - ||case 0: - | ins ->vmeta_arith_vn - || break; - ||case 1: - | ins ->vmeta_arith_nv - || break; - ||default: - | ins ->vmeta_arith_vv - || break; - ||} - |.endmacro - | - |.macro ins_arithmod, res, reg1, reg2 - | fdiv d2, reg1, reg2 - | frintm d2, d2 - | fmsub res, d2, reg2, reg1 - |.endmacro - | - |.macro ins_arithdn, intins, fpins - | ins_arithhead - | ins_arithload CARG1, CARG2 - | ins_arithcheck_int >5 - |.if "intins" == "smull" - | smull CARG1, CARG1w, CARG2w - | cmp CARG1, CARG1, sxtw - | mov CARG1w, CARG1w - | ins_arithfallback bne - |.elif "intins" == "ins_arithmodi" - | ins_arithfallback ins_arithcheck_nzdiv - | bl ->vm_modi - |.else - | intins CARG1w, CARG1w, CARG2w - | ins_arithfallback bvs - |.endif - | add CARG1, CARG1, TISNUM - | str CARG1, [BASE, RA, lsl #3] - |4: - | ins_next - | - |5: // FP variant. - | ins_arithload FARG1, FARG2 - | ins_arithfallback ins_arithcheck_num - | fpins FARG1, FARG1, FARG2 - | str FARG1, [BASE, RA, lsl #3] - | b <4 - |.endmacro - | - |.macro ins_arithfp, fpins - | ins_arithhead - | ins_arithload CARG1, CARG2 - | ins_arithload FARG1, FARG2 - | ins_arithfallback ins_arithcheck_num - |.if "fpins" == "fpow" - | bl extern pow - |.else - | fpins FARG1, FARG1, FARG2 - |.endif - | str FARG1, [BASE, RA, lsl #3] - | ins_next - |.endmacro - - case BC_ADDVN: case BC_ADDNV: case BC_ADDVV: - | ins_arithdn adds, fadd - break; - case BC_SUBVN: case BC_SUBNV: case BC_SUBVV: - | ins_arithdn subs, fsub - break; - case BC_MULVN: case BC_MULNV: case BC_MULVV: - | ins_arithdn smull, fmul - break; - case BC_DIVVN: case BC_DIVNV: case BC_DIVVV: - | ins_arithfp fdiv - break; - case BC_MODVN: case BC_MODNV: case BC_MODVV: - | ins_arithdn ins_arithmodi, ins_arithmod - break; - case BC_POW: - | // NYI: (partial) integer arithmetic. - | ins_arithfp fpow - break; - - case BC_CAT: - | decode_RB RB, INS - | and RC, RC, #255 - | // RA = dst, RB = src_start, RC = src_end - | str BASE, L->base - | sub CARG3, RC, RB - | add CARG2, BASE, RC, lsl #3 - |->BC_CAT_Z: - | // RA = dst, CARG2 = top-1, CARG3 = left - | mov CARG1, L - | str PC, SAVE_PC - | bl extern lj_meta_cat // (lua_State *L, TValue *top, int left) - | // Returns NULL (finished) or TValue * (metamethod). - | ldrb RBw, [PC, #-4+OFS_RB] - | ldr BASE, L->base - | cbnz CRET1, ->vmeta_binop - | ldr TMP0, [BASE, RB, lsl #3] - | str TMP0, [BASE, RA, lsl #3] // Copy result to RA. - | ins_next - break; - - /* -- Constant ops ------------------------------------------------------ */ - - case BC_KSTR: - | // RA = dst, RC = str_const (~) - | mvn RC, RC - | ldr TMP0, [KBASE, RC, lsl #3] - | movn TMP1, #~LJ_TSTR - | add TMP0, TMP0, TMP1, lsl #47 - | str TMP0, [BASE, RA, lsl #3] - | ins_next - break; - case BC_KCDATA: - |.if FFI - | // RA = dst, RC = cdata_const (~) - | mvn RC, RC - | ldr TMP0, [KBASE, RC, lsl #3] - | movn TMP1, #~LJ_TCDATA - | add TMP0, TMP0, TMP1, lsl #47 - | str TMP0, [BASE, RA, lsl #3] - | ins_next - |.endif - break; - case BC_KSHORT: - | // RA = dst, RC = int16_literal - | sxth RCw, RCw - | add TMP0, RC, TISNUM - | str TMP0, [BASE, RA, lsl #3] - | ins_next - break; - case BC_KNUM: - | // RA = dst, RC = num_const - | ldr TMP0, [KBASE, RC, lsl #3] - | str TMP0, [BASE, RA, lsl #3] - | ins_next - break; - case BC_KPRI: - | // RA = dst, RC = primitive_type (~) - | mvn TMP0, RC, lsl #47 - | str TMP0, [BASE, RA, lsl #3] - | ins_next - break; - case BC_KNIL: - | // RA = base, RC = end - | add RA, BASE, RA, lsl #3 - | add RC, BASE, RC, lsl #3 - | str TISNIL, [RA], #8 - |1: - | cmp RA, RC - | str TISNIL, [RA], #8 - | blt <1 - | ins_next_ - break; - - /* -- Upvalue and function ops ------------------------------------------ */ - - case BC_UGET: - | // RA = dst, RC = uvnum - | ldr LFUNC:CARG2, [BASE, FRAME_FUNC] - | add RC, RC, #offsetof(GCfuncL, uvptr)/8 - | and LFUNC:CARG2, CARG2, #LJ_GCVMASK - | ldr UPVAL:CARG2, [LFUNC:CARG2, RC, lsl #3] - | ldr CARG2, UPVAL:CARG2->v - | ldr TMP0, [CARG2] - | str TMP0, [BASE, RA, lsl #3] - | ins_next - break; - case BC_USETV: - | // RA = uvnum, RC = src - | ldr LFUNC:CARG2, [BASE, FRAME_FUNC] - | add RA, RA, #offsetof(GCfuncL, uvptr)/8 - | and LFUNC:CARG2, CARG2, #LJ_GCVMASK - | ldr UPVAL:CARG1, [LFUNC:CARG2, RA, lsl #3] - | ldr CARG3, [BASE, RC, lsl #3] - | ldr CARG2, UPVAL:CARG1->v - | ldrb TMP2w, UPVAL:CARG1->marked - | ldrb TMP0w, UPVAL:CARG1->closed - | asr ITYPE, CARG3, #47 - | str CARG3, [CARG2] - | add ITYPE, ITYPE, #-LJ_TISGCV - | tst TMP2w, #LJ_GC_BLACK // isblack(uv) - | ccmp TMP0w, #0, #4, ne // && uv->closed - | ccmn ITYPE, #-(LJ_TNUMX - LJ_TISGCV), #0, ne // && tvisgcv(v) - | bhi >2 - |1: - | ins_next - | - |2: // Check if new value is white. - | and GCOBJ:CARG3, CARG3, #LJ_GCVMASK - | ldrb TMP1w, GCOBJ:CARG3->gch.marked - | tst TMP1w, #LJ_GC_WHITES // iswhite(str) - | beq <1 - | // Crossed a write barrier. Move the barrier forward. - | mov CARG1, GL - | bl extern lj_gc_barrieruv // (global_State *g, TValue *tv) - | b <1 - break; - case BC_USETS: - | // RA = uvnum, RC = str_const (~) - | ldr LFUNC:CARG2, [BASE, FRAME_FUNC] - | add RA, RA, #offsetof(GCfuncL, uvptr)/8 - | mvn RC, RC - | and LFUNC:CARG2, CARG2, #LJ_GCVMASK - | ldr UPVAL:CARG1, [LFUNC:CARG2, RA, lsl #3] - | ldr STR:CARG3, [KBASE, RC, lsl #3] - | movn TMP0, #~LJ_TSTR - | ldr CARG2, UPVAL:CARG1->v - | ldrb TMP2w, UPVAL:CARG1->marked - | add TMP0, STR:CARG3, TMP0, lsl #47 - | ldrb TMP1w, STR:CARG3->marked - | str TMP0, [CARG2] - | tbnz TMP2w, #2, >2 // isblack(uv) - |1: - | ins_next - | - |2: // Check if string is white and ensure upvalue is closed. - | ldrb TMP0w, UPVAL:CARG1->closed - | tst TMP1w, #LJ_GC_WHITES // iswhite(str) - | ccmp TMP0w, #0, #4, ne - | beq <1 - | // Crossed a write barrier. Move the barrier forward. - | mov CARG1, GL - | bl extern lj_gc_barrieruv // (global_State *g, TValue *tv) - | b <1 - break; - case BC_USETN: - | // RA = uvnum, RC = num_const - | ldr LFUNC:CARG2, [BASE, FRAME_FUNC] - | add RA, RA, #offsetof(GCfuncL, uvptr)/8 - | and LFUNC:CARG2, CARG2, #LJ_GCVMASK - | ldr UPVAL:CARG2, [LFUNC:CARG2, RA, lsl #3] - | ldr TMP0, [KBASE, RC, lsl #3] - | ldr CARG2, UPVAL:CARG2->v - | str TMP0, [CARG2] - | ins_next - break; - case BC_USETP: - | // RA = uvnum, RC = primitive_type (~) - | ldr LFUNC:CARG2, [BASE, FRAME_FUNC] - | add RA, RA, #offsetof(GCfuncL, uvptr)/8 - | and LFUNC:CARG2, CARG2, #LJ_GCVMASK - | ldr UPVAL:CARG2, [LFUNC:CARG2, RA, lsl #3] - | mvn TMP0, RC, lsl #47 - | ldr CARG2, UPVAL:CARG2->v - | str TMP0, [CARG2] - | ins_next - break; - - case BC_UCLO: - | // RA = level, RC = target - | ldr CARG3, L->openupval - | add RC, PC, RC, lsl #2 - | str BASE, L->base - | sub PC, RC, #0x20000 - | cbz CARG3, >1 - | mov CARG1, L - | add CARG2, BASE, RA, lsl #3 - | bl extern lj_func_closeuv // (lua_State *L, TValue *level) - | ldr BASE, L->base - |1: - | ins_next - break; - - case BC_FNEW: - | // RA = dst, RC = proto_const (~) (holding function prototype) - | mvn RC, RC - | str BASE, L->base - | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] - | str PC, SAVE_PC - | ldr CARG2, [KBASE, RC, lsl #3] - | mov CARG1, L - | and LFUNC:CARG3, CARG3, #LJ_GCVMASK - | // (lua_State *L, GCproto *pt, GCfuncL *parent) - | bl extern lj_func_newL_gc - | // Returns GCfuncL *. - | ldr BASE, L->base - | movn TMP0, #~LJ_TFUNC - | add CRET1, CRET1, TMP0, lsl #47 - | str CRET1, [BASE, RA, lsl #3] - | ins_next - break; - - /* -- Table ops --------------------------------------------------------- */ - - case BC_TNEW: - case BC_TDUP: - | // RA = dst, RC = (hbits|asize) | tab_const (~) - | ldp CARG3, CARG4, GL->gc.total // Assumes threshold follows total. - | str BASE, L->base - | str PC, SAVE_PC - | mov CARG1, L - | cmp CARG3, CARG4 - | bhs >5 - |1: - if (op == BC_TNEW) { - | and CARG2, RC, #0x7ff - | lsr CARG3, RC, #11 - | cmp CARG2, #0x7ff - | mov TMP0, #0x801 - | csel CARG2, CARG2, TMP0, ne - | bl extern lj_tab_new // (lua_State *L, int32_t asize, uint32_t hbits) - | // Returns GCtab *. - } else { - | mvn RC, RC - | ldr CARG2, [KBASE, RC, lsl #3] - | bl extern lj_tab_dup // (lua_State *L, Table *kt) - | // Returns GCtab *. - } - | ldr BASE, L->base - | movk CRET1, #(LJ_TTAB>>1)&0xffff, lsl #48 - | str CRET1, [BASE, RA, lsl #3] - | ins_next - | - |5: - | bl extern lj_gc_step_fixtop // (lua_State *L) - | mov CARG1, L - | b <1 - break; - - case BC_GGET: - | // RA = dst, RC = str_const (~) - case BC_GSET: - | // RA = dst, RC = str_const (~) - | ldr LFUNC:CARG1, [BASE, FRAME_FUNC] - | mvn RC, RC - | and LFUNC:CARG1, CARG1, #LJ_GCVMASK - | ldr TAB:CARG2, LFUNC:CARG1->env - | ldr STR:RC, [KBASE, RC, lsl #3] - if (op == BC_GGET) { - | b ->BC_TGETS_Z - } else { - | b ->BC_TSETS_Z - } - break; - - case BC_TGETV: - | decode_RB RB, INS - | and RC, RC, #255 - | // RA = dst, RB = table, RC = key - | ldr CARG2, [BASE, RB, lsl #3] - | ldr TMP1, [BASE, RC, lsl #3] - | checktab CARG2, ->vmeta_tgetv - | checkint TMP1, >9 // Integer key? - | ldr CARG3, TAB:CARG2->array - | ldr CARG1w, TAB:CARG2->asize - | add CARG3, CARG3, TMP1, uxtw #3 - | cmp TMP1w, CARG1w // In array part? - | bhs ->vmeta_tgetv - | ldr TMP0, [CARG3] - | cmp TMP0, TISNIL - | beq >5 - |1: - | str TMP0, [BASE, RA, lsl #3] - | ins_next - | - |5: // Check for __index if table value is nil. - | ldr TAB:CARG1, TAB:CARG2->metatable - | cbz TAB:CARG1, <1 // No metatable: done. - | ldrb TMP1w, TAB:CARG1->nomm - | tbnz TMP1w, #MM_index, <1 // 'no __index' flag set: done. - | b ->vmeta_tgetv - | - |9: - | asr ITYPE, TMP1, #47 - | cmn ITYPE, #-LJ_TSTR // String key? - | bne ->vmeta_tgetv - | and STR:RC, TMP1, #LJ_GCVMASK - | b ->BC_TGETS_Z - break; - case BC_TGETS: - | decode_RB RB, INS - | and RC, RC, #255 - | // RA = dst, RB = table, RC = str_const (~) - | ldr CARG2, [BASE, RB, lsl #3] - | mvn RC, RC - | ldr STR:RC, [KBASE, RC, lsl #3] - | checktab CARG2, ->vmeta_tgets1 - |->BC_TGETS_Z: - | // TAB:CARG2 = GCtab *, STR:RC = GCstr *, RA = dst - | ldr TMP1w, TAB:CARG2->hmask - | ldr TMP2w, STR:RC->hash - | ldr NODE:CARG3, TAB:CARG2->node - | and TMP1w, TMP1w, TMP2w // idx = str->hash & tab->hmask - | add TMP1, TMP1, TMP1, lsl #1 - | movn CARG4, #~LJ_TSTR - | add NODE:CARG3, NODE:CARG3, TMP1, lsl #3 // node = tab->node + idx*3*8 - | add CARG4, STR:RC, CARG4, lsl #47 // Tagged key to look for. - |1: - | ldp TMP0, CARG1, NODE:CARG3->val - | ldr NODE:CARG3, NODE:CARG3->next - | cmp CARG1, CARG4 - | bne >4 - | cmp TMP0, TISNIL - | beq >5 - |3: - | str TMP0, [BASE, RA, lsl #3] - | ins_next - | - |4: // Follow hash chain. - | cbnz NODE:CARG3, <1 - | // End of hash chain: key not found, nil result. - | mov TMP0, TISNIL - | - |5: // Check for __index if table value is nil. - | ldr TAB:CARG1, TAB:CARG2->metatable - | cbz TAB:CARG1, <3 // No metatable: done. - | ldrb TMP1w, TAB:CARG1->nomm - | tbnz TMP1w, #MM_index, <3 // 'no __index' flag set: done. - | b ->vmeta_tgets - break; - case BC_TGETB: - | decode_RB RB, INS - | and RC, RC, #255 - | // RA = dst, RB = table, RC = index - | ldr CARG2, [BASE, RB, lsl #3] - | checktab CARG2, ->vmeta_tgetb - | ldr CARG3, TAB:CARG2->array - | ldr CARG1w, TAB:CARG2->asize - | add CARG3, CARG3, RC, lsl #3 - | cmp RCw, CARG1w // In array part? - | bhs ->vmeta_tgetb - | ldr TMP0, [CARG3] - | cmp TMP0, TISNIL - | beq >5 - |1: - | str TMP0, [BASE, RA, lsl #3] - | ins_next - | - |5: // Check for __index if table value is nil. - | ldr TAB:CARG1, TAB:CARG2->metatable - | cbz TAB:CARG1, <1 // No metatable: done. - | ldrb TMP1w, TAB:CARG1->nomm - | tbnz TMP1w, #MM_index, <1 // 'no __index' flag set: done. - | b ->vmeta_tgetb - break; - case BC_TGETR: - | decode_RB RB, INS - | and RC, RC, #255 - | // RA = dst, RB = table, RC = key - | ldr CARG1, [BASE, RB, lsl #3] - | ldr TMP1, [BASE, RC, lsl #3] - | and TAB:CARG1, CARG1, #LJ_GCVMASK - | ldr CARG3, TAB:CARG1->array - | ldr TMP2w, TAB:CARG1->asize - | add CARG3, CARG3, TMP1w, uxtw #3 - | cmp TMP1w, TMP2w // In array part? - | bhs ->vmeta_tgetr - | ldr TMP0, [CARG3] - |->BC_TGETR_Z: - | str TMP0, [BASE, RA, lsl #3] - | ins_next - break; - - case BC_TSETV: - | decode_RB RB, INS - | and RC, RC, #255 - | // RA = src, RB = table, RC = key - | ldr CARG2, [BASE, RB, lsl #3] - | ldr TMP1, [BASE, RC, lsl #3] - | checktab CARG2, ->vmeta_tsetv - | checkint TMP1, >9 // Integer key? - | ldr CARG3, TAB:CARG2->array - | ldr CARG1w, TAB:CARG2->asize - | add CARG3, CARG3, TMP1, uxtw #3 - | cmp TMP1w, CARG1w // In array part? - | bhs ->vmeta_tsetv - | ldr TMP1, [CARG3] - | ldr TMP0, [BASE, RA, lsl #3] - | ldrb TMP2w, TAB:CARG2->marked - | cmp TMP1, TISNIL // Previous value is nil? - | beq >5 - |1: - | str TMP0, [CARG3] - | tbnz TMP2w, #2, >7 // isblack(table) - |2: - | ins_next - | - |5: // Check for __newindex if previous value is nil. - | ldr TAB:CARG1, TAB:CARG2->metatable - | cbz TAB:CARG1, <1 // No metatable: done. - | ldrb TMP1w, TAB:CARG1->nomm - | tbnz TMP1w, #MM_newindex, <1 // 'no __newindex' flag set: done. - | b ->vmeta_tsetv - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:CARG2, TMP2w, TMP1 - | b <2 - | - |9: - | asr ITYPE, TMP1, #47 - | cmn ITYPE, #-LJ_TSTR // String key? - | bne ->vmeta_tsetv - | and STR:RC, TMP1, #LJ_GCVMASK - | b ->BC_TSETS_Z - break; - case BC_TSETS: - | decode_RB RB, INS - | and RC, RC, #255 - | // RA = dst, RB = table, RC = str_const (~) - | ldr CARG2, [BASE, RB, lsl #3] - | mvn RC, RC - | ldr STR:RC, [KBASE, RC, lsl #3] - | checktab CARG2, ->vmeta_tsets1 - |->BC_TSETS_Z: - | // TAB:CARG2 = GCtab *, STR:RC = GCstr *, RA = src - | ldr TMP1w, TAB:CARG2->hmask - | ldr TMP2w, STR:RC->hash - | ldr NODE:CARG3, TAB:CARG2->node - | and TMP1w, TMP1w, TMP2w // idx = str->hash & tab->hmask - | add TMP1, TMP1, TMP1, lsl #1 - | movn CARG4, #~LJ_TSTR - | add NODE:CARG3, NODE:CARG3, TMP1, lsl #3 // node = tab->node + idx*3*8 - | add CARG4, STR:RC, CARG4, lsl #47 // Tagged key to look for. - | strb wzr, TAB:CARG2->nomm // Clear metamethod cache. - |1: - | ldp TMP1, CARG1, NODE:CARG3->val - | ldr NODE:TMP3, NODE:CARG3->next - | ldrb TMP2w, TAB:CARG2->marked - | cmp CARG1, CARG4 - | bne >5 - | ldr TMP0, [BASE, RA, lsl #3] - | cmp TMP1, TISNIL // Previous value is nil? - | beq >4 - |2: - | str TMP0, NODE:CARG3->val - | tbnz TMP2w, #2, >7 // isblack(table) - |3: - | ins_next - | - |4: // Check for __newindex if previous value is nil. - | ldr TAB:CARG1, TAB:CARG2->metatable - | cbz TAB:CARG1, <2 // No metatable: done. - | ldrb TMP1w, TAB:CARG1->nomm - | tbnz TMP1w, #MM_newindex, <2 // 'no __newindex' flag set: done. - | b ->vmeta_tsets - | - |5: // Follow hash chain. - | mov NODE:CARG3, NODE:TMP3 - | cbnz NODE:TMP3, <1 - | // End of hash chain: key not found, add a new one. - | - | // But check for __newindex first. - | ldr TAB:CARG1, TAB:CARG2->metatable - | cbz TAB:CARG1, >6 // No metatable: continue. - | ldrb TMP1w, TAB:CARG1->nomm - | // 'no __newindex' flag NOT set: check. - | tbz TMP1w, #MM_newindex, ->vmeta_tsets - |6: - | movn TMP1, #~LJ_TSTR - | str PC, SAVE_PC - | add TMP0, STR:RC, TMP1, lsl #47 - | str BASE, L->base - | mov CARG1, L - | str TMP0, TMPD - | add CARG3, sp, TMPDofs - | bl extern lj_tab_newkey // (lua_State *L, GCtab *t, TValue *k) - | // Returns TValue *. - | ldr BASE, L->base - | ldr TMP0, [BASE, RA, lsl #3] - | str TMP0, [CRET1] - | b <3 // No 2nd write barrier needed. - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:CARG2, TMP2w, TMP1 - | b <3 - break; - case BC_TSETB: - | decode_RB RB, INS - | and RC, RC, #255 - | // RA = src, RB = table, RC = index - | ldr CARG2, [BASE, RB, lsl #3] - | checktab CARG2, ->vmeta_tsetb - | ldr CARG3, TAB:CARG2->array - | ldr CARG1w, TAB:CARG2->asize - | add CARG3, CARG3, RC, lsl #3 - | cmp RCw, CARG1w // In array part? - | bhs ->vmeta_tsetb - | ldr TMP1, [CARG3] - | ldr TMP0, [BASE, RA, lsl #3] - | ldrb TMP2w, TAB:CARG2->marked - | cmp TMP1, TISNIL // Previous value is nil? - | beq >5 - |1: - | str TMP0, [CARG3] - | tbnz TMP2w, #2, >7 // isblack(table) - |2: - | ins_next - | - |5: // Check for __newindex if previous value is nil. - | ldr TAB:CARG1, TAB:CARG2->metatable - | cbz TAB:CARG1, <1 // No metatable: done. - | ldrb TMP1w, TAB:CARG1->nomm - | tbnz TMP1w, #MM_newindex, <1 // 'no __newindex' flag set: done. - | b ->vmeta_tsetb - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:CARG2, TMP2w, TMP1 - | b <2 - break; - case BC_TSETR: - | decode_RB RB, INS - | and RC, RC, #255 - | // RA = src, RB = table, RC = key - | ldr CARG2, [BASE, RB, lsl #3] - | ldr TMP1, [BASE, RC, lsl #3] - | and TAB:CARG2, CARG2, #LJ_GCVMASK - | ldr CARG1, TAB:CARG2->array - | ldrb TMP2w, TAB:CARG2->marked - | ldr CARG4w, TAB:CARG2->asize - | add CARG1, CARG1, TMP1, uxtw #3 - | tbnz TMP2w, #2, >7 // isblack(table) - |2: - | cmp TMP1w, CARG4w // In array part? - | bhs ->vmeta_tsetr - |->BC_TSETR_Z: - | ldr TMP0, [BASE, RA, lsl #3] - | str TMP0, [CARG1] - | ins_next - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:CARG2, TMP2w, TMP0 - | b <2 - break; - - case BC_TSETM: - | // RA = base (table at base-1), RC = num_const (start index) - | add RA, BASE, RA, lsl #3 - |1: - | ldr RBw, SAVE_MULTRES - | ldr TAB:CARG2, [RA, #-8] // Guaranteed to be a table. - | ldr TMP1, [KBASE, RC, lsl #3] // Integer constant is in lo-word. - | sub RB, RB, #8 - | cbz RB, >4 // Nothing to copy? - | and TAB:CARG2, CARG2, #LJ_GCVMASK - | ldr CARG1w, TAB:CARG2->asize - | add CARG3w, TMP1w, RBw, lsr #3 - | ldr CARG4, TAB:CARG2->array - | cmp CARG3, CARG1 - | add RB, RA, RB - | bhi >5 - | add TMP1, CARG4, TMP1w, uxtw #3 - | ldrb TMP2w, TAB:CARG2->marked - |3: // Copy result slots to table. - | ldr TMP0, [RA], #8 - | str TMP0, [TMP1], #8 - | cmp RA, RB - | blo <3 - | tbnz TMP2w, #2, >7 // isblack(table) - |4: - | ins_next - | - |5: // Need to resize array part. - | str BASE, L->base - | mov CARG1, L - | str PC, SAVE_PC - | bl extern lj_tab_reasize // (lua_State *L, GCtab *t, int nasize) - | // Must not reallocate the stack. - | b <1 - | - |7: // Possible table write barrier for any value. Skip valiswhite check. - | barrierback TAB:CARG2, TMP2w, TMP1 - | b <4 - break; - - /* -- Calls and vararg handling ----------------------------------------- */ - - case BC_CALLM: - | // RA = base, (RB = nresults+1,) RC = extra_nargs - | ldr TMP0w, SAVE_MULTRES - | decode_RC8RD NARGS8:RC, RC - | add NARGS8:RC, NARGS8:RC, TMP0 - | b ->BC_CALL_Z - break; - case BC_CALL: - | decode_RC8RD NARGS8:RC, RC - | // RA = base, (RB = nresults+1,) RC = (nargs+1)*8 - |->BC_CALL_Z: - | mov RB, BASE // Save old BASE for vmeta_call. - | add BASE, BASE, RA, lsl #3 - | ldr CARG3, [BASE] - | sub NARGS8:RC, NARGS8:RC, #8 - | add BASE, BASE, #16 - | checkfunc CARG3, ->vmeta_call - | ins_call - break; - - case BC_CALLMT: - | // RA = base, (RB = 0,) RC = extra_nargs - | ldr TMP0w, SAVE_MULTRES - | add NARGS8:RC, TMP0, RC, lsl #3 - | b ->BC_CALLT1_Z - break; - case BC_CALLT: - | lsl NARGS8:RC, RC, #3 - | // RA = base, (RB = 0,) RC = (nargs+1)*8 - |->BC_CALLT1_Z: - | add RA, BASE, RA, lsl #3 - | ldr TMP1, [RA] - | sub NARGS8:RC, NARGS8:RC, #8 - | add RA, RA, #16 - | checktp CARG3, TMP1, LJ_TFUNC, ->vmeta_callt - | ldr PC, [BASE, FRAME_PC] - |->BC_CALLT2_Z: - | mov RB, #0 - | ldrb TMP2w, LFUNC:CARG3->ffid - | tst PC, #FRAME_TYPE - | bne >7 - |1: - | str TMP1, [BASE, FRAME_FUNC] // Copy function down, but keep PC. - | cbz NARGS8:RC, >3 - |2: - | ldr TMP0, [RA, RB] - | add TMP1, RB, #8 - | cmp TMP1, NARGS8:RC - | str TMP0, [BASE, RB] - | mov RB, TMP1 - | bne <2 - |3: - | cmp TMP2, #1 // (> FF_C) Calling a fast function? - | bhi >5 - |4: - | ins_callt - | - |5: // Tailcall to a fast function with a Lua frame below. - | ldrb RAw, [PC, #-4+OFS_RA] - | sub CARG1, BASE, RA, lsl #3 - | ldr LFUNC:CARG1, [CARG1, #-32] - | and LFUNC:CARG1, CARG1, #LJ_GCVMASK - | ldr CARG1, LFUNC:CARG1->pc - | ldr KBASE, [CARG1, #PC2PROTO(k)] - | b <4 - | - |7: // Tailcall from a vararg function. - | eor PC, PC, #FRAME_VARG - | tst PC, #FRAME_TYPEP // Vararg frame below? - | csel TMP2, RB, TMP2, ne // Clear ffid if no Lua function below. - | bne <1 - | sub BASE, BASE, PC - | ldr PC, [BASE, FRAME_PC] - | tst PC, #FRAME_TYPE - | csel TMP2, RB, TMP2, ne // Clear ffid if no Lua function below. - | b <1 - break; - - case BC_ITERC: - | // RA = base, (RB = nresults+1, RC = nargs+1 (2+1)) - | add RA, BASE, RA, lsl #3 - | ldr CARG3, [RA, #-24] - | mov RB, BASE // Save old BASE for vmeta_call. - | ldp CARG1, CARG2, [RA, #-16] - | add BASE, RA, #16 - | mov NARGS8:RC, #16 // Iterators get 2 arguments. - | str CARG3, [RA] // Copy callable. - | stp CARG1, CARG2, [RA, #16] // Copy state and control var. - | checkfunc CARG3, ->vmeta_call - | ins_call - break; - - case BC_ITERN: - | // RA = base, (RB = nresults+1, RC = nargs+1 (2+1)) - |.if JIT - | // NYI: add hotloop, record BC_ITERN. - |.endif - | add RA, BASE, RA, lsl #3 - | ldr TAB:RB, [RA, #-16] - | ldrh TMP3w, [PC, # OFS_RD] - | ldr CARG1w, [RA, #-8+LO] // Get index from control var. - | add PC, PC, #4 - | add TMP3, PC, TMP3, lsl #2 - | and TAB:RB, RB, #LJ_GCVMASK - | sub TMP3, TMP3, #0x20000 - | ldr TMP1w, TAB:RB->asize - | ldr CARG2, TAB:RB->array - |1: // Traverse array part. - | subs RC, CARG1, TMP1 - | add CARG3, CARG2, CARG1, lsl #3 - | bhs >5 // Index points after array part? - | ldr TMP0, [CARG3] - | cmp TMP0, TISNIL - | cinc CARG1, CARG1, eq // Skip holes in array part. - | beq <1 - | add CARG1, CARG1, TISNUM - | stp CARG1, TMP0, [RA] - | add CARG1, CARG1, #1 - |3: - | str CARG1w, [RA, #-8+LO] // Update control var. - | mov PC, TMP3 - |4: - | ins_next - | - |5: // Traverse hash part. - | ldr TMP2w, TAB:RB->hmask - | ldr NODE:RB, TAB:RB->node - |6: - | add CARG1, RC, RC, lsl #1 - | cmp RC, TMP2 // End of iteration? Branch to ITERN+1. - | add NODE:CARG3, NODE:RB, CARG1, lsl #3 // node = tab->node + idx*3*8 - | bhi <4 - | ldp TMP0, CARG1, NODE:CARG3->val - | cmp TMP0, TISNIL - | add RC, RC, #1 - | beq <6 // Skip holes in hash part. - | stp CARG1, TMP0, [RA] - | add CARG1, RC, TMP1 - | b <3 - break; - - case BC_ISNEXT: - | // RA = base, RC = target (points to ITERN) - | add RA, BASE, RA, lsl #3 - | ldr CFUNC:CARG1, [RA, #-24] - | add RC, PC, RC, lsl #2 - | ldp TAB:CARG3, CARG4, [RA, #-16] - | sub RC, RC, #0x20000 - | checkfunc CFUNC:CARG1, >5 - | asr TMP0, TAB:CARG3, #47 - | ldrb TMP1w, CFUNC:CARG1->ffid - | cmn TMP0, #-LJ_TTAB - | ccmp CARG4, TISNIL, #0, eq - | ccmp TMP1w, #FF_next_N, #0, eq - | bne >5 - | mov TMP0w, #0xfffe7fff - | lsl TMP0, TMP0, #32 - | str TMP0, [RA, #-8] // Initialize control var. - |1: - | mov PC, RC - | ins_next - | - |5: // Despecialize bytecode if any of the checks fail. - | mov TMP0, #BC_JMP - | mov TMP1, #BC_ITERC - | strb TMP0w, [PC, #-4+OFS_OP] - | strb TMP1w, [RC, # OFS_OP] - | b <1 - break; - - case BC_VARG: - | decode_RB RB, INS - | and RC, RC, #255 - | // RA = base, RB = (nresults+1), RC = numparams - | ldr TMP1, [BASE, FRAME_PC] - | add RC, BASE, RC, lsl #3 - | add RA, BASE, RA, lsl #3 - | add RC, RC, #FRAME_VARG - | add TMP2, RA, RB, lsl #3 - | sub RC, RC, TMP1 // RC = vbase - | // Note: RC may now be even _above_ BASE if nargs was < numparams. - | sub TMP3, BASE, #16 // TMP3 = vtop - | cbz RB, >5 - | sub TMP2, TMP2, #16 - |1: // Copy vararg slots to destination slots. - | cmp RC, TMP3 - | ldr TMP0, [RC], #8 - | csel TMP0, TMP0, TISNIL, lo - | cmp RA, TMP2 - | str TMP0, [RA], #8 - | blo <1 - |2: - | ins_next - | - |5: // Copy all varargs. - | ldr TMP0, L->maxstack - | subs TMP2, TMP3, RC - | csel RB, xzr, TMP2, le // MULTRES = (max(vtop-vbase,0)+1)*8 - | add RB, RB, #8 - | add TMP1, RA, TMP2 - | str RBw, SAVE_MULTRES - | ble <2 // Nothing to copy. - | cmp TMP1, TMP0 - | bhi >7 - |6: - | ldr TMP0, [RC], #8 - | str TMP0, [RA], #8 - | cmp RC, TMP3 - | blo <6 - | b <2 - | - |7: // Grow stack for varargs. - | lsr CARG2, TMP2, #3 - | stp BASE, RA, L->base - | mov CARG1, L - | sub RC, RC, BASE // Need delta, because BASE may change. - | str PC, SAVE_PC - | bl extern lj_state_growstack // (lua_State *L, int n) - | ldp BASE, RA, L->base - | add RC, BASE, RC - | sub TMP3, BASE, #16 - | b <6 - break; - - /* -- Returns ----------------------------------------------------------- */ - - case BC_RETM: - | // RA = results, RC = extra results - | ldr TMP0w, SAVE_MULTRES - | ldr PC, [BASE, FRAME_PC] - | add RA, BASE, RA, lsl #3 - | add RC, TMP0, RC, lsl #3 - | b ->BC_RETM_Z - break; - - case BC_RET: - | // RA = results, RC = nresults+1 - | ldr PC, [BASE, FRAME_PC] - | lsl RC, RC, #3 - | add RA, BASE, RA, lsl #3 - |->BC_RETM_Z: - | str RCw, SAVE_MULTRES - |1: - | ands CARG1, PC, #FRAME_TYPE - | eor CARG2, PC, #FRAME_VARG - | bne ->BC_RETV2_Z - | - |->BC_RET_Z: - | // BASE = base, RA = resultptr, RC = (nresults+1)*8, PC = return - | ldr INSw, [PC, #-4] - | subs TMP1, RC, #8 - | sub CARG3, BASE, #16 - | beq >3 - |2: - | ldr TMP0, [RA], #8 - | add BASE, BASE, #8 - | sub TMP1, TMP1, #8 - | str TMP0, [BASE, #-24] - | cbnz TMP1, <2 - |3: - | decode_RA RA, INS - | sub CARG4, CARG3, RA, lsl #3 - | decode_RB RB, INS - | ldr LFUNC:CARG1, [CARG4, FRAME_FUNC] - |5: - | cmp RC, RB, lsl #3 // More results expected? - | blo >6 - | and LFUNC:CARG1, CARG1, #LJ_GCVMASK - | mov BASE, CARG4 - | ldr CARG2, LFUNC:CARG1->pc - | ldr KBASE, [CARG2, #PC2PROTO(k)] - | ins_next - | - |6: // Fill up results with nil. - | add BASE, BASE, #8 - | add RC, RC, #8 - | str TISNIL, [BASE, #-24] - | b <5 - | - |->BC_RETV1_Z: // Non-standard return case. - | add RA, BASE, RA, lsl #3 - |->BC_RETV2_Z: - | tst CARG2, #FRAME_TYPEP - | bne ->vm_return - | // Return from vararg function: relocate BASE down. - | sub BASE, BASE, CARG2 - | ldr PC, [BASE, FRAME_PC] - | b <1 - break; - - case BC_RET0: case BC_RET1: - | // RA = results, RC = nresults+1 - | ldr PC, [BASE, FRAME_PC] - | lsl RC, RC, #3 - | str RCw, SAVE_MULTRES - | ands CARG1, PC, #FRAME_TYPE - | eor CARG2, PC, #FRAME_VARG - | bne ->BC_RETV1_Z - | ldr INSw, [PC, #-4] - if (op == BC_RET1) { - | ldr TMP0, [BASE, RA, lsl #3] - } - | sub CARG4, BASE, #16 - | decode_RA RA, INS - | sub BASE, CARG4, RA, lsl #3 - if (op == BC_RET1) { - | str TMP0, [CARG4], #8 - } - | decode_RB RB, INS - | ldr LFUNC:CARG1, [BASE, FRAME_FUNC] - |5: - | cmp RC, RB, lsl #3 - | blo >6 - | and LFUNC:CARG1, CARG1, #LJ_GCVMASK - | ldr CARG2, LFUNC:CARG1->pc - | ldr KBASE, [CARG2, #PC2PROTO(k)] - | ins_next - | - |6: // Fill up results with nil. - | add RC, RC, #8 - | str TISNIL, [CARG4], #8 - | b <5 - break; - - /* -- Loops and branches ------------------------------------------------ */ - - |.define FOR_IDX, [RA]; .define FOR_TIDX, [RA, #4] - |.define FOR_STOP, [RA, #8]; .define FOR_TSTOP, [RA, #12] - |.define FOR_STEP, [RA, #16]; .define FOR_TSTEP, [RA, #20] - |.define FOR_EXT, [RA, #24]; .define FOR_TEXT, [RA, #28] - - case BC_FORL: - |.if JIT - | hotloop - |.endif - | // Fall through. Assumes BC_IFORL follows. - break; - - case BC_JFORI: - case BC_JFORL: -#if !LJ_HASJIT - break; -#endif - case BC_FORI: - case BC_IFORL: - | // RA = base, RC = target (after end of loop or start of loop) - vk = (op == BC_IFORL || op == BC_JFORL); - | add RA, BASE, RA, lsl #3 - | ldp CARG1, CARG2, FOR_IDX // CARG1 = IDX, CARG2 = STOP - | ldr CARG3, FOR_STEP // CARG3 = STEP - if (op != BC_JFORL) { - | add RC, PC, RC, lsl #2 - | sub RC, RC, #0x20000 - } - | checkint CARG1, >5 - if (!vk) { - | checkint CARG2, ->vmeta_for - | checkint CARG3, ->vmeta_for - | tbnz CARG3w, #31, >4 - | cmp CARG1w, CARG2w - } else { - | adds CARG1w, CARG1w, CARG3w - | bvs >2 - | add TMP0, CARG1, TISNUM - | tbnz CARG3w, #31, >4 - | cmp CARG1w, CARG2w - } - |1: - if (op == BC_FORI) { - | csel PC, RC, PC, gt - } else if (op == BC_JFORI) { - | mov PC, RC - | ldrh RCw, [RC, #-4+OFS_RD] - } else if (op == BC_IFORL) { - | csel PC, RC, PC, le - } - if (vk) { - | str TMP0, FOR_IDX - | str TMP0, FOR_EXT - } else { - | str CARG1, FOR_EXT - } - if (op == BC_JFORI || op == BC_JFORL) { - | ble =>BC_JLOOP - } - |2: - | ins_next - | - |4: // Invert check for negative step. - | cmp CARG2w, CARG1w - | b <1 - | - |5: // FP loop. - | ldp d0, d1, FOR_IDX - | blo ->vmeta_for - if (!vk) { - | checknum CARG2, ->vmeta_for - | checknum CARG3, ->vmeta_for - | str d0, FOR_EXT - } else { - | ldr d2, FOR_STEP - | fadd d0, d0, d2 - } - | tbnz CARG3, #63, >7 - | fcmp d0, d1 - |6: - if (vk) { - | str d0, FOR_IDX - | str d0, FOR_EXT - } - if (op == BC_FORI) { - | csel PC, RC, PC, hi - } else if (op == BC_JFORI) { - | ldrh RCw, [RC, #-4+OFS_RD] - | bls =>BC_JLOOP - } else if (op == BC_IFORL) { - | csel PC, RC, PC, ls - } else { - | bls =>BC_JLOOP - } - | b <2 - | - |7: // Invert check for negative step. - | fcmp d1, d0 - | b <6 - break; - - case BC_ITERL: - |.if JIT - | hotloop - |.endif - | // Fall through. Assumes BC_IITERL follows. - break; - - case BC_JITERL: -#if !LJ_HASJIT - break; -#endif - case BC_IITERL: - | // RA = base, RC = target - | ldr CARG1, [BASE, RA, lsl #3] - | add TMP1, BASE, RA, lsl #3 - | cmp CARG1, TISNIL - | beq >1 // Stop if iterator returned nil. - if (op == BC_JITERL) { - | str CARG1, [TMP1, #-8] - | b =>BC_JLOOP - } else { - | add TMP0, PC, RC, lsl #2 // Otherwise save control var + branch. - | sub PC, TMP0, #0x20000 - | str CARG1, [TMP1, #-8] - } - |1: - | ins_next - break; - - case BC_LOOP: - | // RA = base, RC = target (loop extent) - | // Note: RA/RC is only used by trace recorder to determine scope/extent - | // This opcode does NOT jump, it's only purpose is to detect a hot loop. - |.if JIT - | hotloop - |.endif - | // Fall through. Assumes BC_ILOOP follows. - break; - - case BC_ILOOP: - | // RA = base, RC = target (loop extent) - | ins_next - break; - - case BC_JLOOP: - |.if JIT - | // RA = base (ignored), RC = traceno - | ldr CARG1, [GL, #GL_J(trace)] - | mov CARG2w, #0 // Traces on ARM64 don't store the trace #, so use 0. - | ldr TRACE:RC, [CARG1, RC, lsl #3] - | st_vmstate CARG2w - | ldr RA, TRACE:RC->mcode - | str BASE, GL->jit_base - | str L, GL->tmpbuf.L - | sub sp, sp, #16 // See SPS_FIXED. Avoids sp adjust in every root trace. - | br RA - |.endif - break; - - case BC_JMP: - | // RA = base (only used by trace recorder), RC = target - | add RC, PC, RC, lsl #2 - | sub PC, RC, #0x20000 - | ins_next - break; - - /* -- Function headers -------------------------------------------------- */ - - case BC_FUNCF: - |.if JIT - | hotcall - |.endif - case BC_FUNCV: /* NYI: compiled vararg functions. */ - | // Fall through. Assumes BC_IFUNCF/BC_IFUNCV follow. - break; - - case BC_JFUNCF: -#if !LJ_HASJIT - break; -#endif - case BC_IFUNCF: - | // BASE = new base, RA = BASE+framesize*8, CARG3 = LFUNC, RC = nargs*8 - | ldr CARG1, L->maxstack - | ldrb TMP1w, [PC, #-4+PC2PROTO(numparams)] - | ldr KBASE, [PC, #-4+PC2PROTO(k)] - | cmp RA, CARG1 - | bhi ->vm_growstack_l - |2: - | cmp NARGS8:RC, TMP1, lsl #3 // Check for missing parameters. - | blo >3 - if (op == BC_JFUNCF) { - | decode_RD RC, INS - | b =>BC_JLOOP - } else { - | ins_next - } - | - |3: // Clear missing parameters. - | str TISNIL, [BASE, NARGS8:RC] - | add NARGS8:RC, NARGS8:RC, #8 - | b <2 - break; - - case BC_JFUNCV: -#if !LJ_HASJIT - break; -#endif - | NYI // NYI: compiled vararg functions - break; /* NYI: compiled vararg functions. */ - - case BC_IFUNCV: - | // BASE = new base, RA = BASE+framesize*8, CARG3 = LFUNC, RC = nargs*8 - | ldr CARG1, L->maxstack - | movn TMP0, #~LJ_TFUNC - | add TMP2, BASE, RC - | add LFUNC:CARG3, CARG3, TMP0, lsl #47 - | add RA, RA, RC - | add TMP0, RC, #16+FRAME_VARG - | str LFUNC:CARG3, [TMP2], #8 // Store (tagged) copy of LFUNC. - | ldr KBASE, [PC, #-4+PC2PROTO(k)] - | cmp RA, CARG1 - | str TMP0, [TMP2], #8 // Store delta + FRAME_VARG. - | bhs ->vm_growstack_l - | sub RC, TMP2, #16 - | ldrb TMP1w, [PC, #-4+PC2PROTO(numparams)] - | mov RA, BASE - | mov BASE, TMP2 - | cbz TMP1, >2 - |1: - | cmp RA, RC // Less args than parameters? - | bhs >3 - | ldr TMP0, [RA] - | sub TMP1, TMP1, #1 - | str TISNIL, [RA], #8 // Clear old fixarg slot (help the GC). - | str TMP0, [TMP2], #8 - | cbnz TMP1, <1 - |2: - | ins_next - | - |3: - | sub TMP1, TMP1, #1 - | str TISNIL, [TMP2], #8 - | cbz TMP1, <2 - | b <3 - break; - - case BC_FUNCC: - case BC_FUNCCW: - | // BASE = new base, RA = BASE+framesize*8, CARG3 = CFUNC, RC = nargs*8 - if (op == BC_FUNCC) { - | ldr CARG4, CFUNC:CARG3->f - } else { - | ldr CARG4, GL->wrapf - } - | add CARG2, RA, NARGS8:RC - | ldr CARG1, L->maxstack - | add RC, BASE, NARGS8:RC - | cmp CARG2, CARG1 - | stp BASE, RC, L->base - if (op == BC_FUNCCW) { - | ldr CARG2, CFUNC:CARG3->f - } - | mv_vmstate TMP0w, C - | mov CARG1, L - | bhi ->vm_growstack_c // Need to grow stack. - | st_vmstate TMP0w - | blr CARG4 // (lua_State *L [, lua_CFunction f]) - | // Returns nresults. - | ldp BASE, TMP1, L->base - | str L, GL->cur_L - | sbfiz RC, CRET1, #3, #32 - | st_vmstate ST_INTERP - | ldr PC, [BASE, FRAME_PC] - | sub RA, TMP1, RC // RA = L->top - nresults*8 - | b ->vm_returnc - break; - - /* ---------------------------------------------------------------------- */ - - default: - fprintf(stderr, "Error: undefined opcode BC_%s\n", bc_names[op]); - exit(2); - break; - } -} - -static int build_backend(BuildCtx *ctx) -{ - int op; - - dasm_growpc(Dst, BC__MAX); - - build_subroutines(ctx); - - |.code_op - for (op = 0; op < BC__MAX; op++) - build_ins(ctx, (BCOp)op, op); - - return BC__MAX; -} - -/* Emit pseudo frame-info for all assembler functions. */ -static void emit_asm_debug(BuildCtx *ctx) -{ - int fcofs = (int)((uint8_t *)ctx->glob[GLOB_vm_ffi_call] - ctx->code); - int i, cf = CFRAME_SIZE >> 3; - switch (ctx->mode) { - case BUILD_elfasm: - fprintf(ctx->fp, "\t.section .debug_frame,\"\",%%progbits\n"); - fprintf(ctx->fp, - ".Lframe0:\n" - "\t.long .LECIE0-.LSCIE0\n" - ".LSCIE0:\n" - "\t.long 0xffffffff\n" - "\t.byte 0x1\n" - "\t.string \"\"\n" - "\t.uleb128 0x1\n" - "\t.sleb128 -8\n" - "\t.byte 30\n" /* Return address is in lr. */ - "\t.byte 0xc\n\t.uleb128 31\n\t.uleb128 0\n" /* def_cfa sp */ - "\t.align 3\n" - ".LECIE0:\n\n"); - fprintf(ctx->fp, - ".LSFDE0:\n" - "\t.long .LEFDE0-.LASFDE0\n" - ".LASFDE0:\n" - "\t.long .Lframe0\n" - "\t.quad .Lbegin\n" - "\t.quad %d\n" - "\t.byte 0xe\n\t.uleb128 %d\n" /* def_cfa_offset */ - "\t.byte 0x9d\n\t.uleb128 %d\n" /* offset fp */ - "\t.byte 0x9e\n\t.uleb128 %d\n", /* offset lr */ - fcofs, CFRAME_SIZE, cf, cf-1); - for (i = 19; i <= 28; i++) /* offset x19-x28 */ - fprintf(ctx->fp, "\t.byte 0x%x\n\t.uleb128 %d\n", 0x80+i, cf-i+17); - for (i = 8; i <= 15; i++) /* offset d8-d15 */ - fprintf(ctx->fp, "\t.byte 5\n\t.uleb128 0x%x\n\t.uleb128 %d\n", - 64+i, cf-i-4); - fprintf(ctx->fp, - "\t.align 3\n" - ".LEFDE0:\n\n"); -#if LJ_HASFFI - fprintf(ctx->fp, - ".LSFDE1:\n" - "\t.long .LEFDE1-.LASFDE1\n" - ".LASFDE1:\n" - "\t.long .Lframe0\n" - "\t.quad lj_vm_ffi_call\n" - "\t.quad %d\n" - "\t.byte 0xe\n\t.uleb128 32\n" /* def_cfa_offset */ - "\t.byte 0x9d\n\t.uleb128 4\n" /* offset fp */ - "\t.byte 0x9e\n\t.uleb128 3\n" /* offset lr */ - "\t.byte 0x93\n\t.uleb128 2\n" /* offset x19 */ - "\t.align 3\n" - ".LEFDE1:\n\n", (int)ctx->codesz - fcofs); -#endif - fprintf(ctx->fp, "\t.section .eh_frame,\"a\",%%progbits\n"); - fprintf(ctx->fp, - ".Lframe1:\n" - "\t.long .LECIE1-.LSCIE1\n" - ".LSCIE1:\n" - "\t.long 0\n" - "\t.byte 0x1\n" - "\t.string \"zPR\"\n" - "\t.uleb128 0x1\n" - "\t.sleb128 -8\n" - "\t.byte 30\n" /* Return address is in lr. */ - "\t.uleb128 6\n" /* augmentation length */ - "\t.byte 0x1b\n" /* pcrel|sdata4 */ - "\t.long lj_err_unwind_dwarf-.\n" - "\t.byte 0x1b\n" /* pcrel|sdata4 */ - "\t.byte 0xc\n\t.uleb128 31\n\t.uleb128 0\n" /* def_cfa sp */ - "\t.align 3\n" - ".LECIE1:\n\n"); - fprintf(ctx->fp, - ".LSFDE2:\n" - "\t.long .LEFDE2-.LASFDE2\n" - ".LASFDE2:\n" - "\t.long .LASFDE2-.Lframe1\n" - "\t.long .Lbegin-.\n" - "\t.long %d\n" - "\t.uleb128 0\n" /* augmentation length */ - "\t.byte 0xe\n\t.uleb128 %d\n" /* def_cfa_offset */ - "\t.byte 0x9d\n\t.uleb128 %d\n" /* offset fp */ - "\t.byte 0x9e\n\t.uleb128 %d\n", /* offset lr */ - fcofs, CFRAME_SIZE, cf, cf-1); - for (i = 19; i <= 28; i++) /* offset x19-x28 */ - fprintf(ctx->fp, "\t.byte 0x%x\n\t.uleb128 %d\n", 0x80+i, cf-i+17); - for (i = 8; i <= 15; i++) /* offset d8-d15 */ - fprintf(ctx->fp, "\t.byte 5\n\t.uleb128 0x%x\n\t.uleb128 %d\n", - 64+i, cf-i-4); - fprintf(ctx->fp, - "\t.align 3\n" - ".LEFDE2:\n\n"); -#if LJ_HASFFI - fprintf(ctx->fp, - ".Lframe2:\n" - "\t.long .LECIE2-.LSCIE2\n" - ".LSCIE2:\n" - "\t.long 0\n" - "\t.byte 0x1\n" - "\t.string \"zR\"\n" - "\t.uleb128 0x1\n" - "\t.sleb128 -8\n" - "\t.byte 30\n" /* Return address is in lr. */ - "\t.uleb128 1\n" /* augmentation length */ - "\t.byte 0x1b\n" /* pcrel|sdata4 */ - "\t.byte 0xc\n\t.uleb128 31\n\t.uleb128 0\n" /* def_cfa sp */ - "\t.align 3\n" - ".LECIE2:\n\n"); - fprintf(ctx->fp, - ".LSFDE3:\n" - "\t.long .LEFDE3-.LASFDE3\n" - ".LASFDE3:\n" - "\t.long .LASFDE3-.Lframe2\n" - "\t.long lj_vm_ffi_call-.\n" - "\t.long %d\n" - "\t.uleb128 0\n" /* augmentation length */ - "\t.byte 0xe\n\t.uleb128 32\n" /* def_cfa_offset */ - "\t.byte 0x9d\n\t.uleb128 4\n" /* offset fp */ - "\t.byte 0x9e\n\t.uleb128 3\n" /* offset lr */ - "\t.byte 0x93\n\t.uleb128 2\n" /* offset x19 */ - "\t.align 3\n" - ".LEFDE3:\n\n", (int)ctx->codesz - fcofs); -#endif - break; - default: - break; - } -} - diff --git a/lib/LuaJIT/src/vm_mips.dasc b/lib/LuaJIT/src/vm_mips.dasc deleted file mode 100644 index f324812..0000000 --- a/lib/LuaJIT/src/vm_mips.dasc +++ /dev/null @@ -1,5264 +0,0 @@ -|// Low-level VM code for MIPS CPUs. -|// Bytecode interpreter, fast functions and helper functions. -|// Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -|// -|// MIPS soft-float support contributed by Djordje Kovacevic and -|// Stefan Pejic from RT-RK.com, sponsored by Cisco Systems, Inc. -| -|.arch mips -|.section code_op, code_sub -| -|.actionlist build_actionlist -|.globals GLOB_ -|.globalnames globnames -|.externnames extnames -| -|// Note: The ragged indentation of the instructions is intentional. -|// The starting columns indicate data dependencies. -| -|//----------------------------------------------------------------------- -| -|// Fixed register assignments for the interpreter. -|// Don't use: r0 = 0, r26/r27 = reserved, r28 = gp, r29 = sp, r31 = ra -| -|.macro .FPU, a, b -|.if FPU -| a, b -|.endif -|.endmacro -| -|// The following must be C callee-save (but BASE is often refetched). -|.define BASE, r16 // Base of current Lua stack frame. -|.define KBASE, r17 // Constants of current Lua function. -|.define PC, r18 // Next PC. -|.define DISPATCH, r19 // Opcode dispatch table. -|.define LREG, r20 // Register holding lua_State (also in SAVE_L). -|.define MULTRES, r21 // Size of multi-result: (nresults+1)*8. -| -|.define JGL, r30 // On-trace: global_State + 32768. -| -|// Constants for type-comparisons, stores and conversions. C callee-save. -|.define TISNUM, r22 -|.define TISNIL, r30 -|.if FPU -|.define TOBIT, f30 // 2^52 + 2^51. -|.endif -| -|// The following temporaries are not saved across C calls, except for RA. -|.define RA, r23 // Callee-save. -|.define RB, r8 -|.define RC, r9 -|.define RD, r10 -|.define INS, r11 -| -|.define AT, r1 // Assembler temporary. -|.define TMP0, r12 -|.define TMP1, r13 -|.define TMP2, r14 -|.define TMP3, r15 -| -|// MIPS o32 calling convention. -|.define CFUNCADDR, r25 -|.define CARG1, r4 -|.define CARG2, r5 -|.define CARG3, r6 -|.define CARG4, r7 -| -|.define CRET1, r2 -|.define CRET2, r3 -| -|.if ENDIAN_LE -|.define SFRETLO, CRET1 -|.define SFRETHI, CRET2 -|.define SFARG1LO, CARG1 -|.define SFARG1HI, CARG2 -|.define SFARG2LO, CARG3 -|.define SFARG2HI, CARG4 -|.else -|.define SFRETLO, CRET2 -|.define SFRETHI, CRET1 -|.define SFARG1LO, CARG2 -|.define SFARG1HI, CARG1 -|.define SFARG2LO, CARG4 -|.define SFARG2HI, CARG3 -|.endif -| -|.if FPU -|.define FARG1, f12 -|.define FARG2, f14 -| -|.define FRET1, f0 -|.define FRET2, f2 -|.endif -| -|// Stack layout while in interpreter. Must match with lj_frame.h. -|.if FPU // MIPS32 hard-float. -| -|.define CFRAME_SPACE, 112 // Delta for sp. -| -|.define SAVE_ERRF, 124(sp) // 32 bit C frame info. -|.define SAVE_NRES, 120(sp) -|.define SAVE_CFRAME, 116(sp) -|.define SAVE_L, 112(sp) -|//----- 8 byte aligned, ^^^^ 16 byte register save area, owned by interpreter. -|.define SAVE_GPR_, 72 // .. 72+10*4: 32 bit GPR saves. -|.define SAVE_FPR_, 24 // .. 24+6*8: 64 bit FPR saves. -| -|.else // MIPS32 soft-float -| -|.define CFRAME_SPACE, 64 // Delta for sp. -| -|.define SAVE_ERRF, 76(sp) // 32 bit C frame info. -|.define SAVE_NRES, 72(sp) -|.define SAVE_CFRAME, 68(sp) -|.define SAVE_L, 64(sp) -|//----- 8 byte aligned, ^^^^ 16 byte register save area, owned by interpreter. -|.define SAVE_GPR_, 24 // .. 24+10*4: 32 bit GPR saves. -| -|.endif -| -|.define SAVE_PC, 20(sp) -|.define ARG5, 16(sp) -|.define CSAVE_4, 12(sp) -|.define CSAVE_3, 8(sp) -|.define CSAVE_2, 4(sp) -|.define CSAVE_1, 0(sp) -|//----- 8 byte aligned, ^^^^ 16 byte register save area, owned by callee. -| -|.define ARG5_OFS, 16 -|.define SAVE_MULTRES, ARG5 -| -|//----------------------------------------------------------------------- -| -|.macro saveregs -| addiu sp, sp, -CFRAME_SPACE -| sw ra, SAVE_GPR_+9*4(sp) -| sw r30, SAVE_GPR_+8*4(sp) -| .FPU sdc1 f30, SAVE_FPR_+5*8(sp) -| sw r23, SAVE_GPR_+7*4(sp) -| sw r22, SAVE_GPR_+6*4(sp) -| .FPU sdc1 f28, SAVE_FPR_+4*8(sp) -| sw r21, SAVE_GPR_+5*4(sp) -| sw r20, SAVE_GPR_+4*4(sp) -| .FPU sdc1 f26, SAVE_FPR_+3*8(sp) -| sw r19, SAVE_GPR_+3*4(sp) -| sw r18, SAVE_GPR_+2*4(sp) -| .FPU sdc1 f24, SAVE_FPR_+2*8(sp) -| sw r17, SAVE_GPR_+1*4(sp) -| sw r16, SAVE_GPR_+0*4(sp) -| .FPU sdc1 f22, SAVE_FPR_+1*8(sp) -| .FPU sdc1 f20, SAVE_FPR_+0*8(sp) -|.endmacro -| -|.macro restoreregs_ret -| lw ra, SAVE_GPR_+9*4(sp) -| lw r30, SAVE_GPR_+8*4(sp) -| .FPU ldc1 f30, SAVE_FPR_+5*8(sp) -| lw r23, SAVE_GPR_+7*4(sp) -| lw r22, SAVE_GPR_+6*4(sp) -| .FPU ldc1 f28, SAVE_FPR_+4*8(sp) -| lw r21, SAVE_GPR_+5*4(sp) -| lw r20, SAVE_GPR_+4*4(sp) -| .FPU ldc1 f26, SAVE_FPR_+3*8(sp) -| lw r19, SAVE_GPR_+3*4(sp) -| lw r18, SAVE_GPR_+2*4(sp) -| .FPU ldc1 f24, SAVE_FPR_+2*8(sp) -| lw r17, SAVE_GPR_+1*4(sp) -| lw r16, SAVE_GPR_+0*4(sp) -| .FPU ldc1 f22, SAVE_FPR_+1*8(sp) -| .FPU ldc1 f20, SAVE_FPR_+0*8(sp) -| jr ra -| addiu sp, sp, CFRAME_SPACE -|.endmacro -| -|// Type definitions. Some of these are only used for documentation. -|.type L, lua_State, LREG -|.type GL, global_State -|.type TVALUE, TValue -|.type GCOBJ, GCobj -|.type STR, GCstr -|.type TAB, GCtab -|.type LFUNC, GCfuncL -|.type CFUNC, GCfuncC -|.type PROTO, GCproto -|.type UPVAL, GCupval -|.type NODE, Node -|.type NARGS8, int -|.type TRACE, GCtrace -|.type SBUF, SBuf -| -|//----------------------------------------------------------------------- -| -|// Trap for not-yet-implemented parts. -|.macro NYI; .long 0xf0f0f0f0; .endmacro -| -|// Macros to mark delay slots. -|.macro ., a; a; .endmacro -|.macro ., a,b; a,b; .endmacro -|.macro ., a,b,c; a,b,c; .endmacro -| -|//----------------------------------------------------------------------- -| -|// Endian-specific defines. -|.if ENDIAN_LE -|.define FRAME_PC, -4 -|.define FRAME_FUNC, -8 -|.define HI, 4 -|.define LO, 0 -|.define OFS_RD, 2 -|.define OFS_RA, 1 -|.define OFS_OP, 0 -|.else -|.define FRAME_PC, -8 -|.define FRAME_FUNC, -4 -|.define HI, 0 -|.define LO, 4 -|.define OFS_RD, 0 -|.define OFS_RA, 2 -|.define OFS_OP, 3 -|.endif -| -|// Instruction decode. -|.macro decode_OP1, dst, ins; andi dst, ins, 0xff; .endmacro -|.macro decode_OP4a, dst, ins; andi dst, ins, 0xff; .endmacro -|.macro decode_OP4b, dst; sll dst, dst, 2; .endmacro -|.macro decode_RC4a, dst, ins; srl dst, ins, 14; .endmacro -|.macro decode_RC4b, dst; andi dst, dst, 0x3fc; .endmacro -|.macro decode_RD4b, dst; sll dst, dst, 2; .endmacro -|.macro decode_RA8a, dst, ins; srl dst, ins, 5; .endmacro -|.macro decode_RA8b, dst; andi dst, dst, 0x7f8; .endmacro -|.macro decode_RB8a, dst, ins; srl dst, ins, 21; .endmacro -|.macro decode_RB8b, dst; andi dst, dst, 0x7f8; .endmacro -|.macro decode_RD8a, dst, ins; srl dst, ins, 16; .endmacro -|.macro decode_RD8b, dst; sll dst, dst, 3; .endmacro -|.macro decode_RDtoRC8, dst, src; andi dst, src, 0x7f8; .endmacro -| -|// Instruction fetch. -|.macro ins_NEXT1 -| lw INS, 0(PC) -| addiu PC, PC, 4 -|.endmacro -|// Instruction decode+dispatch. -|.macro ins_NEXT2 -| decode_OP4a TMP1, INS -| decode_OP4b TMP1 -| addu TMP0, DISPATCH, TMP1 -| decode_RD8a RD, INS -| lw AT, 0(TMP0) -| decode_RA8a RA, INS -| decode_RD8b RD -| jr AT -| decode_RA8b RA -|.endmacro -|.macro ins_NEXT -| ins_NEXT1 -| ins_NEXT2 -|.endmacro -| -|// Instruction footer. -|.if 1 -| // Replicated dispatch. Less unpredictable branches, but higher I-Cache use. -| .define ins_next, ins_NEXT -| .define ins_next_, ins_NEXT -| .define ins_next1, ins_NEXT1 -| .define ins_next2, ins_NEXT2 -|.else -| // Common dispatch. Lower I-Cache use, only one (very) unpredictable branch. -| // Affects only certain kinds of benchmarks (and only with -j off). -| .macro ins_next -| b ->ins_next -| .endmacro -| .macro ins_next1 -| .endmacro -| .macro ins_next2 -| b ->ins_next -| .endmacro -| .macro ins_next_ -| ->ins_next: -| ins_NEXT -| .endmacro -|.endif -| -|// Call decode and dispatch. -|.macro ins_callt -| // BASE = new base, RB = LFUNC/CFUNC, RC = nargs*8, FRAME_PC(BASE) = PC -| lw PC, LFUNC:RB->pc -| lw INS, 0(PC) -| addiu PC, PC, 4 -| decode_OP4a TMP1, INS -| decode_RA8a RA, INS -| decode_OP4b TMP1 -| decode_RA8b RA -| addu TMP0, DISPATCH, TMP1 -| lw TMP0, 0(TMP0) -| jr TMP0 -| addu RA, RA, BASE -|.endmacro -| -|.macro ins_call -| // BASE = new base, RB = LFUNC/CFUNC, RC = nargs*8, PC = caller PC -| sw PC, FRAME_PC(BASE) -| ins_callt -|.endmacro -| -|//----------------------------------------------------------------------- -| -|.macro branch_RD -| srl TMP0, RD, 1 -| lui AT, (-(BCBIAS_J*4 >> 16) & 65535) -| addu TMP0, TMP0, AT -| addu PC, PC, TMP0 -|.endmacro -| -|// Assumes DISPATCH is relative to GL. -#define DISPATCH_GL(field) (GG_DISP2G + (int)offsetof(global_State, field)) -#define DISPATCH_J(field) (GG_DISP2J + (int)offsetof(jit_State, field)) -#define GG_DISP2GOT (GG_OFS(got) - GG_OFS(dispatch)) -#define DISPATCH_GOT(name) (GG_DISP2GOT + 4*LJ_GOT_##name) -| -#define PC2PROTO(field) ((int)offsetof(GCproto, field)-(int)sizeof(GCproto)) -| -|.macro load_got, func -| lw CFUNCADDR, DISPATCH_GOT(func)(DISPATCH) -|.endmacro -|// Much faster. Sadly, there's no easy way to force the required code layout. -|// .macro call_intern, func; bal extern func; .endmacro -|.macro call_intern, func; jalr CFUNCADDR; .endmacro -|.macro call_extern; jalr CFUNCADDR; .endmacro -|.macro jmp_extern; jr CFUNCADDR; .endmacro -| -|.macro hotcheck, delta, target -| srl TMP1, PC, 1 -| andi TMP1, TMP1, 126 -| addu TMP1, TMP1, DISPATCH -| lhu TMP2, GG_DISP2HOT(TMP1) -| addiu TMP2, TMP2, -delta -| bltz TMP2, target -|. sh TMP2, GG_DISP2HOT(TMP1) -|.endmacro -| -|.macro hotloop -| hotcheck HOTCOUNT_LOOP, ->vm_hotloop -|.endmacro -| -|.macro hotcall -| hotcheck HOTCOUNT_CALL, ->vm_hotcall -|.endmacro -| -|// Set current VM state. Uses TMP0. -|.macro li_vmstate, st; li TMP0, ~LJ_VMST_..st; .endmacro -|.macro st_vmstate; sw TMP0, DISPATCH_GL(vmstate)(DISPATCH); .endmacro -| -|// Move table write barrier back. Overwrites mark and tmp. -|.macro barrierback, tab, mark, tmp, target -| lw tmp, DISPATCH_GL(gc.grayagain)(DISPATCH) -| andi mark, mark, ~LJ_GC_BLACK & 255 // black2gray(tab) -| sw tab, DISPATCH_GL(gc.grayagain)(DISPATCH) -| sb mark, tab->marked -| b target -|. sw tmp, tab->gclist -|.endmacro -| -|//----------------------------------------------------------------------- - -/* Generate subroutines used by opcodes and other parts of the VM. */ -/* The .code_sub section should be last to help static branch prediction. */ -static void build_subroutines(BuildCtx *ctx) -{ - |.code_sub - | - |//----------------------------------------------------------------------- - |//-- Return handling ---------------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_returnp: - | // See vm_return. Also: TMP2 = previous base. - | andi AT, PC, FRAME_P - | beqz AT, ->cont_dispatch - |. li TMP1, LJ_TTRUE - | - | // Return from pcall or xpcall fast func. - | lw PC, FRAME_PC(TMP2) // Fetch PC of previous frame. - | move BASE, TMP2 // Restore caller base. - | // Prepending may overwrite the pcall frame, so do it at the end. - | sw TMP1, FRAME_PC(RA) // Prepend true to results. - | addiu RA, RA, -8 - | - |->vm_returnc: - | addiu RD, RD, 8 // RD = (nresults+1)*8. - | andi TMP0, PC, FRAME_TYPE - | beqz RD, ->vm_unwind_c_eh - |. li CRET1, LUA_YIELD - | beqz TMP0, ->BC_RET_Z // Handle regular return to Lua. - |. move MULTRES, RD - | - |->vm_return: - | // BASE = base, RA = resultptr, RD/MULTRES = (nresults+1)*8, PC = return - | // TMP0 = PC & FRAME_TYPE - | li TMP2, -8 - | xori AT, TMP0, FRAME_C - | and TMP2, PC, TMP2 - | bnez AT, ->vm_returnp - | subu TMP2, BASE, TMP2 // TMP2 = previous base. - | - | addiu TMP1, RD, -8 - | sw TMP2, L->base - | li_vmstate C - | lw TMP2, SAVE_NRES - | addiu BASE, BASE, -8 - | st_vmstate - | beqz TMP1, >2 - |. sll TMP2, TMP2, 3 - |1: - | addiu TMP1, TMP1, -8 - | lw SFRETHI, HI(RA) - | lw SFRETLO, LO(RA) - | addiu RA, RA, 8 - | sw SFRETHI, HI(BASE) - | sw SFRETLO, LO(BASE) - | bnez TMP1, <1 - |. addiu BASE, BASE, 8 - | - |2: - | bne TMP2, RD, >6 - |3: - |. sw BASE, L->top // Store new top. - | - |->vm_leave_cp: - | lw TMP0, SAVE_CFRAME // Restore previous C frame. - | move CRET1, r0 // Ok return status for vm_pcall. - | sw TMP0, L->cframe - | - |->vm_leave_unw: - | restoreregs_ret - | - |6: - | lw TMP1, L->maxstack - | slt AT, TMP2, RD - | bnez AT, >7 // Less results wanted? - | // More results wanted. Check stack size and fill up results with nil. - |. slt AT, BASE, TMP1 - | beqz AT, >8 - |. nop - | sw TISNIL, HI(BASE) - | addiu RD, RD, 8 - | b <2 - |. addiu BASE, BASE, 8 - | - |7: // Less results wanted. - | subu TMP0, RD, TMP2 - | subu TMP0, BASE, TMP0 // Either keep top or shrink it. - | b <3 - |. movn BASE, TMP0, TMP2 // LUA_MULTRET+1 case? - | - |8: // Corner case: need to grow stack for filling up results. - | // This can happen if: - | // - A C function grows the stack (a lot). - | // - The GC shrinks the stack in between. - | // - A return back from a lua_call() with (high) nresults adjustment. - | load_got lj_state_growstack - | move MULTRES, RD - | srl CARG2, TMP2, 3 - | call_intern lj_state_growstack // (lua_State *L, int n) - |. move CARG1, L - | lw TMP2, SAVE_NRES - | lw BASE, L->top // Need the (realloced) L->top in BASE. - | move RD, MULTRES - | b <2 - |. sll TMP2, TMP2, 3 - | - |->vm_unwind_c: // Unwind C stack, return from vm_pcall. - | // (void *cframe, int errcode) - | move sp, CARG1 - | move CRET1, CARG2 - |->vm_unwind_c_eh: // Landing pad for external unwinder. - | lw L, SAVE_L - | li TMP0, ~LJ_VMST_C - | lw GL:TMP1, L->glref - | b ->vm_leave_unw - |. sw TMP0, GL:TMP1->vmstate - | - |->vm_unwind_ff: // Unwind C stack, return from ff pcall. - | // (void *cframe) - | li AT, -4 - | and sp, CARG1, AT - |->vm_unwind_ff_eh: // Landing pad for external unwinder. - | lw L, SAVE_L - | .FPU lui TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float). - | li TISNUM, LJ_TISNUM // Setup type comparison constants. - | li TISNIL, LJ_TNIL - | lw BASE, L->base - | lw DISPATCH, L->glref // Setup pointer to dispatch table. - | .FPU mtc1 TMP3, TOBIT - | li TMP1, LJ_TFALSE - | li_vmstate INTERP - | lw PC, FRAME_PC(BASE) // Fetch PC of previous frame. - | .FPU cvt.d.s TOBIT, TOBIT - | addiu RA, BASE, -8 // Results start at BASE-8. - | addiu DISPATCH, DISPATCH, GG_G2DISP - | sw TMP1, HI(RA) // Prepend false to error message. - | st_vmstate - | b ->vm_returnc - |. li RD, 16 // 2 results: false + error message. - | - |//----------------------------------------------------------------------- - |//-- Grow stack for calls ----------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_growstack_c: // Grow stack for C function. - | b >2 - |. li CARG2, LUA_MINSTACK - | - |->vm_growstack_l: // Grow stack for Lua function. - | // BASE = new base, RA = BASE+framesize*8, RC = nargs*8, PC = first PC - | addu RC, BASE, RC - | subu RA, RA, BASE - | sw BASE, L->base - | addiu PC, PC, 4 // Must point after first instruction. - | sw RC, L->top - | srl CARG2, RA, 3 - |2: - | // L->base = new base, L->top = top - | load_got lj_state_growstack - | sw PC, SAVE_PC - | call_intern lj_state_growstack // (lua_State *L, int n) - |. move CARG1, L - | lw BASE, L->base - | lw RC, L->top - | lw LFUNC:RB, FRAME_FUNC(BASE) - | subu RC, RC, BASE - | // BASE = new base, RB = LFUNC/CFUNC, RC = nargs*8, FRAME_PC(BASE) = PC - | ins_callt // Just retry the call. - | - |//----------------------------------------------------------------------- - |//-- Entry points into the assembler VM --------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_resume: // Setup C frame and resume thread. - | // (lua_State *L, TValue *base, int nres1 = 0, ptrdiff_t ef = 0) - | saveregs - | move L, CARG1 - | lw DISPATCH, L->glref // Setup pointer to dispatch table. - | move BASE, CARG2 - | lbu TMP1, L->status - | sw L, SAVE_L - | li PC, FRAME_CP - | addiu TMP0, sp, CFRAME_RESUME - | addiu DISPATCH, DISPATCH, GG_G2DISP - | sw r0, SAVE_NRES - | sw r0, SAVE_ERRF - | sw CARG1, SAVE_PC // Any value outside of bytecode is ok. - | sw r0, SAVE_CFRAME - | beqz TMP1, >3 - |. sw TMP0, L->cframe - | - | // Resume after yield (like a return). - | sw L, DISPATCH_GL(cur_L)(DISPATCH) - | move RA, BASE - | lw BASE, L->base - | li TISNUM, LJ_TISNUM // Setup type comparison constants. - | lw TMP1, L->top - | lw PC, FRAME_PC(BASE) - | .FPU lui TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float). - | subu RD, TMP1, BASE - | .FPU mtc1 TMP3, TOBIT - | sb r0, L->status - | .FPU cvt.d.s TOBIT, TOBIT - | li_vmstate INTERP - | addiu RD, RD, 8 - | st_vmstate - | move MULTRES, RD - | andi TMP0, PC, FRAME_TYPE - | beqz TMP0, ->BC_RET_Z - |. li TISNIL, LJ_TNIL - | b ->vm_return - |. nop - | - |->vm_pcall: // Setup protected C frame and enter VM. - | // (lua_State *L, TValue *base, int nres1, ptrdiff_t ef) - | saveregs - | sw CARG4, SAVE_ERRF - | b >1 - |. li PC, FRAME_CP - | - |->vm_call: // Setup C frame and enter VM. - | // (lua_State *L, TValue *base, int nres1) - | saveregs - | li PC, FRAME_C - | - |1: // Entry point for vm_pcall above (PC = ftype). - | lw TMP1, L:CARG1->cframe - | move L, CARG1 - | sw CARG3, SAVE_NRES - | lw DISPATCH, L->glref // Setup pointer to dispatch table. - | sw CARG1, SAVE_L - | move BASE, CARG2 - | addiu DISPATCH, DISPATCH, GG_G2DISP - | sw CARG1, SAVE_PC // Any value outside of bytecode is ok. - | sw TMP1, SAVE_CFRAME - | sw sp, L->cframe // Add our C frame to cframe chain. - | - |3: // Entry point for vm_cpcall/vm_resume (BASE = base, PC = ftype). - | sw L, DISPATCH_GL(cur_L)(DISPATCH) - | lw TMP2, L->base // TMP2 = old base (used in vmeta_call). - | li TISNUM, LJ_TISNUM // Setup type comparison constants. - | .FPU lui TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float). - | lw TMP1, L->top - | .FPU mtc1 TMP3, TOBIT - | addu PC, PC, BASE - | subu NARGS8:RC, TMP1, BASE - | subu PC, PC, TMP2 // PC = frame delta + frame type - | .FPU cvt.d.s TOBIT, TOBIT - | li_vmstate INTERP - | li TISNIL, LJ_TNIL - | st_vmstate - | - |->vm_call_dispatch: - | // TMP2 = old base, BASE = new base, RC = nargs*8, PC = caller PC - | lw TMP0, FRAME_PC(BASE) - | li AT, LJ_TFUNC - | bne TMP0, AT, ->vmeta_call - |. lw LFUNC:RB, FRAME_FUNC(BASE) - | - |->vm_call_dispatch_f: - | ins_call - | // BASE = new base, RB = func, RC = nargs*8, PC = caller PC - | - |->vm_cpcall: // Setup protected C frame, call C. - | // (lua_State *L, lua_CFunction func, void *ud, lua_CPFunction cp) - | saveregs - | move L, CARG1 - | lw TMP0, L:CARG1->stack - | sw CARG1, SAVE_L - | lw TMP1, L->top - | lw DISPATCH, L->glref // Setup pointer to dispatch table. - | sw CARG1, SAVE_PC // Any value outside of bytecode is ok. - | subu TMP0, TMP0, TMP1 // Compute -savestack(L, L->top). - | lw TMP1, L->cframe - | addiu DISPATCH, DISPATCH, GG_G2DISP - | sw TMP0, SAVE_NRES // Neg. delta means cframe w/o frame. - | sw r0, SAVE_ERRF // No error function. - | sw TMP1, SAVE_CFRAME - | sw sp, L->cframe // Add our C frame to cframe chain. - | sw L, DISPATCH_GL(cur_L)(DISPATCH) - | jalr CARG4 // (lua_State *L, lua_CFunction func, void *ud) - |. move CFUNCADDR, CARG4 - | move BASE, CRET1 - | bnez CRET1, <3 // Else continue with the call. - |. li PC, FRAME_CP - | b ->vm_leave_cp // No base? Just remove C frame. - |. nop - | - |//----------------------------------------------------------------------- - |//-- Metamethod handling ------------------------------------------------ - |//----------------------------------------------------------------------- - | - |// The lj_meta_* functions (except for lj_meta_cat) don't reallocate the - |// stack, so BASE doesn't need to be reloaded across these calls. - | - |//-- Continuation dispatch ---------------------------------------------- - | - |->cont_dispatch: - | // BASE = meta base, RA = resultptr, RD = (nresults+1)*8 - | lw TMP0, -16+LO(BASE) // Continuation. - | move RB, BASE - | move BASE, TMP2 // Restore caller BASE. - | lw LFUNC:TMP1, FRAME_FUNC(TMP2) - |.if FFI - | sltiu AT, TMP0, 2 - |.endif - | lw PC, -16+HI(RB) // Restore PC from [cont|PC]. - | addu TMP2, RA, RD - | lw TMP1, LFUNC:TMP1->pc - |.if FFI - | bnez AT, >1 - |.endif - |. sw TISNIL, -8+HI(TMP2) // Ensure one valid arg. - | // BASE = base, RA = resultptr, RB = meta base - | jr TMP0 // Jump to continuation. - |. lw KBASE, PC2PROTO(k)(TMP1) - | - |.if FFI - |1: - | bnez TMP0, ->cont_ffi_callback // cont = 1: return from FFI callback. - | // cont = 0: tailcall from C function. - |. addiu TMP1, RB, -16 - | b ->vm_call_tail - |. subu RC, TMP1, BASE - |.endif - | - |->cont_cat: // RA = resultptr, RB = meta base - | lw INS, -4(PC) - | addiu CARG2, RB, -16 - | lw SFRETHI, HI(RA) - | lw SFRETLO, LO(RA) - | decode_RB8a MULTRES, INS - | decode_RA8a RA, INS - | decode_RB8b MULTRES - | decode_RA8b RA - | addu TMP1, BASE, MULTRES - | sw BASE, L->base - | subu CARG3, CARG2, TMP1 - | sw SFRETHI, HI(CARG2) - | bne TMP1, CARG2, ->BC_CAT_Z - |. sw SFRETLO, LO(CARG2) - | addu RA, BASE, RA - | sw SFRETHI, HI(RA) - | b ->cont_nop - |. sw SFRETLO, LO(RA) - | - |//-- Table indexing metamethods ----------------------------------------- - | - |->vmeta_tgets1: - | addiu CARG3, DISPATCH, DISPATCH_GL(tmptv) - | li TMP0, LJ_TSTR - | sw STR:RC, LO(CARG3) - | b >1 - |. sw TMP0, HI(CARG3) - | - |->vmeta_tgets: - | addiu CARG2, DISPATCH, DISPATCH_GL(tmptv) - | li TMP0, LJ_TTAB - | sw TAB:RB, LO(CARG2) - | addiu CARG3, DISPATCH, DISPATCH_GL(tmptv2) - | sw TMP0, HI(CARG2) - | li TMP1, LJ_TSTR - | sw STR:RC, LO(CARG3) - | b >1 - |. sw TMP1, HI(CARG3) - | - |->vmeta_tgetb: // TMP0 = index - | addiu CARG3, DISPATCH, DISPATCH_GL(tmptv) - | sw TMP0, LO(CARG3) - | sw TISNUM, HI(CARG3) - | - |->vmeta_tgetv: - |1: - | load_got lj_meta_tget - | sw BASE, L->base - | sw PC, SAVE_PC - | call_intern lj_meta_tget // (lua_State *L, TValue *o, TValue *k) - |. move CARG1, L - | // Returns TValue * (finished) or NULL (metamethod). - | beqz CRET1, >3 - |. addiu TMP1, BASE, -FRAME_CONT - | lw SFARG1HI, HI(CRET1) - | lw SFARG2HI, LO(CRET1) - | ins_next1 - | sw SFARG1HI, HI(RA) - | sw SFARG2HI, LO(RA) - | ins_next2 - | - |3: // Call __index metamethod. - | // BASE = base, L->top = new base, stack = cont/func/t/k - | lw BASE, L->top - | sw PC, -16+HI(BASE) // [cont|PC] - | subu PC, BASE, TMP1 - | lw LFUNC:RB, FRAME_FUNC(BASE) // Guaranteed to be a function here. - | b ->vm_call_dispatch_f - |. li NARGS8:RC, 16 // 2 args for func(t, k). - | - |->vmeta_tgetr: - | load_got lj_tab_getinth - | call_intern lj_tab_getinth // (GCtab *t, int32_t key) - |. nop - | // Returns cTValue * or NULL. - | beqz CRET1, ->BC_TGETR_Z - |. move SFARG2HI, TISNIL - | lw SFARG2HI, HI(CRET1) - | b ->BC_TGETR_Z - |. lw SFARG2LO, LO(CRET1) - | - |//----------------------------------------------------------------------- - | - |->vmeta_tsets1: - | addiu CARG3, DISPATCH, DISPATCH_GL(tmptv) - | li TMP0, LJ_TSTR - | sw STR:RC, LO(CARG3) - | b >1 - |. sw TMP0, HI(CARG3) - | - |->vmeta_tsets: - | addiu CARG2, DISPATCH, DISPATCH_GL(tmptv) - | li TMP0, LJ_TTAB - | sw TAB:RB, LO(CARG2) - | addiu CARG3, DISPATCH, DISPATCH_GL(tmptv2) - | sw TMP0, HI(CARG2) - | li TMP1, LJ_TSTR - | sw STR:RC, LO(CARG3) - | b >1 - |. sw TMP1, HI(CARG3) - | - |->vmeta_tsetb: // TMP0 = index - | addiu CARG3, DISPATCH, DISPATCH_GL(tmptv) - | sw TMP0, LO(CARG3) - | sw TISNUM, HI(CARG3) - | - |->vmeta_tsetv: - |1: - | load_got lj_meta_tset - | sw BASE, L->base - | sw PC, SAVE_PC - | call_intern lj_meta_tset // (lua_State *L, TValue *o, TValue *k) - |. move CARG1, L - | // Returns TValue * (finished) or NULL (metamethod). - | lw SFARG1HI, HI(RA) - | beqz CRET1, >3 - |. lw SFARG1LO, LO(RA) - | // NOBARRIER: lj_meta_tset ensures the table is not black. - | ins_next1 - | sw SFARG1HI, HI(CRET1) - | sw SFARG1LO, LO(CRET1) - | ins_next2 - | - |3: // Call __newindex metamethod. - | // BASE = base, L->top = new base, stack = cont/func/t/k/(v) - | addiu TMP1, BASE, -FRAME_CONT - | lw BASE, L->top - | sw PC, -16+HI(BASE) // [cont|PC] - | subu PC, BASE, TMP1 - | lw LFUNC:RB, FRAME_FUNC(BASE) // Guaranteed to be a function here. - | sw SFARG1HI, 16+HI(BASE) // Copy value to third argument. - | sw SFARG1LO, 16+LO(BASE) - | b ->vm_call_dispatch_f - |. li NARGS8:RC, 24 // 3 args for func(t, k, v) - | - |->vmeta_tsetr: - | load_got lj_tab_setinth - | sw BASE, L->base - | sw PC, SAVE_PC - | call_intern lj_tab_setinth // (lua_State *L, GCtab *t, int32_t key) - |. move CARG1, L - | // Returns TValue *. - | b ->BC_TSETR_Z - |. nop - | - |//-- Comparison metamethods --------------------------------------------- - | - |->vmeta_comp: - | // RA/RD point to o1/o2. - | move CARG2, RA - | move CARG3, RD - | load_got lj_meta_comp - | addiu PC, PC, -4 - | sw BASE, L->base - | sw PC, SAVE_PC - | decode_OP1 CARG4, INS - | call_intern lj_meta_comp // (lua_State *L, TValue *o1, *o2, int op) - |. move CARG1, L - | // Returns 0/1 or TValue * (metamethod). - |3: - | sltiu AT, CRET1, 2 - | beqz AT, ->vmeta_binop - | negu TMP2, CRET1 - |4: - | lhu RD, OFS_RD(PC) - | addiu PC, PC, 4 - | lui TMP1, (-(BCBIAS_J*4 >> 16) & 65535) - | sll RD, RD, 2 - | addu RD, RD, TMP1 - | and RD, RD, TMP2 - | addu PC, PC, RD - |->cont_nop: - | ins_next - | - |->cont_ra: // RA = resultptr - | lbu TMP1, -4+OFS_RA(PC) - | lw SFRETHI, HI(RA) - | lw SFRETLO, LO(RA) - | sll TMP1, TMP1, 3 - | addu TMP1, BASE, TMP1 - | sw SFRETHI, HI(TMP1) - | b ->cont_nop - |. sw SFRETLO, LO(TMP1) - | - |->cont_condt: // RA = resultptr - | lw TMP0, HI(RA) - | sltiu AT, TMP0, LJ_TISTRUECOND - | b <4 - |. negu TMP2, AT // Branch if result is true. - | - |->cont_condf: // RA = resultptr - | lw TMP0, HI(RA) - | sltiu AT, TMP0, LJ_TISTRUECOND - | b <4 - |. addiu TMP2, AT, -1 // Branch if result is false. - | - |->vmeta_equal: - | // SFARG1LO/SFARG2LO point to o1/o2. TMP0 is set to 0/1. - | load_got lj_meta_equal - | move CARG2, SFARG1LO - | move CARG3, SFARG2LO - | move CARG4, TMP0 - | addiu PC, PC, -4 - | sw BASE, L->base - | sw PC, SAVE_PC - | call_intern lj_meta_equal // (lua_State *L, GCobj *o1, *o2, int ne) - |. move CARG1, L - | // Returns 0/1 or TValue * (metamethod). - | b <3 - |. nop - | - |->vmeta_equal_cd: - |.if FFI - | load_got lj_meta_equal_cd - | move CARG2, INS - | addiu PC, PC, -4 - | sw BASE, L->base - | sw PC, SAVE_PC - | call_intern lj_meta_equal_cd // (lua_State *L, BCIns op) - |. move CARG1, L - | // Returns 0/1 or TValue * (metamethod). - | b <3 - |. nop - |.endif - | - |->vmeta_istype: - | load_got lj_meta_istype - | addiu PC, PC, -4 - | sw BASE, L->base - | srl CARG2, RA, 3 - | srl CARG3, RD, 3 - | sw PC, SAVE_PC - | call_intern lj_meta_istype // (lua_State *L, BCReg ra, BCReg tp) - |. move CARG1, L - | b ->cont_nop - |. nop - | - |//-- Arithmetic metamethods --------------------------------------------- - | - |->vmeta_unm: - | move RC, RB - | - |->vmeta_arith: - | load_got lj_meta_arith - | decode_OP1 TMP0, INS - | sw BASE, L->base - | move CARG2, RA - | sw PC, SAVE_PC - | move CARG3, RB - | move CARG4, RC - | sw TMP0, ARG5 - | call_intern lj_meta_arith // (lua_State *L, TValue *ra,*rb,*rc, BCReg op) - |. move CARG1, L - | // Returns NULL (finished) or TValue * (metamethod). - | beqz CRET1, ->cont_nop - |. nop - | - | // Call metamethod for binary op. - |->vmeta_binop: - | // BASE = old base, CRET1 = new base, stack = cont/func/o1/o2 - | subu TMP1, CRET1, BASE - | sw PC, -16+HI(CRET1) // [cont|PC] - | move TMP2, BASE - | addiu PC, TMP1, FRAME_CONT - | move BASE, CRET1 - | b ->vm_call_dispatch - |. li NARGS8:RC, 16 // 2 args for func(o1, o2). - | - |->vmeta_len: - | // CARG2 already set by BC_LEN. -#if LJ_52 - | move MULTRES, CARG1 -#endif - | load_got lj_meta_len - | sw BASE, L->base - | sw PC, SAVE_PC - | call_intern lj_meta_len // (lua_State *L, TValue *o) - |. move CARG1, L - | // Returns NULL (retry) or TValue * (metamethod base). -#if LJ_52 - | bnez CRET1, ->vmeta_binop // Binop call for compatibility. - |. nop - | b ->BC_LEN_Z - |. move CARG1, MULTRES -#else - | b ->vmeta_binop // Binop call for compatibility. - |. nop -#endif - | - |//-- Call metamethod ---------------------------------------------------- - | - |->vmeta_call: // Resolve and call __call metamethod. - | // TMP2 = old base, BASE = new base, RC = nargs*8 - | load_got lj_meta_call - | sw TMP2, L->base // This is the callers base! - | addiu CARG2, BASE, -8 - | sw PC, SAVE_PC - | addu CARG3, BASE, RC - | move MULTRES, NARGS8:RC - | call_intern lj_meta_call // (lua_State *L, TValue *func, TValue *top) - |. move CARG1, L - | lw LFUNC:RB, FRAME_FUNC(BASE) // Guaranteed to be a function here. - | addiu NARGS8:RC, MULTRES, 8 // Got one more argument now. - | ins_call - | - |->vmeta_callt: // Resolve __call for BC_CALLT. - | // BASE = old base, RA = new base, RC = nargs*8 - | load_got lj_meta_call - | sw BASE, L->base - | addiu CARG2, RA, -8 - | sw PC, SAVE_PC - | addu CARG3, RA, RC - | move MULTRES, NARGS8:RC - | call_intern lj_meta_call // (lua_State *L, TValue *func, TValue *top) - |. move CARG1, L - | lw TMP1, FRAME_PC(BASE) - | lw LFUNC:RB, FRAME_FUNC(RA) // Guaranteed to be a function here. - | b ->BC_CALLT_Z - |. addiu NARGS8:RC, MULTRES, 8 // Got one more argument now. - | - |//-- Argument coercion for 'for' statement ------------------------------ - | - |->vmeta_for: - | load_got lj_meta_for - | sw BASE, L->base - | move CARG2, RA - | sw PC, SAVE_PC - | move MULTRES, INS - | call_intern lj_meta_for // (lua_State *L, TValue *base) - |. move CARG1, L - |.if JIT - | decode_OP1 TMP0, MULTRES - | li AT, BC_JFORI - |.endif - | decode_RA8a RA, MULTRES - | decode_RD8a RD, MULTRES - | decode_RA8b RA - |.if JIT - | beq TMP0, AT, =>BC_JFORI - |. decode_RD8b RD - | b =>BC_FORI - |. nop - |.else - | b =>BC_FORI - |. decode_RD8b RD - |.endif - | - |//----------------------------------------------------------------------- - |//-- Fast functions ----------------------------------------------------- - |//----------------------------------------------------------------------- - | - |.macro .ffunc, name - |->ff_ .. name: - |.endmacro - | - |.macro .ffunc_1, name - |->ff_ .. name: - | lw SFARG1HI, HI(BASE) - | beqz NARGS8:RC, ->fff_fallback - |. lw SFARG1LO, LO(BASE) - |.endmacro - | - |.macro .ffunc_2, name - |->ff_ .. name: - | sltiu AT, NARGS8:RC, 16 - | lw SFARG1HI, HI(BASE) - | bnez AT, ->fff_fallback - |. lw SFARG2HI, 8+HI(BASE) - | lw SFARG1LO, LO(BASE) - | lw SFARG2LO, 8+LO(BASE) - |.endmacro - | - |.macro .ffunc_n, name // Caveat: has delay slot! - |->ff_ .. name: - | lw SFARG1HI, HI(BASE) - |.if FPU - | ldc1 FARG1, 0(BASE) - |.else - | lw SFARG1LO, LO(BASE) - |.endif - | beqz NARGS8:RC, ->fff_fallback - |. sltiu AT, SFARG1HI, LJ_TISNUM - | beqz AT, ->fff_fallback - |.endmacro - | - |.macro .ffunc_nn, name // Caveat: has delay slot! - |->ff_ .. name: - | sltiu AT, NARGS8:RC, 16 - | lw SFARG1HI, HI(BASE) - | bnez AT, ->fff_fallback - |. lw SFARG2HI, 8+HI(BASE) - | sltiu TMP0, SFARG1HI, LJ_TISNUM - |.if FPU - | ldc1 FARG1, 0(BASE) - |.else - | lw SFARG1LO, LO(BASE) - |.endif - | sltiu TMP1, SFARG2HI, LJ_TISNUM - |.if FPU - | ldc1 FARG2, 8(BASE) - |.else - | lw SFARG2LO, 8+LO(BASE) - |.endif - | and TMP0, TMP0, TMP1 - | beqz TMP0, ->fff_fallback - |.endmacro - | - |// Inlined GC threshold check. Caveat: uses TMP0 and TMP1 and has delay slot! - |.macro ffgccheck - | lw TMP0, DISPATCH_GL(gc.total)(DISPATCH) - | lw TMP1, DISPATCH_GL(gc.threshold)(DISPATCH) - | subu AT, TMP0, TMP1 - | bgezal AT, ->fff_gcstep - |.endmacro - | - |//-- Base library: checks ----------------------------------------------- - | - |.ffunc_1 assert - | sltiu AT, SFARG1HI, LJ_TISTRUECOND - | beqz AT, ->fff_fallback - |. addiu RA, BASE, -8 - | lw PC, FRAME_PC(BASE) - | addiu RD, NARGS8:RC, 8 // Compute (nresults+1)*8. - | addu TMP2, RA, NARGS8:RC - | sw SFARG1HI, HI(RA) - | addiu TMP1, BASE, 8 - | beq BASE, TMP2, ->fff_res // Done if exactly 1 argument. - |. sw SFARG1LO, LO(RA) - |1: - | lw SFRETHI, HI(TMP1) - | lw SFRETLO, LO(TMP1) - | sw SFRETHI, -8+HI(TMP1) - | sw SFRETLO, -8+LO(TMP1) - | bne TMP1, TMP2, <1 - |. addiu TMP1, TMP1, 8 - | b ->fff_res - |. nop - | - |.ffunc type - | lw SFARG1HI, HI(BASE) - | beqz NARGS8:RC, ->fff_fallback - |. sltiu TMP0, SFARG1HI, LJ_TISNUM - | movn SFARG1HI, TISNUM, TMP0 - | not TMP1, SFARG1HI - | sll TMP1, TMP1, 3 - | addu TMP1, CFUNC:RB, TMP1 - | lw SFARG1HI, CFUNC:TMP1->upvalue[0].u32.hi - | b ->fff_restv - |. lw SFARG1LO, CFUNC:TMP1->upvalue[0].u32.lo - | - |//-- Base library: getters and setters --------------------------------- - | - |.ffunc_1 getmetatable - | li AT, LJ_TTAB - | bne SFARG1HI, AT, >6 - |. li AT, LJ_TUDATA - |1: // Field metatable must be at same offset for GCtab and GCudata! - | lw TAB:SFARG1LO, TAB:SFARG1LO->metatable - |2: - | lw STR:RC, DISPATCH_GL(gcroot[GCROOT_MMNAME+MM_metatable])(DISPATCH) - | beqz TAB:SFARG1LO, ->fff_restv - |. li SFARG1HI, LJ_TNIL - | lw TMP0, TAB:SFARG1LO->hmask - | li SFARG1HI, LJ_TTAB // Use metatable as default result. - | lw TMP1, STR:RC->hash - | lw NODE:TMP2, TAB:SFARG1LO->node - | and TMP1, TMP1, TMP0 // idx = str->hash & tab->hmask - | sll TMP0, TMP1, 5 - | sll TMP1, TMP1, 3 - | subu TMP1, TMP0, TMP1 - | addu NODE:TMP2, NODE:TMP2, TMP1 // node = tab->node + (idx*32-idx*8) - | li AT, LJ_TSTR - |3: // Rearranged logic, because we expect _not_ to find the key. - | lw CARG4, offsetof(Node, key)+HI(NODE:TMP2) - | lw TMP0, offsetof(Node, key)+LO(NODE:TMP2) - | lw NODE:TMP3, NODE:TMP2->next - | bne CARG4, AT, >4 - |. lw CARG3, offsetof(Node, val)+HI(NODE:TMP2) - | beq TMP0, STR:RC, >5 - |. lw TMP1, offsetof(Node, val)+LO(NODE:TMP2) - |4: - | beqz NODE:TMP3, ->fff_restv // Not found, keep default result. - |. move NODE:TMP2, NODE:TMP3 - | b <3 - |. nop - |5: - | beq CARG3, TISNIL, ->fff_restv // Ditto for nil value. - |. nop - | move SFARG1HI, CARG3 // Return value of mt.__metatable. - | b ->fff_restv - |. move SFARG1LO, TMP1 - | - |6: - | beq SFARG1HI, AT, <1 - |. sltu AT, TISNUM, SFARG1HI - | movz SFARG1HI, TISNUM, AT - | not TMP1, SFARG1HI - | sll TMP1, TMP1, 2 - | addu TMP1, DISPATCH, TMP1 - | b <2 - |. lw TAB:SFARG1LO, DISPATCH_GL(gcroot[GCROOT_BASEMT])(TMP1) - | - |.ffunc_2 setmetatable - | // Fast path: no mt for table yet and not clearing the mt. - | li AT, LJ_TTAB - | bne SFARG1HI, AT, ->fff_fallback - |. addiu SFARG2HI, SFARG2HI, -LJ_TTAB - | lw TAB:TMP1, TAB:SFARG1LO->metatable - | lbu TMP3, TAB:SFARG1LO->marked - | or AT, SFARG2HI, TAB:TMP1 - | bnez AT, ->fff_fallback - |. andi AT, TMP3, LJ_GC_BLACK // isblack(table) - | beqz AT, ->fff_restv - |. sw TAB:SFARG2LO, TAB:SFARG1LO->metatable - | barrierback TAB:SFARG1LO, TMP3, TMP0, ->fff_restv - | - |.ffunc rawget - | lw CARG4, HI(BASE) - | sltiu AT, NARGS8:RC, 16 - | lw TAB:CARG2, LO(BASE) - | load_got lj_tab_get - | addiu CARG4, CARG4, -LJ_TTAB - | or AT, AT, CARG4 - | bnez AT, ->fff_fallback - | addiu CARG3, BASE, 8 - | call_intern lj_tab_get // (lua_State *L, GCtab *t, cTValue *key) - |. move CARG1, L - | // Returns cTValue *. - | lw SFARG1HI, HI(CRET1) - | b ->fff_restv - |. lw SFARG1LO, LO(CRET1) - | - |//-- Base library: conversions ------------------------------------------ - | - |.ffunc tonumber - | // Only handles the number case inline (without a base argument). - | lw CARG1, HI(BASE) - | xori AT, NARGS8:RC, 8 // Exactly one number argument. - | sltu TMP0, TISNUM, CARG1 - | or AT, AT, TMP0 - | bnez AT, ->fff_fallback - |. lw SFARG1HI, HI(BASE) - | b ->fff_restv - |. lw SFARG1LO, LO(BASE) - | - |.ffunc_1 tostring - | // Only handles the string or number case inline. - | li AT, LJ_TSTR - | // A __tostring method in the string base metatable is ignored. - | beq SFARG1HI, AT, ->fff_restv // String key? - | // Handle numbers inline, unless a number base metatable is present. - |. lw TMP1, DISPATCH_GL(gcroot[GCROOT_BASEMT_NUM])(DISPATCH) - | sltu TMP0, TISNUM, SFARG1HI - | or TMP0, TMP0, TMP1 - | bnez TMP0, ->fff_fallback - |. sw BASE, L->base // Add frame since C call can throw. - | ffgccheck - |. sw PC, SAVE_PC // Redundant (but a defined value). - | load_got lj_strfmt_number - | move CARG1, L - | call_intern lj_strfmt_number // (lua_State *L, cTValue *o) - |. move CARG2, BASE - | // Returns GCstr *. - | li SFARG1HI, LJ_TSTR - | b ->fff_restv - |. move SFARG1LO, CRET1 - | - |//-- Base library: iterators ------------------------------------------- - | - |.ffunc next - | lw CARG1, HI(BASE) - | lw TAB:CARG2, LO(BASE) - | beqz NARGS8:RC, ->fff_fallback - |. addu TMP2, BASE, NARGS8:RC - | li AT, LJ_TTAB - | sw TISNIL, HI(TMP2) // Set missing 2nd arg to nil. - | bne CARG1, AT, ->fff_fallback - |. lw PC, FRAME_PC(BASE) - | load_got lj_tab_next - | sw BASE, L->base // Add frame since C call can throw. - | sw BASE, L->top // Dummy frame length is ok. - | addiu CARG3, BASE, 8 - | sw PC, SAVE_PC - | call_intern lj_tab_next // (lua_State *L, GCtab *t, TValue *key) - |. move CARG1, L - | // Returns 0 at end of traversal. - | beqz CRET1, ->fff_restv // End of traversal: return nil. - |. li SFARG1HI, LJ_TNIL - | lw TMP0, 8+HI(BASE) - | lw TMP1, 8+LO(BASE) - | addiu RA, BASE, -8 - | lw TMP2, 16+HI(BASE) - | lw TMP3, 16+LO(BASE) - | sw TMP0, HI(RA) - | sw TMP1, LO(RA) - | sw TMP2, 8+HI(RA) - | sw TMP3, 8+LO(RA) - | b ->fff_res - |. li RD, (2+1)*8 - | - |.ffunc_1 pairs - | li AT, LJ_TTAB - | bne SFARG1HI, AT, ->fff_fallback - |. lw PC, FRAME_PC(BASE) -#if LJ_52 - | lw TAB:TMP2, TAB:SFARG1LO->metatable - | lw TMP0, CFUNC:RB->upvalue[0].u32.hi - | lw TMP1, CFUNC:RB->upvalue[0].u32.lo - | bnez TAB:TMP2, ->fff_fallback -#else - | lw TMP0, CFUNC:RB->upvalue[0].u32.hi - | lw TMP1, CFUNC:RB->upvalue[0].u32.lo -#endif - |. addiu RA, BASE, -8 - | sw TISNIL, 8+HI(BASE) - | sw TMP0, HI(RA) - | sw TMP1, LO(RA) - | b ->fff_res - |. li RD, (3+1)*8 - | - |.ffunc ipairs_aux - | sltiu AT, NARGS8:RC, 16 - | lw CARG3, HI(BASE) - | lw TAB:CARG1, LO(BASE) - | lw CARG4, 8+HI(BASE) - | bnez AT, ->fff_fallback - |. addiu CARG3, CARG3, -LJ_TTAB - | xor CARG4, CARG4, TISNUM - | and AT, CARG3, CARG4 - | bnez AT, ->fff_fallback - |. lw PC, FRAME_PC(BASE) - | lw TMP2, 8+LO(BASE) - | lw TMP0, TAB:CARG1->asize - | lw TMP1, TAB:CARG1->array - | addiu TMP2, TMP2, 1 - | sw TISNUM, -8+HI(BASE) - | sltu AT, TMP2, TMP0 - | sw TMP2, -8+LO(BASE) - | beqz AT, >2 // Not in array part? - |. addiu RA, BASE, -8 - | sll TMP3, TMP2, 3 - | addu TMP3, TMP1, TMP3 - | lw TMP1, HI(TMP3) - | lw TMP2, LO(TMP3) - |1: - | beq TMP1, TISNIL, ->fff_res // End of iteration, return 0 results. - |. li RD, (0+1)*8 - | sw TMP1, 8+HI(RA) - | sw TMP2, 8+LO(RA) - | b ->fff_res - |. li RD, (2+1)*8 - | - |2: // Check for empty hash part first. Otherwise call C function. - | lw TMP0, TAB:CARG1->hmask - | load_got lj_tab_getinth - | beqz TMP0, ->fff_res - |. li RD, (0+1)*8 - | call_intern lj_tab_getinth // (GCtab *t, int32_t key) - |. move CARG2, TMP2 - | // Returns cTValue * or NULL. - | beqz CRET1, ->fff_res - |. li RD, (0+1)*8 - | lw TMP1, HI(CRET1) - | b <1 - |. lw TMP2, LO(CRET1) - | - |.ffunc_1 ipairs - | li AT, LJ_TTAB - | bne SFARG1HI, AT, ->fff_fallback - |. lw PC, FRAME_PC(BASE) -#if LJ_52 - | lw TAB:TMP2, TAB:SFARG1LO->metatable - | lw TMP0, CFUNC:RB->upvalue[0].u32.hi - | lw TMP1, CFUNC:RB->upvalue[0].u32.lo - | bnez TAB:TMP2, ->fff_fallback -#else - | lw TMP0, CFUNC:RB->upvalue[0].u32.hi - | lw TMP1, CFUNC:RB->upvalue[0].u32.lo -#endif - |. addiu RA, BASE, -8 - | sw TISNUM, 8+HI(BASE) - | sw r0, 8+LO(BASE) - | sw TMP0, HI(RA) - | sw TMP1, LO(RA) - | b ->fff_res - |. li RD, (3+1)*8 - | - |//-- Base library: catch errors ---------------------------------------- - | - |.ffunc pcall - | lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH) - | beqz NARGS8:RC, ->fff_fallback - | move TMP2, BASE - | addiu BASE, BASE, 8 - | // Remember active hook before pcall. - | srl TMP3, TMP3, HOOK_ACTIVE_SHIFT - | andi TMP3, TMP3, 1 - | addiu PC, TMP3, 8+FRAME_PCALL - | b ->vm_call_dispatch - |. addiu NARGS8:RC, NARGS8:RC, -8 - | - |.ffunc xpcall - | sltiu AT, NARGS8:RC, 16 - | lw CARG4, 8+HI(BASE) - | bnez AT, ->fff_fallback - |. lw CARG3, 8+LO(BASE) - | lw CARG1, LO(BASE) - | lw CARG2, HI(BASE) - | lbu TMP1, DISPATCH_GL(hookmask)(DISPATCH) - | li AT, LJ_TFUNC - | move TMP2, BASE - | bne CARG4, AT, ->fff_fallback // Traceback must be a function. - | addiu BASE, BASE, 16 - | // Remember active hook before pcall. - | srl TMP3, TMP3, HOOK_ACTIVE_SHIFT - | sw CARG3, LO(TMP2) // Swap function and traceback. - | sw CARG4, HI(TMP2) - | andi TMP3, TMP3, 1 - | sw CARG1, 8+LO(TMP2) - | sw CARG2, 8+HI(TMP2) - | addiu PC, TMP3, 16+FRAME_PCALL - | b ->vm_call_dispatch - |. addiu NARGS8:RC, NARGS8:RC, -16 - | - |//-- Coroutine library -------------------------------------------------- - | - |.macro coroutine_resume_wrap, resume - |.if resume - |.ffunc coroutine_resume - | lw CARG3, HI(BASE) - | beqz NARGS8:RC, ->fff_fallback - |. lw CARG1, LO(BASE) - | li AT, LJ_TTHREAD - | bne CARG3, AT, ->fff_fallback - |.else - |.ffunc coroutine_wrap_aux - | lw L:CARG1, CFUNC:RB->upvalue[0].gcr - |.endif - | lbu TMP0, L:CARG1->status - | lw TMP1, L:CARG1->cframe - | lw CARG2, L:CARG1->top - | lw TMP2, L:CARG1->base - | addiu TMP3, TMP0, -LUA_YIELD - | bgtz TMP3, ->fff_fallback // st > LUA_YIELD? - |. xor TMP2, TMP2, CARG2 - | bnez TMP1, ->fff_fallback // cframe != 0? - |. or AT, TMP2, TMP0 - | lw TMP0, L:CARG1->maxstack - | beqz AT, ->fff_fallback // base == top && st == 0? - |. lw PC, FRAME_PC(BASE) - | addu TMP2, CARG2, NARGS8:RC - | sltu AT, TMP0, TMP2 - | bnez AT, ->fff_fallback // Stack overflow? - |. sw PC, SAVE_PC - | sw BASE, L->base - |1: - |.if resume - | addiu BASE, BASE, 8 // Keep resumed thread in stack for GC. - | addiu NARGS8:RC, NARGS8:RC, -8 - | addiu TMP2, TMP2, -8 - |.endif - | sw TMP2, L:CARG1->top - | addu TMP1, BASE, NARGS8:RC - | move CARG3, CARG2 - | sw BASE, L->top - |2: // Move args to coroutine. - | lw SFRETHI, HI(BASE) - | lw SFRETLO, LO(BASE) - | sltu AT, BASE, TMP1 - | beqz AT, >3 - |. addiu BASE, BASE, 8 - | sw SFRETHI, HI(CARG3) - | sw SFRETLO, LO(CARG3) - | b <2 - |. addiu CARG3, CARG3, 8 - |3: - | bal ->vm_resume // (lua_State *L, TValue *base, 0, 0) - |. move L:RA, L:CARG1 - | // Returns thread status. - |4: - | lw TMP2, L:RA->base - | sltiu AT, CRET1, LUA_YIELD+1 - | lw TMP3, L:RA->top - | li_vmstate INTERP - | lw BASE, L->base - | sw L, DISPATCH_GL(cur_L)(DISPATCH) - | st_vmstate - | beqz AT, >8 - |. subu RD, TMP3, TMP2 - | lw TMP0, L->maxstack - | beqz RD, >6 // No results? - |. addu TMP1, BASE, RD - | sltu AT, TMP0, TMP1 - | bnez AT, >9 // Need to grow stack? - |. addu TMP3, TMP2, RD - | sw TMP2, L:RA->top // Clear coroutine stack. - | move TMP1, BASE - |5: // Move results from coroutine. - | lw SFRETHI, HI(TMP2) - | lw SFRETLO, LO(TMP2) - | addiu TMP2, TMP2, 8 - | sltu AT, TMP2, TMP3 - | sw SFRETHI, HI(TMP1) - | sw SFRETLO, LO(TMP1) - | bnez AT, <5 - |. addiu TMP1, TMP1, 8 - |6: - | andi TMP0, PC, FRAME_TYPE - |.if resume - | li TMP1, LJ_TTRUE - | addiu RA, BASE, -8 - | sw TMP1, -8+HI(BASE) // Prepend true to results. - | addiu RD, RD, 16 - |.else - | move RA, BASE - | addiu RD, RD, 8 - |.endif - |7: - | sw PC, SAVE_PC - | beqz TMP0, ->BC_RET_Z - |. move MULTRES, RD - | b ->vm_return - |. nop - | - |8: // Coroutine returned with error (at co->top-1). - |.if resume - | addiu TMP3, TMP3, -8 - | li TMP1, LJ_TFALSE - | lw SFRETHI, HI(TMP3) - | lw SFRETLO, LO(TMP3) - | sw TMP3, L:RA->top // Remove error from coroutine stack. - | li RD, (2+1)*8 - | sw TMP1, -8+HI(BASE) // Prepend false to results. - | addiu RA, BASE, -8 - | sw SFRETHI, HI(BASE) // Copy error message. - | sw SFRETLO, LO(BASE) - | b <7 - |. andi TMP0, PC, FRAME_TYPE - |.else - | load_got lj_ffh_coroutine_wrap_err - | move CARG2, L:RA - | call_intern lj_ffh_coroutine_wrap_err // (lua_State *L, lua_State *co) - |. move CARG1, L - |.endif - | - |9: // Handle stack expansion on return from yield. - | load_got lj_state_growstack - | srl CARG2, RD, 3 - | call_intern lj_state_growstack // (lua_State *L, int n) - |. move CARG1, L - | b <4 - |. li CRET1, 0 - |.endmacro - | - | coroutine_resume_wrap 1 // coroutine.resume - | coroutine_resume_wrap 0 // coroutine.wrap - | - |.ffunc coroutine_yield - | lw TMP0, L->cframe - | addu TMP1, BASE, NARGS8:RC - | sw BASE, L->base - | andi TMP0, TMP0, CFRAME_RESUME - | sw TMP1, L->top - | beqz TMP0, ->fff_fallback - |. li CRET1, LUA_YIELD - | sw r0, L->cframe - | b ->vm_leave_unw - |. sb CRET1, L->status - | - |//-- Math library ------------------------------------------------------- - | - |.ffunc_1 math_abs - | bne SFARG1HI, TISNUM, >1 - |. sra TMP0, SFARG1LO, 31 - | xor TMP1, SFARG1LO, TMP0 - | subu SFARG1LO, TMP1, TMP0 - | bgez SFARG1LO, ->fff_restv - |. nop - | lui SFARG1HI, 0x41e0 // 2^31 as a double. - | b ->fff_restv - |. li SFARG1LO, 0 - |1: - | sltiu AT, SFARG1HI, LJ_TISNUM - | beqz AT, ->fff_fallback - |. sll SFARG1HI, SFARG1HI, 1 - | srl SFARG1HI, SFARG1HI, 1 - |// fallthrough - | - |->fff_restv: - | // SFARG1LO/SFARG1HI = TValue result. - | lw PC, FRAME_PC(BASE) - | sw SFARG1HI, -8+HI(BASE) - | addiu RA, BASE, -8 - | sw SFARG1LO, -8+LO(BASE) - |->fff_res1: - | // RA = results, PC = return. - | li RD, (1+1)*8 - |->fff_res: - | // RA = results, RD = (nresults+1)*8, PC = return. - | andi TMP0, PC, FRAME_TYPE - | bnez TMP0, ->vm_return - |. move MULTRES, RD - | lw INS, -4(PC) - | decode_RB8a RB, INS - | decode_RB8b RB - |5: - | sltu AT, RD, RB - | bnez AT, >6 // More results expected? - |. decode_RA8a TMP0, INS - | decode_RA8b TMP0 - | ins_next1 - | // Adjust BASE. KBASE is assumed to be set for the calling frame. - | subu BASE, RA, TMP0 - | ins_next2 - | - |6: // Fill up results with nil. - | addu TMP1, RA, RD - | addiu RD, RD, 8 - | b <5 - |. sw TISNIL, -8+HI(TMP1) - | - |.macro math_extern, func - | .ffunc math_ .. func - | lw SFARG1HI, HI(BASE) - | beqz NARGS8:RC, ->fff_fallback - |. load_got func - | sltiu AT, SFARG1HI, LJ_TISNUM - | beqz AT, ->fff_fallback - |.if FPU - |. ldc1 FARG1, 0(BASE) - |.else - |. lw SFARG1LO, LO(BASE) - |.endif - | call_extern - |. nop - | b ->fff_resn - |. nop - |.endmacro - | - |.macro math_extern2, func - | .ffunc_nn math_ .. func - |. load_got func - | call_extern - |. nop - | b ->fff_resn - |. nop - |.endmacro - | - |// TODO: Return integer type if result is integer (own sf implementation). - |.macro math_round, func - |->ff_math_ .. func: - | lw SFARG1HI, HI(BASE) - | beqz NARGS8:RC, ->fff_fallback - |. lw SFARG1LO, LO(BASE) - | beq SFARG1HI, TISNUM, ->fff_restv - |. sltu AT, SFARG1HI, TISNUM - | beqz AT, ->fff_fallback - |.if FPU - |. ldc1 FARG1, 0(BASE) - | bal ->vm_ .. func - |.else - |. load_got func - | call_extern - |.endif - |. nop - | b ->fff_resn - |. nop - |.endmacro - | - | math_round floor - | math_round ceil - | - |.ffunc math_log - | li AT, 8 - | bne NARGS8:RC, AT, ->fff_fallback // Exactly 1 argument. - |. lw SFARG1HI, HI(BASE) - | sltiu AT, SFARG1HI, LJ_TISNUM - | beqz AT, ->fff_fallback - |. load_got log - |.if FPU - | call_extern - |. ldc1 FARG1, 0(BASE) - |.else - | call_extern - |. lw SFARG1LO, LO(BASE) - |.endif - | b ->fff_resn - |. nop - | - | math_extern log10 - | math_extern exp - | math_extern sin - | math_extern cos - | math_extern tan - | math_extern asin - | math_extern acos - | math_extern atan - | math_extern sinh - | math_extern cosh - | math_extern tanh - | math_extern2 pow - | math_extern2 atan2 - | math_extern2 fmod - | - |.if FPU - |.ffunc_n math_sqrt - |. sqrt.d FRET1, FARG1 - |// fallthrough to ->fff_resn - |.else - | math_extern sqrt - |.endif - | - |->fff_resn: - | lw PC, FRAME_PC(BASE) - | addiu RA, BASE, -8 - |.if FPU - | b ->fff_res1 - |. sdc1 FRET1, -8(BASE) - |.else - | sw SFRETHI, -8+HI(BASE) - | b ->fff_res1 - |. sw SFRETLO, -8+LO(BASE) - |.endif - | - | - |.ffunc math_ldexp - | sltiu AT, NARGS8:RC, 16 - | lw SFARG1HI, HI(BASE) - | bnez AT, ->fff_fallback - |. lw CARG4, 8+HI(BASE) - | bne CARG4, TISNUM, ->fff_fallback - | load_got ldexp - |. sltu AT, SFARG1HI, TISNUM - | beqz AT, ->fff_fallback - |.if FPU - |. ldc1 FARG1, 0(BASE) - |.else - |. lw SFARG1LO, LO(BASE) - |.endif - | call_extern - |. lw CARG3, 8+LO(BASE) - | b ->fff_resn - |. nop - | - |.ffunc_n math_frexp - | load_got frexp - | lw PC, FRAME_PC(BASE) - | call_extern - |. addiu CARG3, DISPATCH, DISPATCH_GL(tmptv) - | lw TMP1, DISPATCH_GL(tmptv)(DISPATCH) - | addiu RA, BASE, -8 - |.if FPU - | mtc1 TMP1, FARG2 - | sdc1 FRET1, 0(RA) - | cvt.d.w FARG2, FARG2 - | sdc1 FARG2, 8(RA) - |.else - | sw SFRETLO, LO(RA) - | sw SFRETHI, HI(RA) - | sw TMP1, 8+LO(RA) - | sw TISNUM, 8+HI(RA) - |.endif - | b ->fff_res - |. li RD, (2+1)*8 - | - |.ffunc_n math_modf - | load_got modf - | lw PC, FRAME_PC(BASE) - | call_extern - |. addiu CARG3, BASE, -8 - | addiu RA, BASE, -8 - |.if FPU - | sdc1 FRET1, 0(BASE) - |.else - | sw SFRETLO, LO(BASE) - | sw SFRETHI, HI(BASE) - |.endif - | b ->fff_res - |. li RD, (2+1)*8 - | - |.macro math_minmax, name, intins, fpins - | .ffunc_1 name - | addu TMP3, BASE, NARGS8:RC - | bne SFARG1HI, TISNUM, >5 - |. addiu TMP2, BASE, 8 - |1: // Handle integers. - |. lw SFARG2HI, HI(TMP2) - | beq TMP2, TMP3, ->fff_restv - |. lw SFARG2LO, LO(TMP2) - | bne SFARG2HI, TISNUM, >3 - |. slt AT, SFARG1LO, SFARG2LO - | intins SFARG1LO, SFARG2LO, AT - | b <1 - |. addiu TMP2, TMP2, 8 - | - |3: // Convert intermediate result to number and continue with number loop. - | sltiu AT, SFARG2HI, LJ_TISNUM - | beqz AT, ->fff_fallback - |.if FPU - |. mtc1 SFARG1LO, FRET1 - | cvt.d.w FRET1, FRET1 - | b >7 - |. ldc1 FARG1, 0(TMP2) - |.else - |. nop - | bal ->vm_sfi2d_1 - |. nop - | b >7 - |. nop - |.endif - | - |5: - |. sltiu AT, SFARG1HI, LJ_TISNUM - | beqz AT, ->fff_fallback - |.if FPU - |. ldc1 FRET1, 0(BASE) - |.endif - | - |6: // Handle numbers. - |. lw SFARG2HI, HI(TMP2) - |.if FPU - | beq TMP2, TMP3, ->fff_resn - |.else - | beq TMP2, TMP3, ->fff_restv - |.endif - |. sltiu AT, SFARG2HI, LJ_TISNUM - | beqz AT, >8 - |.if FPU - |. ldc1 FARG1, 0(TMP2) - |.else - |. lw SFARG2LO, LO(TMP2) - |.endif - |7: - |.if FPU - | c.olt.d FRET1, FARG1 - | fpins FRET1, FARG1 - |.else - | bal ->vm_sfcmpolt - |. nop - | intins SFARG1LO, SFARG2LO, CRET1 - | intins SFARG1HI, SFARG2HI, CRET1 - |.endif - | b <6 - |. addiu TMP2, TMP2, 8 - | - |8: // Convert integer to number and continue with number loop. - | bne SFARG2HI, TISNUM, ->fff_fallback - |.if FPU - |. lwc1 FARG1, LO(TMP2) - | b <7 - |. cvt.d.w FARG1, FARG1 - |.else - |. nop - | bal ->vm_sfi2d_2 - |. nop - | b <7 - |. nop - |.endif - | - |.endmacro - | - | math_minmax math_min, movz, movf.d - | math_minmax math_max, movn, movt.d - | - |//-- String library ----------------------------------------------------- - | - |.ffunc string_byte // Only handle the 1-arg case here. - | lw CARG3, HI(BASE) - | lw STR:CARG1, LO(BASE) - | xori AT, NARGS8:RC, 8 - | addiu CARG3, CARG3, -LJ_TSTR - | or AT, AT, CARG3 - | bnez AT, ->fff_fallback // Need exactly 1 string argument. - |. nop - | lw TMP0, STR:CARG1->len - | addiu RA, BASE, -8 - | lw PC, FRAME_PC(BASE) - | sltu RD, r0, TMP0 - | lbu TMP1, STR:CARG1[1] // Access is always ok (NUL at end). - | addiu RD, RD, 1 - | sll RD, RD, 3 // RD = ((str->len != 0)+1)*8 - | sw TISNUM, HI(RA) - | b ->fff_res - |. sw TMP1, LO(RA) - | - |.ffunc string_char // Only handle the 1-arg case here. - | ffgccheck - |. nop - | lw CARG3, HI(BASE) - | lw CARG1, LO(BASE) - | li TMP1, 255 - | xori AT, NARGS8:RC, 8 // Exactly 1 argument. - | xor TMP0, CARG3, TISNUM // Integer. - | sltu TMP1, TMP1, CARG1 // !(255 < n). - | or AT, AT, TMP0 - | or AT, AT, TMP1 - | bnez AT, ->fff_fallback - |. li CARG3, 1 - | addiu CARG2, sp, ARG5_OFS - | sb CARG1, ARG5 - |->fff_newstr: - | load_got lj_str_new - | sw BASE, L->base - | sw PC, SAVE_PC - | call_intern lj_str_new // (lua_State *L, char *str, size_t l) - |. move CARG1, L - | // Returns GCstr *. - | lw BASE, L->base - |->fff_resstr: - | move SFARG1LO, CRET1 - | b ->fff_restv - |. li SFARG1HI, LJ_TSTR - | - |.ffunc string_sub - | ffgccheck - |. nop - | addiu AT, NARGS8:RC, -16 - | lw CARG3, 16+HI(BASE) - | lw TMP0, HI(BASE) - | lw STR:CARG1, LO(BASE) - | bltz AT, ->fff_fallback - |. lw CARG2, 8+HI(BASE) - | beqz AT, >1 - |. li CARG4, -1 - | bne CARG3, TISNUM, ->fff_fallback - |. lw CARG4, 16+LO(BASE) - |1: - | bne CARG2, TISNUM, ->fff_fallback - |. li AT, LJ_TSTR - | bne TMP0, AT, ->fff_fallback - |. lw CARG3, 8+LO(BASE) - | lw CARG2, STR:CARG1->len - | // STR:CARG1 = str, CARG2 = str->len, CARG3 = start, CARG4 = end - | slt AT, CARG4, r0 - | addiu TMP0, CARG2, 1 - | addu TMP1, CARG4, TMP0 - | slt TMP3, CARG3, r0 - | movn CARG4, TMP1, AT // if (end < 0) end += len+1 - | addu TMP1, CARG3, TMP0 - | movn CARG3, TMP1, TMP3 // if (start < 0) start += len+1 - | li TMP2, 1 - | slt AT, CARG4, r0 - | slt TMP3, r0, CARG3 - | movn CARG4, r0, AT // if (end < 0) end = 0 - | movz CARG3, TMP2, TMP3 // if (start < 1) start = 1 - | slt AT, CARG2, CARG4 - | movn CARG4, CARG2, AT // if (end > len) end = len - | addu CARG2, STR:CARG1, CARG3 - | subu CARG3, CARG4, CARG3 // len = end - start - | addiu CARG2, CARG2, sizeof(GCstr)-1 - | bgez CARG3, ->fff_newstr - |. addiu CARG3, CARG3, 1 // len++ - |->fff_emptystr: // Return empty string. - | addiu STR:SFARG1LO, DISPATCH, DISPATCH_GL(strempty) - | b ->fff_restv - |. li SFARG1HI, LJ_TSTR - | - |.macro ffstring_op, name - | .ffunc string_ .. name - | ffgccheck - |. nop - | lw CARG3, HI(BASE) - | lw STR:CARG2, LO(BASE) - | beqz NARGS8:RC, ->fff_fallback - |. li AT, LJ_TSTR - | bne CARG3, AT, ->fff_fallback - |. addiu SBUF:CARG1, DISPATCH, DISPATCH_GL(tmpbuf) - | load_got lj_buf_putstr_ .. name - | lw TMP0, SBUF:CARG1->b - | sw L, SBUF:CARG1->L - | sw BASE, L->base - | sw TMP0, SBUF:CARG1->p - | call_intern extern lj_buf_putstr_ .. name - |. sw PC, SAVE_PC - | load_got lj_buf_tostr - | call_intern lj_buf_tostr - |. move SBUF:CARG1, SBUF:CRET1 - | b ->fff_resstr - |. lw BASE, L->base - |.endmacro - | - |ffstring_op reverse - |ffstring_op lower - |ffstring_op upper - | - |//-- Bit library -------------------------------------------------------- - | - |->vm_tobit_fb: - | beqz TMP1, ->fff_fallback - |.if FPU - |. ldc1 FARG1, 0(BASE) - | add.d FARG1, FARG1, TOBIT - | jr ra - |. mfc1 CRET1, FARG1 - |.else - |// FP number to bit conversion for soft-float. - |->vm_tobit: - | sll TMP0, SFARG1HI, 1 - | lui AT, 0x0020 - | addu TMP0, TMP0, AT - | slt AT, TMP0, r0 - | movz SFARG1LO, r0, AT - | beqz AT, >2 - |. li TMP1, 0x3e0 - | not TMP1, TMP1 - | sra TMP0, TMP0, 21 - | subu TMP0, TMP1, TMP0 - | slt AT, TMP0, r0 - | bnez AT, >1 - |. sll TMP1, SFARG1HI, 11 - | lui AT, 0x8000 - | or TMP1, TMP1, AT - | srl AT, SFARG1LO, 21 - | or TMP1, TMP1, AT - | slt AT, SFARG1HI, r0 - | beqz AT, >2 - |. srlv SFARG1LO, TMP1, TMP0 - | subu SFARG1LO, r0, SFARG1LO - |2: - | jr ra - |. move CRET1, SFARG1LO - |1: - | addiu TMP0, TMP0, 21 - | srlv TMP1, SFARG1LO, TMP0 - | li AT, 20 - | subu TMP0, AT, TMP0 - | sll SFARG1LO, SFARG1HI, 12 - | sllv AT, SFARG1LO, TMP0 - | or SFARG1LO, TMP1, AT - | slt AT, SFARG1HI, r0 - | beqz AT, <2 - |. nop - | jr ra - |. subu CRET1, r0, SFARG1LO - |.endif - | - |.macro .ffunc_bit, name - | .ffunc_1 bit_..name - | beq SFARG1HI, TISNUM, >6 - |. move CRET1, SFARG1LO - | bal ->vm_tobit_fb - |. sltu TMP1, SFARG1HI, TISNUM - |6: - |.endmacro - | - |.macro .ffunc_bit_op, name, ins - | .ffunc_bit name - | addiu TMP2, BASE, 8 - | addu TMP3, BASE, NARGS8:RC - |1: - | lw SFARG1HI, HI(TMP2) - | beq TMP2, TMP3, ->fff_resi - |. lw SFARG1LO, LO(TMP2) - |.if FPU - | bne SFARG1HI, TISNUM, >2 - |. addiu TMP2, TMP2, 8 - | b <1 - |. ins CRET1, CRET1, SFARG1LO - |2: - | ldc1 FARG1, -8(TMP2) - | sltu TMP1, SFARG1HI, TISNUM - | beqz TMP1, ->fff_fallback - |. add.d FARG1, FARG1, TOBIT - | mfc1 SFARG1LO, FARG1 - | b <1 - |. ins CRET1, CRET1, SFARG1LO - |.else - | beq SFARG1HI, TISNUM, >2 - |. move CRET2, CRET1 - | bal ->vm_tobit_fb - |. sltu TMP1, SFARG1HI, TISNUM - | move SFARG1LO, CRET2 - |2: - | ins CRET1, CRET1, SFARG1LO - | b <1 - |. addiu TMP2, TMP2, 8 - |.endif - |.endmacro - | - |.ffunc_bit_op band, and - |.ffunc_bit_op bor, or - |.ffunc_bit_op bxor, xor - | - |.ffunc_bit bswap - | srl TMP0, CRET1, 24 - | srl TMP2, CRET1, 8 - | sll TMP1, CRET1, 24 - | andi TMP2, TMP2, 0xff00 - | or TMP0, TMP0, TMP1 - | andi CRET1, CRET1, 0xff00 - | or TMP0, TMP0, TMP2 - | sll CRET1, CRET1, 8 - | b ->fff_resi - |. or CRET1, TMP0, CRET1 - | - |.ffunc_bit bnot - | b ->fff_resi - |. not CRET1, CRET1 - | - |.macro .ffunc_bit_sh, name, ins, shmod - | .ffunc_2 bit_..name - | beq SFARG1HI, TISNUM, >1 - |. nop - | bal ->vm_tobit_fb - |. sltu TMP1, SFARG1HI, TISNUM - | move SFARG1LO, CRET1 - |1: - | bne SFARG2HI, TISNUM, ->fff_fallback - |. nop - |.if shmod == 1 - | li AT, 32 - | subu TMP0, AT, SFARG2LO - | sllv SFARG2LO, SFARG1LO, SFARG2LO - | srlv SFARG1LO, SFARG1LO, TMP0 - |.elif shmod == 2 - | li AT, 32 - | subu TMP0, AT, SFARG2LO - | srlv SFARG2LO, SFARG1LO, SFARG2LO - | sllv SFARG1LO, SFARG1LO, TMP0 - |.endif - | b ->fff_resi - |. ins CRET1, SFARG1LO, SFARG2LO - |.endmacro - | - |.ffunc_bit_sh lshift, sllv, 0 - |.ffunc_bit_sh rshift, srlv, 0 - |.ffunc_bit_sh arshift, srav, 0 - |// Can't use rotrv, since it's only in MIPS32R2. - |.ffunc_bit_sh rol, or, 1 - |.ffunc_bit_sh ror, or, 2 - | - |.ffunc_bit tobit - |->fff_resi: - | lw PC, FRAME_PC(BASE) - | addiu RA, BASE, -8 - | sw TISNUM, -8+HI(BASE) - | b ->fff_res1 - |. sw CRET1, -8+LO(BASE) - | - |//----------------------------------------------------------------------- - | - |->fff_fallback: // Call fast function fallback handler. - | // BASE = new base, RB = CFUNC, RC = nargs*8 - | lw TMP3, CFUNC:RB->f - | addu TMP1, BASE, NARGS8:RC - | lw PC, FRAME_PC(BASE) // Fallback may overwrite PC. - | addiu TMP0, TMP1, 8*LUA_MINSTACK - | lw TMP2, L->maxstack - | sw PC, SAVE_PC // Redundant (but a defined value). - | sltu AT, TMP2, TMP0 - | sw BASE, L->base - | sw TMP1, L->top - | bnez AT, >5 // Need to grow stack. - |. move CFUNCADDR, TMP3 - | jalr TMP3 // (lua_State *L) - |. move CARG1, L - | // Either throws an error, or recovers and returns -1, 0 or nresults+1. - | lw BASE, L->base - | sll RD, CRET1, 3 - | bgtz CRET1, ->fff_res // Returned nresults+1? - |. addiu RA, BASE, -8 - |1: // Returned 0 or -1: retry fast path. - | lw TMP0, L->top - | lw LFUNC:RB, FRAME_FUNC(BASE) - | bnez CRET1, ->vm_call_tail // Returned -1? - |. subu NARGS8:RC, TMP0, BASE - | ins_callt // Returned 0: retry fast path. - | - |// Reconstruct previous base for vmeta_call during tailcall. - |->vm_call_tail: - | andi TMP0, PC, FRAME_TYPE - | li AT, -4 - | bnez TMP0, >3 - |. and TMP1, PC, AT - | lbu TMP1, OFS_RA(PC) - | sll TMP1, TMP1, 3 - | addiu TMP1, TMP1, 8 - |3: - | b ->vm_call_dispatch // Resolve again for tailcall. - |. subu TMP2, BASE, TMP1 - | - |5: // Grow stack for fallback handler. - | load_got lj_state_growstack - | li CARG2, LUA_MINSTACK - | call_intern lj_state_growstack // (lua_State *L, int n) - |. move CARG1, L - | lw BASE, L->base - | b <1 - |. li CRET1, 0 // Force retry. - | - |->fff_gcstep: // Call GC step function. - | // BASE = new base, RC = nargs*8 - | move MULTRES, ra - | load_got lj_gc_step - | sw BASE, L->base - | addu TMP0, BASE, NARGS8:RC - | sw PC, SAVE_PC // Redundant (but a defined value). - | sw TMP0, L->top - | call_intern lj_gc_step // (lua_State *L) - |. move CARG1, L - | lw BASE, L->base - | move ra, MULTRES - | lw TMP0, L->top - | lw CFUNC:RB, FRAME_FUNC(BASE) - | jr ra - |. subu NARGS8:RC, TMP0, BASE - | - |//----------------------------------------------------------------------- - |//-- Special dispatch targets ------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_record: // Dispatch target for recording phase. - |.if JIT - | lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH) - | andi AT, TMP3, HOOK_VMEVENT // No recording while in vmevent. - | bnez AT, >5 - | // Decrement the hookcount for consistency, but always do the call. - |. lw TMP2, DISPATCH_GL(hookcount)(DISPATCH) - | andi AT, TMP3, HOOK_ACTIVE - | bnez AT, >1 - |. addiu TMP2, TMP2, -1 - | andi AT, TMP3, LUA_MASKLINE|LUA_MASKCOUNT - | beqz AT, >1 - |. nop - | b >1 - |. sw TMP2, DISPATCH_GL(hookcount)(DISPATCH) - |.endif - | - |->vm_rethook: // Dispatch target for return hooks. - | lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH) - | andi AT, TMP3, HOOK_ACTIVE // Hook already active? - | beqz AT, >1 - |5: // Re-dispatch to static ins. - |. lw AT, GG_DISP2STATIC(TMP0) // Assumes TMP0 holds DISPATCH+OP*4. - | jr AT - |. nop - | - |->vm_inshook: // Dispatch target for instr/line hooks. - | lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH) - | lw TMP2, DISPATCH_GL(hookcount)(DISPATCH) - | andi AT, TMP3, HOOK_ACTIVE // Hook already active? - | bnez AT, <5 - |. andi AT, TMP3, LUA_MASKLINE|LUA_MASKCOUNT - | beqz AT, <5 - |. addiu TMP2, TMP2, -1 - | beqz TMP2, >1 - |. sw TMP2, DISPATCH_GL(hookcount)(DISPATCH) - | andi AT, TMP3, LUA_MASKLINE - | beqz AT, <5 - |1: - |. load_got lj_dispatch_ins - | sw MULTRES, SAVE_MULTRES - | move CARG2, PC - | sw BASE, L->base - | // SAVE_PC must hold the _previous_ PC. The callee updates it with PC. - | call_intern lj_dispatch_ins // (lua_State *L, const BCIns *pc) - |. move CARG1, L - |3: - | lw BASE, L->base - |4: // Re-dispatch to static ins. - | lw INS, -4(PC) - | decode_OP4a TMP1, INS - | decode_OP4b TMP1 - | addu TMP0, DISPATCH, TMP1 - | decode_RD8a RD, INS - | lw AT, GG_DISP2STATIC(TMP0) - | decode_RA8a RA, INS - | decode_RD8b RD - | jr AT - | decode_RA8b RA - | - |->cont_hook: // Continue from hook yield. - | addiu PC, PC, 4 - | b <4 - |. lw MULTRES, -24+LO(RB) // Restore MULTRES for *M ins. - | - |->vm_hotloop: // Hot loop counter underflow. - |.if JIT - | lw LFUNC:TMP1, FRAME_FUNC(BASE) - | addiu CARG1, DISPATCH, GG_DISP2J - | sw PC, SAVE_PC - | lw TMP1, LFUNC:TMP1->pc - | move CARG2, PC - | sw L, DISPATCH_J(L)(DISPATCH) - | lbu TMP1, PC2PROTO(framesize)(TMP1) - | load_got lj_trace_hot - | sw BASE, L->base - | sll TMP1, TMP1, 3 - | addu TMP1, BASE, TMP1 - | call_intern lj_trace_hot // (jit_State *J, const BCIns *pc) - |. sw TMP1, L->top - | b <3 - |. nop - |.endif - | - |->vm_callhook: // Dispatch target for call hooks. - |.if JIT - | b >1 - |.endif - |. move CARG2, PC - | - |->vm_hotcall: // Hot call counter underflow. - |.if JIT - | ori CARG2, PC, 1 - |1: - |.endif - | load_got lj_dispatch_call - | addu TMP0, BASE, RC - | sw PC, SAVE_PC - | sw BASE, L->base - | subu RA, RA, BASE - | sw TMP0, L->top - | call_intern lj_dispatch_call // (lua_State *L, const BCIns *pc) - |. move CARG1, L - | // Returns ASMFunction. - | lw BASE, L->base - | lw TMP0, L->top - | sw r0, SAVE_PC // Invalidate for subsequent line hook. - | subu NARGS8:RC, TMP0, BASE - | addu RA, BASE, RA - | lw LFUNC:RB, FRAME_FUNC(BASE) - | jr CRET1 - |. lw INS, -4(PC) - | - |->cont_stitch: // Trace stitching. - |.if JIT - | // RA = resultptr, RB = meta base - | lw INS, -4(PC) - | lw TMP2, -24+LO(RB) // Save previous trace. - | decode_RA8a RC, INS - | addiu AT, MULTRES, -8 - | decode_RA8b RC - | beqz AT, >2 - |. addu RC, BASE, RC // Call base. - |1: // Move results down. - | lw SFRETHI, HI(RA) - | lw SFRETLO, LO(RA) - | addiu AT, AT, -8 - | addiu RA, RA, 8 - | sw SFRETHI, HI(RC) - | sw SFRETLO, LO(RC) - | bnez AT, <1 - |. addiu RC, RC, 8 - |2: - | decode_RA8a RA, INS - | decode_RB8a RB, INS - | decode_RA8b RA - | decode_RB8b RB - | addu RA, RA, RB - | addu RA, BASE, RA - |3: - | sltu AT, RC, RA - | bnez AT, >9 // More results wanted? - |. nop - | - | lhu TMP3, TRACE:TMP2->traceno - | lhu RD, TRACE:TMP2->link - | beq RD, TMP3, ->cont_nop // Blacklisted. - |. load_got lj_dispatch_stitch - | bnez RD, =>BC_JLOOP // Jump to stitched trace. - |. sll RD, RD, 3 - | - | // Stitch a new trace to the previous trace. - | sw TMP3, DISPATCH_J(exitno)(DISPATCH) - | sw L, DISPATCH_J(L)(DISPATCH) - | sw BASE, L->base - | addiu CARG1, DISPATCH, GG_DISP2J - | call_intern lj_dispatch_stitch // (jit_State *J, const BCIns *pc) - |. move CARG2, PC - | b ->cont_nop - |. lw BASE, L->base - | - |9: - | sw TISNIL, HI(RC) - | b <3 - |. addiu RC, RC, 8 - |.endif - | - |->vm_profhook: // Dispatch target for profiler hook. -#if LJ_HASPROFILE - | load_got lj_dispatch_profile - | sw MULTRES, SAVE_MULTRES - | move CARG2, PC - | sw BASE, L->base - | call_intern lj_dispatch_profile // (lua_State *L, const BCIns *pc) - |. move CARG1, L - | // HOOK_PROFILE is off again, so re-dispatch to dynamic instruction. - | addiu PC, PC, -4 - | b ->cont_nop - |. lw BASE, L->base -#endif - | - |//----------------------------------------------------------------------- - |//-- Trace exit handler ------------------------------------------------- - |//----------------------------------------------------------------------- - | - |.macro savex_, a, b - |.if FPU - | sdc1 f..a, 16+a*8(sp) - | sw r..a, 16+32*8+a*4(sp) - | sw r..b, 16+32*8+b*4(sp) - |.else - | sw r..a, 16+a*4(sp) - | sw r..b, 16+b*4(sp) - |.endif - |.endmacro - | - |->vm_exit_handler: - |.if JIT - |.if FPU - | addiu sp, sp, -(16+32*8+32*4) - |.else - | addiu sp, sp, -(16+32*4) - |.endif - | savex_ 0, 1 - | savex_ 2, 3 - | savex_ 4, 5 - | savex_ 6, 7 - | savex_ 8, 9 - | savex_ 10, 11 - | savex_ 12, 13 - | savex_ 14, 15 - | savex_ 16, 17 - | savex_ 18, 19 - | savex_ 20, 21 - | savex_ 22, 23 - | savex_ 24, 25 - | savex_ 26, 27 - |.if FPU - | sdc1 f28, 16+28*8(sp) - | sdc1 f30, 16+30*8(sp) - | sw r28, 16+32*8+28*4(sp) - | sw r30, 16+32*8+30*4(sp) - | sw r0, 16+32*8+31*4(sp) // Clear RID_TMP. - | addiu TMP2, sp, 16+32*8+32*4 // Recompute original value of sp. - | sw TMP2, 16+32*8+29*4(sp) // Store sp in RID_SP - |.else - | sw r28, 16+28*4(sp) - | sw r30, 16+30*4(sp) - | sw r0, 16+31*4(sp) // Clear RID_TMP. - | addiu TMP2, sp, 16+32*4 // Recompute original value of sp. - | sw TMP2, 16+29*4(sp) // Store sp in RID_SP - |.endif - | li_vmstate EXIT - | addiu DISPATCH, JGL, -GG_DISP2G-32768 - | lw TMP1, 0(TMP2) // Load exit number. - | st_vmstate - | lw L, DISPATCH_GL(cur_L)(DISPATCH) - | lw BASE, DISPATCH_GL(jit_base)(DISPATCH) - | load_got lj_trace_exit - | sw L, DISPATCH_J(L)(DISPATCH) - | sw ra, DISPATCH_J(parent)(DISPATCH) // Store trace number. - | sw BASE, L->base - | sw TMP1, DISPATCH_J(exitno)(DISPATCH) // Store exit number. - | addiu CARG1, DISPATCH, GG_DISP2J - | sw r0, DISPATCH_GL(jit_base)(DISPATCH) - | call_intern lj_trace_exit // (jit_State *J, ExitState *ex) - |. addiu CARG2, sp, 16 - | // Returns MULTRES (unscaled) or negated error code. - | lw TMP1, L->cframe - | li AT, -4 - | lw BASE, L->base - | and sp, TMP1, AT - | lw PC, SAVE_PC // Get SAVE_PC. - | b >1 - |. sw L, SAVE_L // Set SAVE_L (on-trace resume/yield). - |.endif - |->vm_exit_interp: - |.if JIT - | // CRET1 = MULTRES or negated error code, BASE, PC and JGL set. - | lw L, SAVE_L - | addiu DISPATCH, JGL, -GG_DISP2G-32768 - | sw BASE, L->base - |1: - | bltz CRET1, >9 // Check for error from exit. - |. lw LFUNC:RB, FRAME_FUNC(BASE) - | .FPU lui TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float). - | sll MULTRES, CRET1, 3 - | li TISNIL, LJ_TNIL - | li TISNUM, LJ_TISNUM // Setup type comparison constants. - | sw MULTRES, SAVE_MULTRES - | .FPU mtc1 TMP3, TOBIT - | lw TMP1, LFUNC:RB->pc - | sw r0, DISPATCH_GL(jit_base)(DISPATCH) - | lw KBASE, PC2PROTO(k)(TMP1) - | .FPU cvt.d.s TOBIT, TOBIT - | // Modified copy of ins_next which handles function header dispatch, too. - | lw INS, 0(PC) - | addiu PC, PC, 4 - | // Assumes TISNIL == ~LJ_VMST_INTERP == -1 - | sw TISNIL, DISPATCH_GL(vmstate)(DISPATCH) - | decode_OP4a TMP1, INS - | decode_OP4b TMP1 - | sltiu TMP2, TMP1, BC_FUNCF*4 - | addu TMP0, DISPATCH, TMP1 - | decode_RD8a RD, INS - | lw AT, 0(TMP0) - | decode_RA8a RA, INS - | beqz TMP2, >2 - |. decode_RA8b RA - | jr AT - |. decode_RD8b RD - |2: - | sltiu TMP2, TMP1, (BC_FUNCC+2)*4 // Fast function? - | bnez TMP2, >3 - |. lw TMP1, FRAME_PC(BASE) - | // Check frame below fast function. - | andi TMP0, TMP1, FRAME_TYPE - | bnez TMP0, >3 // Trace stitching continuation? - |. nop - | // Otherwise set KBASE for Lua function below fast function. - | lw TMP2, -4(TMP1) - | decode_RA8a TMP0, TMP2 - | decode_RA8b TMP0 - | subu TMP1, BASE, TMP0 - | lw LFUNC:TMP2, -8+FRAME_FUNC(TMP1) - | lw TMP1, LFUNC:TMP2->pc - | lw KBASE, PC2PROTO(k)(TMP1) - |3: - | addiu RC, MULTRES, -8 - | jr AT - |. addu RA, RA, BASE - | - |9: // Rethrow error from the right C frame. - | load_got lj_err_throw - | negu CARG2, CRET1 - | call_intern lj_err_throw // (lua_State *L, int errcode) - |. move CARG1, L - |.endif - | - |//----------------------------------------------------------------------- - |//-- Math helper functions ---------------------------------------------- - |//----------------------------------------------------------------------- - | - |// Hard-float round to integer. - |// Modifies AT, TMP0, FRET1, FRET2, f4. Keeps all others incl. FARG1. - |.macro vm_round_hf, func - | lui TMP0, 0x4330 // Hiword of 2^52 (double). - | mtc1 r0, f4 - | mtc1 TMP0, f5 - | abs.d FRET2, FARG1 // |x| - | mfc1 AT, f13 - | c.olt.d 0, FRET2, f4 - | add.d FRET1, FRET2, f4 // (|x| + 2^52) - 2^52 - | bc1f 0, >1 // Truncate only if |x| < 2^52. - |. sub.d FRET1, FRET1, f4 - | slt AT, AT, r0 - |.if "func" == "ceil" - | lui TMP0, 0xbff0 // Hiword of -1 (double). Preserves -0. - |.else - | lui TMP0, 0x3ff0 // Hiword of +1 (double). - |.endif - |.if "func" == "trunc" - | mtc1 TMP0, f5 - | c.olt.d 0, FRET2, FRET1 // |x| < result? - | sub.d FRET2, FRET1, f4 - | movt.d FRET1, FRET2, 0 // If yes, subtract +1. - | neg.d FRET2, FRET1 - | jr ra - |. movn.d FRET1, FRET2, AT // Merge sign bit back in. - |.else - | neg.d FRET2, FRET1 - | mtc1 TMP0, f5 - | movn.d FRET1, FRET2, AT // Merge sign bit back in. - |.if "func" == "ceil" - | c.olt.d 0, FRET1, FARG1 // x > result? - |.else - | c.olt.d 0, FARG1, FRET1 // x < result? - |.endif - | sub.d FRET2, FRET1, f4 // If yes, subtract +-1. - | jr ra - |. movt.d FRET1, FRET2, 0 - |.endif - |1: - | jr ra - |. mov.d FRET1, FARG1 - |.endmacro - | - |.macro vm_round, func - |.if FPU - | vm_round_hf, func - |.endif - |.endmacro - | - |->vm_floor: - | vm_round floor - |->vm_ceil: - | vm_round ceil - |->vm_trunc: - |.if JIT - | vm_round trunc - |.endif - | - |// Soft-float integer to number conversion. - |.macro sfi2d, AHI, ALO - |.if not FPU - | beqz ALO, >9 // Handle zero first. - |. sra TMP0, ALO, 31 - | xor TMP1, ALO, TMP0 - | subu TMP1, TMP1, TMP0 // Absolute value in TMP1. - | clz AHI, TMP1 - | andi TMP0, TMP0, 0x800 // Mask sign bit. - | li AT, 0x3ff+31-1 - | sllv TMP1, TMP1, AHI // Align mantissa left with leading 1. - | subu AHI, AT, AHI // Exponent - 1 in AHI. - | sll ALO, TMP1, 21 - | or AHI, AHI, TMP0 // Sign | Exponent. - | srl TMP1, TMP1, 11 - | sll AHI, AHI, 20 // Align left. - | jr ra - |. addu AHI, AHI, TMP1 // Add mantissa, increment exponent. - |9: - | jr ra - |. li AHI, 0 - |.endif - |.endmacro - | - |// Input SFARG1LO. Output: SFARG1*. Temporaries: AT, TMP0, TMP1. - |->vm_sfi2d_1: - | sfi2d SFARG1HI, SFARG1LO - | - |// Input SFARG2LO. Output: SFARG2*. Temporaries: AT, TMP0, TMP1. - |->vm_sfi2d_2: - | sfi2d SFARG2HI, SFARG2LO - | - |// Soft-float comparison. Equivalent to c.eq.d. - |// Input: SFARG*. Output: CRET1. Temporaries: AT, TMP0, TMP1. - |->vm_sfcmpeq: - |.if not FPU - | sll AT, SFARG1HI, 1 - | sll TMP0, SFARG2HI, 1 - | or CRET1, SFARG1LO, SFARG2LO - | or TMP1, AT, TMP0 - | or TMP1, TMP1, CRET1 - | beqz TMP1, >8 // Both args +-0: return 1. - |. sltu CRET1, r0, SFARG1LO - | lui TMP1, 0xffe0 - | addu AT, AT, CRET1 - | sltu CRET1, r0, SFARG2LO - | sltu AT, TMP1, AT - | addu TMP0, TMP0, CRET1 - | sltu TMP0, TMP1, TMP0 - | or TMP1, AT, TMP0 - | bnez TMP1, >9 // Either arg is NaN: return 0; - |. xor TMP0, SFARG1HI, SFARG2HI - | xor TMP1, SFARG1LO, SFARG2LO - | or AT, TMP0, TMP1 - | jr ra - |. sltiu CRET1, AT, 1 // Same values: return 1. - |8: - | jr ra - |. li CRET1, 1 - |9: - | jr ra - |. li CRET1, 0 - |.endif - | - |// Soft-float comparison. Equivalent to c.ult.d and c.olt.d. - |// Input: SFARG*. Output: CRET1. Temporaries: AT, TMP0, TMP1, CRET2. - |->vm_sfcmpult: - |.if not FPU - | b >1 - |. li CRET2, 1 - |.endif - | - |->vm_sfcmpolt: - |.if not FPU - | li CRET2, 0 - |1: - | sll AT, SFARG1HI, 1 - | sll TMP0, SFARG2HI, 1 - | or CRET1, SFARG1LO, SFARG2LO - | or TMP1, AT, TMP0 - | or TMP1, TMP1, CRET1 - | beqz TMP1, >8 // Both args +-0: return 0. - |. sltu CRET1, r0, SFARG1LO - | lui TMP1, 0xffe0 - | addu AT, AT, CRET1 - | sltu CRET1, r0, SFARG2LO - | sltu AT, TMP1, AT - | addu TMP0, TMP0, CRET1 - | sltu TMP0, TMP1, TMP0 - | or TMP1, AT, TMP0 - | bnez TMP1, >9 // Either arg is NaN: return 0 or 1; - |. and AT, SFARG1HI, SFARG2HI - | bltz AT, >5 // Both args negative? - |. nop - | beq SFARG1HI, SFARG2HI, >8 - |. sltu CRET1, SFARG1LO, SFARG2LO - | jr ra - |. slt CRET1, SFARG1HI, SFARG2HI - |5: // Swap conditions if both operands are negative. - | beq SFARG1HI, SFARG2HI, >8 - |. sltu CRET1, SFARG2LO, SFARG1LO - | jr ra - |. slt CRET1, SFARG2HI, SFARG1HI - |8: - | jr ra - |. nop - |9: - | jr ra - |. move CRET1, CRET2 - |.endif - | - |// Soft-float comparison. Equivalent to c.ole.d a, b or c.ole.d b, a. - |// Input: SFARG*, TMP3. Output: CRET1. Temporaries: AT, TMP0, TMP1. - |->vm_sfcmpolex: - |.if not FPU - | sll AT, SFARG1HI, 1 - | sll TMP0, SFARG2HI, 1 - | or CRET1, SFARG1LO, SFARG2LO - | or TMP1, AT, TMP0 - | or TMP1, TMP1, CRET1 - | beqz TMP1, >8 // Both args +-0: return 1. - |. sltu CRET1, r0, SFARG1LO - | lui TMP1, 0xffe0 - | addu AT, AT, CRET1 - | sltu CRET1, r0, SFARG2LO - | sltu AT, TMP1, AT - | addu TMP0, TMP0, CRET1 - | sltu TMP0, TMP1, TMP0 - | or TMP1, AT, TMP0 - | bnez TMP1, >9 // Either arg is NaN: return 0; - |. and AT, SFARG1HI, SFARG2HI - | xor AT, AT, TMP3 - | bltz AT, >5 // Both args negative? - |. nop - | beq SFARG1HI, SFARG2HI, >6 - |. sltu CRET1, SFARG2LO, SFARG1LO - | jr ra - |. slt CRET1, SFARG2HI, SFARG1HI - |5: // Swap conditions if both operands are negative. - | beq SFARG1HI, SFARG2HI, >6 - |. sltu CRET1, SFARG1LO, SFARG2LO - | slt CRET1, SFARG1HI, SFARG2HI - |6: - | jr ra - |. nop - |8: - | jr ra - |. li CRET1, 1 - |9: - | jr ra - |. li CRET1, 0 - |.endif - | - |.macro sfmin_max, name, intins - |->vm_sf .. name: - |.if JIT and not FPU - | move TMP2, ra - | bal ->vm_sfcmpolt - |. nop - | move TMP0, CRET1 - | move SFRETHI, SFARG1HI - | move SFRETLO, SFARG1LO - | move ra, TMP2 - | intins SFRETHI, SFARG2HI, TMP0 - | jr ra - |. intins SFRETLO, SFARG2LO, TMP0 - |.endif - |.endmacro - | - | sfmin_max min, movz - | sfmin_max max, movn - | - |//----------------------------------------------------------------------- - |//-- Miscellaneous functions -------------------------------------------- - |//----------------------------------------------------------------------- - | - |//----------------------------------------------------------------------- - |//-- FFI helper functions ----------------------------------------------- - |//----------------------------------------------------------------------- - | - |// Handler for callback functions. Callback slot number in r1, g in r2. - |->vm_ffi_callback: - |.if FFI - |.type CTSTATE, CTState, PC - | saveregs - | lw CTSTATE, GL:r2->ctype_state - | addiu DISPATCH, r2, GG_G2DISP - | load_got lj_ccallback_enter - | sw r1, CTSTATE->cb.slot - | sw CARG1, CTSTATE->cb.gpr[0] - | sw CARG2, CTSTATE->cb.gpr[1] - | .FPU sdc1 FARG1, CTSTATE->cb.fpr[0] - | sw CARG3, CTSTATE->cb.gpr[2] - | sw CARG4, CTSTATE->cb.gpr[3] - | .FPU sdc1 FARG2, CTSTATE->cb.fpr[1] - | addiu TMP0, sp, CFRAME_SPACE+16 - | sw TMP0, CTSTATE->cb.stack - | sw r0, SAVE_PC // Any value outside of bytecode is ok. - | move CARG2, sp - | call_intern lj_ccallback_enter // (CTState *cts, void *cf) - |. move CARG1, CTSTATE - | // Returns lua_State *. - | lw BASE, L:CRET1->base - | lw RC, L:CRET1->top - | li TISNUM, LJ_TISNUM // Setup type comparison constants. - | move L, CRET1 - | .FPU lui TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float). - | lw LFUNC:RB, FRAME_FUNC(BASE) - | .FPU mtc1 TMP3, TOBIT - | li_vmstate INTERP - | li TISNIL, LJ_TNIL - | subu RC, RC, BASE - | st_vmstate - | .FPU cvt.d.s TOBIT, TOBIT - | ins_callt - |.endif - | - |->cont_ffi_callback: // Return from FFI callback. - |.if FFI - | load_got lj_ccallback_leave - | lw CTSTATE, DISPATCH_GL(ctype_state)(DISPATCH) - | sw BASE, L->base - | sw RB, L->top - | sw L, CTSTATE->L - | move CARG2, RA - | call_intern lj_ccallback_leave // (CTState *cts, TValue *o) - |. move CARG1, CTSTATE - | .FPU ldc1 FRET1, CTSTATE->cb.fpr[0] - | lw CRET1, CTSTATE->cb.gpr[0] - | .FPU ldc1 FRET2, CTSTATE->cb.fpr[1] - | b ->vm_leave_unw - |. lw CRET2, CTSTATE->cb.gpr[1] - |.endif - | - |->vm_ffi_call: // Call C function via FFI. - | // Caveat: needs special frame unwinding, see below. - |.if FFI - | .type CCSTATE, CCallState, CARG1 - | lw TMP1, CCSTATE->spadj - | lbu CARG2, CCSTATE->nsp - | move TMP2, sp - | subu sp, sp, TMP1 - | sw ra, -4(TMP2) - | sll CARG2, CARG2, 2 - | sw r16, -8(TMP2) - | sw CCSTATE, -12(TMP2) - | move r16, TMP2 - | addiu TMP1, CCSTATE, offsetof(CCallState, stack) - | addiu TMP2, sp, 16 - | beqz CARG2, >2 - |. addu TMP3, TMP1, CARG2 - |1: - | lw TMP0, 0(TMP1) - | addiu TMP1, TMP1, 4 - | sltu AT, TMP1, TMP3 - | sw TMP0, 0(TMP2) - | bnez AT, <1 - |. addiu TMP2, TMP2, 4 - |2: - | lw CFUNCADDR, CCSTATE->func - | lw CARG2, CCSTATE->gpr[1] - | lw CARG3, CCSTATE->gpr[2] - | lw CARG4, CCSTATE->gpr[3] - | .FPU ldc1 FARG1, CCSTATE->fpr[0] - | .FPU ldc1 FARG2, CCSTATE->fpr[1] - | jalr CFUNCADDR - |. lw CARG1, CCSTATE->gpr[0] // Do this last, since CCSTATE is CARG1. - | lw CCSTATE:TMP1, -12(r16) - | lw TMP2, -8(r16) - | lw ra, -4(r16) - | sw CRET1, CCSTATE:TMP1->gpr[0] - | sw CRET2, CCSTATE:TMP1->gpr[1] - |.if FPU - | sdc1 FRET1, CCSTATE:TMP1->fpr[0] - | sdc1 FRET2, CCSTATE:TMP1->fpr[1] - |.else - | sw CARG1, CCSTATE:TMP1->gpr[2] // Soft-float: complex double .im part. - | sw CARG2, CCSTATE:TMP1->gpr[3] - |.endif - | move sp, r16 - | jr ra - |. move r16, TMP2 - |.endif - |// Note: vm_ffi_call must be the last function in this object file! - | - |//----------------------------------------------------------------------- -} - -/* Generate the code for a single instruction. */ -static void build_ins(BuildCtx *ctx, BCOp op, int defop) -{ - int vk = 0; - |=>defop: - - switch (op) { - - /* -- Comparison ops ---------------------------------------------------- */ - - /* Remember: all ops branch for a true comparison, fall through otherwise. */ - - case BC_ISLT: case BC_ISGE: case BC_ISLE: case BC_ISGT: - | // RA = src1*8, RD = src2*8, JMP with RD = target - |.macro bc_comp, FRA, FRD, RAHI, RALO, RDHI, RDLO, movop, fmovop, fcomp, sfcomp - | addu RA, BASE, RA - | addu RD, BASE, RD - | lw RAHI, HI(RA) - | lw RDHI, HI(RD) - | lhu TMP2, OFS_RD(PC) - | addiu PC, PC, 4 - | bne RAHI, TISNUM, >2 - |. lw RALO, LO(RA) - | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) - | lw RDLO, LO(RD) - | bne RDHI, TISNUM, >5 - |. decode_RD4b TMP2 - | slt AT, SFARG1LO, SFARG2LO - | addu TMP2, TMP2, TMP3 - | movop TMP2, r0, AT - |1: - | addu PC, PC, TMP2 - | ins_next - | - |2: // RA is not an integer. - | sltiu AT, RAHI, LJ_TISNUM - | beqz AT, ->vmeta_comp - |. lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) - | sltiu AT, RDHI, LJ_TISNUM - |.if FPU - | ldc1 FRA, 0(RA) - | ldc1 FRD, 0(RD) - |.else - | lw RDLO, LO(RD) - |.endif - | beqz AT, >4 - |. decode_RD4b TMP2 - |3: // RA and RD are both numbers. - |.if FPU - | fcomp f20, f22 - | addu TMP2, TMP2, TMP3 - | b <1 - |. fmovop TMP2, r0 - |.else - | bal sfcomp - |. addu TMP2, TMP2, TMP3 - | b <1 - |. movop TMP2, r0, CRET1 - |.endif - | - |4: // RA is a number, RD is not a number. - | bne RDHI, TISNUM, ->vmeta_comp - | // RA is a number, RD is an integer. Convert RD to a number. - |.if FPU - |. lwc1 FRD, LO(RD) - | b <3 - |. cvt.d.w FRD, FRD - |.else - |. nop - |.if "RDHI" == "SFARG1HI" - | bal ->vm_sfi2d_1 - |.else - | bal ->vm_sfi2d_2 - |.endif - |. nop - | b <3 - |. nop - |.endif - | - |5: // RA is an integer, RD is not an integer - | sltiu AT, RDHI, LJ_TISNUM - | beqz AT, ->vmeta_comp - | // RA is an integer, RD is a number. Convert RA to a number. - |.if FPU - |. mtc1 RALO, FRA - | ldc1 FRD, 0(RD) - | b <3 - | cvt.d.w FRA, FRA - |.else - |. nop - |.if "RAHI" == "SFARG1HI" - | bal ->vm_sfi2d_1 - |.else - | bal ->vm_sfi2d_2 - |.endif - |. nop - | b <3 - |. nop - |.endif - |.endmacro - | - if (op == BC_ISLT) { - | bc_comp f20, f22, SFARG1HI, SFARG1LO, SFARG2HI, SFARG2LO, movz, movf, c.olt.d, ->vm_sfcmpolt - } else if (op == BC_ISGE) { - | bc_comp f20, f22, SFARG1HI, SFARG1LO, SFARG2HI, SFARG2LO, movn, movt, c.olt.d, ->vm_sfcmpolt - } else if (op == BC_ISLE) { - | bc_comp f22, f20, SFARG2HI, SFARG2LO, SFARG1HI, SFARG1LO, movn, movt, c.ult.d, ->vm_sfcmpult - } else { - | bc_comp f22, f20, SFARG2HI, SFARG2LO, SFARG1HI, SFARG1LO, movz, movf, c.ult.d, ->vm_sfcmpult - } - break; - - case BC_ISEQV: case BC_ISNEV: - vk = op == BC_ISEQV; - | // RA = src1*8, RD = src2*8, JMP with RD = target - | addu RA, BASE, RA - | addiu PC, PC, 4 - | addu RD, BASE, RD - | lw SFARG1HI, HI(RA) - | lhu TMP2, -4+OFS_RD(PC) - | lw SFARG2HI, HI(RD) - | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) - | sltu AT, TISNUM, SFARG1HI - | sltu TMP0, TISNUM, SFARG2HI - | or AT, AT, TMP0 - if (vk) { - | beqz AT, ->BC_ISEQN_Z - } else { - | beqz AT, ->BC_ISNEN_Z - } - |. decode_RD4b TMP2 - | // Either or both types are not numbers. - | lw SFARG1LO, LO(RA) - | lw SFARG2LO, LO(RD) - | addu TMP2, TMP2, TMP3 - |.if FFI - | li TMP3, LJ_TCDATA - | beq SFARG1HI, TMP3, ->vmeta_equal_cd - |.endif - |. sltiu AT, SFARG1HI, LJ_TISPRI // Not a primitive? - |.if FFI - | beq SFARG2HI, TMP3, ->vmeta_equal_cd - |.endif - |. xor TMP3, SFARG1LO, SFARG2LO // Same tv? - | xor SFARG2HI, SFARG2HI, SFARG1HI // Same type? - | sltiu TMP0, SFARG1HI, LJ_TISTABUD+1 // Table or userdata? - | movz TMP3, r0, AT // Ignore tv if primitive. - | movn TMP0, r0, SFARG2HI // Tab/ud and same type? - | or AT, SFARG2HI, TMP3 // Same type && (pri||same tv). - | movz TMP0, r0, AT - | beqz TMP0, >1 // Done if not tab/ud or not same type or same tv. - if (vk) { - |. movn TMP2, r0, AT - } else { - |. movz TMP2, r0, AT - } - | // Different tables or userdatas. Need to check __eq metamethod. - | // Field metatable must be at same offset for GCtab and GCudata! - | lw TAB:TMP1, TAB:SFARG1LO->metatable - | beqz TAB:TMP1, >1 // No metatable? - |. nop - | lbu TMP1, TAB:TMP1->nomm - | andi TMP1, TMP1, 1<1 // Or 'no __eq' flag set? - |. nop - | b ->vmeta_equal // Handle __eq metamethod. - |. li TMP0, 1-vk // ne = 0 or 1. - |1: - | addu PC, PC, TMP2 - | ins_next - break; - - case BC_ISEQS: case BC_ISNES: - vk = op == BC_ISEQS; - | // RA = src*8, RD = str_const*8 (~), JMP with RD = target - | addu RA, BASE, RA - | addiu PC, PC, 4 - | lw TMP0, HI(RA) - | srl RD, RD, 1 - | lw STR:TMP3, LO(RA) - | subu RD, KBASE, RD - | lhu TMP2, -4+OFS_RD(PC) - |.if FFI - | li AT, LJ_TCDATA - | beq TMP0, AT, ->vmeta_equal_cd - |.endif - |. lw STR:TMP1, -4(RD) // KBASE-4-str_const*4 - | addiu TMP0, TMP0, -LJ_TSTR - | decode_RD4b TMP2 - | xor TMP1, STR:TMP1, STR:TMP3 - | or TMP0, TMP0, TMP1 - | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) - | addu TMP2, TMP2, TMP3 - if (vk) { - | movn TMP2, r0, TMP0 - } else { - | movz TMP2, r0, TMP0 - } - | addu PC, PC, TMP2 - | ins_next - break; - - case BC_ISEQN: case BC_ISNEN: - vk = op == BC_ISEQN; - | // RA = src*8, RD = num_const*8, JMP with RD = target - | addu RA, BASE, RA - | addu RD, KBASE, RD - | lw SFARG1HI, HI(RA) - | lw SFARG2HI, HI(RD) - | lhu TMP2, OFS_RD(PC) - | addiu PC, PC, 4 - | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) - | decode_RD4b TMP2 - if (vk) { - |->BC_ISEQN_Z: - } else { - |->BC_ISNEN_Z: - } - | bne SFARG1HI, TISNUM, >3 - |. lw SFARG1LO, LO(RA) - | lw SFARG2LO, LO(RD) - | addu TMP2, TMP2, TMP3 - | bne SFARG2HI, TISNUM, >6 - |. xor AT, SFARG1LO, SFARG2LO - if (vk) { - | movn TMP2, r0, AT - |1: - | addu PC, PC, TMP2 - |2: - } else { - | movz TMP2, r0, AT - |1: - |2: - | addu PC, PC, TMP2 - } - | ins_next - | - |3: // RA is not an integer. - | sltiu AT, SFARG1HI, LJ_TISNUM - |.if FFI - | beqz AT, >8 - |.else - | beqz AT, <2 - |.endif - |. addu TMP2, TMP2, TMP3 - | sltiu AT, SFARG2HI, LJ_TISNUM - |.if FPU - | ldc1 f20, 0(RA) - | ldc1 f22, 0(RD) - |.endif - | beqz AT, >5 - |. lw SFARG2LO, LO(RD) - |4: // RA and RD are both numbers. - |.if FPU - | c.eq.d f20, f22 - | b <1 - if (vk) { - |. movf TMP2, r0 - } else { - |. movt TMP2, r0 - } - |.else - | bal ->vm_sfcmpeq - |. nop - | b <1 - if (vk) { - |. movz TMP2, r0, CRET1 - } else { - |. movn TMP2, r0, CRET1 - } - |.endif - | - |5: // RA is a number, RD is not a number. - |.if FFI - | bne SFARG2HI, TISNUM, >9 - |.else - | bne SFARG2HI, TISNUM, <2 - |.endif - | // RA is a number, RD is an integer. Convert RD to a number. - |.if FPU - |. lwc1 f22, LO(RD) - | b <4 - |. cvt.d.w f22, f22 - |.else - |. nop - | bal ->vm_sfi2d_2 - |. nop - | b <4 - |. nop - |.endif - | - |6: // RA is an integer, RD is not an integer - | sltiu AT, SFARG2HI, LJ_TISNUM - |.if FFI - | beqz AT, >9 - |.else - | beqz AT, <2 - |.endif - | // RA is an integer, RD is a number. Convert RA to a number. - |.if FPU - |. mtc1 SFARG1LO, f20 - | ldc1 f22, 0(RD) - | b <4 - | cvt.d.w f20, f20 - |.else - |. nop - | bal ->vm_sfi2d_1 - |. nop - | b <4 - |. nop - |.endif - | - |.if FFI - |8: - | li AT, LJ_TCDATA - | bne SFARG1HI, AT, <2 - |. nop - | b ->vmeta_equal_cd - |. nop - |9: - | li AT, LJ_TCDATA - | bne SFARG2HI, AT, <2 - |. nop - | b ->vmeta_equal_cd - |. nop - |.endif - break; - - case BC_ISEQP: case BC_ISNEP: - vk = op == BC_ISEQP; - | // RA = src*8, RD = primitive_type*8 (~), JMP with RD = target - | addu RA, BASE, RA - | srl TMP1, RD, 3 - | lw TMP0, HI(RA) - | lhu TMP2, OFS_RD(PC) - | not TMP1, TMP1 - | addiu PC, PC, 4 - |.if FFI - | li AT, LJ_TCDATA - | beq TMP0, AT, ->vmeta_equal_cd - |.endif - |. xor TMP0, TMP0, TMP1 - | decode_RD4b TMP2 - | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) - | addu TMP2, TMP2, TMP3 - if (vk) { - | movn TMP2, r0, TMP0 - } else { - | movz TMP2, r0, TMP0 - } - | addu PC, PC, TMP2 - | ins_next - break; - - /* -- Unary test and copy ops ------------------------------------------- */ - - case BC_ISTC: case BC_ISFC: case BC_IST: case BC_ISF: - | // RA = dst*8 or unused, RD = src*8, JMP with RD = target - | addu RD, BASE, RD - | lhu TMP2, OFS_RD(PC) - | lw TMP0, HI(RD) - | addiu PC, PC, 4 - if (op == BC_IST || op == BC_ISF) { - | sltiu TMP0, TMP0, LJ_TISTRUECOND - | decode_RD4b TMP2 - | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) - | addu TMP2, TMP2, TMP3 - if (op == BC_IST) { - | movz TMP2, r0, TMP0 - } else { - | movn TMP2, r0, TMP0 - } - | addu PC, PC, TMP2 - } else { - | sltiu TMP0, TMP0, LJ_TISTRUECOND - | lw SFRETHI, HI(RD) - | lw SFRETLO, LO(RD) - if (op == BC_ISTC) { - | beqz TMP0, >1 - } else { - | bnez TMP0, >1 - } - |. addu RA, BASE, RA - | decode_RD4b TMP2 - | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) - | addu TMP2, TMP2, TMP3 - | sw SFRETHI, HI(RA) - | sw SFRETLO, LO(RA) - | addu PC, PC, TMP2 - |1: - } - | ins_next - break; - - case BC_ISTYPE: - | // RA = src*8, RD = -type*8 - | addu TMP2, BASE, RA - | srl TMP1, RD, 3 - | lw TMP0, HI(TMP2) - | ins_next1 - | addu AT, TMP0, TMP1 - | bnez AT, ->vmeta_istype - |. ins_next2 - break; - case BC_ISNUM: - | // RA = src*8, RD = -(TISNUM-1)*8 - | addu TMP2, BASE, RA - | lw TMP0, HI(TMP2) - | ins_next1 - | sltiu AT, TMP0, LJ_TISNUM - | beqz AT, ->vmeta_istype - |. ins_next2 - break; - - /* -- Unary ops --------------------------------------------------------- */ - - case BC_MOV: - | // RA = dst*8, RD = src*8 - | addu RD, BASE, RD - | addu RA, BASE, RA - | lw SFRETHI, HI(RD) - | lw SFRETLO, LO(RD) - | ins_next1 - | sw SFRETHI, HI(RA) - | sw SFRETLO, LO(RA) - | ins_next2 - break; - case BC_NOT: - | // RA = dst*8, RD = src*8 - | addu RD, BASE, RD - | addu RA, BASE, RA - | lw TMP0, HI(RD) - | li TMP1, LJ_TFALSE - | sltiu TMP0, TMP0, LJ_TISTRUECOND - | addiu TMP1, TMP0, LJ_TTRUE - | ins_next1 - | sw TMP1, HI(RA) - | ins_next2 - break; - case BC_UNM: - | // RA = dst*8, RD = src*8 - | addu RB, BASE, RD - | lw SFARG1HI, HI(RB) - | addu RA, BASE, RA - | bne SFARG1HI, TISNUM, >2 - |. lw SFARG1LO, LO(RB) - | lui TMP1, 0x8000 - | beq SFARG1LO, TMP1, ->vmeta_unm // Meta handler deals with -2^31. - |. negu SFARG1LO, SFARG1LO - |1: - | ins_next1 - | sw SFARG1HI, HI(RA) - | sw SFARG1LO, LO(RA) - | ins_next2 - |2: - | sltiu AT, SFARG1HI, LJ_TISNUM - | beqz AT, ->vmeta_unm - |. lui TMP1, 0x8000 - | b <1 - |. xor SFARG1HI, SFARG1HI, TMP1 - break; - case BC_LEN: - | // RA = dst*8, RD = src*8 - | addu CARG2, BASE, RD - | addu RA, BASE, RA - | lw TMP0, HI(CARG2) - | lw CARG1, LO(CARG2) - | li AT, LJ_TSTR - | bne TMP0, AT, >2 - |. li AT, LJ_TTAB - | lw CRET1, STR:CARG1->len - |1: - | ins_next1 - | sw TISNUM, HI(RA) - | sw CRET1, LO(RA) - | ins_next2 - |2: - | bne TMP0, AT, ->vmeta_len - |. nop -#if LJ_52 - | lw TAB:TMP2, TAB:CARG1->metatable - | bnez TAB:TMP2, >9 - |. nop - |3: -#endif - |->BC_LEN_Z: - | load_got lj_tab_len - | call_intern lj_tab_len // (GCtab *t) - |. nop - | // Returns uint32_t (but less than 2^31). - | b <1 - |. nop -#if LJ_52 - |9: - | lbu TMP0, TAB:TMP2->nomm - | andi TMP0, TMP0, 1<vmeta_len - |. nop -#endif - break; - - /* -- Binary ops -------------------------------------------------------- */ - - |.macro fpmod, a, b, c - | bal ->vm_floor // floor(b/c) - |. div.d FARG1, b, c - | mul.d a, FRET1, c - | sub.d a, b, a // b - floor(b/c)*c - |.endmacro - - |.macro sfpmod - | addiu sp, sp, -16 - | - | load_got __divdf3 - | sw SFARG1HI, HI(sp) - | sw SFARG1LO, LO(sp) - | sw SFARG2HI, 8+HI(sp) - | call_extern - |. sw SFARG2LO, 8+LO(sp) - | - | load_got floor - | move SFARG1HI, SFRETHI - | call_extern - |. move SFARG1LO, SFRETLO - | - | load_got __muldf3 - | move SFARG1HI, SFRETHI - | move SFARG1LO, SFRETLO - | lw SFARG2HI, 8+HI(sp) - | call_extern - |. lw SFARG2LO, 8+LO(sp) - | - | load_got __subdf3 - | lw SFARG1HI, HI(sp) - | lw SFARG1LO, LO(sp) - | move SFARG2HI, SFRETHI - | call_extern - |. move SFARG2LO, SFRETLO - | - | addiu sp, sp, 16 - |.endmacro - - |.macro ins_arithpre, label - ||vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN); - | // RA = dst*8, RB = src1*8, RC = src2*8 | num_const*8 - ||switch (vk) { - ||case 0: - | decode_RB8a RB, INS - | decode_RB8b RB - | decode_RDtoRC8 RC, RD - | // RA = dst*8, RB = src1*8, RC = num_const*8 - | addu RB, BASE, RB - |.if "label" ~= "none" - | b label - |.endif - |. addu RC, KBASE, RC - || break; - ||case 1: - | decode_RB8a RC, INS - | decode_RB8b RC - | decode_RDtoRC8 RB, RD - | // RA = dst*8, RB = num_const*8, RC = src1*8 - | addu RC, BASE, RC - |.if "label" ~= "none" - | b label - |.endif - |. addu RB, KBASE, RB - || break; - ||default: - | decode_RB8a RB, INS - | decode_RB8b RB - | decode_RDtoRC8 RC, RD - | // RA = dst*8, RB = src1*8, RC = src2*8 - | addu RB, BASE, RB - |.if "label" ~= "none" - | b label - |.endif - |. addu RC, BASE, RC - || break; - ||} - |.endmacro - | - |.macro ins_arith, intins, fpins, fpcall, label - | ins_arithpre none - | - |.if "label" ~= "none" - |label: - |.endif - | - | lw SFARG1HI, HI(RB) - | lw SFARG2HI, HI(RC) - | - |.if "intins" ~= "div" - | - | // Check for two integers. - | lw SFARG1LO, LO(RB) - | bne SFARG1HI, TISNUM, >5 - |. lw SFARG2LO, LO(RC) - | bne SFARG2HI, TISNUM, >5 - | - |.if "intins" == "addu" - |. intins CRET1, SFARG1LO, SFARG2LO - | xor TMP1, CRET1, SFARG1LO // ((y^a) & (y^b)) < 0: overflow. - | xor TMP2, CRET1, SFARG2LO - | and TMP1, TMP1, TMP2 - | bltz TMP1, ->vmeta_arith - |. addu RA, BASE, RA - |.elif "intins" == "subu" - |. intins CRET1, SFARG1LO, SFARG2LO - | xor TMP1, CRET1, SFARG1LO // ((y^a) & (a^b)) < 0: overflow. - | xor TMP2, SFARG1LO, SFARG2LO - | and TMP1, TMP1, TMP2 - | bltz TMP1, ->vmeta_arith - |. addu RA, BASE, RA - |.elif "intins" == "mult" - |. intins SFARG1LO, SFARG2LO - | mflo CRET1 - | mfhi TMP2 - | sra TMP1, CRET1, 31 - | bne TMP1, TMP2, ->vmeta_arith - |. addu RA, BASE, RA - |.else - |. load_got lj_vm_modi - | beqz SFARG2LO, ->vmeta_arith - |. addu RA, BASE, RA - |.if ENDIAN_BE - | move CARG1, SFARG1LO - |.endif - | call_extern - |. move CARG2, SFARG2LO - |.endif - | - | ins_next1 - | sw TISNUM, HI(RA) - | sw CRET1, LO(RA) - |3: - | ins_next2 - | - |.elif not FPU - | - | lw SFARG1LO, LO(RB) - | lw SFARG2LO, LO(RC) - | - |.endif - | - |5: // Check for two numbers. - | .FPU ldc1 f20, 0(RB) - | sltiu AT, SFARG1HI, LJ_TISNUM - | sltiu TMP0, SFARG2HI, LJ_TISNUM - | .FPU ldc1 f22, 0(RC) - | and AT, AT, TMP0 - | beqz AT, ->vmeta_arith - |. addu RA, BASE, RA - | - |.if FPU - | fpins FRET1, f20, f22 - |.elif "fpcall" == "sfpmod" - | sfpmod - |.else - | load_got fpcall - | call_extern - |. nop - |.endif - | - | ins_next1 - |.if not FPU - | sw SFRETHI, HI(RA) - |.endif - |.if "intins" ~= "div" - | b <3 - |.endif - |.if FPU - |. sdc1 FRET1, 0(RA) - |.else - |. sw SFRETLO, LO(RA) - |.endif - |.if "intins" == "div" - | ins_next2 - |.endif - | - |.endmacro - - case BC_ADDVN: case BC_ADDNV: case BC_ADDVV: - | ins_arith addu, add.d, __adddf3, none - break; - case BC_SUBVN: case BC_SUBNV: case BC_SUBVV: - | ins_arith subu, sub.d, __subdf3, none - break; - case BC_MULVN: case BC_MULNV: case BC_MULVV: - | ins_arith mult, mul.d, __muldf3, none - break; - case BC_DIVVN: - | ins_arith div, div.d, __divdf3, ->BC_DIVVN_Z - break; - case BC_DIVNV: case BC_DIVVV: - | ins_arithpre ->BC_DIVVN_Z - break; - case BC_MODVN: - | ins_arith modi, fpmod, sfpmod, ->BC_MODVN_Z - break; - case BC_MODNV: case BC_MODVV: - | ins_arithpre ->BC_MODVN_Z - break; - case BC_POW: - | ins_arithpre none - | lw SFARG1HI, HI(RB) - | lw SFARG2HI, HI(RC) - | sltiu AT, SFARG1HI, LJ_TISNUM - | sltiu TMP0, SFARG2HI, LJ_TISNUM - | and AT, AT, TMP0 - | load_got pow - | beqz AT, ->vmeta_arith - |. addu RA, BASE, RA - |.if FPU - | ldc1 FARG1, 0(RB) - | ldc1 FARG2, 0(RC) - |.else - | lw SFARG1LO, LO(RB) - | lw SFARG2LO, LO(RC) - |.endif - | call_extern - |. nop - | ins_next1 - |.if FPU - | sdc1 FRET1, 0(RA) - |.else - | sw SFRETHI, HI(RA) - | sw SFRETLO, LO(RA) - |.endif - | ins_next2 - break; - - case BC_CAT: - | // RA = dst*8, RB = src_start*8, RC = src_end*8 - | decode_RB8a RB, INS - | decode_RB8b RB - | decode_RDtoRC8 RC, RD - | subu CARG3, RC, RB - | sw BASE, L->base - | addu CARG2, BASE, RC - | move MULTRES, RB - |->BC_CAT_Z: - | load_got lj_meta_cat - | srl CARG3, CARG3, 3 - | sw PC, SAVE_PC - | call_intern lj_meta_cat // (lua_State *L, TValue *top, int left) - |. move CARG1, L - | // Returns NULL (finished) or TValue * (metamethod). - | bnez CRET1, ->vmeta_binop - |. lw BASE, L->base - | addu RB, BASE, MULTRES - | lw SFRETHI, HI(RB) - | lw SFRETLO, LO(RB) - | addu RA, BASE, RA - | ins_next1 - | sw SFRETHI, HI(RA) - | sw SFRETLO, LO(RA) - | ins_next2 - break; - - /* -- Constant ops ------------------------------------------------------ */ - - case BC_KSTR: - | // RA = dst*8, RD = str_const*8 (~) - | srl TMP1, RD, 1 - | subu TMP1, KBASE, TMP1 - | ins_next1 - | lw TMP0, -4(TMP1) // KBASE-4-str_const*4 - | addu RA, BASE, RA - | li TMP2, LJ_TSTR - | sw TMP0, LO(RA) - | sw TMP2, HI(RA) - | ins_next2 - break; - case BC_KCDATA: - |.if FFI - | // RA = dst*8, RD = cdata_const*8 (~) - | srl TMP1, RD, 1 - | subu TMP1, KBASE, TMP1 - | ins_next1 - | lw TMP0, -4(TMP1) // KBASE-4-cdata_const*4 - | addu RA, BASE, RA - | li TMP2, LJ_TCDATA - | sw TMP0, LO(RA) - | sw TMP2, HI(RA) - | ins_next2 - |.endif - break; - case BC_KSHORT: - | // RA = dst*8, RD = int16_literal*8 - | sra RD, INS, 16 - | addu RA, BASE, RA - | ins_next1 - | sw TISNUM, HI(RA) - | sw RD, LO(RA) - | ins_next2 - break; - case BC_KNUM: - | // RA = dst*8, RD = num_const*8 - | addu RD, KBASE, RD - | addu RA, BASE, RA - | lw SFRETHI, HI(RD) - | lw SFRETLO, LO(RD) - | ins_next1 - | sw SFRETHI, HI(RA) - | sw SFRETLO, LO(RA) - | ins_next2 - break; - case BC_KPRI: - | // RA = dst*8, RD = primitive_type*8 (~) - | srl TMP1, RD, 3 - | addu RA, BASE, RA - | not TMP0, TMP1 - | ins_next1 - | sw TMP0, HI(RA) - | ins_next2 - break; - case BC_KNIL: - | // RA = base*8, RD = end*8 - | addu RA, BASE, RA - | sw TISNIL, HI(RA) - | addiu RA, RA, 8 - | addu RD, BASE, RD - |1: - | sw TISNIL, HI(RA) - | slt AT, RA, RD - | bnez AT, <1 - |. addiu RA, RA, 8 - | ins_next_ - break; - - /* -- Upvalue and function ops ------------------------------------------ */ - - case BC_UGET: - | // RA = dst*8, RD = uvnum*8 - | lw LFUNC:RB, FRAME_FUNC(BASE) - | srl RD, RD, 1 - | addu RD, RD, LFUNC:RB - | lw UPVAL:RB, LFUNC:RD->uvptr - | ins_next1 - | lw TMP1, UPVAL:RB->v - | lw SFRETHI, HI(TMP1) - | lw SFRETLO, LO(TMP1) - | addu RA, BASE, RA - | sw SFRETHI, HI(RA) - | sw SFRETLO, LO(RA) - | ins_next2 - break; - case BC_USETV: - | // RA = uvnum*8, RD = src*8 - | lw LFUNC:RB, FRAME_FUNC(BASE) - | srl RA, RA, 1 - | addu RD, BASE, RD - | addu RA, RA, LFUNC:RB - | lw UPVAL:RB, LFUNC:RA->uvptr - | lw SFRETHI, HI(RD) - | lw SFRETLO, LO(RD) - | lbu TMP3, UPVAL:RB->marked - | lw CARG2, UPVAL:RB->v - | andi TMP3, TMP3, LJ_GC_BLACK // isblack(uv) - | lbu TMP0, UPVAL:RB->closed - | sw SFRETHI, HI(CARG2) - | sw SFRETLO, LO(CARG2) - | li AT, LJ_GC_BLACK|1 - | or TMP3, TMP3, TMP0 - | beq TMP3, AT, >2 // Upvalue is closed and black? - |. addiu TMP2, SFRETHI, -(LJ_TNUMX+1) - |1: - | ins_next - | - |2: // Check if new value is collectable. - | sltiu AT, TMP2, LJ_TISGCV - (LJ_TNUMX+1) - | beqz AT, <1 // tvisgcv(v) - |. nop - | lbu TMP3, GCOBJ:SFRETLO->gch.marked - | andi TMP3, TMP3, LJ_GC_WHITES // iswhite(v) - | beqz TMP3, <1 - |. load_got lj_gc_barrieruv - | // Crossed a write barrier. Move the barrier forward. - | call_intern lj_gc_barrieruv // (global_State *g, TValue *tv) - |. addiu CARG1, DISPATCH, GG_DISP2G - | b <1 - |. nop - break; - case BC_USETS: - | // RA = uvnum*8, RD = str_const*8 (~) - | lw LFUNC:RB, FRAME_FUNC(BASE) - | srl RA, RA, 1 - | srl TMP1, RD, 1 - | addu RA, RA, LFUNC:RB - | subu TMP1, KBASE, TMP1 - | lw UPVAL:RB, LFUNC:RA->uvptr - | lw STR:TMP1, -4(TMP1) // KBASE-4-str_const*4 - | lbu TMP2, UPVAL:RB->marked - | lw CARG2, UPVAL:RB->v - | lbu TMP3, STR:TMP1->marked - | andi AT, TMP2, LJ_GC_BLACK // isblack(uv) - | lbu TMP2, UPVAL:RB->closed - | li TMP0, LJ_TSTR - | sw STR:TMP1, LO(CARG2) - | bnez AT, >2 - |. sw TMP0, HI(CARG2) - |1: - | ins_next - | - |2: // Check if string is white and ensure upvalue is closed. - | beqz TMP2, <1 - |. andi AT, TMP3, LJ_GC_WHITES // iswhite(str) - | beqz AT, <1 - |. load_got lj_gc_barrieruv - | // Crossed a write barrier. Move the barrier forward. - | call_intern lj_gc_barrieruv // (global_State *g, TValue *tv) - |. addiu CARG1, DISPATCH, GG_DISP2G - | b <1 - |. nop - break; - case BC_USETN: - | // RA = uvnum*8, RD = num_const*8 - | lw LFUNC:RB, FRAME_FUNC(BASE) - | srl RA, RA, 1 - | addu RD, KBASE, RD - | addu RA, RA, LFUNC:RB - | lw UPVAL:RB, LFUNC:RA->uvptr - | lw SFRETHI, HI(RD) - | lw SFRETLO, LO(RD) - | lw TMP1, UPVAL:RB->v - | ins_next1 - | sw SFRETHI, HI(TMP1) - | sw SFRETLO, LO(TMP1) - | ins_next2 - break; - case BC_USETP: - | // RA = uvnum*8, RD = primitive_type*8 (~) - | lw LFUNC:RB, FRAME_FUNC(BASE) - | srl RA, RA, 1 - | srl TMP0, RD, 3 - | addu RA, RA, LFUNC:RB - | not TMP0, TMP0 - | lw UPVAL:RB, LFUNC:RA->uvptr - | ins_next1 - | lw TMP1, UPVAL:RB->v - | sw TMP0, HI(TMP1) - | ins_next2 - break; - - case BC_UCLO: - | // RA = level*8, RD = target - | lw TMP2, L->openupval - | branch_RD // Do this first since RD is not saved. - | load_got lj_func_closeuv - | sw BASE, L->base - | beqz TMP2, >1 - |. move CARG1, L - | call_intern lj_func_closeuv // (lua_State *L, TValue *level) - |. addu CARG2, BASE, RA - | lw BASE, L->base - |1: - | ins_next - break; - - case BC_FNEW: - | // RA = dst*8, RD = proto_const*8 (~) (holding function prototype) - | srl TMP1, RD, 1 - | load_got lj_func_newL_gc - | subu TMP1, KBASE, TMP1 - | lw CARG3, FRAME_FUNC(BASE) - | lw CARG2, -4(TMP1) // KBASE-4-tab_const*4 - | sw BASE, L->base - | sw PC, SAVE_PC - | // (lua_State *L, GCproto *pt, GCfuncL *parent) - | call_intern lj_func_newL_gc - |. move CARG1, L - | // Returns GCfuncL *. - | lw BASE, L->base - | li TMP0, LJ_TFUNC - | ins_next1 - | addu RA, BASE, RA - | sw LFUNC:CRET1, LO(RA) - | sw TMP0, HI(RA) - | ins_next2 - break; - - /* -- Table ops --------------------------------------------------------- */ - - case BC_TNEW: - case BC_TDUP: - | // RA = dst*8, RD = (hbits|asize)*8 | tab_const*8 (~) - | lw TMP0, DISPATCH_GL(gc.total)(DISPATCH) - | lw TMP1, DISPATCH_GL(gc.threshold)(DISPATCH) - | sw BASE, L->base - | sw PC, SAVE_PC - | sltu AT, TMP0, TMP1 - | beqz AT, >5 - |1: - if (op == BC_TNEW) { - | load_got lj_tab_new - | srl CARG2, RD, 3 - | andi CARG2, CARG2, 0x7ff - | li TMP0, 0x801 - | addiu AT, CARG2, -0x7ff - | srl CARG3, RD, 14 - | movz CARG2, TMP0, AT - | // (lua_State *L, int32_t asize, uint32_t hbits) - | call_intern lj_tab_new - |. move CARG1, L - | // Returns Table *. - } else { - | load_got lj_tab_dup - | srl TMP1, RD, 1 - | subu TMP1, KBASE, TMP1 - | move CARG1, L - | call_intern lj_tab_dup // (lua_State *L, Table *kt) - |. lw CARG2, -4(TMP1) // KBASE-4-str_const*4 - | // Returns Table *. - } - | lw BASE, L->base - | ins_next1 - | addu RA, BASE, RA - | li TMP0, LJ_TTAB - | sw TAB:CRET1, LO(RA) - | sw TMP0, HI(RA) - | ins_next2 - |5: - | load_got lj_gc_step_fixtop - | move MULTRES, RD - | call_intern lj_gc_step_fixtop // (lua_State *L) - |. move CARG1, L - | b <1 - |. move RD, MULTRES - break; - - case BC_GGET: - | // RA = dst*8, RD = str_const*8 (~) - case BC_GSET: - | // RA = src*8, RD = str_const*8 (~) - | lw LFUNC:TMP2, FRAME_FUNC(BASE) - | srl TMP1, RD, 1 - | subu TMP1, KBASE, TMP1 - | lw TAB:RB, LFUNC:TMP2->env - | lw STR:RC, -4(TMP1) // KBASE-4-str_const*4 - if (op == BC_GGET) { - | b ->BC_TGETS_Z - } else { - | b ->BC_TSETS_Z - } - |. addu RA, BASE, RA - break; - - case BC_TGETV: - | // RA = dst*8, RB = table*8, RC = key*8 - | decode_RB8a RB, INS - | decode_RB8b RB - | decode_RDtoRC8 RC, RD - | addu CARG2, BASE, RB - | addu CARG3, BASE, RC - | lw TMP1, HI(CARG2) - | lw TMP2, HI(CARG3) - | lw TAB:RB, LO(CARG2) - | li AT, LJ_TTAB - | bne TMP1, AT, ->vmeta_tgetv - |. addu RA, BASE, RA - | bne TMP2, TISNUM, >5 - |. lw RC, LO(CARG3) - | lw TMP0, TAB:RB->asize - | lw TMP1, TAB:RB->array - | sltu AT, RC, TMP0 - | sll TMP2, RC, 3 - | beqz AT, ->vmeta_tgetv // Integer key and in array part? - |. addu TMP2, TMP1, TMP2 - | lw SFRETHI, HI(TMP2) - | beq SFRETHI, TISNIL, >2 - |. lw SFRETLO, LO(TMP2) - |1: - | ins_next1 - | sw SFRETHI, HI(RA) - | sw SFRETLO, LO(RA) - | ins_next2 - | - |2: // Check for __index if table value is nil. - | lw TAB:TMP2, TAB:RB->metatable - | beqz TAB:TMP2, <1 // No metatable: done. - |. nop - | lbu TMP0, TAB:TMP2->nomm - | andi TMP0, TMP0, 1<vmeta_tgetv - |. nop - | - |5: - | li AT, LJ_TSTR - | bne TMP2, AT, ->vmeta_tgetv - |. nop - | b ->BC_TGETS_Z // String key? - |. nop - break; - case BC_TGETS: - | // RA = dst*8, RB = table*8, RC = str_const*4 (~) - | decode_RB8a RB, INS - | decode_RB8b RB - | addu CARG2, BASE, RB - | decode_RC4a RC, INS - | lw TMP0, HI(CARG2) - | decode_RC4b RC - | li AT, LJ_TTAB - | lw TAB:RB, LO(CARG2) - | subu CARG3, KBASE, RC - | lw STR:RC, -4(CARG3) // KBASE-4-str_const*4 - | bne TMP0, AT, ->vmeta_tgets1 - |. addu RA, BASE, RA - |->BC_TGETS_Z: - | // TAB:RB = GCtab *, STR:RC = GCstr *, RA = dst*8 - | lw TMP0, TAB:RB->hmask - | lw TMP1, STR:RC->hash - | lw NODE:TMP2, TAB:RB->node - | and TMP1, TMP1, TMP0 // idx = str->hash & tab->hmask - | sll TMP0, TMP1, 5 - | sll TMP1, TMP1, 3 - | subu TMP1, TMP0, TMP1 - | addu NODE:TMP2, NODE:TMP2, TMP1 // node = tab->node + (idx*32-idx*8) - |1: - | lw CARG1, offsetof(Node, key)+HI(NODE:TMP2) - | lw TMP0, offsetof(Node, key)+LO(NODE:TMP2) - | lw NODE:TMP1, NODE:TMP2->next - | lw SFRETHI, offsetof(Node, val)+HI(NODE:TMP2) - | addiu CARG1, CARG1, -LJ_TSTR - | xor TMP0, TMP0, STR:RC - | or AT, CARG1, TMP0 - | bnez AT, >4 - |. lw TAB:TMP3, TAB:RB->metatable - | beq SFRETHI, TISNIL, >5 // Key found, but nil value? - |. lw SFRETLO, offsetof(Node, val)+LO(NODE:TMP2) - |3: - | ins_next1 - | sw SFRETHI, HI(RA) - | sw SFRETLO, LO(RA) - | ins_next2 - | - |4: // Follow hash chain. - | bnez NODE:TMP1, <1 - |. move NODE:TMP2, NODE:TMP1 - | // End of hash chain: key not found, nil result. - | - |5: // Check for __index if table value is nil. - | beqz TAB:TMP3, <3 // No metatable: done. - |. li SFRETHI, LJ_TNIL - | lbu TMP0, TAB:TMP3->nomm - | andi TMP0, TMP0, 1<vmeta_tgets - |. nop - break; - case BC_TGETB: - | // RA = dst*8, RB = table*8, RC = index*8 - | decode_RB8a RB, INS - | decode_RB8b RB - | addu CARG2, BASE, RB - | decode_RDtoRC8 RC, RD - | lw CARG1, HI(CARG2) - | li AT, LJ_TTAB - | lw TAB:RB, LO(CARG2) - | addu RA, BASE, RA - | bne CARG1, AT, ->vmeta_tgetb - |. srl TMP0, RC, 3 - | lw TMP1, TAB:RB->asize - | lw TMP2, TAB:RB->array - | sltu AT, TMP0, TMP1 - | beqz AT, ->vmeta_tgetb - |. addu RC, TMP2, RC - | lw SFRETHI, HI(RC) - | beq SFRETHI, TISNIL, >5 - |. lw SFRETLO, LO(RC) - |1: - | ins_next1 - | sw SFRETHI, HI(RA) - | sw SFRETLO, LO(RA) - | ins_next2 - | - |5: // Check for __index if table value is nil. - | lw TAB:TMP2, TAB:RB->metatable - | beqz TAB:TMP2, <1 // No metatable: done. - |. nop - | lbu TMP1, TAB:TMP2->nomm - | andi TMP1, TMP1, 1<vmeta_tgetb // Caveat: preserve TMP0 and CARG2! - |. nop - break; - case BC_TGETR: - | // RA = dst*8, RB = table*8, RC = key*8 - | decode_RB8a RB, INS - | decode_RB8b RB - | decode_RDtoRC8 RC, RD - | addu RB, BASE, RB - | addu RC, BASE, RC - | lw TAB:CARG1, LO(RB) - | lw CARG2, LO(RC) - | addu RA, BASE, RA - | lw TMP0, TAB:CARG1->asize - | lw TMP1, TAB:CARG1->array - | sltu AT, CARG2, TMP0 - | sll TMP2, CARG2, 3 - | beqz AT, ->vmeta_tgetr // In array part? - |. addu CRET1, TMP1, TMP2 - | lw SFARG2HI, HI(CRET1) - | lw SFARG2LO, LO(CRET1) - |->BC_TGETR_Z: - | ins_next1 - | sw SFARG2HI, HI(RA) - | sw SFARG2LO, LO(RA) - | ins_next2 - break; - - case BC_TSETV: - | // RA = src*8, RB = table*8, RC = key*8 - | decode_RB8a RB, INS - | decode_RB8b RB - | decode_RDtoRC8 RC, RD - | addu CARG2, BASE, RB - | addu CARG3, BASE, RC - | lw TMP1, HI(CARG2) - | lw TMP2, HI(CARG3) - | lw TAB:RB, LO(CARG2) - | li AT, LJ_TTAB - | bne TMP1, AT, ->vmeta_tsetv - |. addu RA, BASE, RA - | bne TMP2, TISNUM, >5 - |. lw RC, LO(CARG3) - | lw TMP0, TAB:RB->asize - | lw TMP1, TAB:RB->array - | sltu AT, RC, TMP0 - | sll TMP2, RC, 3 - | beqz AT, ->vmeta_tsetv // Integer key and in array part? - |. addu TMP1, TMP1, TMP2 - | lw TMP0, HI(TMP1) - | lbu TMP3, TAB:RB->marked - | lw SFRETHI, HI(RA) - | beq TMP0, TISNIL, >3 - |. lw SFRETLO, LO(RA) - |1: - | andi AT, TMP3, LJ_GC_BLACK // isblack(table) - | sw SFRETHI, HI(TMP1) - | bnez AT, >7 - |. sw SFRETLO, LO(TMP1) - |2: - | ins_next - | - |3: // Check for __newindex if previous value is nil. - | lw TAB:TMP2, TAB:RB->metatable - | beqz TAB:TMP2, <1 // No metatable: done. - |. nop - | lbu TMP2, TAB:TMP2->nomm - | andi TMP2, TMP2, 1<vmeta_tsetv - |. nop - | - |5: - | li AT, LJ_TSTR - | bne TMP2, AT, ->vmeta_tsetv - |. nop - | b ->BC_TSETS_Z // String key? - |. nop - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:RB, TMP3, TMP0, <2 - break; - case BC_TSETS: - | // RA = src*8, RB = table*8, RC = str_const*8 (~) - | decode_RB8a RB, INS - | decode_RB8b RB - | addu CARG2, BASE, RB - | decode_RC4a RC, INS - | lw TMP0, HI(CARG2) - | decode_RC4b RC - | li AT, LJ_TTAB - | subu CARG3, KBASE, RC - | lw TAB:RB, LO(CARG2) - | lw STR:RC, -4(CARG3) // KBASE-4-str_const*4 - | bne TMP0, AT, ->vmeta_tsets1 - |. addu RA, BASE, RA - |->BC_TSETS_Z: - | // TAB:RB = GCtab *, STR:RC = GCstr *, RA = BASE+src*8 - | lw TMP0, TAB:RB->hmask - | lw TMP1, STR:RC->hash - | lw NODE:TMP2, TAB:RB->node - | sb r0, TAB:RB->nomm // Clear metamethod cache. - | and TMP1, TMP1, TMP0 // idx = str->hash & tab->hmask - | sll TMP0, TMP1, 5 - | sll TMP1, TMP1, 3 - | subu TMP1, TMP0, TMP1 - | addu NODE:TMP2, NODE:TMP2, TMP1 // node = tab->node + (idx*32-idx*8) - |.if FPU - | ldc1 f20, 0(RA) - |.else - | lw SFRETHI, HI(RA) - | lw SFRETLO, LO(RA) - |.endif - |1: - | lw CARG1, offsetof(Node, key)+HI(NODE:TMP2) - | lw TMP0, offsetof(Node, key)+LO(NODE:TMP2) - | li AT, LJ_TSTR - | lw NODE:TMP1, NODE:TMP2->next - | bne CARG1, AT, >5 - |. lw CARG2, offsetof(Node, val)+HI(NODE:TMP2) - | bne TMP0, STR:RC, >5 - |. lbu TMP3, TAB:RB->marked - | beq CARG2, TISNIL, >4 // Key found, but nil value? - |. lw TAB:TMP0, TAB:RB->metatable - |2: - | andi AT, TMP3, LJ_GC_BLACK // isblack(table) - |.if FPU - | bnez AT, >7 - |. sdc1 f20, NODE:TMP2->val - |.else - | sw SFRETHI, NODE:TMP2->val.u32.hi - | bnez AT, >7 - |. sw SFRETLO, NODE:TMP2->val.u32.lo - |.endif - |3: - | ins_next - | - |4: // Check for __newindex if previous value is nil. - | beqz TAB:TMP0, <2 // No metatable: done. - |. nop - | lbu TMP0, TAB:TMP0->nomm - | andi TMP0, TMP0, 1<vmeta_tsets - |. nop - | - |5: // Follow hash chain. - | bnez NODE:TMP1, <1 - |. move NODE:TMP2, NODE:TMP1 - | // End of hash chain: key not found, add a new one - | - | // But check for __newindex first. - | lw TAB:TMP2, TAB:RB->metatable - | beqz TAB:TMP2, >6 // No metatable: continue. - |. addiu CARG3, DISPATCH, DISPATCH_GL(tmptv) - | lbu TMP0, TAB:TMP2->nomm - | andi TMP0, TMP0, 1<vmeta_tsets // 'no __newindex' flag NOT set: check. - |. li AT, LJ_TSTR - |6: - | load_got lj_tab_newkey - | sw STR:RC, LO(CARG3) - | sw AT, HI(CARG3) - | sw BASE, L->base - | move CARG2, TAB:RB - | sw PC, SAVE_PC - | call_intern lj_tab_newkey // (lua_State *L, GCtab *t, TValue *k - |. move CARG1, L - | // Returns TValue *. - | lw BASE, L->base - |.if FPU - | b <3 // No 2nd write barrier needed. - |. sdc1 f20, 0(CRET1) - |.else - | lw SFARG1HI, HI(RA) - | lw SFARG1LO, LO(RA) - | sw SFARG1HI, HI(CRET1) - | b <3 // No 2nd write barrier needed. - |. sw SFARG1LO, LO(CRET1) - |.endif - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:RB, TMP3, TMP0, <3 - break; - case BC_TSETB: - | // RA = src*8, RB = table*8, RC = index*8 - | decode_RB8a RB, INS - | decode_RB8b RB - | addu CARG2, BASE, RB - | decode_RDtoRC8 RC, RD - | lw CARG1, HI(CARG2) - | li AT, LJ_TTAB - | lw TAB:RB, LO(CARG2) - | addu RA, BASE, RA - | bne CARG1, AT, ->vmeta_tsetb - |. srl TMP0, RC, 3 - | lw TMP1, TAB:RB->asize - | lw TMP2, TAB:RB->array - | sltu AT, TMP0, TMP1 - | beqz AT, ->vmeta_tsetb - |. addu RC, TMP2, RC - | lw TMP1, HI(RC) - | lbu TMP3, TAB:RB->marked - | beq TMP1, TISNIL, >5 - |1: - |. lw SFRETHI, HI(RA) - | lw SFRETLO, LO(RA) - | andi AT, TMP3, LJ_GC_BLACK // isblack(table) - | sw SFRETHI, HI(RC) - | bnez AT, >7 - |. sw SFRETLO, LO(RC) - |2: - | ins_next - | - |5: // Check for __newindex if previous value is nil. - | lw TAB:TMP2, TAB:RB->metatable - | beqz TAB:TMP2, <1 // No metatable: done. - |. nop - | lbu TMP1, TAB:TMP2->nomm - | andi TMP1, TMP1, 1<vmeta_tsetb // Caveat: preserve TMP0 and CARG2! - |. nop - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:RB, TMP3, TMP0, <2 - break; - case BC_TSETR: - | // RA = dst*8, RB = table*8, RC = key*8 - | decode_RB8a RB, INS - | decode_RB8b RB - | decode_RDtoRC8 RC, RD - | addu CARG1, BASE, RB - | addu CARG3, BASE, RC - | lw TAB:CARG2, LO(CARG1) - | lw CARG3, LO(CARG3) - | lbu TMP3, TAB:CARG2->marked - | lw TMP0, TAB:CARG2->asize - | lw TMP1, TAB:CARG2->array - | andi AT, TMP3, LJ_GC_BLACK // isblack(table) - | bnez AT, >7 - |. addu RA, BASE, RA - |2: - | sltu AT, CARG3, TMP0 - | sll TMP2, CARG3, 3 - | beqz AT, ->vmeta_tsetr // In array part? - |. addu CRET1, TMP1, TMP2 - |->BC_TSETR_Z: - | lw SFARG1HI, HI(RA) - | lw SFARG1LO, LO(RA) - | ins_next1 - | sw SFARG1HI, HI(CRET1) - | sw SFARG1LO, LO(CRET1) - | ins_next2 - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:CARG2, TMP3, CRET1, <2 - break; - - case BC_TSETM: - | // RA = base*8 (table at base-1), RD = num_const*8 (start index) - | addu RA, BASE, RA - |1: - | addu TMP3, KBASE, RD - | lw TAB:CARG2, -8+LO(RA) // Guaranteed to be a table. - | addiu TMP0, MULTRES, -8 - | lw TMP3, LO(TMP3) // Integer constant is in lo-word. - | beqz TMP0, >4 // Nothing to copy? - |. srl CARG3, TMP0, 3 - | addu CARG3, CARG3, TMP3 - | lw TMP2, TAB:CARG2->asize - | sll TMP1, TMP3, 3 - | lbu TMP3, TAB:CARG2->marked - | lw CARG1, TAB:CARG2->array - | sltu AT, TMP2, CARG3 - | bnez AT, >5 - |. addu TMP2, RA, TMP0 - | addu TMP1, TMP1, CARG1 - | andi TMP0, TMP3, LJ_GC_BLACK // isblack(table) - |3: // Copy result slots to table. - | lw SFRETHI, HI(RA) - | lw SFRETLO, LO(RA) - | addiu RA, RA, 8 - | sltu AT, RA, TMP2 - | sw SFRETHI, HI(TMP1) - | sw SFRETLO, LO(TMP1) - | bnez AT, <3 - |. addiu TMP1, TMP1, 8 - | bnez TMP0, >7 - |. nop - |4: - | ins_next - | - |5: // Need to resize array part. - | load_got lj_tab_reasize - | sw BASE, L->base - | sw PC, SAVE_PC - | move BASE, RD - | call_intern lj_tab_reasize // (lua_State *L, GCtab *t, int nasize) - |. move CARG1, L - | // Must not reallocate the stack. - | move RD, BASE - | b <1 - |. lw BASE, L->base // Reload BASE for lack of a saved register. - | - |7: // Possible table write barrier for any value. Skip valiswhite check. - | barrierback TAB:CARG2, TMP3, TMP0, <4 - break; - - /* -- Calls and vararg handling ----------------------------------------- */ - - case BC_CALLM: - | // RA = base*8, (RB = (nresults+1)*8,) RC = extra_nargs*8 - | decode_RDtoRC8 NARGS8:RC, RD - | b ->BC_CALL_Z - |. addu NARGS8:RC, NARGS8:RC, MULTRES - break; - case BC_CALL: - | // RA = base*8, (RB = (nresults+1)*8,) RC = (nargs+1)*8 - | decode_RDtoRC8 NARGS8:RC, RD - |->BC_CALL_Z: - | move TMP2, BASE - | addu BASE, BASE, RA - | li AT, LJ_TFUNC - | lw TMP0, HI(BASE) - | lw LFUNC:RB, LO(BASE) - | addiu BASE, BASE, 8 - | bne TMP0, AT, ->vmeta_call - |. addiu NARGS8:RC, NARGS8:RC, -8 - | ins_call - break; - - case BC_CALLMT: - | // RA = base*8, (RB = 0,) RC = extra_nargs*8 - | addu NARGS8:RD, NARGS8:RD, MULTRES // BC_CALLT gets RC from RD. - | // Fall through. Assumes BC_CALLT follows. - break; - case BC_CALLT: - | // RA = base*8, (RB = 0,) RC = (nargs+1)*8 - | addu RA, BASE, RA - | li AT, LJ_TFUNC - | lw TMP0, HI(RA) - | lw LFUNC:RB, LO(RA) - | move NARGS8:RC, RD - | lw TMP1, FRAME_PC(BASE) - | addiu RA, RA, 8 - | bne TMP0, AT, ->vmeta_callt - |. addiu NARGS8:RC, NARGS8:RC, -8 - |->BC_CALLT_Z: - | andi TMP0, TMP1, FRAME_TYPE // Caveat: preserve TMP0 until the 'or'. - | lbu TMP3, LFUNC:RB->ffid - | bnez TMP0, >7 - |. xori TMP2, TMP1, FRAME_VARG - |1: - | sw LFUNC:RB, FRAME_FUNC(BASE) // Copy function down, but keep PC. - | sltiu AT, TMP3, 2 // (> FF_C) Calling a fast function? - | move TMP2, BASE - | beqz NARGS8:RC, >3 - |. move TMP3, NARGS8:RC - |2: - | lw SFRETHI, HI(RA) - | lw SFRETLO, LO(RA) - | addiu RA, RA, 8 - | addiu TMP3, TMP3, -8 - | sw SFRETHI, HI(TMP2) - | sw SFRETLO, LO(TMP2) - | bnez TMP3, <2 - |. addiu TMP2, TMP2, 8 - |3: - | or TMP0, TMP0, AT - | beqz TMP0, >5 - |. nop - |4: - | ins_callt - | - |5: // Tailcall to a fast function with a Lua frame below. - | lw INS, -4(TMP1) - | decode_RA8a RA, INS - | decode_RA8b RA - | subu TMP1, BASE, RA - | lw LFUNC:TMP1, -8+FRAME_FUNC(TMP1) - | lw TMP1, LFUNC:TMP1->pc - | b <4 - |. lw KBASE, PC2PROTO(k)(TMP1) // Need to prepare KBASE. - | - |7: // Tailcall from a vararg function. - | andi AT, TMP2, FRAME_TYPEP - | bnez AT, <1 // Vararg frame below? - |. subu TMP2, BASE, TMP2 // Relocate BASE down. - | move BASE, TMP2 - | lw TMP1, FRAME_PC(TMP2) - | b <1 - |. andi TMP0, TMP1, FRAME_TYPE - break; - - case BC_ITERC: - | // RA = base*8, (RB = (nresults+1)*8, RC = (nargs+1)*8 ((2+1)*8)) - | move TMP2, BASE - | addu BASE, BASE, RA - | li AT, LJ_TFUNC - | lw TMP1, -24+HI(BASE) - | lw LFUNC:RB, -24+LO(BASE) - | lw SFARG1HI, -16+HI(BASE) - | lw SFARG1LO, -16+LO(BASE) - | lw SFARG2HI, -8+HI(BASE) - | lw SFARG2LO, -8+LO(BASE) - | sw TMP1, HI(BASE) // Copy callable. - | sw LFUNC:RB, LO(BASE) - | sw SFARG1HI, 8+HI(BASE) // Copy state. - | sw SFARG1LO, 8+LO(BASE) - | sw SFARG2HI, 16+HI(BASE) // Copy control var. - | sw SFARG2LO, 16+LO(BASE) - | addiu BASE, BASE, 8 - | bne TMP1, AT, ->vmeta_call - |. li NARGS8:RC, 16 // Iterators get 2 arguments. - | ins_call - break; - - case BC_ITERN: - | // RA = base*8, (RB = (nresults+1)*8, RC = (nargs+1)*8 (2+1)*8) - |.if JIT - | // NYI: add hotloop, record BC_ITERN. - |.endif - | addu RA, BASE, RA - | lw TAB:RB, -16+LO(RA) - | lw RC, -8+LO(RA) // Get index from control var. - | lw TMP0, TAB:RB->asize - | lw TMP1, TAB:RB->array - | addiu PC, PC, 4 - |1: // Traverse array part. - | sltu AT, RC, TMP0 - | beqz AT, >5 // Index points after array part? - |. sll TMP3, RC, 3 - | addu TMP3, TMP1, TMP3 - | lw SFARG1HI, HI(TMP3) - | lw SFARG1LO, LO(TMP3) - | lhu RD, -4+OFS_RD(PC) - | sw TISNUM, HI(RA) - | sw RC, LO(RA) - | beq SFARG1HI, TISNIL, <1 // Skip holes in array part. - |. addiu RC, RC, 1 - | sw SFARG1HI, 8+HI(RA) - | sw SFARG1LO, 8+LO(RA) - | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) - | decode_RD4b RD - | addu RD, RD, TMP3 - | sw RC, -8+LO(RA) // Update control var. - | addu PC, PC, RD - |3: - | ins_next - | - |5: // Traverse hash part. - | lw TMP1, TAB:RB->hmask - | subu RC, RC, TMP0 - | lw TMP2, TAB:RB->node - |6: - | sltu AT, TMP1, RC // End of iteration? Branch to ITERL+1. - | bnez AT, <3 - |. sll TMP3, RC, 5 - | sll RB, RC, 3 - | subu TMP3, TMP3, RB - | addu NODE:TMP3, TMP3, TMP2 - | lw SFARG1HI, NODE:TMP3->val.u32.hi - | lw SFARG1LO, NODE:TMP3->val.u32.lo - | lhu RD, -4+OFS_RD(PC) - | beq SFARG1HI, TISNIL, <6 // Skip holes in hash part. - |. addiu RC, RC, 1 - | lw SFARG2HI, NODE:TMP3->key.u32.hi - | lw SFARG2LO, NODE:TMP3->key.u32.lo - | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) - | sw SFARG1HI, 8+HI(RA) - | sw SFARG1LO, 8+LO(RA) - | addu RC, RC, TMP0 - | decode_RD4b RD - | addu RD, RD, TMP3 - | sw SFARG2HI, HI(RA) - | sw SFARG2LO, LO(RA) - | addu PC, PC, RD - | b <3 - |. sw RC, -8+LO(RA) // Update control var. - break; - - case BC_ISNEXT: - | // RA = base*8, RD = target (points to ITERN) - | addu RA, BASE, RA - | srl TMP0, RD, 1 - | lw CARG1, -24+HI(RA) - | lw CFUNC:CARG2, -24+LO(RA) - | addu TMP0, PC, TMP0 - | lw CARG3, -16+HI(RA) - | lw CARG4, -8+HI(RA) - | li AT, LJ_TFUNC - | bne CARG1, AT, >5 - |. lui TMP2, (-(BCBIAS_J*4 >> 16) & 65535) - | lbu CARG2, CFUNC:CARG2->ffid - | addiu CARG3, CARG3, -LJ_TTAB - | addiu CARG4, CARG4, -LJ_TNIL - | or CARG3, CARG3, CARG4 - | addiu CARG2, CARG2, -FF_next_N - | or CARG2, CARG2, CARG3 - | bnez CARG2, >5 - |. lui TMP1, 0xfffe - | addu PC, TMP0, TMP2 - | ori TMP1, TMP1, 0x7fff - | sw r0, -8+LO(RA) // Initialize control var. - | sw TMP1, -8+HI(RA) - |1: - | ins_next - |5: // Despecialize bytecode if any of the checks fail. - | li TMP3, BC_JMP - | li TMP1, BC_ITERC - | sb TMP3, -4+OFS_OP(PC) - | addu PC, TMP0, TMP2 - | b <1 - |. sb TMP1, OFS_OP(PC) - break; - - case BC_VARG: - | // RA = base*8, RB = (nresults+1)*8, RC = numparams*8 - | lw TMP0, FRAME_PC(BASE) - | decode_RDtoRC8 RC, RD - | decode_RB8a RB, INS - | addu RC, BASE, RC - | decode_RB8b RB - | addu RA, BASE, RA - | addiu RC, RC, FRAME_VARG - | addu TMP2, RA, RB - | addiu TMP3, BASE, -8 // TMP3 = vtop - | subu RC, RC, TMP0 // RC = vbase - | // Note: RC may now be even _above_ BASE if nargs was < numparams. - | beqz RB, >5 // Copy all varargs? - |. subu TMP1, TMP3, RC - | addiu TMP2, TMP2, -16 - |1: // Copy vararg slots to destination slots. - | lw CARG1, HI(RC) - | sltu AT, RC, TMP3 - | lw CARG2, LO(RC) - | addiu RC, RC, 8 - | movz CARG1, TISNIL, AT - | sw CARG1, HI(RA) - | sw CARG2, LO(RA) - | sltu AT, RA, TMP2 - | bnez AT, <1 - |. addiu RA, RA, 8 - |3: - | ins_next - | - |5: // Copy all varargs. - | lw TMP0, L->maxstack - | blez TMP1, <3 // No vararg slots? - |. li MULTRES, 8 // MULTRES = (0+1)*8 - | addu TMP2, RA, TMP1 - | sltu AT, TMP0, TMP2 - | bnez AT, >7 - |. addiu MULTRES, TMP1, 8 - |6: - | lw SFRETHI, HI(RC) - | lw SFRETLO, LO(RC) - | addiu RC, RC, 8 - | sw SFRETHI, HI(RA) - | sw SFRETLO, LO(RA) - | sltu AT, RC, TMP3 - | bnez AT, <6 // More vararg slots? - |. addiu RA, RA, 8 - | b <3 - |. nop - | - |7: // Grow stack for varargs. - | load_got lj_state_growstack - | sw RA, L->top - | subu RA, RA, BASE - | sw BASE, L->base - | subu BASE, RC, BASE // Need delta, because BASE may change. - | sw PC, SAVE_PC - | srl CARG2, TMP1, 3 - | call_intern lj_state_growstack // (lua_State *L, int n) - |. move CARG1, L - | move RC, BASE - | lw BASE, L->base - | addu RA, BASE, RA - | addu RC, BASE, RC - | b <6 - |. addiu TMP3, BASE, -8 - break; - - /* -- Returns ----------------------------------------------------------- */ - - case BC_RETM: - | // RA = results*8, RD = extra_nresults*8 - | addu RD, RD, MULTRES // MULTRES >= 8, so RD >= 8. - | // Fall through. Assumes BC_RET follows. - break; - - case BC_RET: - | // RA = results*8, RD = (nresults+1)*8 - | lw PC, FRAME_PC(BASE) - | addu RA, BASE, RA - | move MULTRES, RD - |1: - | andi TMP0, PC, FRAME_TYPE - | bnez TMP0, ->BC_RETV_Z - |. xori TMP1, PC, FRAME_VARG - | - |->BC_RET_Z: - | // BASE = base, RA = resultptr, RD = (nresults+1)*8, PC = return - | lw INS, -4(PC) - | addiu TMP2, BASE, -8 - | addiu RC, RD, -8 - | decode_RA8a TMP0, INS - | decode_RB8a RB, INS - | decode_RA8b TMP0 - | decode_RB8b RB - | addu TMP3, TMP2, RB - | beqz RC, >3 - |. subu BASE, TMP2, TMP0 - |2: - | lw SFRETHI, HI(RA) - | lw SFRETLO, LO(RA) - | addiu RA, RA, 8 - | addiu RC, RC, -8 - | sw SFRETHI, HI(TMP2) - | sw SFRETLO, LO(TMP2) - | bnez RC, <2 - |. addiu TMP2, TMP2, 8 - |3: - | addiu TMP3, TMP3, -8 - |5: - | sltu AT, TMP2, TMP3 - | bnez AT, >6 - |. lw LFUNC:TMP1, FRAME_FUNC(BASE) - | ins_next1 - | lw TMP1, LFUNC:TMP1->pc - | lw KBASE, PC2PROTO(k)(TMP1) - | ins_next2 - | - |6: // Fill up results with nil. - | sw TISNIL, HI(TMP2) - | b <5 - |. addiu TMP2, TMP2, 8 - | - |->BC_RETV_Z: // Non-standard return case. - | andi TMP2, TMP1, FRAME_TYPEP - | bnez TMP2, ->vm_return - |. nop - | // Return from vararg function: relocate BASE down. - | subu BASE, BASE, TMP1 - | b <1 - |. lw PC, FRAME_PC(BASE) - break; - - case BC_RET0: case BC_RET1: - | // RA = results*8, RD = (nresults+1)*8 - | lw PC, FRAME_PC(BASE) - | addu RA, BASE, RA - | move MULTRES, RD - | andi TMP0, PC, FRAME_TYPE - | bnez TMP0, ->BC_RETV_Z - |. xori TMP1, PC, FRAME_VARG - | - | lw INS, -4(PC) - | addiu TMP2, BASE, -8 - if (op == BC_RET1) { - | lw SFRETHI, HI(RA) - | lw SFRETLO, LO(RA) - } - | decode_RB8a RB, INS - | decode_RA8a RA, INS - | decode_RB8b RB - | decode_RA8b RA - if (op == BC_RET1) { - | sw SFRETHI, HI(TMP2) - | sw SFRETLO, LO(TMP2) - } - | subu BASE, TMP2, RA - |5: - | sltu AT, RD, RB - | bnez AT, >6 - |. lw LFUNC:TMP1, FRAME_FUNC(BASE) - | ins_next1 - | lw TMP1, LFUNC:TMP1->pc - | lw KBASE, PC2PROTO(k)(TMP1) - | ins_next2 - | - |6: // Fill up results with nil. - | addiu TMP2, TMP2, 8 - | addiu RD, RD, 8 - | b <5 - if (op == BC_RET1) { - |. sw TISNIL, HI(TMP2) - } else { - |. sw TISNIL, -8+HI(TMP2) - } - break; - - /* -- Loops and branches ------------------------------------------------ */ - - case BC_FORL: - |.if JIT - | hotloop - |.endif - | // Fall through. Assumes BC_IFORL follows. - break; - - case BC_JFORI: - case BC_JFORL: -#if !LJ_HASJIT - break; -#endif - case BC_FORI: - case BC_IFORL: - | // RA = base*8, RD = target (after end of loop or start of loop) - vk = (op == BC_IFORL || op == BC_JFORL); - | addu RA, BASE, RA - | lw SFARG1HI, FORL_IDX*8+HI(RA) - | lw SFARG1LO, FORL_IDX*8+LO(RA) - if (op != BC_JFORL) { - | srl RD, RD, 1 - | lui TMP2, (-(BCBIAS_J*4 >> 16) & 65535) - | addu TMP2, RD, TMP2 - } - if (!vk) { - | lw SFARG2HI, FORL_STOP*8+HI(RA) - | lw SFARG2LO, FORL_STOP*8+LO(RA) - | bne SFARG1HI, TISNUM, >5 - |. lw SFRETHI, FORL_STEP*8+HI(RA) - | xor AT, SFARG2HI, TISNUM - | lw SFRETLO, FORL_STEP*8+LO(RA) - | xor TMP0, SFRETHI, TISNUM - | or AT, AT, TMP0 - | bnez AT, ->vmeta_for - |. slt AT, SFRETLO, r0 - | slt CRET1, SFARG2LO, SFARG1LO - | slt TMP1, SFARG1LO, SFARG2LO - | movn CRET1, TMP1, AT - } else { - | bne SFARG1HI, TISNUM, >5 - |. lw SFARG2LO, FORL_STEP*8+LO(RA) - | lw SFRETLO, FORL_STOP*8+LO(RA) - | move TMP3, SFARG1LO - | addu SFARG1LO, SFARG1LO, SFARG2LO - | xor TMP0, SFARG1LO, TMP3 - | xor TMP1, SFARG1LO, SFARG2LO - | and TMP0, TMP0, TMP1 - | slt TMP1, SFARG1LO, SFRETLO - | slt CRET1, SFRETLO, SFARG1LO - | slt AT, SFARG2LO, r0 - | slt TMP0, TMP0, r0 // ((y^a) & (y^b)) < 0: overflow. - | movn CRET1, TMP1, AT - | or CRET1, CRET1, TMP0 - } - |1: - if (op == BC_FORI) { - | movz TMP2, r0, CRET1 - | addu PC, PC, TMP2 - } else if (op == BC_JFORI) { - | addu PC, PC, TMP2 - | lhu RD, -4+OFS_RD(PC) - } else if (op == BC_IFORL) { - | movn TMP2, r0, CRET1 - | addu PC, PC, TMP2 - } - if (vk) { - | sw SFARG1HI, FORL_IDX*8+HI(RA) - | sw SFARG1LO, FORL_IDX*8+LO(RA) - } - | ins_next1 - | sw SFARG1HI, FORL_EXT*8+HI(RA) - | sw SFARG1LO, FORL_EXT*8+LO(RA) - |2: - if (op == BC_JFORI) { - | beqz CRET1, =>BC_JLOOP - |. decode_RD8b RD - } else if (op == BC_JFORL) { - | beqz CRET1, =>BC_JLOOP - } - | ins_next2 - | - |5: // FP loop. - |.if FPU - if (!vk) { - | ldc1 f0, FORL_IDX*8(RA) - | ldc1 f2, FORL_STOP*8(RA) - | sltiu TMP0, SFARG1HI, LJ_TISNUM - | sltiu TMP1, SFARG2HI, LJ_TISNUM - | sltiu AT, SFRETHI, LJ_TISNUM - | and TMP0, TMP0, TMP1 - | and AT, AT, TMP0 - | beqz AT, ->vmeta_for - |. slt TMP3, SFRETHI, r0 - | c.ole.d 0, f0, f2 - | c.ole.d 1, f2, f0 - | li CRET1, 1 - | movt CRET1, r0, 0 - | movt AT, r0, 1 - | b <1 - |. movn CRET1, AT, TMP3 - } else { - | ldc1 f0, FORL_IDX*8(RA) - | ldc1 f4, FORL_STEP*8(RA) - | ldc1 f2, FORL_STOP*8(RA) - | lw SFARG2HI, FORL_STEP*8+HI(RA) - | add.d f0, f0, f4 - | c.ole.d 0, f0, f2 - | c.ole.d 1, f2, f0 - | slt TMP3, SFARG2HI, r0 - | li CRET1, 1 - | li AT, 1 - | movt CRET1, r0, 0 - | movt AT, r0, 1 - | movn CRET1, AT, TMP3 - if (op == BC_IFORL) { - | movn TMP2, r0, CRET1 - | addu PC, PC, TMP2 - } - | sdc1 f0, FORL_IDX*8(RA) - | ins_next1 - | b <2 - |. sdc1 f0, FORL_EXT*8(RA) - } - |.else - if (!vk) { - | sltiu TMP0, SFARG1HI, LJ_TISNUM - | sltiu TMP1, SFARG2HI, LJ_TISNUM - | sltiu AT, SFRETHI, LJ_TISNUM - | and TMP0, TMP0, TMP1 - | and AT, AT, TMP0 - | beqz AT, ->vmeta_for - |. nop - | bal ->vm_sfcmpolex - |. move TMP3, SFRETHI - | b <1 - |. nop - } else { - | lw SFARG2HI, FORL_STEP*8+HI(RA) - | load_got __adddf3 - | call_extern - |. sw TMP2, ARG5 - | lw SFARG2HI, FORL_STOP*8+HI(RA) - | lw SFARG2LO, FORL_STOP*8+LO(RA) - | move SFARG1HI, SFRETHI - | move SFARG1LO, SFRETLO - | bal ->vm_sfcmpolex - |. lw TMP3, FORL_STEP*8+HI(RA) - if ( op == BC_JFORL ) { - | lhu RD, -4+OFS_RD(PC) - | lw TMP2, ARG5 - | b <1 - |. decode_RD8b RD - } else { - | b <1 - |. lw TMP2, ARG5 - } - } - |.endif - break; - - case BC_ITERL: - |.if JIT - | hotloop - |.endif - | // Fall through. Assumes BC_IITERL follows. - break; - - case BC_JITERL: -#if !LJ_HASJIT - break; -#endif - case BC_IITERL: - | // RA = base*8, RD = target - | addu RA, BASE, RA - | lw TMP1, HI(RA) - | beq TMP1, TISNIL, >1 // Stop if iterator returned nil. - |. lw TMP2, LO(RA) - if (op == BC_JITERL) { - | sw TMP1, -8+HI(RA) - | b =>BC_JLOOP - |. sw TMP2, -8+LO(RA) - } else { - | branch_RD // Otherwise save control var + branch. - | sw TMP1, -8+HI(RA) - | sw TMP2, -8+LO(RA) - } - |1: - | ins_next - break; - - case BC_LOOP: - | // RA = base*8, RD = target (loop extent) - | // Note: RA/RD is only used by trace recorder to determine scope/extent - | // This opcode does NOT jump, it's only purpose is to detect a hot loop. - |.if JIT - | hotloop - |.endif - | // Fall through. Assumes BC_ILOOP follows. - break; - - case BC_ILOOP: - | // RA = base*8, RD = target (loop extent) - | ins_next - break; - - case BC_JLOOP: - |.if JIT - | // RA = base*8 (ignored), RD = traceno*8 - | lw TMP1, DISPATCH_J(trace)(DISPATCH) - | srl RD, RD, 1 - | li AT, 0 - | addu TMP1, TMP1, RD - | // Traces on MIPS don't store the trace number, so use 0. - | sw AT, DISPATCH_GL(vmstate)(DISPATCH) - | lw TRACE:TMP2, 0(TMP1) - | sw BASE, DISPATCH_GL(jit_base)(DISPATCH) - | lw TMP2, TRACE:TMP2->mcode - | sw L, DISPATCH_GL(tmpbuf.L)(DISPATCH) - | jr TMP2 - |. addiu JGL, DISPATCH, GG_DISP2G+32768 - |.endif - break; - - case BC_JMP: - | // RA = base*8 (only used by trace recorder), RD = target - | branch_RD - | ins_next - break; - - /* -- Function headers -------------------------------------------------- */ - - case BC_FUNCF: - |.if JIT - | hotcall - |.endif - case BC_FUNCV: /* NYI: compiled vararg functions. */ - | // Fall through. Assumes BC_IFUNCF/BC_IFUNCV follow. - break; - - case BC_JFUNCF: -#if !LJ_HASJIT - break; -#endif - case BC_IFUNCF: - | // BASE = new base, RA = BASE+framesize*8, RB = LFUNC, RC = nargs*8 - | lw TMP2, L->maxstack - | lbu TMP1, -4+PC2PROTO(numparams)(PC) - | lw KBASE, -4+PC2PROTO(k)(PC) - | sltu AT, TMP2, RA - | bnez AT, ->vm_growstack_l - |. sll TMP1, TMP1, 3 - if (op != BC_JFUNCF) { - | ins_next1 - } - |2: - | sltu AT, NARGS8:RC, TMP1 // Check for missing parameters. - | bnez AT, >3 - |. addu AT, BASE, NARGS8:RC - if (op == BC_JFUNCF) { - | decode_RD8a RD, INS - | b =>BC_JLOOP - |. decode_RD8b RD - } else { - | ins_next2 - } - | - |3: // Clear missing parameters. - | sw TISNIL, HI(AT) - | b <2 - |. addiu NARGS8:RC, NARGS8:RC, 8 - break; - - case BC_JFUNCV: -#if !LJ_HASJIT - break; -#endif - | NYI // NYI: compiled vararg functions - break; /* NYI: compiled vararg functions. */ - - case BC_IFUNCV: - | // BASE = new base, RA = BASE+framesize*8, RB = LFUNC, RC = nargs*8 - | addu TMP1, BASE, RC - | lw TMP2, L->maxstack - | addu TMP0, RA, RC - | sw LFUNC:RB, LO(TMP1) // Store copy of LFUNC. - | addiu TMP3, RC, 8+FRAME_VARG - | sltu AT, TMP0, TMP2 - | lw KBASE, -4+PC2PROTO(k)(PC) - | beqz AT, ->vm_growstack_l - |. sw TMP3, HI(TMP1) // Store delta + FRAME_VARG. - | lbu TMP2, -4+PC2PROTO(numparams)(PC) - | move RA, BASE - | move RC, TMP1 - | ins_next1 - | beqz TMP2, >3 - |. addiu BASE, TMP1, 8 - |1: - | lw TMP0, HI(RA) - | lw TMP3, LO(RA) - | sltu AT, RA, RC // Less args than parameters? - | move CARG1, TMP0 - | movz TMP0, TISNIL, AT // Clear missing parameters. - | movn CARG1, TISNIL, AT // Clear old fixarg slot (help the GC). - | sw TMP3, 8+LO(TMP1) - | addiu TMP2, TMP2, -1 - | sw TMP0, 8+HI(TMP1) - | addiu TMP1, TMP1, 8 - | sw CARG1, HI(RA) - | bnez TMP2, <1 - |. addiu RA, RA, 8 - |3: - | ins_next2 - break; - - case BC_FUNCC: - case BC_FUNCCW: - | // BASE = new base, RA = BASE+framesize*8, RB = CFUNC, RC = nargs*8 - if (op == BC_FUNCC) { - | lw CFUNCADDR, CFUNC:RB->f - } else { - | lw CFUNCADDR, DISPATCH_GL(wrapf)(DISPATCH) - } - | addu TMP1, RA, NARGS8:RC - | lw TMP2, L->maxstack - | addu RC, BASE, NARGS8:RC - | sw BASE, L->base - | sltu AT, TMP2, TMP1 - | sw RC, L->top - | li_vmstate C - if (op == BC_FUNCCW) { - | lw CARG2, CFUNC:RB->f - } - | bnez AT, ->vm_growstack_c // Need to grow stack. - |. move CARG1, L - | jalr CFUNCADDR // (lua_State *L [, lua_CFunction f]) - |. st_vmstate - | // Returns nresults. - | lw BASE, L->base - | sll RD, CRET1, 3 - | lw TMP1, L->top - | li_vmstate INTERP - | lw PC, FRAME_PC(BASE) // Fetch PC of caller. - | subu RA, TMP1, RD // RA = L->top - nresults*8 - | sw L, DISPATCH_GL(cur_L)(DISPATCH) - | b ->vm_returnc - |. st_vmstate - break; - - /* ---------------------------------------------------------------------- */ - - default: - fprintf(stderr, "Error: undefined opcode BC_%s\n", bc_names[op]); - exit(2); - break; - } -} - -static int build_backend(BuildCtx *ctx) -{ - int op; - - dasm_growpc(Dst, BC__MAX); - - build_subroutines(ctx); - - |.code_op - for (op = 0; op < BC__MAX; op++) - build_ins(ctx, (BCOp)op, op); - - return BC__MAX; -} - -/* Emit pseudo frame-info for all assembler functions. */ -static void emit_asm_debug(BuildCtx *ctx) -{ - int fcofs = (int)((uint8_t *)ctx->glob[GLOB_vm_ffi_call] - ctx->code); - int i; - switch (ctx->mode) { - case BUILD_elfasm: - fprintf(ctx->fp, "\t.section .debug_frame,\"\",@progbits\n"); - fprintf(ctx->fp, - ".Lframe0:\n" - "\t.4byte .LECIE0-.LSCIE0\n" - ".LSCIE0:\n" - "\t.4byte 0xffffffff\n" - "\t.byte 0x1\n" - "\t.string \"\"\n" - "\t.uleb128 0x1\n" - "\t.sleb128 -4\n" - "\t.byte 31\n" - "\t.byte 0xc\n\t.uleb128 29\n\t.uleb128 0\n" - "\t.align 2\n" - ".LECIE0:\n\n"); - fprintf(ctx->fp, - ".LSFDE0:\n" - "\t.4byte .LEFDE0-.LASFDE0\n" - ".LASFDE0:\n" - "\t.4byte .Lframe0\n" - "\t.4byte .Lbegin\n" - "\t.4byte %d\n" - "\t.byte 0xe\n\t.uleb128 %d\n" - "\t.byte 0x9f\n\t.sleb128 1\n" - "\t.byte 0x9e\n\t.sleb128 2\n", - fcofs, CFRAME_SIZE); - for (i = 23; i >= 16; i--) - fprintf(ctx->fp, "\t.byte %d\n\t.uleb128 %d\n", 0x80+i, 26-i); -#if !LJ_SOFTFP - for (i = 30; i >= 20; i -= 2) - fprintf(ctx->fp, "\t.byte %d\n\t.uleb128 %d\n", 0x80+32+i, 42-i); -#endif - fprintf(ctx->fp, - "\t.align 2\n" - ".LEFDE0:\n\n"); -#if LJ_HASFFI - fprintf(ctx->fp, - ".LSFDE1:\n" - "\t.4byte .LEFDE1-.LASFDE1\n" - ".LASFDE1:\n" - "\t.4byte .Lframe0\n" - "\t.4byte lj_vm_ffi_call\n" - "\t.4byte %d\n" - "\t.byte 0x9f\n\t.uleb128 1\n" - "\t.byte 0x90\n\t.uleb128 2\n" - "\t.byte 0xd\n\t.uleb128 0x10\n" - "\t.align 2\n" - ".LEFDE1:\n\n", (int)ctx->codesz - fcofs); -#endif -#if !LJ_NO_UNWIND - fprintf(ctx->fp, "\t.section .eh_frame,\"aw\",@progbits\n"); - fprintf(ctx->fp, - "\t.globl lj_err_unwind_dwarf\n" - ".Lframe1:\n" - "\t.4byte .LECIE1-.LSCIE1\n" - ".LSCIE1:\n" - "\t.4byte 0\n" - "\t.byte 0x1\n" - "\t.string \"zPR\"\n" - "\t.uleb128 0x1\n" - "\t.sleb128 -4\n" - "\t.byte 31\n" - "\t.uleb128 6\n" /* augmentation length */ - "\t.byte 0\n" - "\t.4byte lj_err_unwind_dwarf\n" - "\t.byte 0\n" - "\t.byte 0xc\n\t.uleb128 29\n\t.uleb128 0\n" - "\t.align 2\n" - ".LECIE1:\n\n"); - fprintf(ctx->fp, - ".LSFDE2:\n" - "\t.4byte .LEFDE2-.LASFDE2\n" - ".LASFDE2:\n" - "\t.4byte .LASFDE2-.Lframe1\n" - "\t.4byte .Lbegin\n" - "\t.4byte %d\n" - "\t.uleb128 0\n" /* augmentation length */ - "\t.byte 0xe\n\t.uleb128 %d\n" - "\t.byte 0x9f\n\t.sleb128 1\n" - "\t.byte 0x9e\n\t.sleb128 2\n", - fcofs, CFRAME_SIZE); - for (i = 23; i >= 16; i--) - fprintf(ctx->fp, "\t.byte %d\n\t.uleb128 %d\n", 0x80+i, 26-i); -#if !LJ_SOFTFP - for (i = 30; i >= 20; i -= 2) - fprintf(ctx->fp, "\t.byte %d\n\t.uleb128 %d\n", 0x80+32+i, 42-i); -#endif - fprintf(ctx->fp, - "\t.align 2\n" - ".LEFDE2:\n\n"); -#if LJ_HASFFI - fprintf(ctx->fp, - ".Lframe2:\n" - "\t.4byte .LECIE2-.LSCIE2\n" - ".LSCIE2:\n" - "\t.4byte 0\n" - "\t.byte 0x1\n" - "\t.string \"zR\"\n" - "\t.uleb128 0x1\n" - "\t.sleb128 -4\n" - "\t.byte 31\n" - "\t.uleb128 1\n" /* augmentation length */ - "\t.byte 0\n" - "\t.byte 0xc\n\t.uleb128 29\n\t.uleb128 0\n" - "\t.align 2\n" - ".LECIE2:\n\n"); - fprintf(ctx->fp, - ".LSFDE3:\n" - "\t.4byte .LEFDE3-.LASFDE3\n" - ".LASFDE3:\n" - "\t.4byte .LASFDE3-.Lframe2\n" - "\t.4byte lj_vm_ffi_call\n" - "\t.4byte %d\n" - "\t.uleb128 0\n" /* augmentation length */ - "\t.byte 0x9f\n\t.uleb128 1\n" - "\t.byte 0x90\n\t.uleb128 2\n" - "\t.byte 0xd\n\t.uleb128 0x10\n" - "\t.align 2\n" - ".LEFDE3:\n\n", (int)ctx->codesz - fcofs); -#endif -#endif - break; - default: - break; - } -} - diff --git a/lib/LuaJIT/src/vm_mips64.dasc b/lib/LuaJIT/src/vm_mips64.dasc deleted file mode 100644 index 1682c81..0000000 --- a/lib/LuaJIT/src/vm_mips64.dasc +++ /dev/null @@ -1,5112 +0,0 @@ -|// Low-level VM code for MIPS64 CPUs. -|// Bytecode interpreter, fast functions and helper functions. -|// Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -|// -|// Contributed by Djordje Kovacevic and Stefan Pejic from RT-RK.com. -|// Sponsored by Cisco Systems, Inc. -| -|.arch mips64 -|.section code_op, code_sub -| -|.actionlist build_actionlist -|.globals GLOB_ -|.globalnames globnames -|.externnames extnames -| -|// Note: The ragged indentation of the instructions is intentional. -|// The starting columns indicate data dependencies. -| -|//----------------------------------------------------------------------- -| -|// Fixed register assignments for the interpreter. -|// Don't use: r0 = 0, r26/r27 = reserved, r28 = gp, r29 = sp, r31 = ra -| -|.macro .FPU, a, b -|.if FPU -| a, b -|.endif -|.endmacro -| -|// The following must be C callee-save (but BASE is often refetched). -|.define BASE, r16 // Base of current Lua stack frame. -|.define KBASE, r17 // Constants of current Lua function. -|.define PC, r18 // Next PC. -|.define DISPATCH, r19 // Opcode dispatch table. -|.define LREG, r20 // Register holding lua_State (also in SAVE_L). -|.define MULTRES, r21 // Size of multi-result: (nresults+1)*8. -| -|.define JGL, r30 // On-trace: global_State + 32768. -| -|// Constants for type-comparisons, stores and conversions. C callee-save. -|.define TISNIL, r30 -|.define TISNUM, r22 -|.if FPU -|.define TOBIT, f30 // 2^52 + 2^51. -|.endif -| -|// The following temporaries are not saved across C calls, except for RA. -|.define RA, r23 // Callee-save. -|.define RB, r8 -|.define RC, r9 -|.define RD, r10 -|.define INS, r11 -| -|.define AT, r1 // Assembler temporary. -|.define TMP0, r12 -|.define TMP1, r13 -|.define TMP2, r14 -|.define TMP3, r15 -| -|// MIPS n64 calling convention. -|.define CFUNCADDR, r25 -|.define CARG1, r4 -|.define CARG2, r5 -|.define CARG3, r6 -|.define CARG4, r7 -|.define CARG5, r8 -|.define CARG6, r9 -|.define CARG7, r10 -|.define CARG8, r11 -| -|.define CRET1, r2 -|.define CRET2, r3 -| -|.if FPU -|.define FARG1, f12 -|.define FARG2, f13 -|.define FARG3, f14 -|.define FARG4, f15 -|.define FARG5, f16 -|.define FARG6, f17 -|.define FARG7, f18 -|.define FARG8, f19 -| -|.define FRET1, f0 -|.define FRET2, f2 -|.endif -| -|// Stack layout while in interpreter. Must match with lj_frame.h. -|.if FPU // MIPS64 hard-float. -| -|.define CFRAME_SPACE, 192 // Delta for sp. -| -|//----- 16 byte aligned, <-- sp entering interpreter -|.define SAVE_ERRF, 188(sp) // 32 bit values. -|.define SAVE_NRES, 184(sp) -|.define SAVE_CFRAME, 176(sp) // 64 bit values. -|.define SAVE_L, 168(sp) -|.define SAVE_PC, 160(sp) -|//----- 16 byte aligned -|.define SAVE_GPR_, 80 // .. 80+10*8: 64 bit GPR saves. -|.define SAVE_FPR_, 16 // .. 16+8*8: 64 bit FPR saves. -| -|.else // MIPS64 soft-float -| -|.define CFRAME_SPACE, 128 // Delta for sp. -| -|//----- 16 byte aligned, <-- sp entering interpreter -|.define SAVE_ERRF, 124(sp) // 32 bit values. -|.define SAVE_NRES, 120(sp) -|.define SAVE_CFRAME, 112(sp) // 64 bit values. -|.define SAVE_L, 104(sp) -|.define SAVE_PC, 96(sp) -|//----- 16 byte aligned -|.define SAVE_GPR_, 16 // .. 16+10*8: 64 bit GPR saves. -| -|.endif -| -|.define TMPX, 8(sp) // Unused by interpreter, temp for JIT code. -|.define TMPD, 0(sp) -|//----- 16 byte aligned -| -|.define TMPD_OFS, 0 -| -|.define SAVE_MULTRES, TMPD -| -|//----------------------------------------------------------------------- -| -|.macro saveregs -| daddiu sp, sp, -CFRAME_SPACE -| sd ra, SAVE_GPR_+9*8(sp) -| sd r30, SAVE_GPR_+8*8(sp) -| .FPU sdc1 f31, SAVE_FPR_+7*8(sp) -| sd r23, SAVE_GPR_+7*8(sp) -| .FPU sdc1 f30, SAVE_FPR_+6*8(sp) -| sd r22, SAVE_GPR_+6*8(sp) -| .FPU sdc1 f29, SAVE_FPR_+5*8(sp) -| sd r21, SAVE_GPR_+5*8(sp) -| .FPU sdc1 f28, SAVE_FPR_+4*8(sp) -| sd r20, SAVE_GPR_+4*8(sp) -| .FPU sdc1 f27, SAVE_FPR_+3*8(sp) -| sd r19, SAVE_GPR_+3*8(sp) -| .FPU sdc1 f26, SAVE_FPR_+2*8(sp) -| sd r18, SAVE_GPR_+2*8(sp) -| .FPU sdc1 f25, SAVE_FPR_+1*8(sp) -| sd r17, SAVE_GPR_+1*8(sp) -| .FPU sdc1 f24, SAVE_FPR_+0*8(sp) -| sd r16, SAVE_GPR_+0*8(sp) -|.endmacro -| -|.macro restoreregs_ret -| ld ra, SAVE_GPR_+9*8(sp) -| ld r30, SAVE_GPR_+8*8(sp) -| ld r23, SAVE_GPR_+7*8(sp) -| .FPU ldc1 f31, SAVE_FPR_+7*8(sp) -| ld r22, SAVE_GPR_+6*8(sp) -| .FPU ldc1 f30, SAVE_FPR_+6*8(sp) -| ld r21, SAVE_GPR_+5*8(sp) -| .FPU ldc1 f29, SAVE_FPR_+5*8(sp) -| ld r20, SAVE_GPR_+4*8(sp) -| .FPU ldc1 f28, SAVE_FPR_+4*8(sp) -| ld r19, SAVE_GPR_+3*8(sp) -| .FPU ldc1 f27, SAVE_FPR_+3*8(sp) -| ld r18, SAVE_GPR_+2*8(sp) -| .FPU ldc1 f26, SAVE_FPR_+2*8(sp) -| ld r17, SAVE_GPR_+1*8(sp) -| .FPU ldc1 f25, SAVE_FPR_+1*8(sp) -| ld r16, SAVE_GPR_+0*8(sp) -| .FPU ldc1 f24, SAVE_FPR_+0*8(sp) -| jr ra -| daddiu sp, sp, CFRAME_SPACE -|.endmacro -| -|// Type definitions. Some of these are only used for documentation. -|.type L, lua_State, LREG -|.type GL, global_State -|.type TVALUE, TValue -|.type GCOBJ, GCobj -|.type STR, GCstr -|.type TAB, GCtab -|.type LFUNC, GCfuncL -|.type CFUNC, GCfuncC -|.type PROTO, GCproto -|.type UPVAL, GCupval -|.type NODE, Node -|.type NARGS8, int -|.type TRACE, GCtrace -|.type SBUF, SBuf -| -|//----------------------------------------------------------------------- -| -|// Trap for not-yet-implemented parts. -|.macro NYI; .long 0xf0f0f0f0; .endmacro -| -|// Macros to mark delay slots. -|.macro ., a; a; .endmacro -|.macro ., a,b; a,b; .endmacro -|.macro ., a,b,c; a,b,c; .endmacro -|.macro ., a,b,c,d; a,b,c,d; .endmacro -| -|.define FRAME_PC, -8 -|.define FRAME_FUNC, -16 -| -|//----------------------------------------------------------------------- -| -|// Endian-specific defines. -|.if ENDIAN_LE -|.define HI, 4 -|.define LO, 0 -|.define OFS_RD, 2 -|.define OFS_RA, 1 -|.define OFS_OP, 0 -|.else -|.define HI, 0 -|.define LO, 4 -|.define OFS_RD, 0 -|.define OFS_RA, 2 -|.define OFS_OP, 3 -|.endif -| -|// Instruction decode. -|.macro decode_OP1, dst, ins; andi dst, ins, 0xff; .endmacro -|.macro decode_OP8a, dst, ins; andi dst, ins, 0xff; .endmacro -|.macro decode_OP8b, dst; sll dst, dst, 3; .endmacro -|.macro decode_RC8a, dst, ins; srl dst, ins, 13; .endmacro -|.macro decode_RC8b, dst; andi dst, dst, 0x7f8; .endmacro -|.macro decode_RD4b, dst; sll dst, dst, 2; .endmacro -|.macro decode_RA8a, dst, ins; srl dst, ins, 5; .endmacro -|.macro decode_RA8b, dst; andi dst, dst, 0x7f8; .endmacro -|.macro decode_RB8a, dst, ins; srl dst, ins, 21; .endmacro -|.macro decode_RB8b, dst; andi dst, dst, 0x7f8; .endmacro -|.macro decode_RD8a, dst, ins; srl dst, ins, 16; .endmacro -|.macro decode_RD8b, dst; sll dst, dst, 3; .endmacro -|.macro decode_RDtoRC8, dst, src; andi dst, src, 0x7f8; .endmacro -| -|// Instruction fetch. -|.macro ins_NEXT1 -| lw INS, 0(PC) -| daddiu PC, PC, 4 -|.endmacro -|// Instruction decode+dispatch. -|.macro ins_NEXT2 -| decode_OP8a TMP1, INS -| decode_OP8b TMP1 -| daddu TMP0, DISPATCH, TMP1 -| decode_RD8a RD, INS -| ld AT, 0(TMP0) -| decode_RA8a RA, INS -| decode_RD8b RD -| jr AT -| decode_RA8b RA -|.endmacro -|.macro ins_NEXT -| ins_NEXT1 -| ins_NEXT2 -|.endmacro -| -|// Instruction footer. -|.if 1 -| // Replicated dispatch. Less unpredictable branches, but higher I-Cache use. -| .define ins_next, ins_NEXT -| .define ins_next_, ins_NEXT -| .define ins_next1, ins_NEXT1 -| .define ins_next2, ins_NEXT2 -|.else -| // Common dispatch. Lower I-Cache use, only one (very) unpredictable branch. -| // Affects only certain kinds of benchmarks (and only with -j off). -| .macro ins_next -| b ->ins_next -| .endmacro -| .macro ins_next1 -| .endmacro -| .macro ins_next2 -| b ->ins_next -| .endmacro -| .macro ins_next_ -| ->ins_next: -| ins_NEXT -| .endmacro -|.endif -| -|// Call decode and dispatch. -|.macro ins_callt -| // BASE = new base, RB = LFUNC/CFUNC, RC = nargs*8, FRAME_PC(BASE) = PC -| ld PC, LFUNC:RB->pc -| lw INS, 0(PC) -| daddiu PC, PC, 4 -| decode_OP8a TMP1, INS -| decode_RA8a RA, INS -| decode_OP8b TMP1 -| decode_RA8b RA -| daddu TMP0, DISPATCH, TMP1 -| ld TMP0, 0(TMP0) -| jr TMP0 -| daddu RA, RA, BASE -|.endmacro -| -|.macro ins_call -| // BASE = new base, RB = LFUNC/CFUNC, RC = nargs*8, PC = caller PC -| sd PC, FRAME_PC(BASE) -| ins_callt -|.endmacro -| -|//----------------------------------------------------------------------- -| -|.macro branch_RD -| srl TMP0, RD, 1 -| lui AT, (-(BCBIAS_J*4 >> 16) & 65535) -| addu TMP0, TMP0, AT -| daddu PC, PC, TMP0 -|.endmacro -| -|// Assumes DISPATCH is relative to GL. -#define DISPATCH_GL(field) (GG_DISP2G + (int)offsetof(global_State, field)) -#define DISPATCH_J(field) (GG_DISP2J + (int)offsetof(jit_State, field)) -#define GG_DISP2GOT (GG_OFS(got) - GG_OFS(dispatch)) -#define DISPATCH_GOT(name) (GG_DISP2GOT + sizeof(void*)*LJ_GOT_##name) -| -#define PC2PROTO(field) ((int)offsetof(GCproto, field)-(int)sizeof(GCproto)) -| -|.macro load_got, func -| ld CFUNCADDR, DISPATCH_GOT(func)(DISPATCH) -|.endmacro -|// Much faster. Sadly, there's no easy way to force the required code layout. -|// .macro call_intern, func; bal extern func; .endmacro -|.macro call_intern, func; jalr CFUNCADDR; .endmacro -|.macro call_extern; jalr CFUNCADDR; .endmacro -|.macro jmp_extern; jr CFUNCADDR; .endmacro -| -|.macro hotcheck, delta, target -| dsrl TMP1, PC, 1 -| andi TMP1, TMP1, 126 -| daddu TMP1, TMP1, DISPATCH -| lhu TMP2, GG_DISP2HOT(TMP1) -| addiu TMP2, TMP2, -delta -| bltz TMP2, target -|. sh TMP2, GG_DISP2HOT(TMP1) -|.endmacro -| -|.macro hotloop -| hotcheck HOTCOUNT_LOOP, ->vm_hotloop -|.endmacro -| -|.macro hotcall -| hotcheck HOTCOUNT_CALL, ->vm_hotcall -|.endmacro -| -|// Set current VM state. Uses TMP0. -|.macro li_vmstate, st; li TMP0, ~LJ_VMST_..st; .endmacro -|.macro st_vmstate; sw TMP0, DISPATCH_GL(vmstate)(DISPATCH); .endmacro -| -|// Move table write barrier back. Overwrites mark and tmp. -|.macro barrierback, tab, mark, tmp, target -| ld tmp, DISPATCH_GL(gc.grayagain)(DISPATCH) -| andi mark, mark, ~LJ_GC_BLACK & 255 // black2gray(tab) -| sd tab, DISPATCH_GL(gc.grayagain)(DISPATCH) -| sb mark, tab->marked -| b target -|. sd tmp, tab->gclist -|.endmacro -| -|// Clear type tag. Isolate lowest 14+32+1=47 bits of reg. -|.macro cleartp, reg; dextm reg, reg, 0, 14; .endmacro -|.macro cleartp, dst, reg; dextm dst, reg, 0, 14; .endmacro -| -|// Set type tag: Merge 17 type bits into bits [15+32=47, 31+32+1=64) of dst. -|.macro settp, dst, tp; dinsu dst, tp, 15, 31; .endmacro -| -|// Extract (negative) type tag. -|.macro gettp, dst, src; dsra dst, src, 47; .endmacro -| -|// Macros to check the TValue type and extract the GCobj. Branch on failure. -|.macro checktp, reg, tp, target -| gettp AT, reg -| daddiu AT, AT, tp -| bnez AT, target -|. cleartp reg -|.endmacro -|.macro checktp, dst, reg, tp, target -| gettp AT, reg -| daddiu AT, AT, tp -| bnez AT, target -|. cleartp dst, reg -|.endmacro -|.macro checkstr, reg, target; checktp reg, -LJ_TSTR, target; .endmacro -|.macro checktab, reg, target; checktp reg, -LJ_TTAB, target; .endmacro -|.macro checkfunc, reg, target; checktp reg, -LJ_TFUNC, target; .endmacro -|.macro checkint, reg, target // Caveat: has delay slot! -| gettp AT, reg -| bne AT, TISNUM, target -|.endmacro -|.macro checknum, reg, target // Caveat: has delay slot! -| gettp AT, reg -| sltiu AT, AT, LJ_TISNUM -| beqz AT, target -|.endmacro -| -|.macro mov_false, reg -| lu reg, 0x8000 -| dsll reg, reg, 32 -| not reg, reg -|.endmacro -|.macro mov_true, reg -| li reg, 0x0001 -| dsll reg, reg, 48 -| not reg, reg -|.endmacro -| -|//----------------------------------------------------------------------- - -/* Generate subroutines used by opcodes and other parts of the VM. */ -/* The .code_sub section should be last to help static branch prediction. */ -static void build_subroutines(BuildCtx *ctx) -{ - |.code_sub - | - |//----------------------------------------------------------------------- - |//-- Return handling ---------------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_returnp: - | // See vm_return. Also: TMP2 = previous base. - | andi AT, PC, FRAME_P - | beqz AT, ->cont_dispatch - | - | // Return from pcall or xpcall fast func. - |. mov_true TMP1 - | ld PC, FRAME_PC(TMP2) // Fetch PC of previous frame. - | move BASE, TMP2 // Restore caller base. - | // Prepending may overwrite the pcall frame, so do it at the end. - | sd TMP1, -8(RA) // Prepend true to results. - | daddiu RA, RA, -8 - | - |->vm_returnc: - | addiu RD, RD, 8 // RD = (nresults+1)*8. - | andi TMP0, PC, FRAME_TYPE - | beqz RD, ->vm_unwind_c_eh - |. li CRET1, LUA_YIELD - | beqz TMP0, ->BC_RET_Z // Handle regular return to Lua. - |. move MULTRES, RD - | - |->vm_return: - | // BASE = base, RA = resultptr, RD/MULTRES = (nresults+1)*8, PC = return - | // TMP0 = PC & FRAME_TYPE - | li TMP2, -8 - | xori AT, TMP0, FRAME_C - | and TMP2, PC, TMP2 - | bnez AT, ->vm_returnp - | dsubu TMP2, BASE, TMP2 // TMP2 = previous base. - | - | addiu TMP1, RD, -8 - | sd TMP2, L->base - | li_vmstate C - | lw TMP2, SAVE_NRES - | daddiu BASE, BASE, -16 - | st_vmstate - | beqz TMP1, >2 - |. sll TMP2, TMP2, 3 - |1: - | addiu TMP1, TMP1, -8 - | ld CRET1, 0(RA) - | daddiu RA, RA, 8 - | sd CRET1, 0(BASE) - | bnez TMP1, <1 - |. daddiu BASE, BASE, 8 - | - |2: - | bne TMP2, RD, >6 - |3: - |. sd BASE, L->top // Store new top. - | - |->vm_leave_cp: - | ld TMP0, SAVE_CFRAME // Restore previous C frame. - | move CRET1, r0 // Ok return status for vm_pcall. - | sd TMP0, L->cframe - | - |->vm_leave_unw: - | restoreregs_ret - | - |6: - | ld TMP1, L->maxstack - | slt AT, TMP2, RD - | bnez AT, >7 // Less results wanted? - | // More results wanted. Check stack size and fill up results with nil. - |. slt AT, BASE, TMP1 - | beqz AT, >8 - |. nop - | sd TISNIL, 0(BASE) - | addiu RD, RD, 8 - | b <2 - |. daddiu BASE, BASE, 8 - | - |7: // Less results wanted. - | subu TMP0, RD, TMP2 - | dsubu TMP0, BASE, TMP0 // Either keep top or shrink it. - | b <3 - |. movn BASE, TMP0, TMP2 // LUA_MULTRET+1 case? - | - |8: // Corner case: need to grow stack for filling up results. - | // This can happen if: - | // - A C function grows the stack (a lot). - | // - The GC shrinks the stack in between. - | // - A return back from a lua_call() with (high) nresults adjustment. - | load_got lj_state_growstack - | move MULTRES, RD - | srl CARG2, TMP2, 3 - | call_intern lj_state_growstack // (lua_State *L, int n) - |. move CARG1, L - | lw TMP2, SAVE_NRES - | ld BASE, L->top // Need the (realloced) L->top in BASE. - | move RD, MULTRES - | b <2 - |. sll TMP2, TMP2, 3 - | - |->vm_unwind_c: // Unwind C stack, return from vm_pcall. - | // (void *cframe, int errcode) - | move sp, CARG1 - | move CRET1, CARG2 - |->vm_unwind_c_eh: // Landing pad for external unwinder. - | ld L, SAVE_L - | li TMP0, ~LJ_VMST_C - | ld GL:TMP1, L->glref - | b ->vm_leave_unw - |. sw TMP0, GL:TMP1->vmstate - | - |->vm_unwind_ff: // Unwind C stack, return from ff pcall. - | // (void *cframe) - | li AT, -4 - | and sp, CARG1, AT - |->vm_unwind_ff_eh: // Landing pad for external unwinder. - | ld L, SAVE_L - | .FPU lui TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float). - | li TISNIL, LJ_TNIL - | li TISNUM, LJ_TISNUM - | ld BASE, L->base - | ld DISPATCH, L->glref // Setup pointer to dispatch table. - | .FPU mtc1 TMP3, TOBIT - | mov_false TMP1 - | li_vmstate INTERP - | ld PC, FRAME_PC(BASE) // Fetch PC of previous frame. - | .FPU cvt.d.s TOBIT, TOBIT - | daddiu RA, BASE, -8 // Results start at BASE-8. - | daddiu DISPATCH, DISPATCH, GG_G2DISP - | sd TMP1, 0(RA) // Prepend false to error message. - | st_vmstate - | b ->vm_returnc - |. li RD, 16 // 2 results: false + error message. - | - |//----------------------------------------------------------------------- - |//-- Grow stack for calls ----------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_growstack_c: // Grow stack for C function. - | b >2 - |. li CARG2, LUA_MINSTACK - | - |->vm_growstack_l: // Grow stack for Lua function. - | // BASE = new base, RA = BASE+framesize*8, RC = nargs*8, PC = first PC - | daddu RC, BASE, RC - | dsubu RA, RA, BASE - | sd BASE, L->base - | daddiu PC, PC, 4 // Must point after first instruction. - | sd RC, L->top - | srl CARG2, RA, 3 - |2: - | // L->base = new base, L->top = top - | load_got lj_state_growstack - | sd PC, SAVE_PC - | call_intern lj_state_growstack // (lua_State *L, int n) - |. move CARG1, L - | ld BASE, L->base - | ld RC, L->top - | ld LFUNC:RB, FRAME_FUNC(BASE) - | dsubu RC, RC, BASE - | cleartp LFUNC:RB - | // BASE = new base, RB = LFUNC/CFUNC, RC = nargs*8, FRAME_PC(BASE) = PC - | ins_callt // Just retry the call. - | - |//----------------------------------------------------------------------- - |//-- Entry points into the assembler VM --------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_resume: // Setup C frame and resume thread. - | // (lua_State *L, TValue *base, int nres1 = 0, ptrdiff_t ef = 0) - | saveregs - | move L, CARG1 - | ld DISPATCH, L->glref // Setup pointer to dispatch table. - | move BASE, CARG2 - | lbu TMP1, L->status - | sd L, SAVE_L - | li PC, FRAME_CP - | daddiu TMP0, sp, CFRAME_RESUME - | daddiu DISPATCH, DISPATCH, GG_G2DISP - | sw r0, SAVE_NRES - | sw r0, SAVE_ERRF - | sd CARG1, SAVE_PC // Any value outside of bytecode is ok. - | sd r0, SAVE_CFRAME - | beqz TMP1, >3 - |. sd TMP0, L->cframe - | - | // Resume after yield (like a return). - | sd L, DISPATCH_GL(cur_L)(DISPATCH) - | move RA, BASE - | ld BASE, L->base - | ld TMP1, L->top - | ld PC, FRAME_PC(BASE) - | .FPU lui TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float). - | dsubu RD, TMP1, BASE - | .FPU mtc1 TMP3, TOBIT - | sb r0, L->status - | .FPU cvt.d.s TOBIT, TOBIT - | li_vmstate INTERP - | daddiu RD, RD, 8 - | st_vmstate - | move MULTRES, RD - | andi TMP0, PC, FRAME_TYPE - | li TISNIL, LJ_TNIL - | beqz TMP0, ->BC_RET_Z - |. li TISNUM, LJ_TISNUM - | b ->vm_return - |. nop - | - |->vm_pcall: // Setup protected C frame and enter VM. - | // (lua_State *L, TValue *base, int nres1, ptrdiff_t ef) - | saveregs - | sw CARG4, SAVE_ERRF - | b >1 - |. li PC, FRAME_CP - | - |->vm_call: // Setup C frame and enter VM. - | // (lua_State *L, TValue *base, int nres1) - | saveregs - | li PC, FRAME_C - | - |1: // Entry point for vm_pcall above (PC = ftype). - | ld TMP1, L:CARG1->cframe - | move L, CARG1 - | sw CARG3, SAVE_NRES - | ld DISPATCH, L->glref // Setup pointer to dispatch table. - | sd CARG1, SAVE_L - | move BASE, CARG2 - | daddiu DISPATCH, DISPATCH, GG_G2DISP - | sd CARG1, SAVE_PC // Any value outside of bytecode is ok. - | sd TMP1, SAVE_CFRAME - | sd sp, L->cframe // Add our C frame to cframe chain. - | - |3: // Entry point for vm_cpcall/vm_resume (BASE = base, PC = ftype). - | sd L, DISPATCH_GL(cur_L)(DISPATCH) - | ld TMP2, L->base // TMP2 = old base (used in vmeta_call). - | .FPU lui TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float). - | ld TMP1, L->top - | .FPU mtc1 TMP3, TOBIT - | daddu PC, PC, BASE - | dsubu NARGS8:RC, TMP1, BASE - | li TISNUM, LJ_TISNUM - | dsubu PC, PC, TMP2 // PC = frame delta + frame type - | .FPU cvt.d.s TOBIT, TOBIT - | li_vmstate INTERP - | li TISNIL, LJ_TNIL - | st_vmstate - | - |->vm_call_dispatch: - | // TMP2 = old base, BASE = new base, RC = nargs*8, PC = caller PC - | ld LFUNC:RB, FRAME_FUNC(BASE) - | checkfunc LFUNC:RB, ->vmeta_call - | - |->vm_call_dispatch_f: - | ins_call - | // BASE = new base, RB = func, RC = nargs*8, PC = caller PC - | - |->vm_cpcall: // Setup protected C frame, call C. - | // (lua_State *L, lua_CFunction func, void *ud, lua_CPFunction cp) - | saveregs - | move L, CARG1 - | ld TMP0, L:CARG1->stack - | sd CARG1, SAVE_L - | ld TMP1, L->top - | ld DISPATCH, L->glref // Setup pointer to dispatch table. - | sd CARG1, SAVE_PC // Any value outside of bytecode is ok. - | dsubu TMP0, TMP0, TMP1 // Compute -savestack(L, L->top). - | ld TMP1, L->cframe - | daddiu DISPATCH, DISPATCH, GG_G2DISP - | sw TMP0, SAVE_NRES // Neg. delta means cframe w/o frame. - | sw r0, SAVE_ERRF // No error function. - | sd TMP1, SAVE_CFRAME - | sd sp, L->cframe // Add our C frame to cframe chain. - | sd L, DISPATCH_GL(cur_L)(DISPATCH) - | jalr CARG4 // (lua_State *L, lua_CFunction func, void *ud) - |. move CFUNCADDR, CARG4 - | move BASE, CRET1 - | bnez CRET1, <3 // Else continue with the call. - |. li PC, FRAME_CP - | b ->vm_leave_cp // No base? Just remove C frame. - |. nop - | - |//----------------------------------------------------------------------- - |//-- Metamethod handling ------------------------------------------------ - |//----------------------------------------------------------------------- - | - |// The lj_meta_* functions (except for lj_meta_cat) don't reallocate the - |// stack, so BASE doesn't need to be reloaded across these calls. - | - |//-- Continuation dispatch ---------------------------------------------- - | - |->cont_dispatch: - | // BASE = meta base, RA = resultptr, RD = (nresults+1)*8 - | ld TMP0, -32(BASE) // Continuation. - | move RB, BASE - | move BASE, TMP2 // Restore caller BASE. - | ld LFUNC:TMP1, FRAME_FUNC(TMP2) - |.if FFI - | sltiu AT, TMP0, 2 - |.endif - | ld PC, -24(RB) // Restore PC from [cont|PC]. - | cleartp LFUNC:TMP1 - | daddu TMP2, RA, RD - | ld TMP1, LFUNC:TMP1->pc - |.if FFI - | bnez AT, >1 - |.endif - |. sd TISNIL, -8(TMP2) // Ensure one valid arg. - | // BASE = base, RA = resultptr, RB = meta base - | jr TMP0 // Jump to continuation. - |. ld KBASE, PC2PROTO(k)(TMP1) - | - |.if FFI - |1: - | bnez TMP0, ->cont_ffi_callback // cont = 1: return from FFI callback. - | // cont = 0: tailcall from C function. - |. daddiu TMP1, RB, -32 - | b ->vm_call_tail - |. dsubu RC, TMP1, BASE - |.endif - | - |->cont_cat: // RA = resultptr, RB = meta base - | lw INS, -4(PC) - | daddiu CARG2, RB, -32 - | ld CRET1, 0(RA) - | decode_RB8a MULTRES, INS - | decode_RA8a RA, INS - | decode_RB8b MULTRES - | decode_RA8b RA - | daddu TMP1, BASE, MULTRES - | sd BASE, L->base - | dsubu CARG3, CARG2, TMP1 - | bne TMP1, CARG2, ->BC_CAT_Z - |. sd CRET1, 0(CARG2) - | daddu RA, BASE, RA - | b ->cont_nop - |. sd CRET1, 0(RA) - | - |//-- Table indexing metamethods ----------------------------------------- - | - |->vmeta_tgets1: - | daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv) - | li TMP0, LJ_TSTR - | settp STR:RC, TMP0 - | b >1 - |. sd STR:RC, 0(CARG3) - | - |->vmeta_tgets: - | daddiu CARG2, DISPATCH, DISPATCH_GL(tmptv) - | li TMP0, LJ_TTAB - | li TMP1, LJ_TSTR - | settp TAB:RB, TMP0 - | daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv2) - | sd TAB:RB, 0(CARG2) - | settp STR:RC, TMP1 - | b >1 - |. sd STR:RC, 0(CARG3) - | - |->vmeta_tgetb: // TMP0 = index - | daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv) - | settp TMP0, TISNUM - | sd TMP0, 0(CARG3) - | - |->vmeta_tgetv: - |1: - | load_got lj_meta_tget - | sd BASE, L->base - | sd PC, SAVE_PC - | call_intern lj_meta_tget // (lua_State *L, TValue *o, TValue *k) - |. move CARG1, L - | // Returns TValue * (finished) or NULL (metamethod). - | beqz CRET1, >3 - |. daddiu TMP1, BASE, -FRAME_CONT - | ld CARG1, 0(CRET1) - | ins_next1 - | sd CARG1, 0(RA) - | ins_next2 - | - |3: // Call __index metamethod. - | // BASE = base, L->top = new base, stack = cont/func/t/k - | ld BASE, L->top - | sd PC, -24(BASE) // [cont|PC] - | dsubu PC, BASE, TMP1 - | ld LFUNC:RB, FRAME_FUNC(BASE) // Guaranteed to be a function here. - | cleartp LFUNC:RB - | b ->vm_call_dispatch_f - |. li NARGS8:RC, 16 // 2 args for func(t, k). - | - |->vmeta_tgetr: - | load_got lj_tab_getinth - | call_intern lj_tab_getinth // (GCtab *t, int32_t key) - |. nop - | // Returns cTValue * or NULL. - | beqz CRET1, ->BC_TGETR_Z - |. move CARG2, TISNIL - | b ->BC_TGETR_Z - |. ld CARG2, 0(CRET1) - | - |//----------------------------------------------------------------------- - | - |->vmeta_tsets1: - | daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv) - | li TMP0, LJ_TSTR - | settp STR:RC, TMP0 - | b >1 - |. sd STR:RC, 0(CARG3) - | - |->vmeta_tsets: - | daddiu CARG2, DISPATCH, DISPATCH_GL(tmptv) - | li TMP0, LJ_TTAB - | li TMP1, LJ_TSTR - | settp TAB:RB, TMP0 - | daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv2) - | sd TAB:RB, 0(CARG2) - | settp STR:RC, TMP1 - | b >1 - |. sd STR:RC, 0(CARG3) - | - |->vmeta_tsetb: // TMP0 = index - | daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv) - | settp TMP0, TISNUM - | sd TMP0, 0(CARG3) - | - |->vmeta_tsetv: - |1: - | load_got lj_meta_tset - | sd BASE, L->base - | sd PC, SAVE_PC - | call_intern lj_meta_tset // (lua_State *L, TValue *o, TValue *k) - |. move CARG1, L - | // Returns TValue * (finished) or NULL (metamethod). - | beqz CRET1, >3 - |. ld CARG1, 0(RA) - | // NOBARRIER: lj_meta_tset ensures the table is not black. - | ins_next1 - | sd CARG1, 0(CRET1) - | ins_next2 - | - |3: // Call __newindex metamethod. - | // BASE = base, L->top = new base, stack = cont/func/t/k/(v) - | daddiu TMP1, BASE, -FRAME_CONT - | ld BASE, L->top - | sd PC, -24(BASE) // [cont|PC] - | dsubu PC, BASE, TMP1 - | ld LFUNC:RB, FRAME_FUNC(BASE) // Guaranteed to be a function here. - | cleartp LFUNC:RB - | sd CARG1, 16(BASE) // Copy value to third argument. - | b ->vm_call_dispatch_f - |. li NARGS8:RC, 24 // 3 args for func(t, k, v) - | - |->vmeta_tsetr: - | load_got lj_tab_setinth - | sd BASE, L->base - | sd PC, SAVE_PC - | call_intern lj_tab_setinth // (lua_State *L, GCtab *t, int32_t key) - |. move CARG1, L - | // Returns TValue *. - | b ->BC_TSETR_Z - |. nop - | - |//-- Comparison metamethods --------------------------------------------- - | - |->vmeta_comp: - | // RA/RD point to o1/o2. - | move CARG2, RA - | move CARG3, RD - | load_got lj_meta_comp - | daddiu PC, PC, -4 - | sd BASE, L->base - | sd PC, SAVE_PC - | decode_OP1 CARG4, INS - | call_intern lj_meta_comp // (lua_State *L, TValue *o1, *o2, int op) - |. move CARG1, L - | // Returns 0/1 or TValue * (metamethod). - |3: - | sltiu AT, CRET1, 2 - | beqz AT, ->vmeta_binop - | negu TMP2, CRET1 - |4: - | lhu RD, OFS_RD(PC) - | daddiu PC, PC, 4 - | lui TMP1, (-(BCBIAS_J*4 >> 16) & 65535) - | sll RD, RD, 2 - | addu RD, RD, TMP1 - | and RD, RD, TMP2 - | daddu PC, PC, RD - |->cont_nop: - | ins_next - | - |->cont_ra: // RA = resultptr - | lbu TMP1, -4+OFS_RA(PC) - | ld CRET1, 0(RA) - | sll TMP1, TMP1, 3 - | daddu TMP1, BASE, TMP1 - | b ->cont_nop - |. sd CRET1, 0(TMP1) - | - |->cont_condt: // RA = resultptr - | ld TMP0, 0(RA) - | gettp TMP0, TMP0 - | sltiu AT, TMP0, LJ_TISTRUECOND - | b <4 - |. negu TMP2, AT // Branch if result is true. - | - |->cont_condf: // RA = resultptr - | ld TMP0, 0(RA) - | gettp TMP0, TMP0 - | sltiu AT, TMP0, LJ_TISTRUECOND - | b <4 - |. addiu TMP2, AT, -1 // Branch if result is false. - | - |->vmeta_equal: - | // CARG1/CARG2 point to o1/o2. TMP0 is set to 0/1. - | load_got lj_meta_equal - | cleartp LFUNC:CARG3, CARG2 - | cleartp LFUNC:CARG2, CARG1 - | move CARG4, TMP0 - | daddiu PC, PC, -4 - | sd BASE, L->base - | sd PC, SAVE_PC - | call_intern lj_meta_equal // (lua_State *L, GCobj *o1, *o2, int ne) - |. move CARG1, L - | // Returns 0/1 or TValue * (metamethod). - | b <3 - |. nop - | - |->vmeta_equal_cd: - |.if FFI - | load_got lj_meta_equal_cd - | move CARG2, INS - | daddiu PC, PC, -4 - | sd BASE, L->base - | sd PC, SAVE_PC - | call_intern lj_meta_equal_cd // (lua_State *L, BCIns op) - |. move CARG1, L - | // Returns 0/1 or TValue * (metamethod). - | b <3 - |. nop - |.endif - | - |->vmeta_istype: - | load_got lj_meta_istype - | daddiu PC, PC, -4 - | sd BASE, L->base - | srl CARG2, RA, 3 - | srl CARG3, RD, 3 - | sd PC, SAVE_PC - | call_intern lj_meta_istype // (lua_State *L, BCReg ra, BCReg tp) - |. move CARG1, L - | b ->cont_nop - |. nop - | - |//-- Arithmetic metamethods --------------------------------------------- - | - |->vmeta_unm: - | move RC, RB - | - |->vmeta_arith: - | load_got lj_meta_arith - | sd BASE, L->base - | move CARG2, RA - | sd PC, SAVE_PC - | move CARG3, RB - | move CARG4, RC - | decode_OP1 CARG5, INS // CARG5 == RB. - | call_intern lj_meta_arith // (lua_State *L, TValue *ra,*rb,*rc, BCReg op) - |. move CARG1, L - | // Returns NULL (finished) or TValue * (metamethod). - | beqz CRET1, ->cont_nop - |. nop - | - | // Call metamethod for binary op. - |->vmeta_binop: - | // BASE = old base, CRET1 = new base, stack = cont/func/o1/o2 - | dsubu TMP1, CRET1, BASE - | sd PC, -24(CRET1) // [cont|PC] - | move TMP2, BASE - | daddiu PC, TMP1, FRAME_CONT - | move BASE, CRET1 - | b ->vm_call_dispatch - |. li NARGS8:RC, 16 // 2 args for func(o1, o2). - | - |->vmeta_len: - | // CARG2 already set by BC_LEN. -#if LJ_52 - | move MULTRES, CARG1 -#endif - | load_got lj_meta_len - | sd BASE, L->base - | sd PC, SAVE_PC - | call_intern lj_meta_len // (lua_State *L, TValue *o) - |. move CARG1, L - | // Returns NULL (retry) or TValue * (metamethod base). -#if LJ_52 - | bnez CRET1, ->vmeta_binop // Binop call for compatibility. - |. nop - | b ->BC_LEN_Z - |. move CARG1, MULTRES -#else - | b ->vmeta_binop // Binop call for compatibility. - |. nop -#endif - | - |//-- Call metamethod ---------------------------------------------------- - | - |->vmeta_call: // Resolve and call __call metamethod. - | // TMP2 = old base, BASE = new base, RC = nargs*8 - | load_got lj_meta_call - | sd TMP2, L->base // This is the callers base! - | daddiu CARG2, BASE, -16 - | sd PC, SAVE_PC - | daddu CARG3, BASE, RC - | move MULTRES, NARGS8:RC - | call_intern lj_meta_call // (lua_State *L, TValue *func, TValue *top) - |. move CARG1, L - | ld LFUNC:RB, FRAME_FUNC(BASE) // Guaranteed to be a function here. - | daddiu NARGS8:RC, MULTRES, 8 // Got one more argument now. - | cleartp LFUNC:RB - | ins_call - | - |->vmeta_callt: // Resolve __call for BC_CALLT. - | // BASE = old base, RA = new base, RC = nargs*8 - | load_got lj_meta_call - | sd BASE, L->base - | daddiu CARG2, RA, -16 - | sd PC, SAVE_PC - | daddu CARG3, RA, RC - | move MULTRES, NARGS8:RC - | call_intern lj_meta_call // (lua_State *L, TValue *func, TValue *top) - |. move CARG1, L - | ld RB, FRAME_FUNC(RA) // Guaranteed to be a function here. - | ld TMP1, FRAME_PC(BASE) - | daddiu NARGS8:RC, MULTRES, 8 // Got one more argument now. - | b ->BC_CALLT_Z - |. cleartp LFUNC:CARG3, RB - | - |//-- Argument coercion for 'for' statement ------------------------------ - | - |->vmeta_for: - | load_got lj_meta_for - | sd BASE, L->base - | move CARG2, RA - | sd PC, SAVE_PC - | move MULTRES, INS - | call_intern lj_meta_for // (lua_State *L, TValue *base) - |. move CARG1, L - |.if JIT - | decode_OP1 TMP0, MULTRES - | li AT, BC_JFORI - |.endif - | decode_RA8a RA, MULTRES - | decode_RD8a RD, MULTRES - | decode_RA8b RA - |.if JIT - | beq TMP0, AT, =>BC_JFORI - |. decode_RD8b RD - | b =>BC_FORI - |. nop - |.else - | b =>BC_FORI - |. decode_RD8b RD - |.endif - | - |//----------------------------------------------------------------------- - |//-- Fast functions ----------------------------------------------------- - |//----------------------------------------------------------------------- - | - |.macro .ffunc, name - |->ff_ .. name: - |.endmacro - | - |.macro .ffunc_1, name - |->ff_ .. name: - | beqz NARGS8:RC, ->fff_fallback - |. ld CARG1, 0(BASE) - |.endmacro - | - |.macro .ffunc_2, name - |->ff_ .. name: - | sltiu AT, NARGS8:RC, 16 - | ld CARG1, 0(BASE) - | bnez AT, ->fff_fallback - |. ld CARG2, 8(BASE) - |.endmacro - | - |.macro .ffunc_n, name // Caveat: has delay slot! - |->ff_ .. name: - | ld CARG1, 0(BASE) - | beqz NARGS8:RC, ->fff_fallback - | // Either ldc1 or the 1st instruction of checknum is in the delay slot. - | .FPU ldc1 FARG1, 0(BASE) - | checknum CARG1, ->fff_fallback - |.endmacro - | - |.macro .ffunc_nn, name // Caveat: has delay slot! - |->ff_ .. name: - | ld CARG1, 0(BASE) - | sltiu AT, NARGS8:RC, 16 - | ld CARG2, 8(BASE) - | bnez AT, ->fff_fallback - |. gettp TMP0, CARG1 - | gettp TMP1, CARG2 - | sltiu TMP0, TMP0, LJ_TISNUM - | sltiu TMP1, TMP1, LJ_TISNUM - | .FPU ldc1 FARG1, 0(BASE) - | and TMP0, TMP0, TMP1 - | .FPU ldc1 FARG2, 8(BASE) - | beqz TMP0, ->fff_fallback - |.endmacro - | - |// Inlined GC threshold check. Caveat: uses TMP0 and TMP1 and has delay slot! - |.macro ffgccheck - | ld TMP0, DISPATCH_GL(gc.total)(DISPATCH) - | ld TMP1, DISPATCH_GL(gc.threshold)(DISPATCH) - | dsubu AT, TMP0, TMP1 - | bgezal AT, ->fff_gcstep - |.endmacro - | - |//-- Base library: checks ----------------------------------------------- - |.ffunc_1 assert - | gettp AT, CARG1 - | sltiu AT, AT, LJ_TISTRUECOND - | beqz AT, ->fff_fallback - |. daddiu RA, BASE, -16 - | ld PC, FRAME_PC(BASE) - | addiu RD, NARGS8:RC, 8 // Compute (nresults+1)*8. - | daddu TMP2, RA, RD - | daddiu TMP1, BASE, 8 - | beq BASE, TMP2, ->fff_res // Done if exactly 1 argument. - |. sd CARG1, 0(RA) - |1: - | ld CRET1, 0(TMP1) - | sd CRET1, -16(TMP1) - | bne TMP1, TMP2, <1 - |. daddiu TMP1, TMP1, 8 - | b ->fff_res - |. nop - | - |.ffunc_1 type - | gettp TMP0, CARG1 - | sltu TMP1, TISNUM, TMP0 - | not TMP2, TMP0 - | li TMP3, ~LJ_TISNUM - | movz TMP2, TMP3, TMP1 - | dsll TMP2, TMP2, 3 - | daddu TMP2, CFUNC:RB, TMP2 - | b ->fff_restv - |. ld CARG1, CFUNC:TMP2->upvalue - | - |//-- Base library: getters and setters --------------------------------- - | - |.ffunc_1 getmetatable - | gettp TMP2, CARG1 - | daddiu TMP0, TMP2, -LJ_TTAB - | daddiu TMP1, TMP2, -LJ_TUDATA - | movn TMP0, TMP1, TMP0 - | bnez TMP0, >6 - |. cleartp TAB:CARG1 - |1: // Field metatable must be at same offset for GCtab and GCudata! - | ld TAB:RB, TAB:CARG1->metatable - |2: - | ld STR:RC, DISPATCH_GL(gcroot[GCROOT_MMNAME+MM_metatable])(DISPATCH) - | beqz TAB:RB, ->fff_restv - |. li CARG1, LJ_TNIL - | lw TMP0, TAB:RB->hmask - | lw TMP1, STR:RC->hash - | ld NODE:TMP2, TAB:RB->node - | and TMP1, TMP1, TMP0 // idx = str->hash & tab->hmask - | dsll TMP0, TMP1, 5 - | dsll TMP1, TMP1, 3 - | dsubu TMP1, TMP0, TMP1 - | daddu NODE:TMP2, NODE:TMP2, TMP1 // node = tab->node + (idx*32-idx*8) - | li CARG4, LJ_TSTR - | settp STR:RC, CARG4 // Tagged key to look for. - |3: // Rearranged logic, because we expect _not_ to find the key. - | ld TMP0, NODE:TMP2->key - | ld CARG1, NODE:TMP2->val - | ld NODE:TMP2, NODE:TMP2->next - | beq RC, TMP0, >5 - |. li AT, LJ_TTAB - | bnez NODE:TMP2, <3 - |. nop - |4: - | move CARG1, RB - | b ->fff_restv // Not found, keep default result. - |. settp CARG1, AT - |5: - | bne CARG1, TISNIL, ->fff_restv - |. nop - | b <4 // Ditto for nil value. - |. nop - | - |6: - | sltiu AT, TMP2, LJ_TISNUM - | movn TMP2, TISNUM, AT - | dsll TMP2, TMP2, 3 - | dsubu TMP0, DISPATCH, TMP2 - | b <2 - |. ld TAB:RB, DISPATCH_GL(gcroot[GCROOT_BASEMT])-8(TMP0) - | - |.ffunc_2 setmetatable - | // Fast path: no mt for table yet and not clearing the mt. - | checktp TMP1, CARG1, -LJ_TTAB, ->fff_fallback - | gettp TMP3, CARG2 - | ld TAB:TMP0, TAB:TMP1->metatable - | lbu TMP2, TAB:TMP1->marked - | daddiu AT, TMP3, -LJ_TTAB - | cleartp TAB:CARG2 - | or AT, AT, TAB:TMP0 - | bnez AT, ->fff_fallback - |. andi AT, TMP2, LJ_GC_BLACK // isblack(table) - | beqz AT, ->fff_restv - |. sd TAB:CARG2, TAB:TMP1->metatable - | barrierback TAB:TMP1, TMP2, TMP0, ->fff_restv - | - |.ffunc rawget - | ld CARG2, 0(BASE) - | sltiu AT, NARGS8:RC, 16 - | load_got lj_tab_get - | gettp TMP0, CARG2 - | cleartp CARG2 - | daddiu TMP0, TMP0, -LJ_TTAB - | or AT, AT, TMP0 - | bnez AT, ->fff_fallback - |. daddiu CARG3, BASE, 8 - | call_intern lj_tab_get // (lua_State *L, GCtab *t, cTValue *key) - |. move CARG1, L - | b ->fff_restv - |. ld CARG1, 0(CRET1) - | - |//-- Base library: conversions ------------------------------------------ - | - |.ffunc tonumber - | // Only handles the number case inline (without a base argument). - | ld CARG1, 0(BASE) - | xori AT, NARGS8:RC, 8 // Exactly one number argument. - | gettp TMP1, CARG1 - | sltu TMP0, TISNUM, TMP1 - | or AT, AT, TMP0 - | bnez AT, ->fff_fallback - |. nop - | b ->fff_restv - |. nop - | - |.ffunc_1 tostring - | // Only handles the string or number case inline. - | gettp TMP0, CARG1 - | daddiu AT, TMP0, -LJ_TSTR - | // A __tostring method in the string base metatable is ignored. - | beqz AT, ->fff_restv // String key? - | // Handle numbers inline, unless a number base metatable is present. - |. ld TMP1, DISPATCH_GL(gcroot[GCROOT_BASEMT_NUM])(DISPATCH) - | sltu TMP0, TISNUM, TMP0 - | or TMP0, TMP0, TMP1 - | bnez TMP0, ->fff_fallback - |. sd BASE, L->base // Add frame since C call can throw. - | ffgccheck - |. sd PC, SAVE_PC // Redundant (but a defined value). - | load_got lj_strfmt_number - | move CARG1, L - | call_intern lj_strfmt_number // (lua_State *L, cTValue *o) - |. move CARG2, BASE - | // Returns GCstr *. - | li AT, LJ_TSTR - | settp CRET1, AT - | b ->fff_restv - |. move CARG1, CRET1 - | - |//-- Base library: iterators ------------------------------------------- - | - |.ffunc_1 next - | checktp CARG2, CARG1, -LJ_TTAB, ->fff_fallback - | daddu TMP2, BASE, NARGS8:RC - | sd TISNIL, 0(TMP2) // Set missing 2nd arg to nil. - | ld PC, FRAME_PC(BASE) - | load_got lj_tab_next - | sd BASE, L->base // Add frame since C call can throw. - | sd BASE, L->top // Dummy frame length is ok. - | daddiu CARG3, BASE, 8 - | sd PC, SAVE_PC - | call_intern lj_tab_next // (lua_State *L, GCtab *t, TValue *key) - |. move CARG1, L - | // Returns 0 at end of traversal. - | beqz CRET1, ->fff_restv // End of traversal: return nil. - |. move CARG1, TISNIL - | ld TMP0, 8(BASE) - | daddiu RA, BASE, -16 - | ld TMP2, 16(BASE) - | sd TMP0, 0(RA) - | sd TMP2, 8(RA) - | b ->fff_res - |. li RD, (2+1)*8 - | - |.ffunc_1 pairs - | checktp TAB:TMP1, CARG1, -LJ_TTAB, ->fff_fallback - | ld PC, FRAME_PC(BASE) -#if LJ_52 - | ld TAB:TMP2, TAB:TMP1->metatable - | ld TMP0, CFUNC:RB->upvalue[0] - | bnez TAB:TMP2, ->fff_fallback -#else - | ld TMP0, CFUNC:RB->upvalue[0] -#endif - |. daddiu RA, BASE, -16 - | sd TISNIL, 0(BASE) - | sd CARG1, -8(BASE) - | sd TMP0, 0(RA) - | b ->fff_res - |. li RD, (3+1)*8 - | - |.ffunc_2 ipairs_aux - | checktab CARG1, ->fff_fallback - | checkint CARG2, ->fff_fallback - |. lw TMP0, TAB:CARG1->asize - | ld TMP1, TAB:CARG1->array - | ld PC, FRAME_PC(BASE) - | sextw TMP2, CARG2 - | addiu TMP2, TMP2, 1 - | sltu AT, TMP2, TMP0 - | daddiu RA, BASE, -16 - | zextw TMP0, TMP2 - | settp TMP0, TISNUM - | beqz AT, >2 // Not in array part? - |. sd TMP0, 0(RA) - | dsll TMP3, TMP2, 3 - | daddu TMP3, TMP1, TMP3 - | ld TMP1, 0(TMP3) - |1: - | beq TMP1, TISNIL, ->fff_res // End of iteration, return 0 results. - |. li RD, (0+1)*8 - | sd TMP1, -8(BASE) - | b ->fff_res - |. li RD, (2+1)*8 - |2: // Check for empty hash part first. Otherwise call C function. - | lw TMP0, TAB:CARG1->hmask - | load_got lj_tab_getinth - | beqz TMP0, ->fff_res - |. li RD, (0+1)*8 - | call_intern lj_tab_getinth // (GCtab *t, int32_t key) - |. move CARG2, TMP2 - | // Returns cTValue * or NULL. - | beqz CRET1, ->fff_res - |. li RD, (0+1)*8 - | b <1 - |. ld TMP1, 0(CRET1) - | - |.ffunc_1 ipairs - | checktp TAB:TMP1, CARG1, -LJ_TTAB, ->fff_fallback - | ld PC, FRAME_PC(BASE) -#if LJ_52 - | ld TAB:TMP2, TAB:TMP1->metatable - | ld CFUNC:TMP0, CFUNC:RB->upvalue[0] - | bnez TAB:TMP2, ->fff_fallback -#else - | ld TMP0, CFUNC:RB->upvalue[0] -#endif - | daddiu RA, BASE, -16 - | dsll AT, TISNUM, 47 - | sd CARG1, -8(BASE) - | sd AT, 0(BASE) - | sd CFUNC:TMP0, 0(RA) - | b ->fff_res - |. li RD, (3+1)*8 - | - |//-- Base library: catch errors ---------------------------------------- - | - |.ffunc pcall - | daddiu NARGS8:RC, NARGS8:RC, -8 - | lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH) - | bltz NARGS8:RC, ->fff_fallback - |. move TMP2, BASE - | daddiu BASE, BASE, 16 - | // Remember active hook before pcall. - | srl TMP3, TMP3, HOOK_ACTIVE_SHIFT - | andi TMP3, TMP3, 1 - | daddiu PC, TMP3, 16+FRAME_PCALL - | beqz NARGS8:RC, ->vm_call_dispatch - |1: - |. daddu TMP0, BASE, NARGS8:RC - |2: - | ld TMP1, -16(TMP0) - | sd TMP1, -8(TMP0) - | daddiu TMP0, TMP0, -8 - | bne TMP0, BASE, <2 - |. nop - | b ->vm_call_dispatch - |. nop - | - |.ffunc xpcall - | daddiu NARGS8:TMP0, NARGS8:RC, -16 - | ld CARG1, 0(BASE) - | ld CARG2, 8(BASE) - | bltz NARGS8:TMP0, ->fff_fallback - |. lbu TMP1, DISPATCH_GL(hookmask)(DISPATCH) - | gettp AT, CARG2 - | daddiu AT, AT, -LJ_TFUNC - | bnez AT, ->fff_fallback // Traceback must be a function. - |. move TMP2, BASE - | move NARGS8:RC, NARGS8:TMP0 - | daddiu BASE, BASE, 24 - | // Remember active hook before pcall. - | srl TMP3, TMP3, HOOK_ACTIVE_SHIFT - | sd CARG2, 0(TMP2) // Swap function and traceback. - | andi TMP3, TMP3, 1 - | sd CARG1, 8(TMP2) - | beqz NARGS8:RC, ->vm_call_dispatch - |. daddiu PC, TMP3, 24+FRAME_PCALL - | b <1 - |. nop - | - |//-- Coroutine library -------------------------------------------------- - | - |.macro coroutine_resume_wrap, resume - |.if resume - |.ffunc_1 coroutine_resume - | checktp CARG1, CARG1, -LJ_TTHREAD, ->fff_fallback - |.else - |.ffunc coroutine_wrap_aux - | ld L:CARG1, CFUNC:RB->upvalue[0].gcr - | cleartp L:CARG1 - |.endif - | lbu TMP0, L:CARG1->status - | ld TMP1, L:CARG1->cframe - | ld CARG2, L:CARG1->top - | ld TMP2, L:CARG1->base - | addiu AT, TMP0, -LUA_YIELD - | daddu CARG3, CARG2, TMP0 - | daddiu TMP3, CARG2, 8 - | bgtz AT, ->fff_fallback // st > LUA_YIELD? - |. movn CARG2, TMP3, AT - | xor TMP2, TMP2, CARG3 - | bnez TMP1, ->fff_fallback // cframe != 0? - |. or AT, TMP2, TMP0 - | ld TMP0, L:CARG1->maxstack - | beqz AT, ->fff_fallback // base == top && st == 0? - |. ld PC, FRAME_PC(BASE) - | daddu TMP2, CARG2, NARGS8:RC - | sltu AT, TMP0, TMP2 - | bnez AT, ->fff_fallback // Stack overflow? - |. sd PC, SAVE_PC - | sd BASE, L->base - |1: - |.if resume - | daddiu BASE, BASE, 8 // Keep resumed thread in stack for GC. - | daddiu NARGS8:RC, NARGS8:RC, -8 - | daddiu TMP2, TMP2, -8 - |.endif - | sd TMP2, L:CARG1->top - | daddu TMP1, BASE, NARGS8:RC - | move CARG3, CARG2 - | sd BASE, L->top - |2: // Move args to coroutine. - | ld CRET1, 0(BASE) - | sltu AT, BASE, TMP1 - | beqz AT, >3 - |. daddiu BASE, BASE, 8 - | sd CRET1, 0(CARG3) - | b <2 - |. daddiu CARG3, CARG3, 8 - |3: - | bal ->vm_resume // (lua_State *L, TValue *base, 0, 0) - |. move L:RA, L:CARG1 - | // Returns thread status. - |4: - | ld TMP2, L:RA->base - | sltiu AT, CRET1, LUA_YIELD+1 - | ld TMP3, L:RA->top - | li_vmstate INTERP - | ld BASE, L->base - | sd L, DISPATCH_GL(cur_L)(DISPATCH) - | st_vmstate - | beqz AT, >8 - |. dsubu RD, TMP3, TMP2 - | ld TMP0, L->maxstack - | beqz RD, >6 // No results? - |. daddu TMP1, BASE, RD - | sltu AT, TMP0, TMP1 - | bnez AT, >9 // Need to grow stack? - |. daddu TMP3, TMP2, RD - | sd TMP2, L:RA->top // Clear coroutine stack. - | move TMP1, BASE - |5: // Move results from coroutine. - | ld CRET1, 0(TMP2) - | daddiu TMP2, TMP2, 8 - | sltu AT, TMP2, TMP3 - | sd CRET1, 0(TMP1) - | bnez AT, <5 - |. daddiu TMP1, TMP1, 8 - |6: - | andi TMP0, PC, FRAME_TYPE - |.if resume - | mov_true TMP1 - | daddiu RA, BASE, -8 - | sd TMP1, -8(BASE) // Prepend true to results. - | daddiu RD, RD, 16 - |.else - | move RA, BASE - | daddiu RD, RD, 8 - |.endif - |7: - | sd PC, SAVE_PC - | beqz TMP0, ->BC_RET_Z - |. move MULTRES, RD - | b ->vm_return - |. nop - | - |8: // Coroutine returned with error (at co->top-1). - |.if resume - | daddiu TMP3, TMP3, -8 - | mov_false TMP1 - | ld CRET1, 0(TMP3) - | sd TMP3, L:RA->top // Remove error from coroutine stack. - | li RD, (2+1)*8 - | sd TMP1, -8(BASE) // Prepend false to results. - | daddiu RA, BASE, -8 - | sd CRET1, 0(BASE) // Copy error message. - | b <7 - |. andi TMP0, PC, FRAME_TYPE - |.else - | load_got lj_ffh_coroutine_wrap_err - | move CARG2, L:RA - | call_intern lj_ffh_coroutine_wrap_err // (lua_State *L, lua_State *co) - |. move CARG1, L - |.endif - | - |9: // Handle stack expansion on return from yield. - | load_got lj_state_growstack - | srl CARG2, RD, 3 - | call_intern lj_state_growstack // (lua_State *L, int n) - |. move CARG1, L - | b <4 - |. li CRET1, 0 - |.endmacro - | - | coroutine_resume_wrap 1 // coroutine.resume - | coroutine_resume_wrap 0 // coroutine.wrap - | - |.ffunc coroutine_yield - | ld TMP0, L->cframe - | daddu TMP1, BASE, NARGS8:RC - | sd BASE, L->base - | andi TMP0, TMP0, CFRAME_RESUME - | sd TMP1, L->top - | beqz TMP0, ->fff_fallback - |. li CRET1, LUA_YIELD - | sd r0, L->cframe - | b ->vm_leave_unw - |. sb CRET1, L->status - | - |//-- Math library ------------------------------------------------------- - | - |.ffunc_1 math_abs - | gettp CARG2, CARG1 - | daddiu AT, CARG2, -LJ_TISNUM - | bnez AT, >1 - |. sextw TMP1, CARG1 - | sra TMP0, TMP1, 31 // Extract sign. - | xor TMP1, TMP1, TMP0 - | dsubu CARG1, TMP1, TMP0 - | dsll TMP3, CARG1, 32 - | bgez TMP3, ->fff_restv - |. settp CARG1, TISNUM - | li CARG1, 0x41e0 // 2^31 as a double. - | b ->fff_restv - |. dsll CARG1, CARG1, 48 - |1: - | sltiu AT, CARG2, LJ_TISNUM - | beqz AT, ->fff_fallback - |. dextm CARG1, CARG1, 0, 30 - |// fallthrough - | - |->fff_restv: - | // CARG1 = TValue result. - | ld PC, FRAME_PC(BASE) - | daddiu RA, BASE, -16 - | sd CARG1, -16(BASE) - |->fff_res1: - | // RA = results, PC = return. - | li RD, (1+1)*8 - |->fff_res: - | // RA = results, RD = (nresults+1)*8, PC = return. - | andi TMP0, PC, FRAME_TYPE - | bnez TMP0, ->vm_return - |. move MULTRES, RD - | lw INS, -4(PC) - | decode_RB8a RB, INS - | decode_RB8b RB - |5: - | sltu AT, RD, RB - | bnez AT, >6 // More results expected? - |. decode_RA8a TMP0, INS - | decode_RA8b TMP0 - | ins_next1 - | // Adjust BASE. KBASE is assumed to be set for the calling frame. - | dsubu BASE, RA, TMP0 - | ins_next2 - | - |6: // Fill up results with nil. - | daddu TMP1, RA, RD - | daddiu RD, RD, 8 - | b <5 - |. sd TISNIL, -8(TMP1) - | - |.macro math_extern, func - | .ffunc_n math_ .. func - | load_got func - | call_extern - |. nop - | b ->fff_resn - |. nop - |.endmacro - | - |.macro math_extern2, func - | .ffunc_nn math_ .. func - |. load_got func - | call_extern - |. nop - | b ->fff_resn - |. nop - |.endmacro - | - |// TODO: Return integer type if result is integer (own sf implementation). - |.macro math_round, func - |->ff_math_ .. func: - | ld CARG1, 0(BASE) - | beqz NARGS8:RC, ->fff_fallback - |. gettp TMP0, CARG1 - | beq TMP0, TISNUM, ->fff_restv - |. sltu AT, TMP0, TISNUM - | beqz AT, ->fff_fallback - |.if FPU - |. ldc1 FARG1, 0(BASE) - | bal ->vm_ .. func - |. nop - |.else - |. load_got func - | call_extern - |. nop - |.endif - | b ->fff_resn - |. nop - |.endmacro - | - | math_round floor - | math_round ceil - | - |.ffunc math_log - | li AT, 8 - | bne NARGS8:RC, AT, ->fff_fallback // Exactly 1 argument. - |. ld CARG1, 0(BASE) - | checknum CARG1, ->fff_fallback - |. load_got log - |.if FPU - | call_extern - |. ldc1 FARG1, 0(BASE) - |.else - | call_extern - |. nop - |.endif - | b ->fff_resn - |. nop - | - | math_extern log10 - | math_extern exp - | math_extern sin - | math_extern cos - | math_extern tan - | math_extern asin - | math_extern acos - | math_extern atan - | math_extern sinh - | math_extern cosh - | math_extern tanh - | math_extern2 pow - | math_extern2 atan2 - | math_extern2 fmod - | - |.if FPU - |.ffunc_n math_sqrt - |. sqrt.d FRET1, FARG1 - |// fallthrough to ->fff_resn - |.else - | math_extern sqrt - |.endif - | - |->fff_resn: - | ld PC, FRAME_PC(BASE) - | daddiu RA, BASE, -16 - | b ->fff_res1 - |.if FPU - |. sdc1 FRET1, 0(RA) - |.else - |. sd CRET1, 0(RA) - |.endif - | - | - |.ffunc_2 math_ldexp - | checknum CARG1, ->fff_fallback - | checkint CARG2, ->fff_fallback - |. load_got ldexp - | .FPU ldc1 FARG1, 0(BASE) - | call_extern - |. lw CARG2, 8+LO(BASE) - | b ->fff_resn - |. nop - | - |.ffunc_n math_frexp - | load_got frexp - | ld PC, FRAME_PC(BASE) - | call_extern - |. daddiu CARG2, DISPATCH, DISPATCH_GL(tmptv) - | lw TMP1, DISPATCH_GL(tmptv)(DISPATCH) - | daddiu RA, BASE, -16 - |.if FPU - | mtc1 TMP1, FARG2 - | sdc1 FRET1, 0(RA) - | cvt.d.w FARG2, FARG2 - | sdc1 FARG2, 8(RA) - |.else - | sd CRET1, 0(RA) - | zextw TMP1, TMP1 - | settp TMP1, TISNUM - | sd TMP1, 8(RA) - |.endif - | b ->fff_res - |. li RD, (2+1)*8 - | - |.ffunc_n math_modf - | load_got modf - | ld PC, FRAME_PC(BASE) - | call_extern - |. daddiu CARG2, BASE, -16 - | daddiu RA, BASE, -16 - |.if FPU - | sdc1 FRET1, -8(BASE) - |.else - | sd CRET1, -8(BASE) - |.endif - | b ->fff_res - |. li RD, (2+1)*8 - | - |.macro math_minmax, name, intins, fpins - | .ffunc_1 name - | daddu TMP3, BASE, NARGS8:RC - | checkint CARG1, >5 - |. daddiu TMP2, BASE, 8 - |1: // Handle integers. - | beq TMP2, TMP3, ->fff_restv - |. ld CARG2, 0(TMP2) - | checkint CARG2, >3 - |. sextw CARG1, CARG1 - | lw CARG2, LO(TMP2) - |. slt AT, CARG1, CARG2 - | intins CARG1, CARG2, AT - | daddiu TMP2, TMP2, 8 - | zextw CARG1, CARG1 - | b <1 - |. settp CARG1, TISNUM - | - |3: // Convert intermediate result to number and continue with number loop. - | checknum CARG2, ->fff_fallback - |.if FPU - |. mtc1 CARG1, FRET1 - | cvt.d.w FRET1, FRET1 - | b >7 - |. ldc1 FARG1, 0(TMP2) - |.else - |. nop - | bal ->vm_sfi2d_1 - |. nop - | b >7 - |. nop - |.endif - | - |5: - | .FPU ldc1 FRET1, 0(BASE) - | checknum CARG1, ->fff_fallback - |6: // Handle numbers. - |. ld CARG2, 0(TMP2) - | beq TMP2, TMP3, ->fff_resn - |.if FPU - | ldc1 FARG1, 0(TMP2) - |.else - | move CRET1, CARG1 - |.endif - | checknum CARG2, >8 - |. nop - |7: - |.if FPU - | c.olt.d FRET1, FARG1 - | fpins FRET1, FARG1 - |.else - | bal ->vm_sfcmpolt - |. nop - | intins CARG1, CARG2, CRET1 - |.endif - | b <6 - |. daddiu TMP2, TMP2, 8 - | - |8: // Convert integer to number and continue with number loop. - | checkint CARG2, ->fff_fallback - |.if FPU - |. lwc1 FARG1, LO(TMP2) - | b <7 - |. cvt.d.w FARG1, FARG1 - |.else - |. lw CARG2, LO(TMP2) - | bal ->vm_sfi2d_2 - |. nop - | b <7 - |. nop - |.endif - | - |.endmacro - | - | math_minmax math_min, movz, movf.d - | math_minmax math_max, movn, movt.d - | - |//-- String library ----------------------------------------------------- - | - |.ffunc string_byte // Only handle the 1-arg case here. - | ld CARG1, 0(BASE) - | gettp TMP0, CARG1 - | xori AT, NARGS8:RC, 8 - | daddiu TMP0, TMP0, -LJ_TSTR - | or AT, AT, TMP0 - | bnez AT, ->fff_fallback // Need exactly 1 string argument. - |. cleartp STR:CARG1 - | lw TMP0, STR:CARG1->len - | daddiu RA, BASE, -16 - | ld PC, FRAME_PC(BASE) - | sltu RD, r0, TMP0 - | lbu TMP1, STR:CARG1[1] // Access is always ok (NUL at end). - | addiu RD, RD, 1 - | sll RD, RD, 3 // RD = ((str->len != 0)+1)*8 - | settp TMP1, TISNUM - | b ->fff_res - |. sd TMP1, 0(RA) - | - |.ffunc string_char // Only handle the 1-arg case here. - | ffgccheck - |. nop - | ld CARG1, 0(BASE) - | gettp TMP0, CARG1 - | xori AT, NARGS8:RC, 8 // Exactly 1 argument. - | daddiu TMP0, TMP0, -LJ_TISNUM // Integer. - | li TMP1, 255 - | sextw CARG1, CARG1 - | or AT, AT, TMP0 - | sltu TMP1, TMP1, CARG1 // !(255 < n). - | or AT, AT, TMP1 - | bnez AT, ->fff_fallback - |. li CARG3, 1 - | daddiu CARG2, sp, TMPD_OFS - | sb CARG1, TMPD - |->fff_newstr: - | load_got lj_str_new - | sd BASE, L->base - | sd PC, SAVE_PC - | call_intern lj_str_new // (lua_State *L, char *str, size_t l) - |. move CARG1, L - | // Returns GCstr *. - | ld BASE, L->base - |->fff_resstr: - | li AT, LJ_TSTR - | settp CRET1, AT - | b ->fff_restv - |. move CARG1, CRET1 - | - |.ffunc string_sub - | ffgccheck - |. nop - | addiu AT, NARGS8:RC, -16 - | ld TMP0, 0(BASE) - | bltz AT, ->fff_fallback - |. gettp TMP3, TMP0 - | cleartp STR:CARG1, TMP0 - | ld CARG2, 8(BASE) - | beqz AT, >1 - |. li CARG4, -1 - | ld CARG3, 16(BASE) - | checkint CARG3, ->fff_fallback - |. sextw CARG4, CARG3 - |1: - | checkint CARG2, ->fff_fallback - |. li AT, LJ_TSTR - | bne TMP3, AT, ->fff_fallback - |. sextw CARG3, CARG2 - | lw CARG2, STR:CARG1->len - | // STR:CARG1 = str, CARG2 = str->len, CARG3 = start, CARG4 = end - | slt AT, CARG4, r0 - | addiu TMP0, CARG2, 1 - | addu TMP1, CARG4, TMP0 - | slt TMP3, CARG3, r0 - | movn CARG4, TMP1, AT // if (end < 0) end += len+1 - | addu TMP1, CARG3, TMP0 - | movn CARG3, TMP1, TMP3 // if (start < 0) start += len+1 - | li TMP2, 1 - | slt AT, CARG4, r0 - | slt TMP3, r0, CARG3 - | movn CARG4, r0, AT // if (end < 0) end = 0 - | movz CARG3, TMP2, TMP3 // if (start < 1) start = 1 - | slt AT, CARG2, CARG4 - | movn CARG4, CARG2, AT // if (end > len) end = len - | daddu CARG2, STR:CARG1, CARG3 - | subu CARG3, CARG4, CARG3 // len = end - start - | daddiu CARG2, CARG2, sizeof(GCstr)-1 - | bgez CARG3, ->fff_newstr - |. addiu CARG3, CARG3, 1 // len++ - |->fff_emptystr: // Return empty string. - | li AT, LJ_TSTR - | daddiu STR:CARG1, DISPATCH, DISPATCH_GL(strempty) - | b ->fff_restv - |. settp CARG1, AT - | - |.macro ffstring_op, name - | .ffunc string_ .. name - | ffgccheck - |. nop - | beqz NARGS8:RC, ->fff_fallback - |. ld CARG2, 0(BASE) - | checkstr STR:CARG2, ->fff_fallback - | daddiu SBUF:CARG1, DISPATCH, DISPATCH_GL(tmpbuf) - | load_got lj_buf_putstr_ .. name - | ld TMP0, SBUF:CARG1->b - | sd L, SBUF:CARG1->L - | sd BASE, L->base - | sd TMP0, SBUF:CARG1->p - | call_intern extern lj_buf_putstr_ .. name - |. sd PC, SAVE_PC - | load_got lj_buf_tostr - | call_intern lj_buf_tostr - |. move SBUF:CARG1, SBUF:CRET1 - | b ->fff_resstr - |. ld BASE, L->base - |.endmacro - | - |ffstring_op reverse - |ffstring_op lower - |ffstring_op upper - | - |//-- Bit library -------------------------------------------------------- - | - |->vm_tobit_fb: - | beqz TMP1, ->fff_fallback - |.if FPU - |. ldc1 FARG1, 0(BASE) - | add.d FARG1, FARG1, TOBIT - | mfc1 CRET1, FARG1 - | jr ra - |. zextw CRET1, CRET1 - |.else - |// FP number to bit conversion for soft-float. - |->vm_tobit: - | dsll TMP0, CARG1, 1 - | li CARG3, 1076 - | dsrl AT, TMP0, 53 - | dsubu CARG3, CARG3, AT - | sltiu AT, CARG3, 54 - | beqz AT, >1 - |. dextm TMP0, TMP0, 0, 20 - | dinsu TMP0, AT, 21, 21 - | slt AT, CARG1, r0 - | dsrlv CRET1, TMP0, CARG3 - | dsubu TMP0, r0, CRET1 - | movn CRET1, TMP0, AT - | jr ra - |. zextw CRET1, CRET1 - |1: - | jr ra - |. move CRET1, r0 - | - |// FP number to int conversion with a check for soft-float. - |// Modifies CARG1, CRET1, CRET2, TMP0, AT. - |->vm_tointg: - |.if JIT - | dsll CRET2, CARG1, 1 - | beqz CRET2, >2 - |. li TMP0, 1076 - | dsrl AT, CRET2, 53 - | dsubu TMP0, TMP0, AT - | sltiu AT, TMP0, 54 - | beqz AT, >1 - |. dextm CRET2, CRET2, 0, 20 - | dinsu CRET2, AT, 21, 21 - | slt AT, CARG1, r0 - | dsrlv CRET1, CRET2, TMP0 - | dsubu CARG1, r0, CRET1 - | movn CRET1, CARG1, AT - | li CARG1, 64 - | subu TMP0, CARG1, TMP0 - | dsllv CRET2, CRET2, TMP0 // Integer check. - | sextw AT, CRET1 - | xor AT, CRET1, AT // Range check. - | jr ra - |. movz CRET2, AT, CRET2 - |1: - | jr ra - |. li CRET2, 1 - |2: - | jr ra - |. move CRET1, r0 - |.endif - |.endif - | - |.macro .ffunc_bit, name - | .ffunc_1 bit_..name - | gettp TMP0, CARG1 - | beq TMP0, TISNUM, >6 - |. zextw CRET1, CARG1 - | bal ->vm_tobit_fb - |. sltiu TMP1, TMP0, LJ_TISNUM - |6: - |.endmacro - | - |.macro .ffunc_bit_op, name, bins - | .ffunc_bit name - | daddiu TMP2, BASE, 8 - | daddu TMP3, BASE, NARGS8:RC - |1: - | beq TMP2, TMP3, ->fff_resi - |. ld CARG1, 0(TMP2) - | gettp TMP0, CARG1 - |.if FPU - | bne TMP0, TISNUM, >2 - |. daddiu TMP2, TMP2, 8 - | zextw CARG1, CARG1 - | b <1 - |. bins CRET1, CRET1, CARG1 - |2: - | ldc1 FARG1, -8(TMP2) - | sltiu AT, TMP0, LJ_TISNUM - | beqz AT, ->fff_fallback - |. add.d FARG1, FARG1, TOBIT - | mfc1 CARG1, FARG1 - | zextw CARG1, CARG1 - | b <1 - |. bins CRET1, CRET1, CARG1 - |.else - | beq TMP0, TISNUM, >2 - |. move CRET2, CRET1 - | bal ->vm_tobit_fb - |. sltiu TMP1, TMP0, LJ_TISNUM - | move CARG1, CRET2 - |2: - | zextw CARG1, CARG1 - | bins CRET1, CRET1, CARG1 - | b <1 - |. daddiu TMP2, TMP2, 8 - |.endif - |.endmacro - | - |.ffunc_bit_op band, and - |.ffunc_bit_op bor, or - |.ffunc_bit_op bxor, xor - | - |.ffunc_bit bswap - | dsrl TMP0, CRET1, 8 - | dsrl TMP1, CRET1, 24 - | andi TMP2, TMP0, 0xff00 - | dins TMP1, CRET1, 24, 31 - | dins TMP2, TMP0, 16, 23 - | b ->fff_resi - |. or CRET1, TMP1, TMP2 - | - |.ffunc_bit bnot - | not CRET1, CRET1 - | b ->fff_resi - |. zextw CRET1, CRET1 - | - |.macro .ffunc_bit_sh, name, shins, shmod - | .ffunc_2 bit_..name - | gettp TMP0, CARG1 - | beq TMP0, TISNUM, >1 - |. nop - | bal ->vm_tobit_fb - |. sltiu TMP1, TMP0, LJ_TISNUM - | move CARG1, CRET1 - |1: - | gettp TMP0, CARG2 - | bne TMP0, TISNUM, ->fff_fallback - |. zextw CARG2, CARG2 - | sextw CARG1, CARG1 - |.if shmod == 1 - | negu CARG2, CARG2 - |.endif - | shins CRET1, CARG1, CARG2 - | b ->fff_resi - |. zextw CRET1, CRET1 - |.endmacro - | - |.ffunc_bit_sh lshift, sllv, 0 - |.ffunc_bit_sh rshift, srlv, 0 - |.ffunc_bit_sh arshift, srav, 0 - |.ffunc_bit_sh rol, rotrv, 1 - |.ffunc_bit_sh ror, rotrv, 0 - | - |.ffunc_bit tobit - |->fff_resi: - | ld PC, FRAME_PC(BASE) - | daddiu RA, BASE, -16 - | settp CRET1, TISNUM - | b ->fff_res1 - |. sd CRET1, -16(BASE) - | - |//----------------------------------------------------------------------- - |->fff_fallback: // Call fast function fallback handler. - | // BASE = new base, RB = CFUNC, RC = nargs*8 - | ld TMP3, CFUNC:RB->f - | daddu TMP1, BASE, NARGS8:RC - | ld PC, FRAME_PC(BASE) // Fallback may overwrite PC. - | daddiu TMP0, TMP1, 8*LUA_MINSTACK - | ld TMP2, L->maxstack - | sd PC, SAVE_PC // Redundant (but a defined value). - | sltu AT, TMP2, TMP0 - | sd BASE, L->base - | sd TMP1, L->top - | bnez AT, >5 // Need to grow stack. - |. move CFUNCADDR, TMP3 - | jalr TMP3 // (lua_State *L) - |. move CARG1, L - | // Either throws an error, or recovers and returns -1, 0 or nresults+1. - | ld BASE, L->base - | sll RD, CRET1, 3 - | bgtz CRET1, ->fff_res // Returned nresults+1? - |. daddiu RA, BASE, -16 - |1: // Returned 0 or -1: retry fast path. - | ld LFUNC:RB, FRAME_FUNC(BASE) - | ld TMP0, L->top - | cleartp LFUNC:RB - | bnez CRET1, ->vm_call_tail // Returned -1? - |. dsubu NARGS8:RC, TMP0, BASE - | ins_callt // Returned 0: retry fast path. - | - |// Reconstruct previous base for vmeta_call during tailcall. - |->vm_call_tail: - | andi TMP0, PC, FRAME_TYPE - | li AT, -4 - | bnez TMP0, >3 - |. and TMP1, PC, AT - | lbu TMP1, OFS_RA(PC) - | sll TMP1, TMP1, 3 - | addiu TMP1, TMP1, 16 - |3: - | b ->vm_call_dispatch // Resolve again for tailcall. - |. dsubu TMP2, BASE, TMP1 - | - |5: // Grow stack for fallback handler. - | load_got lj_state_growstack - | li CARG2, LUA_MINSTACK - | call_intern lj_state_growstack // (lua_State *L, int n) - |. move CARG1, L - | ld BASE, L->base - | b <1 - |. li CRET1, 0 // Force retry. - | - |->fff_gcstep: // Call GC step function. - | // BASE = new base, RC = nargs*8 - | move MULTRES, ra - | load_got lj_gc_step - | sd BASE, L->base - | daddu TMP0, BASE, NARGS8:RC - | sd PC, SAVE_PC // Redundant (but a defined value). - | sd TMP0, L->top - | call_intern lj_gc_step // (lua_State *L) - |. move CARG1, L - | ld BASE, L->base - | move ra, MULTRES - | ld TMP0, L->top - | ld CFUNC:RB, FRAME_FUNC(BASE) - | cleartp CFUNC:RB - | jr ra - |. dsubu NARGS8:RC, TMP0, BASE - | - |//----------------------------------------------------------------------- - |//-- Special dispatch targets ------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_record: // Dispatch target for recording phase. - |.if JIT - | lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH) - | andi AT, TMP3, HOOK_VMEVENT // No recording while in vmevent. - | bnez AT, >5 - | // Decrement the hookcount for consistency, but always do the call. - |. lw TMP2, DISPATCH_GL(hookcount)(DISPATCH) - | andi AT, TMP3, HOOK_ACTIVE - | bnez AT, >1 - |. addiu TMP2, TMP2, -1 - | andi AT, TMP3, LUA_MASKLINE|LUA_MASKCOUNT - | beqz AT, >1 - |. nop - | b >1 - |. sw TMP2, DISPATCH_GL(hookcount)(DISPATCH) - |.endif - | - |->vm_rethook: // Dispatch target for return hooks. - | lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH) - | andi AT, TMP3, HOOK_ACTIVE // Hook already active? - | beqz AT, >1 - |5: // Re-dispatch to static ins. - |. ld AT, GG_DISP2STATIC(TMP0) // Assumes TMP0 holds DISPATCH+OP*4. - | jr AT - |. nop - | - |->vm_inshook: // Dispatch target for instr/line hooks. - | lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH) - | lw TMP2, DISPATCH_GL(hookcount)(DISPATCH) - | andi AT, TMP3, HOOK_ACTIVE // Hook already active? - | bnez AT, <5 - |. andi AT, TMP3, LUA_MASKLINE|LUA_MASKCOUNT - | beqz AT, <5 - |. addiu TMP2, TMP2, -1 - | beqz TMP2, >1 - |. sw TMP2, DISPATCH_GL(hookcount)(DISPATCH) - | andi AT, TMP3, LUA_MASKLINE - | beqz AT, <5 - |1: - |. load_got lj_dispatch_ins - | sw MULTRES, SAVE_MULTRES - | move CARG2, PC - | sd BASE, L->base - | // SAVE_PC must hold the _previous_ PC. The callee updates it with PC. - | call_intern lj_dispatch_ins // (lua_State *L, const BCIns *pc) - |. move CARG1, L - |3: - | ld BASE, L->base - |4: // Re-dispatch to static ins. - | lw INS, -4(PC) - | decode_OP8a TMP1, INS - | decode_OP8b TMP1 - | daddu TMP0, DISPATCH, TMP1 - | decode_RD8a RD, INS - | ld AT, GG_DISP2STATIC(TMP0) - | decode_RA8a RA, INS - | decode_RD8b RD - | jr AT - | decode_RA8b RA - | - |->cont_hook: // Continue from hook yield. - | daddiu PC, PC, 4 - | b <4 - |. lw MULTRES, -24+LO(RB) // Restore MULTRES for *M ins. - | - |->vm_hotloop: // Hot loop counter underflow. - |.if JIT - | ld LFUNC:TMP1, FRAME_FUNC(BASE) - | daddiu CARG1, DISPATCH, GG_DISP2J - | cleartp LFUNC:TMP1 - | sd PC, SAVE_PC - | ld TMP1, LFUNC:TMP1->pc - | move CARG2, PC - | sd L, DISPATCH_J(L)(DISPATCH) - | lbu TMP1, PC2PROTO(framesize)(TMP1) - | load_got lj_trace_hot - | sd BASE, L->base - | dsll TMP1, TMP1, 3 - | daddu TMP1, BASE, TMP1 - | call_intern lj_trace_hot // (jit_State *J, const BCIns *pc) - |. sd TMP1, L->top - | b <3 - |. nop - |.endif - | - | - |->vm_callhook: // Dispatch target for call hooks. - |.if JIT - | b >1 - |.endif - |. move CARG2, PC - | - |->vm_hotcall: // Hot call counter underflow. - |.if JIT - | ori CARG2, PC, 1 - |1: - |.endif - | load_got lj_dispatch_call - | daddu TMP0, BASE, RC - | sd PC, SAVE_PC - | sd BASE, L->base - | dsubu RA, RA, BASE - | sd TMP0, L->top - | call_intern lj_dispatch_call // (lua_State *L, const BCIns *pc) - |. move CARG1, L - | // Returns ASMFunction. - | ld BASE, L->base - | ld TMP0, L->top - | sd r0, SAVE_PC // Invalidate for subsequent line hook. - | dsubu NARGS8:RC, TMP0, BASE - | daddu RA, BASE, RA - | ld LFUNC:RB, FRAME_FUNC(BASE) - | cleartp LFUNC:RB - | jr CRET1 - |. lw INS, -4(PC) - | - |->cont_stitch: // Trace stitching. - |.if JIT - | // RA = resultptr, RB = meta base - | lw INS, -4(PC) - | ld TRACE:TMP2, -40(RB) // Save previous trace. - | decode_RA8a RC, INS - | daddiu AT, MULTRES, -8 - | cleartp TRACE:TMP2 - | decode_RA8b RC - | beqz AT, >2 - |. daddu RC, BASE, RC // Call base. - |1: // Move results down. - | ld CARG1, 0(RA) - | daddiu AT, AT, -8 - | daddiu RA, RA, 8 - | sd CARG1, 0(RC) - | bnez AT, <1 - |. daddiu RC, RC, 8 - |2: - | decode_RA8a RA, INS - | decode_RB8a RB, INS - | decode_RA8b RA - | decode_RB8b RB - | daddu RA, RA, RB - | daddu RA, BASE, RA - |3: - | sltu AT, RC, RA - | bnez AT, >9 // More results wanted? - |. nop - | - | lhu TMP3, TRACE:TMP2->traceno - | lhu RD, TRACE:TMP2->link - | beq RD, TMP3, ->cont_nop // Blacklisted. - |. load_got lj_dispatch_stitch - | bnez RD, =>BC_JLOOP // Jump to stitched trace. - |. sll RD, RD, 3 - | - | // Stitch a new trace to the previous trace. - | sw TMP3, DISPATCH_J(exitno)(DISPATCH) - | sd L, DISPATCH_J(L)(DISPATCH) - | sd BASE, L->base - | daddiu CARG1, DISPATCH, GG_DISP2J - | call_intern lj_dispatch_stitch // (jit_State *J, const BCIns *pc) - |. move CARG2, PC - | b ->cont_nop - |. ld BASE, L->base - | - |9: - | sd TISNIL, 0(RC) - | b <3 - |. daddiu RC, RC, 8 - |.endif - | - |->vm_profhook: // Dispatch target for profiler hook. -#if LJ_HASPROFILE - | load_got lj_dispatch_profile - | sw MULTRES, SAVE_MULTRES - | move CARG2, PC - | sd BASE, L->base - | call_intern lj_dispatch_profile // (lua_State *L, const BCIns *pc) - |. move CARG1, L - | // HOOK_PROFILE is off again, so re-dispatch to dynamic instruction. - | daddiu PC, PC, -4 - | b ->cont_nop - |. ld BASE, L->base -#endif - | - |//----------------------------------------------------------------------- - |//-- Trace exit handler ------------------------------------------------- - |//----------------------------------------------------------------------- - | - |.macro savex_, a, b - |.if FPU - | sdc1 f..a, a*8(sp) - | sdc1 f..b, b*8(sp) - | sd r..a, 32*8+a*8(sp) - | sd r..b, 32*8+b*8(sp) - |.else - | sd r..a, a*8(sp) - | sd r..b, b*8(sp) - |.endif - |.endmacro - | - |->vm_exit_handler: - |.if JIT - |.if FPU - | daddiu sp, sp, -(32*8+32*8) - |.else - | daddiu sp, sp, -(32*8) - |.endif - | savex_ 0, 1 - | savex_ 2, 3 - | savex_ 4, 5 - | savex_ 6, 7 - | savex_ 8, 9 - | savex_ 10, 11 - | savex_ 12, 13 - | savex_ 14, 15 - | savex_ 16, 17 - | savex_ 18, 19 - | savex_ 20, 21 - | savex_ 22, 23 - | savex_ 24, 25 - | savex_ 26, 27 - | savex_ 28, 30 - |.if FPU - | sdc1 f29, 29*8(sp) - | sdc1 f31, 31*8(sp) - | sd r0, 32*8+31*8(sp) // Clear RID_TMP. - | daddiu TMP2, sp, 32*8+32*8 // Recompute original value of sp. - | sd TMP2, 32*8+29*8(sp) // Store sp in RID_SP - |.else - | sd r0, 31*8(sp) // Clear RID_TMP. - | daddiu TMP2, sp, 32*8 // Recompute original value of sp. - | sd TMP2, 29*8(sp) // Store sp in RID_SP - |.endif - | li_vmstate EXIT - | daddiu DISPATCH, JGL, -GG_DISP2G-32768 - | lw TMP1, 0(TMP2) // Load exit number. - | st_vmstate - | ld L, DISPATCH_GL(cur_L)(DISPATCH) - | ld BASE, DISPATCH_GL(jit_base)(DISPATCH) - | load_got lj_trace_exit - | sd L, DISPATCH_J(L)(DISPATCH) - | sw ra, DISPATCH_J(parent)(DISPATCH) // Store trace number. - | sd BASE, L->base - | sw TMP1, DISPATCH_J(exitno)(DISPATCH) // Store exit number. - | daddiu CARG1, DISPATCH, GG_DISP2J - | sd r0, DISPATCH_GL(jit_base)(DISPATCH) - | call_intern lj_trace_exit // (jit_State *J, ExitState *ex) - |. move CARG2, sp - | // Returns MULTRES (unscaled) or negated error code. - | ld TMP1, L->cframe - | li AT, -4 - | ld BASE, L->base - | and sp, TMP1, AT - | ld PC, SAVE_PC // Get SAVE_PC. - | b >1 - |. sd L, SAVE_L // Set SAVE_L (on-trace resume/yield). - |.endif - |->vm_exit_interp: - |.if JIT - | // CRET1 = MULTRES or negated error code, BASE, PC and JGL set. - | ld L, SAVE_L - | daddiu DISPATCH, JGL, -GG_DISP2G-32768 - | sd BASE, L->base - |1: - | bltz CRET1, >9 // Check for error from exit. - |. ld LFUNC:RB, FRAME_FUNC(BASE) - | .FPU lui TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float). - | dsll MULTRES, CRET1, 3 - | cleartp LFUNC:RB - | sw MULTRES, SAVE_MULTRES - | li TISNIL, LJ_TNIL - | li TISNUM, LJ_TISNUM // Setup type comparison constants. - | .FPU mtc1 TMP3, TOBIT - | ld TMP1, LFUNC:RB->pc - | sd r0, DISPATCH_GL(jit_base)(DISPATCH) - | ld KBASE, PC2PROTO(k)(TMP1) - | .FPU cvt.d.s TOBIT, TOBIT - | // Modified copy of ins_next which handles function header dispatch, too. - | lw INS, 0(PC) - | daddiu PC, PC, 4 - | // Assumes TISNIL == ~LJ_VMST_INTERP == -1 - | sw TISNIL, DISPATCH_GL(vmstate)(DISPATCH) - | decode_OP8a TMP1, INS - | decode_OP8b TMP1 - | sltiu TMP2, TMP1, BC_FUNCF*8 - | daddu TMP0, DISPATCH, TMP1 - | decode_RD8a RD, INS - | ld AT, 0(TMP0) - | decode_RA8a RA, INS - | beqz TMP2, >2 - |. decode_RA8b RA - | jr AT - |. decode_RD8b RD - |2: - | sltiu TMP2, TMP1, (BC_FUNCC+2)*8 // Fast function? - | bnez TMP2, >3 - |. ld TMP1, FRAME_PC(BASE) - | // Check frame below fast function. - | andi TMP0, TMP1, FRAME_TYPE - | bnez TMP0, >3 // Trace stitching continuation? - |. nop - | // Otherwise set KBASE for Lua function below fast function. - | lw TMP2, -4(TMP1) - | decode_RA8a TMP0, TMP2 - | decode_RA8b TMP0 - | dsubu TMP1, BASE, TMP0 - | ld LFUNC:TMP2, -32(TMP1) - | cleartp LFUNC:TMP2 - | ld TMP1, LFUNC:TMP2->pc - | ld KBASE, PC2PROTO(k)(TMP1) - |3: - | daddiu RC, MULTRES, -8 - | jr AT - |. daddu RA, RA, BASE - | - |9: // Rethrow error from the right C frame. - | load_got lj_err_throw - | negu CARG2, CRET1 - | call_intern lj_err_throw // (lua_State *L, int errcode) - |. move CARG1, L - |.endif - | - |//----------------------------------------------------------------------- - |//-- Math helper functions ---------------------------------------------- - |//----------------------------------------------------------------------- - | - |// Hard-float round to integer. - |// Modifies AT, TMP0, FRET1, FRET2, f4. Keeps all others incl. FARG1. - |.macro vm_round_hf, func - | lui TMP0, 0x4330 // Hiword of 2^52 (double). - | dsll TMP0, TMP0, 32 - | dmtc1 TMP0, f4 - | abs.d FRET2, FARG1 // |x| - | dmfc1 AT, FARG1 - | c.olt.d 0, FRET2, f4 - | add.d FRET1, FRET2, f4 // (|x| + 2^52) - 2^52 - | bc1f 0, >1 // Truncate only if |x| < 2^52. - |. sub.d FRET1, FRET1, f4 - | slt AT, AT, r0 - |.if "func" == "ceil" - | lui TMP0, 0xbff0 // Hiword of -1 (double). Preserves -0. - |.else - | lui TMP0, 0x3ff0 // Hiword of +1 (double). - |.endif - |.if "func" == "trunc" - | dsll TMP0, TMP0, 32 - | dmtc1 TMP0, f4 - | c.olt.d 0, FRET2, FRET1 // |x| < result? - | sub.d FRET2, FRET1, f4 - | movt.d FRET1, FRET2, 0 // If yes, subtract +1. - | neg.d FRET2, FRET1 - | jr ra - |. movn.d FRET1, FRET2, AT // Merge sign bit back in. - |.else - | neg.d FRET2, FRET1 - | dsll TMP0, TMP0, 32 - | dmtc1 TMP0, f4 - | movn.d FRET1, FRET2, AT // Merge sign bit back in. - |.if "func" == "ceil" - | c.olt.d 0, FRET1, FARG1 // x > result? - |.else - | c.olt.d 0, FARG1, FRET1 // x < result? - |.endif - | sub.d FRET2, FRET1, f4 // If yes, subtract +-1. - | jr ra - |. movt.d FRET1, FRET2, 0 - |.endif - |1: - | jr ra - |. mov.d FRET1, FARG1 - |.endmacro - | - |.macro vm_round, func - |.if FPU - | vm_round_hf, func - |.endif - |.endmacro - | - |->vm_floor: - | vm_round floor - |->vm_ceil: - | vm_round ceil - |->vm_trunc: - |.if JIT - | vm_round trunc - |.endif - | - |// Soft-float integer to number conversion. - |.macro sfi2d, ARG - |.if not FPU - | beqz ARG, >9 // Handle zero first. - |. sra TMP0, ARG, 31 - | xor TMP1, ARG, TMP0 - | dsubu TMP1, TMP1, TMP0 // Absolute value in TMP1. - | dclz ARG, TMP1 - | addiu ARG, ARG, -11 - | li AT, 0x3ff+63-11-1 - | dsllv TMP1, TMP1, ARG // Align mantissa left with leading 1. - | subu ARG, AT, ARG // Exponent - 1. - | ins ARG, TMP0, 11, 11 // Sign | Exponent. - | dsll ARG, ARG, 52 // Align left. - | jr ra - |. daddu ARG, ARG, TMP1 // Add mantissa, increment exponent. - |9: - | jr ra - |. nop - |.endif - |.endmacro - | - |// Input CARG1. Output: CARG1. Temporaries: AT, TMP0, TMP1. - |->vm_sfi2d_1: - | sfi2d CARG1 - | - |// Input CARG2. Output: CARG2. Temporaries: AT, TMP0, TMP1. - |->vm_sfi2d_2: - | sfi2d CARG2 - | - |// Soft-float comparison. Equivalent to c.eq.d. - |// Input: CARG*. Output: CRET1. Temporaries: AT, TMP0, TMP1. - |->vm_sfcmpeq: - |.if not FPU - | dsll AT, CARG1, 1 - | dsll TMP0, CARG2, 1 - | or TMP1, AT, TMP0 - | beqz TMP1, >8 // Both args +-0: return 1. - |. lui TMP1, 0xffe0 - | dsll TMP1, TMP1, 32 - | sltu AT, TMP1, AT - | sltu TMP0, TMP1, TMP0 - | or TMP1, AT, TMP0 - | bnez TMP1, >9 // Either arg is NaN: return 0; - |. xor AT, CARG1, CARG2 - | jr ra - |. sltiu CRET1, AT, 1 // Same values: return 1. - |8: - | jr ra - |. li CRET1, 1 - |9: - | jr ra - |. li CRET1, 0 - |.endif - | - |// Soft-float comparison. Equivalent to c.ult.d and c.olt.d. - |// Input: CARG1, CARG2. Output: CRET1. Temporaries: AT, TMP0, TMP1, CRET2. - |->vm_sfcmpult: - |.if not FPU - | b >1 - |. li CRET2, 1 - |.endif - | - |->vm_sfcmpolt: - |.if not FPU - | li CRET2, 0 - |1: - | dsll AT, CARG1, 1 - | dsll TMP0, CARG2, 1 - | or TMP1, AT, TMP0 - | beqz TMP1, >8 // Both args +-0: return 0. - |. lui TMP1, 0xffe0 - | dsll TMP1, TMP1, 32 - | sltu AT, TMP1, AT - | sltu TMP0, TMP1, TMP0 - | or TMP1, AT, TMP0 - | bnez TMP1, >9 // Either arg is NaN: return 0 or 1; - |. and AT, CARG1, CARG2 - | bltz AT, >5 // Both args negative? - |. nop - | jr ra - |. slt CRET1, CARG1, CARG2 - |5: // Swap conditions if both operands are negative. - | jr ra - |. slt CRET1, CARG2, CARG1 - |8: - | jr ra - |. li CRET1, 0 - |9: - | jr ra - |. move CRET1, CRET2 - |.endif - | - |// Soft-float comparison. Equivalent to c.ole.d a, b or c.ole.d b, a. - |// Input: CARG1, CARG2, TMP3. Output: CRET1. Temporaries: AT, TMP0, TMP1. - |->vm_sfcmpolex: - |.if not FPU - | dsll AT, CARG1, 1 - | dsll TMP0, CARG2, 1 - | or TMP1, AT, TMP0 - | beqz TMP1, >8 // Both args +-0: return 1. - |. lui TMP1, 0xffe0 - | dsll TMP1, TMP1, 32 - | sltu AT, TMP1, AT - | sltu TMP0, TMP1, TMP0 - | or TMP1, AT, TMP0 - | bnez TMP1, >9 // Either arg is NaN: return 0; - |. and AT, CARG1, CARG2 - | xor AT, AT, TMP3 - | bltz AT, >5 // Both args negative? - |. nop - | jr ra - |. slt CRET1, CARG2, CARG1 - |5: // Swap conditions if both operands are negative. - | jr ra - |. slt CRET1, CARG1, CARG2 - |8: - | jr ra - |. li CRET1, 1 - |9: - | jr ra - |. li CRET1, 0 - |.endif - | - |.macro sfmin_max, name, intins - |->vm_sf .. name: - |.if JIT and not FPU - | move TMP2, ra - | bal ->vm_sfcmpolt - |. nop - | move ra, TMP2 - | move TMP0, CRET1 - | move CRET1, CARG1 - | jr ra - |. intins CRET1, CARG2, TMP0 - |.endif - |.endmacro - | - | sfmin_max min, movz - | sfmin_max max, movn - | - |//----------------------------------------------------------------------- - |//-- Miscellaneous functions -------------------------------------------- - |//----------------------------------------------------------------------- - | - |//----------------------------------------------------------------------- - |//-- FFI helper functions ----------------------------------------------- - |//----------------------------------------------------------------------- - | - |// Handler for callback functions. Callback slot number in r1, g in r2. - |->vm_ffi_callback: - |.if FFI - |.type CTSTATE, CTState, PC - | saveregs - | ld CTSTATE, GL:r2->ctype_state - | daddiu DISPATCH, r2, GG_G2DISP - | load_got lj_ccallback_enter - | sw r1, CTSTATE->cb.slot - | sd CARG1, CTSTATE->cb.gpr[0] - | .FPU sdc1 FARG1, CTSTATE->cb.fpr[0] - | sd CARG2, CTSTATE->cb.gpr[1] - | .FPU sdc1 FARG2, CTSTATE->cb.fpr[1] - | sd CARG3, CTSTATE->cb.gpr[2] - | .FPU sdc1 FARG3, CTSTATE->cb.fpr[2] - | sd CARG4, CTSTATE->cb.gpr[3] - | .FPU sdc1 FARG4, CTSTATE->cb.fpr[3] - | sd CARG5, CTSTATE->cb.gpr[4] - | .FPU sdc1 FARG5, CTSTATE->cb.fpr[4] - | sd CARG6, CTSTATE->cb.gpr[5] - | .FPU sdc1 FARG6, CTSTATE->cb.fpr[5] - | sd CARG7, CTSTATE->cb.gpr[6] - | .FPU sdc1 FARG7, CTSTATE->cb.fpr[6] - | sd CARG8, CTSTATE->cb.gpr[7] - | .FPU sdc1 FARG8, CTSTATE->cb.fpr[7] - | daddiu TMP0, sp, CFRAME_SPACE - | sd TMP0, CTSTATE->cb.stack - | sd r0, SAVE_PC // Any value outside of bytecode is ok. - | move CARG2, sp - | call_intern lj_ccallback_enter // (CTState *cts, void *cf) - |. move CARG1, CTSTATE - | // Returns lua_State *. - | ld BASE, L:CRET1->base - | ld RC, L:CRET1->top - | move L, CRET1 - | .FPU lui TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float). - | ld LFUNC:RB, FRAME_FUNC(BASE) - | .FPU mtc1 TMP3, TOBIT - | li TISNIL, LJ_TNIL - | li TISNUM, LJ_TISNUM - | li_vmstate INTERP - | subu RC, RC, BASE - | cleartp LFUNC:RB - | st_vmstate - | .FPU cvt.d.s TOBIT, TOBIT - | ins_callt - |.endif - | - |->cont_ffi_callback: // Return from FFI callback. - |.if FFI - | load_got lj_ccallback_leave - | ld CTSTATE, DISPATCH_GL(ctype_state)(DISPATCH) - | sd BASE, L->base - | sd RB, L->top - | sd L, CTSTATE->L - | move CARG2, RA - | call_intern lj_ccallback_leave // (CTState *cts, TValue *o) - |. move CARG1, CTSTATE - | .FPU ldc1 FRET1, CTSTATE->cb.fpr[0] - | ld CRET1, CTSTATE->cb.gpr[0] - | .FPU ldc1 FRET2, CTSTATE->cb.fpr[1] - | b ->vm_leave_unw - |. ld CRET2, CTSTATE->cb.gpr[1] - |.endif - | - |->vm_ffi_call: // Call C function via FFI. - | // Caveat: needs special frame unwinding, see below. - |.if FFI - | .type CCSTATE, CCallState, CARG1 - | lw TMP1, CCSTATE->spadj - | lbu CARG2, CCSTATE->nsp - | move TMP2, sp - | dsubu sp, sp, TMP1 - | sd ra, -8(TMP2) - | sll CARG2, CARG2, 3 - | sd r16, -16(TMP2) - | sd CCSTATE, -24(TMP2) - | move r16, TMP2 - | daddiu TMP1, CCSTATE, offsetof(CCallState, stack) - | move TMP2, sp - | beqz CARG2, >2 - |. daddu TMP3, TMP1, CARG2 - |1: - | ld TMP0, 0(TMP1) - | daddiu TMP1, TMP1, 8 - | sltu AT, TMP1, TMP3 - | sd TMP0, 0(TMP2) - | bnez AT, <1 - |. daddiu TMP2, TMP2, 8 - |2: - | ld CFUNCADDR, CCSTATE->func - | .FPU ldc1 FARG1, CCSTATE->gpr[0] - | ld CARG2, CCSTATE->gpr[1] - | .FPU ldc1 FARG2, CCSTATE->gpr[1] - | ld CARG3, CCSTATE->gpr[2] - | .FPU ldc1 FARG3, CCSTATE->gpr[2] - | ld CARG4, CCSTATE->gpr[3] - | .FPU ldc1 FARG4, CCSTATE->gpr[3] - | ld CARG5, CCSTATE->gpr[4] - | .FPU ldc1 FARG5, CCSTATE->gpr[4] - | ld CARG6, CCSTATE->gpr[5] - | .FPU ldc1 FARG6, CCSTATE->gpr[5] - | ld CARG7, CCSTATE->gpr[6] - | .FPU ldc1 FARG7, CCSTATE->gpr[6] - | ld CARG8, CCSTATE->gpr[7] - | .FPU ldc1 FARG8, CCSTATE->gpr[7] - | jalr CFUNCADDR - |. ld CARG1, CCSTATE->gpr[0] // Do this last, since CCSTATE is CARG1. - | ld CCSTATE:TMP1, -24(r16) - | ld TMP2, -16(r16) - | ld ra, -8(r16) - | sd CRET1, CCSTATE:TMP1->gpr[0] - | sd CRET2, CCSTATE:TMP1->gpr[1] - |.if FPU - | sdc1 FRET1, CCSTATE:TMP1->fpr[0] - | sdc1 FRET2, CCSTATE:TMP1->fpr[1] - |.else - | sd CARG1, CCSTATE:TMP1->gpr[2] // 2nd FP struct field for soft-float. - |.endif - | move sp, r16 - | jr ra - |. move r16, TMP2 - |.endif - |// Note: vm_ffi_call must be the last function in this object file! - | - |//----------------------------------------------------------------------- -} - -/* Generate the code for a single instruction. */ -static void build_ins(BuildCtx *ctx, BCOp op, int defop) -{ - int vk = 0; - |=>defop: - - switch (op) { - - /* -- Comparison ops ---------------------------------------------------- */ - - /* Remember: all ops branch for a true comparison, fall through otherwise. */ - - case BC_ISLT: case BC_ISGE: case BC_ISLE: case BC_ISGT: - | // RA = src1*8, RD = src2*8, JMP with RD = target - |.macro bc_comp, FRA, FRD, ARGRA, ARGRD, movop, fmovop, fcomp, sfcomp - | daddu RA, BASE, RA - | daddu RD, BASE, RD - | ld ARGRA, 0(RA) - | ld ARGRD, 0(RD) - | lhu TMP2, OFS_RD(PC) - | gettp CARG3, ARGRA - | gettp CARG4, ARGRD - | bne CARG3, TISNUM, >2 - |. daddiu PC, PC, 4 - | bne CARG4, TISNUM, >5 - |. decode_RD4b TMP2 - | sextw ARGRA, ARGRA - | sextw ARGRD, ARGRD - | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) - | slt AT, CARG1, CARG2 - | addu TMP2, TMP2, TMP3 - | movop TMP2, r0, AT - |1: - | daddu PC, PC, TMP2 - | ins_next - | - |2: // RA is not an integer. - | sltiu AT, CARG3, LJ_TISNUM - | beqz AT, ->vmeta_comp - |. lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) - | sltiu AT, CARG4, LJ_TISNUM - | beqz AT, >4 - |. decode_RD4b TMP2 - |.if FPU - | ldc1 FRA, 0(RA) - | ldc1 FRD, 0(RD) - |.endif - |3: // RA and RD are both numbers. - |.if FPU - | fcomp f20, f22 - | addu TMP2, TMP2, TMP3 - | b <1 - |. fmovop TMP2, r0 - |.else - | bal sfcomp - |. addu TMP2, TMP2, TMP3 - | b <1 - |. movop TMP2, r0, CRET1 - |.endif - | - |4: // RA is a number, RD is not a number. - | bne CARG4, TISNUM, ->vmeta_comp - | // RA is a number, RD is an integer. Convert RD to a number. - |.if FPU - |. lwc1 FRD, LO(RD) - | ldc1 FRA, 0(RA) - | b <3 - |. cvt.d.w FRD, FRD - |.else - |.if "ARGRD" == "CARG1" - |. sextw CARG1, CARG1 - | bal ->vm_sfi2d_1 - |. nop - |.else - |. sextw CARG2, CARG2 - | bal ->vm_sfi2d_2 - |. nop - |.endif - | b <3 - |. nop - |.endif - | - |5: // RA is an integer, RD is not an integer - | sltiu AT, CARG4, LJ_TISNUM - | beqz AT, ->vmeta_comp - |. lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) - | // RA is an integer, RD is a number. Convert RA to a number. - |.if FPU - | lwc1 FRA, LO(RA) - | ldc1 FRD, 0(RD) - | b <3 - | cvt.d.w FRA, FRA - |.else - |.if "ARGRA" == "CARG1" - | bal ->vm_sfi2d_1 - |. sextw CARG1, CARG1 - |.else - | bal ->vm_sfi2d_2 - |. sextw CARG2, CARG2 - |.endif - | b <3 - |. nop - |.endif - |.endmacro - | - if (op == BC_ISLT) { - | bc_comp f20, f22, CARG1, CARG2, movz, movf, c.olt.d, ->vm_sfcmpolt - } else if (op == BC_ISGE) { - | bc_comp f20, f22, CARG1, CARG2, movn, movt, c.olt.d, ->vm_sfcmpolt - } else if (op == BC_ISLE) { - | bc_comp f22, f20, CARG2, CARG1, movn, movt, c.ult.d, ->vm_sfcmpult - } else { - | bc_comp f22, f20, CARG2, CARG1, movz, movf, c.ult.d, ->vm_sfcmpult - } - break; - - case BC_ISEQV: case BC_ISNEV: - vk = op == BC_ISEQV; - | // RA = src1*8, RD = src2*8, JMP with RD = target - | daddu RA, BASE, RA - | daddiu PC, PC, 4 - | daddu RD, BASE, RD - | ld CARG1, 0(RA) - | lhu TMP2, -4+OFS_RD(PC) - | ld CARG2, 0(RD) - | gettp CARG3, CARG1 - | gettp CARG4, CARG2 - | sltu AT, TISNUM, CARG3 - | sltu TMP1, TISNUM, CARG4 - | or AT, AT, TMP1 - if (vk) { - | beqz AT, ->BC_ISEQN_Z - } else { - | beqz AT, ->BC_ISNEN_Z - } - | // Either or both types are not numbers. - | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) - |.if FFI - |. li AT, LJ_TCDATA - | beq CARG3, AT, ->vmeta_equal_cd - |.endif - | decode_RD4b TMP2 - |.if FFI - | beq CARG4, AT, ->vmeta_equal_cd - |. nop - |.endif - | bne CARG1, CARG2, >2 - |. addu TMP2, TMP2, TMP3 - | // Tag and value are equal. - if (vk) { - |->BC_ISEQV_Z: - | daddu PC, PC, TMP2 - } - |1: - | ins_next - | - |2: // Check if the tags are the same and it's a table or userdata. - | xor AT, CARG3, CARG4 // Same type? - | sltiu TMP0, CARG3, LJ_TISTABUD+1 // Table or userdata? - | movn TMP0, r0, AT - if (vk) { - | beqz TMP0, <1 - } else { - | beqz TMP0, ->BC_ISEQV_Z // Reuse code from opposite instruction. - } - | // Different tables or userdatas. Need to check __eq metamethod. - | // Field metatable must be at same offset for GCtab and GCudata! - |. cleartp TAB:TMP1, CARG1 - | ld TAB:TMP3, TAB:TMP1->metatable - if (vk) { - | beqz TAB:TMP3, <1 // No metatable? - |. nop - | lbu TMP3, TAB:TMP3->nomm - | andi TMP3, TMP3, 1<1 // Or 'no __eq' flag set? - } else { - | beqz TAB:TMP3,->BC_ISEQV_Z // No metatable? - |. nop - | lbu TMP3, TAB:TMP3->nomm - | andi TMP3, TMP3, 1<BC_ISEQV_Z // Or 'no __eq' flag set? - } - |. nop - | b ->vmeta_equal // Handle __eq metamethod. - |. li TMP0, 1-vk // ne = 0 or 1. - break; - - case BC_ISEQS: case BC_ISNES: - vk = op == BC_ISEQS; - | // RA = src*8, RD = str_const*8 (~), JMP with RD = target - | daddu RA, BASE, RA - | daddiu PC, PC, 4 - | ld CARG1, 0(RA) - | dsubu RD, KBASE, RD - | lhu TMP2, -4+OFS_RD(PC) - | ld CARG2, -8(RD) // KBASE-8-str_const*8 - |.if FFI - | gettp TMP0, CARG1 - | li AT, LJ_TCDATA - |.endif - | li TMP1, LJ_TSTR - | decode_RD4b TMP2 - |.if FFI - | beq TMP0, AT, ->vmeta_equal_cd - |.endif - |. settp CARG2, TMP1 - | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) - | xor TMP1, CARG1, CARG2 - | addu TMP2, TMP2, TMP3 - if (vk) { - | movn TMP2, r0, TMP1 - } else { - | movz TMP2, r0, TMP1 - } - | daddu PC, PC, TMP2 - | ins_next - break; - - case BC_ISEQN: case BC_ISNEN: - vk = op == BC_ISEQN; - | // RA = src*8, RD = num_const*8, JMP with RD = target - | daddu RA, BASE, RA - | daddu RD, KBASE, RD - | ld CARG1, 0(RA) - | ld CARG2, 0(RD) - | lhu TMP2, OFS_RD(PC) - | gettp CARG3, CARG1 - | gettp CARG4, CARG2 - | daddiu PC, PC, 4 - | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) - if (vk) { - |->BC_ISEQN_Z: - } else { - |->BC_ISNEN_Z: - } - | bne CARG3, TISNUM, >3 - |. decode_RD4b TMP2 - | bne CARG4, TISNUM, >6 - |. addu TMP2, TMP2, TMP3 - | xor AT, CARG1, CARG2 - if (vk) { - | movn TMP2, r0, AT - |1: - | daddu PC, PC, TMP2 - |2: - } else { - | movz TMP2, r0, AT - |1: - |2: - | daddu PC, PC, TMP2 - } - | ins_next - | - |3: // RA is not an integer. - | sltu AT, CARG3, TISNUM - |.if FFI - | beqz AT, >8 - |.else - | beqz AT, <2 - |.endif - |. addu TMP2, TMP2, TMP3 - | sltu AT, CARG4, TISNUM - |.if FPU - | ldc1 f20, 0(RA) - | ldc1 f22, 0(RD) - |.endif - | beqz AT, >5 - |. nop - |4: // RA and RD are both numbers. - |.if FPU - | c.eq.d f20, f22 - | b <1 - if (vk) { - |. movf TMP2, r0 - } else { - |. movt TMP2, r0 - } - |.else - | bal ->vm_sfcmpeq - |. nop - | b <1 - if (vk) { - |. movz TMP2, r0, CRET1 - } else { - |. movn TMP2, r0, CRET1 - } - |.endif - | - |5: // RA is a number, RD is not a number. - |.if FFI - | bne CARG4, TISNUM, >9 - |.else - | bne CARG4, TISNUM, <2 - |.endif - | // RA is a number, RD is an integer. Convert RD to a number. - |.if FPU - |. lwc1 f22, LO(RD) - | b <4 - |. cvt.d.w f22, f22 - |.else - |. sextw CARG2, CARG2 - | bal ->vm_sfi2d_2 - |. nop - | b <4 - |. nop - |.endif - | - |6: // RA is an integer, RD is not an integer - | sltu AT, CARG4, TISNUM - |.if FFI - | beqz AT, >9 - |.else - | beqz AT, <2 - |.endif - | // RA is an integer, RD is a number. Convert RA to a number. - |.if FPU - |. lwc1 f20, LO(RA) - | ldc1 f22, 0(RD) - | b <4 - | cvt.d.w f20, f20 - |.else - |. sextw CARG1, CARG1 - | bal ->vm_sfi2d_1 - |. nop - | b <4 - |. nop - |.endif - | - |.if FFI - |8: - | li AT, LJ_TCDATA - | bne CARG3, AT, <2 - |. nop - | b ->vmeta_equal_cd - |. nop - |9: - | li AT, LJ_TCDATA - | bne CARG4, AT, <2 - |. nop - | b ->vmeta_equal_cd - |. nop - |.endif - break; - - case BC_ISEQP: case BC_ISNEP: - vk = op == BC_ISEQP; - | // RA = src*8, RD = primitive_type*8 (~), JMP with RD = target - | daddu RA, BASE, RA - | srl TMP1, RD, 3 - | ld TMP0, 0(RA) - | lhu TMP2, OFS_RD(PC) - | not TMP1, TMP1 - | gettp TMP0, TMP0 - | daddiu PC, PC, 4 - |.if FFI - | li AT, LJ_TCDATA - | beq TMP0, AT, ->vmeta_equal_cd - |.endif - |. xor TMP0, TMP0, TMP1 - | decode_RD4b TMP2 - | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) - | addu TMP2, TMP2, TMP3 - if (vk) { - | movn TMP2, r0, TMP0 - } else { - | movz TMP2, r0, TMP0 - } - | daddu PC, PC, TMP2 - | ins_next - break; - - /* -- Unary test and copy ops ------------------------------------------- */ - - case BC_ISTC: case BC_ISFC: case BC_IST: case BC_ISF: - | // RA = dst*8 or unused, RD = src*8, JMP with RD = target - | daddu RD, BASE, RD - | lhu TMP2, OFS_RD(PC) - | ld TMP0, 0(RD) - | daddiu PC, PC, 4 - | gettp TMP0, TMP0 - | sltiu TMP0, TMP0, LJ_TISTRUECOND - if (op == BC_IST || op == BC_ISF) { - | decode_RD4b TMP2 - | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) - | addu TMP2, TMP2, TMP3 - if (op == BC_IST) { - | movz TMP2, r0, TMP0 - } else { - | movn TMP2, r0, TMP0 - } - | daddu PC, PC, TMP2 - } else { - | ld CRET1, 0(RD) - if (op == BC_ISTC) { - | beqz TMP0, >1 - } else { - | bnez TMP0, >1 - } - |. daddu RA, BASE, RA - | decode_RD4b TMP2 - | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) - | addu TMP2, TMP2, TMP3 - | sd CRET1, 0(RA) - | daddu PC, PC, TMP2 - |1: - } - | ins_next - break; - - case BC_ISTYPE: - | // RA = src*8, RD = -type*8 - | daddu TMP2, BASE, RA - | srl TMP1, RD, 3 - | ld TMP0, 0(TMP2) - | ins_next1 - | gettp TMP0, TMP0 - | daddu AT, TMP0, TMP1 - | bnez AT, ->vmeta_istype - |. ins_next2 - break; - case BC_ISNUM: - | // RA = src*8, RD = -(TISNUM-1)*8 - | daddu TMP2, BASE, RA - | ld TMP0, 0(TMP2) - | ins_next1 - | checknum TMP0, ->vmeta_istype - |. ins_next2 - break; - - /* -- Unary ops --------------------------------------------------------- */ - - case BC_MOV: - | // RA = dst*8, RD = src*8 - | daddu RD, BASE, RD - | daddu RA, BASE, RA - | ld CRET1, 0(RD) - | ins_next1 - | sd CRET1, 0(RA) - | ins_next2 - break; - case BC_NOT: - | // RA = dst*8, RD = src*8 - | daddu RD, BASE, RD - | daddu RA, BASE, RA - | ld TMP0, 0(RD) - | li AT, LJ_TTRUE - | gettp TMP0, TMP0 - | sltu TMP0, AT, TMP0 - | addiu TMP0, TMP0, 1 - | dsll TMP0, TMP0, 47 - | not TMP0, TMP0 - | ins_next1 - | sd TMP0, 0(RA) - | ins_next2 - break; - case BC_UNM: - | // RA = dst*8, RD = src*8 - | daddu RB, BASE, RD - | ld CARG1, 0(RB) - | daddu RA, BASE, RA - | gettp CARG3, CARG1 - | bne CARG3, TISNUM, >2 - |. lui TMP1, 0x8000 - | sextw CARG1, CARG1 - | beq CARG1, TMP1, ->vmeta_unm // Meta handler deals with -2^31. - |. negu CARG1, CARG1 - | zextw CARG1, CARG1 - | settp CARG1, TISNUM - |1: - | ins_next1 - | sd CARG1, 0(RA) - | ins_next2 - |2: - | sltiu AT, CARG3, LJ_TISNUM - | beqz AT, ->vmeta_unm - |. dsll TMP1, TMP1, 32 - | b <1 - |. xor CARG1, CARG1, TMP1 - break; - case BC_LEN: - | // RA = dst*8, RD = src*8 - | daddu CARG2, BASE, RD - | daddu RA, BASE, RA - | ld TMP0, 0(CARG2) - | gettp TMP1, TMP0 - | daddiu AT, TMP1, -LJ_TSTR - | bnez AT, >2 - |. cleartp STR:CARG1, TMP0 - | lw CRET1, STR:CARG1->len - |1: - | settp CRET1, TISNUM - | ins_next1 - | sd CRET1, 0(RA) - | ins_next2 - |2: - | daddiu AT, TMP1, -LJ_TTAB - | bnez AT, ->vmeta_len - |. nop -#if LJ_52 - | ld TAB:TMP2, TAB:CARG1->metatable - | bnez TAB:TMP2, >9 - |. nop - |3: -#endif - |->BC_LEN_Z: - | load_got lj_tab_len - | call_intern lj_tab_len // (GCtab *t) - |. nop - | // Returns uint32_t (but less than 2^31). - | b <1 - |. nop -#if LJ_52 - |9: - | lbu TMP0, TAB:TMP2->nomm - | andi TMP0, TMP0, 1<vmeta_len - |. nop -#endif - break; - - /* -- Binary ops -------------------------------------------------------- */ - - |.macro fpmod, a, b, c - | bal ->vm_floor // floor(b/c) - |. div.d FARG1, b, c - | mul.d a, FRET1, c - | sub.d a, b, a // b - floor(b/c)*c - |.endmacro - - |.macro sfpmod - | daddiu sp, sp, -16 - | - | load_got __divdf3 - | sd CARG1, 0(sp) - | call_extern - |. sd CARG2, 8(sp) - | - | load_got floor - | call_extern - |. move CARG1, CRET1 - | - | load_got __muldf3 - | move CARG1, CRET1 - | call_extern - |. ld CARG2, 8(sp) - | - | load_got __subdf3 - | ld CARG1, 0(sp) - | call_extern - |. move CARG2, CRET1 - | - | daddiu sp, sp, 16 - |.endmacro - - |.macro ins_arithpre, label - ||vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN); - | // RA = dst*8, RB = src1*8, RC = src2*8 | num_const*8 - ||switch (vk) { - ||case 0: - | decode_RB8a RB, INS - | decode_RB8b RB - | decode_RDtoRC8 RC, RD - | // RA = dst*8, RB = src1*8, RC = num_const*8 - | daddu RB, BASE, RB - |.if "label" ~= "none" - | b label - |.endif - |. daddu RC, KBASE, RC - || break; - ||case 1: - | decode_RB8a RC, INS - | decode_RB8b RC - | decode_RDtoRC8 RB, RD - | // RA = dst*8, RB = num_const*8, RC = src1*8 - | daddu RC, BASE, RC - |.if "label" ~= "none" - | b label - |.endif - |. daddu RB, KBASE, RB - || break; - ||default: - | decode_RB8a RB, INS - | decode_RB8b RB - | decode_RDtoRC8 RC, RD - | // RA = dst*8, RB = src1*8, RC = src2*8 - | daddu RB, BASE, RB - |.if "label" ~= "none" - | b label - |.endif - |. daddu RC, BASE, RC - || break; - ||} - |.endmacro - | - |.macro ins_arith, intins, fpins, fpcall, label - | ins_arithpre none - | - |.if "label" ~= "none" - |label: - |.endif - | - |// Used in 5. - | ld CARG1, 0(RB) - | ld CARG2, 0(RC) - | gettp TMP0, CARG1 - | gettp TMP1, CARG2 - | - |.if "intins" ~= "div" - | - | // Check for two integers. - | sextw CARG3, CARG1 - | bne TMP0, TISNUM, >5 - |. sextw CARG4, CARG2 - | bne TMP1, TISNUM, >5 - | - |.if "intins" == "addu" - |. intins CRET1, CARG3, CARG4 - | xor TMP1, CRET1, CARG3 // ((y^a) & (y^b)) < 0: overflow. - | xor TMP2, CRET1, CARG4 - | and TMP1, TMP1, TMP2 - | bltz TMP1, ->vmeta_arith - |. daddu RA, BASE, RA - |.elif "intins" == "subu" - |. intins CRET1, CARG3, CARG4 - | xor TMP1, CRET1, CARG3 // ((y^a) & (a^b)) < 0: overflow. - | xor TMP2, CARG3, CARG4 - | and TMP1, TMP1, TMP2 - | bltz TMP1, ->vmeta_arith - |. daddu RA, BASE, RA - |.elif "intins" == "mult" - |. intins CARG3, CARG4 - | mflo CRET1 - | mfhi TMP2 - | sra TMP1, CRET1, 31 - | bne TMP1, TMP2, ->vmeta_arith - |. daddu RA, BASE, RA - |.else - |. load_got lj_vm_modi - | beqz CARG4, ->vmeta_arith - |. daddu RA, BASE, RA - | move CARG1, CARG3 - | call_extern - |. move CARG2, CARG4 - |.endif - | - | zextw CRET1, CRET1 - | settp CRET1, TISNUM - | ins_next1 - | sd CRET1, 0(RA) - |3: - | ins_next2 - | - |.endif - | - |5: // Check for two numbers. - | .FPU ldc1 f20, 0(RB) - | sltu AT, TMP0, TISNUM - | sltu TMP0, TMP1, TISNUM - | .FPU ldc1 f22, 0(RC) - | and AT, AT, TMP0 - | beqz AT, ->vmeta_arith - |. daddu RA, BASE, RA - | - |.if FPU - | fpins FRET1, f20, f22 - |.elif "fpcall" == "sfpmod" - | sfpmod - |.else - | load_got fpcall - | call_extern - |. nop - |.endif - | - | ins_next1 - |.if "intins" ~= "div" - | b <3 - |.endif - |.if FPU - |. sdc1 FRET1, 0(RA) - |.else - |. sd CRET1, 0(RA) - |.endif - |.if "intins" == "div" - | ins_next2 - |.endif - | - |.endmacro - - case BC_ADDVN: case BC_ADDNV: case BC_ADDVV: - | ins_arith addu, add.d, __adddf3, none - break; - case BC_SUBVN: case BC_SUBNV: case BC_SUBVV: - | ins_arith subu, sub.d, __subdf3, none - break; - case BC_MULVN: case BC_MULNV: case BC_MULVV: - | ins_arith mult, mul.d, __muldf3, none - break; - case BC_DIVVN: - | ins_arith div, div.d, __divdf3, ->BC_DIVVN_Z - break; - case BC_DIVNV: case BC_DIVVV: - | ins_arithpre ->BC_DIVVN_Z - break; - case BC_MODVN: - | ins_arith modi, fpmod, sfpmod, ->BC_MODVN_Z - break; - case BC_MODNV: case BC_MODVV: - | ins_arithpre ->BC_MODVN_Z - break; - case BC_POW: - | ins_arithpre none - | ld CARG1, 0(RB) - | ld CARG2, 0(RC) - | gettp TMP0, CARG1 - | gettp TMP1, CARG2 - | sltiu TMP0, TMP0, LJ_TISNUM - | sltiu TMP1, TMP1, LJ_TISNUM - | and AT, TMP0, TMP1 - | load_got pow - | beqz AT, ->vmeta_arith - |. daddu RA, BASE, RA - |.if FPU - | ldc1 FARG1, 0(RB) - | ldc1 FARG2, 0(RC) - |.endif - | call_extern - |. nop - | ins_next1 - |.if FPU - | sdc1 FRET1, 0(RA) - |.else - | sd CRET1, 0(RA) - |.endif - | ins_next2 - break; - - case BC_CAT: - | // RA = dst*8, RB = src_start*8, RC = src_end*8 - | decode_RB8a RB, INS - | decode_RB8b RB - | decode_RDtoRC8 RC, RD - | dsubu CARG3, RC, RB - | sd BASE, L->base - | daddu CARG2, BASE, RC - | move MULTRES, RB - |->BC_CAT_Z: - | load_got lj_meta_cat - | srl CARG3, CARG3, 3 - | sd PC, SAVE_PC - | call_intern lj_meta_cat // (lua_State *L, TValue *top, int left) - |. move CARG1, L - | // Returns NULL (finished) or TValue * (metamethod). - | bnez CRET1, ->vmeta_binop - |. ld BASE, L->base - | daddu RB, BASE, MULTRES - | ld CRET1, 0(RB) - | daddu RA, BASE, RA - | ins_next1 - | sd CRET1, 0(RA) - | ins_next2 - break; - - /* -- Constant ops ------------------------------------------------------ */ - - case BC_KSTR: - | // RA = dst*8, RD = str_const*8 (~) - | dsubu TMP1, KBASE, RD - | ins_next1 - | li TMP2, LJ_TSTR - | ld TMP0, -8(TMP1) // KBASE-8-str_const*8 - | daddu RA, BASE, RA - | settp TMP0, TMP2 - | sd TMP0, 0(RA) - | ins_next2 - break; - case BC_KCDATA: - |.if FFI - | // RA = dst*8, RD = cdata_const*8 (~) - | dsubu TMP1, KBASE, RD - | ins_next1 - | ld TMP0, -8(TMP1) // KBASE-8-cdata_const*8 - | li TMP2, LJ_TCDATA - | daddu RA, BASE, RA - | settp TMP0, TMP2 - | sd TMP0, 0(RA) - | ins_next2 - |.endif - break; - case BC_KSHORT: - | // RA = dst*8, RD = int16_literal*8 - | sra RD, INS, 16 - | daddu RA, BASE, RA - | zextw RD, RD - | ins_next1 - | settp RD, TISNUM - | sd RD, 0(RA) - | ins_next2 - break; - case BC_KNUM: - | // RA = dst*8, RD = num_const*8 - | daddu RD, KBASE, RD - | daddu RA, BASE, RA - | ld CRET1, 0(RD) - | ins_next1 - | sd CRET1, 0(RA) - | ins_next2 - break; - case BC_KPRI: - | // RA = dst*8, RD = primitive_type*8 (~) - | daddu RA, BASE, RA - | dsll TMP0, RD, 44 - | not TMP0, TMP0 - | ins_next1 - | sd TMP0, 0(RA) - | ins_next2 - break; - case BC_KNIL: - | // RA = base*8, RD = end*8 - | daddu RA, BASE, RA - | sd TISNIL, 0(RA) - | daddiu RA, RA, 8 - | daddu RD, BASE, RD - |1: - | sd TISNIL, 0(RA) - | slt AT, RA, RD - | bnez AT, <1 - |. daddiu RA, RA, 8 - | ins_next_ - break; - - /* -- Upvalue and function ops ------------------------------------------ */ - - case BC_UGET: - | // RA = dst*8, RD = uvnum*8 - | ld LFUNC:RB, FRAME_FUNC(BASE) - | daddu RA, BASE, RA - | cleartp LFUNC:RB - | daddu RD, RD, LFUNC:RB - | ld UPVAL:RB, LFUNC:RD->uvptr - | ins_next1 - | ld TMP1, UPVAL:RB->v - | ld CRET1, 0(TMP1) - | sd CRET1, 0(RA) - | ins_next2 - break; - case BC_USETV: - | // RA = uvnum*8, RD = src*8 - | ld LFUNC:RB, FRAME_FUNC(BASE) - | daddu RD, BASE, RD - | cleartp LFUNC:RB - | daddu RA, RA, LFUNC:RB - | ld UPVAL:RB, LFUNC:RA->uvptr - | ld CRET1, 0(RD) - | lbu TMP3, UPVAL:RB->marked - | ld CARG2, UPVAL:RB->v - | andi TMP3, TMP3, LJ_GC_BLACK // isblack(uv) - | lbu TMP0, UPVAL:RB->closed - | gettp TMP2, CRET1 - | sd CRET1, 0(CARG2) - | li AT, LJ_GC_BLACK|1 - | or TMP3, TMP3, TMP0 - | beq TMP3, AT, >2 // Upvalue is closed and black? - |. daddiu TMP2, TMP2, -(LJ_TNUMX+1) - |1: - | ins_next - | - |2: // Check if new value is collectable. - | sltiu AT, TMP2, LJ_TISGCV - (LJ_TNUMX+1) - | beqz AT, <1 // tvisgcv(v) - |. cleartp GCOBJ:CRET1, CRET1 - | lbu TMP3, GCOBJ:CRET1->gch.marked - | andi TMP3, TMP3, LJ_GC_WHITES // iswhite(v) - | beqz TMP3, <1 - |. load_got lj_gc_barrieruv - | // Crossed a write barrier. Move the barrier forward. - | call_intern lj_gc_barrieruv // (global_State *g, TValue *tv) - |. daddiu CARG1, DISPATCH, GG_DISP2G - | b <1 - |. nop - break; - case BC_USETS: - | // RA = uvnum*8, RD = str_const*8 (~) - | ld LFUNC:RB, FRAME_FUNC(BASE) - | dsubu TMP1, KBASE, RD - | cleartp LFUNC:RB - | daddu RA, RA, LFUNC:RB - | ld UPVAL:RB, LFUNC:RA->uvptr - | ld STR:TMP1, -8(TMP1) // KBASE-8-str_const*8 - | lbu TMP2, UPVAL:RB->marked - | ld CARG2, UPVAL:RB->v - | lbu TMP3, STR:TMP1->marked - | andi AT, TMP2, LJ_GC_BLACK // isblack(uv) - | lbu TMP2, UPVAL:RB->closed - | li TMP0, LJ_TSTR - | settp TMP1, TMP0 - | bnez AT, >2 - |. sd TMP1, 0(CARG2) - |1: - | ins_next - | - |2: // Check if string is white and ensure upvalue is closed. - | beqz TMP2, <1 - |. andi AT, TMP3, LJ_GC_WHITES // iswhite(str) - | beqz AT, <1 - |. load_got lj_gc_barrieruv - | // Crossed a write barrier. Move the barrier forward. - | call_intern lj_gc_barrieruv // (global_State *g, TValue *tv) - |. daddiu CARG1, DISPATCH, GG_DISP2G - | b <1 - |. nop - break; - case BC_USETN: - | // RA = uvnum*8, RD = num_const*8 - | ld LFUNC:RB, FRAME_FUNC(BASE) - | daddu RD, KBASE, RD - | cleartp LFUNC:RB - | daddu RA, RA, LFUNC:RB - | ld UPVAL:RB, LFUNC:RA->uvptr - | ld CRET1, 0(RD) - | ld TMP1, UPVAL:RB->v - | ins_next1 - | sd CRET1, 0(TMP1) - | ins_next2 - break; - case BC_USETP: - | // RA = uvnum*8, RD = primitive_type*8 (~) - | ld LFUNC:RB, FRAME_FUNC(BASE) - | dsll TMP0, RD, 44 - | cleartp LFUNC:RB - | daddu RA, RA, LFUNC:RB - | not TMP0, TMP0 - | ld UPVAL:RB, LFUNC:RA->uvptr - | ins_next1 - | ld TMP1, UPVAL:RB->v - | sd TMP0, 0(TMP1) - | ins_next2 - break; - - case BC_UCLO: - | // RA = level*8, RD = target - | ld TMP2, L->openupval - | branch_RD // Do this first since RD is not saved. - | load_got lj_func_closeuv - | sd BASE, L->base - | beqz TMP2, >1 - |. move CARG1, L - | call_intern lj_func_closeuv // (lua_State *L, TValue *level) - |. daddu CARG2, BASE, RA - | ld BASE, L->base - |1: - | ins_next - break; - - case BC_FNEW: - | // RA = dst*8, RD = proto_const*8 (~) (holding function prototype) - | load_got lj_func_newL_gc - | dsubu TMP1, KBASE, RD - | ld CARG3, FRAME_FUNC(BASE) - | ld CARG2, -8(TMP1) // KBASE-8-tab_const*8 - | sd BASE, L->base - | sd PC, SAVE_PC - | cleartp CARG3 - | // (lua_State *L, GCproto *pt, GCfuncL *parent) - | call_intern lj_func_newL_gc - |. move CARG1, L - | // Returns GCfuncL *. - | li TMP0, LJ_TFUNC - | ld BASE, L->base - | ins_next1 - | settp CRET1, TMP0 - | daddu RA, BASE, RA - | sd CRET1, 0(RA) - | ins_next2 - break; - - /* -- Table ops --------------------------------------------------------- */ - - case BC_TNEW: - case BC_TDUP: - | // RA = dst*8, RD = (hbits|asize)*8 | tab_const*8 (~) - | ld TMP0, DISPATCH_GL(gc.total)(DISPATCH) - | ld TMP1, DISPATCH_GL(gc.threshold)(DISPATCH) - | sd BASE, L->base - | sd PC, SAVE_PC - | sltu AT, TMP0, TMP1 - | beqz AT, >5 - |1: - if (op == BC_TNEW) { - | load_got lj_tab_new - | srl CARG2, RD, 3 - | andi CARG2, CARG2, 0x7ff - | li TMP0, 0x801 - | addiu AT, CARG2, -0x7ff - | srl CARG3, RD, 14 - | movz CARG2, TMP0, AT - | // (lua_State *L, int32_t asize, uint32_t hbits) - | call_intern lj_tab_new - |. move CARG1, L - | // Returns Table *. - } else { - | load_got lj_tab_dup - | dsubu TMP1, KBASE, RD - | move CARG1, L - | call_intern lj_tab_dup // (lua_State *L, Table *kt) - |. ld CARG2, -8(TMP1) // KBASE-8-str_const*8 - | // Returns Table *. - } - | li TMP0, LJ_TTAB - | ld BASE, L->base - | ins_next1 - | daddu RA, BASE, RA - | settp CRET1, TMP0 - | sd CRET1, 0(RA) - | ins_next2 - |5: - | load_got lj_gc_step_fixtop - | move MULTRES, RD - | call_intern lj_gc_step_fixtop // (lua_State *L) - |. move CARG1, L - | b <1 - |. move RD, MULTRES - break; - - case BC_GGET: - | // RA = dst*8, RD = str_const*8 (~) - case BC_GSET: - | // RA = src*8, RD = str_const*8 (~) - | ld LFUNC:TMP2, FRAME_FUNC(BASE) - | dsubu TMP1, KBASE, RD - | ld STR:RC, -8(TMP1) // KBASE-8-str_const*8 - | cleartp LFUNC:TMP2 - | ld TAB:RB, LFUNC:TMP2->env - if (op == BC_GGET) { - | b ->BC_TGETS_Z - } else { - | b ->BC_TSETS_Z - } - |. daddu RA, BASE, RA - break; - - case BC_TGETV: - | // RA = dst*8, RB = table*8, RC = key*8 - | decode_RB8a RB, INS - | decode_RB8b RB - | decode_RDtoRC8 RC, RD - | daddu CARG2, BASE, RB - | daddu CARG3, BASE, RC - | ld TAB:RB, 0(CARG2) - | ld TMP2, 0(CARG3) - | daddu RA, BASE, RA - | checktab TAB:RB, ->vmeta_tgetv - | gettp TMP3, TMP2 - | bne TMP3, TISNUM, >5 // Integer key? - |. lw TMP0, TAB:RB->asize - | sextw TMP2, TMP2 - | ld TMP1, TAB:RB->array - | sltu AT, TMP2, TMP0 - | sll TMP2, TMP2, 3 - | beqz AT, ->vmeta_tgetv // Integer key and in array part? - |. daddu TMP2, TMP1, TMP2 - | ld AT, 0(TMP2) - | beq AT, TISNIL, >2 - |. ld CRET1, 0(TMP2) - |1: - | ins_next1 - | sd CRET1, 0(RA) - | ins_next2 - | - |2: // Check for __index if table value is nil. - | ld TAB:TMP2, TAB:RB->metatable - | beqz TAB:TMP2, <1 // No metatable: done. - |. nop - | lbu TMP0, TAB:TMP2->nomm - | andi TMP0, TMP0, 1<vmeta_tgetv - |. nop - | - |5: - | li AT, LJ_TSTR - | bne TMP3, AT, ->vmeta_tgetv - |. cleartp RC, TMP2 - | b ->BC_TGETS_Z // String key? - |. nop - break; - case BC_TGETS: - | // RA = dst*8, RB = table*8, RC = str_const*8 (~) - | decode_RB8a RB, INS - | decode_RB8b RB - | decode_RC8a RC, INS - | daddu CARG2, BASE, RB - | decode_RC8b RC - | ld TAB:RB, 0(CARG2) - | dsubu CARG3, KBASE, RC - | daddu RA, BASE, RA - | ld STR:RC, -8(CARG3) // KBASE-8-str_const*8 - | checktab TAB:RB, ->vmeta_tgets1 - |->BC_TGETS_Z: - | // TAB:RB = GCtab *, STR:RC = GCstr *, RA = dst*8 - | lw TMP0, TAB:RB->hmask - | lw TMP1, STR:RC->hash - | ld NODE:TMP2, TAB:RB->node - | and TMP1, TMP1, TMP0 // idx = str->hash & tab->hmask - | sll TMP0, TMP1, 5 - | sll TMP1, TMP1, 3 - | subu TMP1, TMP0, TMP1 - | li TMP3, LJ_TSTR - | daddu NODE:TMP2, NODE:TMP2, TMP1 // node = tab->node + (idx*32-idx*8) - | settp STR:RC, TMP3 // Tagged key to look for. - |1: - | ld CARG1, NODE:TMP2->key - | ld CRET1, NODE:TMP2->val - | ld NODE:TMP1, NODE:TMP2->next - | bne CARG1, RC, >4 - |. ld TAB:TMP3, TAB:RB->metatable - | beq CRET1, TISNIL, >5 // Key found, but nil value? - |. nop - |3: - | ins_next1 - | sd CRET1, 0(RA) - | ins_next2 - | - |4: // Follow hash chain. - | bnez NODE:TMP1, <1 - |. move NODE:TMP2, NODE:TMP1 - | // End of hash chain: key not found, nil result. - | - |5: // Check for __index if table value is nil. - | beqz TAB:TMP3, <3 // No metatable: done. - |. move CRET1, TISNIL - | lbu TMP0, TAB:TMP3->nomm - | andi TMP0, TMP0, 1<vmeta_tgets - |. nop - break; - case BC_TGETB: - | // RA = dst*8, RB = table*8, RC = index*8 - | decode_RB8a RB, INS - | decode_RB8b RB - | daddu CARG2, BASE, RB - | decode_RDtoRC8 RC, RD - | ld TAB:RB, 0(CARG2) - | daddu RA, BASE, RA - | srl TMP0, RC, 3 - | checktab TAB:RB, ->vmeta_tgetb - | lw TMP1, TAB:RB->asize - | ld TMP2, TAB:RB->array - | sltu AT, TMP0, TMP1 - | beqz AT, ->vmeta_tgetb - |. daddu RC, TMP2, RC - | ld AT, 0(RC) - | beq AT, TISNIL, >5 - |. ld CRET1, 0(RC) - |1: - | ins_next1 - | sd CRET1, 0(RA) - | ins_next2 - | - |5: // Check for __index if table value is nil. - | ld TAB:TMP2, TAB:RB->metatable - | beqz TAB:TMP2, <1 // No metatable: done. - |. nop - | lbu TMP1, TAB:TMP2->nomm - | andi TMP1, TMP1, 1<vmeta_tgetb // Caveat: preserve TMP0 and CARG2! - |. nop - break; - case BC_TGETR: - | // RA = dst*8, RB = table*8, RC = key*8 - | decode_RB8a RB, INS - | decode_RB8b RB - | decode_RDtoRC8 RC, RD - | daddu RB, BASE, RB - | daddu RC, BASE, RC - | ld TAB:CARG1, 0(RB) - | lw CARG2, LO(RC) - | daddu RA, BASE, RA - | cleartp TAB:CARG1 - | lw TMP0, TAB:CARG1->asize - | ld TMP1, TAB:CARG1->array - | sltu AT, CARG2, TMP0 - | sll TMP2, CARG2, 3 - | beqz AT, ->vmeta_tgetr // In array part? - |. daddu CRET1, TMP1, TMP2 - | ld CARG2, 0(CRET1) - |->BC_TGETR_Z: - | ins_next1 - | sd CARG2, 0(RA) - | ins_next2 - break; - - case BC_TSETV: - | // RA = src*8, RB = table*8, RC = key*8 - | decode_RB8a RB, INS - | decode_RB8b RB - | decode_RDtoRC8 RC, RD - | daddu CARG2, BASE, RB - | daddu CARG3, BASE, RC - | ld RB, 0(CARG2) - | ld TMP2, 0(CARG3) - | daddu RA, BASE, RA - | checktab RB, ->vmeta_tsetv - | checkint TMP2, >5 - |. sextw RC, TMP2 - | lw TMP0, TAB:RB->asize - | ld TMP1, TAB:RB->array - | sltu AT, RC, TMP0 - | sll TMP2, RC, 3 - | beqz AT, ->vmeta_tsetv // Integer key and in array part? - |. daddu TMP1, TMP1, TMP2 - | ld TMP0, 0(TMP1) - | lbu TMP3, TAB:RB->marked - | beq TMP0, TISNIL, >3 - |. ld CRET1, 0(RA) - |1: - | andi AT, TMP3, LJ_GC_BLACK // isblack(table) - | bnez AT, >7 - |. sd CRET1, 0(TMP1) - |2: - | ins_next - | - |3: // Check for __newindex if previous value is nil. - | ld TAB:TMP2, TAB:RB->metatable - | beqz TAB:TMP2, <1 // No metatable: done. - |. nop - | lbu TMP2, TAB:TMP2->nomm - | andi TMP2, TMP2, 1<vmeta_tsetv - |. nop - | - |5: - | gettp AT, TMP2 - | daddiu AT, AT, -LJ_TSTR - | bnez AT, ->vmeta_tsetv - |. nop - | b ->BC_TSETS_Z // String key? - |. cleartp STR:RC, TMP2 - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:RB, TMP3, TMP0, <2 - break; - case BC_TSETS: - | // RA = src*8, RB = table*8, RC = str_const*8 (~) - | decode_RB8a RB, INS - | decode_RB8b RB - | daddu CARG2, BASE, RB - | decode_RC8a RC, INS - | ld TAB:RB, 0(CARG2) - | decode_RC8b RC - | dsubu CARG3, KBASE, RC - | ld RC, -8(CARG3) // KBASE-8-str_const*8 - | daddu RA, BASE, RA - | cleartp STR:RC - | checktab TAB:RB, ->vmeta_tsets1 - |->BC_TSETS_Z: - | // TAB:RB = GCtab *, STR:RC = GCstr *, RA = BASE+src*8 - | lw TMP0, TAB:RB->hmask - | lw TMP1, STR:RC->hash - | ld NODE:TMP2, TAB:RB->node - | sb r0, TAB:RB->nomm // Clear metamethod cache. - | and TMP1, TMP1, TMP0 // idx = str->hash & tab->hmask - | sll TMP0, TMP1, 5 - | sll TMP1, TMP1, 3 - | subu TMP1, TMP0, TMP1 - | li TMP3, LJ_TSTR - | daddu NODE:TMP2, NODE:TMP2, TMP1 // node = tab->node + (idx*32-idx*8) - | settp STR:RC, TMP3 // Tagged key to look for. - |.if FPU - | ldc1 f20, 0(RA) - |.else - | ld CRET1, 0(RA) - |.endif - |1: - | ld TMP0, NODE:TMP2->key - | ld CARG2, NODE:TMP2->val - | ld NODE:TMP1, NODE:TMP2->next - | bne TMP0, RC, >5 - |. lbu TMP3, TAB:RB->marked - | beq CARG2, TISNIL, >4 // Key found, but nil value? - |. ld TAB:TMP0, TAB:RB->metatable - |2: - | andi AT, TMP3, LJ_GC_BLACK // isblack(table) - | bnez AT, >7 - |.if FPU - |. sdc1 f20, NODE:TMP2->val - |.else - |. sd CRET1, NODE:TMP2->val - |.endif - |3: - | ins_next - | - |4: // Check for __newindex if previous value is nil. - | beqz TAB:TMP0, <2 // No metatable: done. - |. nop - | lbu TMP0, TAB:TMP0->nomm - | andi TMP0, TMP0, 1<vmeta_tsets - |. nop - | - |5: // Follow hash chain. - | bnez NODE:TMP1, <1 - |. move NODE:TMP2, NODE:TMP1 - | // End of hash chain: key not found, add a new one - | - | // But check for __newindex first. - | ld TAB:TMP2, TAB:RB->metatable - | beqz TAB:TMP2, >6 // No metatable: continue. - |. daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv) - | lbu TMP0, TAB:TMP2->nomm - | andi TMP0, TMP0, 1<vmeta_tsets // 'no __newindex' flag NOT set: check. - |6: - | load_got lj_tab_newkey - | sd RC, 0(CARG3) - | sd BASE, L->base - | move CARG2, TAB:RB - | sd PC, SAVE_PC - | call_intern lj_tab_newkey // (lua_State *L, GCtab *t, TValue *k - |. move CARG1, L - | // Returns TValue *. - | ld BASE, L->base - |.if FPU - | b <3 // No 2nd write barrier needed. - |. sdc1 f20, 0(CRET1) - |.else - | ld CARG1, 0(RA) - | b <3 // No 2nd write barrier needed. - |. sd CARG1, 0(CRET1) - |.endif - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:RB, TMP3, TMP0, <3 - break; - case BC_TSETB: - | // RA = src*8, RB = table*8, RC = index*8 - | decode_RB8a RB, INS - | decode_RB8b RB - | daddu CARG2, BASE, RB - | decode_RDtoRC8 RC, RD - | ld TAB:RB, 0(CARG2) - | daddu RA, BASE, RA - | srl TMP0, RC, 3 - | checktab RB, ->vmeta_tsetb - | lw TMP1, TAB:RB->asize - | ld TMP2, TAB:RB->array - | sltu AT, TMP0, TMP1 - | beqz AT, ->vmeta_tsetb - |. daddu RC, TMP2, RC - | ld TMP1, 0(RC) - | lbu TMP3, TAB:RB->marked - | beq TMP1, TISNIL, >5 - |1: - |. ld CRET1, 0(RA) - | andi AT, TMP3, LJ_GC_BLACK // isblack(table) - | bnez AT, >7 - |. sd CRET1, 0(RC) - |2: - | ins_next - | - |5: // Check for __newindex if previous value is nil. - | ld TAB:TMP2, TAB:RB->metatable - | beqz TAB:TMP2, <1 // No metatable: done. - |. nop - | lbu TMP1, TAB:TMP2->nomm - | andi TMP1, TMP1, 1<vmeta_tsetb // Caveat: preserve TMP0 and CARG2! - |. nop - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:RB, TMP3, TMP0, <2 - break; - case BC_TSETR: - | // RA = dst*8, RB = table*8, RC = key*8 - | decode_RB8a RB, INS - | decode_RB8b RB - | decode_RDtoRC8 RC, RD - | daddu CARG1, BASE, RB - | daddu CARG3, BASE, RC - | ld TAB:CARG2, 0(CARG1) - | lw CARG3, LO(CARG3) - | cleartp TAB:CARG2 - | lbu TMP3, TAB:CARG2->marked - | lw TMP0, TAB:CARG2->asize - | ld TMP1, TAB:CARG2->array - | andi AT, TMP3, LJ_GC_BLACK // isblack(table) - | bnez AT, >7 - |. daddu RA, BASE, RA - |2: - | sltu AT, CARG3, TMP0 - | sll TMP2, CARG3, 3 - | beqz AT, ->vmeta_tsetr // In array part? - |. daddu CRET1, TMP1, TMP2 - |->BC_TSETR_Z: - | ld CARG1, 0(RA) - | ins_next1 - | sd CARG1, 0(CRET1) - | ins_next2 - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:CARG2, TMP3, CRET1, <2 - break; - - case BC_TSETM: - | // RA = base*8 (table at base-1), RD = num_const*8 (start index) - | daddu RA, BASE, RA - |1: - | daddu TMP3, KBASE, RD - | ld TAB:CARG2, -8(RA) // Guaranteed to be a table. - | addiu TMP0, MULTRES, -8 - | lw TMP3, LO(TMP3) // Integer constant is in lo-word. - | beqz TMP0, >4 // Nothing to copy? - |. srl CARG3, TMP0, 3 - | cleartp CARG2 - | addu CARG3, CARG3, TMP3 - | lw TMP2, TAB:CARG2->asize - | sll TMP1, TMP3, 3 - | lbu TMP3, TAB:CARG2->marked - | ld CARG1, TAB:CARG2->array - | sltu AT, TMP2, CARG3 - | bnez AT, >5 - |. daddu TMP2, RA, TMP0 - | daddu TMP1, TMP1, CARG1 - | andi TMP0, TMP3, LJ_GC_BLACK // isblack(table) - |3: // Copy result slots to table. - | ld CRET1, 0(RA) - | daddiu RA, RA, 8 - | sltu AT, RA, TMP2 - | sd CRET1, 0(TMP1) - | bnez AT, <3 - |. daddiu TMP1, TMP1, 8 - | bnez TMP0, >7 - |. nop - |4: - | ins_next - | - |5: // Need to resize array part. - | load_got lj_tab_reasize - | sd BASE, L->base - | sd PC, SAVE_PC - | move BASE, RD - | call_intern lj_tab_reasize // (lua_State *L, GCtab *t, int nasize) - |. move CARG1, L - | // Must not reallocate the stack. - | move RD, BASE - | b <1 - |. ld BASE, L->base // Reload BASE for lack of a saved register. - | - |7: // Possible table write barrier for any value. Skip valiswhite check. - | barrierback TAB:CARG2, TMP3, TMP0, <4 - break; - - /* -- Calls and vararg handling ----------------------------------------- */ - - case BC_CALLM: - | // RA = base*8, (RB = (nresults+1)*8,) RC = extra_nargs*8 - | decode_RDtoRC8 NARGS8:RC, RD - | b ->BC_CALL_Z - |. addu NARGS8:RC, NARGS8:RC, MULTRES - break; - case BC_CALL: - | // RA = base*8, (RB = (nresults+1)*8,) RC = (nargs+1)*8 - | decode_RDtoRC8 NARGS8:RC, RD - |->BC_CALL_Z: - | move TMP2, BASE - | daddu BASE, BASE, RA - | ld LFUNC:RB, 0(BASE) - | daddiu BASE, BASE, 16 - | addiu NARGS8:RC, NARGS8:RC, -8 - | checkfunc RB, ->vmeta_call - | ins_call - break; - - case BC_CALLMT: - | // RA = base*8, (RB = 0,) RC = extra_nargs*8 - | addu NARGS8:RD, NARGS8:RD, MULTRES // BC_CALLT gets RC from RD. - | // Fall through. Assumes BC_CALLT follows. - break; - case BC_CALLT: - | // RA = base*8, (RB = 0,) RC = (nargs+1)*8 - | daddu RA, BASE, RA - | ld RB, 0(RA) - | move NARGS8:RC, RD - | ld TMP1, FRAME_PC(BASE) - | daddiu RA, RA, 16 - | addiu NARGS8:RC, NARGS8:RC, -8 - | checktp CARG3, RB, -LJ_TFUNC, ->vmeta_callt - |->BC_CALLT_Z: - | andi TMP0, TMP1, FRAME_TYPE // Caveat: preserve TMP0 until the 'or'. - | lbu TMP3, LFUNC:CARG3->ffid - | bnez TMP0, >7 - |. xori TMP2, TMP1, FRAME_VARG - |1: - | sd RB, FRAME_FUNC(BASE) // Copy function down, but keep PC. - | sltiu AT, TMP3, 2 // (> FF_C) Calling a fast function? - | move TMP2, BASE - | move RB, CARG3 - | beqz NARGS8:RC, >3 - |. move TMP3, NARGS8:RC - |2: - | ld CRET1, 0(RA) - | daddiu RA, RA, 8 - | addiu TMP3, TMP3, -8 - | sd CRET1, 0(TMP2) - | bnez TMP3, <2 - |. daddiu TMP2, TMP2, 8 - |3: - | or TMP0, TMP0, AT - | beqz TMP0, >5 - |. nop - |4: - | ins_callt - | - |5: // Tailcall to a fast function with a Lua frame below. - | lw INS, -4(TMP1) - | decode_RA8a RA, INS - | decode_RA8b RA - | dsubu TMP1, BASE, RA - | ld TMP1, -32(TMP1) - | cleartp LFUNC:TMP1 - | ld TMP1, LFUNC:TMP1->pc - | b <4 - |. ld KBASE, PC2PROTO(k)(TMP1) // Need to prepare KBASE. - | - |7: // Tailcall from a vararg function. - | andi AT, TMP2, FRAME_TYPEP - | bnez AT, <1 // Vararg frame below? - |. dsubu TMP2, BASE, TMP2 // Relocate BASE down. - | move BASE, TMP2 - | ld TMP1, FRAME_PC(TMP2) - | b <1 - |. andi TMP0, TMP1, FRAME_TYPE - break; - - case BC_ITERC: - | // RA = base*8, (RB = (nresults+1)*8, RC = (nargs+1)*8 ((2+1)*8)) - | move TMP2, BASE // Save old BASE fir vmeta_call. - | daddu BASE, BASE, RA - | ld RB, -24(BASE) - | ld CARG1, -16(BASE) - | ld CARG2, -8(BASE) - | li NARGS8:RC, 16 // Iterators get 2 arguments. - | sd RB, 0(BASE) // Copy callable. - | sd CARG1, 16(BASE) // Copy state. - | sd CARG2, 24(BASE) // Copy control var. - | daddiu BASE, BASE, 16 - | checkfunc RB, ->vmeta_call - | ins_call - break; - - case BC_ITERN: - | // RA = base*8, (RB = (nresults+1)*8, RC = (nargs+1)*8 (2+1)*8) - |.if JIT - | // NYI: add hotloop, record BC_ITERN. - |.endif - | daddu RA, BASE, RA - | ld TAB:RB, -16(RA) - | lw RC, -8+LO(RA) // Get index from control var. - | cleartp TAB:RB - | daddiu PC, PC, 4 - | lw TMP0, TAB:RB->asize - | ld TMP1, TAB:RB->array - | dsll CARG3, TISNUM, 47 - |1: // Traverse array part. - | sltu AT, RC, TMP0 - | beqz AT, >5 // Index points after array part? - |. sll TMP3, RC, 3 - | daddu TMP3, TMP1, TMP3 - | ld CARG1, 0(TMP3) - | lhu RD, -4+OFS_RD(PC) - | or TMP2, RC, CARG3 - | beq CARG1, TISNIL, <1 // Skip holes in array part. - |. addiu RC, RC, 1 - | sd TMP2, 0(RA) - | sd CARG1, 8(RA) - | or TMP0, RC, CARG3 - | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) - | decode_RD4b RD - | daddu RD, RD, TMP3 - | sw TMP0, -8+LO(RA) // Update control var. - | daddu PC, PC, RD - |3: - | ins_next - | - |5: // Traverse hash part. - | lw TMP1, TAB:RB->hmask - | subu RC, RC, TMP0 - | ld TMP2, TAB:RB->node - |6: - | sltu AT, TMP1, RC // End of iteration? Branch to ITERL+1. - | bnez AT, <3 - |. sll TMP3, RC, 5 - | sll RB, RC, 3 - | subu TMP3, TMP3, RB - | daddu NODE:TMP3, TMP3, TMP2 - | ld CARG1, 0(NODE:TMP3) - | lhu RD, -4+OFS_RD(PC) - | beq CARG1, TISNIL, <6 // Skip holes in hash part. - |. addiu RC, RC, 1 - | ld CARG2, NODE:TMP3->key - | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) - | sd CARG1, 8(RA) - | addu RC, RC, TMP0 - | decode_RD4b RD - | addu RD, RD, TMP3 - | sd CARG2, 0(RA) - | daddu PC, PC, RD - | b <3 - |. sw RC, -8+LO(RA) // Update control var. - break; - - case BC_ISNEXT: - | // RA = base*8, RD = target (points to ITERN) - | daddu RA, BASE, RA - | srl TMP0, RD, 1 - | ld CFUNC:CARG1, -24(RA) - | daddu TMP0, PC, TMP0 - | ld CARG2, -16(RA) - | ld CARG3, -8(RA) - | lui TMP2, (-(BCBIAS_J*4 >> 16) & 65535) - | checkfunc CFUNC:CARG1, >5 - | gettp CARG2, CARG2 - | daddiu CARG2, CARG2, -LJ_TTAB - | lbu TMP1, CFUNC:CARG1->ffid - | daddiu CARG3, CARG3, -LJ_TNIL - | or AT, CARG2, CARG3 - | daddiu TMP1, TMP1, -FF_next_N - | or AT, AT, TMP1 - | bnez AT, >5 - |. lui TMP1, 0xfffe - | daddu PC, TMP0, TMP2 - | ori TMP1, TMP1, 0x7fff - | dsll TMP1, TMP1, 32 - | sd TMP1, -8(RA) - |1: - | ins_next - |5: // Despecialize bytecode if any of the checks fail. - | li TMP3, BC_JMP - | li TMP1, BC_ITERC - | sb TMP3, -4+OFS_OP(PC) - | daddu PC, TMP0, TMP2 - | b <1 - |. sb TMP1, OFS_OP(PC) - break; - - case BC_VARG: - | // RA = base*8, RB = (nresults+1)*8, RC = numparams*8 - | ld TMP0, FRAME_PC(BASE) - | decode_RDtoRC8 RC, RD - | decode_RB8a RB, INS - | daddu RC, BASE, RC - | decode_RB8b RB - | daddu RA, BASE, RA - | daddiu RC, RC, FRAME_VARG - | daddu TMP2, RA, RB - | daddiu TMP3, BASE, -16 // TMP3 = vtop - | dsubu RC, RC, TMP0 // RC = vbase - | // Note: RC may now be even _above_ BASE if nargs was < numparams. - | beqz RB, >5 // Copy all varargs? - |. dsubu TMP1, TMP3, RC - | daddiu TMP2, TMP2, -16 - |1: // Copy vararg slots to destination slots. - | ld CARG1, 0(RC) - | sltu AT, RC, TMP3 - | daddiu RC, RC, 8 - | movz CARG1, TISNIL, AT - | sd CARG1, 0(RA) - | sltu AT, RA, TMP2 - | bnez AT, <1 - |. daddiu RA, RA, 8 - |3: - | ins_next - | - |5: // Copy all varargs. - | ld TMP0, L->maxstack - | blez TMP1, <3 // No vararg slots? - |. li MULTRES, 8 // MULTRES = (0+1)*8 - | daddu TMP2, RA, TMP1 - | sltu AT, TMP0, TMP2 - | bnez AT, >7 - |. daddiu MULTRES, TMP1, 8 - |6: - | ld CRET1, 0(RC) - | daddiu RC, RC, 8 - | sd CRET1, 0(RA) - | sltu AT, RC, TMP3 - | bnez AT, <6 // More vararg slots? - |. daddiu RA, RA, 8 - | b <3 - |. nop - | - |7: // Grow stack for varargs. - | load_got lj_state_growstack - | sd RA, L->top - | dsubu RA, RA, BASE - | sd BASE, L->base - | dsubu BASE, RC, BASE // Need delta, because BASE may change. - | sd PC, SAVE_PC - | srl CARG2, TMP1, 3 - | call_intern lj_state_growstack // (lua_State *L, int n) - |. move CARG1, L - | move RC, BASE - | ld BASE, L->base - | daddu RA, BASE, RA - | daddu RC, BASE, RC - | b <6 - |. daddiu TMP3, BASE, -16 - break; - - /* -- Returns ----------------------------------------------------------- */ - - case BC_RETM: - | // RA = results*8, RD = extra_nresults*8 - | addu RD, RD, MULTRES // MULTRES >= 8, so RD >= 8. - | // Fall through. Assumes BC_RET follows. - break; - - case BC_RET: - | // RA = results*8, RD = (nresults+1)*8 - | ld PC, FRAME_PC(BASE) - | daddu RA, BASE, RA - | move MULTRES, RD - |1: - | andi TMP0, PC, FRAME_TYPE - | bnez TMP0, ->BC_RETV_Z - |. xori TMP1, PC, FRAME_VARG - | - |->BC_RET_Z: - | // BASE = base, RA = resultptr, RD = (nresults+1)*8, PC = return - | lw INS, -4(PC) - | daddiu TMP2, BASE, -16 - | daddiu RC, RD, -8 - | decode_RA8a TMP0, INS - | decode_RB8a RB, INS - | decode_RA8b TMP0 - | decode_RB8b RB - | daddu TMP3, TMP2, RB - | beqz RC, >3 - |. dsubu BASE, TMP2, TMP0 - |2: - | ld CRET1, 0(RA) - | daddiu RA, RA, 8 - | daddiu RC, RC, -8 - | sd CRET1, 0(TMP2) - | bnez RC, <2 - |. daddiu TMP2, TMP2, 8 - |3: - | daddiu TMP3, TMP3, -8 - |5: - | sltu AT, TMP2, TMP3 - | bnez AT, >6 - |. ld LFUNC:TMP1, FRAME_FUNC(BASE) - | ins_next1 - | cleartp LFUNC:TMP1 - | ld TMP1, LFUNC:TMP1->pc - | ld KBASE, PC2PROTO(k)(TMP1) - | ins_next2 - | - |6: // Fill up results with nil. - | sd TISNIL, 0(TMP2) - | b <5 - |. daddiu TMP2, TMP2, 8 - | - |->BC_RETV_Z: // Non-standard return case. - | andi TMP2, TMP1, FRAME_TYPEP - | bnez TMP2, ->vm_return - |. nop - | // Return from vararg function: relocate BASE down. - | dsubu BASE, BASE, TMP1 - | b <1 - |. ld PC, FRAME_PC(BASE) - break; - - case BC_RET0: case BC_RET1: - | // RA = results*8, RD = (nresults+1)*8 - | ld PC, FRAME_PC(BASE) - | daddu RA, BASE, RA - | move MULTRES, RD - | andi TMP0, PC, FRAME_TYPE - | bnez TMP0, ->BC_RETV_Z - |. xori TMP1, PC, FRAME_VARG - | lw INS, -4(PC) - | daddiu TMP2, BASE, -16 - if (op == BC_RET1) { - | ld CRET1, 0(RA) - } - | decode_RB8a RB, INS - | decode_RA8a RA, INS - | decode_RB8b RB - | decode_RA8b RA - | dsubu BASE, TMP2, RA - if (op == BC_RET1) { - | sd CRET1, 0(TMP2) - } - |5: - | sltu AT, RD, RB - | bnez AT, >6 - |. ld TMP1, FRAME_FUNC(BASE) - | ins_next1 - | cleartp LFUNC:TMP1 - | ld TMP1, LFUNC:TMP1->pc - | ld KBASE, PC2PROTO(k)(TMP1) - | ins_next2 - | - |6: // Fill up results with nil. - | daddiu TMP2, TMP2, 8 - | daddiu RD, RD, 8 - | b <5 - if (op == BC_RET1) { - |. sd TISNIL, 0(TMP2) - } else { - |. sd TISNIL, -8(TMP2) - } - break; - - /* -- Loops and branches ------------------------------------------------ */ - - case BC_FORL: - |.if JIT - | hotloop - |.endif - | // Fall through. Assumes BC_IFORL follows. - break; - - case BC_JFORI: - case BC_JFORL: -#if !LJ_HASJIT - break; -#endif - case BC_FORI: - case BC_IFORL: - | // RA = base*8, RD = target (after end of loop or start of loop) - vk = (op == BC_IFORL || op == BC_JFORL); - | daddu RA, BASE, RA - | ld CARG1, FORL_IDX*8(RA) // IDX CARG1 - CARG3 type - | gettp CARG3, CARG1 - if (op != BC_JFORL) { - | srl RD, RD, 1 - | lui TMP2, (-(BCBIAS_J*4 >> 16) & 65535) - | daddu TMP2, RD, TMP2 - } - if (!vk) { - | ld CARG2, FORL_STOP*8(RA) // STOP CARG2 - CARG4 type - | ld CRET1, FORL_STEP*8(RA) // STEP CRET1 - CRET2 type - | gettp CARG4, CARG2 - | bne CARG3, TISNUM, >5 - |. gettp CRET2, CRET1 - | bne CARG4, TISNUM, ->vmeta_for - |. sextw CARG3, CARG1 - | bne CRET2, TISNUM, ->vmeta_for - |. sextw CARG2, CARG2 - | dext AT, CRET1, 31, 0 - | slt CRET1, CARG2, CARG3 - | slt TMP1, CARG3, CARG2 - | movn CRET1, TMP1, AT - } else { - | bne CARG3, TISNUM, >5 - |. ld CARG2, FORL_STEP*8(RA) // STEP CARG2 - CARG4 type - | ld CRET1, FORL_STOP*8(RA) // STOP CRET1 - CRET2 type - | sextw TMP3, CARG1 - | sextw CARG2, CARG2 - | sextw CRET1, CRET1 - | addu CARG1, TMP3, CARG2 - | xor TMP0, CARG1, TMP3 - | xor TMP1, CARG1, CARG2 - | and TMP0, TMP0, TMP1 - | slt TMP1, CARG1, CRET1 - | slt CRET1, CRET1, CARG1 - | slt AT, CARG2, r0 - | slt TMP0, TMP0, r0 // ((y^a) & (y^b)) < 0: overflow. - | movn CRET1, TMP1, AT - | or CRET1, CRET1, TMP0 - | zextw CARG1, CARG1 - | settp CARG1, TISNUM - } - |1: - if (op == BC_FORI) { - | movz TMP2, r0, CRET1 - | daddu PC, PC, TMP2 - } else if (op == BC_JFORI) { - | daddu PC, PC, TMP2 - | lhu RD, -4+OFS_RD(PC) - } else if (op == BC_IFORL) { - | movn TMP2, r0, CRET1 - | daddu PC, PC, TMP2 - } - if (vk) { - | sd CARG1, FORL_IDX*8(RA) - } - | ins_next1 - | sd CARG1, FORL_EXT*8(RA) - |2: - if (op == BC_JFORI) { - | beqz CRET1, =>BC_JLOOP - |. decode_RD8b RD - } else if (op == BC_JFORL) { - | beqz CRET1, =>BC_JLOOP - } - | ins_next2 - | - |5: // FP loop. - |.if FPU - if (!vk) { - | ldc1 f0, FORL_IDX*8(RA) - | ldc1 f2, FORL_STOP*8(RA) - | sltiu TMP0, CARG3, LJ_TISNUM - | sltiu TMP1, CARG4, LJ_TISNUM - | sltiu AT, CRET2, LJ_TISNUM - | ld TMP3, FORL_STEP*8(RA) - | and TMP0, TMP0, TMP1 - | and AT, AT, TMP0 - | beqz AT, ->vmeta_for - |. slt TMP3, TMP3, r0 - | c.ole.d 0, f0, f2 - | c.ole.d 1, f2, f0 - | li CRET1, 1 - | movt CRET1, r0, 0 - | movt AT, r0, 1 - | b <1 - |. movn CRET1, AT, TMP3 - } else { - | ldc1 f0, FORL_IDX*8(RA) - | ldc1 f4, FORL_STEP*8(RA) - | ldc1 f2, FORL_STOP*8(RA) - | ld TMP3, FORL_STEP*8(RA) - | add.d f0, f0, f4 - | c.ole.d 0, f0, f2 - | c.ole.d 1, f2, f0 - | slt TMP3, TMP3, r0 - | li CRET1, 1 - | li AT, 1 - | movt CRET1, r0, 0 - | movt AT, r0, 1 - | movn CRET1, AT, TMP3 - if (op == BC_IFORL) { - | movn TMP2, r0, CRET1 - | daddu PC, PC, TMP2 - } - | sdc1 f0, FORL_IDX*8(RA) - | ins_next1 - | b <2 - |. sdc1 f0, FORL_EXT*8(RA) - } - |.else - if (!vk) { - | sltiu TMP0, CARG3, LJ_TISNUM - | sltiu TMP1, CARG4, LJ_TISNUM - | sltiu AT, CRET2, LJ_TISNUM - | and TMP0, TMP0, TMP1 - | and AT, AT, TMP0 - | beqz AT, ->vmeta_for - |. nop - | bal ->vm_sfcmpolex - |. lw TMP3, FORL_STEP*8+HI(RA) - | b <1 - |. nop - } else { - | load_got __adddf3 - | call_extern - |. sw TMP2, TMPD - | ld CARG2, FORL_STOP*8(RA) - | move CARG1, CRET1 - if ( op == BC_JFORL ) { - | lhu RD, -4+OFS_RD(PC) - | decode_RD8b RD - } - | bal ->vm_sfcmpolex - |. lw TMP3, FORL_STEP*8+HI(RA) - | b <1 - |. lw TMP2, TMPD - } - |.endif - break; - - case BC_ITERL: - |.if JIT - | hotloop - |.endif - | // Fall through. Assumes BC_IITERL follows. - break; - - case BC_JITERL: -#if !LJ_HASJIT - break; -#endif - case BC_IITERL: - | // RA = base*8, RD = target - | daddu RA, BASE, RA - | ld TMP1, 0(RA) - | beq TMP1, TISNIL, >1 // Stop if iterator returned nil. - |. nop - if (op == BC_JITERL) { - | b =>BC_JLOOP - |. sd TMP1, -8(RA) - } else { - | branch_RD // Otherwise save control var + branch. - | sd TMP1, -8(RA) - } - |1: - | ins_next - break; - - case BC_LOOP: - | // RA = base*8, RD = target (loop extent) - | // Note: RA/RD is only used by trace recorder to determine scope/extent - | // This opcode does NOT jump, it's only purpose is to detect a hot loop. - |.if JIT - | hotloop - |.endif - | // Fall through. Assumes BC_ILOOP follows. - break; - - case BC_ILOOP: - | // RA = base*8, RD = target (loop extent) - | ins_next - break; - - case BC_JLOOP: - |.if JIT - | // RA = base*8 (ignored), RD = traceno*8 - | ld TMP1, DISPATCH_J(trace)(DISPATCH) - | li AT, 0 - | daddu TMP1, TMP1, RD - | // Traces on MIPS don't store the trace number, so use 0. - | sd AT, DISPATCH_GL(vmstate)(DISPATCH) - | ld TRACE:TMP2, 0(TMP1) - | sd BASE, DISPATCH_GL(jit_base)(DISPATCH) - | ld TMP2, TRACE:TMP2->mcode - | sd L, DISPATCH_GL(tmpbuf.L)(DISPATCH) - | jr TMP2 - |. daddiu JGL, DISPATCH, GG_DISP2G+32768 - |.endif - break; - - case BC_JMP: - | // RA = base*8 (only used by trace recorder), RD = target - | branch_RD - | ins_next - break; - - /* -- Function headers -------------------------------------------------- */ - - case BC_FUNCF: - |.if JIT - | hotcall - |.endif - case BC_FUNCV: /* NYI: compiled vararg functions. */ - | // Fall through. Assumes BC_IFUNCF/BC_IFUNCV follow. - break; - - case BC_JFUNCF: -#if !LJ_HASJIT - break; -#endif - case BC_IFUNCF: - | // BASE = new base, RA = BASE+framesize*8, RB = LFUNC, RC = nargs*8 - | ld TMP2, L->maxstack - | lbu TMP1, -4+PC2PROTO(numparams)(PC) - | ld KBASE, -4+PC2PROTO(k)(PC) - | sltu AT, TMP2, RA - | bnez AT, ->vm_growstack_l - |. sll TMP1, TMP1, 3 - if (op != BC_JFUNCF) { - | ins_next1 - } - |2: - | sltu AT, NARGS8:RC, TMP1 // Check for missing parameters. - | bnez AT, >3 - |. daddu AT, BASE, NARGS8:RC - if (op == BC_JFUNCF) { - | decode_RD8a RD, INS - | b =>BC_JLOOP - |. decode_RD8b RD - } else { - | ins_next2 - } - | - |3: // Clear missing parameters. - | sd TISNIL, 0(AT) - | b <2 - |. addiu NARGS8:RC, NARGS8:RC, 8 - break; - - case BC_JFUNCV: -#if !LJ_HASJIT - break; -#endif - | NYI // NYI: compiled vararg functions - break; /* NYI: compiled vararg functions. */ - - case BC_IFUNCV: - | // BASE = new base, RA = BASE+framesize*8, RB = LFUNC, RC = nargs*8 - | li TMP0, LJ_TFUNC - | daddu TMP1, BASE, RC - | ld TMP2, L->maxstack - | settp LFUNC:RB, TMP0 - | daddu TMP0, RA, RC - | sd LFUNC:RB, 0(TMP1) // Store (tagged) copy of LFUNC. - | daddiu TMP3, RC, 16+FRAME_VARG - | sltu AT, TMP0, TMP2 - | ld KBASE, -4+PC2PROTO(k)(PC) - | beqz AT, ->vm_growstack_l - |. sd TMP3, 8(TMP1) // Store delta + FRAME_VARG. - | lbu TMP2, -4+PC2PROTO(numparams)(PC) - | move RA, BASE - | move RC, TMP1 - | ins_next1 - | beqz TMP2, >3 - |. daddiu BASE, TMP1, 16 - |1: - | ld TMP0, 0(RA) - | sltu AT, RA, RC // Less args than parameters? - | move CARG1, TMP0 - | movz TMP0, TISNIL, AT // Clear missing parameters. - | movn CARG1, TISNIL, AT // Clear old fixarg slot (help the GC). - | addiu TMP2, TMP2, -1 - | sd TMP0, 16(TMP1) - | daddiu TMP1, TMP1, 8 - | sd CARG1, 0(RA) - | bnez TMP2, <1 - |. daddiu RA, RA, 8 - |3: - | ins_next2 - break; - - case BC_FUNCC: - case BC_FUNCCW: - | // BASE = new base, RA = BASE+framesize*8, RB = CFUNC, RC = nargs*8 - if (op == BC_FUNCC) { - | ld CFUNCADDR, CFUNC:RB->f - } else { - | ld CFUNCADDR, DISPATCH_GL(wrapf)(DISPATCH) - } - | daddu TMP1, RA, NARGS8:RC - | ld TMP2, L->maxstack - | daddu RC, BASE, NARGS8:RC - | sd BASE, L->base - | sltu AT, TMP2, TMP1 - | sd RC, L->top - | li_vmstate C - if (op == BC_FUNCCW) { - | ld CARG2, CFUNC:RB->f - } - | bnez AT, ->vm_growstack_c // Need to grow stack. - |. move CARG1, L - | jalr CFUNCADDR // (lua_State *L [, lua_CFunction f]) - |. st_vmstate - | // Returns nresults. - | ld BASE, L->base - | sll RD, CRET1, 3 - | ld TMP1, L->top - | li_vmstate INTERP - | ld PC, FRAME_PC(BASE) // Fetch PC of caller. - | dsubu RA, TMP1, RD // RA = L->top - nresults*8 - | sd L, DISPATCH_GL(cur_L)(DISPATCH) - | b ->vm_returnc - |. st_vmstate - break; - - /* ---------------------------------------------------------------------- */ - - default: - fprintf(stderr, "Error: undefined opcode BC_%s\n", bc_names[op]); - exit(2); - break; - } -} - -static int build_backend(BuildCtx *ctx) -{ - int op; - - dasm_growpc(Dst, BC__MAX); - - build_subroutines(ctx); - - |.code_op - for (op = 0; op < BC__MAX; op++) - build_ins(ctx, (BCOp)op, op); - - return BC__MAX; -} - -/* Emit pseudo frame-info for all assembler functions. */ -static void emit_asm_debug(BuildCtx *ctx) -{ - int fcofs = (int)((uint8_t *)ctx->glob[GLOB_vm_ffi_call] - ctx->code); - int i; - switch (ctx->mode) { - case BUILD_elfasm: - fprintf(ctx->fp, "\t.section .debug_frame,\"\",@progbits\n"); - fprintf(ctx->fp, - ".Lframe0:\n" - "\t.4byte .LECIE0-.LSCIE0\n" - ".LSCIE0:\n" - "\t.4byte 0xffffffff\n" - "\t.byte 0x1\n" - "\t.string \"\"\n" - "\t.uleb128 0x1\n" - "\t.sleb128 -4\n" - "\t.byte 31\n" - "\t.byte 0xc\n\t.uleb128 29\n\t.uleb128 0\n" - "\t.align 2\n" - ".LECIE0:\n\n"); - fprintf(ctx->fp, - ".LSFDE0:\n" - "\t.4byte .LEFDE0-.LASFDE0\n" - ".LASFDE0:\n" - "\t.4byte .Lframe0\n" - "\t.8byte .Lbegin\n" - "\t.8byte %d\n" - "\t.byte 0xe\n\t.uleb128 %d\n" - "\t.byte 0x9f\n\t.sleb128 2*5\n" - "\t.byte 0x9e\n\t.sleb128 2*6\n", - fcofs, CFRAME_SIZE); - for (i = 23; i >= 16; i--) - fprintf(ctx->fp, "\t.byte %d\n\t.uleb128 %d\n", 0x80+i, 2*(30-i)); -#if !LJ_SOFTFP - for (i = 31; i >= 24; i--) - fprintf(ctx->fp, "\t.byte %d\n\t.uleb128 %d\n", 0x80+32+i, 2*(46-i)); -#endif - fprintf(ctx->fp, - "\t.align 2\n" - ".LEFDE0:\n\n"); -#if LJ_HASFFI - fprintf(ctx->fp, - ".LSFDE1:\n" - "\t.4byte .LEFDE1-.LASFDE1\n" - ".LASFDE1:\n" - "\t.4byte .Lframe0\n" - "\t.4byte lj_vm_ffi_call\n" - "\t.4byte %d\n" - "\t.byte 0x9f\n\t.uleb128 2*1\n" - "\t.byte 0x90\n\t.uleb128 2*2\n" - "\t.byte 0xd\n\t.uleb128 0x10\n" - "\t.align 2\n" - ".LEFDE1:\n\n", (int)ctx->codesz - fcofs); -#endif -#if !LJ_NO_UNWIND - /* NYI */ -#endif - break; - default: - break; - } -} - diff --git a/lib/LuaJIT/src/vm_ppc.dasc b/lib/LuaJIT/src/vm_ppc.dasc deleted file mode 100644 index 0839668..0000000 --- a/lib/LuaJIT/src/vm_ppc.dasc +++ /dev/null @@ -1,6053 +0,0 @@ -|// Low-level VM code for PowerPC 32 bit or 32on64 bit mode. -|// Bytecode interpreter, fast functions and helper functions. -|// Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -| -|.arch ppc -|.section code_op, code_sub -| -|.actionlist build_actionlist -|.globals GLOB_ -|.globalnames globnames -|.externnames extnames -| -|// Note: The ragged indentation of the instructions is intentional. -|// The starting columns indicate data dependencies. -| -|//----------------------------------------------------------------------- -| -|// DynASM defines used by the PPC port: -|// -|// P64 64 bit pointers (only for GPR64 testing). -|// Note: see vm_ppc64.dasc for a full PPC64 _LP64 port. -|// GPR64 64 bit registers (but possibly 32 bit pointers, e.g. PS3). -|// Affects reg saves, stack layout, carry/overflow/dot flags etc. -|// FRAME32 Use 32 bit frame layout, even with GPR64 (Xbox 360). -|// TOC Need table of contents (64 bit or 32 bit variant, e.g. PS3). -|// Function pointers are really a struct: code, TOC, env (optional). -|// TOCENV Function pointers have an environment pointer, too (not on PS3). -|// PPE Power Processor Element of Cell (PS3) or Xenon (Xbox 360). -|// Must avoid (slow) micro-coded instructions. -| -|.if P64 -|.define TOC, 1 -|.define TOCENV, 1 -|.macro lpx, a, b, c; ldx a, b, c; .endmacro -|.macro lp, a, b; ld a, b; .endmacro -|.macro stp, a, b; std a, b; .endmacro -|.define decode_OPP, decode_OP8 -|.if FFI -|// Missing: Calling conventions, 64 bit regs, TOC. -|.error lib_ffi not yet implemented for PPC64 -|.endif -|.else -|.macro lpx, a, b, c; lwzx a, b, c; .endmacro -|.macro lp, a, b; lwz a, b; .endmacro -|.macro stp, a, b; stw a, b; .endmacro -|.define decode_OPP, decode_OP4 -|.endif -| -|// Convenience macros for TOC handling. -|.if TOC -|// Linker needs a TOC patch area for every external call relocation. -|.macro blex, target; bl extern target@plt; nop; .endmacro -|.macro .toc, a, b; a, b; .endmacro -|.if P64 -|.define TOC_OFS, 8 -|.define ENV_OFS, 16 -|.else -|.define TOC_OFS, 4 -|.define ENV_OFS, 8 -|.endif -|.else // No TOC. -|.macro blex, target; bl extern target@plt; .endmacro -|.macro .toc, a, b; .endmacro -|.endif -|.macro .tocenv, a, b; .if TOCENV; a, b; .endif; .endmacro -| -|.macro .gpr64, a, b; .if GPR64; a, b; .endif; .endmacro -| -|.macro andix., y, a, i -|.if PPE -| rlwinm y, a, 0, 31-lj_fls(i), 31-lj_ffs(i) -| cmpwi y, 0 -|.else -| andi. y, a, i -|.endif -|.endmacro -| -|.macro clrso, reg -|.if PPE -| li reg, 0 -| mtxer reg -|.else -| mcrxr cr0 -|.endif -|.endmacro -| -|.macro checkov, reg, noov -|.if PPE -| mfxer reg -| add reg, reg, reg -| cmpwi reg, 0 -| li reg, 0 -| mtxer reg -| bgey noov -|.else -| mcrxr cr0 -| bley noov -|.endif -|.endmacro -| -|//----------------------------------------------------------------------- -| -|// Fixed register assignments for the interpreter. -|// Don't use: r1 = sp, r2 and r13 = reserved (TOC, TLS or SDATA) -| -|.macro .FPU, a, b -|.if FPU -| a, b -|.endif -|.endmacro -| -|.macro .FPU, a, b, c -|.if FPU -| a, b, c -|.endif -|.endmacro -| -|// The following must be C callee-save (but BASE is often refetched). -|.define BASE, r14 // Base of current Lua stack frame. -|.define KBASE, r15 // Constants of current Lua function. -|.define PC, r16 // Next PC. -|.define DISPATCH, r17 // Opcode dispatch table. -|.define LREG, r18 // Register holding lua_State (also in SAVE_L). -|.define MULTRES, r19 // Size of multi-result: (nresults+1)*8. -|.define JGL, r31 // On-trace: global_State + 32768. -| -|// Constants for type-comparisons, stores and conversions. C callee-save. -|.define TISNUM, r22 -|.define TISNIL, r23 -|.define ZERO, r24 -|.if FPU -|.define TOBIT, f30 // 2^52 + 2^51. -|.define TONUM, f31 // 2^52 + 2^51 + 2^31. -|.endif -| -|// The following temporaries are not saved across C calls, except for RA. -|.define RA, r20 // Callee-save. -|.define RB, r10 -|.define RC, r11 -|.define RD, r12 -|.define INS, r7 // Overlaps CARG5. -| -|.define TMP0, r0 -|.define TMP1, r8 -|.define TMP2, r9 -|.define TMP3, r6 // Overlaps CARG4. -| -|// Saved temporaries. -|.define SAVE0, r21 -|.define SAVE1, r25 -| -|// Calling conventions. -|.define CARG1, r3 -|.define CARG2, r4 -|.define CARG3, r5 -|.define CARG4, r6 // Overlaps TMP3. -|.define CARG5, r7 // Overlaps INS. -| -|.if FPU -|.define FARG1, f1 -|.define FARG2, f2 -|.endif -| -|.define CRET1, r3 -|.define CRET2, r4 -| -|.define TOCREG, r2 // TOC register (only used by C code). -|.define ENVREG, r11 // Environment pointer (nested C functions). -| -|// Stack layout while in interpreter. Must match with lj_frame.h. -|.if GPR64 -|.if FRAME32 -| -|// 456(sp) // \ 32/64 bit C frame info -|.define TONUM_LO, 452(sp) // | -|.define TONUM_HI, 448(sp) // | -|.define TMPD_LO, 444(sp) // | -|.define TMPD_HI, 440(sp) // | -|.define SAVE_CR, 432(sp) // | 64 bit CR save. -|.define SAVE_ERRF, 424(sp) // > Parameter save area. -|.define SAVE_NRES, 420(sp) // | -|.define SAVE_L, 416(sp) // | -|.define SAVE_PC, 412(sp) // | -|.define SAVE_MULTRES, 408(sp) // | -|.define SAVE_CFRAME, 400(sp) // / 64 bit C frame chain. -|// 392(sp) // Reserved. -|.define CFRAME_SPACE, 384 // Delta for sp. -|// Back chain for sp: 384(sp) <-- sp entering interpreter -|.define SAVE_LR, 376(sp) // 32 bit LR stored in hi-part. -|.define SAVE_GPR_, 232 // .. 232+18*8: 64 bit GPR saves. -|.define SAVE_FPR_, 88 // .. 88+18*8: 64 bit FPR saves. -|// 80(sp) // Needed for 16 byte stack frame alignment. -|// 16(sp) // Callee parameter save area (ABI mandated). -|// 8(sp) // Reserved -|// Back chain for sp: 0(sp) <-- sp while in interpreter -|// 32 bit sp stored in hi-part of 0(sp). -| -|.define TMPD_BLO, 447(sp) -|.define TMPD, TMPD_HI -|.define TONUM_D, TONUM_HI -| -|.else -| -|// 508(sp) // \ 32 bit C frame info. -|.define SAVE_ERRF, 472(sp) // | -|.define SAVE_NRES, 468(sp) // | -|.define SAVE_L, 464(sp) // > Parameter save area. -|.define SAVE_PC, 460(sp) // | -|.define SAVE_MULTRES, 456(sp) // | -|.define SAVE_CFRAME, 448(sp) // / 64 bit C frame chain. -|.define SAVE_LR, 416(sp) -|.define CFRAME_SPACE, 400 // Delta for sp. -|// Back chain for sp: 400(sp) <-- sp entering interpreter -|.define SAVE_FPR_, 256 // .. 256+18*8: 64 bit FPR saves. -|.define SAVE_GPR_, 112 // .. 112+18*8: 64 bit GPR saves. -|// 48(sp) // Callee parameter save area (ABI mandated). -|.define SAVE_TOC, 40(sp) // TOC save area. -|.define TMPD_LO, 36(sp) // \ Link editor temp (ABI mandated). -|.define TMPD_HI, 32(sp) // / -|.define TONUM_LO, 28(sp) // \ Compiler temp (ABI mandated). -|.define TONUM_HI, 24(sp) // / -|// Next frame lr: 16(sp) -|.define SAVE_CR, 8(sp) // 64 bit CR save. -|// Back chain for sp: 0(sp) <-- sp while in interpreter -| -|.define TMPD_BLO, 39(sp) -|.define TMPD, TMPD_HI -|.define TONUM_D, TONUM_HI -| -|.endif -|.else -| -|.if FPU -|.define SAVE_LR, 276(sp) -|.define CFRAME_SPACE, 272 // Delta for sp. -|// Back chain for sp: 272(sp) <-- sp entering interpreter -|.define SAVE_FPR_, 128 // .. 128+18*8: 64 bit FPR saves. -|.else -|.define SAVE_LR, 132(sp) -|.define CFRAME_SPACE, 128 // Delta for sp. -|// Back chain for sp: 128(sp) <-- sp entering interpreter -|.endif -|.define SAVE_GPR_, 56 // .. 56+18*4: 32 bit GPR saves. -|.define SAVE_CR, 52(sp) // 32 bit CR save. -|.define SAVE_ERRF, 48(sp) // 32 bit C frame info. -|.define SAVE_NRES, 44(sp) -|.define SAVE_CFRAME, 40(sp) -|.define SAVE_L, 36(sp) -|.define SAVE_PC, 32(sp) -|.define SAVE_MULTRES, 28(sp) -|.define UNUSED1, 24(sp) -|.if FPU -|.define TMPD_LO, 20(sp) -|.define TMPD_HI, 16(sp) -|.define TONUM_LO, 12(sp) -|.define TONUM_HI, 8(sp) -|.else -|.define SFSAVE_4, 20(sp) -|.define SFSAVE_3, 16(sp) -|.define SFSAVE_2, 12(sp) -|.define SFSAVE_1, 8(sp) -|.endif -|// Next frame lr: 4(sp) -|// Back chain for sp: 0(sp) <-- sp while in interpreter -| -|.if FPU -|.define TMPD_BLO, 23(sp) -|.define TMPD, TMPD_HI -|.define TONUM_D, TONUM_HI -|.endif -| -|.endif -| -|.macro save_, reg -|.if GPR64 -| std r..reg, SAVE_GPR_+(reg-14)*8(sp) -|.else -| stw r..reg, SAVE_GPR_+(reg-14)*4(sp) -|.endif -| .FPU stfd f..reg, SAVE_FPR_+(reg-14)*8(sp) -|.endmacro -|.macro rest_, reg -|.if GPR64 -| ld r..reg, SAVE_GPR_+(reg-14)*8(sp) -|.else -| lwz r..reg, SAVE_GPR_+(reg-14)*4(sp) -|.endif -| .FPU lfd f..reg, SAVE_FPR_+(reg-14)*8(sp) -|.endmacro -| -|.macro saveregs -|.if GPR64 and not FRAME32 -| stdu sp, -CFRAME_SPACE(sp) -|.else -| stwu sp, -CFRAME_SPACE(sp) -|.endif -| save_ 14; save_ 15; save_ 16 -| mflr r0 -| save_ 17; save_ 18; save_ 19; save_ 20; save_ 21; save_ 22 -|.if GPR64 and not FRAME32 -| std r0, SAVE_LR -|.else -| stw r0, SAVE_LR -|.endif -| save_ 23; save_ 24; save_ 25 -| mfcr r0 -| save_ 26; save_ 27; save_ 28; save_ 29; save_ 30; save_ 31 -|.if GPR64 -| std r0, SAVE_CR -|.else -| stw r0, SAVE_CR -|.endif -| .toc std TOCREG, SAVE_TOC -|.endmacro -| -|.macro restoreregs -|.if GPR64 and not FRAME32 -| ld r0, SAVE_LR -|.else -| lwz r0, SAVE_LR -|.endif -|.if GPR64 -| ld r12, SAVE_CR -|.else -| lwz r12, SAVE_CR -|.endif -| rest_ 14; rest_ 15; rest_ 16; rest_ 17; rest_ 18; rest_ 19 -| mtlr r0; -|.if PPE; mtocrf 0x20, r12; .else; mtcrf 0x38, r12; .endif -| rest_ 20; rest_ 21; rest_ 22; rest_ 23; rest_ 24; rest_ 25 -|.if PPE; mtocrf 0x10, r12; .endif -| rest_ 26; rest_ 27; rest_ 28; rest_ 29; rest_ 30; rest_ 31 -|.if PPE; mtocrf 0x08, r12; .endif -| addi sp, sp, CFRAME_SPACE -|.endmacro -| -|// Type definitions. Some of these are only used for documentation. -|.type L, lua_State, LREG -|.type GL, global_State -|.type TVALUE, TValue -|.type GCOBJ, GCobj -|.type STR, GCstr -|.type TAB, GCtab -|.type LFUNC, GCfuncL -|.type CFUNC, GCfuncC -|.type PROTO, GCproto -|.type UPVAL, GCupval -|.type NODE, Node -|.type NARGS8, int -|.type TRACE, GCtrace -|.type SBUF, SBuf -| -|//----------------------------------------------------------------------- -| -|// Trap for not-yet-implemented parts. -|.macro NYI; tw 4, sp, sp; .endmacro -| -|.if FPU -|// int/FP conversions. -|.macro tonum_i, freg, reg -| xoris reg, reg, 0x8000 -| stw reg, TONUM_LO -| lfd freg, TONUM_D -| fsub freg, freg, TONUM -|.endmacro -| -|.macro tonum_u, freg, reg -| stw reg, TONUM_LO -| lfd freg, TONUM_D -| fsub freg, freg, TOBIT -|.endmacro -| -|.macro toint, reg, freg, tmpfreg -| fctiwz tmpfreg, freg -| stfd tmpfreg, TMPD -| lwz reg, TMPD_LO -|.endmacro -| -|.macro toint, reg, freg -| toint reg, freg, freg -|.endmacro -|.endif -| -|//----------------------------------------------------------------------- -| -|// Access to frame relative to BASE. -|.define FRAME_PC, -8 -|.define FRAME_FUNC, -4 -| -|// Instruction decode. -|.macro decode_OP4, dst, ins; rlwinm dst, ins, 2, 22, 29; .endmacro -|.macro decode_OP8, dst, ins; rlwinm dst, ins, 3, 21, 28; .endmacro -|.macro decode_RA8, dst, ins; rlwinm dst, ins, 27, 21, 28; .endmacro -|.macro decode_RB8, dst, ins; rlwinm dst, ins, 11, 21, 28; .endmacro -|.macro decode_RC8, dst, ins; rlwinm dst, ins, 19, 21, 28; .endmacro -|.macro decode_RD8, dst, ins; rlwinm dst, ins, 19, 13, 28; .endmacro -| -|.macro decode_OP1, dst, ins; rlwinm dst, ins, 0, 24, 31; .endmacro -|.macro decode_RD4, dst, ins; rlwinm dst, ins, 18, 14, 29; .endmacro -| -|// Instruction fetch. -|.macro ins_NEXT1 -| lwz INS, 0(PC) -| addi PC, PC, 4 -|.endmacro -|// Instruction decode+dispatch. Note: optimized for e300! -|.macro ins_NEXT2 -| decode_OPP TMP1, INS -| lpx TMP0, DISPATCH, TMP1 -| mtctr TMP0 -| decode_RB8 RB, INS -| decode_RD8 RD, INS -| decode_RA8 RA, INS -| decode_RC8 RC, INS -| bctr -|.endmacro -|.macro ins_NEXT -| ins_NEXT1 -| ins_NEXT2 -|.endmacro -| -|// Instruction footer. -|.if 1 -| // Replicated dispatch. Less unpredictable branches, but higher I-Cache use. -| .define ins_next, ins_NEXT -| .define ins_next_, ins_NEXT -| .define ins_next1, ins_NEXT1 -| .define ins_next2, ins_NEXT2 -|.else -| // Common dispatch. Lower I-Cache use, only one (very) unpredictable branch. -| // Affects only certain kinds of benchmarks (and only with -j off). -| .macro ins_next -| b ->ins_next -| .endmacro -| .macro ins_next1 -| .endmacro -| .macro ins_next2 -| b ->ins_next -| .endmacro -| .macro ins_next_ -| ->ins_next: -| ins_NEXT -| .endmacro -|.endif -| -|// Call decode and dispatch. -|.macro ins_callt -| // BASE = new base, RB = LFUNC/CFUNC, RC = nargs*8, FRAME_PC(BASE) = PC -| lwz PC, LFUNC:RB->pc -| lwz INS, 0(PC) -| addi PC, PC, 4 -| decode_OPP TMP1, INS -| decode_RA8 RA, INS -| lpx TMP0, DISPATCH, TMP1 -| add RA, RA, BASE -| mtctr TMP0 -| bctr -|.endmacro -| -|.macro ins_call -| // BASE = new base, RB = LFUNC/CFUNC, RC = nargs*8, PC = caller PC -| stw PC, FRAME_PC(BASE) -| ins_callt -|.endmacro -| -|//----------------------------------------------------------------------- -| -|// Macros to test operand types. -|.macro checknum, reg; cmplw reg, TISNUM; .endmacro -|.macro checknum, cr, reg; cmplw cr, reg, TISNUM; .endmacro -|.macro checkstr, reg; cmpwi reg, LJ_TSTR; .endmacro -|.macro checktab, reg; cmpwi reg, LJ_TTAB; .endmacro -|.macro checkfunc, reg; cmpwi reg, LJ_TFUNC; .endmacro -|.macro checknil, reg; cmpwi reg, LJ_TNIL; .endmacro -| -|.macro branch_RD -| srwi TMP0, RD, 1 -| addis PC, PC, -(BCBIAS_J*4 >> 16) -| add PC, PC, TMP0 -|.endmacro -| -|// Assumes DISPATCH is relative to GL. -#define DISPATCH_GL(field) (GG_DISP2G + (int)offsetof(global_State, field)) -#define DISPATCH_J(field) (GG_DISP2J + (int)offsetof(jit_State, field)) -| -#define PC2PROTO(field) ((int)offsetof(GCproto, field)-(int)sizeof(GCproto)) -| -|.macro hotcheck, delta, target -| rlwinm TMP1, PC, 31, 25, 30 -| addi TMP1, TMP1, GG_DISP2HOT -| lhzx TMP2, DISPATCH, TMP1 -| addic. TMP2, TMP2, -delta -| sthx TMP2, DISPATCH, TMP1 -| blt target -|.endmacro -| -|.macro hotloop -| hotcheck HOTCOUNT_LOOP, ->vm_hotloop -|.endmacro -| -|.macro hotcall -| hotcheck HOTCOUNT_CALL, ->vm_hotcall -|.endmacro -| -|// Set current VM state. Uses TMP0. -|.macro li_vmstate, st; li TMP0, ~LJ_VMST_..st; .endmacro -|.macro st_vmstate; stw TMP0, DISPATCH_GL(vmstate)(DISPATCH); .endmacro -| -|// Move table write barrier back. Overwrites mark and tmp. -|.macro barrierback, tab, mark, tmp -| lwz tmp, DISPATCH_GL(gc.grayagain)(DISPATCH) -| // Assumes LJ_GC_BLACK is 0x04. -| rlwinm mark, mark, 0, 30, 28 // black2gray(tab) -| stw tab, DISPATCH_GL(gc.grayagain)(DISPATCH) -| stb mark, tab->marked -| stw tmp, tab->gclist -|.endmacro -| -|//----------------------------------------------------------------------- - -/* Generate subroutines used by opcodes and other parts of the VM. */ -/* The .code_sub section should be last to help static branch prediction. */ -static void build_subroutines(BuildCtx *ctx) -{ - |.code_sub - | - |//----------------------------------------------------------------------- - |//-- Return handling ---------------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_returnp: - | // See vm_return. Also: TMP2 = previous base. - | andix. TMP0, PC, FRAME_P - | li TMP1, LJ_TTRUE - | beq ->cont_dispatch - | - | // Return from pcall or xpcall fast func. - | lwz PC, FRAME_PC(TMP2) // Fetch PC of previous frame. - | mr BASE, TMP2 // Restore caller base. - | // Prepending may overwrite the pcall frame, so do it at the end. - | stwu TMP1, FRAME_PC(RA) // Prepend true to results. - | - |->vm_returnc: - | addi RD, RD, 8 // RD = (nresults+1)*8. - | andix. TMP0, PC, FRAME_TYPE - | cmpwi cr1, RD, 0 - | li CRET1, LUA_YIELD - | beq cr1, ->vm_unwind_c_eh - | mr MULTRES, RD - | beq ->BC_RET_Z // Handle regular return to Lua. - | - |->vm_return: - | // BASE = base, RA = resultptr, RD/MULTRES = (nresults+1)*8, PC = return - | // TMP0 = PC & FRAME_TYPE - | cmpwi TMP0, FRAME_C - | rlwinm TMP2, PC, 0, 0, 28 - | li_vmstate C - | sub TMP2, BASE, TMP2 // TMP2 = previous base. - | bney ->vm_returnp - | - | addic. TMP1, RD, -8 - | stp TMP2, L->base - | lwz TMP2, SAVE_NRES - | subi BASE, BASE, 8 - | st_vmstate - | slwi TMP2, TMP2, 3 - | beq >2 - |1: - | addic. TMP1, TMP1, -8 - |.if FPU - | lfd f0, 0(RA) - |.else - | lwz CARG1, 0(RA) - | lwz CARG2, 4(RA) - |.endif - | addi RA, RA, 8 - |.if FPU - | stfd f0, 0(BASE) - |.else - | stw CARG1, 0(BASE) - | stw CARG2, 4(BASE) - |.endif - | addi BASE, BASE, 8 - | bney <1 - | - |2: - | cmpw TMP2, RD // More/less results wanted? - | bne >6 - |3: - | stp BASE, L->top // Store new top. - | - |->vm_leave_cp: - | lp TMP0, SAVE_CFRAME // Restore previous C frame. - | li CRET1, 0 // Ok return status for vm_pcall. - | stp TMP0, L->cframe - | - |->vm_leave_unw: - | restoreregs - | blr - | - |6: - | ble >7 // Less results wanted? - | // More results wanted. Check stack size and fill up results with nil. - | lwz TMP1, L->maxstack - | cmplw BASE, TMP1 - | bge >8 - | stw TISNIL, 0(BASE) - | addi RD, RD, 8 - | addi BASE, BASE, 8 - | b <2 - | - |7: // Less results wanted. - | subfic TMP3, TMP2, 0 // LUA_MULTRET+1 case? - | sub TMP0, RD, TMP2 - | subfe TMP1, TMP1, TMP1 // TMP1 = TMP2 == 0 ? 0 : -1 - | and TMP0, TMP0, TMP1 - | sub BASE, BASE, TMP0 // Either keep top or shrink it. - | b <3 - | - |8: // Corner case: need to grow stack for filling up results. - | // This can happen if: - | // - A C function grows the stack (a lot). - | // - The GC shrinks the stack in between. - | // - A return back from a lua_call() with (high) nresults adjustment. - | stp BASE, L->top // Save current top held in BASE (yes). - | mr SAVE0, RD - | srwi CARG2, TMP2, 3 - | mr CARG1, L - | bl extern lj_state_growstack // (lua_State *L, int n) - | lwz TMP2, SAVE_NRES - | mr RD, SAVE0 - | slwi TMP2, TMP2, 3 - | lp BASE, L->top // Need the (realloced) L->top in BASE. - | b <2 - | - |->vm_unwind_c: // Unwind C stack, return from vm_pcall. - | // (void *cframe, int errcode) - | mr sp, CARG1 - | mr CRET1, CARG2 - |->vm_unwind_c_eh: // Landing pad for external unwinder. - | lwz L, SAVE_L - | .toc ld TOCREG, SAVE_TOC - | li TMP0, ~LJ_VMST_C - | lwz GL:TMP1, L->glref - | stw TMP0, GL:TMP1->vmstate - | b ->vm_leave_unw - | - |->vm_unwind_ff: // Unwind C stack, return from ff pcall. - | // (void *cframe) - |.if GPR64 - | rldicr sp, CARG1, 0, 61 - |.else - | rlwinm sp, CARG1, 0, 0, 29 - |.endif - |->vm_unwind_ff_eh: // Landing pad for external unwinder. - | lwz L, SAVE_L - | .toc ld TOCREG, SAVE_TOC - | li TISNUM, LJ_TISNUM // Setup type comparison constants. - | lp BASE, L->base - | .FPU lus TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float). - | lwz DISPATCH, L->glref // Setup pointer to dispatch table. - | li ZERO, 0 - | .FPU stw TMP3, TMPD - | li TMP1, LJ_TFALSE - | .FPU ori TMP3, TMP3, 0x0004 // TONUM = 2^52 + 2^51 + 2^31 (float). - | li TISNIL, LJ_TNIL - | li_vmstate INTERP - | .FPU lfs TOBIT, TMPD - | lwz PC, FRAME_PC(BASE) // Fetch PC of previous frame. - | la RA, -8(BASE) // Results start at BASE-8. - | .FPU stw TMP3, TMPD - | addi DISPATCH, DISPATCH, GG_G2DISP - | stw TMP1, 0(RA) // Prepend false to error message. - | li RD, 16 // 2 results: false + error message. - | st_vmstate - | .FPU lfs TONUM, TMPD - | b ->vm_returnc - | - |//----------------------------------------------------------------------- - |//-- Grow stack for calls ----------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_growstack_c: // Grow stack for C function. - | li CARG2, LUA_MINSTACK - | b >2 - | - |->vm_growstack_l: // Grow stack for Lua function. - | // BASE = new base, RA = BASE+framesize*8, RC = nargs*8, PC = first PC - | add RC, BASE, RC - | sub RA, RA, BASE - | stp BASE, L->base - | addi PC, PC, 4 // Must point after first instruction. - | stp RC, L->top - | srwi CARG2, RA, 3 - |2: - | // L->base = new base, L->top = top - | stw PC, SAVE_PC - | mr CARG1, L - | bl extern lj_state_growstack // (lua_State *L, int n) - | lp BASE, L->base - | lp RC, L->top - | lwz LFUNC:RB, FRAME_FUNC(BASE) - | sub RC, RC, BASE - | // BASE = new base, RB = LFUNC/CFUNC, RC = nargs*8, FRAME_PC(BASE) = PC - | ins_callt // Just retry the call. - | - |//----------------------------------------------------------------------- - |//-- Entry points into the assembler VM --------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_resume: // Setup C frame and resume thread. - | // (lua_State *L, TValue *base, int nres1 = 0, ptrdiff_t ef = 0) - | saveregs - | mr L, CARG1 - | lwz DISPATCH, L->glref // Setup pointer to dispatch table. - | mr BASE, CARG2 - | lbz TMP1, L->status - | stw L, SAVE_L - | li PC, FRAME_CP - | addi TMP0, sp, CFRAME_RESUME - | addi DISPATCH, DISPATCH, GG_G2DISP - | stw CARG3, SAVE_NRES - | cmplwi TMP1, 0 - | stw CARG3, SAVE_ERRF - | stp CARG3, SAVE_CFRAME - | stw CARG1, SAVE_PC // Any value outside of bytecode is ok. - | stp TMP0, L->cframe - | beq >3 - | - | // Resume after yield (like a return). - | stw L, DISPATCH_GL(cur_L)(DISPATCH) - | mr RA, BASE - | lp BASE, L->base - | li TISNUM, LJ_TISNUM // Setup type comparison constants. - | lp TMP1, L->top - | lwz PC, FRAME_PC(BASE) - | .FPU lus TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float). - | stb CARG3, L->status - | .FPU stw TMP3, TMPD - | .FPU ori TMP3, TMP3, 0x0004 // TONUM = 2^52 + 2^51 + 2^31 (float). - | .FPU lfs TOBIT, TMPD - | sub RD, TMP1, BASE - | .FPU stw TMP3, TMPD - | .FPU lus TMP0, 0x4338 // Hiword of 2^52 + 2^51 (double) - | addi RD, RD, 8 - | .FPU stw TMP0, TONUM_HI - | li_vmstate INTERP - | li ZERO, 0 - | st_vmstate - | andix. TMP0, PC, FRAME_TYPE - | mr MULTRES, RD - | .FPU lfs TONUM, TMPD - | li TISNIL, LJ_TNIL - | beq ->BC_RET_Z - | b ->vm_return - | - |->vm_pcall: // Setup protected C frame and enter VM. - | // (lua_State *L, TValue *base, int nres1, ptrdiff_t ef) - | saveregs - | li PC, FRAME_CP - | stw CARG4, SAVE_ERRF - | b >1 - | - |->vm_call: // Setup C frame and enter VM. - | // (lua_State *L, TValue *base, int nres1) - | saveregs - | li PC, FRAME_C - | - |1: // Entry point for vm_pcall above (PC = ftype). - | lp TMP1, L:CARG1->cframe - | mr L, CARG1 - | stw CARG3, SAVE_NRES - | lwz DISPATCH, L->glref // Setup pointer to dispatch table. - | stw CARG1, SAVE_L - | mr BASE, CARG2 - | addi DISPATCH, DISPATCH, GG_G2DISP - | stw CARG1, SAVE_PC // Any value outside of bytecode is ok. - | stp TMP1, SAVE_CFRAME - | stp sp, L->cframe // Add our C frame to cframe chain. - | - |3: // Entry point for vm_cpcall/vm_resume (BASE = base, PC = ftype). - | stw L, DISPATCH_GL(cur_L)(DISPATCH) - | lp TMP2, L->base // TMP2 = old base (used in vmeta_call). - | li TISNUM, LJ_TISNUM // Setup type comparison constants. - | lp TMP1, L->top - | .FPU lus TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float). - | add PC, PC, BASE - | .FPU stw TMP3, TMPD - | li ZERO, 0 - | .FPU ori TMP3, TMP3, 0x0004 // TONUM = 2^52 + 2^51 + 2^31 (float). - | .FPU lfs TOBIT, TMPD - | sub PC, PC, TMP2 // PC = frame delta + frame type - | .FPU stw TMP3, TMPD - | .FPU lus TMP0, 0x4338 // Hiword of 2^52 + 2^51 (double) - | sub NARGS8:RC, TMP1, BASE - | .FPU stw TMP0, TONUM_HI - | li_vmstate INTERP - | .FPU lfs TONUM, TMPD - | li TISNIL, LJ_TNIL - | st_vmstate - | - |->vm_call_dispatch: - | // TMP2 = old base, BASE = new base, RC = nargs*8, PC = caller PC - | lwz TMP0, FRAME_PC(BASE) - | lwz LFUNC:RB, FRAME_FUNC(BASE) - | checkfunc TMP0; bne ->vmeta_call - | - |->vm_call_dispatch_f: - | ins_call - | // BASE = new base, RB = func, RC = nargs*8, PC = caller PC - | - |->vm_cpcall: // Setup protected C frame, call C. - | // (lua_State *L, lua_CFunction func, void *ud, lua_CPFunction cp) - | saveregs - | mr L, CARG1 - | lwz TMP0, L:CARG1->stack - | stw CARG1, SAVE_L - | lp TMP1, L->top - | lwz DISPATCH, L->glref // Setup pointer to dispatch table. - | stw CARG1, SAVE_PC // Any value outside of bytecode is ok. - | sub TMP0, TMP0, TMP1 // Compute -savestack(L, L->top). - | lp TMP1, L->cframe - | addi DISPATCH, DISPATCH, GG_G2DISP - | .toc lp CARG4, 0(CARG4) - | li TMP2, 0 - | stw TMP0, SAVE_NRES // Neg. delta means cframe w/o frame. - | stw TMP2, SAVE_ERRF // No error function. - | stp TMP1, SAVE_CFRAME - | stp sp, L->cframe // Add our C frame to cframe chain. - | stw L, DISPATCH_GL(cur_L)(DISPATCH) - | mtctr CARG4 - | bctrl // (lua_State *L, lua_CFunction func, void *ud) - |.if PPE - | mr BASE, CRET1 - | cmpwi CRET1, 0 - |.else - | mr. BASE, CRET1 - |.endif - | li PC, FRAME_CP - | bne <3 // Else continue with the call. - | b ->vm_leave_cp // No base? Just remove C frame. - | - |//----------------------------------------------------------------------- - |//-- Metamethod handling ------------------------------------------------ - |//----------------------------------------------------------------------- - | - |// The lj_meta_* functions (except for lj_meta_cat) don't reallocate the - |// stack, so BASE doesn't need to be reloaded across these calls. - | - |//-- Continuation dispatch ---------------------------------------------- - | - |->cont_dispatch: - | // BASE = meta base, RA = resultptr, RD = (nresults+1)*8 - | lwz TMP0, -12(BASE) // Continuation. - | mr RB, BASE - | mr BASE, TMP2 // Restore caller BASE. - | lwz LFUNC:TMP1, FRAME_FUNC(TMP2) - |.if FFI - | cmplwi TMP0, 1 - |.endif - | lwz PC, -16(RB) // Restore PC from [cont|PC]. - | subi TMP2, RD, 8 - | lwz TMP1, LFUNC:TMP1->pc - | stwx TISNIL, RA, TMP2 // Ensure one valid arg. - |.if FFI - | ble >1 - |.endif - | lwz KBASE, PC2PROTO(k)(TMP1) - | // BASE = base, RA = resultptr, RB = meta base - | mtctr TMP0 - | bctr // Jump to continuation. - | - |.if FFI - |1: - | beq ->cont_ffi_callback // cont = 1: return from FFI callback. - | // cont = 0: tailcall from C function. - | subi TMP1, RB, 16 - | sub RC, TMP1, BASE - | b ->vm_call_tail - |.endif - | - |->cont_cat: // RA = resultptr, RB = meta base - | lwz INS, -4(PC) - | subi CARG2, RB, 16 - | decode_RB8 SAVE0, INS - |.if FPU - | lfd f0, 0(RA) - |.else - | lwz TMP2, 0(RA) - | lwz TMP3, 4(RA) - |.endif - | add TMP1, BASE, SAVE0 - | stp BASE, L->base - | cmplw TMP1, CARG2 - | sub CARG3, CARG2, TMP1 - | decode_RA8 RA, INS - |.if FPU - | stfd f0, 0(CARG2) - |.else - | stw TMP2, 0(CARG2) - | stw TMP3, 4(CARG2) - |.endif - | bney ->BC_CAT_Z - |.if FPU - | stfdx f0, BASE, RA - |.else - | stwux TMP2, RA, BASE - | stw TMP3, 4(RA) - |.endif - | b ->cont_nop - | - |//-- Table indexing metamethods ----------------------------------------- - | - |->vmeta_tgets1: - | la CARG3, DISPATCH_GL(tmptv)(DISPATCH) - | li TMP0, LJ_TSTR - | decode_RB8 RB, INS - | stw STR:RC, 4(CARG3) - | add CARG2, BASE, RB - | stw TMP0, 0(CARG3) - | b >1 - | - |->vmeta_tgets: - | la CARG2, DISPATCH_GL(tmptv)(DISPATCH) - | li TMP0, LJ_TTAB - | stw TAB:RB, 4(CARG2) - | la CARG3, DISPATCH_GL(tmptv2)(DISPATCH) - | stw TMP0, 0(CARG2) - | li TMP1, LJ_TSTR - | stw STR:RC, 4(CARG3) - | stw TMP1, 0(CARG3) - | b >1 - | - |->vmeta_tgetb: // TMP0 = index - |.if not DUALNUM - | tonum_u f0, TMP0 - |.endif - | decode_RB8 RB, INS - | la CARG3, DISPATCH_GL(tmptv)(DISPATCH) - | add CARG2, BASE, RB - |.if DUALNUM - | stw TISNUM, 0(CARG3) - | stw TMP0, 4(CARG3) - |.else - | stfd f0, 0(CARG3) - |.endif - | b >1 - | - |->vmeta_tgetv: - | decode_RB8 RB, INS - | decode_RC8 RC, INS - | add CARG2, BASE, RB - | add CARG3, BASE, RC - |1: - | stp BASE, L->base - | mr CARG1, L - | stw PC, SAVE_PC - | bl extern lj_meta_tget // (lua_State *L, TValue *o, TValue *k) - | // Returns TValue * (finished) or NULL (metamethod). - | cmplwi CRET1, 0 - | beq >3 - |.if FPU - | lfd f0, 0(CRET1) - |.else - | lwz TMP0, 0(CRET1) - | lwz TMP1, 4(CRET1) - |.endif - | ins_next1 - |.if FPU - | stfdx f0, BASE, RA - |.else - | stwux TMP0, RA, BASE - | stw TMP1, 4(RA) - |.endif - | ins_next2 - | - |3: // Call __index metamethod. - | // BASE = base, L->top = new base, stack = cont/func/t/k - | subfic TMP1, BASE, FRAME_CONT - | lp BASE, L->top - | stw PC, -16(BASE) // [cont|PC] - | add PC, TMP1, BASE - | lwz LFUNC:RB, FRAME_FUNC(BASE) // Guaranteed to be a function here. - | li NARGS8:RC, 16 // 2 args for func(t, k). - | b ->vm_call_dispatch_f - | - |->vmeta_tgetr: - | bl extern lj_tab_getinth // (GCtab *t, int32_t key) - | // Returns cTValue * or NULL. - | cmplwi CRET1, 0 - | beq >1 - |.if FPU - | lfd f14, 0(CRET1) - |.else - | lwz SAVE0, 0(CRET1) - | lwz SAVE1, 4(CRET1) - |.endif - | b ->BC_TGETR_Z - |1: - | stwx TISNIL, BASE, RA - | b ->cont_nop - | - |//----------------------------------------------------------------------- - | - |->vmeta_tsets1: - | la CARG3, DISPATCH_GL(tmptv)(DISPATCH) - | li TMP0, LJ_TSTR - | decode_RB8 RB, INS - | stw STR:RC, 4(CARG3) - | add CARG2, BASE, RB - | stw TMP0, 0(CARG3) - | b >1 - | - |->vmeta_tsets: - | la CARG2, DISPATCH_GL(tmptv)(DISPATCH) - | li TMP0, LJ_TTAB - | stw TAB:RB, 4(CARG2) - | la CARG3, DISPATCH_GL(tmptv2)(DISPATCH) - | stw TMP0, 0(CARG2) - | li TMP1, LJ_TSTR - | stw STR:RC, 4(CARG3) - | stw TMP1, 0(CARG3) - | b >1 - | - |->vmeta_tsetb: // TMP0 = index - |.if not DUALNUM - | tonum_u f0, TMP0 - |.endif - | decode_RB8 RB, INS - | la CARG3, DISPATCH_GL(tmptv)(DISPATCH) - | add CARG2, BASE, RB - |.if DUALNUM - | stw TISNUM, 0(CARG3) - | stw TMP0, 4(CARG3) - |.else - | stfd f0, 0(CARG3) - |.endif - | b >1 - | - |->vmeta_tsetv: - | decode_RB8 RB, INS - | decode_RC8 RC, INS - | add CARG2, BASE, RB - | add CARG3, BASE, RC - |1: - | stp BASE, L->base - | mr CARG1, L - | stw PC, SAVE_PC - | bl extern lj_meta_tset // (lua_State *L, TValue *o, TValue *k) - | // Returns TValue * (finished) or NULL (metamethod). - | cmplwi CRET1, 0 - |.if FPU - | lfdx f0, BASE, RA - |.else - | lwzux TMP2, RA, BASE - | lwz TMP3, 4(RA) - |.endif - | beq >3 - | // NOBARRIER: lj_meta_tset ensures the table is not black. - | ins_next1 - |.if FPU - | stfd f0, 0(CRET1) - |.else - | stw TMP2, 0(CRET1) - | stw TMP3, 4(CRET1) - |.endif - | ins_next2 - | - |3: // Call __newindex metamethod. - | // BASE = base, L->top = new base, stack = cont/func/t/k/(v) - | subfic TMP1, BASE, FRAME_CONT - | lp BASE, L->top - | stw PC, -16(BASE) // [cont|PC] - | add PC, TMP1, BASE - | lwz LFUNC:RB, FRAME_FUNC(BASE) // Guaranteed to be a function here. - | li NARGS8:RC, 24 // 3 args for func(t, k, v) - |.if FPU - | stfd f0, 16(BASE) // Copy value to third argument. - |.else - | stw TMP2, 16(BASE) - | stw TMP3, 20(BASE) - |.endif - | b ->vm_call_dispatch_f - | - |->vmeta_tsetr: - | stp BASE, L->base - | stw PC, SAVE_PC - | bl extern lj_tab_setinth // (lua_State *L, GCtab *t, int32_t key) - | // Returns TValue *. - |.if FPU - | stfd f14, 0(CRET1) - |.else - | stw SAVE0, 0(CRET1) - | stw SAVE1, 4(CRET1) - |.endif - | b ->cont_nop - | - |//-- Comparison metamethods --------------------------------------------- - | - |->vmeta_comp: - | mr CARG1, L - | subi PC, PC, 4 - |.if DUALNUM - | mr CARG2, RA - |.else - | add CARG2, BASE, RA - |.endif - | stw PC, SAVE_PC - |.if DUALNUM - | mr CARG3, RD - |.else - | add CARG3, BASE, RD - |.endif - | stp BASE, L->base - | decode_OP1 CARG4, INS - | bl extern lj_meta_comp // (lua_State *L, TValue *o1, *o2, int op) - | // Returns 0/1 or TValue * (metamethod). - |3: - | cmplwi CRET1, 1 - | bgt ->vmeta_binop - | subfic CRET1, CRET1, 0 - |4: - | lwz INS, 0(PC) - | addi PC, PC, 4 - | decode_RD4 TMP2, INS - | addis TMP2, TMP2, -(BCBIAS_J*4 >> 16) - | and TMP2, TMP2, CRET1 - | add PC, PC, TMP2 - |->cont_nop: - | ins_next - | - |->cont_ra: // RA = resultptr - | lwz INS, -4(PC) - |.if FPU - | lfd f0, 0(RA) - |.else - | lwz CARG1, 0(RA) - | lwz CARG2, 4(RA) - |.endif - | decode_RA8 TMP1, INS - |.if FPU - | stfdx f0, BASE, TMP1 - |.else - | stwux CARG1, TMP1, BASE - | stw CARG2, 4(TMP1) - |.endif - | b ->cont_nop - | - |->cont_condt: // RA = resultptr - | lwz TMP0, 0(RA) - | .gpr64 extsw TMP0, TMP0 - | subfic TMP0, TMP0, LJ_TTRUE // Branch if result is true. - | subfe CRET1, CRET1, CRET1 - | not CRET1, CRET1 - | b <4 - | - |->cont_condf: // RA = resultptr - | lwz TMP0, 0(RA) - | .gpr64 extsw TMP0, TMP0 - | subfic TMP0, TMP0, LJ_TTRUE // Branch if result is false. - | subfe CRET1, CRET1, CRET1 - | b <4 - | - |->vmeta_equal: - | // CARG2, CARG3, CARG4 are already set by BC_ISEQV/BC_ISNEV. - | subi PC, PC, 4 - | stp BASE, L->base - | mr CARG1, L - | stw PC, SAVE_PC - | bl extern lj_meta_equal // (lua_State *L, GCobj *o1, *o2, int ne) - | // Returns 0/1 or TValue * (metamethod). - | b <3 - | - |->vmeta_equal_cd: - |.if FFI - | mr CARG2, INS - | subi PC, PC, 4 - | stp BASE, L->base - | mr CARG1, L - | stw PC, SAVE_PC - | bl extern lj_meta_equal_cd // (lua_State *L, BCIns op) - | // Returns 0/1 or TValue * (metamethod). - | b <3 - |.endif - | - |->vmeta_istype: - | subi PC, PC, 4 - | stp BASE, L->base - | srwi CARG2, RA, 3 - | mr CARG1, L - | srwi CARG3, RD, 3 - | stw PC, SAVE_PC - | bl extern lj_meta_istype // (lua_State *L, BCReg ra, BCReg tp) - | b ->cont_nop - | - |//-- Arithmetic metamethods --------------------------------------------- - | - |->vmeta_arith_nv: - | add CARG3, KBASE, RC - | add CARG4, BASE, RB - | b >1 - |->vmeta_arith_nv2: - |.if DUALNUM - | mr CARG3, RC - | mr CARG4, RB - | b >1 - |.endif - | - |->vmeta_unm: - | mr CARG3, RD - | mr CARG4, RD - | b >1 - | - |->vmeta_arith_vn: - | add CARG3, BASE, RB - | add CARG4, KBASE, RC - | b >1 - | - |->vmeta_arith_vv: - | add CARG3, BASE, RB - | add CARG4, BASE, RC - |.if DUALNUM - | b >1 - |.endif - |->vmeta_arith_vn2: - |->vmeta_arith_vv2: - |.if DUALNUM - | mr CARG3, RB - | mr CARG4, RC - |.endif - |1: - | add CARG2, BASE, RA - | stp BASE, L->base - | mr CARG1, L - | stw PC, SAVE_PC - | decode_OP1 CARG5, INS // Caveat: CARG5 overlaps INS. - | bl extern lj_meta_arith // (lua_State *L, TValue *ra,*rb,*rc, BCReg op) - | // Returns NULL (finished) or TValue * (metamethod). - | cmplwi CRET1, 0 - | beq ->cont_nop - | - | // Call metamethod for binary op. - |->vmeta_binop: - | // BASE = old base, CRET1 = new base, stack = cont/func/o1/o2 - | sub TMP1, CRET1, BASE - | stw PC, -16(CRET1) // [cont|PC] - | mr TMP2, BASE - | addi PC, TMP1, FRAME_CONT - | mr BASE, CRET1 - | li NARGS8:RC, 16 // 2 args for func(o1, o2). - | b ->vm_call_dispatch - | - |->vmeta_len: -#if LJ_52 - | mr SAVE0, CARG1 -#endif - | mr CARG2, RD - | stp BASE, L->base - | mr CARG1, L - | stw PC, SAVE_PC - | bl extern lj_meta_len // (lua_State *L, TValue *o) - | // Returns NULL (retry) or TValue * (metamethod base). -#if LJ_52 - | cmplwi CRET1, 0 - | bne ->vmeta_binop // Binop call for compatibility. - | mr CARG1, SAVE0 - | b ->BC_LEN_Z -#else - | b ->vmeta_binop // Binop call for compatibility. -#endif - | - |//-- Call metamethod ---------------------------------------------------- - | - |->vmeta_call: // Resolve and call __call metamethod. - | // TMP2 = old base, BASE = new base, RC = nargs*8 - | mr CARG1, L - | stp TMP2, L->base // This is the callers base! - | subi CARG2, BASE, 8 - | stw PC, SAVE_PC - | add CARG3, BASE, RC - | mr SAVE0, NARGS8:RC - | bl extern lj_meta_call // (lua_State *L, TValue *func, TValue *top) - | lwz LFUNC:RB, FRAME_FUNC(BASE) // Guaranteed to be a function here. - | addi NARGS8:RC, SAVE0, 8 // Got one more argument now. - | ins_call - | - |->vmeta_callt: // Resolve __call for BC_CALLT. - | // BASE = old base, RA = new base, RC = nargs*8 - | mr CARG1, L - | stp BASE, L->base - | subi CARG2, RA, 8 - | stw PC, SAVE_PC - | add CARG3, RA, RC - | mr SAVE0, NARGS8:RC - | bl extern lj_meta_call // (lua_State *L, TValue *func, TValue *top) - | lwz TMP1, FRAME_PC(BASE) - | addi NARGS8:RC, SAVE0, 8 // Got one more argument now. - | lwz LFUNC:RB, FRAME_FUNC(RA) // Guaranteed to be a function here. - | b ->BC_CALLT_Z - | - |//-- Argument coercion for 'for' statement ------------------------------ - | - |->vmeta_for: - | mr CARG1, L - | stp BASE, L->base - | mr CARG2, RA - | stw PC, SAVE_PC - | mr SAVE0, INS - | bl extern lj_meta_for // (lua_State *L, TValue *base) - |.if JIT - | decode_OP1 TMP0, SAVE0 - |.endif - | decode_RA8 RA, SAVE0 - |.if JIT - | cmpwi TMP0, BC_JFORI - |.endif - | decode_RD8 RD, SAVE0 - |.if JIT - | beqy =>BC_JFORI - |.endif - | b =>BC_FORI - | - |//----------------------------------------------------------------------- - |//-- Fast functions ----------------------------------------------------- - |//----------------------------------------------------------------------- - | - |.macro .ffunc, name - |->ff_ .. name: - |.endmacro - | - |.macro .ffunc_1, name - |->ff_ .. name: - | cmplwi NARGS8:RC, 8 - | lwz CARG3, 0(BASE) - | lwz CARG1, 4(BASE) - | blt ->fff_fallback - |.endmacro - | - |.macro .ffunc_2, name - |->ff_ .. name: - | cmplwi NARGS8:RC, 16 - | lwz CARG3, 0(BASE) - | lwz CARG4, 8(BASE) - | lwz CARG1, 4(BASE) - | lwz CARG2, 12(BASE) - | blt ->fff_fallback - |.endmacro - | - |.macro .ffunc_n, name - |->ff_ .. name: - | cmplwi NARGS8:RC, 8 - | lwz CARG1, 0(BASE) - |.if FPU - | lfd FARG1, 0(BASE) - |.else - | lwz CARG2, 4(BASE) - |.endif - | blt ->fff_fallback - | checknum CARG1; bge ->fff_fallback - |.endmacro - | - |.macro .ffunc_nn, name - |->ff_ .. name: - | cmplwi NARGS8:RC, 16 - | lwz CARG1, 0(BASE) - |.if FPU - | lfd FARG1, 0(BASE) - | lwz CARG3, 8(BASE) - | lfd FARG2, 8(BASE) - |.else - | lwz CARG2, 4(BASE) - | lwz CARG3, 8(BASE) - | lwz CARG4, 12(BASE) - |.endif - | blt ->fff_fallback - | checknum CARG1; bge ->fff_fallback - | checknum CARG3; bge ->fff_fallback - |.endmacro - | - |// Inlined GC threshold check. Caveat: uses TMP0 and TMP1. - |.macro ffgccheck - | lwz TMP0, DISPATCH_GL(gc.total)(DISPATCH) - | lwz TMP1, DISPATCH_GL(gc.threshold)(DISPATCH) - | cmplw TMP0, TMP1 - | bgel ->fff_gcstep - |.endmacro - | - |//-- Base library: checks ----------------------------------------------- - | - |.ffunc_1 assert - | li TMP1, LJ_TFALSE - | la RA, -8(BASE) - | cmplw cr1, CARG3, TMP1 - | lwz PC, FRAME_PC(BASE) - | bge cr1, ->fff_fallback - | stw CARG3, 0(RA) - | addi RD, NARGS8:RC, 8 // Compute (nresults+1)*8. - | addi TMP1, BASE, 8 - | add TMP2, RA, NARGS8:RC - | stw CARG1, 4(RA) - | beq ->fff_res // Done if exactly 1 argument. - |1: - | cmplw TMP1, TMP2 - |.if FPU - | lfd f0, 0(TMP1) - | stfd f0, 0(TMP1) - |.else - | lwz CARG1, 0(TMP1) - | lwz CARG2, 4(TMP1) - | stw CARG1, -8(TMP1) - | stw CARG2, -4(TMP1) - |.endif - | addi TMP1, TMP1, 8 - | bney <1 - | b ->fff_res - | - |.ffunc type - | cmplwi NARGS8:RC, 8 - | lwz CARG1, 0(BASE) - | blt ->fff_fallback - | .gpr64 extsw CARG1, CARG1 - | subfc TMP0, TISNUM, CARG1 - | subfe TMP2, CARG1, CARG1 - | orc TMP1, TMP2, TMP0 - | addi TMP1, TMP1, ~LJ_TISNUM+1 - | slwi TMP1, TMP1, 3 - |.if FPU - | la TMP2, CFUNC:RB->upvalue - | lfdx FARG1, TMP2, TMP1 - |.else - | add TMP1, CFUNC:RB, TMP1 - | lwz CARG1, CFUNC:TMP1->upvalue[0].u32.hi - | lwz CARG2, CFUNC:TMP1->upvalue[0].u32.lo - |.endif - | b ->fff_resn - | - |//-- Base library: getters and setters --------------------------------- - | - |.ffunc_1 getmetatable - | checktab CARG3; bne >6 - |1: // Field metatable must be at same offset for GCtab and GCudata! - | lwz TAB:CARG1, TAB:CARG1->metatable - |2: - | li CARG3, LJ_TNIL - | cmplwi TAB:CARG1, 0 - | lwz STR:RC, DISPATCH_GL(gcroot[GCROOT_MMNAME+MM_metatable])(DISPATCH) - | beq ->fff_restv - | lwz TMP0, TAB:CARG1->hmask - | li CARG3, LJ_TTAB // Use metatable as default result. - | lwz TMP1, STR:RC->hash - | lwz NODE:TMP2, TAB:CARG1->node - | and TMP1, TMP1, TMP0 // idx = str->hash & tab->hmask - | slwi TMP0, TMP1, 5 - | slwi TMP1, TMP1, 3 - | sub TMP1, TMP0, TMP1 - | add NODE:TMP2, NODE:TMP2, TMP1 // node = tab->node + (idx*32-idx*8) - |3: // Rearranged logic, because we expect _not_ to find the key. - | lwz CARG4, NODE:TMP2->key - | lwz TMP0, 4+offsetof(Node, key)(NODE:TMP2) - | lwz CARG2, NODE:TMP2->val - | lwz TMP1, 4+offsetof(Node, val)(NODE:TMP2) - | checkstr CARG4; bne >4 - | cmpw TMP0, STR:RC; beq >5 - |4: - | lwz NODE:TMP2, NODE:TMP2->next - | cmplwi NODE:TMP2, 0 - | beq ->fff_restv // Not found, keep default result. - | b <3 - |5: - | checknil CARG2 - | beq ->fff_restv // Ditto for nil value. - | mr CARG3, CARG2 // Return value of mt.__metatable. - | mr CARG1, TMP1 - | b ->fff_restv - | - |6: - | cmpwi CARG3, LJ_TUDATA; beq <1 - | .gpr64 extsw CARG3, CARG3 - | subfc TMP0, TISNUM, CARG3 - | subfe TMP2, CARG3, CARG3 - | orc TMP1, TMP2, TMP0 - | addi TMP1, TMP1, ~LJ_TISNUM+1 - | slwi TMP1, TMP1, 2 - | la TMP2, DISPATCH_GL(gcroot[GCROOT_BASEMT])(DISPATCH) - | lwzx TAB:CARG1, TMP2, TMP1 - | b <2 - | - |.ffunc_2 setmetatable - | // Fast path: no mt for table yet and not clearing the mt. - | checktab CARG3; bne ->fff_fallback - | lwz TAB:TMP1, TAB:CARG1->metatable - | checktab CARG4; bne ->fff_fallback - | cmplwi TAB:TMP1, 0 - | lbz TMP3, TAB:CARG1->marked - | bne ->fff_fallback - | andix. TMP0, TMP3, LJ_GC_BLACK // isblack(table) - | stw TAB:CARG2, TAB:CARG1->metatable - | beq ->fff_restv - | barrierback TAB:CARG1, TMP3, TMP0 - | b ->fff_restv - | - |.ffunc rawget - | cmplwi NARGS8:RC, 16 - | lwz CARG4, 0(BASE) - | lwz TAB:CARG2, 4(BASE) - | blt ->fff_fallback - | checktab CARG4; bne ->fff_fallback - | la CARG3, 8(BASE) - | mr CARG1, L - | bl extern lj_tab_get // (lua_State *L, GCtab *t, cTValue *key) - | // Returns cTValue *. - |.if FPU - | lfd FARG1, 0(CRET1) - |.else - | lwz CARG2, 4(CRET1) - | lwz CARG1, 0(CRET1) // Caveat: CARG1 == CRET1. - |.endif - | b ->fff_resn - | - |//-- Base library: conversions ------------------------------------------ - | - |.ffunc tonumber - | // Only handles the number case inline (without a base argument). - | cmplwi NARGS8:RC, 8 - | lwz CARG1, 0(BASE) - |.if FPU - | lfd FARG1, 0(BASE) - |.else - | lwz CARG2, 4(BASE) - |.endif - | bne ->fff_fallback // Exactly one argument. - | checknum CARG1; bgt ->fff_fallback - | b ->fff_resn - | - |.ffunc_1 tostring - | // Only handles the string or number case inline. - | checkstr CARG3 - | // A __tostring method in the string base metatable is ignored. - | beq ->fff_restv // String key? - | // Handle numbers inline, unless a number base metatable is present. - | lwz TMP0, DISPATCH_GL(gcroot[GCROOT_BASEMT_NUM])(DISPATCH) - | checknum CARG3 - | cmplwi cr1, TMP0, 0 - | stp BASE, L->base // Add frame since C call can throw. - | crorc 4*cr0+eq, 4*cr0+gt, 4*cr1+eq - | stw PC, SAVE_PC // Redundant (but a defined value). - | beq ->fff_fallback - | ffgccheck - | mr CARG1, L - | mr CARG2, BASE - |.if DUALNUM - | bl extern lj_strfmt_number // (lua_State *L, cTValue *o) - |.else - | bl extern lj_strfmt_num // (lua_State *L, lua_Number *np) - |.endif - | // Returns GCstr *. - | li CARG3, LJ_TSTR - | b ->fff_restv - | - |//-- Base library: iterators ------------------------------------------- - | - |.ffunc next - | cmplwi NARGS8:RC, 8 - | lwz CARG1, 0(BASE) - | lwz TAB:CARG2, 4(BASE) - | blt ->fff_fallback - | stwx TISNIL, BASE, NARGS8:RC // Set missing 2nd arg to nil. - | checktab CARG1 - | lwz PC, FRAME_PC(BASE) - | bne ->fff_fallback - | stp BASE, L->base // Add frame since C call can throw. - | mr CARG1, L - | stp BASE, L->top // Dummy frame length is ok. - | la CARG3, 8(BASE) - | stw PC, SAVE_PC - | bl extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key) - | // Returns 0 at end of traversal. - | cmplwi CRET1, 0 - | li CARG3, LJ_TNIL - | beq ->fff_restv // End of traversal: return nil. - | la RA, -8(BASE) - |.if FPU - | lfd f0, 8(BASE) // Copy key and value to results. - | lfd f1, 16(BASE) - | stfd f0, 0(RA) - | stfd f1, 8(RA) - |.else - | lwz CARG1, 8(BASE) - | lwz CARG2, 12(BASE) - | lwz CARG3, 16(BASE) - | lwz CARG4, 20(BASE) - | stw CARG1, 0(RA) - | stw CARG2, 4(RA) - | stw CARG3, 8(RA) - | stw CARG4, 12(RA) - |.endif - | li RD, (2+1)*8 - | b ->fff_res - | - |.ffunc_1 pairs - | checktab CARG3 - | lwz PC, FRAME_PC(BASE) - | bne ->fff_fallback -#if LJ_52 - | lwz TAB:TMP2, TAB:CARG1->metatable - |.if FPU - | lfd f0, CFUNC:RB->upvalue[0] - |.else - | lwz TMP0, CFUNC:RB->upvalue[0].u32.hi - | lwz TMP1, CFUNC:RB->upvalue[0].u32.lo - |.endif - | cmplwi TAB:TMP2, 0 - | la RA, -8(BASE) - | bne ->fff_fallback -#else - |.if FPU - | lfd f0, CFUNC:RB->upvalue[0] - |.else - | lwz TMP0, CFUNC:RB->upvalue[0].u32.hi - | lwz TMP1, CFUNC:RB->upvalue[0].u32.lo - |.endif - | la RA, -8(BASE) -#endif - | stw TISNIL, 8(BASE) - | li RD, (3+1)*8 - |.if FPU - | stfd f0, 0(RA) - |.else - | stw TMP0, 0(RA) - | stw TMP1, 4(RA) - |.endif - | b ->fff_res - | - |.ffunc ipairs_aux - | cmplwi NARGS8:RC, 16 - | lwz CARG3, 0(BASE) - | lwz TAB:CARG1, 4(BASE) - | lwz CARG4, 8(BASE) - |.if DUALNUM - | lwz TMP2, 12(BASE) - |.else - | lfd FARG2, 8(BASE) - |.endif - | blt ->fff_fallback - | checktab CARG3 - | checknum cr1, CARG4 - | lwz PC, FRAME_PC(BASE) - |.if DUALNUM - | bne ->fff_fallback - | bne cr1, ->fff_fallback - |.else - | lus TMP0, 0x3ff0 - | stw ZERO, TMPD_LO - | bne ->fff_fallback - | stw TMP0, TMPD_HI - | bge cr1, ->fff_fallback - | lfd FARG1, TMPD - | toint TMP2, FARG2, f0 - |.endif - | lwz TMP0, TAB:CARG1->asize - | lwz TMP1, TAB:CARG1->array - |.if not DUALNUM - | fadd FARG2, FARG2, FARG1 - |.endif - | addi TMP2, TMP2, 1 - | la RA, -8(BASE) - | cmplw TMP0, TMP2 - |.if DUALNUM - | stw TISNUM, 0(RA) - | slwi TMP3, TMP2, 3 - | stw TMP2, 4(RA) - |.else - | slwi TMP3, TMP2, 3 - | stfd FARG2, 0(RA) - |.endif - | ble >2 // Not in array part? - |.if FPU - | lwzx TMP2, TMP1, TMP3 - | lfdx f0, TMP1, TMP3 - |.else - | lwzux TMP2, TMP1, TMP3 - | lwz TMP3, 4(TMP1) - |.endif - |1: - | checknil TMP2 - | li RD, (0+1)*8 - | beq ->fff_res // End of iteration, return 0 results. - | li RD, (2+1)*8 - |.if FPU - | stfd f0, 8(RA) - |.else - | stw TMP2, 8(RA) - | stw TMP3, 12(RA) - |.endif - | b ->fff_res - |2: // Check for empty hash part first. Otherwise call C function. - | lwz TMP0, TAB:CARG1->hmask - | cmplwi TMP0, 0 - | li RD, (0+1)*8 - | beq ->fff_res - | mr CARG2, TMP2 - | bl extern lj_tab_getinth // (GCtab *t, int32_t key) - | // Returns cTValue * or NULL. - | cmplwi CRET1, 0 - | li RD, (0+1)*8 - | beq ->fff_res - | lwz TMP2, 0(CRET1) - |.if FPU - | lfd f0, 0(CRET1) - |.else - | lwz TMP3, 4(CRET1) - |.endif - | b <1 - | - |.ffunc_1 ipairs - | checktab CARG3 - | lwz PC, FRAME_PC(BASE) - | bne ->fff_fallback -#if LJ_52 - | lwz TAB:TMP2, TAB:CARG1->metatable - |.if FPU - | lfd f0, CFUNC:RB->upvalue[0] - |.else - | lwz TMP0, CFUNC:RB->upvalue[0].u32.hi - | lwz TMP1, CFUNC:RB->upvalue[0].u32.lo - |.endif - | cmplwi TAB:TMP2, 0 - | la RA, -8(BASE) - | bne ->fff_fallback -#else - |.if FPU - | lfd f0, CFUNC:RB->upvalue[0] - |.else - | lwz TMP0, CFUNC:RB->upvalue[0].u32.hi - | lwz TMP1, CFUNC:RB->upvalue[0].u32.lo - |.endif - | la RA, -8(BASE) -#endif - |.if DUALNUM - | stw TISNUM, 8(BASE) - |.else - | stw ZERO, 8(BASE) - |.endif - | stw ZERO, 12(BASE) - | li RD, (3+1)*8 - |.if FPU - | stfd f0, 0(RA) - |.else - | stw TMP0, 0(RA) - | stw TMP1, 4(RA) - |.endif - | b ->fff_res - | - |//-- Base library: catch errors ---------------------------------------- - | - |.ffunc pcall - | cmplwi NARGS8:RC, 8 - | lbz TMP3, DISPATCH_GL(hookmask)(DISPATCH) - | blt ->fff_fallback - | mr TMP2, BASE - | la BASE, 8(BASE) - | // Remember active hook before pcall. - | rlwinm TMP3, TMP3, 32-HOOK_ACTIVE_SHIFT, 31, 31 - | subi NARGS8:RC, NARGS8:RC, 8 - | addi PC, TMP3, 8+FRAME_PCALL - | b ->vm_call_dispatch - | - |.ffunc xpcall - | cmplwi NARGS8:RC, 16 - | lwz CARG3, 8(BASE) - |.if FPU - | lfd FARG2, 8(BASE) - | lfd FARG1, 0(BASE) - |.else - | lwz CARG1, 0(BASE) - | lwz CARG2, 4(BASE) - | lwz CARG4, 12(BASE) - |.endif - | blt ->fff_fallback - | lbz TMP1, DISPATCH_GL(hookmask)(DISPATCH) - | mr TMP2, BASE - | checkfunc CARG3; bne ->fff_fallback // Traceback must be a function. - | la BASE, 16(BASE) - | // Remember active hook before pcall. - | rlwinm TMP1, TMP1, 32-HOOK_ACTIVE_SHIFT, 31, 31 - |.if FPU - | stfd FARG2, 0(TMP2) // Swap function and traceback. - | stfd FARG1, 8(TMP2) - |.else - | stw CARG3, 0(TMP2) - | stw CARG4, 4(TMP2) - | stw CARG1, 8(TMP2) - | stw CARG2, 12(TMP2) - |.endif - | subi NARGS8:RC, NARGS8:RC, 16 - | addi PC, TMP1, 16+FRAME_PCALL - | b ->vm_call_dispatch - | - |//-- Coroutine library -------------------------------------------------- - | - |.macro coroutine_resume_wrap, resume - |.if resume - |.ffunc_1 coroutine_resume - | cmpwi CARG3, LJ_TTHREAD; bne ->fff_fallback - |.else - |.ffunc coroutine_wrap_aux - | lwz L:CARG1, CFUNC:RB->upvalue[0].gcr - |.endif - | lbz TMP0, L:CARG1->status - | lp TMP1, L:CARG1->cframe - | lp CARG2, L:CARG1->top - | cmplwi cr0, TMP0, LUA_YIELD - | lp TMP2, L:CARG1->base - | cmplwi cr1, TMP1, 0 - | lwz TMP0, L:CARG1->maxstack - | cmplw cr7, CARG2, TMP2 - | lwz PC, FRAME_PC(BASE) - | crorc 4*cr6+lt, 4*cr0+gt, 4*cr1+eq // st>LUA_YIELD || cframe!=0 - | add TMP2, CARG2, NARGS8:RC - | crandc 4*cr6+gt, 4*cr7+eq, 4*cr0+eq // base==top && st!=LUA_YIELD - | cmplw cr1, TMP2, TMP0 - | cror 4*cr6+lt, 4*cr6+lt, 4*cr6+gt - | stw PC, SAVE_PC - | cror 4*cr6+lt, 4*cr6+lt, 4*cr1+gt // cond1 || cond2 || stackov - | stp BASE, L->base - | blt cr6, ->fff_fallback - |1: - |.if resume - | addi BASE, BASE, 8 // Keep resumed thread in stack for GC. - | subi NARGS8:RC, NARGS8:RC, 8 - | subi TMP2, TMP2, 8 - |.endif - | stp TMP2, L:CARG1->top - | li TMP1, 0 - | stp BASE, L->top - |2: // Move args to coroutine. - | cmpw TMP1, NARGS8:RC - |.if FPU - | lfdx f0, BASE, TMP1 - |.else - | add CARG3, BASE, TMP1 - | lwz TMP2, 0(CARG3) - | lwz TMP3, 4(CARG3) - |.endif - | beq >3 - |.if FPU - | stfdx f0, CARG2, TMP1 - |.else - | add CARG3, CARG2, TMP1 - | stw TMP2, 0(CARG3) - | stw TMP3, 4(CARG3) - |.endif - | addi TMP1, TMP1, 8 - | b <2 - |3: - | li CARG3, 0 - | mr L:SAVE0, L:CARG1 - | li CARG4, 0 - | bl ->vm_resume // (lua_State *L, TValue *base, 0, 0) - | // Returns thread status. - |4: - | lp TMP2, L:SAVE0->base - | cmplwi CRET1, LUA_YIELD - | lp TMP3, L:SAVE0->top - | li_vmstate INTERP - | lp BASE, L->base - | stw L, DISPATCH_GL(cur_L)(DISPATCH) - | st_vmstate - | bgt >8 - | sub RD, TMP3, TMP2 - | lwz TMP0, L->maxstack - | cmplwi RD, 0 - | add TMP1, BASE, RD - | beq >6 // No results? - | cmplw TMP1, TMP0 - | li TMP1, 0 - | bgt >9 // Need to grow stack? - | - | subi TMP3, RD, 8 - | stp TMP2, L:SAVE0->top // Clear coroutine stack. - |5: // Move results from coroutine. - | cmplw TMP1, TMP3 - |.if FPU - | lfdx f0, TMP2, TMP1 - | stfdx f0, BASE, TMP1 - |.else - | add CARG3, TMP2, TMP1 - | lwz CARG1, 0(CARG3) - | lwz CARG2, 4(CARG3) - | add CARG3, BASE, TMP1 - | stw CARG1, 0(CARG3) - | stw CARG2, 4(CARG3) - |.endif - | addi TMP1, TMP1, 8 - | bne <5 - |6: - | andix. TMP0, PC, FRAME_TYPE - |.if resume - | li TMP1, LJ_TTRUE - | la RA, -8(BASE) - | stw TMP1, -8(BASE) // Prepend true to results. - | addi RD, RD, 16 - |.else - | mr RA, BASE - | addi RD, RD, 8 - |.endif - |7: - | stw PC, SAVE_PC - | mr MULTRES, RD - | beq ->BC_RET_Z - | b ->vm_return - | - |8: // Coroutine returned with error (at co->top-1). - |.if resume - | andix. TMP0, PC, FRAME_TYPE - | la TMP3, -8(TMP3) - | li TMP1, LJ_TFALSE - |.if FPU - | lfd f0, 0(TMP3) - |.else - | lwz CARG1, 0(TMP3) - | lwz CARG2, 4(TMP3) - |.endif - | stp TMP3, L:SAVE0->top // Remove error from coroutine stack. - | li RD, (2+1)*8 - | stw TMP1, -8(BASE) // Prepend false to results. - | la RA, -8(BASE) - |.if FPU - | stfd f0, 0(BASE) // Copy error message. - |.else - | stw CARG1, 0(BASE) // Copy error message. - | stw CARG2, 4(BASE) - |.endif - | b <7 - |.else - | mr CARG1, L - | mr CARG2, L:SAVE0 - | bl extern lj_ffh_coroutine_wrap_err // (lua_State *L, lua_State *co) - |.endif - | - |9: // Handle stack expansion on return from yield. - | mr CARG1, L - | srwi CARG2, RD, 3 - | bl extern lj_state_growstack // (lua_State *L, int n) - | li CRET1, 0 - | b <4 - |.endmacro - | - | coroutine_resume_wrap 1 // coroutine.resume - | coroutine_resume_wrap 0 // coroutine.wrap - | - |.ffunc coroutine_yield - | lp TMP0, L->cframe - | add TMP1, BASE, NARGS8:RC - | stp BASE, L->base - | andix. TMP0, TMP0, CFRAME_RESUME - | stp TMP1, L->top - | li CRET1, LUA_YIELD - | beq ->fff_fallback - | stp ZERO, L->cframe - | stb CRET1, L->status - | b ->vm_leave_unw - | - |//-- Math library ------------------------------------------------------- - | - |.ffunc_1 math_abs - | checknum CARG3 - |.if DUALNUM - | bne >2 - | srawi TMP1, CARG1, 31 - | xor TMP2, TMP1, CARG1 - |.if GPR64 - | lus TMP0, 0x8000 - | sub CARG1, TMP2, TMP1 - | cmplw CARG1, TMP0 - | beq >1 - |.else - | sub. CARG1, TMP2, TMP1 - | blt >1 - |.endif - |->fff_resi: - | lwz PC, FRAME_PC(BASE) - | la RA, -8(BASE) - | stw TISNUM, -8(BASE) - | stw CRET1, -4(BASE) - | b ->fff_res1 - |1: - | lus CARG3, 0x41e0 // 2^31. - | li CARG1, 0 - | b ->fff_restv - |2: - |.endif - | bge ->fff_fallback - | rlwinm CARG3, CARG3, 0, 1, 31 - | // Fallthrough. - | - |->fff_restv: - | // CARG3/CARG1 = TValue result. - | lwz PC, FRAME_PC(BASE) - | stw CARG3, -8(BASE) - | la RA, -8(BASE) - | stw CARG1, -4(BASE) - |->fff_res1: - | // RA = results, PC = return. - | li RD, (1+1)*8 - |->fff_res: - | // RA = results, RD = (nresults+1)*8, PC = return. - | andix. TMP0, PC, FRAME_TYPE - | mr MULTRES, RD - | bney ->vm_return - | lwz INS, -4(PC) - | decode_RB8 RB, INS - |5: - | cmplw RB, RD // More results expected? - | decode_RA8 TMP0, INS - | bgt >6 - | ins_next1 - | // Adjust BASE. KBASE is assumed to be set for the calling frame. - | sub BASE, RA, TMP0 - | ins_next2 - | - |6: // Fill up results with nil. - | subi TMP1, RD, 8 - | addi RD, RD, 8 - | stwx TISNIL, RA, TMP1 - | b <5 - | - |.macro math_extern, func - | .ffunc_n math_ .. func - | blex func - | b ->fff_resn - |.endmacro - | - |.macro math_extern2, func - | .ffunc_nn math_ .. func - | blex func - | b ->fff_resn - |.endmacro - | - |.macro math_round, func - | .ffunc_1 math_ .. func - | checknum CARG3; beqy ->fff_restv - | rlwinm TMP2, CARG3, 12, 21, 31 - | bge ->fff_fallback - | addic. TMP2, TMP2, -1023 // exp = exponent(x) - 1023 - | cmplwi cr1, TMP2, 31 // 0 <= exp < 31? - | subfic TMP0, TMP2, 31 - | blt >3 - | slwi TMP1, CARG3, 11 - | srwi TMP3, CARG1, 21 - | oris TMP1, TMP1, 0x8000 - | addi TMP2, TMP2, 1 - | or TMP1, TMP1, TMP3 - | slwi CARG2, CARG1, 11 - | bge cr1, >4 - | slw TMP3, TMP1, TMP2 - | srw RD, TMP1, TMP0 - | or TMP3, TMP3, CARG2 - | srawi TMP2, CARG3, 31 - |.if "func" == "floor" - | and TMP1, TMP3, TMP2 - | addic TMP0, TMP1, -1 - | subfe TMP1, TMP0, TMP1 - | add CARG1, RD, TMP1 - | xor CARG1, CARG1, TMP2 - | sub CARG1, CARG1, TMP2 - | b ->fff_resi - |.else - | andc TMP1, TMP3, TMP2 - | addic TMP0, TMP1, -1 - | subfe TMP1, TMP0, TMP1 - | add CARG1, RD, TMP1 - | cmpw CARG1, RD - | xor CARG1, CARG1, TMP2 - | sub CARG1, CARG1, TMP2 - | bge ->fff_resi - | // Overflow to 2^31. - | lus CARG3, 0x41e0 // 2^31. - | li CARG1, 0 - | b ->fff_restv - |.endif - |3: // |x| < 1 - | slwi TMP2, CARG3, 1 - | srawi TMP1, CARG3, 31 - | or TMP2, CARG1, TMP2 // ztest = (hi+hi) | lo - |.if "func" == "floor" - | and TMP1, TMP2, TMP1 // (ztest & sign) == 0 ? 0 : -1 - | subfic TMP2, TMP1, 0 - | subfe CARG1, CARG1, CARG1 - |.else - | andc TMP1, TMP2, TMP1 // (ztest & ~sign) == 0 ? 0 : 1 - | addic TMP2, TMP1, -1 - | subfe CARG1, TMP2, TMP1 - |.endif - | b ->fff_resi - |4: // exp >= 31. Check for -(2^31). - | xoris TMP1, TMP1, 0x8000 - | srawi TMP2, CARG3, 31 - |.if "func" == "floor" - | or TMP1, TMP1, CARG2 - |.endif - |.if PPE - | orc TMP1, TMP1, TMP2 - | cmpwi TMP1, 0 - |.else - | orc. TMP1, TMP1, TMP2 - |.endif - | crand 4*cr0+eq, 4*cr0+eq, 4*cr1+eq - | lus CARG1, 0x8000 // -(2^31). - | beqy ->fff_resi - |5: - |.if FPU - | lfd FARG1, 0(BASE) - |.else - | lwz CARG1, 0(BASE) - | lwz CARG2, 4(BASE) - |.endif - | blex func - | b ->fff_resn - |.endmacro - | - |.if DUALNUM - | math_round floor - | math_round ceil - |.else - | // NYI: use internal implementation. - | math_extern floor - | math_extern ceil - |.endif - | - |.if SQRT - |.ffunc_n math_sqrt - | fsqrt FARG1, FARG1 - | b ->fff_resn - |.else - | math_extern sqrt - |.endif - | - |.ffunc math_log - | cmplwi NARGS8:RC, 8 - | lwz CARG1, 0(BASE) - | bne ->fff_fallback // Need exactly 1 argument. - | checknum CARG1; bge ->fff_fallback - |.if FPU - | lfd FARG1, 0(BASE) - |.else - | lwz CARG2, 4(BASE) - |.endif - | blex log - | b ->fff_resn - | - | math_extern log10 - | math_extern exp - | math_extern sin - | math_extern cos - | math_extern tan - | math_extern asin - | math_extern acos - | math_extern atan - | math_extern sinh - | math_extern cosh - | math_extern tanh - | math_extern2 pow - | math_extern2 atan2 - | math_extern2 fmod - | - |.if DUALNUM - |.ffunc math_ldexp - | cmplwi NARGS8:RC, 16 - | lwz TMP0, 0(BASE) - |.if FPU - | lfd FARG1, 0(BASE) - |.else - | lwz CARG1, 0(BASE) - | lwz CARG2, 4(BASE) - |.endif - | lwz TMP1, 8(BASE) - |.if GPR64 - | lwz CARG2, 12(BASE) - |.elif FPU - | lwz CARG1, 12(BASE) - |.else - | lwz CARG3, 12(BASE) - |.endif - | blt ->fff_fallback - | checknum TMP0; bge ->fff_fallback - | checknum TMP1; bne ->fff_fallback - |.else - |.ffunc_nn math_ldexp - |.if GPR64 - | toint CARG2, FARG2 - |.else - | toint CARG1, FARG2 - |.endif - |.endif - | blex ldexp - | b ->fff_resn - | - |.ffunc_n math_frexp - |.if GPR64 - | la CARG2, DISPATCH_GL(tmptv)(DISPATCH) - |.elif FPU - | la CARG1, DISPATCH_GL(tmptv)(DISPATCH) - |.else - | la CARG3, DISPATCH_GL(tmptv)(DISPATCH) - |.endif - | lwz PC, FRAME_PC(BASE) - | blex frexp - | lwz TMP1, DISPATCH_GL(tmptv)(DISPATCH) - | la RA, -8(BASE) - |.if not DUALNUM - | tonum_i FARG2, TMP1 - |.endif - |.if FPU - | stfd FARG1, 0(RA) - |.else - | stw CRET1, 0(RA) - | stw CRET2, 4(RA) - |.endif - | li RD, (2+1)*8 - |.if DUALNUM - | stw TISNUM, 8(RA) - | stw TMP1, 12(RA) - |.else - | stfd FARG2, 8(RA) - |.endif - | b ->fff_res - | - |.ffunc_n math_modf - |.if GPR64 - | la CARG2, -8(BASE) - |.elif FPU - | la CARG1, -8(BASE) - |.else - | la CARG3, -8(BASE) - |.endif - | lwz PC, FRAME_PC(BASE) - | blex modf - | la RA, -8(BASE) - |.if FPU - | stfd FARG1, 0(BASE) - |.else - | stw CRET1, 0(BASE) - | stw CRET2, 4(BASE) - |.endif - | li RD, (2+1)*8 - | b ->fff_res - | - |.macro math_minmax, name, ismax - |.if DUALNUM - | .ffunc_1 name - | checknum CARG3 - | addi SAVE0, BASE, 8 - | add SAVE1, BASE, NARGS8:RC - | bne >4 - |1: // Handle integers. - | lwz CARG4, 0(SAVE0) - | cmplw cr1, SAVE0, SAVE1 - | lwz CARG2, 4(SAVE0) - | bge cr1, ->fff_resi - | checknum CARG4 - | xoris TMP0, CARG1, 0x8000 - | xoris TMP3, CARG2, 0x8000 - | bne >3 - | subfc TMP3, TMP3, TMP0 - | subfe TMP0, TMP0, TMP0 - |.if ismax - | andc TMP3, TMP3, TMP0 - |.else - | and TMP3, TMP3, TMP0 - |.endif - | add CARG1, TMP3, CARG2 - |.if GPR64 - | rldicl CARG1, CARG1, 0, 32 - |.endif - | addi SAVE0, SAVE0, 8 - | b <1 - |3: - | bge ->fff_fallback - | // Convert intermediate result to number and continue below. - |.if FPU - | tonum_i FARG1, CARG1 - | lfd FARG2, 0(SAVE0) - |.else - | mr CARG2, CARG1 - | bl ->vm_sfi2d_1 - | lwz CARG3, 0(SAVE0) - | lwz CARG4, 4(SAVE0) - |.endif - | b >6 - |4: - |.if FPU - | lfd FARG1, 0(BASE) - |.else - | lwz CARG1, 0(BASE) - | lwz CARG2, 4(BASE) - |.endif - | bge ->fff_fallback - |5: // Handle numbers. - | lwz CARG3, 0(SAVE0) - | cmplw cr1, SAVE0, SAVE1 - |.if FPU - | lfd FARG2, 0(SAVE0) - |.else - | lwz CARG4, 4(SAVE0) - |.endif - | bge cr1, ->fff_resn - | checknum CARG3; bge >7 - |6: - | addi SAVE0, SAVE0, 8 - |.if FPU - | fsub f0, FARG1, FARG2 - |.if ismax - | fsel FARG1, f0, FARG1, FARG2 - |.else - | fsel FARG1, f0, FARG2, FARG1 - |.endif - |.else - | stw CARG1, SFSAVE_1 - | stw CARG2, SFSAVE_2 - | stw CARG3, SFSAVE_3 - | stw CARG4, SFSAVE_4 - | blex __ledf2 - | cmpwi CRET1, 0 - |.if ismax - | blt >8 - |.else - | bge >8 - |.endif - | lwz CARG1, SFSAVE_1 - | lwz CARG2, SFSAVE_2 - | b <5 - |8: - | lwz CARG1, SFSAVE_3 - | lwz CARG2, SFSAVE_4 - |.endif - | b <5 - |7: // Convert integer to number and continue above. - | lwz CARG3, 4(SAVE0) - | bne ->fff_fallback - |.if FPU - | tonum_i FARG2, CARG3 - |.else - | bl ->vm_sfi2d_2 - |.endif - | b <6 - |.else - | .ffunc_n name - | li TMP1, 8 - |1: - | lwzx CARG2, BASE, TMP1 - | lfdx FARG2, BASE, TMP1 - | cmplw cr1, TMP1, NARGS8:RC - | checknum CARG2 - | bge cr1, ->fff_resn - | bge ->fff_fallback - | fsub f0, FARG1, FARG2 - | addi TMP1, TMP1, 8 - |.if ismax - | fsel FARG1, f0, FARG1, FARG2 - |.else - | fsel FARG1, f0, FARG2, FARG1 - |.endif - | b <1 - |.endif - |.endmacro - | - | math_minmax math_min, 0 - | math_minmax math_max, 1 - | - |//-- String library ----------------------------------------------------- - | - |.ffunc string_byte // Only handle the 1-arg case here. - | cmplwi NARGS8:RC, 8 - | lwz CARG3, 0(BASE) - | lwz STR:CARG1, 4(BASE) - | bne ->fff_fallback // Need exactly 1 argument. - | checkstr CARG3 - | bne ->fff_fallback - | lwz TMP0, STR:CARG1->len - |.if DUALNUM - | lbz CARG1, STR:CARG1[1] // Access is always ok (NUL at end). - | li RD, (0+1)*8 - | lwz PC, FRAME_PC(BASE) - | cmplwi TMP0, 0 - | la RA, -8(BASE) - | beqy ->fff_res - | b ->fff_resi - |.else - | lbz TMP1, STR:CARG1[1] // Access is always ok (NUL at end). - | addic TMP3, TMP0, -1 // RD = ((str->len != 0)+1)*8 - | subfe RD, TMP3, TMP0 - | stw TMP1, TONUM_LO // Inlined tonum_u f0, TMP1. - | addi RD, RD, 1 - | lfd f0, TONUM_D - | la RA, -8(BASE) - | lwz PC, FRAME_PC(BASE) - | fsub f0, f0, TOBIT - | slwi RD, RD, 3 - | stfd f0, 0(RA) - | b ->fff_res - |.endif - | - |.ffunc string_char // Only handle the 1-arg case here. - | ffgccheck - | cmplwi NARGS8:RC, 8 - | lwz CARG3, 0(BASE) - |.if DUALNUM - | lwz TMP0, 4(BASE) - | bne ->fff_fallback // Exactly 1 argument. - | checknum CARG3; bne ->fff_fallback - | la CARG2, 7(BASE) - |.else - | lfd FARG1, 0(BASE) - | bne ->fff_fallback // Exactly 1 argument. - | checknum CARG3; bge ->fff_fallback - | toint TMP0, FARG1 - | la CARG2, TMPD_BLO - |.endif - | li CARG3, 1 - | cmplwi TMP0, 255; bgt ->fff_fallback - |->fff_newstr: - | mr CARG1, L - | stp BASE, L->base - | stw PC, SAVE_PC - | bl extern lj_str_new // (lua_State *L, char *str, size_t l) - |->fff_resstr: - | // Returns GCstr *. - | lp BASE, L->base - | li CARG3, LJ_TSTR - | b ->fff_restv - | - |.ffunc string_sub - | ffgccheck - | cmplwi NARGS8:RC, 16 - | lwz CARG3, 16(BASE) - |.if not DUALNUM - | lfd f0, 16(BASE) - |.endif - | lwz TMP0, 0(BASE) - | lwz STR:CARG1, 4(BASE) - | blt ->fff_fallback - | lwz CARG2, 8(BASE) - |.if DUALNUM - | lwz TMP1, 12(BASE) - |.else - | lfd f1, 8(BASE) - |.endif - | li TMP2, -1 - | beq >1 - |.if DUALNUM - | checknum CARG3 - | lwz TMP2, 20(BASE) - | bne ->fff_fallback - |1: - | checknum CARG2; bne ->fff_fallback - |.else - | checknum CARG3; bge ->fff_fallback - | toint TMP2, f0 - |1: - | checknum CARG2; bge ->fff_fallback - |.endif - | checkstr TMP0; bne ->fff_fallback - |.if not DUALNUM - | toint TMP1, f1 - |.endif - | lwz TMP0, STR:CARG1->len - | cmplw TMP0, TMP2 // len < end? (unsigned compare) - | addi TMP3, TMP2, 1 - | blt >5 - |2: - | cmpwi TMP1, 0 // start <= 0? - | add TMP3, TMP1, TMP0 - | ble >7 - |3: - | sub CARG3, TMP2, TMP1 - | addi CARG2, STR:CARG1, #STR-1 - | srawi TMP0, CARG3, 31 - | addi CARG3, CARG3, 1 - | add CARG2, CARG2, TMP1 - | andc CARG3, CARG3, TMP0 - |.if GPR64 - | rldicl CARG2, CARG2, 0, 32 - | rldicl CARG3, CARG3, 0, 32 - |.endif - | b ->fff_newstr - | - |5: // Negative end or overflow. - | cmpw TMP0, TMP2 // len >= end? (signed compare) - | add TMP2, TMP0, TMP3 // Negative end: end = end+len+1. - | bge <2 - | mr TMP2, TMP0 // Overflow: end = len. - | b <2 - | - |7: // Negative start or underflow. - | .gpr64 extsw TMP1, TMP1 - | addic CARG3, TMP1, -1 - | subfe CARG3, CARG3, CARG3 - | srawi CARG2, TMP3, 31 // Note: modifies carry. - | andc TMP3, TMP3, CARG3 - | andc TMP1, TMP3, CARG2 - | addi TMP1, TMP1, 1 // start = 1 + (start ? start+len : 0) - | b <3 - | - |.macro ffstring_op, name - | .ffunc string_ .. name - | ffgccheck - | cmplwi NARGS8:RC, 8 - | lwz CARG3, 0(BASE) - | lwz STR:CARG2, 4(BASE) - | blt ->fff_fallback - | checkstr CARG3 - | la SBUF:CARG1, DISPATCH_GL(tmpbuf)(DISPATCH) - | bne ->fff_fallback - | lwz TMP0, SBUF:CARG1->b - | stw L, SBUF:CARG1->L - | stp BASE, L->base - | stw PC, SAVE_PC - | stw TMP0, SBUF:CARG1->p - | bl extern lj_buf_putstr_ .. name - | bl extern lj_buf_tostr - | b ->fff_resstr - |.endmacro - | - |ffstring_op reverse - |ffstring_op lower - |ffstring_op upper - | - |//-- Bit library -------------------------------------------------------- - | - |.macro .ffunc_bit, name - |.if DUALNUM - | .ffunc_1 bit_..name - | checknum CARG3; bnel ->fff_tobit_fb - |.else - | .ffunc_n bit_..name - | fadd FARG1, FARG1, TOBIT - | stfd FARG1, TMPD - | lwz CARG1, TMPD_LO - |.endif - |.endmacro - | - |.macro .ffunc_bit_op, name, ins - | .ffunc_bit name - | addi SAVE0, BASE, 8 - | add SAVE1, BASE, NARGS8:RC - |1: - | lwz CARG4, 0(SAVE0) - | cmplw cr1, SAVE0, SAVE1 - |.if DUALNUM - | lwz CARG2, 4(SAVE0) - |.else - | lfd FARG1, 0(SAVE0) - |.endif - | bgey cr1, ->fff_resi - | checknum CARG4 - |.if DUALNUM - |.if FPU - | bnel ->fff_bitop_fb - |.else - | beq >3 - | stw CARG1, SFSAVE_1 - | bl ->fff_bitop_fb - | mr CARG2, CARG1 - | lwz CARG1, SFSAVE_1 - |3: - |.endif - |.else - | fadd FARG1, FARG1, TOBIT - | bge ->fff_fallback - | stfd FARG1, TMPD - | lwz CARG2, TMPD_LO - |.endif - | ins CARG1, CARG1, CARG2 - | addi SAVE0, SAVE0, 8 - | b <1 - |.endmacro - | - |.ffunc_bit_op band, and - |.ffunc_bit_op bor, or - |.ffunc_bit_op bxor, xor - | - |.ffunc_bit bswap - | rotlwi TMP0, CARG1, 8 - | rlwimi TMP0, CARG1, 24, 0, 7 - | rlwimi TMP0, CARG1, 24, 16, 23 - | mr CRET1, TMP0 - | b ->fff_resi - | - |.ffunc_bit bnot - | not CRET1, CARG1 - | b ->fff_resi - | - |.macro .ffunc_bit_sh, name, ins, shmod - |.if DUALNUM - | .ffunc_2 bit_..name - |.if FPU - | checknum CARG3; bnel ->fff_tobit_fb - |.else - | checknum CARG3; beq >1 - | bl ->fff_tobit_fb - | lwz CARG2, 12(BASE) // Conversion polluted CARG2. - |1: - |.endif - | // Note: no inline conversion from number for 2nd argument! - | checknum CARG4; bne ->fff_fallback - |.else - | .ffunc_nn bit_..name - | fadd FARG1, FARG1, TOBIT - | fadd FARG2, FARG2, TOBIT - | stfd FARG1, TMPD - | lwz CARG1, TMPD_LO - | stfd FARG2, TMPD - | lwz CARG2, TMPD_LO - |.endif - |.if shmod == 1 - | rlwinm CARG2, CARG2, 0, 27, 31 - |.elif shmod == 2 - | neg CARG2, CARG2 - |.endif - | ins CRET1, CARG1, CARG2 - | b ->fff_resi - |.endmacro - | - |.ffunc_bit_sh lshift, slw, 1 - |.ffunc_bit_sh rshift, srw, 1 - |.ffunc_bit_sh arshift, sraw, 1 - |.ffunc_bit_sh rol, rotlw, 0 - |.ffunc_bit_sh ror, rotlw, 2 - | - |.ffunc_bit tobit - |.if DUALNUM - | b ->fff_resi - |.else - |->fff_resi: - | tonum_i FARG1, CRET1 - |.endif - |->fff_resn: - | lwz PC, FRAME_PC(BASE) - | la RA, -8(BASE) - |.if FPU - | stfd FARG1, -8(BASE) - |.else - | stw CARG1, -8(BASE) - | stw CARG2, -4(BASE) - |.endif - | b ->fff_res1 - | - |// Fallback FP number to bit conversion. - |->fff_tobit_fb: - |.if DUALNUM - |.if FPU - | lfd FARG1, 0(BASE) - | bgt ->fff_fallback - | fadd FARG1, FARG1, TOBIT - | stfd FARG1, TMPD - | lwz CARG1, TMPD_LO - | blr - |.else - | bgt ->fff_fallback - | mr CARG2, CARG1 - | mr CARG1, CARG3 - |// Modifies: CARG1, CARG2, TMP0, TMP1, TMP2. - |->vm_tobit: - | slwi TMP2, CARG1, 1 - | addis TMP2, TMP2, 0x0020 - | cmpwi TMP2, 0 - | bge >2 - | li TMP1, 0x3e0 - | srawi TMP2, TMP2, 21 - | not TMP1, TMP1 - | sub. TMP2, TMP1, TMP2 - | cmpwi cr7, CARG1, 0 - | blt >1 - | slwi TMP1, CARG1, 11 - | srwi TMP0, CARG2, 21 - | oris TMP1, TMP1, 0x8000 - | or TMP1, TMP1, TMP0 - | srw CARG1, TMP1, TMP2 - | bclr 4, 28 // Return if cr7[lt] == 0, no hint. - | neg CARG1, CARG1 - | blr - |1: - | addi TMP2, TMP2, 21 - | srw TMP1, CARG2, TMP2 - | slwi CARG2, CARG1, 12 - | subfic TMP2, TMP2, 20 - | slw TMP0, CARG2, TMP2 - | or CARG1, TMP1, TMP0 - | bclr 4, 28 // Return if cr7[lt] == 0, no hint. - | neg CARG1, CARG1 - | blr - |2: - | li CARG1, 0 - | blr - |.endif - |.endif - |->fff_bitop_fb: - |.if DUALNUM - |.if FPU - | lfd FARG1, 0(SAVE0) - | bgt ->fff_fallback - | fadd FARG1, FARG1, TOBIT - | stfd FARG1, TMPD - | lwz CARG2, TMPD_LO - | blr - |.else - | bgt ->fff_fallback - | mr CARG1, CARG4 - | b ->vm_tobit - |.endif - |.endif - | - |//----------------------------------------------------------------------- - | - |->fff_fallback: // Call fast function fallback handler. - | // BASE = new base, RB = CFUNC, RC = nargs*8 - | lp TMP3, CFUNC:RB->f - | add TMP1, BASE, NARGS8:RC - | lwz PC, FRAME_PC(BASE) // Fallback may overwrite PC. - | addi TMP0, TMP1, 8*LUA_MINSTACK - | lwz TMP2, L->maxstack - | stw PC, SAVE_PC // Redundant (but a defined value). - | .toc lp TMP3, 0(TMP3) - | cmplw TMP0, TMP2 - | stp BASE, L->base - | stp TMP1, L->top - | mr CARG1, L - | bgt >5 // Need to grow stack. - | mtctr TMP3 - | bctrl // (lua_State *L) - | // Either throws an error, or recovers and returns -1, 0 or nresults+1. - | lp BASE, L->base - | cmpwi CRET1, 0 - | slwi RD, CRET1, 3 - | la RA, -8(BASE) - | bgt ->fff_res // Returned nresults+1? - |1: // Returned 0 or -1: retry fast path. - | lp TMP0, L->top - | lwz LFUNC:RB, FRAME_FUNC(BASE) - | sub NARGS8:RC, TMP0, BASE - | bne ->vm_call_tail // Returned -1? - | ins_callt // Returned 0: retry fast path. - | - |// Reconstruct previous base for vmeta_call during tailcall. - |->vm_call_tail: - | andix. TMP0, PC, FRAME_TYPE - | rlwinm TMP1, PC, 0, 0, 28 - | bne >3 - | lwz INS, -4(PC) - | decode_RA8 TMP1, INS - | addi TMP1, TMP1, 8 - |3: - | sub TMP2, BASE, TMP1 - | b ->vm_call_dispatch // Resolve again for tailcall. - | - |5: // Grow stack for fallback handler. - | li CARG2, LUA_MINSTACK - | bl extern lj_state_growstack // (lua_State *L, int n) - | lp BASE, L->base - | cmpw TMP0, TMP0 // Set 4*cr0+eq to force retry. - | b <1 - | - |->fff_gcstep: // Call GC step function. - | // BASE = new base, RC = nargs*8 - | mflr SAVE0 - | stp BASE, L->base - | add TMP0, BASE, NARGS8:RC - | stw PC, SAVE_PC // Redundant (but a defined value). - | stp TMP0, L->top - | mr CARG1, L - | bl extern lj_gc_step // (lua_State *L) - | lp BASE, L->base - | mtlr SAVE0 - | lp TMP0, L->top - | sub NARGS8:RC, TMP0, BASE - | lwz CFUNC:RB, FRAME_FUNC(BASE) - | blr - | - |//----------------------------------------------------------------------- - |//-- Special dispatch targets ------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_record: // Dispatch target for recording phase. - |.if JIT - | lbz TMP3, DISPATCH_GL(hookmask)(DISPATCH) - | andix. TMP0, TMP3, HOOK_VMEVENT // No recording while in vmevent. - | bne >5 - | // Decrement the hookcount for consistency, but always do the call. - | lwz TMP2, DISPATCH_GL(hookcount)(DISPATCH) - | andix. TMP0, TMP3, HOOK_ACTIVE - | bne >1 - | subi TMP2, TMP2, 1 - | andi. TMP0, TMP3, LUA_MASKLINE|LUA_MASKCOUNT - | beqy >1 - | stw TMP2, DISPATCH_GL(hookcount)(DISPATCH) - | b >1 - |.endif - | - |->vm_rethook: // Dispatch target for return hooks. - | lbz TMP3, DISPATCH_GL(hookmask)(DISPATCH) - | andix. TMP0, TMP3, HOOK_ACTIVE // Hook already active? - | beq >1 - |5: // Re-dispatch to static ins. - | addi TMP1, TMP1, GG_DISP2STATIC // Assumes decode_OPP TMP1, INS. - | lpx TMP0, DISPATCH, TMP1 - | mtctr TMP0 - | bctr - | - |->vm_inshook: // Dispatch target for instr/line hooks. - | lbz TMP3, DISPATCH_GL(hookmask)(DISPATCH) - | lwz TMP2, DISPATCH_GL(hookcount)(DISPATCH) - | andix. TMP0, TMP3, HOOK_ACTIVE // Hook already active? - | rlwinm TMP0, TMP3, 31-LUA_HOOKLINE, 31, 0 - | bne <5 - | - | cmpwi cr1, TMP0, 0 - | addic. TMP2, TMP2, -1 - | beq cr1, <5 - | stw TMP2, DISPATCH_GL(hookcount)(DISPATCH) - | beq >1 - | bge cr1, <5 - |1: - | mr CARG1, L - | stw MULTRES, SAVE_MULTRES - | mr CARG2, PC - | stp BASE, L->base - | // SAVE_PC must hold the _previous_ PC. The callee updates it with PC. - | bl extern lj_dispatch_ins // (lua_State *L, const BCIns *pc) - |3: - | lp BASE, L->base - |4: // Re-dispatch to static ins. - | lwz INS, -4(PC) - | decode_OPP TMP1, INS - | decode_RB8 RB, INS - | addi TMP1, TMP1, GG_DISP2STATIC - | decode_RD8 RD, INS - | lpx TMP0, DISPATCH, TMP1 - | decode_RA8 RA, INS - | decode_RC8 RC, INS - | mtctr TMP0 - | bctr - | - |->cont_hook: // Continue from hook yield. - | addi PC, PC, 4 - | lwz MULTRES, -20(RB) // Restore MULTRES for *M ins. - | b <4 - | - |->vm_hotloop: // Hot loop counter underflow. - |.if JIT - | lwz LFUNC:TMP1, FRAME_FUNC(BASE) - | addi CARG1, DISPATCH, GG_DISP2J - | stw PC, SAVE_PC - | lwz TMP1, LFUNC:TMP1->pc - | mr CARG2, PC - | stw L, DISPATCH_J(L)(DISPATCH) - | lbz TMP1, PC2PROTO(framesize)(TMP1) - | stp BASE, L->base - | slwi TMP1, TMP1, 3 - | add TMP1, BASE, TMP1 - | stp TMP1, L->top - | bl extern lj_trace_hot // (jit_State *J, const BCIns *pc) - | b <3 - |.endif - | - |->vm_callhook: // Dispatch target for call hooks. - | mr CARG2, PC - |.if JIT - | b >1 - |.endif - | - |->vm_hotcall: // Hot call counter underflow. - |.if JIT - | ori CARG2, PC, 1 - |1: - |.endif - | add TMP0, BASE, RC - | stw PC, SAVE_PC - | mr CARG1, L - | stp BASE, L->base - | sub RA, RA, BASE - | stp TMP0, L->top - | bl extern lj_dispatch_call // (lua_State *L, const BCIns *pc) - | // Returns ASMFunction. - | lp BASE, L->base - | lp TMP0, L->top - | stw ZERO, SAVE_PC // Invalidate for subsequent line hook. - | sub NARGS8:RC, TMP0, BASE - | add RA, BASE, RA - | lwz LFUNC:RB, FRAME_FUNC(BASE) - | lwz INS, -4(PC) - | mtctr CRET1 - | bctr - | - |->cont_stitch: // Trace stitching. - |.if JIT - | // RA = resultptr, RB = meta base - | lwz INS, -4(PC) - | lwz TRACE:TMP2, -20(RB) // Save previous trace. - | addic. TMP1, MULTRES, -8 - | decode_RA8 RC, INS // Call base. - | beq >2 - |1: // Move results down. - |.if FPU - | lfd f0, 0(RA) - |.else - | lwz CARG1, 0(RA) - | lwz CARG2, 4(RA) - |.endif - | addic. TMP1, TMP1, -8 - | addi RA, RA, 8 - |.if FPU - | stfdx f0, BASE, RC - |.else - | add CARG3, BASE, RC - | stw CARG1, 0(CARG3) - | stw CARG2, 4(CARG3) - |.endif - | addi RC, RC, 8 - | bne <1 - |2: - | decode_RA8 RA, INS - | decode_RB8 RB, INS - | add RA, RA, RB - |3: - | cmplw RA, RC - | bgt >9 // More results wanted? - | - | lhz TMP3, TRACE:TMP2->traceno - | lhz RD, TRACE:TMP2->link - | cmpw RD, TMP3 - | cmpwi cr1, RD, 0 - | beq ->cont_nop // Blacklisted. - | slwi RD, RD, 3 - | bne cr1, =>BC_JLOOP // Jump to stitched trace. - | - | // Stitch a new trace to the previous trace. - | stw TMP3, DISPATCH_J(exitno)(DISPATCH) - | stp L, DISPATCH_J(L)(DISPATCH) - | stp BASE, L->base - | addi CARG1, DISPATCH, GG_DISP2J - | mr CARG2, PC - | bl extern lj_dispatch_stitch // (jit_State *J, const BCIns *pc) - | lp BASE, L->base - | b ->cont_nop - | - |9: - | stwx TISNIL, BASE, RC - | addi RC, RC, 8 - | b <3 - |.endif - | - |->vm_profhook: // Dispatch target for profiler hook. -#if LJ_HASPROFILE - | mr CARG1, L - | stw MULTRES, SAVE_MULTRES - | mr CARG2, PC - | stp BASE, L->base - | bl extern lj_dispatch_profile // (lua_State *L, const BCIns *pc) - | // HOOK_PROFILE is off again, so re-dispatch to dynamic instruction. - | lp BASE, L->base - | subi PC, PC, 4 - | b ->cont_nop -#endif - | - |//----------------------------------------------------------------------- - |//-- Trace exit handler ------------------------------------------------- - |//----------------------------------------------------------------------- - | - |.macro savex_, a, b, c, d - |.if FPU - | stfd f..a, 16+a*8(sp) - | stfd f..b, 16+b*8(sp) - | stfd f..c, 16+c*8(sp) - | stfd f..d, 16+d*8(sp) - |.endif - |.endmacro - | - |->vm_exit_handler: - |.if JIT - | addi sp, sp, -(16+32*8+32*4) - | stmw r2, 16+32*8+2*4(sp) - | addi DISPATCH, JGL, -GG_DISP2G-32768 - | li CARG2, ~LJ_VMST_EXIT - | lwz CARG1, 16+32*8+32*4(sp) // Get stack chain. - | stw CARG2, DISPATCH_GL(vmstate)(DISPATCH) - | savex_ 0,1,2,3 - | stw CARG1, 0(sp) // Store extended stack chain. - | clrso TMP1 - | savex_ 4,5,6,7 - | addi CARG2, sp, 16+32*8+32*4 // Recompute original value of sp. - | savex_ 8,9,10,11 - | stw CARG2, 16+32*8+1*4(sp) // Store sp in RID_SP. - | savex_ 12,13,14,15 - | mflr CARG3 - | li TMP1, 0 - | savex_ 16,17,18,19 - | stw TMP1, 16+32*8+0*4(sp) // Clear RID_TMP. - | savex_ 20,21,22,23 - | lhz CARG4, 2(CARG3) // Load trace number. - | savex_ 24,25,26,27 - | lwz L, DISPATCH_GL(cur_L)(DISPATCH) - | savex_ 28,29,30,31 - | sub CARG3, TMP0, CARG3 // Compute exit number. - | lp BASE, DISPATCH_GL(jit_base)(DISPATCH) - | srwi CARG3, CARG3, 2 - | stp L, DISPATCH_J(L)(DISPATCH) - | subi CARG3, CARG3, 2 - | stp BASE, L->base - | stw CARG4, DISPATCH_J(parent)(DISPATCH) - | stw TMP1, DISPATCH_GL(jit_base)(DISPATCH) - | addi CARG1, DISPATCH, GG_DISP2J - | stw CARG3, DISPATCH_J(exitno)(DISPATCH) - | addi CARG2, sp, 16 - | bl extern lj_trace_exit // (jit_State *J, ExitState *ex) - | // Returns MULTRES (unscaled) or negated error code. - | lp TMP1, L->cframe - | lwz TMP2, 0(sp) - | lp BASE, L->base - |.if GPR64 - | rldicr sp, TMP1, 0, 61 - |.else - | rlwinm sp, TMP1, 0, 0, 29 - |.endif - | lwz PC, SAVE_PC // Get SAVE_PC. - | stw TMP2, 0(sp) - | stw L, SAVE_L // Set SAVE_L (on-trace resume/yield). - | b >1 - |.endif - |->vm_exit_interp: - |.if JIT - | // CARG1 = MULTRES or negated error code, BASE, PC and JGL set. - | lwz L, SAVE_L - | addi DISPATCH, JGL, -GG_DISP2G-32768 - | stp BASE, L->base - |1: - | cmpwi CARG1, 0 - | blt >9 // Check for error from exit. - | lwz LFUNC:RB, FRAME_FUNC(BASE) - | slwi MULTRES, CARG1, 3 - | li TMP2, 0 - | stw MULTRES, SAVE_MULTRES - | lwz TMP1, LFUNC:RB->pc - | stw TMP2, DISPATCH_GL(jit_base)(DISPATCH) - | lwz KBASE, PC2PROTO(k)(TMP1) - | // Setup type comparison constants. - | li TISNUM, LJ_TISNUM - | .FPU lus TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float). - | .FPU stw TMP3, TMPD - | li ZERO, 0 - | .FPU ori TMP3, TMP3, 0x0004 // TONUM = 2^52 + 2^51 + 2^31 (float). - | .FPU lfs TOBIT, TMPD - | .FPU stw TMP3, TMPD - | .FPU lus TMP0, 0x4338 // Hiword of 2^52 + 2^51 (double) - | li TISNIL, LJ_TNIL - | .FPU stw TMP0, TONUM_HI - | .FPU lfs TONUM, TMPD - | // Modified copy of ins_next which handles function header dispatch, too. - | lwz INS, 0(PC) - | addi PC, PC, 4 - | // Assumes TISNIL == ~LJ_VMST_INTERP == -1. - | stw TISNIL, DISPATCH_GL(vmstate)(DISPATCH) - | decode_OPP TMP1, INS - | decode_RA8 RA, INS - | lpx TMP0, DISPATCH, TMP1 - | mtctr TMP0 - | cmplwi TMP1, BC_FUNCF*4 // Function header? - | bge >2 - | decode_RB8 RB, INS - | decode_RD8 RD, INS - | decode_RC8 RC, INS - | bctr - |2: - | cmplwi TMP1, (BC_FUNCC+2)*4 // Fast function? - | blt >3 - | // Check frame below fast function. - | lwz TMP1, FRAME_PC(BASE) - | andix. TMP0, TMP1, FRAME_TYPE - | bney >3 // Trace stitching continuation? - | // Otherwise set KBASE for Lua function below fast function. - | lwz TMP2, -4(TMP1) - | decode_RA8 TMP0, TMP2 - | sub TMP1, BASE, TMP0 - | lwz LFUNC:TMP2, -12(TMP1) - | lwz TMP1, LFUNC:TMP2->pc - | lwz KBASE, PC2PROTO(k)(TMP1) - |3: - | subi RC, MULTRES, 8 - | add RA, RA, BASE - | bctr - | - |9: // Rethrow error from the right C frame. - | neg CARG2, CARG1 - | mr CARG1, L - | bl extern lj_err_throw // (lua_State *L, int errcode) - |.endif - | - |//----------------------------------------------------------------------- - |//-- Math helper functions ---------------------------------------------- - |//----------------------------------------------------------------------- - | - |// NYI: Use internal implementations of floor, ceil, trunc, sfcmp. - | - |.macro sfi2d, AHI, ALO - |.if not FPU - | mr. AHI, ALO - | bclr 12, 2 // Handle zero first. - | srawi TMP0, ALO, 31 - | xor TMP1, ALO, TMP0 - | sub TMP1, TMP1, TMP0 // Absolute value in TMP1. - | cntlzw AHI, TMP1 - | andix. TMP0, TMP0, 0x800 // Mask sign bit. - | slw TMP1, TMP1, AHI // Align mantissa left with leading 1. - | subfic AHI, AHI, 0x3ff+31-1 // Exponent -1 in AHI. - | slwi ALO, TMP1, 21 - | or AHI, AHI, TMP0 // Sign | Exponent. - | srwi TMP1, TMP1, 11 - | slwi AHI, AHI, 20 // Align left. - | add AHI, AHI, TMP1 // Add mantissa, increment exponent. - | blr - |.endif - |.endmacro - | - |// Input: CARG2. Output: CARG1, CARG2. Temporaries: TMP0, TMP1. - |->vm_sfi2d_1: - | sfi2d CARG1, CARG2 - | - |// Input: CARG4. Output: CARG3, CARG4. Temporaries: TMP0, TMP1. - |->vm_sfi2d_2: - | sfi2d CARG3, CARG4 - | - |->vm_modi: - | divwo. TMP0, CARG1, CARG2 - | bso >1 - |.if GPR64 - | xor CARG3, CARG1, CARG2 - | cmpwi CARG3, 0 - |.else - | xor. CARG3, CARG1, CARG2 - |.endif - | mullw TMP0, TMP0, CARG2 - | sub CARG1, CARG1, TMP0 - | bgelr - | cmpwi CARG1, 0; beqlr - | add CARG1, CARG1, CARG2 - | blr - |1: - | cmpwi CARG2, 0 - | li CARG1, 0 - | beqlr - | clrso TMP0 // Clear SO for -2147483648 % -1 and return 0. - | blr - | - |//----------------------------------------------------------------------- - |//-- Miscellaneous functions -------------------------------------------- - |//----------------------------------------------------------------------- - | - |// void lj_vm_cachesync(void *start, void *end) - |// Flush D-Cache and invalidate I-Cache. Assumes 32 byte cache line size. - |// This is a good lower bound, except for very ancient PPC models. - |->vm_cachesync: - |.if JIT or FFI - | // Compute start of first cache line and number of cache lines. - | rlwinm CARG1, CARG1, 0, 0, 26 - | sub CARG2, CARG2, CARG1 - | addi CARG2, CARG2, 31 - | rlwinm. CARG2, CARG2, 27, 5, 31 - | beqlr - | mtctr CARG2 - | mr CARG3, CARG1 - |1: // Flush D-Cache. - | dcbst r0, CARG1 - | addi CARG1, CARG1, 32 - | bdnz <1 - | sync - | mtctr CARG2 - |1: // Invalidate I-Cache. - | icbi r0, CARG3 - | addi CARG3, CARG3, 32 - | bdnz <1 - | isync - | blr - |.endif - | - |//----------------------------------------------------------------------- - |//-- FFI helper functions ----------------------------------------------- - |//----------------------------------------------------------------------- - | - |// Handler for callback functions. Callback slot number in r11, g in r12. - |->vm_ffi_callback: - |.if FFI - |.type CTSTATE, CTState, PC - | saveregs - | lwz CTSTATE, GL:r12->ctype_state - | addi DISPATCH, r12, GG_G2DISP - | stw r11, CTSTATE->cb.slot - | stw r3, CTSTATE->cb.gpr[0] - | .FPU stfd f1, CTSTATE->cb.fpr[0] - | stw r4, CTSTATE->cb.gpr[1] - | .FPU stfd f2, CTSTATE->cb.fpr[1] - | stw r5, CTSTATE->cb.gpr[2] - | .FPU stfd f3, CTSTATE->cb.fpr[2] - | stw r6, CTSTATE->cb.gpr[3] - | .FPU stfd f4, CTSTATE->cb.fpr[3] - | stw r7, CTSTATE->cb.gpr[4] - | .FPU stfd f5, CTSTATE->cb.fpr[4] - | stw r8, CTSTATE->cb.gpr[5] - | .FPU stfd f6, CTSTATE->cb.fpr[5] - | stw r9, CTSTATE->cb.gpr[6] - | .FPU stfd f7, CTSTATE->cb.fpr[6] - | stw r10, CTSTATE->cb.gpr[7] - | .FPU stfd f8, CTSTATE->cb.fpr[7] - | addi TMP0, sp, CFRAME_SPACE+8 - | stw TMP0, CTSTATE->cb.stack - | mr CARG1, CTSTATE - | stw CTSTATE, SAVE_PC // Any value outside of bytecode is ok. - | mr CARG2, sp - | bl extern lj_ccallback_enter // (CTState *cts, void *cf) - | // Returns lua_State *. - | lp BASE, L:CRET1->base - | li TISNUM, LJ_TISNUM // Setup type comparison constants. - | lp RC, L:CRET1->top - | .FPU lus TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float). - | li ZERO, 0 - | mr L, CRET1 - | .FPU stw TMP3, TMPD - | .FPU lus TMP0, 0x4338 // Hiword of 2^52 + 2^51 (double) - | lwz LFUNC:RB, FRAME_FUNC(BASE) - | .FPU ori TMP3, TMP3, 0x0004 // TONUM = 2^52 + 2^51 + 2^31 (float). - | .FPU stw TMP0, TONUM_HI - | li TISNIL, LJ_TNIL - | li_vmstate INTERP - | .FPU lfs TOBIT, TMPD - | .FPU stw TMP3, TMPD - | sub RC, RC, BASE - | st_vmstate - | .FPU lfs TONUM, TMPD - | ins_callt - |.endif - | - |->cont_ffi_callback: // Return from FFI callback. - |.if FFI - | lwz CTSTATE, DISPATCH_GL(ctype_state)(DISPATCH) - | stp BASE, L->base - | stp RB, L->top - | stp L, CTSTATE->L - | mr CARG1, CTSTATE - | mr CARG2, RA - | bl extern lj_ccallback_leave // (CTState *cts, TValue *o) - | lwz CRET1, CTSTATE->cb.gpr[0] - | .FPU lfd FARG1, CTSTATE->cb.fpr[0] - | lwz CRET2, CTSTATE->cb.gpr[1] - | b ->vm_leave_unw - |.endif - | - |->vm_ffi_call: // Call C function via FFI. - | // Caveat: needs special frame unwinding, see below. - |.if FFI - | .type CCSTATE, CCallState, CARG1 - | lwz TMP1, CCSTATE->spadj - | mflr TMP0 - | lbz CARG2, CCSTATE->nsp - | lbz CARG3, CCSTATE->nfpr - | neg TMP1, TMP1 - | stw TMP0, 4(sp) - | cmpwi cr1, CARG3, 0 - | mr TMP2, sp - | addic. CARG2, CARG2, -1 - | stwux sp, sp, TMP1 - | crnot 4*cr1+eq, 4*cr1+eq // For vararg calls. - | stw r14, -4(TMP2) - | stw CCSTATE, -8(TMP2) - | mr r14, TMP2 - | la TMP1, CCSTATE->stack - | slwi CARG2, CARG2, 2 - | blty >2 - | la TMP2, 8(sp) - |1: - | lwzx TMP0, TMP1, CARG2 - | stwx TMP0, TMP2, CARG2 - | addic. CARG2, CARG2, -4 - | bge <1 - |2: - | bney cr1, >3 - | .FPU lfd f1, CCSTATE->fpr[0] - | .FPU lfd f2, CCSTATE->fpr[1] - | .FPU lfd f3, CCSTATE->fpr[2] - | .FPU lfd f4, CCSTATE->fpr[3] - | .FPU lfd f5, CCSTATE->fpr[4] - | .FPU lfd f6, CCSTATE->fpr[5] - | .FPU lfd f7, CCSTATE->fpr[6] - | .FPU lfd f8, CCSTATE->fpr[7] - |3: - | lp TMP0, CCSTATE->func - | lwz CARG2, CCSTATE->gpr[1] - | lwz CARG3, CCSTATE->gpr[2] - | lwz CARG4, CCSTATE->gpr[3] - | lwz CARG5, CCSTATE->gpr[4] - | mtctr TMP0 - | lwz r8, CCSTATE->gpr[5] - | lwz r9, CCSTATE->gpr[6] - | lwz r10, CCSTATE->gpr[7] - | lwz CARG1, CCSTATE->gpr[0] // Do this last, since CCSTATE is CARG1. - | bctrl - | lwz CCSTATE:TMP1, -8(r14) - | lwz TMP2, -4(r14) - | lwz TMP0, 4(r14) - | stw CARG1, CCSTATE:TMP1->gpr[0] - | .FPU stfd FARG1, CCSTATE:TMP1->fpr[0] - | stw CARG2, CCSTATE:TMP1->gpr[1] - | mtlr TMP0 - | stw CARG3, CCSTATE:TMP1->gpr[2] - | mr sp, r14 - | stw CARG4, CCSTATE:TMP1->gpr[3] - | mr r14, TMP2 - | blr - |.endif - |// Note: vm_ffi_call must be the last function in this object file! - | - |//----------------------------------------------------------------------- -} - -/* Generate the code for a single instruction. */ -static void build_ins(BuildCtx *ctx, BCOp op, int defop) -{ - int vk = 0; - |=>defop: - - switch (op) { - - /* -- Comparison ops ---------------------------------------------------- */ - - /* Remember: all ops branch for a true comparison, fall through otherwise. */ - - case BC_ISLT: case BC_ISGE: case BC_ISLE: case BC_ISGT: - | // RA = src1*8, RD = src2*8, JMP with RD = target - |.if DUALNUM - | lwzux CARG1, RA, BASE - | addi PC, PC, 4 - | lwz CARG2, 4(RA) - | lwzux CARG3, RD, BASE - | lwz TMP2, -4(PC) - | checknum cr0, CARG1 - | lwz CARG4, 4(RD) - | decode_RD4 TMP2, TMP2 - | checknum cr1, CARG3 - | addis SAVE0, TMP2, -(BCBIAS_J*4 >> 16) - | bne cr0, >7 - | bne cr1, >8 - | cmpw CARG2, CARG4 - if (op == BC_ISLT) { - | bge >2 - } else if (op == BC_ISGE) { - | blt >2 - } else if (op == BC_ISLE) { - | bgt >2 - } else { - | ble >2 - } - |1: - | add PC, PC, SAVE0 - |2: - | ins_next - | - |7: // RA is not an integer. - | bgt cr0, ->vmeta_comp - | // RA is a number. - | .FPU lfd f0, 0(RA) - | bgt cr1, ->vmeta_comp - | blt cr1, >4 - | // RA is a number, RD is an integer. - |.if FPU - | tonum_i f1, CARG4 - |.else - | bl ->vm_sfi2d_2 - |.endif - | b >5 - | - |8: // RA is an integer, RD is not an integer. - | bgt cr1, ->vmeta_comp - | // RA is an integer, RD is a number. - |.if FPU - | tonum_i f0, CARG2 - |.else - | bl ->vm_sfi2d_1 - |.endif - |4: - | .FPU lfd f1, 0(RD) - |5: - |.if FPU - | fcmpu cr0, f0, f1 - |.else - | blex __ledf2 - | cmpwi CRET1, 0 - |.endif - if (op == BC_ISLT) { - | bge <2 - } else if (op == BC_ISGE) { - | blt <2 - } else if (op == BC_ISLE) { - | cror 4*cr0+lt, 4*cr0+lt, 4*cr0+eq - | bge <2 - } else { - | cror 4*cr0+lt, 4*cr0+lt, 4*cr0+eq - | blt <2 - } - | b <1 - |.else - | lwzx TMP0, BASE, RA - | addi PC, PC, 4 - | lfdx f0, BASE, RA - | lwzx TMP1, BASE, RD - | checknum cr0, TMP0 - | lwz TMP2, -4(PC) - | lfdx f1, BASE, RD - | checknum cr1, TMP1 - | decode_RD4 TMP2, TMP2 - | bge cr0, ->vmeta_comp - | addis TMP2, TMP2, -(BCBIAS_J*4 >> 16) - | bge cr1, ->vmeta_comp - | fcmpu cr0, f0, f1 - if (op == BC_ISLT) { - | bge >1 - } else if (op == BC_ISGE) { - | blt >1 - } else if (op == BC_ISLE) { - | cror 4*cr0+lt, 4*cr0+lt, 4*cr0+eq - | bge >1 - } else { - | cror 4*cr0+lt, 4*cr0+lt, 4*cr0+eq - | blt >1 - } - | add PC, PC, TMP2 - |1: - | ins_next - |.endif - break; - - case BC_ISEQV: case BC_ISNEV: - vk = op == BC_ISEQV; - | // RA = src1*8, RD = src2*8, JMP with RD = target - |.if DUALNUM - | lwzux CARG1, RA, BASE - | addi PC, PC, 4 - | lwz CARG2, 4(RA) - | lwzux CARG3, RD, BASE - | checknum cr0, CARG1 - | lwz SAVE0, -4(PC) - | checknum cr1, CARG3 - | decode_RD4 SAVE0, SAVE0 - | lwz CARG4, 4(RD) - | cror 4*cr7+gt, 4*cr0+gt, 4*cr1+gt - | addis SAVE0, SAVE0, -(BCBIAS_J*4 >> 16) - if (vk) { - | ble cr7, ->BC_ISEQN_Z - } else { - | ble cr7, ->BC_ISNEN_Z - } - |.else - | lwzux CARG1, RA, BASE - | lwz SAVE0, 0(PC) - | lfd f0, 0(RA) - | addi PC, PC, 4 - | lwzux CARG3, RD, BASE - | checknum cr0, CARG1 - | decode_RD4 SAVE0, SAVE0 - | lfd f1, 0(RD) - | checknum cr1, CARG3 - | addis SAVE0, SAVE0, -(BCBIAS_J*4 >> 16) - | bge cr0, >5 - | bge cr1, >5 - | fcmpu cr0, f0, f1 - if (vk) { - | bne >1 - | add PC, PC, SAVE0 - } else { - | beq >1 - | add PC, PC, SAVE0 - } - |1: - | ins_next - |.endif - |5: // Either or both types are not numbers. - |.if not DUALNUM - | lwz CARG2, 4(RA) - | lwz CARG4, 4(RD) - |.endif - |.if FFI - | cmpwi cr7, CARG1, LJ_TCDATA - | cmpwi cr5, CARG3, LJ_TCDATA - |.endif - | not TMP2, CARG1 - | cmplw CARG1, CARG3 - | cmplwi cr1, TMP2, ~LJ_TISPRI // Primitive? - |.if FFI - | cror 4*cr7+eq, 4*cr7+eq, 4*cr5+eq - |.endif - | cmplwi cr6, TMP2, ~LJ_TISTABUD // Table or userdata? - |.if FFI - | beq cr7, ->vmeta_equal_cd - |.endif - | cmplw cr5, CARG2, CARG4 - | crandc 4*cr0+gt, 4*cr0+eq, 4*cr1+gt // 2: Same type and primitive. - | crorc 4*cr0+lt, 4*cr5+eq, 4*cr0+eq // 1: Same tv or different type. - | crand 4*cr0+eq, 4*cr0+eq, 4*cr5+eq // 0: Same type and same tv. - | mr SAVE1, PC - | cror 4*cr0+eq, 4*cr0+eq, 4*cr0+gt // 0 or 2. - | cror 4*cr0+lt, 4*cr0+lt, 4*cr0+gt // 1 or 2. - if (vk) { - | bne cr0, >6 - | add PC, PC, SAVE0 - |6: - } else { - | beq cr0, >6 - | add PC, PC, SAVE0 - |6: - } - |.if DUALNUM - | bge cr0, >2 // Done if 1 or 2. - |1: - | ins_next - |2: - |.else - | blt cr0, <1 // Done if 1 or 2. - |.endif - | blt cr6, <1 // Done if not tab/ud. - | - | // Different tables or userdatas. Need to check __eq metamethod. - | // Field metatable must be at same offset for GCtab and GCudata! - | mr CARG3, CARG4 - | lwz TAB:TMP2, TAB:CARG2->metatable - | li CARG4, 1-vk // ne = 0 or 1. - | cmplwi TAB:TMP2, 0 - | beq <1 // No metatable? - | lbz TMP2, TAB:TMP2->nomm - | andix. TMP2, TMP2, 1<vmeta_equal // Handle __eq metamethod. - break; - - case BC_ISEQS: case BC_ISNES: - vk = op == BC_ISEQS; - | // RA = src*8, RD = str_const*8 (~), JMP with RD = target - | lwzux TMP0, RA, BASE - | srwi RD, RD, 1 - | lwz STR:TMP3, 4(RA) - | lwz TMP2, 0(PC) - | subfic RD, RD, -4 - | addi PC, PC, 4 - |.if FFI - | cmpwi TMP0, LJ_TCDATA - |.endif - | lwzx STR:TMP1, KBASE, RD // KBASE-4-str_const*4 - | .gpr64 extsw TMP0, TMP0 - | subfic TMP0, TMP0, LJ_TSTR - |.if FFI - | beq ->vmeta_equal_cd - |.endif - | sub TMP1, STR:TMP1, STR:TMP3 - | or TMP0, TMP0, TMP1 - | decode_RD4 TMP2, TMP2 - | subfic TMP0, TMP0, 0 - | addis TMP2, TMP2, -(BCBIAS_J*4 >> 16) - | subfe TMP1, TMP1, TMP1 - if (vk) { - | andc TMP2, TMP2, TMP1 - } else { - | and TMP2, TMP2, TMP1 - } - | add PC, PC, TMP2 - | ins_next - break; - - case BC_ISEQN: case BC_ISNEN: - vk = op == BC_ISEQN; - | // RA = src*8, RD = num_const*8, JMP with RD = target - |.if DUALNUM - | lwzux CARG1, RA, BASE - | addi PC, PC, 4 - | lwz CARG2, 4(RA) - | lwzux CARG3, RD, KBASE - | checknum cr0, CARG1 - | lwz SAVE0, -4(PC) - | checknum cr1, CARG3 - | decode_RD4 SAVE0, SAVE0 - | lwz CARG4, 4(RD) - | addis SAVE0, SAVE0, -(BCBIAS_J*4 >> 16) - if (vk) { - |->BC_ISEQN_Z: - } else { - |->BC_ISNEN_Z: - } - | bne cr0, >7 - | bne cr1, >8 - | cmpw CARG2, CARG4 - |4: - |.else - if (vk) { - |->BC_ISEQN_Z: // Dummy label. - } else { - |->BC_ISNEN_Z: // Dummy label. - } - | lwzx CARG1, BASE, RA - | addi PC, PC, 4 - | lfdx f0, BASE, RA - | lwz SAVE0, -4(PC) - | lfdx f1, KBASE, RD - | decode_RD4 SAVE0, SAVE0 - | checknum CARG1 - | addis SAVE0, SAVE0, -(BCBIAS_J*4 >> 16) - | bge >3 - | fcmpu cr0, f0, f1 - |.endif - if (vk) { - | bne >1 - | add PC, PC, SAVE0 - |1: - |.if not FFI - |3: - |.endif - } else { - | beq >2 - |1: - |.if not FFI - |3: - |.endif - | add PC, PC, SAVE0 - |2: - } - | ins_next - |.if FFI - |3: - | cmpwi CARG1, LJ_TCDATA - | beq ->vmeta_equal_cd - | b <1 - |.endif - |.if DUALNUM - |7: // RA is not an integer. - | bge cr0, <3 - | // RA is a number. - | .FPU lfd f0, 0(RA) - | blt cr1, >1 - | // RA is a number, RD is an integer. - |.if FPU - | tonum_i f1, CARG4 - |.else - | bl ->vm_sfi2d_2 - |.endif - | b >2 - | - |8: // RA is an integer, RD is a number. - |.if FPU - | tonum_i f0, CARG2 - |.else - | bl ->vm_sfi2d_1 - |.endif - |1: - | .FPU lfd f1, 0(RD) - |2: - |.if FPU - | fcmpu cr0, f0, f1 - |.else - | blex __ledf2 - | cmpwi CRET1, 0 - |.endif - | b <4 - |.endif - break; - - case BC_ISEQP: case BC_ISNEP: - vk = op == BC_ISEQP; - | // RA = src*8, RD = primitive_type*8 (~), JMP with RD = target - | lwzx TMP0, BASE, RA - | srwi TMP1, RD, 3 - | lwz TMP2, 0(PC) - | not TMP1, TMP1 - | addi PC, PC, 4 - |.if FFI - | cmpwi TMP0, LJ_TCDATA - |.endif - | sub TMP0, TMP0, TMP1 - |.if FFI - | beq ->vmeta_equal_cd - |.endif - | decode_RD4 TMP2, TMP2 - | .gpr64 extsw TMP0, TMP0 - | addic TMP0, TMP0, -1 - | addis TMP2, TMP2, -(BCBIAS_J*4 >> 16) - | subfe TMP1, TMP1, TMP1 - if (vk) { - | and TMP2, TMP2, TMP1 - } else { - | andc TMP2, TMP2, TMP1 - } - | add PC, PC, TMP2 - | ins_next - break; - - /* -- Unary test and copy ops ------------------------------------------- */ - - case BC_ISTC: case BC_ISFC: case BC_IST: case BC_ISF: - | // RA = dst*8 or unused, RD = src*8, JMP with RD = target - | lwzx TMP0, BASE, RD - | lwz INS, 0(PC) - | addi PC, PC, 4 - if (op == BC_IST || op == BC_ISF) { - | .gpr64 extsw TMP0, TMP0 - | subfic TMP0, TMP0, LJ_TTRUE - | decode_RD4 TMP2, INS - | subfe TMP1, TMP1, TMP1 - | addis TMP2, TMP2, -(BCBIAS_J*4 >> 16) - if (op == BC_IST) { - | andc TMP2, TMP2, TMP1 - } else { - | and TMP2, TMP2, TMP1 - } - | add PC, PC, TMP2 - } else { - | li TMP1, LJ_TFALSE - |.if FPU - | lfdx f0, BASE, RD - |.else - | lwzux CARG1, RD, BASE - | lwz CARG2, 4(RD) - |.endif - | cmplw TMP0, TMP1 - if (op == BC_ISTC) { - | bge >1 - } else { - | blt >1 - } - | addis PC, PC, -(BCBIAS_J*4 >> 16) - | decode_RD4 TMP2, INS - |.if FPU - | stfdx f0, BASE, RA - |.else - | stwux CARG1, RA, BASE - | stw CARG2, 4(RA) - |.endif - | add PC, PC, TMP2 - |1: - } - | ins_next - break; - - case BC_ISTYPE: - | // RA = src*8, RD = -type*8 - | lwzx TMP0, BASE, RA - | srwi TMP1, RD, 3 - | ins_next1 - |.if not PPE and not GPR64 - | add. TMP0, TMP0, TMP1 - |.else - | neg TMP1, TMP1 - | cmpw TMP0, TMP1 - |.endif - | bne ->vmeta_istype - | ins_next2 - break; - case BC_ISNUM: - | // RA = src*8, RD = -(TISNUM-1)*8 - | lwzx TMP0, BASE, RA - | ins_next1 - | checknum TMP0 - | bge ->vmeta_istype - | ins_next2 - break; - - /* -- Unary ops --------------------------------------------------------- */ - - case BC_MOV: - | // RA = dst*8, RD = src*8 - | ins_next1 - |.if FPU - | lfdx f0, BASE, RD - | stfdx f0, BASE, RA - |.else - | lwzux TMP0, RD, BASE - | lwz TMP1, 4(RD) - | stwux TMP0, RA, BASE - | stw TMP1, 4(RA) - |.endif - | ins_next2 - break; - case BC_NOT: - | // RA = dst*8, RD = src*8 - | ins_next1 - | lwzx TMP0, BASE, RD - | .gpr64 extsw TMP0, TMP0 - | subfic TMP1, TMP0, LJ_TTRUE - | adde TMP0, TMP0, TMP1 - | stwx TMP0, BASE, RA - | ins_next2 - break; - case BC_UNM: - | // RA = dst*8, RD = src*8 - | lwzux TMP1, RD, BASE - | lwz TMP0, 4(RD) - | checknum TMP1 - |.if DUALNUM - | bne >5 - |.if GPR64 - | lus TMP2, 0x8000 - | neg TMP0, TMP0 - | cmplw TMP0, TMP2 - | beq >4 - |.else - | nego. TMP0, TMP0 - | bso >4 - |1: - |.endif - | ins_next1 - | stwux TISNUM, RA, BASE - | stw TMP0, 4(RA) - |3: - | ins_next2 - |4: - |.if not GPR64 - | // Potential overflow. - | checkov TMP1, <1 // Ignore unrelated overflow. - |.endif - | lus TMP1, 0x41e0 // 2^31. - | li TMP0, 0 - | b >7 - |.endif - |5: - | bge ->vmeta_unm - | xoris TMP1, TMP1, 0x8000 - |7: - | ins_next1 - | stwux TMP1, RA, BASE - | stw TMP0, 4(RA) - |.if DUALNUM - | b <3 - |.else - | ins_next2 - |.endif - break; - case BC_LEN: - | // RA = dst*8, RD = src*8 - | lwzux TMP0, RD, BASE - | lwz CARG1, 4(RD) - | checkstr TMP0; bne >2 - | lwz CRET1, STR:CARG1->len - |1: - |.if DUALNUM - | ins_next1 - | stwux TISNUM, RA, BASE - | stw CRET1, 4(RA) - |.else - | tonum_u f0, CRET1 // Result is a non-negative integer. - | ins_next1 - | stfdx f0, BASE, RA - |.endif - | ins_next2 - |2: - | checktab TMP0; bne ->vmeta_len -#if LJ_52 - | lwz TAB:TMP2, TAB:CARG1->metatable - | cmplwi TAB:TMP2, 0 - | bne >9 - |3: -#endif - |->BC_LEN_Z: - | bl extern lj_tab_len // (GCtab *t) - | // Returns uint32_t (but less than 2^31). - | b <1 -#if LJ_52 - |9: - | lbz TMP0, TAB:TMP2->nomm - | andix. TMP0, TMP0, 1<vmeta_len -#endif - break; - - /* -- Binary ops -------------------------------------------------------- */ - - |.macro ins_arithpre - | // RA = dst*8, RB = src1*8, RC = src2*8 | num_const*8 - ||vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN); - ||switch (vk) { - ||case 0: - | lwzx CARG1, BASE, RB - | .if DUALNUM - | lwzx CARG3, KBASE, RC - | .endif - | .if FPU - | lfdx f14, BASE, RB - | lfdx f15, KBASE, RC - | .else - | add TMP1, BASE, RB - | add TMP2, KBASE, RC - | lwz CARG2, 4(TMP1) - | lwz CARG4, 4(TMP2) - | .endif - | .if DUALNUM - | checknum cr0, CARG1 - | checknum cr1, CARG3 - | crand 4*cr0+lt, 4*cr0+lt, 4*cr1+lt - | bge ->vmeta_arith_vn - | .else - | checknum CARG1; bge ->vmeta_arith_vn - | .endif - || break; - ||case 1: - | lwzx CARG1, BASE, RB - | .if DUALNUM - | lwzx CARG3, KBASE, RC - | .endif - | .if FPU - | lfdx f15, BASE, RB - | lfdx f14, KBASE, RC - | .else - | add TMP1, BASE, RB - | add TMP2, KBASE, RC - | lwz CARG2, 4(TMP1) - | lwz CARG4, 4(TMP2) - | .endif - | .if DUALNUM - | checknum cr0, CARG1 - | checknum cr1, CARG3 - | crand 4*cr0+lt, 4*cr0+lt, 4*cr1+lt - | bge ->vmeta_arith_nv - | .else - | checknum CARG1; bge ->vmeta_arith_nv - | .endif - || break; - ||default: - | lwzx CARG1, BASE, RB - | lwzx CARG3, BASE, RC - | .if FPU - | lfdx f14, BASE, RB - | lfdx f15, BASE, RC - | .else - | add TMP1, BASE, RB - | add TMP2, BASE, RC - | lwz CARG2, 4(TMP1) - | lwz CARG4, 4(TMP2) - | .endif - | checknum cr0, CARG1 - | checknum cr1, CARG3 - | crand 4*cr0+lt, 4*cr0+lt, 4*cr1+lt - | bge ->vmeta_arith_vv - || break; - ||} - |.endmacro - | - |.macro ins_arithfallback, ins - ||switch (vk) { - ||case 0: - | ins ->vmeta_arith_vn2 - || break; - ||case 1: - | ins ->vmeta_arith_nv2 - || break; - ||default: - | ins ->vmeta_arith_vv2 - || break; - ||} - |.endmacro - | - |.macro intmod, a, b, c - | bl ->vm_modi - |.endmacro - | - |.macro fpmod, a, b, c - |->BC_MODVN_Z: - | fdiv FARG1, b, c - | // NYI: Use internal implementation of floor. - | blex floor // floor(b/c) - | fmul a, FARG1, c - | fsub a, b, a // b - floor(b/c)*c - |.endmacro - | - |.macro sfpmod - |->BC_MODVN_Z: - | stw CARG1, SFSAVE_1 - | stw CARG2, SFSAVE_2 - | mr SAVE0, CARG3 - | mr SAVE1, CARG4 - | blex __divdf3 - | blex floor - | mr CARG3, SAVE0 - | mr CARG4, SAVE1 - | blex __muldf3 - | mr CARG3, CRET1 - | mr CARG4, CRET2 - | lwz CARG1, SFSAVE_1 - | lwz CARG2, SFSAVE_2 - | blex __subdf3 - |.endmacro - | - |.macro ins_arithfp, fpins - | ins_arithpre - |.if "fpins" == "fpmod_" - | b ->BC_MODVN_Z // Avoid 3 copies. It's slow anyway. - |.elif FPU - | fpins f0, f14, f15 - | ins_next1 - | stfdx f0, BASE, RA - | ins_next2 - |.else - | blex __divdf3 // Only soft-float div uses this macro. - | ins_next1 - | stwux CRET1, RA, BASE - | stw CRET2, 4(RA) - | ins_next2 - |.endif - |.endmacro - | - |.macro ins_arithdn, intins, fpins, fpcall - | // RA = dst*8, RB = src1*8, RC = src2*8 | num_const*8 - ||vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN); - ||switch (vk) { - ||case 0: - | lwzux CARG1, RB, BASE - | lwzux CARG3, RC, KBASE - | lwz CARG2, 4(RB) - | checknum cr0, CARG1 - | lwz CARG4, 4(RC) - | checknum cr1, CARG3 - || break; - ||case 1: - | lwzux CARG3, RB, BASE - | lwzux CARG1, RC, KBASE - | lwz CARG4, 4(RB) - | checknum cr0, CARG3 - | lwz CARG2, 4(RC) - | checknum cr1, CARG1 - || break; - ||default: - | lwzux CARG1, RB, BASE - | lwzux CARG3, RC, BASE - | lwz CARG2, 4(RB) - | checknum cr0, CARG1 - | lwz CARG4, 4(RC) - | checknum cr1, CARG3 - || break; - ||} - | bne >5 - | bne cr1, >5 - |.if "intins" == "intmod" - | mr CARG1, CARG2 - | mr CARG2, CARG4 - |.endif - | intins CARG1, CARG2, CARG4 - | bso >4 - |1: - | ins_next1 - | stwux TISNUM, RA, BASE - | stw CARG1, 4(RA) - |2: - | ins_next2 - |4: // Overflow. - | checkov TMP0, <1 // Ignore unrelated overflow. - | ins_arithfallback b - |5: // FP variant. - |.if FPU - ||if (vk == 1) { - | lfd f15, 0(RB) - | lfd f14, 0(RC) - ||} else { - | lfd f14, 0(RB) - | lfd f15, 0(RC) - ||} - |.endif - | crand 4*cr0+lt, 4*cr0+lt, 4*cr1+lt - | ins_arithfallback bge - |.if "fpins" == "fpmod_" - | b ->BC_MODVN_Z // Avoid 3 copies. It's slow anyway. - |.else - |.if FPU - | fpins f0, f14, f15 - | stfdx f0, BASE, RA - |.else - |.if "fpcall" == "sfpmod" - | sfpmod - |.else - | blex fpcall - |.endif - | stwux CRET1, RA, BASE - | stw CRET2, 4(RA) - |.endif - | ins_next1 - | b <2 - |.endif - |.endmacro - | - |.macro ins_arith, intins, fpins, fpcall - |.if DUALNUM - | ins_arithdn intins, fpins, fpcall - |.else - | ins_arithfp fpins - |.endif - |.endmacro - - case BC_ADDVN: case BC_ADDNV: case BC_ADDVV: - |.if GPR64 - |.macro addo32., y, a, b - | // Need to check overflow for (a<<32) + (b<<32). - | rldicr TMP0, a, 32, 31 - | rldicr TMP3, b, 32, 31 - | addo. TMP0, TMP0, TMP3 - | add y, a, b - |.endmacro - | ins_arith addo32., fadd, __adddf3 - |.else - | ins_arith addo., fadd, __adddf3 - |.endif - break; - case BC_SUBVN: case BC_SUBNV: case BC_SUBVV: - |.if GPR64 - |.macro subo32., y, a, b - | // Need to check overflow for (a<<32) - (b<<32). - | rldicr TMP0, a, 32, 31 - | rldicr TMP3, b, 32, 31 - | subo. TMP0, TMP0, TMP3 - | sub y, a, b - |.endmacro - | ins_arith subo32., fsub, __subdf3 - |.else - | ins_arith subo., fsub, __subdf3 - |.endif - break; - case BC_MULVN: case BC_MULNV: case BC_MULVV: - | ins_arith mullwo., fmul, __muldf3 - break; - case BC_DIVVN: case BC_DIVNV: case BC_DIVVV: - | ins_arithfp fdiv - break; - case BC_MODVN: - | ins_arith intmod, fpmod, sfpmod - break; - case BC_MODNV: case BC_MODVV: - | ins_arith intmod, fpmod_, sfpmod - break; - case BC_POW: - | // NYI: (partial) integer arithmetic. - | lwzx CARG1, BASE, RB - | lwzx CARG3, BASE, RC - |.if FPU - | lfdx FARG1, BASE, RB - | lfdx FARG2, BASE, RC - |.else - | add TMP1, BASE, RB - | add TMP2, BASE, RC - | lwz CARG2, 4(TMP1) - | lwz CARG4, 4(TMP2) - |.endif - | checknum cr0, CARG1 - | checknum cr1, CARG3 - | crand 4*cr0+lt, 4*cr0+lt, 4*cr1+lt - | bge ->vmeta_arith_vv - | blex pow - | ins_next1 - |.if FPU - | stfdx FARG1, BASE, RA - |.else - | stwux CARG1, RA, BASE - | stw CARG2, 4(RA) - |.endif - | ins_next2 - break; - - case BC_CAT: - | // RA = dst*8, RB = src_start*8, RC = src_end*8 - | sub CARG3, RC, RB - | stp BASE, L->base - | add CARG2, BASE, RC - | mr SAVE0, RB - |->BC_CAT_Z: - | stw PC, SAVE_PC - | mr CARG1, L - | srwi CARG3, CARG3, 3 - | bl extern lj_meta_cat // (lua_State *L, TValue *top, int left) - | // Returns NULL (finished) or TValue * (metamethod). - | cmplwi CRET1, 0 - | lp BASE, L->base - | bne ->vmeta_binop - | ins_next1 - |.if FPU - | lfdx f0, BASE, SAVE0 // Copy result from RB to RA. - | stfdx f0, BASE, RA - |.else - | lwzux TMP0, SAVE0, BASE - | lwz TMP1, 4(SAVE0) - | stwux TMP0, RA, BASE - | stw TMP1, 4(RA) - |.endif - | ins_next2 - break; - - /* -- Constant ops ------------------------------------------------------ */ - - case BC_KSTR: - | // RA = dst*8, RD = str_const*8 (~) - | srwi TMP1, RD, 1 - | subfic TMP1, TMP1, -4 - | ins_next1 - | lwzx TMP0, KBASE, TMP1 // KBASE-4-str_const*4 - | li TMP2, LJ_TSTR - | stwux TMP2, RA, BASE - | stw TMP0, 4(RA) - | ins_next2 - break; - case BC_KCDATA: - |.if FFI - | // RA = dst*8, RD = cdata_const*8 (~) - | srwi TMP1, RD, 1 - | subfic TMP1, TMP1, -4 - | ins_next1 - | lwzx TMP0, KBASE, TMP1 // KBASE-4-cdata_const*4 - | li TMP2, LJ_TCDATA - | stwux TMP2, RA, BASE - | stw TMP0, 4(RA) - | ins_next2 - |.endif - break; - case BC_KSHORT: - | // RA = dst*8, RD = int16_literal*8 - |.if DUALNUM - | slwi RD, RD, 13 - | srawi RD, RD, 16 - | ins_next1 - | stwux TISNUM, RA, BASE - | stw RD, 4(RA) - | ins_next2 - |.else - | // The soft-float approach is faster. - | slwi RD, RD, 13 - | srawi TMP1, RD, 31 - | xor TMP2, TMP1, RD - | sub TMP2, TMP2, TMP1 // TMP2 = abs(x) - | cntlzw TMP3, TMP2 - | subfic TMP1, TMP3, 0x40d // TMP1 = exponent-1 - | slw TMP2, TMP2, TMP3 // TMP2 = left aligned mantissa - | subfic TMP3, RD, 0 - | slwi TMP1, TMP1, 20 - | rlwimi RD, TMP2, 21, 1, 31 // hi = sign(x) | (mantissa>>11) - | subfe TMP0, TMP0, TMP0 - | add RD, RD, TMP1 // hi = hi + exponent-1 - | and RD, RD, TMP0 // hi = x == 0 ? 0 : hi - | ins_next1 - | stwux RD, RA, BASE - | stw ZERO, 4(RA) - | ins_next2 - |.endif - break; - case BC_KNUM: - | // RA = dst*8, RD = num_const*8 - | ins_next1 - |.if FPU - | lfdx f0, KBASE, RD - | stfdx f0, BASE, RA - |.else - | lwzux TMP0, RD, KBASE - | lwz TMP1, 4(RD) - | stwux TMP0, RA, BASE - | stw TMP1, 4(RA) - |.endif - | ins_next2 - break; - case BC_KPRI: - | // RA = dst*8, RD = primitive_type*8 (~) - | srwi TMP1, RD, 3 - | not TMP0, TMP1 - | ins_next1 - | stwx TMP0, BASE, RA - | ins_next2 - break; - case BC_KNIL: - | // RA = base*8, RD = end*8 - | stwx TISNIL, BASE, RA - | addi RA, RA, 8 - |1: - | stwx TISNIL, BASE, RA - | cmpw RA, RD - | addi RA, RA, 8 - | blt <1 - | ins_next_ - break; - - /* -- Upvalue and function ops ------------------------------------------ */ - - case BC_UGET: - | // RA = dst*8, RD = uvnum*8 - | lwz LFUNC:RB, FRAME_FUNC(BASE) - | srwi RD, RD, 1 - | addi RD, RD, offsetof(GCfuncL, uvptr) - | lwzx UPVAL:RB, LFUNC:RB, RD - | ins_next1 - | lwz TMP1, UPVAL:RB->v - |.if FPU - | lfd f0, 0(TMP1) - | stfdx f0, BASE, RA - |.else - | lwz TMP2, 0(TMP1) - | lwz TMP3, 4(TMP1) - | stwux TMP2, RA, BASE - | stw TMP3, 4(RA) - |.endif - | ins_next2 - break; - case BC_USETV: - | // RA = uvnum*8, RD = src*8 - | lwz LFUNC:RB, FRAME_FUNC(BASE) - | srwi RA, RA, 1 - | addi RA, RA, offsetof(GCfuncL, uvptr) - |.if FPU - | lfdux f0, RD, BASE - |.else - | lwzux CARG1, RD, BASE - | lwz CARG3, 4(RD) - |.endif - | lwzx UPVAL:RB, LFUNC:RB, RA - | lbz TMP3, UPVAL:RB->marked - | lwz CARG2, UPVAL:RB->v - | andix. TMP3, TMP3, LJ_GC_BLACK // isblack(uv) - | lbz TMP0, UPVAL:RB->closed - | lwz TMP2, 0(RD) - |.if FPU - | stfd f0, 0(CARG2) - |.else - | stw CARG1, 0(CARG2) - | stw CARG3, 4(CARG2) - |.endif - | cmplwi cr1, TMP0, 0 - | lwz TMP1, 4(RD) - | cror 4*cr0+eq, 4*cr0+eq, 4*cr1+eq - | subi TMP2, TMP2, (LJ_TNUMX+1) - | bne >2 // Upvalue is closed and black? - |1: - | ins_next - | - |2: // Check if new value is collectable. - | cmplwi TMP2, LJ_TISGCV - (LJ_TNUMX+1) - | bge <1 // tvisgcv(v) - | lbz TMP3, GCOBJ:TMP1->gch.marked - | andix. TMP3, TMP3, LJ_GC_WHITES // iswhite(v) - | la CARG1, GG_DISP2G(DISPATCH) - | // Crossed a write barrier. Move the barrier forward. - | beq <1 - | bl extern lj_gc_barrieruv // (global_State *g, TValue *tv) - | b <1 - break; - case BC_USETS: - | // RA = uvnum*8, RD = str_const*8 (~) - | lwz LFUNC:RB, FRAME_FUNC(BASE) - | srwi TMP1, RD, 1 - | srwi RA, RA, 1 - | subfic TMP1, TMP1, -4 - | addi RA, RA, offsetof(GCfuncL, uvptr) - | lwzx STR:TMP1, KBASE, TMP1 // KBASE-4-str_const*4 - | lwzx UPVAL:RB, LFUNC:RB, RA - | lbz TMP3, UPVAL:RB->marked - | lwz CARG2, UPVAL:RB->v - | andix. TMP3, TMP3, LJ_GC_BLACK // isblack(uv) - | lbz TMP3, STR:TMP1->marked - | lbz TMP2, UPVAL:RB->closed - | li TMP0, LJ_TSTR - | stw STR:TMP1, 4(CARG2) - | stw TMP0, 0(CARG2) - | bne >2 - |1: - | ins_next - | - |2: // Check if string is white and ensure upvalue is closed. - | andix. TMP3, TMP3, LJ_GC_WHITES // iswhite(str) - | cmplwi cr1, TMP2, 0 - | cror 4*cr0+eq, 4*cr0+eq, 4*cr1+eq - | la CARG1, GG_DISP2G(DISPATCH) - | // Crossed a write barrier. Move the barrier forward. - | beq <1 - | bl extern lj_gc_barrieruv // (global_State *g, TValue *tv) - | b <1 - break; - case BC_USETN: - | // RA = uvnum*8, RD = num_const*8 - | lwz LFUNC:RB, FRAME_FUNC(BASE) - | srwi RA, RA, 1 - | addi RA, RA, offsetof(GCfuncL, uvptr) - |.if FPU - | lfdx f0, KBASE, RD - |.else - | lwzux TMP2, RD, KBASE - | lwz TMP3, 4(RD) - |.endif - | lwzx UPVAL:RB, LFUNC:RB, RA - | ins_next1 - | lwz TMP1, UPVAL:RB->v - |.if FPU - | stfd f0, 0(TMP1) - |.else - | stw TMP2, 0(TMP1) - | stw TMP3, 4(TMP1) - |.endif - | ins_next2 - break; - case BC_USETP: - | // RA = uvnum*8, RD = primitive_type*8 (~) - | lwz LFUNC:RB, FRAME_FUNC(BASE) - | srwi RA, RA, 1 - | srwi TMP0, RD, 3 - | addi RA, RA, offsetof(GCfuncL, uvptr) - | not TMP0, TMP0 - | lwzx UPVAL:RB, LFUNC:RB, RA - | ins_next1 - | lwz TMP1, UPVAL:RB->v - | stw TMP0, 0(TMP1) - | ins_next2 - break; - - case BC_UCLO: - | // RA = level*8, RD = target - | lwz TMP1, L->openupval - | branch_RD // Do this first since RD is not saved. - | stp BASE, L->base - | cmplwi TMP1, 0 - | mr CARG1, L - | beq >1 - | add CARG2, BASE, RA - | bl extern lj_func_closeuv // (lua_State *L, TValue *level) - | lp BASE, L->base - |1: - | ins_next - break; - - case BC_FNEW: - | // RA = dst*8, RD = proto_const*8 (~) (holding function prototype) - | srwi TMP1, RD, 1 - | stp BASE, L->base - | subfic TMP1, TMP1, -4 - | stw PC, SAVE_PC - | lwzx CARG2, KBASE, TMP1 // KBASE-4-tab_const*4 - | mr CARG1, L - | lwz CARG3, FRAME_FUNC(BASE) - | // (lua_State *L, GCproto *pt, GCfuncL *parent) - | bl extern lj_func_newL_gc - | // Returns GCfuncL *. - | lp BASE, L->base - | li TMP0, LJ_TFUNC - | stwux TMP0, RA, BASE - | stw LFUNC:CRET1, 4(RA) - | ins_next - break; - - /* -- Table ops --------------------------------------------------------- */ - - case BC_TNEW: - case BC_TDUP: - | // RA = dst*8, RD = (hbits|asize)*8 | tab_const*8 (~) - | lwz TMP0, DISPATCH_GL(gc.total)(DISPATCH) - | mr CARG1, L - | lwz TMP1, DISPATCH_GL(gc.threshold)(DISPATCH) - | stp BASE, L->base - | cmplw TMP0, TMP1 - | stw PC, SAVE_PC - | bge >5 - |1: - if (op == BC_TNEW) { - | rlwinm CARG2, RD, 29, 21, 31 - | rlwinm CARG3, RD, 18, 27, 31 - | cmpwi CARG2, 0x7ff; beq >3 - |2: - | bl extern lj_tab_new // (lua_State *L, int32_t asize, uint32_t hbits) - | // Returns Table *. - } else { - | srwi TMP1, RD, 1 - | subfic TMP1, TMP1, -4 - | lwzx CARG2, KBASE, TMP1 // KBASE-4-tab_const*4 - | bl extern lj_tab_dup // (lua_State *L, Table *kt) - | // Returns Table *. - } - | lp BASE, L->base - | li TMP0, LJ_TTAB - | stwux TMP0, RA, BASE - | stw TAB:CRET1, 4(RA) - | ins_next - if (op == BC_TNEW) { - |3: - | li CARG2, 0x801 - | b <2 - } - |5: - | mr SAVE0, RD - | bl extern lj_gc_step_fixtop // (lua_State *L) - | mr RD, SAVE0 - | mr CARG1, L - | b <1 - break; - - case BC_GGET: - | // RA = dst*8, RD = str_const*8 (~) - case BC_GSET: - | // RA = src*8, RD = str_const*8 (~) - | lwz LFUNC:TMP2, FRAME_FUNC(BASE) - | srwi TMP1, RD, 1 - | lwz TAB:RB, LFUNC:TMP2->env - | subfic TMP1, TMP1, -4 - | lwzx STR:RC, KBASE, TMP1 // KBASE-4-str_const*4 - if (op == BC_GGET) { - | b ->BC_TGETS_Z - } else { - | b ->BC_TSETS_Z - } - break; - - case BC_TGETV: - | // RA = dst*8, RB = table*8, RC = key*8 - | lwzux CARG1, RB, BASE - | lwzux CARG2, RC, BASE - | lwz TAB:RB, 4(RB) - |.if DUALNUM - | lwz RC, 4(RC) - |.else - | lfd f0, 0(RC) - |.endif - | checktab CARG1 - | checknum cr1, CARG2 - | bne ->vmeta_tgetv - |.if DUALNUM - | lwz TMP0, TAB:RB->asize - | bne cr1, >5 - | lwz TMP1, TAB:RB->array - | cmplw TMP0, RC - | slwi TMP2, RC, 3 - |.else - | bge cr1, >5 - | // Convert number key to integer, check for integerness and range. - | fctiwz f1, f0 - | fadd f2, f0, TOBIT - | stfd f1, TMPD - | lwz TMP0, TAB:RB->asize - | fsub f2, f2, TOBIT - | lwz TMP2, TMPD_LO - | lwz TMP1, TAB:RB->array - | fcmpu cr1, f0, f2 - | cmplw cr0, TMP0, TMP2 - | crand 4*cr0+gt, 4*cr0+gt, 4*cr1+eq - | slwi TMP2, TMP2, 3 - |.endif - | ble ->vmeta_tgetv // Integer key and in array part? - | lwzx TMP0, TMP1, TMP2 - |.if FPU - | lfdx f14, TMP1, TMP2 - |.else - | lwzux SAVE0, TMP1, TMP2 - | lwz SAVE1, 4(TMP1) - |.endif - | checknil TMP0; beq >2 - |1: - | ins_next1 - |.if FPU - | stfdx f14, BASE, RA - |.else - | stwux SAVE0, RA, BASE - | stw SAVE1, 4(RA) - |.endif - | ins_next2 - | - |2: // Check for __index if table value is nil. - | lwz TAB:TMP2, TAB:RB->metatable - | cmplwi TAB:TMP2, 0 - | beq <1 // No metatable: done. - | lbz TMP0, TAB:TMP2->nomm - | andix. TMP0, TMP0, 1<vmeta_tgetv - | - |5: - | checkstr CARG2; bne ->vmeta_tgetv - |.if not DUALNUM - | lwz STR:RC, 4(RC) - |.endif - | b ->BC_TGETS_Z // String key? - break; - case BC_TGETS: - | // RA = dst*8, RB = table*8, RC = str_const*8 (~) - | lwzux CARG1, RB, BASE - | srwi TMP1, RC, 1 - | lwz TAB:RB, 4(RB) - | subfic TMP1, TMP1, -4 - | checktab CARG1 - | lwzx STR:RC, KBASE, TMP1 // KBASE-4-str_const*4 - | bne ->vmeta_tgets1 - |->BC_TGETS_Z: - | // TAB:RB = GCtab *, STR:RC = GCstr *, RA = dst*8 - | lwz TMP0, TAB:RB->hmask - | lwz TMP1, STR:RC->hash - | lwz NODE:TMP2, TAB:RB->node - | and TMP1, TMP1, TMP0 // idx = str->hash & tab->hmask - | slwi TMP0, TMP1, 5 - | slwi TMP1, TMP1, 3 - | sub TMP1, TMP0, TMP1 - | add NODE:TMP2, NODE:TMP2, TMP1 // node = tab->node + (idx*32-idx*8) - |1: - | lwz CARG1, NODE:TMP2->key - | lwz TMP0, 4+offsetof(Node, key)(NODE:TMP2) - | lwz CARG2, NODE:TMP2->val - | lwz TMP1, 4+offsetof(Node, val)(NODE:TMP2) - | checkstr CARG1; bne >4 - | cmpw TMP0, STR:RC; bne >4 - | checknil CARG2; beq >5 // Key found, but nil value? - |3: - | stwux CARG2, RA, BASE - | stw TMP1, 4(RA) - | ins_next - | - |4: // Follow hash chain. - | lwz NODE:TMP2, NODE:TMP2->next - | cmplwi NODE:TMP2, 0 - | bne <1 - | // End of hash chain: key not found, nil result. - | li CARG2, LJ_TNIL - | - |5: // Check for __index if table value is nil. - | lwz TAB:TMP2, TAB:RB->metatable - | cmplwi TAB:TMP2, 0 - | beq <3 // No metatable: done. - | lbz TMP0, TAB:TMP2->nomm - | andix. TMP0, TMP0, 1<vmeta_tgets - break; - case BC_TGETB: - | // RA = dst*8, RB = table*8, RC = index*8 - | lwzux CARG1, RB, BASE - | srwi TMP0, RC, 3 - | lwz TAB:RB, 4(RB) - | checktab CARG1; bne ->vmeta_tgetb - | lwz TMP1, TAB:RB->asize - | lwz TMP2, TAB:RB->array - | cmplw TMP0, TMP1; bge ->vmeta_tgetb - |.if FPU - | lwzx TMP1, TMP2, RC - | lfdx f0, TMP2, RC - |.else - | lwzux TMP1, TMP2, RC - | lwz TMP3, 4(TMP2) - |.endif - | checknil TMP1; beq >5 - |1: - | ins_next1 - |.if FPU - | stfdx f0, BASE, RA - |.else - | stwux TMP1, RA, BASE - | stw TMP3, 4(RA) - |.endif - | ins_next2 - | - |5: // Check for __index if table value is nil. - | lwz TAB:TMP2, TAB:RB->metatable - | cmplwi TAB:TMP2, 0 - | beq <1 // No metatable: done. - | lbz TMP2, TAB:TMP2->nomm - | andix. TMP2, TMP2, 1<vmeta_tgetb // Caveat: preserve TMP0! - break; - case BC_TGETR: - | // RA = dst*8, RB = table*8, RC = key*8 - | add RB, BASE, RB - | lwz TAB:CARG1, 4(RB) - |.if DUALNUM - | add RC, BASE, RC - | lwz TMP0, TAB:CARG1->asize - | lwz CARG2, 4(RC) - | lwz TMP1, TAB:CARG1->array - |.else - | lfdx f0, BASE, RC - | lwz TMP0, TAB:CARG1->asize - | toint CARG2, f0 - | lwz TMP1, TAB:CARG1->array - |.endif - | cmplw TMP0, CARG2 - | slwi TMP2, CARG2, 3 - | ble ->vmeta_tgetr // In array part? - |.if FPU - | lfdx f14, TMP1, TMP2 - |.else - | lwzux SAVE0, TMP2, TMP1 - | lwz SAVE1, 4(TMP2) - |.endif - |->BC_TGETR_Z: - | ins_next1 - |.if FPU - | stfdx f14, BASE, RA - |.else - | stwux SAVE0, RA, BASE - | stw SAVE1, 4(RA) - |.endif - | ins_next2 - break; - - case BC_TSETV: - | // RA = src*8, RB = table*8, RC = key*8 - | lwzux CARG1, RB, BASE - | lwzux CARG2, RC, BASE - | lwz TAB:RB, 4(RB) - |.if DUALNUM - | lwz RC, 4(RC) - |.else - | lfd f0, 0(RC) - |.endif - | checktab CARG1 - | checknum cr1, CARG2 - | bne ->vmeta_tsetv - |.if DUALNUM - | lwz TMP0, TAB:RB->asize - | bne cr1, >5 - | lwz TMP1, TAB:RB->array - | cmplw TMP0, RC - | slwi TMP0, RC, 3 - |.else - | bge cr1, >5 - | // Convert number key to integer, check for integerness and range. - | fctiwz f1, f0 - | fadd f2, f0, TOBIT - | stfd f1, TMPD - | lwz TMP0, TAB:RB->asize - | fsub f2, f2, TOBIT - | lwz TMP2, TMPD_LO - | lwz TMP1, TAB:RB->array - | fcmpu cr1, f0, f2 - | cmplw cr0, TMP0, TMP2 - | crand 4*cr0+gt, 4*cr0+gt, 4*cr1+eq - | slwi TMP0, TMP2, 3 - |.endif - | ble ->vmeta_tsetv // Integer key and in array part? - | lwzx TMP2, TMP1, TMP0 - | lbz TMP3, TAB:RB->marked - |.if FPU - | lfdx f14, BASE, RA - |.else - | add SAVE1, BASE, RA - | lwz SAVE0, 0(SAVE1) - | lwz SAVE1, 4(SAVE1) - |.endif - | checknil TMP2; beq >3 - |1: - | andix. TMP2, TMP3, LJ_GC_BLACK // isblack(table) - |.if FPU - | stfdx f14, TMP1, TMP0 - |.else - | stwux SAVE0, TMP1, TMP0 - | stw SAVE1, 4(TMP1) - |.endif - | bne >7 - |2: - | ins_next - | - |3: // Check for __newindex if previous value is nil. - | lwz TAB:TMP2, TAB:RB->metatable - | cmplwi TAB:TMP2, 0 - | beq <1 // No metatable: done. - | lbz TMP2, TAB:TMP2->nomm - | andix. TMP2, TMP2, 1<vmeta_tsetv - | - |5: - | checkstr CARG2; bne ->vmeta_tsetv - |.if not DUALNUM - | lwz STR:RC, 4(RC) - |.endif - | b ->BC_TSETS_Z // String key? - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:RB, TMP3, TMP0 - | b <2 - break; - case BC_TSETS: - | // RA = src*8, RB = table*8, RC = str_const*8 (~) - | lwzux CARG1, RB, BASE - | srwi TMP1, RC, 1 - | lwz TAB:RB, 4(RB) - | subfic TMP1, TMP1, -4 - | checktab CARG1 - | lwzx STR:RC, KBASE, TMP1 // KBASE-4-str_const*4 - | bne ->vmeta_tsets1 - |->BC_TSETS_Z: - | // TAB:RB = GCtab *, STR:RC = GCstr *, RA = src*8 - | lwz TMP0, TAB:RB->hmask - | lwz TMP1, STR:RC->hash - | lwz NODE:TMP2, TAB:RB->node - | stb ZERO, TAB:RB->nomm // Clear metamethod cache. - | and TMP1, TMP1, TMP0 // idx = str->hash & tab->hmask - |.if FPU - | lfdx f14, BASE, RA - |.else - | add CARG2, BASE, RA - | lwz SAVE0, 0(CARG2) - | lwz SAVE1, 4(CARG2) - |.endif - | slwi TMP0, TMP1, 5 - | slwi TMP1, TMP1, 3 - | sub TMP1, TMP0, TMP1 - | lbz TMP3, TAB:RB->marked - | add NODE:TMP2, NODE:TMP2, TMP1 // node = tab->node + (idx*32-idx*8) - |1: - | lwz CARG1, NODE:TMP2->key - | lwz TMP0, 4+offsetof(Node, key)(NODE:TMP2) - | lwz CARG2, NODE:TMP2->val - | lwz NODE:TMP1, NODE:TMP2->next - | checkstr CARG1; bne >5 - | cmpw TMP0, STR:RC; bne >5 - | checknil CARG2; beq >4 // Key found, but nil value? - |2: - | andix. TMP0, TMP3, LJ_GC_BLACK // isblack(table) - |.if FPU - | stfd f14, NODE:TMP2->val - |.else - | stw SAVE0, NODE:TMP2->val.u32.hi - | stw SAVE1, NODE:TMP2->val.u32.lo - |.endif - | bne >7 - |3: - | ins_next - | - |4: // Check for __newindex if previous value is nil. - | lwz TAB:TMP1, TAB:RB->metatable - | cmplwi TAB:TMP1, 0 - | beq <2 // No metatable: done. - | lbz TMP0, TAB:TMP1->nomm - | andix. TMP0, TMP0, 1<vmeta_tsets - | - |5: // Follow hash chain. - | cmplwi NODE:TMP1, 0 - | mr NODE:TMP2, NODE:TMP1 - | bne <1 - | // End of hash chain: key not found, add a new one. - | - | // But check for __newindex first. - | lwz TAB:TMP1, TAB:RB->metatable - | la CARG3, DISPATCH_GL(tmptv)(DISPATCH) - | stw PC, SAVE_PC - | mr CARG1, L - | cmplwi TAB:TMP1, 0 - | stp BASE, L->base - | beq >6 // No metatable: continue. - | lbz TMP0, TAB:TMP1->nomm - | andix. TMP0, TMP0, 1<vmeta_tsets // 'no __newindex' flag NOT set: check. - |6: - | li TMP0, LJ_TSTR - | stw STR:RC, 4(CARG3) - | mr CARG2, TAB:RB - | stw TMP0, 0(CARG3) - | bl extern lj_tab_newkey // (lua_State *L, GCtab *t, TValue *k) - | // Returns TValue *. - | lp BASE, L->base - |.if FPU - | stfd f14, 0(CRET1) - |.else - | stw SAVE0, 0(CRET1) - | stw SAVE1, 4(CRET1) - |.endif - | b <3 // No 2nd write barrier needed. - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:RB, TMP3, TMP0 - | b <3 - break; - case BC_TSETB: - | // RA = src*8, RB = table*8, RC = index*8 - | lwzux CARG1, RB, BASE - | srwi TMP0, RC, 3 - | lwz TAB:RB, 4(RB) - | checktab CARG1; bne ->vmeta_tsetb - | lwz TMP1, TAB:RB->asize - | lwz TMP2, TAB:RB->array - | lbz TMP3, TAB:RB->marked - | cmplw TMP0, TMP1 - |.if FPU - | lfdx f14, BASE, RA - |.else - | add CARG2, BASE, RA - | lwz SAVE0, 0(CARG2) - | lwz SAVE1, 4(CARG2) - |.endif - | bge ->vmeta_tsetb - | lwzx TMP1, TMP2, RC - | checknil TMP1; beq >5 - |1: - | andix. TMP0, TMP3, LJ_GC_BLACK // isblack(table) - |.if FPU - | stfdx f14, TMP2, RC - |.else - | stwux SAVE0, RC, TMP2 - | stw SAVE1, 4(RC) - |.endif - | bne >7 - |2: - | ins_next - | - |5: // Check for __newindex if previous value is nil. - | lwz TAB:TMP1, TAB:RB->metatable - | cmplwi TAB:TMP1, 0 - | beq <1 // No metatable: done. - | lbz TMP1, TAB:TMP1->nomm - | andix. TMP1, TMP1, 1<vmeta_tsetb // Caveat: preserve TMP0! - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:RB, TMP3, TMP0 - | b <2 - break; - case BC_TSETR: - | // RA = dst*8, RB = table*8, RC = key*8 - | add RB, BASE, RB - | lwz TAB:CARG2, 4(RB) - |.if DUALNUM - | add RC, BASE, RC - | lbz TMP3, TAB:CARG2->marked - | lwz TMP0, TAB:CARG2->asize - | lwz CARG3, 4(RC) - | lwz TMP1, TAB:CARG2->array - |.else - | lfdx f0, BASE, RC - | lbz TMP3, TAB:CARG2->marked - | lwz TMP0, TAB:CARG2->asize - | toint CARG3, f0 - | lwz TMP1, TAB:CARG2->array - |.endif - | andix. TMP2, TMP3, LJ_GC_BLACK // isblack(table) - | bne >7 - |2: - | cmplw TMP0, CARG3 - | slwi TMP2, CARG3, 3 - |.if FPU - | lfdx f14, BASE, RA - |.else - | lwzux SAVE0, RA, BASE - | lwz SAVE1, 4(RA) - |.endif - | ble ->vmeta_tsetr // In array part? - | ins_next1 - |.if FPU - | stfdx f14, TMP1, TMP2 - |.else - | stwux SAVE0, TMP1, TMP2 - | stw SAVE1, 4(TMP1) - |.endif - | ins_next2 - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:CARG2, TMP3, TMP2 - | b <2 - break; - - - case BC_TSETM: - | // RA = base*8 (table at base-1), RD = num_const*8 (start index) - | add RA, BASE, RA - |1: - | add TMP3, KBASE, RD - | lwz TAB:CARG2, -4(RA) // Guaranteed to be a table. - | addic. TMP0, MULTRES, -8 - | lwz TMP3, 4(TMP3) // Integer constant is in lo-word. - | srwi CARG3, TMP0, 3 - | beq >4 // Nothing to copy? - | add CARG3, CARG3, TMP3 - | lwz TMP2, TAB:CARG2->asize - | slwi TMP1, TMP3, 3 - | lbz TMP3, TAB:CARG2->marked - | cmplw CARG3, TMP2 - | add TMP2, RA, TMP0 - | lwz TMP0, TAB:CARG2->array - | bgt >5 - | add TMP1, TMP1, TMP0 - | andix. TMP0, TMP3, LJ_GC_BLACK // isblack(table) - |3: // Copy result slots to table. - |.if FPU - | lfd f0, 0(RA) - |.else - | lwz SAVE0, 0(RA) - | lwz SAVE1, 4(RA) - |.endif - | addi RA, RA, 8 - | cmpw cr1, RA, TMP2 - |.if FPU - | stfd f0, 0(TMP1) - |.else - | stw SAVE0, 0(TMP1) - | stw SAVE1, 4(TMP1) - |.endif - | addi TMP1, TMP1, 8 - | blt cr1, <3 - | bne >7 - |4: - | ins_next - | - |5: // Need to resize array part. - | stp BASE, L->base - | mr CARG1, L - | stw PC, SAVE_PC - | mr SAVE0, RD - | bl extern lj_tab_reasize // (lua_State *L, GCtab *t, int nasize) - | // Must not reallocate the stack. - | mr RD, SAVE0 - | b <1 - | - |7: // Possible table write barrier for any value. Skip valiswhite check. - | barrierback TAB:CARG2, TMP3, TMP0 - | b <4 - break; - - /* -- Calls and vararg handling ----------------------------------------- */ - - case BC_CALLM: - | // RA = base*8, (RB = (nresults+1)*8,) RC = extra_nargs*8 - | add NARGS8:RC, NARGS8:RC, MULTRES - | // Fall through. Assumes BC_CALL follows. - break; - case BC_CALL: - | // RA = base*8, (RB = (nresults+1)*8,) RC = (nargs+1)*8 - | mr TMP2, BASE - | lwzux TMP0, BASE, RA - | lwz LFUNC:RB, 4(BASE) - | subi NARGS8:RC, NARGS8:RC, 8 - | addi BASE, BASE, 8 - | checkfunc TMP0; bne ->vmeta_call - | ins_call - break; - - case BC_CALLMT: - | // RA = base*8, (RB = 0,) RC = extra_nargs*8 - | add NARGS8:RC, NARGS8:RC, MULTRES - | // Fall through. Assumes BC_CALLT follows. - break; - case BC_CALLT: - | // RA = base*8, (RB = 0,) RC = (nargs+1)*8 - | lwzux TMP0, RA, BASE - | lwz LFUNC:RB, 4(RA) - | subi NARGS8:RC, NARGS8:RC, 8 - | lwz TMP1, FRAME_PC(BASE) - | checkfunc TMP0 - | addi RA, RA, 8 - | bne ->vmeta_callt - |->BC_CALLT_Z: - | andix. TMP0, TMP1, FRAME_TYPE // Caveat: preserve cr0 until the crand. - | lbz TMP3, LFUNC:RB->ffid - | xori TMP2, TMP1, FRAME_VARG - | cmplwi cr1, NARGS8:RC, 0 - | bne >7 - |1: - | stw LFUNC:RB, FRAME_FUNC(BASE) // Copy function down, but keep PC. - | li TMP2, 0 - | cmplwi cr7, TMP3, 1 // (> FF_C) Calling a fast function? - | beq cr1, >3 - |2: - | addi TMP3, TMP2, 8 - |.if FPU - | lfdx f0, RA, TMP2 - |.else - | add CARG3, RA, TMP2 - | lwz CARG1, 0(CARG3) - | lwz CARG2, 4(CARG3) - |.endif - | cmplw cr1, TMP3, NARGS8:RC - |.if FPU - | stfdx f0, BASE, TMP2 - |.else - | stwux CARG1, TMP2, BASE - | stw CARG2, 4(TMP2) - |.endif - | mr TMP2, TMP3 - | bne cr1, <2 - |3: - | crand 4*cr0+eq, 4*cr0+eq, 4*cr7+gt - | beq >5 - |4: - | ins_callt - | - |5: // Tailcall to a fast function with a Lua frame below. - | lwz INS, -4(TMP1) - | decode_RA8 RA, INS - | sub TMP1, BASE, RA - | lwz LFUNC:TMP1, FRAME_FUNC-8(TMP1) - | lwz TMP1, LFUNC:TMP1->pc - | lwz KBASE, PC2PROTO(k)(TMP1) // Need to prepare KBASE. - | b <4 - | - |7: // Tailcall from a vararg function. - | andix. TMP0, TMP2, FRAME_TYPEP - | bne <1 // Vararg frame below? - | sub BASE, BASE, TMP2 // Relocate BASE down. - | lwz TMP1, FRAME_PC(BASE) - | andix. TMP0, TMP1, FRAME_TYPE - | b <1 - break; - - case BC_ITERC: - | // RA = base*8, (RB = (nresults+1)*8, RC = (nargs+1)*8 ((2+1)*8)) - | mr TMP2, BASE - | add BASE, BASE, RA - | lwz TMP1, -24(BASE) - | lwz LFUNC:RB, -20(BASE) - |.if FPU - | lfd f1, -8(BASE) - | lfd f0, -16(BASE) - |.else - | lwz CARG1, -8(BASE) - | lwz CARG2, -4(BASE) - | lwz CARG3, -16(BASE) - | lwz CARG4, -12(BASE) - |.endif - | stw TMP1, 0(BASE) // Copy callable. - | stw LFUNC:RB, 4(BASE) - | checkfunc TMP1 - | li NARGS8:RC, 16 // Iterators get 2 arguments. - |.if FPU - | stfd f1, 16(BASE) // Copy control var. - | stfdu f0, 8(BASE) // Copy state. - |.else - | stw CARG1, 16(BASE) // Copy control var. - | stw CARG2, 20(BASE) - | stwu CARG3, 8(BASE) // Copy state. - | stw CARG4, 4(BASE) - |.endif - | bne ->vmeta_call - | ins_call - break; - - case BC_ITERN: - | // RA = base*8, (RB = (nresults+1)*8, RC = (nargs+1)*8 (2+1)*8) - |.if JIT - | // NYI: add hotloop, record BC_ITERN. - |.endif - | add RA, BASE, RA - | lwz TAB:RB, -12(RA) - | lwz RC, -4(RA) // Get index from control var. - | lwz TMP0, TAB:RB->asize - | lwz TMP1, TAB:RB->array - | addi PC, PC, 4 - |1: // Traverse array part. - | cmplw RC, TMP0 - | slwi TMP3, RC, 3 - | bge >5 // Index points after array part? - | lwzx TMP2, TMP1, TMP3 - |.if FPU - | lfdx f0, TMP1, TMP3 - |.else - | lwzux CARG1, TMP3, TMP1 - | lwz CARG2, 4(TMP3) - |.endif - | checknil TMP2 - | lwz INS, -4(PC) - | beq >4 - |.if DUALNUM - | stw RC, 4(RA) - | stw TISNUM, 0(RA) - |.else - | tonum_u f1, RC - |.endif - | addi RC, RC, 1 - | addis TMP3, PC, -(BCBIAS_J*4 >> 16) - |.if FPU - | stfd f0, 8(RA) - |.else - | stw CARG1, 8(RA) - | stw CARG2, 12(RA) - |.endif - | decode_RD4 TMP1, INS - | stw RC, -4(RA) // Update control var. - | add PC, TMP1, TMP3 - |.if not DUALNUM - | stfd f1, 0(RA) - |.endif - |3: - | ins_next - | - |4: // Skip holes in array part. - | addi RC, RC, 1 - | b <1 - | - |5: // Traverse hash part. - | lwz TMP1, TAB:RB->hmask - | sub RC, RC, TMP0 - | lwz TMP2, TAB:RB->node - |6: - | cmplw RC, TMP1 // End of iteration? Branch to ITERL+1. - | slwi TMP3, RC, 5 - | bgty <3 - | slwi RB, RC, 3 - | sub TMP3, TMP3, RB - | lwzx RB, TMP2, TMP3 - |.if FPU - | lfdx f0, TMP2, TMP3 - |.else - | add CARG3, TMP2, TMP3 - | lwz CARG1, 0(CARG3) - | lwz CARG2, 4(CARG3) - |.endif - | add NODE:TMP3, TMP2, TMP3 - | checknil RB - | lwz INS, -4(PC) - | beq >7 - |.if FPU - | lfd f1, NODE:TMP3->key - |.else - | lwz CARG3, NODE:TMP3->key.u32.hi - | lwz CARG4, NODE:TMP3->key.u32.lo - |.endif - | addis TMP2, PC, -(BCBIAS_J*4 >> 16) - |.if FPU - | stfd f0, 8(RA) - |.else - | stw CARG1, 8(RA) - | stw CARG2, 12(RA) - |.endif - | add RC, RC, TMP0 - | decode_RD4 TMP1, INS - |.if FPU - | stfd f1, 0(RA) - |.else - | stw CARG3, 0(RA) - | stw CARG4, 4(RA) - |.endif - | addi RC, RC, 1 - | add PC, TMP1, TMP2 - | stw RC, -4(RA) // Update control var. - | b <3 - | - |7: // Skip holes in hash part. - | addi RC, RC, 1 - | b <6 - break; - - case BC_ISNEXT: - | // RA = base*8, RD = target (points to ITERN) - | add RA, BASE, RA - | lwz TMP0, -24(RA) - | lwz CFUNC:TMP1, -20(RA) - | lwz TMP2, -16(RA) - | lwz TMP3, -8(RA) - | cmpwi cr0, TMP2, LJ_TTAB - | cmpwi cr1, TMP0, LJ_TFUNC - | cmpwi cr6, TMP3, LJ_TNIL - | bne cr1, >5 - | lbz TMP1, CFUNC:TMP1->ffid - | crand 4*cr0+eq, 4*cr0+eq, 4*cr6+eq - | cmpwi cr7, TMP1, FF_next_N - | srwi TMP0, RD, 1 - | crand 4*cr0+eq, 4*cr0+eq, 4*cr7+eq - | add TMP3, PC, TMP0 - | bne cr0, >5 - | lus TMP1, 0xfffe - | ori TMP1, TMP1, 0x7fff - | stw ZERO, -4(RA) // Initialize control var. - | stw TMP1, -8(RA) - | addis PC, TMP3, -(BCBIAS_J*4 >> 16) - |1: - | ins_next - |5: // Despecialize bytecode if any of the checks fail. - | li TMP0, BC_JMP - | li TMP1, BC_ITERC - | stb TMP0, -1(PC) - | addis PC, TMP3, -(BCBIAS_J*4 >> 16) - | stb TMP1, 3(PC) - | b <1 - break; - - case BC_VARG: - | // RA = base*8, RB = (nresults+1)*8, RC = numparams*8 - | lwz TMP0, FRAME_PC(BASE) - | add RC, BASE, RC - | add RA, BASE, RA - | addi RC, RC, FRAME_VARG - | add TMP2, RA, RB - | subi TMP3, BASE, 8 // TMP3 = vtop - | sub RC, RC, TMP0 // RC = vbase - | // Note: RC may now be even _above_ BASE if nargs was < numparams. - | cmplwi cr1, RB, 0 - |.if PPE - | sub TMP1, TMP3, RC - | cmpwi TMP1, 0 - |.else - | sub. TMP1, TMP3, RC - |.endif - | beq cr1, >5 // Copy all varargs? - | subi TMP2, TMP2, 16 - | ble >2 // No vararg slots? - |1: // Copy vararg slots to destination slots. - |.if FPU - | lfd f0, 0(RC) - |.else - | lwz CARG1, 0(RC) - | lwz CARG2, 4(RC) - |.endif - | addi RC, RC, 8 - |.if FPU - | stfd f0, 0(RA) - |.else - | stw CARG1, 0(RA) - | stw CARG2, 4(RA) - |.endif - | cmplw RA, TMP2 - | cmplw cr1, RC, TMP3 - | bge >3 // All destination slots filled? - | addi RA, RA, 8 - | blt cr1, <1 // More vararg slots? - |2: // Fill up remainder with nil. - | stw TISNIL, 0(RA) - | cmplw RA, TMP2 - | addi RA, RA, 8 - | blt <2 - |3: - | ins_next - | - |5: // Copy all varargs. - | lwz TMP0, L->maxstack - | li MULTRES, 8 // MULTRES = (0+1)*8 - | bley <3 // No vararg slots? - | add TMP2, RA, TMP1 - | cmplw TMP2, TMP0 - | addi MULTRES, TMP1, 8 - | bgt >7 - |6: - |.if FPU - | lfd f0, 0(RC) - |.else - | lwz CARG1, 0(RC) - | lwz CARG2, 4(RC) - |.endif - | addi RC, RC, 8 - |.if FPU - | stfd f0, 0(RA) - |.else - | stw CARG1, 0(RA) - | stw CARG2, 4(RA) - |.endif - | cmplw RC, TMP3 - | addi RA, RA, 8 - | blt <6 // More vararg slots? - | b <3 - | - |7: // Grow stack for varargs. - | mr CARG1, L - | stp RA, L->top - | sub SAVE0, RC, BASE // Need delta, because BASE may change. - | stp BASE, L->base - | sub RA, RA, BASE - | stw PC, SAVE_PC - | srwi CARG2, TMP1, 3 - | bl extern lj_state_growstack // (lua_State *L, int n) - | lp BASE, L->base - | add RA, BASE, RA - | add RC, BASE, SAVE0 - | subi TMP3, BASE, 8 - | b <6 - break; - - /* -- Returns ----------------------------------------------------------- */ - - case BC_RETM: - | // RA = results*8, RD = extra_nresults*8 - | add RD, RD, MULTRES // MULTRES >= 8, so RD >= 8. - | // Fall through. Assumes BC_RET follows. - break; - - case BC_RET: - | // RA = results*8, RD = (nresults+1)*8 - | lwz PC, FRAME_PC(BASE) - | add RA, BASE, RA - | mr MULTRES, RD - |1: - | andix. TMP0, PC, FRAME_TYPE - | xori TMP1, PC, FRAME_VARG - | bne ->BC_RETV_Z - | - |->BC_RET_Z: - | // BASE = base, RA = resultptr, RD = (nresults+1)*8, PC = return - | lwz INS, -4(PC) - | cmpwi RD, 8 - | subi TMP2, BASE, 8 - | subi RC, RD, 8 - | decode_RB8 RB, INS - | beq >3 - | li TMP1, 0 - |2: - | addi TMP3, TMP1, 8 - |.if FPU - | lfdx f0, RA, TMP1 - |.else - | add CARG3, RA, TMP1 - | lwz CARG1, 0(CARG3) - | lwz CARG2, 4(CARG3) - |.endif - | cmpw TMP3, RC - |.if FPU - | stfdx f0, TMP2, TMP1 - |.else - | add CARG3, TMP2, TMP1 - | stw CARG1, 0(CARG3) - | stw CARG2, 4(CARG3) - |.endif - | beq >3 - | addi TMP1, TMP3, 8 - |.if FPU - | lfdx f1, RA, TMP3 - |.else - | add CARG3, RA, TMP3 - | lwz CARG1, 0(CARG3) - | lwz CARG2, 4(CARG3) - |.endif - | cmpw TMP1, RC - |.if FPU - | stfdx f1, TMP2, TMP3 - |.else - | add CARG3, TMP2, TMP3 - | stw CARG1, 0(CARG3) - | stw CARG2, 4(CARG3) - |.endif - | bne <2 - |3: - |5: - | cmplw RB, RD - | decode_RA8 RA, INS - | bgt >6 - | sub BASE, TMP2, RA - | lwz LFUNC:TMP1, FRAME_FUNC(BASE) - | ins_next1 - | lwz TMP1, LFUNC:TMP1->pc - | lwz KBASE, PC2PROTO(k)(TMP1) - | ins_next2 - | - |6: // Fill up results with nil. - | subi TMP1, RD, 8 - | addi RD, RD, 8 - | stwx TISNIL, TMP2, TMP1 - | b <5 - | - |->BC_RETV_Z: // Non-standard return case. - | andix. TMP2, TMP1, FRAME_TYPEP - | bne ->vm_return - | // Return from vararg function: relocate BASE down. - | sub BASE, BASE, TMP1 - | lwz PC, FRAME_PC(BASE) - | b <1 - break; - - case BC_RET0: case BC_RET1: - | // RA = results*8, RD = (nresults+1)*8 - | lwz PC, FRAME_PC(BASE) - | add RA, BASE, RA - | mr MULTRES, RD - | andix. TMP0, PC, FRAME_TYPE - | xori TMP1, PC, FRAME_VARG - | bney ->BC_RETV_Z - | - | lwz INS, -4(PC) - | subi TMP2, BASE, 8 - | decode_RB8 RB, INS - if (op == BC_RET1) { - |.if FPU - | lfd f0, 0(RA) - | stfd f0, 0(TMP2) - |.else - | lwz CARG1, 0(RA) - | lwz CARG2, 4(RA) - | stw CARG1, 0(TMP2) - | stw CARG2, 4(TMP2) - |.endif - } - |5: - | cmplw RB, RD - | decode_RA8 RA, INS - | bgt >6 - | sub BASE, TMP2, RA - | lwz LFUNC:TMP1, FRAME_FUNC(BASE) - | ins_next1 - | lwz TMP1, LFUNC:TMP1->pc - | lwz KBASE, PC2PROTO(k)(TMP1) - | ins_next2 - | - |6: // Fill up results with nil. - | subi TMP1, RD, 8 - | addi RD, RD, 8 - | stwx TISNIL, TMP2, TMP1 - | b <5 - break; - - /* -- Loops and branches ------------------------------------------------ */ - - case BC_FORL: - |.if JIT - | hotloop - |.endif - | // Fall through. Assumes BC_IFORL follows. - break; - - case BC_JFORI: - case BC_JFORL: -#if !LJ_HASJIT - break; -#endif - case BC_FORI: - case BC_IFORL: - | // RA = base*8, RD = target (after end of loop or start of loop) - vk = (op == BC_IFORL || op == BC_JFORL); - |.if DUALNUM - | // Integer loop. - | lwzux TMP1, RA, BASE - | lwz CARG1, FORL_IDX*8+4(RA) - | cmplw cr0, TMP1, TISNUM - if (vk) { - | lwz CARG3, FORL_STEP*8+4(RA) - | bne >9 - |.if GPR64 - | // Need to check overflow for (a<<32) + (b<<32). - | rldicr TMP0, CARG1, 32, 31 - | rldicr TMP2, CARG3, 32, 31 - | add CARG1, CARG1, CARG3 - | addo. TMP0, TMP0, TMP2 - |.else - | addo. CARG1, CARG1, CARG3 - |.endif - | cmpwi cr6, CARG3, 0 - | lwz CARG2, FORL_STOP*8+4(RA) - | bso >6 - |4: - | stw CARG1, FORL_IDX*8+4(RA) - } else { - | lwz SAVE0, FORL_STEP*8(RA) - | lwz CARG3, FORL_STEP*8+4(RA) - | lwz TMP2, FORL_STOP*8(RA) - | lwz CARG2, FORL_STOP*8+4(RA) - | cmplw cr7, SAVE0, TISNUM - | cmplw cr1, TMP2, TISNUM - | crand 4*cr0+eq, 4*cr0+eq, 4*cr7+eq - | crand 4*cr0+eq, 4*cr0+eq, 4*cr1+eq - | cmpwi cr6, CARG3, 0 - | bne >9 - } - | blt cr6, >5 - | cmpw CARG1, CARG2 - |1: - | stw TISNUM, FORL_EXT*8(RA) - if (op != BC_JFORL) { - | srwi RD, RD, 1 - } - | stw CARG1, FORL_EXT*8+4(RA) - if (op != BC_JFORL) { - | add RD, PC, RD - } - if (op == BC_FORI) { - | bgt >3 // See FP loop below. - } else if (op == BC_JFORI) { - | addis PC, RD, -(BCBIAS_J*4 >> 16) - | bley >7 - } else if (op == BC_IFORL) { - | bgt >2 - | addis PC, RD, -(BCBIAS_J*4 >> 16) - } else { - | bley =>BC_JLOOP - } - |2: - | ins_next - |5: // Invert check for negative step. - | cmpw CARG2, CARG1 - | b <1 - if (vk) { - |6: // Potential overflow. - | checkov TMP0, <4 // Ignore unrelated overflow. - | b <2 - } - |.endif - if (vk) { - |.if DUALNUM - |9: // FP loop. - |.if FPU - | lfd f1, FORL_IDX*8(RA) - |.else - | lwz CARG1, FORL_IDX*8(RA) - | lwz CARG2, FORL_IDX*8+4(RA) - |.endif - |.else - | lfdux f1, RA, BASE - |.endif - |.if FPU - | lfd f3, FORL_STEP*8(RA) - | lfd f2, FORL_STOP*8(RA) - | fadd f1, f1, f3 - | stfd f1, FORL_IDX*8(RA) - |.else - | lwz CARG3, FORL_STEP*8(RA) - | lwz CARG4, FORL_STEP*8+4(RA) - | mr SAVE1, RD - | blex __adddf3 - | mr RD, SAVE1 - | stw CRET1, FORL_IDX*8(RA) - | stw CRET2, FORL_IDX*8+4(RA) - | lwz CARG3, FORL_STOP*8(RA) - | lwz CARG4, FORL_STOP*8+4(RA) - |.endif - | lwz SAVE0, FORL_STEP*8(RA) - } else { - |.if DUALNUM - |9: // FP loop. - |.else - | lwzux TMP1, RA, BASE - | lwz SAVE0, FORL_STEP*8(RA) - | lwz TMP2, FORL_STOP*8(RA) - | cmplw cr0, TMP1, TISNUM - | cmplw cr7, SAVE0, TISNUM - | cmplw cr1, TMP2, TISNUM - |.endif - |.if FPU - | lfd f1, FORL_IDX*8(RA) - |.else - | lwz CARG1, FORL_IDX*8(RA) - | lwz CARG2, FORL_IDX*8+4(RA) - |.endif - | crand 4*cr0+lt, 4*cr0+lt, 4*cr7+lt - | crand 4*cr0+lt, 4*cr0+lt, 4*cr1+lt - |.if FPU - | lfd f2, FORL_STOP*8(RA) - |.else - | lwz CARG3, FORL_STOP*8(RA) - | lwz CARG4, FORL_STOP*8+4(RA) - |.endif - | bge ->vmeta_for - } - | cmpwi cr6, SAVE0, 0 - if (op != BC_JFORL) { - | srwi RD, RD, 1 - } - |.if FPU - | stfd f1, FORL_EXT*8(RA) - |.else - | stw CARG1, FORL_EXT*8(RA) - | stw CARG2, FORL_EXT*8+4(RA) - |.endif - if (op != BC_JFORL) { - | add RD, PC, RD - } - |.if FPU - | fcmpu cr0, f1, f2 - |.else - | mr SAVE1, RD - | blex __ledf2 - | cmpwi CRET1, 0 - | mr RD, SAVE1 - |.endif - if (op == BC_JFORI) { - | addis PC, RD, -(BCBIAS_J*4 >> 16) - } - | blt cr6, >5 - if (op == BC_FORI) { - | bgt >3 - } else if (op == BC_IFORL) { - |.if DUALNUM - | bgty <2 - |.else - | bgt >2 - |.endif - |1: - | addis PC, RD, -(BCBIAS_J*4 >> 16) - } else if (op == BC_JFORI) { - | bley >7 - } else { - | bley =>BC_JLOOP - } - |.if DUALNUM - | b <2 - |.else - |2: - | ins_next - |.endif - |5: // Negative step. - if (op == BC_FORI) { - | bge <2 - |3: // Used by integer loop, too. - | addis PC, RD, -(BCBIAS_J*4 >> 16) - } else if (op == BC_IFORL) { - | bgey <1 - } else if (op == BC_JFORI) { - | bgey >7 - } else { - | bgey =>BC_JLOOP - } - | b <2 - if (op == BC_JFORI) { - |7: - | lwz INS, -4(PC) - | decode_RD8 RD, INS - | b =>BC_JLOOP - } - break; - - case BC_ITERL: - |.if JIT - | hotloop - |.endif - | // Fall through. Assumes BC_IITERL follows. - break; - - case BC_JITERL: -#if !LJ_HASJIT - break; -#endif - case BC_IITERL: - | // RA = base*8, RD = target - | lwzux TMP1, RA, BASE - | lwz TMP2, 4(RA) - | checknil TMP1; beq >1 // Stop if iterator returned nil. - if (op == BC_JITERL) { - | stw TMP1, -8(RA) - | stw TMP2, -4(RA) - | b =>BC_JLOOP - } else { - | branch_RD // Otherwise save control var + branch. - | stw TMP1, -8(RA) - | stw TMP2, -4(RA) - } - |1: - | ins_next - break; - - case BC_LOOP: - | // RA = base*8, RD = target (loop extent) - | // Note: RA/RD is only used by trace recorder to determine scope/extent - | // This opcode does NOT jump, it's only purpose is to detect a hot loop. - |.if JIT - | hotloop - |.endif - | // Fall through. Assumes BC_ILOOP follows. - break; - - case BC_ILOOP: - | // RA = base*8, RD = target (loop extent) - | ins_next - break; - - case BC_JLOOP: - |.if JIT - | // RA = base*8 (ignored), RD = traceno*8 - | lwz TMP1, DISPATCH_J(trace)(DISPATCH) - | srwi RD, RD, 1 - | // Traces on PPC don't store the trace number, so use 0. - | stw ZERO, DISPATCH_GL(vmstate)(DISPATCH) - | lwzx TRACE:TMP2, TMP1, RD - | clrso TMP1 - | lp TMP2, TRACE:TMP2->mcode - | stw BASE, DISPATCH_GL(jit_base)(DISPATCH) - | mtctr TMP2 - | addi JGL, DISPATCH, GG_DISP2G+32768 - | stw L, DISPATCH_GL(tmpbuf.L)(DISPATCH) - | bctr - |.endif - break; - - case BC_JMP: - | // RA = base*8 (only used by trace recorder), RD = target - | branch_RD - | ins_next - break; - - /* -- Function headers -------------------------------------------------- */ - - case BC_FUNCF: - |.if JIT - | hotcall - |.endif - case BC_FUNCV: /* NYI: compiled vararg functions. */ - | // Fall through. Assumes BC_IFUNCF/BC_IFUNCV follow. - break; - - case BC_JFUNCF: -#if !LJ_HASJIT - break; -#endif - case BC_IFUNCF: - | // BASE = new base, RA = BASE+framesize*8, RB = LFUNC, RC = nargs*8 - | lwz TMP2, L->maxstack - | lbz TMP1, -4+PC2PROTO(numparams)(PC) - | lwz KBASE, -4+PC2PROTO(k)(PC) - | cmplw RA, TMP2 - | slwi TMP1, TMP1, 3 - | bgt ->vm_growstack_l - if (op != BC_JFUNCF) { - | ins_next1 - } - |2: - | cmplw NARGS8:RC, TMP1 // Check for missing parameters. - | blt >3 - if (op == BC_JFUNCF) { - | decode_RD8 RD, INS - | b =>BC_JLOOP - } else { - | ins_next2 - } - | - |3: // Clear missing parameters. - | stwx TISNIL, BASE, NARGS8:RC - | addi NARGS8:RC, NARGS8:RC, 8 - | b <2 - break; - - case BC_JFUNCV: -#if !LJ_HASJIT - break; -#endif - | NYI // NYI: compiled vararg functions - break; /* NYI: compiled vararg functions. */ - - case BC_IFUNCV: - | // BASE = new base, RA = BASE+framesize*8, RB = LFUNC, RC = nargs*8 - | lwz TMP2, L->maxstack - | add TMP1, BASE, RC - | add TMP0, RA, RC - | stw LFUNC:RB, 4(TMP1) // Store copy of LFUNC. - | addi TMP3, RC, 8+FRAME_VARG - | lwz KBASE, -4+PC2PROTO(k)(PC) - | cmplw TMP0, TMP2 - | stw TMP3, 0(TMP1) // Store delta + FRAME_VARG. - | bge ->vm_growstack_l - | lbz TMP2, -4+PC2PROTO(numparams)(PC) - | mr RA, BASE - | mr RC, TMP1 - | ins_next1 - | cmpwi TMP2, 0 - | addi BASE, TMP1, 8 - | beq >3 - |1: - | cmplw RA, RC // Less args than parameters? - | lwz TMP0, 0(RA) - | lwz TMP3, 4(RA) - | bge >4 - | stw TISNIL, 0(RA) // Clear old fixarg slot (help the GC). - | addi RA, RA, 8 - |2: - | addic. TMP2, TMP2, -1 - | stw TMP0, 8(TMP1) - | stw TMP3, 12(TMP1) - | addi TMP1, TMP1, 8 - | bne <1 - |3: - | ins_next2 - | - |4: // Clear missing parameters. - | li TMP0, LJ_TNIL - | b <2 - break; - - case BC_FUNCC: - case BC_FUNCCW: - | // BASE = new base, RA = BASE+framesize*8, RB = CFUNC, RC = nargs*8 - if (op == BC_FUNCC) { - | lp RD, CFUNC:RB->f - } else { - | lp RD, DISPATCH_GL(wrapf)(DISPATCH) - } - | add TMP1, RA, NARGS8:RC - | lwz TMP2, L->maxstack - | .toc lp TMP3, 0(RD) - | add RC, BASE, NARGS8:RC - | stp BASE, L->base - | cmplw TMP1, TMP2 - | stp RC, L->top - | li_vmstate C - |.if TOC - | mtctr TMP3 - |.else - | mtctr RD - |.endif - if (op == BC_FUNCCW) { - | lp CARG2, CFUNC:RB->f - } - | mr CARG1, L - | bgt ->vm_growstack_c // Need to grow stack. - | .toc lp TOCREG, TOC_OFS(RD) - | .tocenv lp ENVREG, ENV_OFS(RD) - | st_vmstate - | bctrl // (lua_State *L [, lua_CFunction f]) - | // Returns nresults. - | lp BASE, L->base - | .toc ld TOCREG, SAVE_TOC - | slwi RD, CRET1, 3 - | lp TMP1, L->top - | li_vmstate INTERP - | lwz PC, FRAME_PC(BASE) // Fetch PC of caller. - | stw L, DISPATCH_GL(cur_L)(DISPATCH) - | sub RA, TMP1, RD // RA = L->top - nresults*8 - | st_vmstate - | b ->vm_returnc - break; - - /* ---------------------------------------------------------------------- */ - - default: - fprintf(stderr, "Error: undefined opcode BC_%s\n", bc_names[op]); - exit(2); - break; - } -} - -static int build_backend(BuildCtx *ctx) -{ - int op; - - dasm_growpc(Dst, BC__MAX); - - build_subroutines(ctx); - - |.code_op - for (op = 0; op < BC__MAX; op++) - build_ins(ctx, (BCOp)op, op); - - return BC__MAX; -} - -/* Emit pseudo frame-info for all assembler functions. */ -static void emit_asm_debug(BuildCtx *ctx) -{ - int fcofs = (int)((uint8_t *)ctx->glob[GLOB_vm_ffi_call] - ctx->code); - int i; - switch (ctx->mode) { - case BUILD_elfasm: - fprintf(ctx->fp, "\t.section .debug_frame,\"\",@progbits\n"); - fprintf(ctx->fp, - ".Lframe0:\n" - "\t.long .LECIE0-.LSCIE0\n" - ".LSCIE0:\n" - "\t.long 0xffffffff\n" - "\t.byte 0x1\n" - "\t.string \"\"\n" - "\t.uleb128 0x1\n" - "\t.sleb128 -4\n" - "\t.byte 65\n" - "\t.byte 0xc\n\t.uleb128 1\n\t.uleb128 0\n" - "\t.align 2\n" - ".LECIE0:\n\n"); - fprintf(ctx->fp, - ".LSFDE0:\n" - "\t.long .LEFDE0-.LASFDE0\n" - ".LASFDE0:\n" - "\t.long .Lframe0\n" - "\t.long .Lbegin\n" - "\t.long %d\n" - "\t.byte 0xe\n\t.uleb128 %d\n" - "\t.byte 0x11\n\t.uleb128 65\n\t.sleb128 -1\n" - "\t.byte 0x5\n\t.uleb128 70\n\t.uleb128 55\n", - fcofs, CFRAME_SIZE); - for (i = 14; i <= 31; i++) - fprintf(ctx->fp, - "\t.byte %d\n\t.uleb128 %d\n" - "\t.byte %d\n\t.uleb128 %d\n", - 0x80+i, 37+(31-i), 0x80+32+i, 2+2*(31-i)); - fprintf(ctx->fp, - "\t.align 2\n" - ".LEFDE0:\n\n"); -#if LJ_HASFFI - fprintf(ctx->fp, - ".LSFDE1:\n" - "\t.long .LEFDE1-.LASFDE1\n" - ".LASFDE1:\n" - "\t.long .Lframe0\n" -#if LJ_TARGET_PS3 - "\t.long .lj_vm_ffi_call\n" -#else - "\t.long lj_vm_ffi_call\n" -#endif - "\t.long %d\n" - "\t.byte 0x11\n\t.uleb128 65\n\t.sleb128 -1\n" - "\t.byte 0x8e\n\t.uleb128 2\n" - "\t.byte 0xd\n\t.uleb128 0xe\n" - "\t.align 2\n" - ".LEFDE1:\n\n", (int)ctx->codesz - fcofs); -#endif -#if !LJ_NO_UNWIND - fprintf(ctx->fp, "\t.section .eh_frame,\"a\",@progbits\n"); - fprintf(ctx->fp, - ".Lframe1:\n" - "\t.long .LECIE1-.LSCIE1\n" - ".LSCIE1:\n" - "\t.long 0\n" - "\t.byte 0x1\n" - "\t.string \"zPR\"\n" - "\t.uleb128 0x1\n" - "\t.sleb128 -4\n" - "\t.byte 65\n" - "\t.uleb128 6\n" /* augmentation length */ - "\t.byte 0x1b\n" /* pcrel|sdata4 */ - "\t.long lj_err_unwind_dwarf-.\n" - "\t.byte 0x1b\n" /* pcrel|sdata4 */ - "\t.byte 0xc\n\t.uleb128 1\n\t.uleb128 0\n" - "\t.align 2\n" - ".LECIE1:\n\n"); - fprintf(ctx->fp, - ".LSFDE2:\n" - "\t.long .LEFDE2-.LASFDE2\n" - ".LASFDE2:\n" - "\t.long .LASFDE2-.Lframe1\n" - "\t.long .Lbegin-.\n" - "\t.long %d\n" - "\t.uleb128 0\n" /* augmentation length */ - "\t.byte 0xe\n\t.uleb128 %d\n" - "\t.byte 0x11\n\t.uleb128 65\n\t.sleb128 -1\n" - "\t.byte 0x5\n\t.uleb128 70\n\t.uleb128 55\n", - fcofs, CFRAME_SIZE); - for (i = 14; i <= 31; i++) - fprintf(ctx->fp, - "\t.byte %d\n\t.uleb128 %d\n" - "\t.byte %d\n\t.uleb128 %d\n", - 0x80+i, 37+(31-i), 0x80+32+i, 2+2*(31-i)); - fprintf(ctx->fp, - "\t.align 2\n" - ".LEFDE2:\n\n"); -#if LJ_HASFFI - fprintf(ctx->fp, - ".Lframe2:\n" - "\t.long .LECIE2-.LSCIE2\n" - ".LSCIE2:\n" - "\t.long 0\n" - "\t.byte 0x1\n" - "\t.string \"zR\"\n" - "\t.uleb128 0x1\n" - "\t.sleb128 -4\n" - "\t.byte 65\n" - "\t.uleb128 1\n" /* augmentation length */ - "\t.byte 0x1b\n" /* pcrel|sdata4 */ - "\t.byte 0xc\n\t.uleb128 1\n\t.uleb128 0\n" - "\t.align 2\n" - ".LECIE2:\n\n"); - fprintf(ctx->fp, - ".LSFDE3:\n" - "\t.long .LEFDE3-.LASFDE3\n" - ".LASFDE3:\n" - "\t.long .LASFDE3-.Lframe2\n" - "\t.long lj_vm_ffi_call-.\n" - "\t.long %d\n" - "\t.uleb128 0\n" /* augmentation length */ - "\t.byte 0x11\n\t.uleb128 65\n\t.sleb128 -1\n" - "\t.byte 0x8e\n\t.uleb128 2\n" - "\t.byte 0xd\n\t.uleb128 0xe\n" - "\t.align 2\n" - ".LEFDE3:\n\n", (int)ctx->codesz - fcofs); -#endif -#endif - break; - default: - break; - } -} - diff --git a/lib/LuaJIT/src/vm_x64.dasc b/lib/LuaJIT/src/vm_x64.dasc deleted file mode 100644 index a003fb4..0000000 --- a/lib/LuaJIT/src/vm_x64.dasc +++ /dev/null @@ -1,4909 +0,0 @@ -|// Low-level VM code for x64 CPUs in LJ_GC64 mode. -|// Bytecode interpreter, fast functions and helper functions. -|// Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -| -|.arch x64 -|.section code_op, code_sub -| -|.actionlist build_actionlist -|.globals GLOB_ -|.globalnames globnames -|.externnames extnames -| -|//----------------------------------------------------------------------- -| -|.if WIN -|.define X64WIN, 1 // Windows/x64 calling conventions. -|.endif -| -|// Fixed register assignments for the interpreter. -|// This is very fragile and has many dependencies. Caveat emptor. -|.define BASE, rdx // Not C callee-save, refetched anyway. -|.if X64WIN -|.define KBASE, rdi // Must be C callee-save. -|.define PC, rsi // Must be C callee-save. -|.define DISPATCH, rbx // Must be C callee-save. -|.define KBASEd, edi -|.define PCd, esi -|.define DISPATCHd, ebx -|.else -|.define KBASE, r15 // Must be C callee-save. -|.define PC, rbx // Must be C callee-save. -|.define DISPATCH, r14 // Must be C callee-save. -|.define KBASEd, r15d -|.define PCd, ebx -|.define DISPATCHd, r14d -|.endif -| -|.define RA, rcx -|.define RAd, ecx -|.define RAH, ch -|.define RAL, cl -|.define RB, rbp // Must be rbp (C callee-save). -|.define RBd, ebp -|.define RC, rax // Must be rax. -|.define RCd, eax -|.define RCW, ax -|.define RCH, ah -|.define RCL, al -|.define OP, RBd -|.define RD, RC -|.define RDd, RCd -|.define RDW, RCW -|.define RDL, RCL -|.define TMPR, r10 -|.define TMPRd, r10d -|.define ITYPE, r11 -|.define ITYPEd, r11d -| -|.if X64WIN -|.define CARG1, rcx // x64/WIN64 C call arguments. -|.define CARG2, rdx -|.define CARG3, r8 -|.define CARG4, r9 -|.define CARG1d, ecx -|.define CARG2d, edx -|.define CARG3d, r8d -|.define CARG4d, r9d -|.else -|.define CARG1, rdi // x64/POSIX C call arguments. -|.define CARG2, rsi -|.define CARG3, rdx -|.define CARG4, rcx -|.define CARG5, r8 -|.define CARG6, r9 -|.define CARG1d, edi -|.define CARG2d, esi -|.define CARG3d, edx -|.define CARG4d, ecx -|.define CARG5d, r8d -|.define CARG6d, r9d -|.endif -| -|// Type definitions. Some of these are only used for documentation. -|.type L, lua_State -|.type GL, global_State -|.type TVALUE, TValue -|.type GCOBJ, GCobj -|.type STR, GCstr -|.type TAB, GCtab -|.type LFUNC, GCfuncL -|.type CFUNC, GCfuncC -|.type PROTO, GCproto -|.type UPVAL, GCupval -|.type NODE, Node -|.type NARGS, int -|.type TRACE, GCtrace -|.type SBUF, SBuf -| -|// Stack layout while in interpreter. Must match with lj_frame.h. -|//----------------------------------------------------------------------- -|.if X64WIN // x64/Windows stack layout -| -|.define CFRAME_SPACE, aword*5 // Delta for rsp (see <--). -|.macro saveregs_ -| push rdi; push rsi; push rbx -| sub rsp, CFRAME_SPACE -|.endmacro -|.macro saveregs -| push rbp; saveregs_ -|.endmacro -|.macro restoreregs -| add rsp, CFRAME_SPACE -| pop rbx; pop rsi; pop rdi; pop rbp -|.endmacro -| -|.define SAVE_CFRAME, aword [rsp+aword*13] -|.define SAVE_PC, aword [rsp+aword*12] -|.define SAVE_L, aword [rsp+aword*11] -|.define SAVE_ERRF, dword [rsp+dword*21] -|.define SAVE_NRES, dword [rsp+dword*20] -|//----- 16 byte aligned, ^^^ 32 byte register save area, owned by interpreter -|.define SAVE_RET, aword [rsp+aword*9] //<-- rsp entering interpreter. -|.define SAVE_R4, aword [rsp+aword*8] -|.define SAVE_R3, aword [rsp+aword*7] -|.define SAVE_R2, aword [rsp+aword*6] -|.define SAVE_R1, aword [rsp+aword*5] //<-- rsp after register saves. -|.define ARG5, aword [rsp+aword*4] -|.define CSAVE_4, aword [rsp+aword*3] -|.define CSAVE_3, aword [rsp+aword*2] -|.define CSAVE_2, aword [rsp+aword*1] -|.define CSAVE_1, aword [rsp] //<-- rsp while in interpreter. -|//----- 16 byte aligned, ^^^ 32 byte register save area, owned by callee -| -|.define ARG5d, dword [rsp+dword*8] -|.define TMP1, ARG5 // TMP1 overlaps ARG5 -|.define TMP1d, ARG5d -|.define TMP1hi, dword [rsp+dword*9] -|.define MULTRES, TMP1d // MULTRES overlaps TMP1d. -| -|//----------------------------------------------------------------------- -|.else // x64/POSIX stack layout -| -|.define CFRAME_SPACE, aword*5 // Delta for rsp (see <--). -|.macro saveregs_ -| push rbx; push r15; push r14 -|.if NO_UNWIND -| push r13; push r12 -|.endif -| sub rsp, CFRAME_SPACE -|.endmacro -|.macro saveregs -| push rbp; saveregs_ -|.endmacro -|.macro restoreregs -| add rsp, CFRAME_SPACE -|.if NO_UNWIND -| pop r12; pop r13 -|.endif -| pop r14; pop r15; pop rbx; pop rbp -|.endmacro -| -|//----- 16 byte aligned, -|.if NO_UNWIND -|.define SAVE_RET, aword [rsp+aword*11] //<-- rsp entering interpreter. -|.define SAVE_R4, aword [rsp+aword*10] -|.define SAVE_R3, aword [rsp+aword*9] -|.define SAVE_R2, aword [rsp+aword*8] -|.define SAVE_R1, aword [rsp+aword*7] -|.define SAVE_RU2, aword [rsp+aword*6] -|.define SAVE_RU1, aword [rsp+aword*5] //<-- rsp after register saves. -|.else -|.define SAVE_RET, aword [rsp+aword*9] //<-- rsp entering interpreter. -|.define SAVE_R4, aword [rsp+aword*8] -|.define SAVE_R3, aword [rsp+aword*7] -|.define SAVE_R2, aword [rsp+aword*6] -|.define SAVE_R1, aword [rsp+aword*5] //<-- rsp after register saves. -|.endif -|.define SAVE_CFRAME, aword [rsp+aword*4] -|.define SAVE_PC, aword [rsp+aword*3] -|.define SAVE_L, aword [rsp+aword*2] -|.define SAVE_ERRF, dword [rsp+dword*3] -|.define SAVE_NRES, dword [rsp+dword*2] -|.define TMP1, aword [rsp] //<-- rsp while in interpreter. -|//----- 16 byte aligned -| -|.define TMP1d, dword [rsp] -|.define TMP1hi, dword [rsp+dword*1] -|.define MULTRES, TMP1d // MULTRES overlaps TMP1d. -| -|.endif -| -|//----------------------------------------------------------------------- -| -|// Instruction headers. -|.macro ins_A; .endmacro -|.macro ins_AD; .endmacro -|.macro ins_AJ; .endmacro -|.macro ins_ABC; movzx RBd, RCH; movzx RCd, RCL; .endmacro -|.macro ins_AB_; movzx RBd, RCH; .endmacro -|.macro ins_A_C; movzx RCd, RCL; .endmacro -|.macro ins_AND; not RD; .endmacro -| -|// Instruction decode+dispatch. Carefully tuned (nope, lodsd is not faster). -|.macro ins_NEXT -| mov RCd, [PC] -| movzx RAd, RCH -| movzx OP, RCL -| add PC, 4 -| shr RCd, 16 -| jmp aword [DISPATCH+OP*8] -|.endmacro -| -|// Instruction footer. -|.if 1 -| // Replicated dispatch. Less unpredictable branches, but higher I-Cache use. -| .define ins_next, ins_NEXT -| .define ins_next_, ins_NEXT -|.else -| // Common dispatch. Lower I-Cache use, only one (very) unpredictable branch. -| // Affects only certain kinds of benchmarks (and only with -j off). -| // Around 10%-30% slower on Core2, a lot more slower on P4. -| .macro ins_next -| jmp ->ins_next -| .endmacro -| .macro ins_next_ -| ->ins_next: -| ins_NEXT -| .endmacro -|.endif -| -|// Call decode and dispatch. -|.macro ins_callt -| // BASE = new base, RB = LFUNC, RD = nargs+1, [BASE-8] = PC -| mov PC, LFUNC:RB->pc -| mov RAd, [PC] -| movzx OP, RAL -| movzx RAd, RAH -| add PC, 4 -| jmp aword [DISPATCH+OP*8] -|.endmacro -| -|.macro ins_call -| // BASE = new base, RB = LFUNC, RD = nargs+1 -| mov [BASE-8], PC -| ins_callt -|.endmacro -| -|//----------------------------------------------------------------------- -| -|// Macros to clear or set tags. -|.macro cleartp, reg; shl reg, 17; shr reg, 17; .endmacro -|.macro settp, reg, tp -| mov64 ITYPE, ((uint64_t)tp<<47) -| or reg, ITYPE -|.endmacro -|.macro settp, dst, reg, tp -| mov64 dst, ((uint64_t)tp<<47) -| or dst, reg -|.endmacro -|.macro setint, reg -| settp reg, LJ_TISNUM -|.endmacro -|.macro setint, dst, reg -| settp dst, reg, LJ_TISNUM -|.endmacro -| -|// Macros to test operand types. -|.macro checktp_nc, reg, tp, target -| mov ITYPE, reg -| sar ITYPE, 47 -| cmp ITYPEd, tp -| jne target -|.endmacro -|.macro checktp, reg, tp, target -| mov ITYPE, reg -| cleartp reg -| sar ITYPE, 47 -| cmp ITYPEd, tp -| jne target -|.endmacro -|.macro checktptp, src, tp, target -| mov ITYPE, src -| sar ITYPE, 47 -| cmp ITYPEd, tp -| jne target -|.endmacro -|.macro checkstr, reg, target; checktp reg, LJ_TSTR, target; .endmacro -|.macro checktab, reg, target; checktp reg, LJ_TTAB, target; .endmacro -|.macro checkfunc, reg, target; checktp reg, LJ_TFUNC, target; .endmacro -| -|.macro checknumx, reg, target, jump -| mov ITYPE, reg -| sar ITYPE, 47 -| cmp ITYPEd, LJ_TISNUM -| jump target -|.endmacro -|.macro checkint, reg, target; checknumx reg, target, jne; .endmacro -|.macro checkinttp, src, target; checknumx src, target, jne; .endmacro -|.macro checknum, reg, target; checknumx reg, target, jae; .endmacro -|.macro checknumtp, src, target; checknumx src, target, jae; .endmacro -|.macro checknumber, src, target; checknumx src, target, ja; .endmacro -| -|.macro mov_false, reg; mov64 reg, (int64_t)~((uint64_t)1<<47); .endmacro -|.macro mov_true, reg; mov64 reg, (int64_t)~((uint64_t)2<<47); .endmacro -| -|// These operands must be used with movzx. -|.define PC_OP, byte [PC-4] -|.define PC_RA, byte [PC-3] -|.define PC_RB, byte [PC-1] -|.define PC_RC, byte [PC-2] -|.define PC_RD, word [PC-2] -| -|.macro branchPC, reg -| lea PC, [PC+reg*4-BCBIAS_J*4] -|.endmacro -| -|// Assumes DISPATCH is relative to GL. -#define DISPATCH_GL(field) (GG_DISP2G + (int)offsetof(global_State, field)) -#define DISPATCH_J(field) (GG_DISP2J + (int)offsetof(jit_State, field)) -| -#define PC2PROTO(field) ((int)offsetof(GCproto, field)-(int)sizeof(GCproto)) -| -|// Decrement hashed hotcount and trigger trace recorder if zero. -|.macro hotloop, reg -| mov reg, PCd -| shr reg, 1 -| and reg, HOTCOUNT_PCMASK -| sub word [DISPATCH+reg+GG_DISP2HOT], HOTCOUNT_LOOP -| jb ->vm_hotloop -|.endmacro -| -|.macro hotcall, reg -| mov reg, PCd -| shr reg, 1 -| and reg, HOTCOUNT_PCMASK -| sub word [DISPATCH+reg+GG_DISP2HOT], HOTCOUNT_CALL -| jb ->vm_hotcall -|.endmacro -| -|// Set current VM state. -|.macro set_vmstate, st -| mov dword [DISPATCH+DISPATCH_GL(vmstate)], ~LJ_VMST_..st -|.endmacro -| -|.macro fpop1; fstp st1; .endmacro -| -|// Synthesize SSE FP constants. -|.macro sseconst_abs, reg, tmp // Synthesize abs mask. -| mov64 tmp, U64x(7fffffff,ffffffff); movd reg, tmp -|.endmacro -| -|.macro sseconst_hi, reg, tmp, val // Synthesize hi-32 bit const. -| mov64 tmp, U64x(val,00000000); movd reg, tmp -|.endmacro -| -|.macro sseconst_sign, reg, tmp // Synthesize sign mask. -| sseconst_hi reg, tmp, 80000000 -|.endmacro -|.macro sseconst_1, reg, tmp // Synthesize 1.0. -| sseconst_hi reg, tmp, 3ff00000 -|.endmacro -|.macro sseconst_m1, reg, tmp // Synthesize -1.0. -| sseconst_hi reg, tmp, bff00000 -|.endmacro -|.macro sseconst_2p52, reg, tmp // Synthesize 2^52. -| sseconst_hi reg, tmp, 43300000 -|.endmacro -|.macro sseconst_tobit, reg, tmp // Synthesize 2^52 + 2^51. -| sseconst_hi reg, tmp, 43380000 -|.endmacro -| -|// Move table write barrier back. Overwrites reg. -|.macro barrierback, tab, reg -| and byte tab->marked, (uint8_t)~LJ_GC_BLACK // black2gray(tab) -| mov reg, [DISPATCH+DISPATCH_GL(gc.grayagain)] -| mov [DISPATCH+DISPATCH_GL(gc.grayagain)], tab -| mov tab->gclist, reg -|.endmacro -| -|//----------------------------------------------------------------------- - -/* Generate subroutines used by opcodes and other parts of the VM. */ -/* The .code_sub section should be last to help static branch prediction. */ -static void build_subroutines(BuildCtx *ctx) -{ - |.code_sub - | - |//----------------------------------------------------------------------- - |//-- Return handling ---------------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_returnp: - | test PCd, FRAME_P - | jz ->cont_dispatch - | - | // Return from pcall or xpcall fast func. - | and PC, -8 - | sub BASE, PC // Restore caller base. - | lea RA, [RA+PC-8] // Rebase RA and prepend one result. - | mov PC, [BASE-8] // Fetch PC of previous frame. - | // Prepending may overwrite the pcall frame, so do it at the end. - | mov_true ITYPE - | mov aword [BASE+RA], ITYPE // Prepend true to results. - | - |->vm_returnc: - | add RDd, 1 // RD = nresults+1 - | jz ->vm_unwind_yield - | mov MULTRES, RDd - | test PC, FRAME_TYPE - | jz ->BC_RET_Z // Handle regular return to Lua. - | - |->vm_return: - | // BASE = base, RA = resultofs, RD = nresults+1 (= MULTRES), PC = return - | xor PC, FRAME_C - | test PCd, FRAME_TYPE - | jnz ->vm_returnp - | - | // Return to C. - | set_vmstate C - | and PC, -8 - | sub PC, BASE - | neg PC // Previous base = BASE - delta. - | - | sub RDd, 1 - | jz >2 - |1: // Move results down. - | mov RB, [BASE+RA] - | mov [BASE-16], RB - | add BASE, 8 - | sub RDd, 1 - | jnz <1 - |2: - | mov L:RB, SAVE_L - | mov L:RB->base, PC - |3: - | mov RDd, MULTRES - | mov RAd, SAVE_NRES // RA = wanted nresults+1 - |4: - | cmp RAd, RDd - | jne >6 // More/less results wanted? - |5: - | sub BASE, 16 - | mov L:RB->top, BASE - | - |->vm_leave_cp: - | mov RA, SAVE_CFRAME // Restore previous C frame. - | mov L:RB->cframe, RA - | xor eax, eax // Ok return status for vm_pcall. - | - |->vm_leave_unw: - | restoreregs - | ret - | - |6: - | jb >7 // Less results wanted? - | // More results wanted. Check stack size and fill up results with nil. - | cmp BASE, L:RB->maxstack - | ja >8 - | mov aword [BASE-16], LJ_TNIL - | add BASE, 8 - | add RDd, 1 - | jmp <4 - | - |7: // Less results wanted. - | test RAd, RAd - | jz <5 // But check for LUA_MULTRET+1. - | sub RA, RD // Negative result! - | lea BASE, [BASE+RA*8] // Correct top. - | jmp <5 - | - |8: // Corner case: need to grow stack for filling up results. - | // This can happen if: - | // - A C function grows the stack (a lot). - | // - The GC shrinks the stack in between. - | // - A return back from a lua_call() with (high) nresults adjustment. - | mov L:RB->top, BASE // Save current top held in BASE (yes). - | mov MULTRES, RDd // Need to fill only remainder with nil. - | mov CARG2d, RAd - | mov CARG1, L:RB - | call extern lj_state_growstack // (lua_State *L, int n) - | mov BASE, L:RB->top // Need the (realloced) L->top in BASE. - | jmp <3 - | - |->vm_unwind_yield: - | mov al, LUA_YIELD - | jmp ->vm_unwind_c_eh - | - |->vm_unwind_c: // Unwind C stack, return from vm_pcall. - | // (void *cframe, int errcode) - | mov eax, CARG2d // Error return status for vm_pcall. - | mov rsp, CARG1 - |->vm_unwind_c_eh: // Landing pad for external unwinder. - | mov L:RB, SAVE_L - | mov GL:RB, L:RB->glref - | mov dword GL:RB->vmstate, ~LJ_VMST_C - | jmp ->vm_leave_unw - | - |->vm_unwind_rethrow: - |.if not X64WIN - | mov CARG1, SAVE_L - | mov CARG2d, eax - | restoreregs - | jmp extern lj_err_throw // (lua_State *L, int errcode) - |.endif - | - |->vm_unwind_ff: // Unwind C stack, return from ff pcall. - | // (void *cframe) - | and CARG1, CFRAME_RAWMASK - | mov rsp, CARG1 - |->vm_unwind_ff_eh: // Landing pad for external unwinder. - | mov L:RB, SAVE_L - | mov RDd, 1+1 // Really 1+2 results, incr. later. - | mov BASE, L:RB->base - | mov DISPATCH, L:RB->glref // Setup pointer to dispatch table. - | add DISPATCH, GG_G2DISP - | mov PC, [BASE-8] // Fetch PC of previous frame. - | mov_false RA - | mov RB, [BASE] - | mov [BASE-16], RA // Prepend false to error message. - | mov [BASE-8], RB - | mov RA, -16 // Results start at BASE+RA = BASE-16. - | set_vmstate INTERP - | jmp ->vm_returnc // Increments RD/MULTRES and returns. - | - |//----------------------------------------------------------------------- - |//-- Grow stack for calls ----------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_growstack_c: // Grow stack for C function. - | mov CARG2d, LUA_MINSTACK - | jmp >2 - | - |->vm_growstack_v: // Grow stack for vararg Lua function. - | sub RD, 16 // LJ_FR2 - | jmp >1 - | - |->vm_growstack_f: // Grow stack for fixarg Lua function. - | // BASE = new base, RD = nargs+1, RB = L, PC = first PC - | lea RD, [BASE+NARGS:RD*8-8] - |1: - | movzx RAd, byte [PC-4+PC2PROTO(framesize)] - | add PC, 4 // Must point after first instruction. - | mov L:RB->base, BASE - | mov L:RB->top, RD - | mov SAVE_PC, PC - | mov CARG2, RA - |2: - | // RB = L, L->base = new base, L->top = top - | mov CARG1, L:RB - | call extern lj_state_growstack // (lua_State *L, int n) - | mov BASE, L:RB->base - | mov RD, L:RB->top - | mov LFUNC:RB, [BASE-16] - | cleartp LFUNC:RB - | sub RD, BASE - | shr RDd, 3 - | add NARGS:RDd, 1 - | // BASE = new base, RB = LFUNC, RD = nargs+1 - | ins_callt // Just retry the call. - | - |//----------------------------------------------------------------------- - |//-- Entry points into the assembler VM --------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_resume: // Setup C frame and resume thread. - | // (lua_State *L, TValue *base, int nres1 = 0, ptrdiff_t ef = 0) - | saveregs - | mov L:RB, CARG1 // Caveat: CARG1 may be RA. - | mov SAVE_L, CARG1 - | mov RA, CARG2 - | mov PCd, FRAME_CP - | xor RDd, RDd - | lea KBASE, [esp+CFRAME_RESUME] - | mov DISPATCH, L:RB->glref // Setup pointer to dispatch table. - | add DISPATCH, GG_G2DISP - | mov SAVE_PC, RD // Any value outside of bytecode is ok. - | mov SAVE_CFRAME, RD - | mov SAVE_NRES, RDd - | mov SAVE_ERRF, RDd - | mov L:RB->cframe, KBASE - | cmp byte L:RB->status, RDL - | je >2 // Initial resume (like a call). - | - | // Resume after yield (like a return). - | mov [DISPATCH+DISPATCH_GL(cur_L)], L:RB - | set_vmstate INTERP - | mov byte L:RB->status, RDL - | mov BASE, L:RB->base - | mov RD, L:RB->top - | sub RD, RA - | shr RDd, 3 - | add RDd, 1 // RD = nresults+1 - | sub RA, BASE // RA = resultofs - | mov PC, [BASE-8] - | mov MULTRES, RDd - | test PCd, FRAME_TYPE - | jz ->BC_RET_Z - | jmp ->vm_return - | - |->vm_pcall: // Setup protected C frame and enter VM. - | // (lua_State *L, TValue *base, int nres1, ptrdiff_t ef) - | saveregs - | mov PCd, FRAME_CP - | mov SAVE_ERRF, CARG4d - | jmp >1 - | - |->vm_call: // Setup C frame and enter VM. - | // (lua_State *L, TValue *base, int nres1) - | saveregs - | mov PCd, FRAME_C - | - |1: // Entry point for vm_pcall above (PC = ftype). - | mov SAVE_NRES, CARG3d - | mov L:RB, CARG1 // Caveat: CARG1 may be RA. - | mov SAVE_L, CARG1 - | mov RA, CARG2 - | - | mov DISPATCH, L:RB->glref // Setup pointer to dispatch table. - | mov KBASE, L:RB->cframe // Add our C frame to cframe chain. - | mov SAVE_CFRAME, KBASE - | mov SAVE_PC, L:RB // Any value outside of bytecode is ok. - | add DISPATCH, GG_G2DISP - | mov L:RB->cframe, rsp - | - |2: // Entry point for vm_resume/vm_cpcall (RA = base, RB = L, PC = ftype). - | mov [DISPATCH+DISPATCH_GL(cur_L)], L:RB - | set_vmstate INTERP - | mov BASE, L:RB->base // BASE = old base (used in vmeta_call). - | add PC, RA - | sub PC, BASE // PC = frame delta + frame type - | - | mov RD, L:RB->top - | sub RD, RA - | shr NARGS:RDd, 3 - | add NARGS:RDd, 1 // RD = nargs+1 - | - |->vm_call_dispatch: - | mov LFUNC:RB, [RA-16] - | checkfunc LFUNC:RB, ->vmeta_call // Ensure KBASE defined and != BASE. - | - |->vm_call_dispatch_f: - | mov BASE, RA - | ins_call - | // BASE = new base, RB = func, RD = nargs+1, PC = caller PC - | - |->vm_cpcall: // Setup protected C frame, call C. - | // (lua_State *L, lua_CFunction func, void *ud, lua_CPFunction cp) - | saveregs - | mov L:RB, CARG1 // Caveat: CARG1 may be RA. - | mov SAVE_L, CARG1 - | mov SAVE_PC, L:RB // Any value outside of bytecode is ok. - | - | mov KBASE, L:RB->stack // Compute -savestack(L, L->top). - | sub KBASE, L:RB->top - | mov DISPATCH, L:RB->glref // Setup pointer to dispatch table. - | mov SAVE_ERRF, 0 // No error function. - | mov SAVE_NRES, KBASEd // Neg. delta means cframe w/o frame. - | add DISPATCH, GG_G2DISP - | // Handler may change cframe_nres(L->cframe) or cframe_errfunc(L->cframe). - | - | mov KBASE, L:RB->cframe // Add our C frame to cframe chain. - | mov SAVE_CFRAME, KBASE - | mov L:RB->cframe, rsp - | mov [DISPATCH+DISPATCH_GL(cur_L)], L:RB - | - | call CARG4 // (lua_State *L, lua_CFunction func, void *ud) - | // TValue * (new base) or NULL returned in eax (RC). - | test RC, RC - | jz ->vm_leave_cp // No base? Just remove C frame. - | mov RA, RC - | mov PCd, FRAME_CP - | jmp <2 // Else continue with the call. - | - |//----------------------------------------------------------------------- - |//-- Metamethod handling ------------------------------------------------ - |//----------------------------------------------------------------------- - | - |//-- Continuation dispatch ---------------------------------------------- - | - |->cont_dispatch: - | // BASE = meta base, RA = resultofs, RD = nresults+1 (also in MULTRES) - | add RA, BASE - | and PC, -8 - | mov RB, BASE - | sub BASE, PC // Restore caller BASE. - | mov aword [RA+RD*8-8], LJ_TNIL // Ensure one valid arg. - | mov RC, RA // ... in [RC] - | mov PC, [RB-24] // Restore PC from [cont|PC]. - | mov RA, qword [RB-32] // May be negative on WIN64 with debug. - |.if FFI - | cmp RA, 1 - | jbe >1 - |.endif - | mov LFUNC:KBASE, [BASE-16] - | cleartp LFUNC:KBASE - | mov KBASE, LFUNC:KBASE->pc - | mov KBASE, [KBASE+PC2PROTO(k)] - | // BASE = base, RC = result, RB = meta base - | jmp RA // Jump to continuation. - | - |.if FFI - |1: - | je ->cont_ffi_callback // cont = 1: return from FFI callback. - | // cont = 0: Tail call from C function. - | sub RB, BASE - | shr RBd, 3 - | lea RDd, [RBd-3] - | jmp ->vm_call_tail - |.endif - | - |->cont_cat: // BASE = base, RC = result, RB = mbase - | movzx RAd, PC_RB - | sub RB, 32 - | lea RA, [BASE+RA*8] - | sub RA, RB - | je ->cont_ra - | neg RA - | shr RAd, 3 - |.if X64WIN - | mov CARG3d, RAd - | mov L:CARG1, SAVE_L - | mov L:CARG1->base, BASE - | mov RC, [RC] - | mov [RB], RC - | mov CARG2, RB - |.else - | mov L:CARG1, SAVE_L - | mov L:CARG1->base, BASE - | mov CARG3d, RAd - | mov RA, [RC] - | mov [RB], RA - | mov CARG2, RB - |.endif - | jmp ->BC_CAT_Z - | - |//-- Table indexing metamethods ----------------------------------------- - | - |->vmeta_tgets: - | settp STR:RC, LJ_TSTR // STR:RC = GCstr * - | mov TMP1, STR:RC - | lea RC, TMP1 - | cmp PC_OP, BC_GGET - | jne >1 - | settp TAB:RA, TAB:RB, LJ_TTAB // TAB:RB = GCtab * - | lea RB, [DISPATCH+DISPATCH_GL(tmptv)] // Store fn->l.env in g->tmptv. - | mov [RB], TAB:RA - | jmp >2 - | - |->vmeta_tgetb: - | movzx RCd, PC_RC - |.if DUALNUM - | setint RC - | mov TMP1, RC - |.else - | cvtsi2sd xmm0, RCd - | movsd TMP1, xmm0 - |.endif - | lea RC, TMP1 - | jmp >1 - | - |->vmeta_tgetv: - | movzx RCd, PC_RC // Reload TValue *k from RC. - | lea RC, [BASE+RC*8] - |1: - | movzx RBd, PC_RB // Reload TValue *t from RB. - | lea RB, [BASE+RB*8] - |2: - | mov L:CARG1, SAVE_L - | mov L:CARG1->base, BASE // Caveat: CARG2/CARG3 may be BASE. - | mov CARG2, RB - | mov CARG3, RC - | mov L:RB, L:CARG1 - | mov SAVE_PC, PC - | call extern lj_meta_tget // (lua_State *L, TValue *o, TValue *k) - | // TValue * (finished) or NULL (metamethod) returned in eax (RC). - | mov BASE, L:RB->base - | test RC, RC - | jz >3 - |->cont_ra: // BASE = base, RC = result - | movzx RAd, PC_RA - | mov RB, [RC] - | mov [BASE+RA*8], RB - | ins_next - | - |3: // Call __index metamethod. - | // BASE = base, L->top = new base, stack = cont/func/t/k - | mov RA, L:RB->top - | mov [RA-24], PC // [cont|PC] - | lea PC, [RA+FRAME_CONT] - | sub PC, BASE - | mov LFUNC:RB, [RA-16] // Guaranteed to be a function here. - | mov NARGS:RDd, 2+1 // 2 args for func(t, k). - | cleartp LFUNC:RB - | jmp ->vm_call_dispatch_f - | - |->vmeta_tgetr: - | mov CARG1, TAB:RB - | mov RB, BASE // Save BASE. - | mov CARG2d, RCd // Caveat: CARG2 == BASE - | call extern lj_tab_getinth // (GCtab *t, int32_t key) - | // cTValue * or NULL returned in eax (RC). - | movzx RAd, PC_RA - | mov BASE, RB // Restore BASE. - | test RC, RC - | jnz ->BC_TGETR_Z - | mov ITYPE, LJ_TNIL - | jmp ->BC_TGETR2_Z - | - |//----------------------------------------------------------------------- - | - |->vmeta_tsets: - | settp STR:RC, LJ_TSTR // STR:RC = GCstr * - | mov TMP1, STR:RC - | lea RC, TMP1 - | cmp PC_OP, BC_GSET - | jne >1 - | settp TAB:RA, TAB:RB, LJ_TTAB // TAB:RB = GCtab * - | lea RB, [DISPATCH+DISPATCH_GL(tmptv)] // Store fn->l.env in g->tmptv. - | mov [RB], TAB:RA - | jmp >2 - | - |->vmeta_tsetb: - | movzx RCd, PC_RC - |.if DUALNUM - | setint RC - | mov TMP1, RC - |.else - | cvtsi2sd xmm0, RCd - | movsd TMP1, xmm0 - |.endif - | lea RC, TMP1 - | jmp >1 - | - |->vmeta_tsetv: - | movzx RCd, PC_RC // Reload TValue *k from RC. - | lea RC, [BASE+RC*8] - |1: - | movzx RBd, PC_RB // Reload TValue *t from RB. - | lea RB, [BASE+RB*8] - |2: - | mov L:CARG1, SAVE_L - | mov L:CARG1->base, BASE // Caveat: CARG2/CARG3 may be BASE. - | mov CARG2, RB - | mov CARG3, RC - | mov L:RB, L:CARG1 - | mov SAVE_PC, PC - | call extern lj_meta_tset // (lua_State *L, TValue *o, TValue *k) - | // TValue * (finished) or NULL (metamethod) returned in eax (RC). - | mov BASE, L:RB->base - | test RC, RC - | jz >3 - | // NOBARRIER: lj_meta_tset ensures the table is not black. - | movzx RAd, PC_RA - | mov RB, [BASE+RA*8] - | mov [RC], RB - |->cont_nop: // BASE = base, (RC = result) - | ins_next - | - |3: // Call __newindex metamethod. - | // BASE = base, L->top = new base, stack = cont/func/t/k/(v) - | mov RA, L:RB->top - | mov [RA-24], PC // [cont|PC] - | movzx RCd, PC_RA - | // Copy value to third argument. - | mov RB, [BASE+RC*8] - | mov [RA+16], RB - | lea PC, [RA+FRAME_CONT] - | sub PC, BASE - | mov LFUNC:RB, [RA-16] // Guaranteed to be a function here. - | mov NARGS:RDd, 3+1 // 3 args for func(t, k, v). - | cleartp LFUNC:RB - | jmp ->vm_call_dispatch_f - | - |->vmeta_tsetr: - |.if X64WIN - | mov L:CARG1, SAVE_L - | mov CARG3d, RCd - | mov L:CARG1->base, BASE - | xchg CARG2, TAB:RB // Caveat: CARG2 == BASE. - |.else - | mov L:CARG1, SAVE_L - | mov CARG2, TAB:RB - | mov L:CARG1->base, BASE - | mov RB, BASE // Save BASE. - | mov CARG3d, RCd // Caveat: CARG3 == BASE. - |.endif - | mov SAVE_PC, PC - | call extern lj_tab_setinth // (lua_State *L, GCtab *t, int32_t key) - | // TValue * returned in eax (RC). - | movzx RAd, PC_RA - | mov BASE, RB // Restore BASE. - | jmp ->BC_TSETR_Z - | - |//-- Comparison metamethods --------------------------------------------- - | - |->vmeta_comp: - | movzx RDd, PC_RD - | movzx RAd, PC_RA - | mov L:RB, SAVE_L - | mov L:RB->base, BASE // Caveat: CARG2/CARG3 == BASE. - |.if X64WIN - | lea CARG3, [BASE+RD*8] - | lea CARG2, [BASE+RA*8] - |.else - | lea CARG2, [BASE+RA*8] - | lea CARG3, [BASE+RD*8] - |.endif - | mov CARG1, L:RB // Caveat: CARG1/CARG4 == RA. - | movzx CARG4d, PC_OP - | mov SAVE_PC, PC - | call extern lj_meta_comp // (lua_State *L, TValue *o1, *o2, int op) - | // 0/1 or TValue * (metamethod) returned in eax (RC). - |3: - | mov BASE, L:RB->base - | cmp RC, 1 - | ja ->vmeta_binop - |4: - | lea PC, [PC+4] - | jb >6 - |5: - | movzx RDd, PC_RD - | branchPC RD - |6: - | ins_next - | - |->cont_condt: // BASE = base, RC = result - | add PC, 4 - | mov ITYPE, [RC] - | sar ITYPE, 47 - | cmp ITYPEd, LJ_TISTRUECOND // Branch if result is true. - | jb <5 - | jmp <6 - | - |->cont_condf: // BASE = base, RC = result - | mov ITYPE, [RC] - | sar ITYPE, 47 - | cmp ITYPEd, LJ_TISTRUECOND // Branch if result is false. - | jmp <4 - | - |->vmeta_equal: - | cleartp TAB:RD - | sub PC, 4 - |.if X64WIN - | mov CARG3, RD - | mov CARG4d, RBd - | mov L:RB, SAVE_L - | mov L:RB->base, BASE // Caveat: CARG2 == BASE. - | mov CARG2, RA - | mov CARG1, L:RB // Caveat: CARG1 == RA. - |.else - | mov CARG2, RA - | mov CARG4d, RBd // Caveat: CARG4 == RA. - | mov L:RB, SAVE_L - | mov L:RB->base, BASE // Caveat: CARG3 == BASE. - | mov CARG3, RD - | mov CARG1, L:RB - |.endif - | mov SAVE_PC, PC - | call extern lj_meta_equal // (lua_State *L, GCobj *o1, *o2, int ne) - | // 0/1 or TValue * (metamethod) returned in eax (RC). - | jmp <3 - | - |->vmeta_equal_cd: - |.if FFI - | sub PC, 4 - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - | mov CARG1, L:RB - | mov CARG2d, dword [PC-4] - | mov SAVE_PC, PC - | call extern lj_meta_equal_cd // (lua_State *L, BCIns ins) - | // 0/1 or TValue * (metamethod) returned in eax (RC). - | jmp <3 - |.endif - | - |->vmeta_istype: - | mov L:RB, SAVE_L - | mov L:RB->base, BASE // Caveat: CARG2/CARG3 may be BASE. - | mov CARG2d, RAd - | mov CARG3d, RDd - | mov L:CARG1, L:RB - | mov SAVE_PC, PC - | call extern lj_meta_istype // (lua_State *L, BCReg ra, BCReg tp) - | mov BASE, L:RB->base - | jmp <6 - | - |//-- Arithmetic metamethods --------------------------------------------- - | - |->vmeta_arith_vno: - |.if DUALNUM - | movzx RBd, PC_RB - | movzx RCd, PC_RC - |.endif - |->vmeta_arith_vn: - | lea RC, [KBASE+RC*8] - | jmp >1 - | - |->vmeta_arith_nvo: - |.if DUALNUM - | movzx RBd, PC_RB - | movzx RCd, PC_RC - |.endif - |->vmeta_arith_nv: - | lea TMPR, [KBASE+RC*8] - | lea RC, [BASE+RB*8] - | mov RB, TMPR - | jmp >2 - | - |->vmeta_unm: - | lea RC, [BASE+RD*8] - | mov RB, RC - | jmp >2 - | - |->vmeta_arith_vvo: - |.if DUALNUM - | movzx RBd, PC_RB - | movzx RCd, PC_RC - |.endif - |->vmeta_arith_vv: - | lea RC, [BASE+RC*8] - |1: - | lea RB, [BASE+RB*8] - |2: - | lea RA, [BASE+RA*8] - |.if X64WIN - | mov CARG3, RB - | mov CARG4, RC - | movzx RCd, PC_OP - | mov ARG5d, RCd - | mov L:RB, SAVE_L - | mov L:RB->base, BASE // Caveat: CARG2 == BASE. - | mov CARG2, RA - | mov CARG1, L:RB // Caveat: CARG1 == RA. - |.else - | movzx CARG5d, PC_OP - | mov CARG2, RA - | mov CARG4, RC // Caveat: CARG4 == RA. - | mov L:CARG1, SAVE_L - | mov L:CARG1->base, BASE // Caveat: CARG3 == BASE. - | mov CARG3, RB - | mov L:RB, L:CARG1 - |.endif - | mov SAVE_PC, PC - | call extern lj_meta_arith // (lua_State *L, TValue *ra,*rb,*rc, BCReg op) - | // NULL (finished) or TValue * (metamethod) returned in eax (RC). - | mov BASE, L:RB->base - | test RC, RC - | jz ->cont_nop - | - | // Call metamethod for binary op. - |->vmeta_binop: - | // BASE = base, RC = new base, stack = cont/func/o1/o2 - | mov RA, RC - | sub RC, BASE - | mov [RA-24], PC // [cont|PC] - | lea PC, [RC+FRAME_CONT] - | mov NARGS:RDd, 2+1 // 2 args for func(o1, o2). - | jmp ->vm_call_dispatch - | - |->vmeta_len: - | movzx RDd, PC_RD - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - | lea CARG2, [BASE+RD*8] // Caveat: CARG2 == BASE - | mov L:CARG1, L:RB - | mov SAVE_PC, PC - | call extern lj_meta_len // (lua_State *L, TValue *o) - | // NULL (retry) or TValue * (metamethod) returned in eax (RC). - | mov BASE, L:RB->base -#if LJ_52 - | test RC, RC - | jne ->vmeta_binop // Binop call for compatibility. - | movzx RDd, PC_RD - | mov TAB:CARG1, [BASE+RD*8] - | cleartp TAB:CARG1 - | jmp ->BC_LEN_Z -#else - | jmp ->vmeta_binop // Binop call for compatibility. -#endif - | - |//-- Call metamethod ---------------------------------------------------- - | - |->vmeta_call_ra: - | lea RA, [BASE+RA*8+16] - |->vmeta_call: // Resolve and call __call metamethod. - | // BASE = old base, RA = new base, RC = nargs+1, PC = return - | mov TMP1d, NARGS:RDd // Save RA, RC for us. - | mov RB, RA - |.if X64WIN - | mov L:TMPR, SAVE_L - | mov L:TMPR->base, BASE // Caveat: CARG2 is BASE. - | lea CARG2, [RA-16] - | lea CARG3, [RA+NARGS:RD*8-8] - | mov CARG1, L:TMPR // Caveat: CARG1 is RA. - |.else - | mov L:CARG1, SAVE_L - | mov L:CARG1->base, BASE // Caveat: CARG3 is BASE. - | lea CARG2, [RA-16] - | lea CARG3, [RA+NARGS:RD*8-8] - |.endif - | mov SAVE_PC, PC - | call extern lj_meta_call // (lua_State *L, TValue *func, TValue *top) - | mov RA, RB - | mov L:RB, SAVE_L - | mov BASE, L:RB->base - | mov NARGS:RDd, TMP1d - | mov LFUNC:RB, [RA-16] - | add NARGS:RDd, 1 - | // This is fragile. L->base must not move, KBASE must always be defined. - | cmp KBASE, BASE // Continue with CALLT if flag set. - | je ->BC_CALLT_Z - | cleartp LFUNC:RB - | mov BASE, RA - | ins_call // Otherwise call resolved metamethod. - | - |//-- Argument coercion for 'for' statement ------------------------------ - | - |->vmeta_for: - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - | mov CARG2, RA // Caveat: CARG2 == BASE - | mov L:CARG1, L:RB // Caveat: CARG1 == RA - | mov SAVE_PC, PC - | call extern lj_meta_for // (lua_State *L, TValue *base) - | mov BASE, L:RB->base - | mov RCd, [PC-4] - | movzx RAd, RCH - | movzx OP, RCL - | shr RCd, 16 - | jmp aword [DISPATCH+OP*8+GG_DISP2STATIC] // Retry FORI or JFORI. - | - |//----------------------------------------------------------------------- - |//-- Fast functions ----------------------------------------------------- - |//----------------------------------------------------------------------- - | - |.macro .ffunc, name - |->ff_ .. name: - |.endmacro - | - |.macro .ffunc_1, name - |->ff_ .. name: - | cmp NARGS:RDd, 1+1; jb ->fff_fallback - |.endmacro - | - |.macro .ffunc_2, name - |->ff_ .. name: - | cmp NARGS:RDd, 2+1; jb ->fff_fallback - |.endmacro - | - |.macro .ffunc_n, name, op - | .ffunc_1 name - | checknumtp [BASE], ->fff_fallback - | op xmm0, qword [BASE] - |.endmacro - | - |.macro .ffunc_n, name - | .ffunc_n name, movsd - |.endmacro - | - |.macro .ffunc_nn, name - | .ffunc_2 name - | checknumtp [BASE], ->fff_fallback - | checknumtp [BASE+8], ->fff_fallback - | movsd xmm0, qword [BASE] - | movsd xmm1, qword [BASE+8] - |.endmacro - | - |// Inlined GC threshold check. Caveat: uses label 1. - |.macro ffgccheck - | mov RB, [DISPATCH+DISPATCH_GL(gc.total)] - | cmp RB, [DISPATCH+DISPATCH_GL(gc.threshold)] - | jb >1 - | call ->fff_gcstep - |1: - |.endmacro - | - |//-- Base library: checks ----------------------------------------------- - | - |.ffunc_1 assert - | mov ITYPE, [BASE] - | mov RB, ITYPE - | sar ITYPE, 47 - | cmp ITYPEd, LJ_TISTRUECOND; jae ->fff_fallback - | mov PC, [BASE-8] - | mov MULTRES, RDd - | mov RB, [BASE] - | mov [BASE-16], RB - | sub RDd, 2 - | jz >2 - | mov RA, BASE - |1: - | add RA, 8 - | mov RB, [RA] - | mov [RA-16], RB - | sub RDd, 1 - | jnz <1 - |2: - | mov RDd, MULTRES - | jmp ->fff_res_ - | - |.ffunc_1 type - | mov RC, [BASE] - | sar RC, 47 - | mov RBd, LJ_TISNUM - | cmp RCd, RBd - | cmovb RCd, RBd - | not RCd - |2: - | mov CFUNC:RB, [BASE-16] - | cleartp CFUNC:RB - | mov STR:RC, [CFUNC:RB+RC*8+((char *)(&((GCfuncC *)0)->upvalue))] - | mov PC, [BASE-8] - | settp STR:RC, LJ_TSTR - | mov [BASE-16], STR:RC - | jmp ->fff_res1 - | - |//-- Base library: getters and setters --------------------------------- - | - |.ffunc_1 getmetatable - | mov TAB:RB, [BASE] - | mov PC, [BASE-8] - | checktab TAB:RB, >6 - |1: // Field metatable must be at same offset for GCtab and GCudata! - | mov TAB:RB, TAB:RB->metatable - |2: - | test TAB:RB, TAB:RB - | mov aword [BASE-16], LJ_TNIL - | jz ->fff_res1 - | settp TAB:RC, TAB:RB, LJ_TTAB - | mov [BASE-16], TAB:RC // Store metatable as default result. - | mov STR:RC, [DISPATCH+DISPATCH_GL(gcroot)+8*(GCROOT_MMNAME+MM_metatable)] - | mov RAd, TAB:RB->hmask - | and RAd, STR:RC->hash - | settp STR:RC, LJ_TSTR - | imul RAd, #NODE - | add NODE:RA, TAB:RB->node - |3: // Rearranged logic, because we expect _not_ to find the key. - | cmp NODE:RA->key, STR:RC - | je >5 - |4: - | mov NODE:RA, NODE:RA->next - | test NODE:RA, NODE:RA - | jnz <3 - | jmp ->fff_res1 // Not found, keep default result. - |5: - | mov RB, NODE:RA->val - | cmp RB, LJ_TNIL; je ->fff_res1 // Ditto for nil value. - | mov [BASE-16], RB // Return value of mt.__metatable. - | jmp ->fff_res1 - | - |6: - | cmp ITYPEd, LJ_TUDATA; je <1 - | cmp ITYPEd, LJ_TISNUM; ja >7 - | mov ITYPEd, LJ_TISNUM - |7: - | not ITYPEd - | mov TAB:RB, [DISPATCH+ITYPE*8+DISPATCH_GL(gcroot[GCROOT_BASEMT])] - | jmp <2 - | - |.ffunc_2 setmetatable - | mov TAB:RB, [BASE] - | mov TAB:TMPR, TAB:RB - | checktab TAB:RB, ->fff_fallback - | // Fast path: no mt for table yet and not clearing the mt. - | cmp aword TAB:RB->metatable, 0; jne ->fff_fallback - | mov TAB:RA, [BASE+8] - | checktab TAB:RA, ->fff_fallback - | mov TAB:RB->metatable, TAB:RA - | mov PC, [BASE-8] - | mov [BASE-16], TAB:TMPR // Return original table. - | test byte TAB:RB->marked, LJ_GC_BLACK // isblack(table) - | jz >1 - | // Possible write barrier. Table is black, but skip iswhite(mt) check. - | barrierback TAB:RB, RC - |1: - | jmp ->fff_res1 - | - |.ffunc_2 rawget - |.if X64WIN - | mov TAB:RA, [BASE] - | checktab TAB:RA, ->fff_fallback - | mov RB, BASE // Save BASE. - | lea CARG3, [BASE+8] - | mov CARG2, TAB:RA // Caveat: CARG2 == BASE. - | mov CARG1, SAVE_L - |.else - | mov TAB:CARG2, [BASE] - | checktab TAB:CARG2, ->fff_fallback - | mov RB, BASE // Save BASE. - | lea CARG3, [BASE+8] // Caveat: CARG3 == BASE. - | mov CARG1, SAVE_L - |.endif - | call extern lj_tab_get // (lua_State *L, GCtab *t, cTValue *key) - | // cTValue * returned in eax (RD). - | mov BASE, RB // Restore BASE. - | // Copy table slot. - | mov RB, [RD] - | mov PC, [BASE-8] - | mov [BASE-16], RB - | jmp ->fff_res1 - | - |//-- Base library: conversions ------------------------------------------ - | - |.ffunc tonumber - | // Only handles the number case inline (without a base argument). - | cmp NARGS:RDd, 1+1; jne ->fff_fallback // Exactly one argument. - | mov RB, [BASE] - | checknumber RB, ->fff_fallback - | mov PC, [BASE-8] - | mov [BASE-16], RB - | jmp ->fff_res1 - | - |.ffunc_1 tostring - | // Only handles the string or number case inline. - | mov PC, [BASE-8] - | mov STR:RB, [BASE] - | checktp_nc STR:RB, LJ_TSTR, >3 - | // A __tostring method in the string base metatable is ignored. - |2: - | mov [BASE-16], STR:RB - | jmp ->fff_res1 - |3: // Handle numbers inline, unless a number base metatable is present. - | cmp ITYPEd, LJ_TISNUM; ja ->fff_fallback_1 - | cmp aword [DISPATCH+DISPATCH_GL(gcroot[GCROOT_BASEMT_NUM])], 0 - | jne ->fff_fallback - | ffgccheck // Caveat: uses label 1. - | mov L:RB, SAVE_L - | mov L:RB->base, BASE // Add frame since C call can throw. - | mov SAVE_PC, PC // Redundant (but a defined value). - |.if not X64WIN - | mov CARG2, BASE // Otherwise: CARG2 == BASE - |.endif - | mov L:CARG1, L:RB - |.if DUALNUM - | call extern lj_strfmt_number // (lua_State *L, cTValue *o) - |.else - | call extern lj_strfmt_num // (lua_State *L, lua_Number *np) - |.endif - | // GCstr returned in eax (RD). - | mov BASE, L:RB->base - | settp STR:RB, RD, LJ_TSTR - | jmp <2 - | - |//-- Base library: iterators ------------------------------------------- - | - |.ffunc_1 next - | je >2 // Missing 2nd arg? - |1: - |.if X64WIN - | mov RA, [BASE] - | checktab RA, ->fff_fallback - |.else - | mov CARG2, [BASE] - | checktab CARG2, ->fff_fallback - |.endif - | mov L:RB, SAVE_L - | mov L:RB->base, BASE // Add frame since C call can throw. - | mov L:RB->top, BASE // Dummy frame length is ok. - | mov PC, [BASE-8] - |.if X64WIN - | lea CARG3, [BASE+8] - | mov CARG2, RA // Caveat: CARG2 == BASE. - | mov CARG1, L:RB - |.else - | lea CARG3, [BASE+8] // Caveat: CARG3 == BASE. - | mov CARG1, L:RB - |.endif - | mov SAVE_PC, PC // Needed for ITERN fallback. - | call extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key) - | // Flag returned in eax (RD). - | mov BASE, L:RB->base - | test RDd, RDd; jz >3 // End of traversal? - | // Copy key and value to results. - | mov RB, [BASE+8] - | mov RD, [BASE+16] - | mov [BASE-16], RB - | mov [BASE-8], RD - |->fff_res2: - | mov RDd, 1+2 - | jmp ->fff_res - |2: // Set missing 2nd arg to nil. - | mov aword [BASE+8], LJ_TNIL - | jmp <1 - |3: // End of traversal: return nil. - | mov aword [BASE-16], LJ_TNIL - | jmp ->fff_res1 - | - |.ffunc_1 pairs - | mov TAB:RB, [BASE] - | mov TMPR, TAB:RB - | checktab TAB:RB, ->fff_fallback -#if LJ_52 - | cmp aword TAB:RB->metatable, 0; jne ->fff_fallback -#endif - | mov CFUNC:RD, [BASE-16] - | cleartp CFUNC:RD - | mov CFUNC:RD, CFUNC:RD->upvalue[0] - | settp CFUNC:RD, LJ_TFUNC - | mov PC, [BASE-8] - | mov [BASE-16], CFUNC:RD - | mov [BASE-8], TMPR - | mov aword [BASE], LJ_TNIL - | mov RDd, 1+3 - | jmp ->fff_res - | - |.ffunc_2 ipairs_aux - | mov TAB:RB, [BASE] - | checktab TAB:RB, ->fff_fallback - |.if DUALNUM - | mov RA, [BASE+8] - | checkint RA, ->fff_fallback - |.else - | checknumtp [BASE+8], ->fff_fallback - | movsd xmm0, qword [BASE+8] - |.endif - | mov PC, [BASE-8] - |.if DUALNUM - | add RAd, 1 - | setint ITYPE, RA - | mov [BASE-16], ITYPE - |.else - | sseconst_1 xmm1, TMPR - | addsd xmm0, xmm1 - | cvttsd2si RAd, xmm0 - | movsd qword [BASE-16], xmm0 - |.endif - | cmp RAd, TAB:RB->asize; jae >2 // Not in array part? - | mov RD, TAB:RB->array - | lea RD, [RD+RA*8] - |1: - | cmp aword [RD], LJ_TNIL; je ->fff_res0 - | // Copy array slot. - | mov RB, [RD] - | mov [BASE-8], RB - | jmp ->fff_res2 - |2: // Check for empty hash part first. Otherwise call C function. - | cmp dword TAB:RB->hmask, 0; je ->fff_res0 - |.if X64WIN - | mov TMPR, BASE - | mov CARG2d, RAd - | mov CARG1, TAB:RB - | mov RB, TMPR - |.else - | mov CARG1, TAB:RB - | mov RB, BASE // Save BASE. - | mov CARG2d, RAd // Caveat: CARG2 == BASE - |.endif - | call extern lj_tab_getinth // (GCtab *t, int32_t key) - | // cTValue * or NULL returned in eax (RD). - | mov BASE, RB - | test RD, RD - | jnz <1 - |->fff_res0: - | mov RDd, 1+0 - | jmp ->fff_res - | - |.ffunc_1 ipairs - | mov TAB:RB, [BASE] - | mov TMPR, TAB:RB - | checktab TAB:RB, ->fff_fallback -#if LJ_52 - | cmp aword TAB:RB->metatable, 0; jne ->fff_fallback -#endif - | mov CFUNC:RD, [BASE-16] - | cleartp CFUNC:RD - | mov CFUNC:RD, CFUNC:RD->upvalue[0] - | settp CFUNC:RD, LJ_TFUNC - | mov PC, [BASE-8] - | mov [BASE-16], CFUNC:RD - | mov [BASE-8], TMPR - |.if DUALNUM - | mov64 RD, ((uint64_t)LJ_TISNUM<<47) - | mov [BASE], RD - |.else - | mov qword [BASE], 0 - |.endif - | mov RDd, 1+3 - | jmp ->fff_res - | - |//-- Base library: catch errors ---------------------------------------- - | - |.ffunc_1 pcall - | lea RA, [BASE+16] - | sub NARGS:RDd, 1 - | mov PCd, 16+FRAME_PCALL - |1: - | movzx RBd, byte [DISPATCH+DISPATCH_GL(hookmask)] - | shr RB, HOOK_ACTIVE_SHIFT - | and RB, 1 - | add PC, RB // Remember active hook before pcall. - | // Note: this does a (harmless) copy of the function to the PC slot, too. - | mov KBASE, RD - |2: - | mov RB, [RA+KBASE*8-24] - | mov [RA+KBASE*8-16], RB - | sub KBASE, 1 - | ja <2 - | jmp ->vm_call_dispatch - | - |.ffunc_2 xpcall - | mov LFUNC:RA, [BASE+8] - | checktp_nc LFUNC:RA, LJ_TFUNC, ->fff_fallback - | mov LFUNC:RB, [BASE] // Swap function and traceback. - | mov [BASE], LFUNC:RA - | mov [BASE+8], LFUNC:RB - | lea RA, [BASE+24] - | sub NARGS:RDd, 2 - | mov PCd, 24+FRAME_PCALL - | jmp <1 - | - |//-- Coroutine library -------------------------------------------------- - | - |.macro coroutine_resume_wrap, resume - |.if resume - |.ffunc_1 coroutine_resume - | mov L:RB, [BASE] - | cleartp L:RB - |.else - |.ffunc coroutine_wrap_aux - | mov CFUNC:RB, [BASE-16] - | cleartp CFUNC:RB - | mov L:RB, CFUNC:RB->upvalue[0].gcr - | cleartp L:RB - |.endif - | mov PC, [BASE-8] - | mov SAVE_PC, PC - | mov TMP1, L:RB - |.if resume - | checktptp [BASE], LJ_TTHREAD, ->fff_fallback - |.endif - | cmp aword L:RB->cframe, 0; jne ->fff_fallback - | cmp byte L:RB->status, LUA_YIELD; ja ->fff_fallback - | mov RA, L:RB->top - | je >1 // Status != LUA_YIELD (i.e. 0)? - | cmp RA, L:RB->base // Check for presence of initial func. - | je ->fff_fallback - | mov PC, [RA-8] // Move initial function up. - | mov [RA], PC - | add RA, 8 - |1: - |.if resume - | lea PC, [RA+NARGS:RD*8-16] // Check stack space (-1-thread). - |.else - | lea PC, [RA+NARGS:RD*8-8] // Check stack space (-1). - |.endif - | cmp PC, L:RB->maxstack; ja ->fff_fallback - | mov L:RB->top, PC - | - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - |.if resume - | add BASE, 8 // Keep resumed thread in stack for GC. - |.endif - | mov L:RB->top, BASE - |.if resume - | lea RB, [BASE+NARGS:RD*8-24] // RB = end of source for stack move. - |.else - | lea RB, [BASE+NARGS:RD*8-16] // RB = end of source for stack move. - |.endif - | sub RB, PC // Relative to PC. - | - | cmp PC, RA - | je >3 - |2: // Move args to coroutine. - | mov RC, [PC+RB] - | mov [PC-8], RC - | sub PC, 8 - | cmp PC, RA - | jne <2 - |3: - | mov CARG2, RA - | mov CARG1, TMP1 - | call ->vm_resume // (lua_State *L, TValue *base, 0, 0) - | - | mov L:RB, SAVE_L - | mov L:PC, TMP1 - | mov BASE, L:RB->base - | mov [DISPATCH+DISPATCH_GL(cur_L)], L:RB - | set_vmstate INTERP - | - | cmp eax, LUA_YIELD - | ja >8 - |4: - | mov RA, L:PC->base - | mov KBASE, L:PC->top - | mov L:PC->top, RA // Clear coroutine stack. - | mov PC, KBASE - | sub PC, RA - | je >6 // No results? - | lea RD, [BASE+PC] - | shr PCd, 3 - | cmp RD, L:RB->maxstack - | ja >9 // Need to grow stack? - | - | mov RB, BASE - | sub RB, RA - |5: // Move results from coroutine. - | mov RD, [RA] - | mov [RA+RB], RD - | add RA, 8 - | cmp RA, KBASE - | jne <5 - |6: - |.if resume - | lea RDd, [PCd+2] // nresults+1 = 1 + true + results. - | mov_true ITYPE // Prepend true to results. - | mov [BASE-8], ITYPE - |.else - | lea RDd, [PCd+1] // nresults+1 = 1 + results. - |.endif - |7: - | mov PC, SAVE_PC - | mov MULTRES, RDd - |.if resume - | mov RA, -8 - |.else - | xor RAd, RAd - |.endif - | test PCd, FRAME_TYPE - | jz ->BC_RET_Z - | jmp ->vm_return - | - |8: // Coroutine returned with error (at co->top-1). - |.if resume - | mov_false ITYPE // Prepend false to results. - | mov [BASE-8], ITYPE - | mov RA, L:PC->top - | sub RA, 8 - | mov L:PC->top, RA // Clear error from coroutine stack. - | // Copy error message. - | mov RD, [RA] - | mov [BASE], RD - | mov RDd, 1+2 // nresults+1 = 1 + false + error. - | jmp <7 - |.else - | mov CARG2, L:PC - | mov CARG1, L:RB - | call extern lj_ffh_coroutine_wrap_err // (lua_State *L, lua_State *co) - | // Error function does not return. - |.endif - | - |9: // Handle stack expansion on return from yield. - | mov L:RA, TMP1 - | mov L:RA->top, KBASE // Undo coroutine stack clearing. - | mov CARG2, PC - | mov CARG1, L:RB - | call extern lj_state_growstack // (lua_State *L, int n) - | mov L:PC, TMP1 - | mov BASE, L:RB->base - | jmp <4 // Retry the stack move. - |.endmacro - | - | coroutine_resume_wrap 1 // coroutine.resume - | coroutine_resume_wrap 0 // coroutine.wrap - | - |.ffunc coroutine_yield - | mov L:RB, SAVE_L - | test aword L:RB->cframe, CFRAME_RESUME - | jz ->fff_fallback - | mov L:RB->base, BASE - | lea RD, [BASE+NARGS:RD*8-8] - | mov L:RB->top, RD - | xor RDd, RDd - | mov aword L:RB->cframe, RD - | mov al, LUA_YIELD - | mov byte L:RB->status, al - | jmp ->vm_leave_unw - | - |//-- Math library ------------------------------------------------------- - | - | .ffunc_1 math_abs - | mov RB, [BASE] - |.if DUALNUM - | checkint RB, >3 - | cmp RBd, 0; jns ->fff_resi - | neg RBd; js >2 - |->fff_resbit: - |->fff_resi: - | setint RB - |->fff_resRB: - | mov PC, [BASE-8] - | mov [BASE-16], RB - | jmp ->fff_res1 - |2: - | mov64 RB, U64x(41e00000,00000000) // 2^31. - | jmp ->fff_resRB - |3: - | ja ->fff_fallback - |.else - | checknum RB, ->fff_fallback - |.endif - | shl RB, 1 - | shr RB, 1 - | mov PC, [BASE-8] - | mov [BASE-16], RB - | jmp ->fff_res1 - | - |.ffunc_n math_sqrt, sqrtsd - |->fff_resxmm0: - | mov PC, [BASE-8] - | movsd qword [BASE-16], xmm0 - | // fallthrough - | - |->fff_res1: - | mov RDd, 1+1 - |->fff_res: - | mov MULTRES, RDd - |->fff_res_: - | test PCd, FRAME_TYPE - | jnz >7 - |5: - | cmp PC_RB, RDL // More results expected? - | ja >6 - | // Adjust BASE. KBASE is assumed to be set for the calling frame. - | movzx RAd, PC_RA - | neg RA - | lea BASE, [BASE+RA*8-16] // base = base - (RA+2)*8 - | ins_next - | - |6: // Fill up results with nil. - | mov aword [BASE+RD*8-24], LJ_TNIL - | add RD, 1 - | jmp <5 - | - |7: // Non-standard return case. - | mov RA, -16 // Results start at BASE+RA = BASE-16. - | jmp ->vm_return - | - |.macro math_round, func - | .ffunc math_ .. func - |.if DUALNUM - | mov RB, [BASE] - | checknumx RB, ->fff_resRB, je - | ja ->fff_fallback - |.else - | checknumtp [BASE], ->fff_fallback - |.endif - | movsd xmm0, qword [BASE] - | call ->vm_ .. func .. _sse - |.if DUALNUM - | cvttsd2si RBd, xmm0 - | cmp RBd, 0x80000000 - | jne ->fff_resi - | cvtsi2sd xmm1, RBd - | ucomisd xmm0, xmm1 - | jp ->fff_resxmm0 - | je ->fff_resi - |.endif - | jmp ->fff_resxmm0 - |.endmacro - | - | math_round floor - | math_round ceil - | - |.ffunc math_log - | cmp NARGS:RDd, 1+1; jne ->fff_fallback // Exactly one argument. - | checknumtp [BASE], ->fff_fallback - | movsd xmm0, qword [BASE] - | mov RB, BASE - | call extern log - | mov BASE, RB - | jmp ->fff_resxmm0 - | - |.macro math_extern, func - | .ffunc_n math_ .. func - | mov RB, BASE - | call extern func - | mov BASE, RB - | jmp ->fff_resxmm0 - |.endmacro - | - |.macro math_extern2, func - | .ffunc_nn math_ .. func - | mov RB, BASE - | call extern func - | mov BASE, RB - | jmp ->fff_resxmm0 - |.endmacro - | - | math_extern log10 - | math_extern exp - | math_extern sin - | math_extern cos - | math_extern tan - | math_extern asin - | math_extern acos - | math_extern atan - | math_extern sinh - | math_extern cosh - | math_extern tanh - | math_extern2 pow - | math_extern2 atan2 - | math_extern2 fmod - | - |.ffunc_2 math_ldexp - | checknumtp [BASE], ->fff_fallback - | checknumtp [BASE+8], ->fff_fallback - | fld qword [BASE+8] - | fld qword [BASE] - | fscale - | fpop1 - | mov PC, [BASE-8] - | fstp qword [BASE-16] - | jmp ->fff_res1 - | - |.ffunc_n math_frexp - | mov RB, BASE - |.if X64WIN - | lea CARG2, TMP1 // Caveat: CARG2 == BASE - |.else - | lea CARG1, TMP1 - |.endif - | call extern frexp - | mov BASE, RB - | mov RBd, TMP1d - | mov PC, [BASE-8] - | movsd qword [BASE-16], xmm0 - |.if DUALNUM - | setint RB - | mov [BASE-8], RB - |.else - | cvtsi2sd xmm1, RBd - | movsd qword [BASE-8], xmm1 - |.endif - | mov RDd, 1+2 - | jmp ->fff_res - | - |.ffunc_n math_modf - | mov RB, BASE - |.if X64WIN - | lea CARG2, [BASE-16] // Caveat: CARG2 == BASE - |.else - | lea CARG1, [BASE-16] - |.endif - | call extern modf - | mov BASE, RB - | mov PC, [BASE-8] - | movsd qword [BASE-8], xmm0 - | mov RDd, 1+2 - | jmp ->fff_res - | - |.macro math_minmax, name, cmovop, sseop - | .ffunc name - | mov RAd, 2 - |.if DUALNUM - | mov RB, [BASE] - | checkint RB, >4 - |1: // Handle integers. - | cmp RAd, RDd; jae ->fff_resRB - | mov TMPR, [BASE+RA*8-8] - | checkint TMPR, >3 - | cmp RBd, TMPRd - | cmovop RB, TMPR - | add RAd, 1 - | jmp <1 - |3: - | ja ->fff_fallback - | // Convert intermediate result to number and continue below. - | cvtsi2sd xmm0, RBd - | jmp >6 - |4: - | ja ->fff_fallback - |.else - | checknumtp [BASE], ->fff_fallback - |.endif - | - | movsd xmm0, qword [BASE] - |5: // Handle numbers or integers. - | cmp RAd, RDd; jae ->fff_resxmm0 - |.if DUALNUM - | mov RB, [BASE+RA*8-8] - | checknumx RB, >6, jb - | ja ->fff_fallback - | cvtsi2sd xmm1, RBd - | jmp >7 - |.else - | checknumtp [BASE+RA*8-8], ->fff_fallback - |.endif - |6: - | movsd xmm1, qword [BASE+RA*8-8] - |7: - | sseop xmm0, xmm1 - | add RAd, 1 - | jmp <5 - |.endmacro - | - | math_minmax math_min, cmovg, minsd - | math_minmax math_max, cmovl, maxsd - | - |//-- String library ----------------------------------------------------- - | - |.ffunc string_byte // Only handle the 1-arg case here. - | cmp NARGS:RDd, 1+1; jne ->fff_fallback - | mov STR:RB, [BASE] - | checkstr STR:RB, ->fff_fallback - | mov PC, [BASE-8] - | cmp dword STR:RB->len, 1 - | jb ->fff_res0 // Return no results for empty string. - | movzx RBd, byte STR:RB[1] - |.if DUALNUM - | jmp ->fff_resi - |.else - | cvtsi2sd xmm0, RBd; jmp ->fff_resxmm0 - |.endif - | - |.ffunc string_char // Only handle the 1-arg case here. - | ffgccheck - | cmp NARGS:RDd, 1+1; jne ->fff_fallback // *Exactly* 1 arg. - |.if DUALNUM - | mov RB, [BASE] - | checkint RB, ->fff_fallback - |.else - | checknumtp [BASE], ->fff_fallback - | cvttsd2si RBd, qword [BASE] - |.endif - | cmp RBd, 255; ja ->fff_fallback - | mov TMP1d, RBd - | mov TMPRd, 1 - | lea RD, TMP1 // Points to stack. Little-endian. - |->fff_newstr: - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - | mov CARG3d, TMPRd // Zero-extended to size_t. - | mov CARG2, RD - | mov CARG1, L:RB - | mov SAVE_PC, PC - | call extern lj_str_new // (lua_State *L, char *str, size_t l) - |->fff_resstr: - | // GCstr * returned in eax (RD). - | mov BASE, L:RB->base - | mov PC, [BASE-8] - | settp STR:RD, LJ_TSTR - | mov [BASE-16], STR:RD - | jmp ->fff_res1 - | - |.ffunc string_sub - | ffgccheck - | mov TMPRd, -1 - | cmp NARGS:RDd, 1+2; jb ->fff_fallback - | jna >1 - |.if DUALNUM - | mov TMPR, [BASE+16] - | checkint TMPR, ->fff_fallback - |.else - | checknumtp [BASE+16], ->fff_fallback - | cvttsd2si TMPRd, qword [BASE+16] - |.endif - |1: - | mov STR:RB, [BASE] - | checkstr STR:RB, ->fff_fallback - |.if DUALNUM - | mov ITYPE, [BASE+8] - | mov RAd, ITYPEd // Must clear hiword for lea below. - | sar ITYPE, 47 - | cmp ITYPEd, LJ_TISNUM - | jne ->fff_fallback - |.else - | checknumtp [BASE+8], ->fff_fallback - | cvttsd2si RAd, qword [BASE+8] - |.endif - | mov RCd, STR:RB->len - | cmp RCd, TMPRd // len < end? (unsigned compare) - | jb >5 - |2: - | test RAd, RAd // start <= 0? - | jle >7 - |3: - | sub TMPRd, RAd // start > end? - | jl ->fff_emptystr - | lea RD, [STR:RB+RAd+#STR-1] - | add TMPRd, 1 - |4: - | jmp ->fff_newstr - | - |5: // Negative end or overflow. - | jl >6 - | lea TMPRd, [TMPRd+RCd+1] // end = end+(len+1) - | jmp <2 - |6: // Overflow. - | mov TMPRd, RCd // end = len - | jmp <2 - | - |7: // Negative start or underflow. - | je >8 - | add RAd, RCd // start = start+(len+1) - | add RAd, 1 - | jg <3 // start > 0? - |8: // Underflow. - | mov RAd, 1 // start = 1 - | jmp <3 - | - |->fff_emptystr: // Range underflow. - | xor TMPRd, TMPRd // Zero length. Any ptr in RD is ok. - | jmp <4 - | - |.macro ffstring_op, name - | .ffunc_1 string_ .. name - | ffgccheck - |.if X64WIN - | mov STR:TMPR, [BASE] - | checkstr STR:TMPR, ->fff_fallback - |.else - | mov STR:CARG2, [BASE] - | checkstr STR:CARG2, ->fff_fallback - |.endif - | mov L:RB, SAVE_L - | lea SBUF:CARG1, [DISPATCH+DISPATCH_GL(tmpbuf)] - | mov L:RB->base, BASE - |.if X64WIN - | mov STR:CARG2, STR:TMPR // Caveat: CARG2 == BASE - |.endif - | mov RC, SBUF:CARG1->b - | mov SBUF:CARG1->L, L:RB - | mov SBUF:CARG1->p, RC - | mov SAVE_PC, PC - | call extern lj_buf_putstr_ .. name - | mov CARG1, rax - | call extern lj_buf_tostr - | jmp ->fff_resstr - |.endmacro - | - |ffstring_op reverse - |ffstring_op lower - |ffstring_op upper - | - |//-- Bit library -------------------------------------------------------- - | - |.macro .ffunc_bit, name, kind, fdef - | fdef name - |.if kind == 2 - | sseconst_tobit xmm1, RB - |.endif - |.if DUALNUM - | mov RB, [BASE] - | checkint RB, >1 - |.if kind > 0 - | jmp >2 - |.else - | jmp ->fff_resbit - |.endif - |1: - | ja ->fff_fallback - | movd xmm0, RB - |.else - | checknumtp [BASE], ->fff_fallback - | movsd xmm0, qword [BASE] - |.endif - |.if kind < 2 - | sseconst_tobit xmm1, RB - |.endif - | addsd xmm0, xmm1 - | movd RBd, xmm0 - |2: - |.endmacro - | - |.macro .ffunc_bit, name, kind - | .ffunc_bit name, kind, .ffunc_1 - |.endmacro - | - |.ffunc_bit bit_tobit, 0 - | jmp ->fff_resbit - | - |.macro .ffunc_bit_op, name, ins - | .ffunc_bit name, 2 - | mov TMPRd, NARGS:RDd // Save for fallback. - | lea RD, [BASE+NARGS:RD*8-16] - |1: - | cmp RD, BASE - | jbe ->fff_resbit - |.if DUALNUM - | mov RA, [RD] - | checkint RA, >2 - | ins RBd, RAd - | sub RD, 8 - | jmp <1 - |2: - | ja ->fff_fallback_bit_op - | movd xmm0, RA - |.else - | checknumtp [RD], ->fff_fallback_bit_op - | movsd xmm0, qword [RD] - |.endif - | addsd xmm0, xmm1 - | movd RAd, xmm0 - | ins RBd, RAd - | sub RD, 8 - | jmp <1 - |.endmacro - | - |.ffunc_bit_op bit_band, and - |.ffunc_bit_op bit_bor, or - |.ffunc_bit_op bit_bxor, xor - | - |.ffunc_bit bit_bswap, 1 - | bswap RBd - | jmp ->fff_resbit - | - |.ffunc_bit bit_bnot, 1 - | not RBd - |.if DUALNUM - | jmp ->fff_resbit - |.else - |->fff_resbit: - | cvtsi2sd xmm0, RBd - | jmp ->fff_resxmm0 - |.endif - | - |->fff_fallback_bit_op: - | mov NARGS:RDd, TMPRd // Restore for fallback - | jmp ->fff_fallback - | - |.macro .ffunc_bit_sh, name, ins - |.if DUALNUM - | .ffunc_bit name, 1, .ffunc_2 - | // Note: no inline conversion from number for 2nd argument! - | mov RA, [BASE+8] - | checkint RA, ->fff_fallback - |.else - | .ffunc_nn name - | sseconst_tobit xmm2, RB - | addsd xmm0, xmm2 - | addsd xmm1, xmm2 - | movd RBd, xmm0 - | movd RAd, xmm1 - |.endif - | ins RBd, cl // Assumes RA is ecx. - | jmp ->fff_resbit - |.endmacro - | - |.ffunc_bit_sh bit_lshift, shl - |.ffunc_bit_sh bit_rshift, shr - |.ffunc_bit_sh bit_arshift, sar - |.ffunc_bit_sh bit_rol, rol - |.ffunc_bit_sh bit_ror, ror - | - |//----------------------------------------------------------------------- - | - |->fff_fallback_2: - | mov NARGS:RDd, 1+2 // Other args are ignored, anyway. - | jmp ->fff_fallback - |->fff_fallback_1: - | mov NARGS:RDd, 1+1 // Other args are ignored, anyway. - |->fff_fallback: // Call fast function fallback handler. - | // BASE = new base, RD = nargs+1 - | mov L:RB, SAVE_L - | mov PC, [BASE-8] // Fallback may overwrite PC. - | mov SAVE_PC, PC // Redundant (but a defined value). - | mov L:RB->base, BASE - | lea RD, [BASE+NARGS:RD*8-8] - | lea RA, [RD+8*LUA_MINSTACK] // Ensure enough space for handler. - | mov L:RB->top, RD - | mov CFUNC:RD, [BASE-16] - | cleartp CFUNC:RD - | cmp RA, L:RB->maxstack - | ja >5 // Need to grow stack. - | mov CARG1, L:RB - | call aword CFUNC:RD->f // (lua_State *L) - | mov BASE, L:RB->base - | // Either throws an error, or recovers and returns -1, 0 or nresults+1. - | test RDd, RDd; jg ->fff_res // Returned nresults+1? - |1: - | mov RA, L:RB->top - | sub RA, BASE - | shr RAd, 3 - | test RDd, RDd - | lea NARGS:RDd, [RAd+1] - | mov LFUNC:RB, [BASE-16] - | jne ->vm_call_tail // Returned -1? - | cleartp LFUNC:RB - | ins_callt // Returned 0: retry fast path. - | - |// Reconstruct previous base for vmeta_call during tailcall. - |->vm_call_tail: - | mov RA, BASE - | test PCd, FRAME_TYPE - | jnz >3 - | movzx RBd, PC_RA - | neg RB - | lea BASE, [BASE+RB*8-16] // base = base - (RB+2)*8 - | jmp ->vm_call_dispatch // Resolve again for tailcall. - |3: - | mov RB, PC - | and RB, -8 - | sub BASE, RB - | jmp ->vm_call_dispatch // Resolve again for tailcall. - | - |5: // Grow stack for fallback handler. - | mov CARG2d, LUA_MINSTACK - | mov CARG1, L:RB - | call extern lj_state_growstack // (lua_State *L, int n) - | mov BASE, L:RB->base - | xor RDd, RDd // Simulate a return 0. - | jmp <1 // Dumb retry (goes through ff first). - | - |->fff_gcstep: // Call GC step function. - | // BASE = new base, RD = nargs+1 - | pop RB // Must keep stack at same level. - | mov TMP1, RB // Save return address - | mov L:RB, SAVE_L - | mov SAVE_PC, PC // Redundant (but a defined value). - | mov L:RB->base, BASE - | lea RD, [BASE+NARGS:RD*8-8] - | mov CARG1, L:RB - | mov L:RB->top, RD - | call extern lj_gc_step // (lua_State *L) - | mov BASE, L:RB->base - | mov RD, L:RB->top - | sub RD, BASE - | shr RDd, 3 - | add NARGS:RDd, 1 - | mov RB, TMP1 - | push RB // Restore return address. - | ret - | - |//----------------------------------------------------------------------- - |//-- Special dispatch targets ------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_record: // Dispatch target for recording phase. - |.if JIT - | movzx RDd, byte [DISPATCH+DISPATCH_GL(hookmask)] - | test RDL, HOOK_VMEVENT // No recording while in vmevent. - | jnz >5 - | // Decrement the hookcount for consistency, but always do the call. - | test RDL, HOOK_ACTIVE - | jnz >1 - | test RDL, LUA_MASKLINE|LUA_MASKCOUNT - | jz >1 - | dec dword [DISPATCH+DISPATCH_GL(hookcount)] - | jmp >1 - |.endif - | - |->vm_rethook: // Dispatch target for return hooks. - | movzx RDd, byte [DISPATCH+DISPATCH_GL(hookmask)] - | test RDL, HOOK_ACTIVE // Hook already active? - | jnz >5 - | jmp >1 - | - |->vm_inshook: // Dispatch target for instr/line hooks. - | movzx RDd, byte [DISPATCH+DISPATCH_GL(hookmask)] - | test RDL, HOOK_ACTIVE // Hook already active? - | jnz >5 - | - | test RDL, LUA_MASKLINE|LUA_MASKCOUNT - | jz >5 - | dec dword [DISPATCH+DISPATCH_GL(hookcount)] - | jz >1 - | test RDL, LUA_MASKLINE - | jz >5 - |1: - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - | mov CARG2, PC // Caveat: CARG2 == BASE - | mov CARG1, L:RB - | // SAVE_PC must hold the _previous_ PC. The callee updates it with PC. - | call extern lj_dispatch_ins // (lua_State *L, const BCIns *pc) - |3: - | mov BASE, L:RB->base - |4: - | movzx RAd, PC_RA - |5: - | movzx OP, PC_OP - | movzx RDd, PC_RD - | jmp aword [DISPATCH+OP*8+GG_DISP2STATIC] // Re-dispatch to static ins. - | - |->cont_hook: // Continue from hook yield. - | add PC, 4 - | mov RA, [RB-40] - | mov MULTRES, RAd // Restore MULTRES for *M ins. - | jmp <4 - | - |->vm_hotloop: // Hot loop counter underflow. - |.if JIT - | mov LFUNC:RB, [BASE-16] // Same as curr_topL(L). - | cleartp LFUNC:RB - | mov RB, LFUNC:RB->pc - | movzx RDd, byte [RB+PC2PROTO(framesize)] - | lea RD, [BASE+RD*8] - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - | mov L:RB->top, RD - | mov CARG2, PC - | lea CARG1, [DISPATCH+GG_DISP2J] - | mov aword [DISPATCH+DISPATCH_J(L)], L:RB - | mov SAVE_PC, PC - | call extern lj_trace_hot // (jit_State *J, const BCIns *pc) - | jmp <3 - |.endif - | - |->vm_callhook: // Dispatch target for call hooks. - | mov SAVE_PC, PC - |.if JIT - | jmp >1 - |.endif - | - |->vm_hotcall: // Hot call counter underflow. - |.if JIT - | mov SAVE_PC, PC - | or PC, 1 // Marker for hot call. - |1: - |.endif - | lea RD, [BASE+NARGS:RD*8-8] - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - | mov L:RB->top, RD - | mov CARG2, PC - | mov CARG1, L:RB - | call extern lj_dispatch_call // (lua_State *L, const BCIns *pc) - | // ASMFunction returned in eax/rax (RD). - | mov SAVE_PC, 0 // Invalidate for subsequent line hook. - |.if JIT - | and PC, -2 - |.endif - | mov BASE, L:RB->base - | mov RA, RD - | mov RD, L:RB->top - | sub RD, BASE - | mov RB, RA - | movzx RAd, PC_RA - | shr RDd, 3 - | add NARGS:RDd, 1 - | jmp RB - | - |->cont_stitch: // Trace stitching. - |.if JIT - | // BASE = base, RC = result, RB = mbase - | mov TRACE:ITYPE, [RB-40] // Save previous trace. - | cleartp TRACE:ITYPE - | mov TMPRd, MULTRES - | movzx RAd, PC_RA - | lea RA, [BASE+RA*8] // Call base. - | sub TMPRd, 1 - | jz >2 - |1: // Move results down. - | mov RB, [RC] - | mov [RA], RB - | add RC, 8 - | add RA, 8 - | sub TMPRd, 1 - | jnz <1 - |2: - | movzx RCd, PC_RA - | movzx RBd, PC_RB - | add RC, RB - | lea RC, [BASE+RC*8-8] - |3: - | cmp RC, RA - | ja >9 // More results wanted? - | - | test TRACE:ITYPE, TRACE:ITYPE - | jz ->cont_nop - | movzx RBd, word TRACE:ITYPE->traceno - | movzx RDd, word TRACE:ITYPE->link - | cmp RDd, RBd - | je ->cont_nop // Blacklisted. - | test RDd, RDd - | jne =>BC_JLOOP // Jump to stitched trace. - | - | // Stitch a new trace to the previous trace. - | mov [DISPATCH+DISPATCH_J(exitno)], RB - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - | mov CARG2, PC - | lea CARG1, [DISPATCH+GG_DISP2J] - | mov aword [DISPATCH+DISPATCH_J(L)], L:RB - | call extern lj_dispatch_stitch // (jit_State *J, const BCIns *pc) - | mov BASE, L:RB->base - | jmp ->cont_nop - | - |9: // Fill up results with nil. - | mov aword [RA], LJ_TNIL - | add RA, 8 - | jmp <3 - |.endif - | - |->vm_profhook: // Dispatch target for profiler hook. -#if LJ_HASPROFILE - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - | mov CARG2, PC // Caveat: CARG2 == BASE - | mov CARG1, L:RB - | call extern lj_dispatch_profile // (lua_State *L, const BCIns *pc) - | mov BASE, L:RB->base - | // HOOK_PROFILE is off again, so re-dispatch to dynamic instruction. - | sub PC, 4 - | jmp ->cont_nop -#endif - | - |//----------------------------------------------------------------------- - |//-- Trace exit handler ------------------------------------------------- - |//----------------------------------------------------------------------- - | - |// Called from an exit stub with the exit number on the stack. - |// The 16 bit exit number is stored with two (sign-extended) push imm8. - |->vm_exit_handler: - |.if JIT - | push r13; push r12 - | push r11; push r10; push r9; push r8 - | push rdi; push rsi; push rbp; lea rbp, [rsp+88]; push rbp - | push rbx; push rdx; push rcx; push rax - | movzx RCd, byte [rbp-8] // Reconstruct exit number. - | mov RCH, byte [rbp-16] - | mov [rbp-8], r15; mov [rbp-16], r14 - | // DISPATCH is preserved on-trace in LJ_GC64 mode. - | mov RAd, [DISPATCH+DISPATCH_GL(vmstate)] // Get trace number. - | set_vmstate EXIT - | mov [DISPATCH+DISPATCH_J(exitno)], RCd - | mov [DISPATCH+DISPATCH_J(parent)], RAd - |.if X64WIN - | sub rsp, 16*8+4*8 // Room for SSE regs + save area. - |.else - | sub rsp, 16*8 // Room for SSE regs. - |.endif - | add rbp, -128 - | movsd qword [rbp-8], xmm15; movsd qword [rbp-16], xmm14 - | movsd qword [rbp-24], xmm13; movsd qword [rbp-32], xmm12 - | movsd qword [rbp-40], xmm11; movsd qword [rbp-48], xmm10 - | movsd qword [rbp-56], xmm9; movsd qword [rbp-64], xmm8 - | movsd qword [rbp-72], xmm7; movsd qword [rbp-80], xmm6 - | movsd qword [rbp-88], xmm5; movsd qword [rbp-96], xmm4 - | movsd qword [rbp-104], xmm3; movsd qword [rbp-112], xmm2 - | movsd qword [rbp-120], xmm1; movsd qword [rbp-128], xmm0 - | // Caveat: RB is rbp. - | mov L:RB, [DISPATCH+DISPATCH_GL(cur_L)] - | mov BASE, [DISPATCH+DISPATCH_GL(jit_base)] - | mov aword [DISPATCH+DISPATCH_J(L)], L:RB - | mov L:RB->base, BASE - |.if X64WIN - | lea CARG2, [rsp+4*8] - |.else - | mov CARG2, rsp - |.endif - | lea CARG1, [DISPATCH+GG_DISP2J] - | mov qword [DISPATCH+DISPATCH_GL(jit_base)], 0 - | call extern lj_trace_exit // (jit_State *J, ExitState *ex) - | // MULTRES or negated error code returned in eax (RD). - | mov RA, L:RB->cframe - | and RA, CFRAME_RAWMASK - | mov [RA+CFRAME_OFS_L], L:RB // Set SAVE_L (on-trace resume/yield). - | mov BASE, L:RB->base - | mov PC, [RA+CFRAME_OFS_PC] // Get SAVE_PC. - | jmp >1 - |.endif - |->vm_exit_interp: - | // RD = MULTRES or negated error code, BASE, PC and DISPATCH set. - |.if JIT - | // Restore additional callee-save registers only used in compiled code. - |.if X64WIN - | lea RA, [rsp+10*16+4*8] - |1: - | movdqa xmm15, [RA-10*16] - | movdqa xmm14, [RA-9*16] - | movdqa xmm13, [RA-8*16] - | movdqa xmm12, [RA-7*16] - | movdqa xmm11, [RA-6*16] - | movdqa xmm10, [RA-5*16] - | movdqa xmm9, [RA-4*16] - | movdqa xmm8, [RA-3*16] - | movdqa xmm7, [RA-2*16] - | mov rsp, RA // Reposition stack to C frame. - | movdqa xmm6, [RA-1*16] - | mov r15, CSAVE_1 - | mov r14, CSAVE_2 - | mov r13, CSAVE_3 - | mov r12, CSAVE_4 - |.else - | lea RA, [rsp+16] - |1: - | mov r13, [RA-8] - | mov r12, [RA] - | mov rsp, RA // Reposition stack to C frame. - |.endif - | test RDd, RDd; js >9 // Check for error from exit. - | mov L:RB, SAVE_L - | mov MULTRES, RDd - | mov LFUNC:KBASE, [BASE-16] - | cleartp LFUNC:KBASE - | mov KBASE, LFUNC:KBASE->pc - | mov KBASE, [KBASE+PC2PROTO(k)] - | mov L:RB->base, BASE - | mov qword [DISPATCH+DISPATCH_GL(jit_base)], 0 - | set_vmstate INTERP - | // Modified copy of ins_next which handles function header dispatch, too. - | mov RCd, [PC] - | movzx RAd, RCH - | movzx OP, RCL - | add PC, 4 - | shr RCd, 16 - | cmp OP, BC_FUNCF // Function header? - | jb >3 - | cmp OP, BC_FUNCC+2 // Fast function? - | jae >4 - |2: - | mov RCd, MULTRES // RC/RD holds nres+1. - |3: - | jmp aword [DISPATCH+OP*8] - | - |4: // Check frame below fast function. - | mov RC, [BASE-8] - | test RCd, FRAME_TYPE - | jnz <2 // Trace stitching continuation? - | // Otherwise set KBASE for Lua function below fast function. - | movzx RCd, byte [RC-3] - | neg RC - | mov LFUNC:KBASE, [BASE+RC*8-32] - | cleartp LFUNC:KBASE - | mov KBASE, LFUNC:KBASE->pc - | mov KBASE, [KBASE+PC2PROTO(k)] - | jmp <2 - | - |9: // Rethrow error from the right C frame. - | neg RD - | mov CARG1, L:RB - | mov CARG2, RD - | call extern lj_err_throw // (lua_State *L, int errcode) - |.endif - | - |//----------------------------------------------------------------------- - |//-- Math helper functions ---------------------------------------------- - |//----------------------------------------------------------------------- - | - |// FP value rounding. Called by math.floor/math.ceil fast functions - |// and from JIT code. arg/ret is xmm0. xmm0-xmm3 and RD (eax) modified. - |.macro vm_round, name, mode, cond - |->name: - |->name .. _sse: - | sseconst_abs xmm2, RD - | sseconst_2p52 xmm3, RD - | movaps xmm1, xmm0 - | andpd xmm1, xmm2 // |x| - | ucomisd xmm3, xmm1 // No truncation if 2^52 <= |x|. - | jbe >1 - | andnpd xmm2, xmm0 // Isolate sign bit. - |.if mode == 2 // trunc(x)? - | movaps xmm0, xmm1 - | addsd xmm1, xmm3 // (|x| + 2^52) - 2^52 - | subsd xmm1, xmm3 - | sseconst_1 xmm3, RD - | cmpsd xmm0, xmm1, 1 // |x| < result? - | andpd xmm0, xmm3 - | subsd xmm1, xmm0 // If yes, subtract -1. - | orpd xmm1, xmm2 // Merge sign bit back in. - |.else - | addsd xmm1, xmm3 // (|x| + 2^52) - 2^52 - | subsd xmm1, xmm3 - | orpd xmm1, xmm2 // Merge sign bit back in. - | .if mode == 1 // ceil(x)? - | sseconst_m1 xmm2, RD // Must subtract -1 to preserve -0. - | cmpsd xmm0, xmm1, 6 // x > result? - | .else // floor(x)? - | sseconst_1 xmm2, RD - | cmpsd xmm0, xmm1, 1 // x < result? - | .endif - | andpd xmm0, xmm2 - | subsd xmm1, xmm0 // If yes, subtract +-1. - |.endif - | movaps xmm0, xmm1 - |1: - | ret - |.endmacro - | - | vm_round vm_floor, 0, 1 - | vm_round vm_ceil, 1, JIT - | vm_round vm_trunc, 2, JIT - | - |// FP modulo x%y. Called by BC_MOD* and vm_arith. - |->vm_mod: - |// Args in xmm0/xmm1, return value in xmm0. - |// Caveat: xmm0-xmm5 and RC (eax) modified! - | movaps xmm5, xmm0 - | divsd xmm0, xmm1 - | sseconst_abs xmm2, RD - | sseconst_2p52 xmm3, RD - | movaps xmm4, xmm0 - | andpd xmm4, xmm2 // |x/y| - | ucomisd xmm3, xmm4 // No truncation if 2^52 <= |x/y|. - | jbe >1 - | andnpd xmm2, xmm0 // Isolate sign bit. - | addsd xmm4, xmm3 // (|x/y| + 2^52) - 2^52 - | subsd xmm4, xmm3 - | orpd xmm4, xmm2 // Merge sign bit back in. - | sseconst_1 xmm2, RD - | cmpsd xmm0, xmm4, 1 // x/y < result? - | andpd xmm0, xmm2 - | subsd xmm4, xmm0 // If yes, subtract 1.0. - | movaps xmm0, xmm5 - | mulsd xmm1, xmm4 - | subsd xmm0, xmm1 - | ret - |1: - | mulsd xmm1, xmm0 - | movaps xmm0, xmm5 - | subsd xmm0, xmm1 - | ret - | - |// Args in xmm0/eax. Ret in xmm0. xmm0-xmm1 and eax modified. - |->vm_powi_sse: - | cmp eax, 1; jle >6 // i<=1? - | // Now 1 < (unsigned)i <= 0x80000000. - |1: // Handle leading zeros. - | test eax, 1; jnz >2 - | mulsd xmm0, xmm0 - | shr eax, 1 - | jmp <1 - |2: - | shr eax, 1; jz >5 - | movaps xmm1, xmm0 - |3: // Handle trailing bits. - | mulsd xmm0, xmm0 - | shr eax, 1; jz >4 - | jnc <3 - | mulsd xmm1, xmm0 - | jmp <3 - |4: - | mulsd xmm0, xmm1 - |5: - | ret - |6: - | je <5 // x^1 ==> x - | jb >7 // x^0 ==> 1 - | neg eax - | call <1 - | sseconst_1 xmm1, RD - | divsd xmm1, xmm0 - | movaps xmm0, xmm1 - | ret - |7: - | sseconst_1 xmm0, RD - | ret - | - |//----------------------------------------------------------------------- - |//-- Miscellaneous functions -------------------------------------------- - |//----------------------------------------------------------------------- - | - |// int lj_vm_cpuid(uint32_t f, uint32_t res[4]) - |->vm_cpuid: - | mov eax, CARG1d - | .if X64WIN; push rsi; mov rsi, CARG2; .endif - | push rbx - | xor ecx, ecx - | cpuid - | mov [rsi], eax - | mov [rsi+4], ebx - | mov [rsi+8], ecx - | mov [rsi+12], edx - | pop rbx - | .if X64WIN; pop rsi; .endif - | ret - | - |//----------------------------------------------------------------------- - |//-- Assertions --------------------------------------------------------- - |//----------------------------------------------------------------------- - | - |->assert_bad_for_arg_type: -#ifdef LUA_USE_ASSERT - | int3 -#endif - | int3 - | - |//----------------------------------------------------------------------- - |//-- FFI helper functions ----------------------------------------------- - |//----------------------------------------------------------------------- - | - |// Handler for callback functions. Callback slot number in ah/al. - |->vm_ffi_callback: - |.if FFI - |.type CTSTATE, CTState, PC - | saveregs_ // ebp/rbp already saved. ebp now holds global_State *. - | lea DISPATCH, [ebp+GG_G2DISP] - | mov CTSTATE, GL:ebp->ctype_state - | movzx eax, ax - | mov CTSTATE->cb.slot, eax - | mov CTSTATE->cb.gpr[0], CARG1 - | mov CTSTATE->cb.gpr[1], CARG2 - | mov CTSTATE->cb.gpr[2], CARG3 - | mov CTSTATE->cb.gpr[3], CARG4 - | movsd qword CTSTATE->cb.fpr[0], xmm0 - | movsd qword CTSTATE->cb.fpr[1], xmm1 - | movsd qword CTSTATE->cb.fpr[2], xmm2 - | movsd qword CTSTATE->cb.fpr[3], xmm3 - |.if X64WIN - | lea rax, [rsp+CFRAME_SIZE+4*8] - |.else - | lea rax, [rsp+CFRAME_SIZE] - | mov CTSTATE->cb.gpr[4], CARG5 - | mov CTSTATE->cb.gpr[5], CARG6 - | movsd qword CTSTATE->cb.fpr[4], xmm4 - | movsd qword CTSTATE->cb.fpr[5], xmm5 - | movsd qword CTSTATE->cb.fpr[6], xmm6 - | movsd qword CTSTATE->cb.fpr[7], xmm7 - |.endif - | mov CTSTATE->cb.stack, rax - | mov CARG2, rsp - | mov SAVE_PC, CTSTATE // Any value outside of bytecode is ok. - | mov CARG1, CTSTATE - | call extern lj_ccallback_enter // (CTState *cts, void *cf) - | // lua_State * returned in eax (RD). - | set_vmstate INTERP - | mov BASE, L:RD->base - | mov RD, L:RD->top - | sub RD, BASE - | mov LFUNC:RB, [BASE-16] - | cleartp LFUNC:RB - | shr RD, 3 - | add RD, 1 - | ins_callt - |.endif - | - |->cont_ffi_callback: // Return from FFI callback. - |.if FFI - | mov L:RA, SAVE_L - | mov CTSTATE, [DISPATCH+DISPATCH_GL(ctype_state)] - | mov aword CTSTATE->L, L:RA - | mov L:RA->base, BASE - | mov L:RA->top, RB - | mov CARG1, CTSTATE - | mov CARG2, RC - | call extern lj_ccallback_leave // (CTState *cts, TValue *o) - | mov rax, CTSTATE->cb.gpr[0] - | movsd xmm0, qword CTSTATE->cb.fpr[0] - | jmp ->vm_leave_unw - |.endif - | - |->vm_ffi_call: // Call C function via FFI. - | // Caveat: needs special frame unwinding, see below. - |.if FFI - | .type CCSTATE, CCallState, rbx - | push rbp; mov rbp, rsp; push rbx; mov CCSTATE, CARG1 - | - | // Readjust stack. - | mov eax, CCSTATE->spadj - | sub rsp, rax - | - | // Copy stack slots. - | movzx ecx, byte CCSTATE->nsp - | sub ecx, 1 - | js >2 - |1: - | mov rax, [CCSTATE+rcx*8+offsetof(CCallState, stack)] - | mov [rsp+rcx*8+CCALL_SPS_EXTRA*8], rax - | sub ecx, 1 - | jns <1 - |2: - | - | movzx eax, byte CCSTATE->nfpr - | mov CARG1, CCSTATE->gpr[0] - | mov CARG2, CCSTATE->gpr[1] - | mov CARG3, CCSTATE->gpr[2] - | mov CARG4, CCSTATE->gpr[3] - |.if not X64WIN - | mov CARG5, CCSTATE->gpr[4] - | mov CARG6, CCSTATE->gpr[5] - |.endif - | test eax, eax; jz >5 - | movaps xmm0, CCSTATE->fpr[0] - | movaps xmm1, CCSTATE->fpr[1] - | movaps xmm2, CCSTATE->fpr[2] - | movaps xmm3, CCSTATE->fpr[3] - |.if not X64WIN - | cmp eax, 4; jbe >5 - | movaps xmm4, CCSTATE->fpr[4] - | movaps xmm5, CCSTATE->fpr[5] - | movaps xmm6, CCSTATE->fpr[6] - | movaps xmm7, CCSTATE->fpr[7] - |.endif - |5: - | - | call aword CCSTATE->func - | - | mov CCSTATE->gpr[0], rax - | movaps CCSTATE->fpr[0], xmm0 - |.if not X64WIN - | mov CCSTATE->gpr[1], rdx - | movaps CCSTATE->fpr[1], xmm1 - |.endif - | - | mov rbx, [rbp-8]; leave; ret - |.endif - |// Note: vm_ffi_call must be the last function in this object file! - | - |//----------------------------------------------------------------------- -} - -/* Generate the code for a single instruction. */ -static void build_ins(BuildCtx *ctx, BCOp op, int defop) -{ - int vk = 0; - |// Note: aligning all instructions does not pay off. - |=>defop: - - switch (op) { - - /* -- Comparison ops ---------------------------------------------------- */ - - /* Remember: all ops branch for a true comparison, fall through otherwise. */ - - |.macro jmp_comp, lt, ge, le, gt, target - ||switch (op) { - ||case BC_ISLT: - | lt target - ||break; - ||case BC_ISGE: - | ge target - ||break; - ||case BC_ISLE: - | le target - ||break; - ||case BC_ISGT: - | gt target - ||break; - ||default: break; /* Shut up GCC. */ - ||} - |.endmacro - - case BC_ISLT: case BC_ISGE: case BC_ISLE: case BC_ISGT: - | // RA = src1, RD = src2, JMP with RD = target - | ins_AD - | mov ITYPE, [BASE+RA*8] - | mov RB, [BASE+RD*8] - | mov RA, ITYPE - | mov RD, RB - | sar ITYPE, 47 - | sar RB, 47 - |.if DUALNUM - | cmp ITYPEd, LJ_TISNUM; jne >7 - | cmp RBd, LJ_TISNUM; jne >8 - | add PC, 4 - | cmp RAd, RDd - | jmp_comp jge, jl, jg, jle, >9 - |6: - | movzx RDd, PC_RD - | branchPC RD - |9: - | ins_next - | - |7: // RA is not an integer. - | ja ->vmeta_comp - | // RA is a number. - | cmp RBd, LJ_TISNUM; jb >1; jne ->vmeta_comp - | // RA is a number, RD is an integer. - | cvtsi2sd xmm0, RDd - | jmp >2 - | - |8: // RA is an integer, RD is not an integer. - | ja ->vmeta_comp - | // RA is an integer, RD is a number. - | cvtsi2sd xmm1, RAd - | movd xmm0, RD - | jmp >3 - |.else - | cmp ITYPEd, LJ_TISNUM; jae ->vmeta_comp - | cmp RBd, LJ_TISNUM; jae ->vmeta_comp - |.endif - |1: - | movd xmm0, RD - |2: - | movd xmm1, RA - |3: - | add PC, 4 - | ucomisd xmm0, xmm1 - | // Unordered: all of ZF CF PF set, ordered: PF clear. - | // To preserve NaN semantics GE/GT branch on unordered, but LT/LE don't. - |.if DUALNUM - | jmp_comp jbe, ja, jb, jae, <9 - | jmp <6 - |.else - | jmp_comp jbe, ja, jb, jae, >1 - | movzx RDd, PC_RD - | branchPC RD - |1: - | ins_next - |.endif - break; - - case BC_ISEQV: case BC_ISNEV: - vk = op == BC_ISEQV; - | ins_AD // RA = src1, RD = src2, JMP with RD = target - | mov RB, [BASE+RD*8] - | mov ITYPE, [BASE+RA*8] - | add PC, 4 - | mov RD, RB - | mov RA, ITYPE - | sar RB, 47 - | sar ITYPE, 47 - |.if DUALNUM - | cmp RBd, LJ_TISNUM; jne >7 - | cmp ITYPEd, LJ_TISNUM; jne >8 - | cmp RDd, RAd - if (vk) { - | jne >9 - } else { - | je >9 - } - | movzx RDd, PC_RD - | branchPC RD - |9: - | ins_next - | - |7: // RD is not an integer. - | ja >5 - | // RD is a number. - | movd xmm1, RD - | cmp ITYPEd, LJ_TISNUM; jb >1; jne >5 - | // RD is a number, RA is an integer. - | cvtsi2sd xmm0, RAd - | jmp >2 - | - |8: // RD is an integer, RA is not an integer. - | ja >5 - | // RD is an integer, RA is a number. - | cvtsi2sd xmm1, RDd - | jmp >1 - | - |.else - | cmp RBd, LJ_TISNUM; jae >5 - | cmp ITYPEd, LJ_TISNUM; jae >5 - | movd xmm1, RD - |.endif - |1: - | movd xmm0, RA - |2: - | ucomisd xmm0, xmm1 - |4: - iseqne_fp: - if (vk) { - | jp >2 // Unordered means not equal. - | jne >2 - } else { - | jp >2 // Unordered means not equal. - | je >1 - } - iseqne_end: - if (vk) { - |1: // EQ: Branch to the target. - | movzx RDd, PC_RD - | branchPC RD - |2: // NE: Fallthrough to next instruction. - |.if not FFI - |3: - |.endif - } else { - |.if not FFI - |3: - |.endif - |2: // NE: Branch to the target. - | movzx RDd, PC_RD - | branchPC RD - |1: // EQ: Fallthrough to next instruction. - } - if (LJ_DUALNUM && (op == BC_ISEQV || op == BC_ISNEV || - op == BC_ISEQN || op == BC_ISNEN)) { - | jmp <9 - } else { - | ins_next - } - | - if (op == BC_ISEQV || op == BC_ISNEV) { - |5: // Either or both types are not numbers. - |.if FFI - | cmp RBd, LJ_TCDATA; je ->vmeta_equal_cd - | cmp ITYPEd, LJ_TCDATA; je ->vmeta_equal_cd - |.endif - | cmp RA, RD - | je <1 // Same GCobjs or pvalues? - | cmp RBd, ITYPEd - | jne <2 // Not the same type? - | cmp RBd, LJ_TISTABUD - | ja <2 // Different objects and not table/ud? - | - | // Different tables or userdatas. Need to check __eq metamethod. - | // Field metatable must be at same offset for GCtab and GCudata! - | cleartp TAB:RA - | mov TAB:RB, TAB:RA->metatable - | test TAB:RB, TAB:RB - | jz <2 // No metatable? - | test byte TAB:RB->nomm, 1<vmeta_equal // Handle __eq metamethod. - } else { - |.if FFI - |3: - | cmp ITYPEd, LJ_TCDATA - if (LJ_DUALNUM && vk) { - | jne <9 - } else { - | jne <2 - } - | jmp ->vmeta_equal_cd - |.endif - } - break; - case BC_ISEQS: case BC_ISNES: - vk = op == BC_ISEQS; - | ins_AND // RA = src, RD = str const, JMP with RD = target - | mov RB, [BASE+RA*8] - | add PC, 4 - | checkstr RB, >3 - | cmp RB, [KBASE+RD*8] - iseqne_test: - if (vk) { - | jne >2 - } else { - | je >1 - } - goto iseqne_end; - case BC_ISEQN: case BC_ISNEN: - vk = op == BC_ISEQN; - | ins_AD // RA = src, RD = num const, JMP with RD = target - | mov RB, [BASE+RA*8] - | add PC, 4 - |.if DUALNUM - | checkint RB, >7 - | mov RD, [KBASE+RD*8] - | checkint RD, >8 - | cmp RBd, RDd - if (vk) { - | jne >9 - } else { - | je >9 - } - | movzx RDd, PC_RD - | branchPC RD - |9: - | ins_next - | - |7: // RA is not an integer. - | ja >3 - | // RA is a number. - | mov RD, [KBASE+RD*8] - | checkint RD, >1 - | // RA is a number, RD is an integer. - | cvtsi2sd xmm0, RDd - | jmp >2 - | - |8: // RA is an integer, RD is a number. - | cvtsi2sd xmm0, RBd - | movd xmm1, RD - | ucomisd xmm0, xmm1 - | jmp >4 - |1: - | movd xmm0, RD - |.else - | checknum RB, >3 - |1: - | movsd xmm0, qword [KBASE+RD*8] - |.endif - |2: - | ucomisd xmm0, qword [BASE+RA*8] - |4: - goto iseqne_fp; - case BC_ISEQP: case BC_ISNEP: - vk = op == BC_ISEQP; - | ins_AND // RA = src, RD = primitive type (~), JMP with RD = target - | mov RB, [BASE+RA*8] - | sar RB, 47 - | add PC, 4 - | cmp RBd, RDd - if (!LJ_HASFFI) goto iseqne_test; - if (vk) { - | jne >3 - | movzx RDd, PC_RD - | branchPC RD - |2: - | ins_next - |3: - | cmp RBd, LJ_TCDATA; jne <2 - | jmp ->vmeta_equal_cd - } else { - | je >2 - | cmp RBd, LJ_TCDATA; je ->vmeta_equal_cd - | movzx RDd, PC_RD - | branchPC RD - |2: - | ins_next - } - break; - - /* -- Unary test and copy ops ------------------------------------------- */ - - case BC_ISTC: case BC_ISFC: case BC_IST: case BC_ISF: - | ins_AD // RA = dst or unused, RD = src, JMP with RD = target - | mov ITYPE, [BASE+RD*8] - | add PC, 4 - if (op == BC_ISTC || op == BC_ISFC) { - | mov RB, ITYPE - } - | sar ITYPE, 47 - | cmp ITYPEd, LJ_TISTRUECOND - if (op == BC_IST || op == BC_ISTC) { - | jae >1 - } else { - | jb >1 - } - if (op == BC_ISTC || op == BC_ISFC) { - | mov [BASE+RA*8], RB - } - | movzx RDd, PC_RD - | branchPC RD - |1: // Fallthrough to the next instruction. - | ins_next - break; - - case BC_ISTYPE: - | ins_AD // RA = src, RD = -type - | mov RB, [BASE+RA*8] - | sar RB, 47 - | add RBd, RDd - | jne ->vmeta_istype - | ins_next - break; - case BC_ISNUM: - | ins_AD // RA = src, RD = -(TISNUM-1) - | checknumtp [BASE+RA*8], ->vmeta_istype - | ins_next - break; - - /* -- Unary ops --------------------------------------------------------- */ - - case BC_MOV: - | ins_AD // RA = dst, RD = src - | mov RB, [BASE+RD*8] - | mov [BASE+RA*8], RB - | ins_next_ - break; - case BC_NOT: - | ins_AD // RA = dst, RD = src - | mov RB, [BASE+RD*8] - | sar RB, 47 - | mov RCd, 2 - | cmp RB, LJ_TISTRUECOND - | sbb RCd, 0 - | shl RC, 47 - | not RC - | mov [BASE+RA*8], RC - | ins_next - break; - case BC_UNM: - | ins_AD // RA = dst, RD = src - | mov RB, [BASE+RD*8] - |.if DUALNUM - | checkint RB, >5 - | neg RBd - | jo >4 - | setint RB - |9: - | mov [BASE+RA*8], RB - | ins_next - |4: - | mov64 RB, U64x(41e00000,00000000) // 2^31. - | jmp <9 - |5: - | ja ->vmeta_unm - |.else - | checknum RB, ->vmeta_unm - |.endif - | mov64 RD, U64x(80000000,00000000) - | xor RB, RD - |.if DUALNUM - | jmp <9 - |.else - | mov [BASE+RA*8], RB - | ins_next - |.endif - break; - case BC_LEN: - | ins_AD // RA = dst, RD = src - | mov RD, [BASE+RD*8] - | checkstr RD, >2 - |.if DUALNUM - | mov RDd, dword STR:RD->len - |1: - | setint RD - | mov [BASE+RA*8], RD - |.else - | xorps xmm0, xmm0 - | cvtsi2sd xmm0, dword STR:RD->len - |1: - | movsd qword [BASE+RA*8], xmm0 - |.endif - | ins_next - |2: - | cmp ITYPEd, LJ_TTAB; jne ->vmeta_len - | mov TAB:CARG1, TAB:RD -#if LJ_52 - | mov TAB:RB, TAB:RD->metatable - | cmp TAB:RB, 0 - | jnz >9 - |3: -#endif - |->BC_LEN_Z: - | mov RB, BASE // Save BASE. - | call extern lj_tab_len // (GCtab *t) - | // Length of table returned in eax (RD). - |.if DUALNUM - | // Nothing to do. - |.else - | cvtsi2sd xmm0, RDd - |.endif - | mov BASE, RB // Restore BASE. - | movzx RAd, PC_RA - | jmp <1 -#if LJ_52 - |9: // Check for __len. - | test byte TAB:RB->nomm, 1<vmeta_len // 'no __len' flag NOT set: check. -#endif - break; - - /* -- Binary ops -------------------------------------------------------- */ - - |.macro ins_arithpre, sseins, ssereg - | ins_ABC - ||vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN); - ||switch (vk) { - ||case 0: - | checknumtp [BASE+RB*8], ->vmeta_arith_vn - | .if DUALNUM - | checknumtp [KBASE+RC*8], ->vmeta_arith_vn - | .endif - | movsd xmm0, qword [BASE+RB*8] - | sseins ssereg, qword [KBASE+RC*8] - || break; - ||case 1: - | checknumtp [BASE+RB*8], ->vmeta_arith_nv - | .if DUALNUM - | checknumtp [KBASE+RC*8], ->vmeta_arith_nv - | .endif - | movsd xmm0, qword [KBASE+RC*8] - | sseins ssereg, qword [BASE+RB*8] - || break; - ||default: - | checknumtp [BASE+RB*8], ->vmeta_arith_vv - | checknumtp [BASE+RC*8], ->vmeta_arith_vv - | movsd xmm0, qword [BASE+RB*8] - | sseins ssereg, qword [BASE+RC*8] - || break; - ||} - |.endmacro - | - |.macro ins_arithdn, intins - | ins_ABC - ||vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN); - ||switch (vk) { - ||case 0: - | mov RB, [BASE+RB*8] - | mov RC, [KBASE+RC*8] - | checkint RB, ->vmeta_arith_vno - | checkint RC, ->vmeta_arith_vno - | intins RBd, RCd; jo ->vmeta_arith_vno - || break; - ||case 1: - | mov RB, [BASE+RB*8] - | mov RC, [KBASE+RC*8] - | checkint RB, ->vmeta_arith_nvo - | checkint RC, ->vmeta_arith_nvo - | intins RCd, RBd; jo ->vmeta_arith_nvo - || break; - ||default: - | mov RB, [BASE+RB*8] - | mov RC, [BASE+RC*8] - | checkint RB, ->vmeta_arith_vvo - | checkint RC, ->vmeta_arith_vvo - | intins RBd, RCd; jo ->vmeta_arith_vvo - || break; - ||} - ||if (vk == 1) { - | setint RC - | mov [BASE+RA*8], RC - ||} else { - | setint RB - | mov [BASE+RA*8], RB - ||} - | ins_next - |.endmacro - | - |.macro ins_arithpost - | movsd qword [BASE+RA*8], xmm0 - |.endmacro - | - |.macro ins_arith, sseins - | ins_arithpre sseins, xmm0 - | ins_arithpost - | ins_next - |.endmacro - | - |.macro ins_arith, intins, sseins - |.if DUALNUM - | ins_arithdn intins - |.else - | ins_arith, sseins - |.endif - |.endmacro - - | // RA = dst, RB = src1 or num const, RC = src2 or num const - case BC_ADDVN: case BC_ADDNV: case BC_ADDVV: - | ins_arith add, addsd - break; - case BC_SUBVN: case BC_SUBNV: case BC_SUBVV: - | ins_arith sub, subsd - break; - case BC_MULVN: case BC_MULNV: case BC_MULVV: - | ins_arith imul, mulsd - break; - case BC_DIVVN: case BC_DIVNV: case BC_DIVVV: - | ins_arith divsd - break; - case BC_MODVN: - | ins_arithpre movsd, xmm1 - |->BC_MODVN_Z: - | call ->vm_mod - | ins_arithpost - | ins_next - break; - case BC_MODNV: case BC_MODVV: - | ins_arithpre movsd, xmm1 - | jmp ->BC_MODVN_Z // Avoid 3 copies. It's slow anyway. - break; - case BC_POW: - | ins_arithpre movsd, xmm1 - | mov RB, BASE - | call extern pow - | movzx RAd, PC_RA - | mov BASE, RB - | ins_arithpost - | ins_next - break; - - case BC_CAT: - | ins_ABC // RA = dst, RB = src_start, RC = src_end - | mov L:CARG1, SAVE_L - | mov L:CARG1->base, BASE - | lea CARG2, [BASE+RC*8] - | mov CARG3d, RCd - | sub CARG3d, RBd - |->BC_CAT_Z: - | mov L:RB, L:CARG1 - | mov SAVE_PC, PC - | call extern lj_meta_cat // (lua_State *L, TValue *top, int left) - | // NULL (finished) or TValue * (metamethod) returned in eax (RC). - | mov BASE, L:RB->base - | test RC, RC - | jnz ->vmeta_binop - | movzx RBd, PC_RB // Copy result to Stk[RA] from Stk[RB]. - | movzx RAd, PC_RA - | mov RC, [BASE+RB*8] - | mov [BASE+RA*8], RC - | ins_next - break; - - /* -- Constant ops ------------------------------------------------------ */ - - case BC_KSTR: - | ins_AND // RA = dst, RD = str const (~) - | mov RD, [KBASE+RD*8] - | settp RD, LJ_TSTR - | mov [BASE+RA*8], RD - | ins_next - break; - case BC_KCDATA: - |.if FFI - | ins_AND // RA = dst, RD = cdata const (~) - | mov RD, [KBASE+RD*8] - | settp RD, LJ_TCDATA - | mov [BASE+RA*8], RD - | ins_next - |.endif - break; - case BC_KSHORT: - | ins_AD // RA = dst, RD = signed int16 literal - |.if DUALNUM - | movsx RDd, RDW - | setint RD - | mov [BASE+RA*8], RD - |.else - | movsx RDd, RDW // Sign-extend literal. - | cvtsi2sd xmm0, RDd - | movsd qword [BASE+RA*8], xmm0 - |.endif - | ins_next - break; - case BC_KNUM: - | ins_AD // RA = dst, RD = num const - | movsd xmm0, qword [KBASE+RD*8] - | movsd qword [BASE+RA*8], xmm0 - | ins_next - break; - case BC_KPRI: - | ins_AD // RA = dst, RD = primitive type (~) - | shl RD, 47 - | not RD - | mov [BASE+RA*8], RD - | ins_next - break; - case BC_KNIL: - | ins_AD // RA = dst_start, RD = dst_end - | lea RA, [BASE+RA*8+8] - | lea RD, [BASE+RD*8] - | mov RB, LJ_TNIL - | mov [RA-8], RB // Sets minimum 2 slots. - |1: - | mov [RA], RB - | add RA, 8 - | cmp RA, RD - | jbe <1 - | ins_next - break; - - /* -- Upvalue and function ops ------------------------------------------ */ - - case BC_UGET: - | ins_AD // RA = dst, RD = upvalue # - | mov LFUNC:RB, [BASE-16] - | cleartp LFUNC:RB - | mov UPVAL:RB, [LFUNC:RB+RD*8+offsetof(GCfuncL, uvptr)] - | mov RB, UPVAL:RB->v - | mov RD, [RB] - | mov [BASE+RA*8], RD - | ins_next - break; - case BC_USETV: -#define TV2MARKOFS \ - ((int32_t)offsetof(GCupval, marked)-(int32_t)offsetof(GCupval, tv)) - | ins_AD // RA = upvalue #, RD = src - | mov LFUNC:RB, [BASE-16] - | cleartp LFUNC:RB - | mov UPVAL:RB, [LFUNC:RB+RA*8+offsetof(GCfuncL, uvptr)] - | cmp byte UPVAL:RB->closed, 0 - | mov RB, UPVAL:RB->v - | mov RA, [BASE+RD*8] - | mov [RB], RA - | jz >1 - | // Check barrier for closed upvalue. - | test byte [RB+TV2MARKOFS], LJ_GC_BLACK // isblack(uv) - | jnz >2 - |1: - | ins_next - | - |2: // Upvalue is black. Check if new value is collectable and white. - | mov RD, RA - | sar RD, 47 - | sub RDd, LJ_TISGCV - | cmp RDd, LJ_TNUMX - LJ_TISGCV // tvisgcv(v) - | jbe <1 - | cleartp GCOBJ:RA - | test byte GCOBJ:RA->gch.marked, LJ_GC_WHITES // iswhite(v) - | jz <1 - | // Crossed a write barrier. Move the barrier forward. - |.if not X64WIN - | mov CARG2, RB - | mov RB, BASE // Save BASE. - |.else - | xchg CARG2, RB // Save BASE (CARG2 == BASE). - |.endif - | lea GL:CARG1, [DISPATCH+GG_DISP2G] - | call extern lj_gc_barrieruv // (global_State *g, TValue *tv) - | mov BASE, RB // Restore BASE. - | jmp <1 - break; -#undef TV2MARKOFS - case BC_USETS: - | ins_AND // RA = upvalue #, RD = str const (~) - | mov LFUNC:RB, [BASE-16] - | cleartp LFUNC:RB - | mov UPVAL:RB, [LFUNC:RB+RA*8+offsetof(GCfuncL, uvptr)] - | mov STR:RA, [KBASE+RD*8] - | mov RD, UPVAL:RB->v - | settp STR:ITYPE, STR:RA, LJ_TSTR - | mov [RD], STR:ITYPE - | test byte UPVAL:RB->marked, LJ_GC_BLACK // isblack(uv) - | jnz >2 - |1: - | ins_next - | - |2: // Check if string is white and ensure upvalue is closed. - | test byte GCOBJ:RA->gch.marked, LJ_GC_WHITES // iswhite(str) - | jz <1 - | cmp byte UPVAL:RB->closed, 0 - | jz <1 - | // Crossed a write barrier. Move the barrier forward. - | mov RB, BASE // Save BASE (CARG2 == BASE). - | mov CARG2, RD - | lea GL:CARG1, [DISPATCH+GG_DISP2G] - | call extern lj_gc_barrieruv // (global_State *g, TValue *tv) - | mov BASE, RB // Restore BASE. - | jmp <1 - break; - case BC_USETN: - | ins_AD // RA = upvalue #, RD = num const - | mov LFUNC:RB, [BASE-16] - | cleartp LFUNC:RB - | movsd xmm0, qword [KBASE+RD*8] - | mov UPVAL:RB, [LFUNC:RB+RA*8+offsetof(GCfuncL, uvptr)] - | mov RA, UPVAL:RB->v - | movsd qword [RA], xmm0 - | ins_next - break; - case BC_USETP: - | ins_AD // RA = upvalue #, RD = primitive type (~) - | mov LFUNC:RB, [BASE-16] - | cleartp LFUNC:RB - | mov UPVAL:RB, [LFUNC:RB+RA*8+offsetof(GCfuncL, uvptr)] - | shl RD, 47 - | not RD - | mov RA, UPVAL:RB->v - | mov [RA], RD - | ins_next - break; - case BC_UCLO: - | ins_AD // RA = level, RD = target - | branchPC RD // Do this first to free RD. - | mov L:RB, SAVE_L - | cmp aword L:RB->openupval, 0 - | je >1 - | mov L:RB->base, BASE - | lea CARG2, [BASE+RA*8] // Caveat: CARG2 == BASE - | mov L:CARG1, L:RB // Caveat: CARG1 == RA - | call extern lj_func_closeuv // (lua_State *L, TValue *level) - | mov BASE, L:RB->base - |1: - | ins_next - break; - - case BC_FNEW: - | ins_AND // RA = dst, RD = proto const (~) (holding function prototype) - | mov L:RB, SAVE_L - | mov L:RB->base, BASE // Caveat: CARG2/CARG3 may be BASE. - | mov CARG3, [BASE-16] - | cleartp CARG3 - | mov CARG2, [KBASE+RD*8] // Fetch GCproto *. - | mov CARG1, L:RB - | mov SAVE_PC, PC - | // (lua_State *L, GCproto *pt, GCfuncL *parent) - | call extern lj_func_newL_gc - | // GCfuncL * returned in eax (RC). - | mov BASE, L:RB->base - | movzx RAd, PC_RA - | settp LFUNC:RC, LJ_TFUNC - | mov [BASE+RA*8], LFUNC:RC - | ins_next - break; - - /* -- Table ops --------------------------------------------------------- */ - - case BC_TNEW: - | ins_AD // RA = dst, RD = hbits|asize - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - | mov RA, [DISPATCH+DISPATCH_GL(gc.total)] - | cmp RA, [DISPATCH+DISPATCH_GL(gc.threshold)] - | mov SAVE_PC, PC - | jae >5 - |1: - | mov CARG3d, RDd - | and RDd, 0x7ff - | shr CARG3d, 11 - | cmp RDd, 0x7ff - | je >3 - |2: - | mov L:CARG1, L:RB - | mov CARG2d, RDd - | call extern lj_tab_new // (lua_State *L, int32_t asize, uint32_t hbits) - | // Table * returned in eax (RC). - | mov BASE, L:RB->base - | movzx RAd, PC_RA - | settp TAB:RC, LJ_TTAB - | mov [BASE+RA*8], TAB:RC - | ins_next - |3: // Turn 0x7ff into 0x801. - | mov RDd, 0x801 - | jmp <2 - |5: - | mov L:CARG1, L:RB - | call extern lj_gc_step_fixtop // (lua_State *L) - | movzx RDd, PC_RD - | jmp <1 - break; - case BC_TDUP: - | ins_AND // RA = dst, RD = table const (~) (holding template table) - | mov L:RB, SAVE_L - | mov RA, [DISPATCH+DISPATCH_GL(gc.total)] - | mov SAVE_PC, PC - | cmp RA, [DISPATCH+DISPATCH_GL(gc.threshold)] - | mov L:RB->base, BASE - | jae >3 - |2: - | mov TAB:CARG2, [KBASE+RD*8] // Caveat: CARG2 == BASE - | mov L:CARG1, L:RB // Caveat: CARG1 == RA - | call extern lj_tab_dup // (lua_State *L, Table *kt) - | // Table * returned in eax (RC). - | mov BASE, L:RB->base - | movzx RAd, PC_RA - | settp TAB:RC, LJ_TTAB - | mov [BASE+RA*8], TAB:RC - | ins_next - |3: - | mov L:CARG1, L:RB - | call extern lj_gc_step_fixtop // (lua_State *L) - | movzx RDd, PC_RD // Need to reload RD. - | not RD - | jmp <2 - break; - - case BC_GGET: - | ins_AND // RA = dst, RD = str const (~) - | mov LFUNC:RB, [BASE-16] - | cleartp LFUNC:RB - | mov TAB:RB, LFUNC:RB->env - | mov STR:RC, [KBASE+RD*8] - | jmp ->BC_TGETS_Z - break; - case BC_GSET: - | ins_AND // RA = src, RD = str const (~) - | mov LFUNC:RB, [BASE-16] - | cleartp LFUNC:RB - | mov TAB:RB, LFUNC:RB->env - | mov STR:RC, [KBASE+RD*8] - | jmp ->BC_TSETS_Z - break; - - case BC_TGETV: - | ins_ABC // RA = dst, RB = table, RC = key - | mov TAB:RB, [BASE+RB*8] - | mov RC, [BASE+RC*8] - | checktab TAB:RB, ->vmeta_tgetv - | - | // Integer key? - |.if DUALNUM - | checkint RC, >5 - |.else - | // Convert number to int and back and compare. - | checknum RC, >5 - | movd xmm0, RC - | cvttsd2si RCd, xmm0 - | cvtsi2sd xmm1, RCd - | ucomisd xmm0, xmm1 - | jne ->vmeta_tgetv // Generic numeric key? Use fallback. - |.endif - | cmp RCd, TAB:RB->asize // Takes care of unordered, too. - | jae ->vmeta_tgetv // Not in array part? Use fallback. - | shl RCd, 3 - | add RC, TAB:RB->array - | // Get array slot. - | mov ITYPE, [RC] - | cmp ITYPE, LJ_TNIL // Avoid overwriting RB in fastpath. - | je >2 - |1: - | mov [BASE+RA*8], ITYPE - | ins_next - | - |2: // Check for __index if table value is nil. - | mov TAB:TMPR, TAB:RB->metatable - | test TAB:TMPR, TAB:TMPR - | jz <1 - | test byte TAB:TMPR->nomm, 1<vmeta_tgetv // 'no __index' flag NOT set: check. - | jmp <1 - | - |5: // String key? - | cmp ITYPEd, LJ_TSTR; jne ->vmeta_tgetv - | cleartp STR:RC - | jmp ->BC_TGETS_Z - break; - case BC_TGETS: - | ins_ABC // RA = dst, RB = table, RC = str const (~) - | mov TAB:RB, [BASE+RB*8] - | not RC - | mov STR:RC, [KBASE+RC*8] - | checktab TAB:RB, ->vmeta_tgets - |->BC_TGETS_Z: // RB = GCtab *, RC = GCstr * - | mov TMPRd, TAB:RB->hmask - | and TMPRd, STR:RC->hash - | imul TMPRd, #NODE - | add NODE:TMPR, TAB:RB->node - | settp ITYPE, STR:RC, LJ_TSTR - |1: - | cmp NODE:TMPR->key, ITYPE - | jne >4 - | // Get node value. - | mov ITYPE, NODE:TMPR->val - | cmp ITYPE, LJ_TNIL - | je >5 // Key found, but nil value? - |2: - | mov [BASE+RA*8], ITYPE - | ins_next - | - |4: // Follow hash chain. - | mov NODE:TMPR, NODE:TMPR->next - | test NODE:TMPR, NODE:TMPR - | jnz <1 - | // End of hash chain: key not found, nil result. - | mov ITYPE, LJ_TNIL - | - |5: // Check for __index if table value is nil. - | mov TAB:TMPR, TAB:RB->metatable - | test TAB:TMPR, TAB:TMPR - | jz <2 // No metatable: done. - | test byte TAB:TMPR->nomm, 1<vmeta_tgets // Caveat: preserve STR:RC. - break; - case BC_TGETB: - | ins_ABC // RA = dst, RB = table, RC = byte literal - | mov TAB:RB, [BASE+RB*8] - | checktab TAB:RB, ->vmeta_tgetb - | cmp RCd, TAB:RB->asize - | jae ->vmeta_tgetb - | shl RCd, 3 - | add RC, TAB:RB->array - | // Get array slot. - | mov ITYPE, [RC] - | cmp ITYPE, LJ_TNIL - | je >2 - |1: - | mov [BASE+RA*8], ITYPE - | ins_next - | - |2: // Check for __index if table value is nil. - | mov TAB:TMPR, TAB:RB->metatable - | test TAB:TMPR, TAB:TMPR - | jz <1 - | test byte TAB:TMPR->nomm, 1<vmeta_tgetb // 'no __index' flag NOT set: check. - | jmp <1 - break; - case BC_TGETR: - | ins_ABC // RA = dst, RB = table, RC = key - | mov TAB:RB, [BASE+RB*8] - | cleartp TAB:RB - |.if DUALNUM - | mov RCd, dword [BASE+RC*8] - |.else - | cvttsd2si RCd, qword [BASE+RC*8] - |.endif - | cmp RCd, TAB:RB->asize - | jae ->vmeta_tgetr // Not in array part? Use fallback. - | shl RCd, 3 - | add RC, TAB:RB->array - | // Get array slot. - |->BC_TGETR_Z: - | mov ITYPE, [RC] - |->BC_TGETR2_Z: - | mov [BASE+RA*8], ITYPE - | ins_next - break; - - case BC_TSETV: - | ins_ABC // RA = src, RB = table, RC = key - | mov TAB:RB, [BASE+RB*8] - | mov RC, [BASE+RC*8] - | checktab TAB:RB, ->vmeta_tsetv - | - | // Integer key? - |.if DUALNUM - | checkint RC, >5 - |.else - | // Convert number to int and back and compare. - | checknum RC, >5 - | movd xmm0, RC - | cvttsd2si RCd, xmm0 - | cvtsi2sd xmm1, RCd - | ucomisd xmm0, xmm1 - | jne ->vmeta_tsetv // Generic numeric key? Use fallback. - |.endif - | cmp RCd, TAB:RB->asize // Takes care of unordered, too. - | jae ->vmeta_tsetv - | shl RCd, 3 - | add RC, TAB:RB->array - | cmp aword [RC], LJ_TNIL - | je >3 // Previous value is nil? - |1: - | test byte TAB:RB->marked, LJ_GC_BLACK // isblack(table) - | jnz >7 - |2: // Set array slot. - | mov RB, [BASE+RA*8] - | mov [RC], RB - | ins_next - | - |3: // Check for __newindex if previous value is nil. - | mov TAB:TMPR, TAB:RB->metatable - | test TAB:TMPR, TAB:TMPR - | jz <1 - | test byte TAB:TMPR->nomm, 1<vmeta_tsetv // 'no __newindex' flag NOT set: check. - | jmp <1 - | - |5: // String key? - | cmp ITYPEd, LJ_TSTR; jne ->vmeta_tsetv - | cleartp STR:RC - | jmp ->BC_TSETS_Z - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:RB, TMPR - | jmp <2 - break; - case BC_TSETS: - | ins_ABC // RA = src, RB = table, RC = str const (~) - | mov TAB:RB, [BASE+RB*8] - | not RC - | mov STR:RC, [KBASE+RC*8] - | checktab TAB:RB, ->vmeta_tsets - |->BC_TSETS_Z: // RB = GCtab *, RC = GCstr * - | mov TMPRd, TAB:RB->hmask - | and TMPRd, STR:RC->hash - | imul TMPRd, #NODE - | mov byte TAB:RB->nomm, 0 // Clear metamethod cache. - | add NODE:TMPR, TAB:RB->node - | settp ITYPE, STR:RC, LJ_TSTR - |1: - | cmp NODE:TMPR->key, ITYPE - | jne >5 - | // Ok, key found. Assumes: offsetof(Node, val) == 0 - | cmp aword [TMPR], LJ_TNIL - | je >4 // Previous value is nil? - |2: - | test byte TAB:RB->marked, LJ_GC_BLACK // isblack(table) - | jnz >7 - |3: // Set node value. - | mov ITYPE, [BASE+RA*8] - | mov [TMPR], ITYPE - | ins_next - | - |4: // Check for __newindex if previous value is nil. - | mov TAB:ITYPE, TAB:RB->metatable - | test TAB:ITYPE, TAB:ITYPE - | jz <2 - | test byte TAB:ITYPE->nomm, 1<vmeta_tsets // 'no __newindex' flag NOT set: check. - | jmp <2 - | - |5: // Follow hash chain. - | mov NODE:TMPR, NODE:TMPR->next - | test NODE:TMPR, NODE:TMPR - | jnz <1 - | // End of hash chain: key not found, add a new one. - | - | // But check for __newindex first. - | mov TAB:TMPR, TAB:RB->metatable - | test TAB:TMPR, TAB:TMPR - | jz >6 // No metatable: continue. - | test byte TAB:TMPR->nomm, 1<vmeta_tsets // 'no __newindex' flag NOT set: check. - |6: - | mov TMP1, ITYPE - | mov L:CARG1, SAVE_L - | mov L:CARG1->base, BASE - | lea CARG3, TMP1 - | mov CARG2, TAB:RB - | mov SAVE_PC, PC - | call extern lj_tab_newkey // (lua_State *L, GCtab *t, TValue *k) - | // Handles write barrier for the new key. TValue * returned in eax (RC). - | mov L:CARG1, SAVE_L - | mov BASE, L:CARG1->base - | mov TMPR, rax - | movzx RAd, PC_RA - | jmp <2 // Must check write barrier for value. - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:RB, ITYPE - | jmp <3 - break; - case BC_TSETB: - | ins_ABC // RA = src, RB = table, RC = byte literal - | mov TAB:RB, [BASE+RB*8] - | checktab TAB:RB, ->vmeta_tsetb - | cmp RCd, TAB:RB->asize - | jae ->vmeta_tsetb - | shl RCd, 3 - | add RC, TAB:RB->array - | cmp aword [RC], LJ_TNIL - | je >3 // Previous value is nil? - |1: - | test byte TAB:RB->marked, LJ_GC_BLACK // isblack(table) - | jnz >7 - |2: // Set array slot. - | mov ITYPE, [BASE+RA*8] - | mov [RC], ITYPE - | ins_next - | - |3: // Check for __newindex if previous value is nil. - | mov TAB:TMPR, TAB:RB->metatable - | test TAB:TMPR, TAB:TMPR - | jz <1 - | test byte TAB:TMPR->nomm, 1<vmeta_tsetb // 'no __newindex' flag NOT set: check. - | jmp <1 - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:RB, TMPR - | jmp <2 - break; - case BC_TSETR: - | ins_ABC // RA = src, RB = table, RC = key - | mov TAB:RB, [BASE+RB*8] - | cleartp TAB:RB - |.if DUALNUM - | mov RC, [BASE+RC*8] - |.else - | cvttsd2si RCd, qword [BASE+RC*8] - |.endif - | test byte TAB:RB->marked, LJ_GC_BLACK // isblack(table) - | jnz >7 - |2: - | cmp RCd, TAB:RB->asize - | jae ->vmeta_tsetr - | shl RCd, 3 - | add RC, TAB:RB->array - | // Set array slot. - |->BC_TSETR_Z: - | mov ITYPE, [BASE+RA*8] - | mov [RC], ITYPE - | ins_next - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:RB, TMPR - | jmp <2 - break; - - case BC_TSETM: - | ins_AD // RA = base (table at base-1), RD = num const (start index) - |1: - | mov TMPRd, dword [KBASE+RD*8] // Integer constant is in lo-word. - | lea RA, [BASE+RA*8] - | mov TAB:RB, [RA-8] // Guaranteed to be a table. - | cleartp TAB:RB - | test byte TAB:RB->marked, LJ_GC_BLACK // isblack(table) - | jnz >7 - |2: - | mov RDd, MULTRES - | sub RDd, 1 - | jz >4 // Nothing to copy? - | add RDd, TMPRd // Compute needed size. - | cmp RDd, TAB:RB->asize - | ja >5 // Doesn't fit into array part? - | sub RDd, TMPRd - | shl TMPRd, 3 - | add TMPR, TAB:RB->array - |3: // Copy result slots to table. - | mov RB, [RA] - | add RA, 8 - | mov [TMPR], RB - | add TMPR, 8 - | sub RDd, 1 - | jnz <3 - |4: - | ins_next - | - |5: // Need to resize array part. - | mov L:CARG1, SAVE_L - | mov L:CARG1->base, BASE // Caveat: CARG2/CARG3 may be BASE. - | mov CARG2, TAB:RB - | mov CARG3d, RDd - | mov L:RB, L:CARG1 - | mov SAVE_PC, PC - | call extern lj_tab_reasize // (lua_State *L, GCtab *t, int nasize) - | mov BASE, L:RB->base - | movzx RAd, PC_RA // Restore RA. - | movzx RDd, PC_RD // Restore RD. - | jmp <1 // Retry. - | - |7: // Possible table write barrier for any value. Skip valiswhite check. - | barrierback TAB:RB, RD - | jmp <2 - break; - - /* -- Calls and vararg handling ----------------------------------------- */ - - case BC_CALL: case BC_CALLM: - | ins_A_C // RA = base, (RB = nresults+1,) RC = nargs+1 | extra_nargs - if (op == BC_CALLM) { - | add NARGS:RDd, MULTRES - } - | mov LFUNC:RB, [BASE+RA*8] - | checkfunc LFUNC:RB, ->vmeta_call_ra - | lea BASE, [BASE+RA*8+16] - | ins_call - break; - - case BC_CALLMT: - | ins_AD // RA = base, RD = extra_nargs - | add NARGS:RDd, MULTRES - | // Fall through. Assumes BC_CALLT follows and ins_AD is a no-op. - break; - case BC_CALLT: - | ins_AD // RA = base, RD = nargs+1 - | lea RA, [BASE+RA*8+16] - | mov KBASE, BASE // Use KBASE for move + vmeta_call hint. - | mov LFUNC:RB, [RA-16] - | checktp_nc LFUNC:RB, LJ_TFUNC, ->vmeta_call - |->BC_CALLT_Z: - | mov PC, [BASE-8] - | test PCd, FRAME_TYPE - | jnz >7 - |1: - | mov [BASE-16], LFUNC:RB // Copy func+tag down, reloaded below. - | mov MULTRES, NARGS:RDd - | sub NARGS:RDd, 1 - | jz >3 - |2: // Move args down. - | mov RB, [RA] - | add RA, 8 - | mov [KBASE], RB - | add KBASE, 8 - | sub NARGS:RDd, 1 - | jnz <2 - | - | mov LFUNC:RB, [BASE-16] - |3: - | cleartp LFUNC:RB - | mov NARGS:RDd, MULTRES - | cmp byte LFUNC:RB->ffid, 1 // (> FF_C) Calling a fast function? - | ja >5 - |4: - | ins_callt - | - |5: // Tailcall to a fast function. - | test PCd, FRAME_TYPE // Lua frame below? - | jnz <4 - | movzx RAd, PC_RA - | neg RA - | mov LFUNC:KBASE, [BASE+RA*8-32] // Need to prepare KBASE. - | cleartp LFUNC:KBASE - | mov KBASE, LFUNC:KBASE->pc - | mov KBASE, [KBASE+PC2PROTO(k)] - | jmp <4 - | - |7: // Tailcall from a vararg function. - | sub PC, FRAME_VARG - | test PCd, FRAME_TYPEP - | jnz >8 // Vararg frame below? - | sub BASE, PC // Need to relocate BASE/KBASE down. - | mov KBASE, BASE - | mov PC, [BASE-8] - | jmp <1 - |8: - | add PCd, FRAME_VARG - | jmp <1 - break; - - case BC_ITERC: - | ins_A // RA = base, (RB = nresults+1,) RC = nargs+1 (2+1) - | lea RA, [BASE+RA*8+16] // fb = base+2 - | mov RB, [RA-32] // Copy state. fb[0] = fb[-4]. - | mov RC, [RA-24] // Copy control var. fb[1] = fb[-3]. - | mov [RA], RB - | mov [RA+8], RC - | mov LFUNC:RB, [RA-40] // Copy callable. fb[-2] = fb[-5] - | mov [RA-16], LFUNC:RB - | mov NARGS:RDd, 2+1 // Handle like a regular 2-arg call. - | checkfunc LFUNC:RB, ->vmeta_call - | mov BASE, RA - | ins_call - break; - - case BC_ITERN: - | ins_A // RA = base, (RB = nresults+1, RC = nargs+1 (2+1)) - |.if JIT - | // NYI: add hotloop, record BC_ITERN. - |.endif - | mov TAB:RB, [BASE+RA*8-16] - | cleartp TAB:RB - | mov RCd, [BASE+RA*8-8] // Get index from control var. - | mov TMPRd, TAB:RB->asize - | add PC, 4 - | mov ITYPE, TAB:RB->array - |1: // Traverse array part. - | cmp RCd, TMPRd; jae >5 // Index points after array part? - | cmp aword [ITYPE+RC*8], LJ_TNIL; je >4 - |.if not DUALNUM - | cvtsi2sd xmm0, RCd - |.endif - | // Copy array slot to returned value. - | mov RB, [ITYPE+RC*8] - | mov [BASE+RA*8+8], RB - | // Return array index as a numeric key. - |.if DUALNUM - | setint ITYPE, RC - | mov [BASE+RA*8], ITYPE - |.else - | movsd qword [BASE+RA*8], xmm0 - |.endif - | add RCd, 1 - | mov [BASE+RA*8-8], RCd // Update control var. - |2: - | movzx RDd, PC_RD // Get target from ITERL. - | branchPC RD - |3: - | ins_next - | - |4: // Skip holes in array part. - | add RCd, 1 - | jmp <1 - | - |5: // Traverse hash part. - | sub RCd, TMPRd - |6: - | cmp RCd, TAB:RB->hmask; ja <3 // End of iteration? Branch to ITERL+1. - | imul ITYPEd, RCd, #NODE - | add NODE:ITYPE, TAB:RB->node - | cmp aword NODE:ITYPE->val, LJ_TNIL; je >7 - | lea TMPRd, [RCd+TMPRd+1] - | // Copy key and value from hash slot. - | mov RB, NODE:ITYPE->key - | mov RC, NODE:ITYPE->val - | mov [BASE+RA*8], RB - | mov [BASE+RA*8+8], RC - | mov [BASE+RA*8-8], TMPRd - | jmp <2 - | - |7: // Skip holes in hash part. - | add RCd, 1 - | jmp <6 - break; - - case BC_ISNEXT: - | ins_AD // RA = base, RD = target (points to ITERN) - | mov CFUNC:RB, [BASE+RA*8-24] - | checkfunc CFUNC:RB, >5 - | checktptp [BASE+RA*8-16], LJ_TTAB, >5 - | cmp aword [BASE+RA*8-8], LJ_TNIL; jne >5 - | cmp byte CFUNC:RB->ffid, FF_next_N; jne >5 - | branchPC RD - | mov64 TMPR, U64x(fffe7fff, 00000000) - | mov [BASE+RA*8-8], TMPR // Initialize control var. - |1: - | ins_next - |5: // Despecialize bytecode if any of the checks fail. - | mov PC_OP, BC_JMP - | branchPC RD - | mov byte [PC], BC_ITERC - | jmp <1 - break; - - case BC_VARG: - | ins_ABC // RA = base, RB = nresults+1, RC = numparams - | lea TMPR, [BASE+RC*8+(16+FRAME_VARG)] - | lea RA, [BASE+RA*8] - | sub TMPR, [BASE-8] - | // Note: TMPR may now be even _above_ BASE if nargs was < numparams. - | test RB, RB - | jz >5 // Copy all varargs? - | lea RB, [RA+RB*8-8] - | cmp TMPR, BASE // No vararg slots? - | jnb >2 - |1: // Copy vararg slots to destination slots. - | mov RC, [TMPR-16] - | add TMPR, 8 - | mov [RA], RC - | add RA, 8 - | cmp RA, RB // All destination slots filled? - | jnb >3 - | cmp TMPR, BASE // No more vararg slots? - | jb <1 - |2: // Fill up remainder with nil. - | mov aword [RA], LJ_TNIL - | add RA, 8 - | cmp RA, RB - | jb <2 - |3: - | ins_next - | - |5: // Copy all varargs. - | mov MULTRES, 1 // MULTRES = 0+1 - | mov RC, BASE - | sub RC, TMPR - | jbe <3 // No vararg slots? - | mov RBd, RCd - | shr RBd, 3 - | add RBd, 1 - | mov MULTRES, RBd // MULTRES = #varargs+1 - | mov L:RB, SAVE_L - | add RC, RA - | cmp RC, L:RB->maxstack - | ja >7 // Need to grow stack? - |6: // Copy all vararg slots. - | mov RC, [TMPR-16] - | add TMPR, 8 - | mov [RA], RC - | add RA, 8 - | cmp TMPR, BASE // No more vararg slots? - | jb <6 - | jmp <3 - | - |7: // Grow stack for varargs. - | mov L:RB->base, BASE - | mov L:RB->top, RA - | mov SAVE_PC, PC - | sub TMPR, BASE // Need delta, because BASE may change. - | mov TMP1hi, TMPRd - | mov CARG2d, MULTRES - | sub CARG2d, 1 - | mov CARG1, L:RB - | call extern lj_state_growstack // (lua_State *L, int n) - | mov BASE, L:RB->base - | movsxd TMPR, TMP1hi - | mov RA, L:RB->top - | add TMPR, BASE - | jmp <6 - break; - - /* -- Returns ----------------------------------------------------------- */ - - case BC_RETM: - | ins_AD // RA = results, RD = extra_nresults - | add RDd, MULTRES // MULTRES >=1, so RD >=1. - | // Fall through. Assumes BC_RET follows and ins_AD is a no-op. - break; - - case BC_RET: case BC_RET0: case BC_RET1: - | ins_AD // RA = results, RD = nresults+1 - if (op != BC_RET0) { - | shl RAd, 3 - } - |1: - | mov PC, [BASE-8] - | mov MULTRES, RDd // Save nresults+1. - | test PCd, FRAME_TYPE // Check frame type marker. - | jnz >7 // Not returning to a fixarg Lua func? - switch (op) { - case BC_RET: - |->BC_RET_Z: - | mov KBASE, BASE // Use KBASE for result move. - | sub RDd, 1 - | jz >3 - |2: // Move results down. - | mov RB, [KBASE+RA] - | mov [KBASE-16], RB - | add KBASE, 8 - | sub RDd, 1 - | jnz <2 - |3: - | mov RDd, MULTRES // Note: MULTRES may be >255. - | movzx RBd, PC_RB // So cannot compare with RDL! - |5: - | cmp RBd, RDd // More results expected? - | ja >6 - break; - case BC_RET1: - | mov RB, [BASE+RA] - | mov [BASE-16], RB - /* fallthrough */ - case BC_RET0: - |5: - | cmp PC_RB, RDL // More results expected? - | ja >6 - default: - break; - } - | movzx RAd, PC_RA - | neg RA - | lea BASE, [BASE+RA*8-16] // base = base - (RA+2)*8 - | mov LFUNC:KBASE, [BASE-16] - | cleartp LFUNC:KBASE - | mov KBASE, LFUNC:KBASE->pc - | mov KBASE, [KBASE+PC2PROTO(k)] - | ins_next - | - |6: // Fill up results with nil. - if (op == BC_RET) { - | mov aword [KBASE-16], LJ_TNIL // Note: relies on shifted base. - | add KBASE, 8 - } else { - | mov aword [BASE+RD*8-24], LJ_TNIL - } - | add RD, 1 - | jmp <5 - | - |7: // Non-standard return case. - | lea RB, [PC-FRAME_VARG] - | test RBd, FRAME_TYPEP - | jnz ->vm_return - | // Return from vararg function: relocate BASE down and RA up. - | sub BASE, RB - if (op != BC_RET0) { - | add RA, RB - } - | jmp <1 - break; - - /* -- Loops and branches ------------------------------------------------ */ - - |.define FOR_IDX, [RA] - |.define FOR_STOP, [RA+8] - |.define FOR_STEP, [RA+16] - |.define FOR_EXT, [RA+24] - - case BC_FORL: - |.if JIT - | hotloop RBd - |.endif - | // Fall through. Assumes BC_IFORL follows and ins_AJ is a no-op. - break; - - case BC_JFORI: - case BC_JFORL: -#if !LJ_HASJIT - break; -#endif - case BC_FORI: - case BC_IFORL: - vk = (op == BC_IFORL || op == BC_JFORL); - | ins_AJ // RA = base, RD = target (after end of loop or start of loop) - | lea RA, [BASE+RA*8] - if (LJ_DUALNUM) { - | mov RB, FOR_IDX - | checkint RB, >9 - | mov TMPR, FOR_STOP - if (!vk) { - | checkint TMPR, ->vmeta_for - | mov ITYPE, FOR_STEP - | test ITYPEd, ITYPEd; js >5 - | sar ITYPE, 47; - | cmp ITYPEd, LJ_TISNUM; jne ->vmeta_for - } else { -#ifdef LUA_USE_ASSERT - | checkinttp FOR_STOP, ->assert_bad_for_arg_type - | checkinttp FOR_STEP, ->assert_bad_for_arg_type -#endif - | mov ITYPE, FOR_STEP - | test ITYPEd, ITYPEd; js >5 - | add RBd, ITYPEd; jo >1 - | setint RB - | mov FOR_IDX, RB - } - | cmp RBd, TMPRd - | mov FOR_EXT, RB - if (op == BC_FORI) { - | jle >7 - |1: - |6: - | branchPC RD - } else if (op == BC_JFORI) { - | branchPC RD - | movzx RDd, PC_RD - | jle =>BC_JLOOP - |1: - |6: - } else if (op == BC_IFORL) { - | jg >7 - |6: - | branchPC RD - |1: - } else { - | jle =>BC_JLOOP - |1: - |6: - } - |7: - | ins_next - | - |5: // Invert check for negative step. - if (!vk) { - | sar ITYPE, 47; - | cmp ITYPEd, LJ_TISNUM; jne ->vmeta_for - } else { - | add RBd, ITYPEd; jo <1 - | setint RB - | mov FOR_IDX, RB - } - | cmp RBd, TMPRd - | mov FOR_EXT, RB - if (op == BC_FORI) { - | jge <7 - } else if (op == BC_JFORI) { - | branchPC RD - | movzx RDd, PC_RD - | jge =>BC_JLOOP - } else if (op == BC_IFORL) { - | jl <7 - } else { - | jge =>BC_JLOOP - } - | jmp <6 - |9: // Fallback to FP variant. - if (!vk) { - | jae ->vmeta_for - } - } else if (!vk) { - | checknumtp FOR_IDX, ->vmeta_for - } - if (!vk) { - | checknumtp FOR_STOP, ->vmeta_for - } else { -#ifdef LUA_USE_ASSERT - | checknumtp FOR_STOP, ->assert_bad_for_arg_type - | checknumtp FOR_STEP, ->assert_bad_for_arg_type -#endif - } - | mov RB, FOR_STEP - if (!vk) { - | checknum RB, ->vmeta_for - } - | movsd xmm0, qword FOR_IDX - | movsd xmm1, qword FOR_STOP - if (vk) { - | addsd xmm0, qword FOR_STEP - | movsd qword FOR_IDX, xmm0 - | test RB, RB; js >3 - } else { - | jl >3 - } - | ucomisd xmm1, xmm0 - |1: - | movsd qword FOR_EXT, xmm0 - if (op == BC_FORI) { - |.if DUALNUM - | jnb <7 - |.else - | jnb >2 - | branchPC RD - |.endif - } else if (op == BC_JFORI) { - | branchPC RD - | movzx RDd, PC_RD - | jnb =>BC_JLOOP - } else if (op == BC_IFORL) { - |.if DUALNUM - | jb <7 - |.else - | jb >2 - | branchPC RD - |.endif - } else { - | jnb =>BC_JLOOP - } - |.if DUALNUM - | jmp <6 - |.else - |2: - | ins_next - |.endif - | - |3: // Invert comparison if step is negative. - | ucomisd xmm0, xmm1 - | jmp <1 - break; - - case BC_ITERL: - |.if JIT - | hotloop RBd - |.endif - | // Fall through. Assumes BC_IITERL follows and ins_AJ is a no-op. - break; - - case BC_JITERL: -#if !LJ_HASJIT - break; -#endif - case BC_IITERL: - | ins_AJ // RA = base, RD = target - | lea RA, [BASE+RA*8] - | mov RB, [RA] - | cmp RB, LJ_TNIL; je >1 // Stop if iterator returned nil. - if (op == BC_JITERL) { - | mov [RA-8], RB - | jmp =>BC_JLOOP - } else { - | branchPC RD // Otherwise save control var + branch. - | mov [RA-8], RB - } - |1: - | ins_next - break; - - case BC_LOOP: - | ins_A // RA = base, RD = target (loop extent) - | // Note: RA/RD is only used by trace recorder to determine scope/extent - | // This opcode does NOT jump, it's only purpose is to detect a hot loop. - |.if JIT - | hotloop RBd - |.endif - | // Fall through. Assumes BC_ILOOP follows and ins_A is a no-op. - break; - - case BC_ILOOP: - | ins_A // RA = base, RD = target (loop extent) - | ins_next - break; - - case BC_JLOOP: - |.if JIT - | ins_AD // RA = base (ignored), RD = traceno - | mov RA, [DISPATCH+DISPATCH_J(trace)] - | mov TRACE:RD, [RA+RD*8] - | mov RD, TRACE:RD->mcode - | mov L:RB, SAVE_L - | mov [DISPATCH+DISPATCH_GL(jit_base)], BASE - | mov [DISPATCH+DISPATCH_GL(tmpbuf.L)], L:RB - | // Save additional callee-save registers only used in compiled code. - |.if X64WIN - | mov CSAVE_4, r12 - | mov CSAVE_3, r13 - | mov CSAVE_2, r14 - | mov CSAVE_1, r15 - | mov RA, rsp - | sub rsp, 10*16+4*8 - | movdqa [RA-1*16], xmm6 - | movdqa [RA-2*16], xmm7 - | movdqa [RA-3*16], xmm8 - | movdqa [RA-4*16], xmm9 - | movdqa [RA-5*16], xmm10 - | movdqa [RA-6*16], xmm11 - | movdqa [RA-7*16], xmm12 - | movdqa [RA-8*16], xmm13 - | movdqa [RA-9*16], xmm14 - | movdqa [RA-10*16], xmm15 - |.else - | sub rsp, 16 - | mov [rsp+16], r12 - | mov [rsp+8], r13 - |.endif - | jmp RD - |.endif - break; - - case BC_JMP: - | ins_AJ // RA = unused, RD = target - | branchPC RD - | ins_next - break; - - /* -- Function headers -------------------------------------------------- */ - - /* - ** Reminder: A function may be called with func/args above L->maxstack, - ** i.e. occupying EXTRA_STACK slots. And vmeta_call may add one extra slot, - ** too. This means all FUNC* ops (including fast functions) must check - ** for stack overflow _before_ adding more slots! - */ - - case BC_FUNCF: - |.if JIT - | hotcall RBd - |.endif - case BC_FUNCV: /* NYI: compiled vararg functions. */ - | // Fall through. Assumes BC_IFUNCF/BC_IFUNCV follow and ins_AD is a no-op. - break; - - case BC_JFUNCF: -#if !LJ_HASJIT - break; -#endif - case BC_IFUNCF: - | ins_AD // BASE = new base, RA = framesize, RD = nargs+1 - | mov KBASE, [PC-4+PC2PROTO(k)] - | mov L:RB, SAVE_L - | lea RA, [BASE+RA*8] // Top of frame. - | cmp RA, L:RB->maxstack - | ja ->vm_growstack_f - | movzx RAd, byte [PC-4+PC2PROTO(numparams)] - | cmp NARGS:RDd, RAd // Check for missing parameters. - | jbe >3 - |2: - if (op == BC_JFUNCF) { - | movzx RDd, PC_RD - | jmp =>BC_JLOOP - } else { - | ins_next - } - | - |3: // Clear missing parameters. - | mov aword [BASE+NARGS:RD*8-8], LJ_TNIL - | add NARGS:RDd, 1 - | cmp NARGS:RDd, RAd - | jbe <3 - | jmp <2 - break; - - case BC_JFUNCV: -#if !LJ_HASJIT - break; -#endif - | int3 // NYI: compiled vararg functions - break; /* NYI: compiled vararg functions. */ - - case BC_IFUNCV: - | ins_AD // BASE = new base, RA = framesize, RD = nargs+1 - | lea RBd, [NARGS:RD*8+FRAME_VARG+8] - | lea RD, [BASE+NARGS:RD*8+8] - | mov LFUNC:KBASE, [BASE-16] - | mov [RD-8], RB // Store delta + FRAME_VARG. - | mov [RD-16], LFUNC:KBASE // Store copy of LFUNC. - | mov L:RB, SAVE_L - | lea RA, [RD+RA*8] - | cmp RA, L:RB->maxstack - | ja ->vm_growstack_v // Need to grow stack. - | mov RA, BASE - | mov BASE, RD - | movzx RBd, byte [PC-4+PC2PROTO(numparams)] - | test RBd, RBd - | jz >2 - | add RA, 8 - |1: // Copy fixarg slots up to new frame. - | add RA, 8 - | cmp RA, BASE - | jnb >3 // Less args than parameters? - | mov KBASE, [RA-16] - | mov [RD], KBASE - | add RD, 8 - | mov aword [RA-16], LJ_TNIL // Clear old fixarg slot (help the GC). - | sub RBd, 1 - | jnz <1 - |2: - if (op == BC_JFUNCV) { - | movzx RDd, PC_RD - | jmp =>BC_JLOOP - } else { - | mov KBASE, [PC-4+PC2PROTO(k)] - | ins_next - } - | - |3: // Clear missing parameters. - | mov aword [RD], LJ_TNIL - | add RD, 8 - | sub RBd, 1 - | jnz <3 - | jmp <2 - break; - - case BC_FUNCC: - case BC_FUNCCW: - | ins_AD // BASE = new base, RA = ins RA|RD (unused), RD = nargs+1 - | mov CFUNC:RB, [BASE-16] - | cleartp CFUNC:RB - | mov KBASE, CFUNC:RB->f - | mov L:RB, SAVE_L - | lea RD, [BASE+NARGS:RD*8-8] - | mov L:RB->base, BASE - | lea RA, [RD+8*LUA_MINSTACK] - | cmp RA, L:RB->maxstack - | mov L:RB->top, RD - if (op == BC_FUNCC) { - | mov CARG1, L:RB // Caveat: CARG1 may be RA. - } else { - | mov CARG2, KBASE - | mov CARG1, L:RB // Caveat: CARG1 may be RA. - } - | ja ->vm_growstack_c // Need to grow stack. - | set_vmstate C - if (op == BC_FUNCC) { - | call KBASE // (lua_State *L) - } else { - | // (lua_State *L, lua_CFunction f) - | call aword [DISPATCH+DISPATCH_GL(wrapf)] - } - | // nresults returned in eax (RD). - | mov BASE, L:RB->base - | mov [DISPATCH+DISPATCH_GL(cur_L)], L:RB - | set_vmstate INTERP - | lea RA, [BASE+RD*8] - | neg RA - | add RA, L:RB->top // RA = (L->top-(L->base+nresults))*8 - | mov PC, [BASE-8] // Fetch PC of caller. - | jmp ->vm_returnc - break; - - /* ---------------------------------------------------------------------- */ - - default: - fprintf(stderr, "Error: undefined opcode BC_%s\n", bc_names[op]); - exit(2); - break; - } -} - -static int build_backend(BuildCtx *ctx) -{ - int op; - dasm_growpc(Dst, BC__MAX); - build_subroutines(ctx); - |.code_op - for (op = 0; op < BC__MAX; op++) - build_ins(ctx, (BCOp)op, op); - return BC__MAX; -} - -/* Emit pseudo frame-info for all assembler functions. */ -static void emit_asm_debug(BuildCtx *ctx) -{ - int fcofs = (int)((uint8_t *)ctx->glob[GLOB_vm_ffi_call] - ctx->code); - switch (ctx->mode) { - case BUILD_elfasm: - fprintf(ctx->fp, "\t.section .debug_frame,\"\",@progbits\n"); - fprintf(ctx->fp, - ".Lframe0:\n" - "\t.long .LECIE0-.LSCIE0\n" - ".LSCIE0:\n" - "\t.long 0xffffffff\n" - "\t.byte 0x1\n" - "\t.string \"\"\n" - "\t.uleb128 0x1\n" - "\t.sleb128 -8\n" - "\t.byte 0x10\n" - "\t.byte 0xc\n\t.uleb128 0x7\n\t.uleb128 8\n" - "\t.byte 0x80+0x10\n\t.uleb128 0x1\n" - "\t.align 8\n" - ".LECIE0:\n\n"); - fprintf(ctx->fp, - ".LSFDE0:\n" - "\t.long .LEFDE0-.LASFDE0\n" - ".LASFDE0:\n" - "\t.long .Lframe0\n" - "\t.quad .Lbegin\n" - "\t.quad %d\n" - "\t.byte 0xe\n\t.uleb128 %d\n" /* def_cfa_offset */ - "\t.byte 0x86\n\t.uleb128 0x2\n" /* offset rbp */ - "\t.byte 0x83\n\t.uleb128 0x3\n" /* offset rbx */ - "\t.byte 0x8f\n\t.uleb128 0x4\n" /* offset r15 */ - "\t.byte 0x8e\n\t.uleb128 0x5\n" /* offset r14 */ -#if LJ_NO_UNWIND - "\t.byte 0x8d\n\t.uleb128 0x6\n" /* offset r13 */ - "\t.byte 0x8c\n\t.uleb128 0x7\n" /* offset r12 */ -#endif - "\t.align 8\n" - ".LEFDE0:\n\n", fcofs, CFRAME_SIZE); -#if LJ_HASFFI - fprintf(ctx->fp, - ".LSFDE1:\n" - "\t.long .LEFDE1-.LASFDE1\n" - ".LASFDE1:\n" - "\t.long .Lframe0\n" - "\t.quad lj_vm_ffi_call\n" - "\t.quad %d\n" - "\t.byte 0xe\n\t.uleb128 16\n" /* def_cfa_offset */ - "\t.byte 0x86\n\t.uleb128 0x2\n" /* offset rbp */ - "\t.byte 0xd\n\t.uleb128 0x6\n" /* def_cfa_register rbp */ - "\t.byte 0x83\n\t.uleb128 0x3\n" /* offset rbx */ - "\t.align 8\n" - ".LEFDE1:\n\n", (int)ctx->codesz - fcofs); -#endif -#if !LJ_NO_UNWIND -#if (defined(__sun__) && defined(__svr4__)) - fprintf(ctx->fp, "\t.section .eh_frame,\"a\",@unwind\n"); -#else - fprintf(ctx->fp, "\t.section .eh_frame,\"a\",@progbits\n"); -#endif - fprintf(ctx->fp, - ".Lframe1:\n" - "\t.long .LECIE1-.LSCIE1\n" - ".LSCIE1:\n" - "\t.long 0\n" - "\t.byte 0x1\n" - "\t.string \"zPR\"\n" - "\t.uleb128 0x1\n" - "\t.sleb128 -8\n" - "\t.byte 0x10\n" - "\t.uleb128 6\n" /* augmentation length */ - "\t.byte 0x1b\n" /* pcrel|sdata4 */ - "\t.long lj_err_unwind_dwarf-.\n" - "\t.byte 0x1b\n" /* pcrel|sdata4 */ - "\t.byte 0xc\n\t.uleb128 0x7\n\t.uleb128 8\n" - "\t.byte 0x80+0x10\n\t.uleb128 0x1\n" - "\t.align 8\n" - ".LECIE1:\n\n"); - fprintf(ctx->fp, - ".LSFDE2:\n" - "\t.long .LEFDE2-.LASFDE2\n" - ".LASFDE2:\n" - "\t.long .LASFDE2-.Lframe1\n" - "\t.long .Lbegin-.\n" - "\t.long %d\n" - "\t.uleb128 0\n" /* augmentation length */ - "\t.byte 0xe\n\t.uleb128 %d\n" /* def_cfa_offset */ - "\t.byte 0x86\n\t.uleb128 0x2\n" /* offset rbp */ - "\t.byte 0x83\n\t.uleb128 0x3\n" /* offset rbx */ - "\t.byte 0x8f\n\t.uleb128 0x4\n" /* offset r15 */ - "\t.byte 0x8e\n\t.uleb128 0x5\n" /* offset r14 */ - "\t.align 8\n" - ".LEFDE2:\n\n", fcofs, CFRAME_SIZE); -#if LJ_HASFFI - fprintf(ctx->fp, - ".Lframe2:\n" - "\t.long .LECIE2-.LSCIE2\n" - ".LSCIE2:\n" - "\t.long 0\n" - "\t.byte 0x1\n" - "\t.string \"zR\"\n" - "\t.uleb128 0x1\n" - "\t.sleb128 -8\n" - "\t.byte 0x10\n" - "\t.uleb128 1\n" /* augmentation length */ - "\t.byte 0x1b\n" /* pcrel|sdata4 */ - "\t.byte 0xc\n\t.uleb128 0x7\n\t.uleb128 8\n" - "\t.byte 0x80+0x10\n\t.uleb128 0x1\n" - "\t.align 8\n" - ".LECIE2:\n\n"); - fprintf(ctx->fp, - ".LSFDE3:\n" - "\t.long .LEFDE3-.LASFDE3\n" - ".LASFDE3:\n" - "\t.long .LASFDE3-.Lframe2\n" - "\t.long lj_vm_ffi_call-.\n" - "\t.long %d\n" - "\t.uleb128 0\n" /* augmentation length */ - "\t.byte 0xe\n\t.uleb128 16\n" /* def_cfa_offset */ - "\t.byte 0x86\n\t.uleb128 0x2\n" /* offset rbp */ - "\t.byte 0xd\n\t.uleb128 0x6\n" /* def_cfa_register rbp */ - "\t.byte 0x83\n\t.uleb128 0x3\n" /* offset rbx */ - "\t.align 8\n" - ".LEFDE3:\n\n", (int)ctx->codesz - fcofs); -#endif -#endif - break; -#if !LJ_NO_UNWIND - /* Mental note: never let Apple design an assembler. - ** Or a linker. Or a plastic case. But I digress. - */ - case BUILD_machasm: { -#if LJ_HASFFI - int fcsize = 0; -#endif - int i; - fprintf(ctx->fp, "\t.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support\n"); - fprintf(ctx->fp, - "EH_frame1:\n" - "\t.set L$set$x,LECIEX-LSCIEX\n" - "\t.long L$set$x\n" - "LSCIEX:\n" - "\t.long 0\n" - "\t.byte 0x1\n" - "\t.ascii \"zPR\\0\"\n" - "\t.byte 0x1\n" - "\t.byte 128-8\n" - "\t.byte 0x10\n" - "\t.byte 6\n" /* augmentation length */ - "\t.byte 0x9b\n" /* indirect|pcrel|sdata4 */ - "\t.long _lj_err_unwind_dwarf+4@GOTPCREL\n" - "\t.byte 0x1b\n" /* pcrel|sdata4 */ - "\t.byte 0xc\n\t.byte 0x7\n\t.byte 8\n" - "\t.byte 0x80+0x10\n\t.byte 0x1\n" - "\t.align 3\n" - "LECIEX:\n\n"); - for (i = 0; i < ctx->nsym; i++) { - const char *name = ctx->sym[i].name; - int32_t size = ctx->sym[i+1].ofs - ctx->sym[i].ofs; - if (size == 0) continue; -#if LJ_HASFFI - if (!strcmp(name, "_lj_vm_ffi_call")) { fcsize = size; continue; } -#endif - fprintf(ctx->fp, - "%s.eh:\n" - "LSFDE%d:\n" - "\t.set L$set$%d,LEFDE%d-LASFDE%d\n" - "\t.long L$set$%d\n" - "LASFDE%d:\n" - "\t.long LASFDE%d-EH_frame1\n" - "\t.long %s-.\n" - "\t.long %d\n" - "\t.byte 0\n" /* augmentation length */ - "\t.byte 0xe\n\t.byte %d\n" /* def_cfa_offset */ - "\t.byte 0x86\n\t.byte 0x2\n" /* offset rbp */ - "\t.byte 0x83\n\t.byte 0x3\n" /* offset rbx */ - "\t.byte 0x8f\n\t.byte 0x4\n" /* offset r15 */ - "\t.byte 0x8e\n\t.byte 0x5\n" /* offset r14 */ - "\t.align 3\n" - "LEFDE%d:\n\n", - name, i, i, i, i, i, i, i, name, size, CFRAME_SIZE, i); - } -#if LJ_HASFFI - if (fcsize) { - fprintf(ctx->fp, - "EH_frame2:\n" - "\t.set L$set$y,LECIEY-LSCIEY\n" - "\t.long L$set$y\n" - "LSCIEY:\n" - "\t.long 0\n" - "\t.byte 0x1\n" - "\t.ascii \"zR\\0\"\n" - "\t.byte 0x1\n" - "\t.byte 128-8\n" - "\t.byte 0x10\n" - "\t.byte 1\n" /* augmentation length */ - "\t.byte 0x1b\n" /* pcrel|sdata4 */ - "\t.byte 0xc\n\t.byte 0x7\n\t.byte 8\n" - "\t.byte 0x80+0x10\n\t.byte 0x1\n" - "\t.align 3\n" - "LECIEY:\n\n"); - fprintf(ctx->fp, - "_lj_vm_ffi_call.eh:\n" - "LSFDEY:\n" - "\t.set L$set$yy,LEFDEY-LASFDEY\n" - "\t.long L$set$yy\n" - "LASFDEY:\n" - "\t.long LASFDEY-EH_frame2\n" - "\t.long _lj_vm_ffi_call-.\n" - "\t.long %d\n" - "\t.byte 0\n" /* augmentation length */ - "\t.byte 0xe\n\t.byte 16\n" /* def_cfa_offset */ - "\t.byte 0x86\n\t.byte 0x2\n" /* offset rbp */ - "\t.byte 0xd\n\t.byte 0x6\n" /* def_cfa_register rbp */ - "\t.byte 0x83\n\t.byte 0x3\n" /* offset rbx */ - "\t.align 3\n" - "LEFDEY:\n\n", fcsize); - } -#endif - fprintf(ctx->fp, ".subsections_via_symbols\n"); - } - break; -#endif - default: /* Difficult for other modes. */ - break; - } -} - diff --git a/lib/LuaJIT/src/vm_x86.dasc b/lib/LuaJIT/src/vm_x86.dasc deleted file mode 100644 index 211ae7b..0000000 --- a/lib/LuaJIT/src/vm_x86.dasc +++ /dev/null @@ -1,5780 +0,0 @@ -|// Low-level VM code for x86 CPUs. -|// Bytecode interpreter, fast functions and helper functions. -|// Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -| -|.if P64 -|.arch x64 -|.else -|.arch x86 -|.endif -|.section code_op, code_sub -| -|.actionlist build_actionlist -|.globals GLOB_ -|.globalnames globnames -|.externnames extnames -| -|//----------------------------------------------------------------------- -| -|.if P64 -|.define X64, 1 -|.if WIN -|.define X64WIN, 1 -|.endif -|.endif -| -|// Fixed register assignments for the interpreter. -|// This is very fragile and has many dependencies. Caveat emptor. -|.define BASE, edx // Not C callee-save, refetched anyway. -|.if not X64 -|.define KBASE, edi // Must be C callee-save. -|.define KBASEa, KBASE -|.define PC, esi // Must be C callee-save. -|.define PCa, PC -|.define DISPATCH, ebx // Must be C callee-save. -|.elif X64WIN -|.define KBASE, edi // Must be C callee-save. -|.define KBASEa, rdi -|.define PC, esi // Must be C callee-save. -|.define PCa, rsi -|.define DISPATCH, ebx // Must be C callee-save. -|.else -|.define KBASE, r15d // Must be C callee-save. -|.define KBASEa, r15 -|.define PC, ebx // Must be C callee-save. -|.define PCa, rbx -|.define DISPATCH, r14d // Must be C callee-save. -|.endif -| -|.define RA, ecx -|.define RAH, ch -|.define RAL, cl -|.define RB, ebp // Must be ebp (C callee-save). -|.define RC, eax // Must be eax. -|.define RCW, ax -|.define RCH, ah -|.define RCL, al -|.define OP, RB -|.define RD, RC -|.define RDW, RCW -|.define RDL, RCL -|.if X64 -|.define RAa, rcx -|.define RBa, rbp -|.define RCa, rax -|.define RDa, rax -|.else -|.define RAa, RA -|.define RBa, RB -|.define RCa, RC -|.define RDa, RD -|.endif -| -|.if not X64 -|.define FCARG1, ecx // x86 fastcall arguments. -|.define FCARG2, edx -|.elif X64WIN -|.define CARG1, rcx // x64/WIN64 C call arguments. -|.define CARG2, rdx -|.define CARG3, r8 -|.define CARG4, r9 -|.define CARG1d, ecx -|.define CARG2d, edx -|.define CARG3d, r8d -|.define CARG4d, r9d -|.define FCARG1, CARG1d // Upwards compatible to x86 fastcall. -|.define FCARG2, CARG2d -|.else -|.define CARG1, rdi // x64/POSIX C call arguments. -|.define CARG2, rsi -|.define CARG3, rdx -|.define CARG4, rcx -|.define CARG5, r8 -|.define CARG6, r9 -|.define CARG1d, edi -|.define CARG2d, esi -|.define CARG3d, edx -|.define CARG4d, ecx -|.define CARG5d, r8d -|.define CARG6d, r9d -|.define FCARG1, CARG1d // Simulate x86 fastcall. -|.define FCARG2, CARG2d -|.endif -| -|// Type definitions. Some of these are only used for documentation. -|.type L, lua_State -|.type GL, global_State -|.type TVALUE, TValue -|.type GCOBJ, GCobj -|.type STR, GCstr -|.type TAB, GCtab -|.type LFUNC, GCfuncL -|.type CFUNC, GCfuncC -|.type PROTO, GCproto -|.type UPVAL, GCupval -|.type NODE, Node -|.type NARGS, int -|.type TRACE, GCtrace -|.type SBUF, SBuf -| -|// Stack layout while in interpreter. Must match with lj_frame.h. -|//----------------------------------------------------------------------- -|.if not X64 // x86 stack layout. -| -|.if WIN -| -|.define CFRAME_SPACE, aword*9 // Delta for esp (see <--). -|.macro saveregs_ -| push edi; push esi; push ebx -| push extern lj_err_unwind_win -| fs; push dword [0] -| fs; mov [0], esp -| sub esp, CFRAME_SPACE -|.endmacro -|.macro restoreregs -| add esp, CFRAME_SPACE -| fs; pop dword [0] -| pop edi // Short for esp += 4. -| pop ebx; pop esi; pop edi; pop ebp -|.endmacro -| -|.else -| -|.define CFRAME_SPACE, aword*7 // Delta for esp (see <--). -|.macro saveregs_ -| push edi; push esi; push ebx -| sub esp, CFRAME_SPACE -|.endmacro -|.macro restoreregs -| add esp, CFRAME_SPACE -| pop ebx; pop esi; pop edi; pop ebp -|.endmacro -| -|.endif -| -|.macro saveregs -| push ebp; saveregs_ -|.endmacro -| -|.if WIN -|.define SAVE_ERRF, aword [esp+aword*19] // vm_pcall/vm_cpcall only. -|.define SAVE_NRES, aword [esp+aword*18] -|.define SAVE_CFRAME, aword [esp+aword*17] -|.define SAVE_L, aword [esp+aword*16] -|//----- 16 byte aligned, ^^^ arguments from C caller -|.define SAVE_RET, aword [esp+aword*15] //<-- esp entering interpreter. -|.define SAVE_R4, aword [esp+aword*14] -|.define SAVE_R3, aword [esp+aword*13] -|.define SAVE_R2, aword [esp+aword*12] -|//----- 16 byte aligned -|.define SAVE_R1, aword [esp+aword*11] -|.define SEH_FUNC, aword [esp+aword*10] -|.define SEH_NEXT, aword [esp+aword*9] //<-- esp after register saves. -|.define UNUSED2, aword [esp+aword*8] -|//----- 16 byte aligned -|.define UNUSED1, aword [esp+aword*7] -|.define SAVE_PC, aword [esp+aword*6] -|.define TMP2, aword [esp+aword*5] -|.define TMP1, aword [esp+aword*4] -|//----- 16 byte aligned -|.define ARG4, aword [esp+aword*3] -|.define ARG3, aword [esp+aword*2] -|.define ARG2, aword [esp+aword*1] -|.define ARG1, aword [esp] //<-- esp while in interpreter. -|//----- 16 byte aligned, ^^^ arguments for C callee -|.else -|.define SAVE_ERRF, aword [esp+aword*15] // vm_pcall/vm_cpcall only. -|.define SAVE_NRES, aword [esp+aword*14] -|.define SAVE_CFRAME, aword [esp+aword*13] -|.define SAVE_L, aword [esp+aword*12] -|//----- 16 byte aligned, ^^^ arguments from C caller -|.define SAVE_RET, aword [esp+aword*11] //<-- esp entering interpreter. -|.define SAVE_R4, aword [esp+aword*10] -|.define SAVE_R3, aword [esp+aword*9] -|.define SAVE_R2, aword [esp+aword*8] -|//----- 16 byte aligned -|.define SAVE_R1, aword [esp+aword*7] //<-- esp after register saves. -|.define SAVE_PC, aword [esp+aword*6] -|.define TMP2, aword [esp+aword*5] -|.define TMP1, aword [esp+aword*4] -|//----- 16 byte aligned -|.define ARG4, aword [esp+aword*3] -|.define ARG3, aword [esp+aword*2] -|.define ARG2, aword [esp+aword*1] -|.define ARG1, aword [esp] //<-- esp while in interpreter. -|//----- 16 byte aligned, ^^^ arguments for C callee -|.endif -| -|// FPARGx overlaps ARGx and ARG(x+1) on x86. -|.define FPARG3, qword [esp+qword*1] -|.define FPARG1, qword [esp] -|// TMPQ overlaps TMP1/TMP2. ARG5/MULTRES overlap TMP1/TMP2 (and TMPQ). -|.define TMPQ, qword [esp+aword*4] -|.define TMP3, ARG4 -|.define ARG5, TMP1 -|.define TMPa, TMP1 -|.define MULTRES, TMP2 -| -|// Arguments for vm_call and vm_pcall. -|.define INARG_BASE, SAVE_CFRAME // Overwritten by SAVE_CFRAME! -| -|// Arguments for vm_cpcall. -|.define INARG_CP_CALL, SAVE_ERRF -|.define INARG_CP_UD, SAVE_NRES -|.define INARG_CP_FUNC, SAVE_CFRAME -| -|//----------------------------------------------------------------------- -|.elif X64WIN // x64/Windows stack layout -| -|.define CFRAME_SPACE, aword*5 // Delta for rsp (see <--). -|.macro saveregs_ -| push rdi; push rsi; push rbx -| sub rsp, CFRAME_SPACE -|.endmacro -|.macro saveregs -| push rbp; saveregs_ -|.endmacro -|.macro restoreregs -| add rsp, CFRAME_SPACE -| pop rbx; pop rsi; pop rdi; pop rbp -|.endmacro -| -|.define SAVE_CFRAME, aword [rsp+aword*13] -|.define SAVE_PC, dword [rsp+dword*25] -|.define SAVE_L, dword [rsp+dword*24] -|.define SAVE_ERRF, dword [rsp+dword*23] -|.define SAVE_NRES, dword [rsp+dword*22] -|.define TMP2, dword [rsp+dword*21] -|.define TMP1, dword [rsp+dword*20] -|//----- 16 byte aligned, ^^^ 32 byte register save area, owned by interpreter -|.define SAVE_RET, aword [rsp+aword*9] //<-- rsp entering interpreter. -|.define SAVE_R4, aword [rsp+aword*8] -|.define SAVE_R3, aword [rsp+aword*7] -|.define SAVE_R2, aword [rsp+aword*6] -|.define SAVE_R1, aword [rsp+aword*5] //<-- rsp after register saves. -|.define ARG5, aword [rsp+aword*4] -|.define CSAVE_4, aword [rsp+aword*3] -|.define CSAVE_3, aword [rsp+aword*2] -|.define CSAVE_2, aword [rsp+aword*1] -|.define CSAVE_1, aword [rsp] //<-- rsp while in interpreter. -|//----- 16 byte aligned, ^^^ 32 byte register save area, owned by callee -| -|// TMPQ overlaps TMP1/TMP2. MULTRES overlaps TMP2 (and TMPQ). -|.define TMPQ, qword [rsp+aword*10] -|.define MULTRES, TMP2 -|.define TMPa, ARG5 -|.define ARG5d, dword [rsp+aword*4] -|.define TMP3, ARG5d -| -|//----------------------------------------------------------------------- -|.else // x64/POSIX stack layout -| -|.define CFRAME_SPACE, aword*5 // Delta for rsp (see <--). -|.macro saveregs_ -| push rbx; push r15; push r14 -|.if NO_UNWIND -| push r13; push r12 -|.endif -| sub rsp, CFRAME_SPACE -|.endmacro -|.macro saveregs -| push rbp; saveregs_ -|.endmacro -|.macro restoreregs -| add rsp, CFRAME_SPACE -|.if NO_UNWIND -| pop r12; pop r13 -|.endif -| pop r14; pop r15; pop rbx; pop rbp -|.endmacro -| -|//----- 16 byte aligned, -|.if NO_UNWIND -|.define SAVE_RET, aword [rsp+aword*11] //<-- rsp entering interpreter. -|.define SAVE_R4, aword [rsp+aword*10] -|.define SAVE_R3, aword [rsp+aword*9] -|.define SAVE_R2, aword [rsp+aword*8] -|.define SAVE_R1, aword [rsp+aword*7] -|.define SAVE_RU2, aword [rsp+aword*6] -|.define SAVE_RU1, aword [rsp+aword*5] //<-- rsp after register saves. -|.else -|.define SAVE_RET, aword [rsp+aword*9] //<-- rsp entering interpreter. -|.define SAVE_R4, aword [rsp+aword*8] -|.define SAVE_R3, aword [rsp+aword*7] -|.define SAVE_R2, aword [rsp+aword*6] -|.define SAVE_R1, aword [rsp+aword*5] //<-- rsp after register saves. -|.endif -|.define SAVE_CFRAME, aword [rsp+aword*4] -|.define SAVE_PC, dword [rsp+dword*7] -|.define SAVE_L, dword [rsp+dword*6] -|.define SAVE_ERRF, dword [rsp+dword*5] -|.define SAVE_NRES, dword [rsp+dword*4] -|.define TMPa, aword [rsp+aword*1] -|.define TMP2, dword [rsp+dword*1] -|.define TMP1, dword [rsp] //<-- rsp while in interpreter. -|//----- 16 byte aligned -| -|// TMPQ overlaps TMP1/TMP2. MULTRES overlaps TMP2 (and TMPQ). -|.define TMPQ, qword [rsp] -|.define TMP3, dword [rsp+aword*1] -|.define MULTRES, TMP2 -| -|.endif -| -|//----------------------------------------------------------------------- -| -|// Instruction headers. -|.macro ins_A; .endmacro -|.macro ins_AD; .endmacro -|.macro ins_AJ; .endmacro -|.macro ins_ABC; movzx RB, RCH; movzx RC, RCL; .endmacro -|.macro ins_AB_; movzx RB, RCH; .endmacro -|.macro ins_A_C; movzx RC, RCL; .endmacro -|.macro ins_AND; not RDa; .endmacro -| -|// Instruction decode+dispatch. Carefully tuned (nope, lodsd is not faster). -|.macro ins_NEXT -| mov RC, [PC] -| movzx RA, RCH -| movzx OP, RCL -| add PC, 4 -| shr RC, 16 -|.if X64 -| jmp aword [DISPATCH+OP*8] -|.else -| jmp aword [DISPATCH+OP*4] -|.endif -|.endmacro -| -|// Instruction footer. -|.if 1 -| // Replicated dispatch. Less unpredictable branches, but higher I-Cache use. -| .define ins_next, ins_NEXT -| .define ins_next_, ins_NEXT -|.else -| // Common dispatch. Lower I-Cache use, only one (very) unpredictable branch. -| // Affects only certain kinds of benchmarks (and only with -j off). -| // Around 10%-30% slower on Core2, a lot more slower on P4. -| .macro ins_next -| jmp ->ins_next -| .endmacro -| .macro ins_next_ -| ->ins_next: -| ins_NEXT -| .endmacro -|.endif -| -|// Call decode and dispatch. -|.macro ins_callt -| // BASE = new base, RB = LFUNC, RD = nargs+1, [BASE-4] = PC -| mov PC, LFUNC:RB->pc -| mov RA, [PC] -| movzx OP, RAL -| movzx RA, RAH -| add PC, 4 -|.if X64 -| jmp aword [DISPATCH+OP*8] -|.else -| jmp aword [DISPATCH+OP*4] -|.endif -|.endmacro -| -|.macro ins_call -| // BASE = new base, RB = LFUNC, RD = nargs+1 -| mov [BASE-4], PC -| ins_callt -|.endmacro -| -|//----------------------------------------------------------------------- -| -|// Macros to test operand types. -|.macro checktp, reg, tp; cmp dword [BASE+reg*8+4], tp; .endmacro -|.macro checknum, reg, target; checktp reg, LJ_TISNUM; jae target; .endmacro -|.macro checkint, reg, target; checktp reg, LJ_TISNUM; jne target; .endmacro -|.macro checkstr, reg, target; checktp reg, LJ_TSTR; jne target; .endmacro -|.macro checktab, reg, target; checktp reg, LJ_TTAB; jne target; .endmacro -| -|// These operands must be used with movzx. -|.define PC_OP, byte [PC-4] -|.define PC_RA, byte [PC-3] -|.define PC_RB, byte [PC-1] -|.define PC_RC, byte [PC-2] -|.define PC_RD, word [PC-2] -| -|.macro branchPC, reg -| lea PC, [PC+reg*4-BCBIAS_J*4] -|.endmacro -| -|// Assumes DISPATCH is relative to GL. -#define DISPATCH_GL(field) (GG_DISP2G + (int)offsetof(global_State, field)) -#define DISPATCH_J(field) (GG_DISP2J + (int)offsetof(jit_State, field)) -| -#define PC2PROTO(field) ((int)offsetof(GCproto, field)-(int)sizeof(GCproto)) -| -|// Decrement hashed hotcount and trigger trace recorder if zero. -|.macro hotloop, reg -| mov reg, PC -| shr reg, 1 -| and reg, HOTCOUNT_PCMASK -| sub word [DISPATCH+reg+GG_DISP2HOT], HOTCOUNT_LOOP -| jb ->vm_hotloop -|.endmacro -| -|.macro hotcall, reg -| mov reg, PC -| shr reg, 1 -| and reg, HOTCOUNT_PCMASK -| sub word [DISPATCH+reg+GG_DISP2HOT], HOTCOUNT_CALL -| jb ->vm_hotcall -|.endmacro -| -|// Set current VM state. -|.macro set_vmstate, st -| mov dword [DISPATCH+DISPATCH_GL(vmstate)], ~LJ_VMST_..st -|.endmacro -| -|// x87 compares. -|.macro fcomparepp // Compare and pop st0 >< st1. -| fucomip st1 -| fpop -|.endmacro -| -|.macro fpop1; fstp st1; .endmacro -| -|// Synthesize SSE FP constants. -|.macro sseconst_abs, reg, tmp // Synthesize abs mask. -|.if X64 -| mov64 tmp, U64x(7fffffff,ffffffff); movd reg, tmp -|.else -| pxor reg, reg; pcmpeqd reg, reg; psrlq reg, 1 -|.endif -|.endmacro -| -|.macro sseconst_hi, reg, tmp, val // Synthesize hi-32 bit const. -|.if X64 -| mov64 tmp, U64x(val,00000000); movd reg, tmp -|.else -| mov tmp, 0x .. val; movd reg, tmp; pshufd reg, reg, 0x51 -|.endif -|.endmacro -| -|.macro sseconst_sign, reg, tmp // Synthesize sign mask. -| sseconst_hi reg, tmp, 80000000 -|.endmacro -|.macro sseconst_1, reg, tmp // Synthesize 1.0. -| sseconst_hi reg, tmp, 3ff00000 -|.endmacro -|.macro sseconst_m1, reg, tmp // Synthesize -1.0. -| sseconst_hi reg, tmp, bff00000 -|.endmacro -|.macro sseconst_2p52, reg, tmp // Synthesize 2^52. -| sseconst_hi reg, tmp, 43300000 -|.endmacro -|.macro sseconst_tobit, reg, tmp // Synthesize 2^52 + 2^51. -| sseconst_hi reg, tmp, 43380000 -|.endmacro -| -|// Move table write barrier back. Overwrites reg. -|.macro barrierback, tab, reg -| and byte tab->marked, (uint8_t)~LJ_GC_BLACK // black2gray(tab) -| mov reg, [DISPATCH+DISPATCH_GL(gc.grayagain)] -| mov [DISPATCH+DISPATCH_GL(gc.grayagain)], tab -| mov tab->gclist, reg -|.endmacro -| -|//----------------------------------------------------------------------- - -/* Generate subroutines used by opcodes and other parts of the VM. */ -/* The .code_sub section should be last to help static branch prediction. */ -static void build_subroutines(BuildCtx *ctx) -{ - |.code_sub - | - |//----------------------------------------------------------------------- - |//-- Return handling ---------------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_returnp: - | test PC, FRAME_P - | jz ->cont_dispatch - | - | // Return from pcall or xpcall fast func. - | and PC, -8 - | sub BASE, PC // Restore caller base. - | lea RAa, [RA+PC-8] // Rebase RA and prepend one result. - | mov PC, [BASE-4] // Fetch PC of previous frame. - | // Prepending may overwrite the pcall frame, so do it at the end. - | mov dword [BASE+RA+4], LJ_TTRUE // Prepend true to results. - | - |->vm_returnc: - | add RD, 1 // RD = nresults+1 - | jz ->vm_unwind_yield - | mov MULTRES, RD - | test PC, FRAME_TYPE - | jz ->BC_RET_Z // Handle regular return to Lua. - | - |->vm_return: - | // BASE = base, RA = resultofs, RD = nresults+1 (= MULTRES), PC = return - | xor PC, FRAME_C - | test PC, FRAME_TYPE - | jnz ->vm_returnp - | - | // Return to C. - | set_vmstate C - | and PC, -8 - | sub PC, BASE - | neg PC // Previous base = BASE - delta. - | - | sub RD, 1 - | jz >2 - |1: // Move results down. - |.if X64 - | mov RBa, [BASE+RA] - | mov [BASE-8], RBa - |.else - | mov RB, [BASE+RA] - | mov [BASE-8], RB - | mov RB, [BASE+RA+4] - | mov [BASE-4], RB - |.endif - | add BASE, 8 - | sub RD, 1 - | jnz <1 - |2: - | mov L:RB, SAVE_L - | mov L:RB->base, PC - |3: - | mov RD, MULTRES - | mov RA, SAVE_NRES // RA = wanted nresults+1 - |4: - | cmp RA, RD - | jne >6 // More/less results wanted? - |5: - | sub BASE, 8 - | mov L:RB->top, BASE - | - |->vm_leave_cp: - | mov RAa, SAVE_CFRAME // Restore previous C frame. - | mov L:RB->cframe, RAa - | xor eax, eax // Ok return status for vm_pcall. - | - |->vm_leave_unw: - | restoreregs - | ret - | - |6: - | jb >7 // Less results wanted? - | // More results wanted. Check stack size and fill up results with nil. - | cmp BASE, L:RB->maxstack - | ja >8 - | mov dword [BASE-4], LJ_TNIL - | add BASE, 8 - | add RD, 1 - | jmp <4 - | - |7: // Less results wanted. - | test RA, RA - | jz <5 // But check for LUA_MULTRET+1. - | sub RA, RD // Negative result! - | lea BASE, [BASE+RA*8] // Correct top. - | jmp <5 - | - |8: // Corner case: need to grow stack for filling up results. - | // This can happen if: - | // - A C function grows the stack (a lot). - | // - The GC shrinks the stack in between. - | // - A return back from a lua_call() with (high) nresults adjustment. - | mov L:RB->top, BASE // Save current top held in BASE (yes). - | mov MULTRES, RD // Need to fill only remainder with nil. - | mov FCARG2, RA - | mov FCARG1, L:RB - | call extern lj_state_growstack@8 // (lua_State *L, int n) - | mov BASE, L:RB->top // Need the (realloced) L->top in BASE. - | jmp <3 - | - |->vm_unwind_yield: - | mov al, LUA_YIELD - | jmp ->vm_unwind_c_eh - | - |->vm_unwind_c@8: // Unwind C stack, return from vm_pcall. - | // (void *cframe, int errcode) - |.if X64 - | mov eax, CARG2d // Error return status for vm_pcall. - | mov rsp, CARG1 - |.else - | mov eax, FCARG2 // Error return status for vm_pcall. - | mov esp, FCARG1 - |.if WIN - | lea FCARG1, SEH_NEXT - | fs; mov [0], FCARG1 - |.endif - |.endif - |->vm_unwind_c_eh: // Landing pad for external unwinder. - | mov L:RB, SAVE_L - | mov GL:RB, L:RB->glref - | mov dword GL:RB->vmstate, ~LJ_VMST_C - | jmp ->vm_leave_unw - | - |->vm_unwind_rethrow: - |.if X64 and not X64WIN - | mov FCARG1, SAVE_L - | mov FCARG2, eax - | restoreregs - | jmp extern lj_err_throw@8 // (lua_State *L, int errcode) - |.endif - | - |->vm_unwind_ff@4: // Unwind C stack, return from ff pcall. - | // (void *cframe) - |.if X64 - | and CARG1, CFRAME_RAWMASK - | mov rsp, CARG1 - |.else - | and FCARG1, CFRAME_RAWMASK - | mov esp, FCARG1 - |.if WIN - | lea FCARG1, SEH_NEXT - | fs; mov [0], FCARG1 - |.endif - |.endif - |->vm_unwind_ff_eh: // Landing pad for external unwinder. - | mov L:RB, SAVE_L - | mov RAa, -8 // Results start at BASE+RA = BASE-8. - | mov RD, 1+1 // Really 1+2 results, incr. later. - | mov BASE, L:RB->base - | mov DISPATCH, L:RB->glref // Setup pointer to dispatch table. - | add DISPATCH, GG_G2DISP - | mov PC, [BASE-4] // Fetch PC of previous frame. - | mov dword [BASE-4], LJ_TFALSE // Prepend false to error message. - | set_vmstate INTERP - | jmp ->vm_returnc // Increments RD/MULTRES and returns. - | - |.if WIN and not X64 - |->vm_rtlunwind@16: // Thin layer around RtlUnwind. - | // (void *cframe, void *excptrec, void *unwinder, int errcode) - | mov [esp], FCARG1 // Return value for RtlUnwind. - | push FCARG2 // Exception record for RtlUnwind. - | push 0 // Ignored by RtlUnwind. - | push dword [FCARG1+CFRAME_OFS_SEH] - | call extern RtlUnwind@16 // Violates ABI (clobbers too much). - | mov FCARG1, eax - | mov FCARG2, [esp+4] // errcode (for vm_unwind_c). - | ret // Jump to unwinder. - |.endif - | - |//----------------------------------------------------------------------- - |//-- Grow stack for calls ----------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_growstack_c: // Grow stack for C function. - | mov FCARG2, LUA_MINSTACK - | jmp >2 - | - |->vm_growstack_v: // Grow stack for vararg Lua function. - | sub RD, 8 - | jmp >1 - | - |->vm_growstack_f: // Grow stack for fixarg Lua function. - | // BASE = new base, RD = nargs+1, RB = L, PC = first PC - | lea RD, [BASE+NARGS:RD*8-8] - |1: - | movzx RA, byte [PC-4+PC2PROTO(framesize)] - | add PC, 4 // Must point after first instruction. - | mov L:RB->base, BASE - | mov L:RB->top, RD - | mov SAVE_PC, PC - | mov FCARG2, RA - |2: - | // RB = L, L->base = new base, L->top = top - | mov FCARG1, L:RB - | call extern lj_state_growstack@8 // (lua_State *L, int n) - | mov BASE, L:RB->base - | mov RD, L:RB->top - | mov LFUNC:RB, [BASE-8] - | sub RD, BASE - | shr RD, 3 - | add NARGS:RD, 1 - | // BASE = new base, RB = LFUNC, RD = nargs+1 - | ins_callt // Just retry the call. - | - |//----------------------------------------------------------------------- - |//-- Entry points into the assembler VM --------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_resume: // Setup C frame and resume thread. - | // (lua_State *L, TValue *base, int nres1 = 0, ptrdiff_t ef = 0) - | saveregs - |.if X64 - | mov L:RB, CARG1d // Caveat: CARG1d may be RA. - | mov SAVE_L, CARG1d - | mov RA, CARG2d - |.else - | mov L:RB, SAVE_L - | mov RA, INARG_BASE // Caveat: overlaps SAVE_CFRAME! - |.endif - | mov PC, FRAME_CP - | xor RD, RD - | lea KBASEa, [esp+CFRAME_RESUME] - | mov DISPATCH, L:RB->glref // Setup pointer to dispatch table. - | add DISPATCH, GG_G2DISP - | mov SAVE_PC, RD // Any value outside of bytecode is ok. - | mov SAVE_CFRAME, RDa - |.if X64 - | mov SAVE_NRES, RD - | mov SAVE_ERRF, RD - |.endif - | mov L:RB->cframe, KBASEa - | cmp byte L:RB->status, RDL - | je >2 // Initial resume (like a call). - | - | // Resume after yield (like a return). - | mov [DISPATCH+DISPATCH_GL(cur_L)], L:RB - | set_vmstate INTERP - | mov byte L:RB->status, RDL - | mov BASE, L:RB->base - | mov RD, L:RB->top - | sub RD, RA - | shr RD, 3 - | add RD, 1 // RD = nresults+1 - | sub RA, BASE // RA = resultofs - | mov PC, [BASE-4] - | mov MULTRES, RD - | test PC, FRAME_TYPE - | jz ->BC_RET_Z - | jmp ->vm_return - | - |->vm_pcall: // Setup protected C frame and enter VM. - | // (lua_State *L, TValue *base, int nres1, ptrdiff_t ef) - | saveregs - | mov PC, FRAME_CP - |.if X64 - | mov SAVE_ERRF, CARG4d - |.endif - | jmp >1 - | - |->vm_call: // Setup C frame and enter VM. - | // (lua_State *L, TValue *base, int nres1) - | saveregs - | mov PC, FRAME_C - | - |1: // Entry point for vm_pcall above (PC = ftype). - |.if X64 - | mov SAVE_NRES, CARG3d - | mov L:RB, CARG1d // Caveat: CARG1d may be RA. - | mov SAVE_L, CARG1d - | mov RA, CARG2d - |.else - | mov L:RB, SAVE_L - | mov RA, INARG_BASE // Caveat: overlaps SAVE_CFRAME! - |.endif - | - | mov DISPATCH, L:RB->glref // Setup pointer to dispatch table. - | mov KBASEa, L:RB->cframe // Add our C frame to cframe chain. - | mov SAVE_CFRAME, KBASEa - | mov SAVE_PC, L:RB // Any value outside of bytecode is ok. - | add DISPATCH, GG_G2DISP - |.if X64 - | mov L:RB->cframe, rsp - |.else - | mov L:RB->cframe, esp - |.endif - | - |2: // Entry point for vm_resume/vm_cpcall (RA = base, RB = L, PC = ftype). - | mov [DISPATCH+DISPATCH_GL(cur_L)], L:RB - | set_vmstate INTERP - | mov BASE, L:RB->base // BASE = old base (used in vmeta_call). - | add PC, RA - | sub PC, BASE // PC = frame delta + frame type - | - | mov RD, L:RB->top - | sub RD, RA - | shr NARGS:RD, 3 - | add NARGS:RD, 1 // RD = nargs+1 - | - |->vm_call_dispatch: - | mov LFUNC:RB, [RA-8] - | cmp dword [RA-4], LJ_TFUNC - | jne ->vmeta_call // Ensure KBASE defined and != BASE. - | - |->vm_call_dispatch_f: - | mov BASE, RA - | ins_call - | // BASE = new base, RB = func, RD = nargs+1, PC = caller PC - | - |->vm_cpcall: // Setup protected C frame, call C. - | // (lua_State *L, lua_CFunction func, void *ud, lua_CPFunction cp) - | saveregs - |.if X64 - | mov L:RB, CARG1d // Caveat: CARG1d may be RA. - | mov SAVE_L, CARG1d - |.else - | mov L:RB, SAVE_L - | // Caveat: INARG_CP_* and SAVE_CFRAME/SAVE_NRES/SAVE_ERRF overlap! - | mov RC, INARG_CP_UD // Get args before they are overwritten. - | mov RA, INARG_CP_FUNC - | mov BASE, INARG_CP_CALL - |.endif - | mov SAVE_PC, L:RB // Any value outside of bytecode is ok. - | - | mov KBASE, L:RB->stack // Compute -savestack(L, L->top). - | sub KBASE, L:RB->top - | mov DISPATCH, L:RB->glref // Setup pointer to dispatch table. - | mov SAVE_ERRF, 0 // No error function. - | mov SAVE_NRES, KBASE // Neg. delta means cframe w/o frame. - | add DISPATCH, GG_G2DISP - | // Handler may change cframe_nres(L->cframe) or cframe_errfunc(L->cframe). - | - |.if X64 - | mov KBASEa, L:RB->cframe // Add our C frame to cframe chain. - | mov SAVE_CFRAME, KBASEa - | mov L:RB->cframe, rsp - | mov [DISPATCH+DISPATCH_GL(cur_L)], L:RB - | - | call CARG4 // (lua_State *L, lua_CFunction func, void *ud) - |.else - | mov ARG3, RC // Have to copy args downwards. - | mov ARG2, RA - | mov ARG1, L:RB - | - | mov KBASE, L:RB->cframe // Add our C frame to cframe chain. - | mov SAVE_CFRAME, KBASE - | mov L:RB->cframe, esp - | mov [DISPATCH+DISPATCH_GL(cur_L)], L:RB - | - | call BASE // (lua_State *L, lua_CFunction func, void *ud) - |.endif - | // TValue * (new base) or NULL returned in eax (RC). - | test RC, RC - | jz ->vm_leave_cp // No base? Just remove C frame. - | mov RA, RC - | mov PC, FRAME_CP - | jmp <2 // Else continue with the call. - | - |//----------------------------------------------------------------------- - |//-- Metamethod handling ------------------------------------------------ - |//----------------------------------------------------------------------- - | - |//-- Continuation dispatch ---------------------------------------------- - | - |->cont_dispatch: - | // BASE = meta base, RA = resultofs, RD = nresults+1 (also in MULTRES) - | add RA, BASE - | and PC, -8 - | mov RB, BASE - | sub BASE, PC // Restore caller BASE. - | mov dword [RA+RD*8-4], LJ_TNIL // Ensure one valid arg. - | mov RC, RA // ... in [RC] - | mov PC, [RB-12] // Restore PC from [cont|PC]. - |.if X64 - | movsxd RAa, dword [RB-16] // May be negative on WIN64 with debug. - |.if FFI - | cmp RA, 1 - | jbe >1 - |.endif - | lea KBASEa, qword [=>0] - | add RAa, KBASEa - |.else - | mov RA, dword [RB-16] - |.if FFI - | cmp RA, 1 - | jbe >1 - |.endif - |.endif - | mov LFUNC:KBASE, [BASE-8] - | mov KBASE, LFUNC:KBASE->pc - | mov KBASE, [KBASE+PC2PROTO(k)] - | // BASE = base, RC = result, RB = meta base - | jmp RAa // Jump to continuation. - | - |.if FFI - |1: - | je ->cont_ffi_callback // cont = 1: return from FFI callback. - | // cont = 0: Tail call from C function. - | sub RB, BASE - | shr RB, 3 - | lea RD, [RB-1] - | jmp ->vm_call_tail - |.endif - | - |->cont_cat: // BASE = base, RC = result, RB = mbase - | movzx RA, PC_RB - | sub RB, 16 - | lea RA, [BASE+RA*8] - | sub RA, RB - | je ->cont_ra - | neg RA - | shr RA, 3 - |.if X64WIN - | mov CARG3d, RA - | mov L:CARG1d, SAVE_L - | mov L:CARG1d->base, BASE - | mov RCa, [RC] - | mov [RB], RCa - | mov CARG2d, RB - |.elif X64 - | mov L:CARG1d, SAVE_L - | mov L:CARG1d->base, BASE - | mov CARG3d, RA - | mov RAa, [RC] - | mov [RB], RAa - | mov CARG2d, RB - |.else - | mov ARG3, RA - | mov RA, [RC+4] - | mov RC, [RC] - | mov [RB+4], RA - | mov [RB], RC - | mov ARG2, RB - |.endif - | jmp ->BC_CAT_Z - | - |//-- Table indexing metamethods ----------------------------------------- - | - |->vmeta_tgets: - | mov TMP1, RC // RC = GCstr * - | mov TMP2, LJ_TSTR - | lea RCa, TMP1 // Store temp. TValue in TMP1/TMP2. - | cmp PC_OP, BC_GGET - | jne >1 - | lea RA, [DISPATCH+DISPATCH_GL(tmptv)] // Store fn->l.env in g->tmptv. - | mov [RA], TAB:RB // RB = GCtab * - | mov dword [RA+4], LJ_TTAB - | mov RB, RA - | jmp >2 - | - |->vmeta_tgetb: - | movzx RC, PC_RC - |.if DUALNUM - | mov TMP2, LJ_TISNUM - | mov TMP1, RC - |.else - | cvtsi2sd xmm0, RC - | movsd TMPQ, xmm0 - |.endif - | lea RCa, TMPQ // Store temp. TValue in TMPQ. - | jmp >1 - | - |->vmeta_tgetv: - | movzx RC, PC_RC // Reload TValue *k from RC. - | lea RC, [BASE+RC*8] - |1: - | movzx RB, PC_RB // Reload TValue *t from RB. - | lea RB, [BASE+RB*8] - |2: - |.if X64 - | mov L:CARG1d, SAVE_L - | mov L:CARG1d->base, BASE // Caveat: CARG2d/CARG3d may be BASE. - | mov CARG2d, RB - | mov CARG3, RCa // May be 64 bit ptr to stack. - | mov L:RB, L:CARG1d - |.else - | mov ARG2, RB - | mov L:RB, SAVE_L - | mov ARG3, RC - | mov ARG1, L:RB - | mov L:RB->base, BASE - |.endif - | mov SAVE_PC, PC - | call extern lj_meta_tget // (lua_State *L, TValue *o, TValue *k) - | // TValue * (finished) or NULL (metamethod) returned in eax (RC). - | mov BASE, L:RB->base - | test RC, RC - | jz >3 - |->cont_ra: // BASE = base, RC = result - | movzx RA, PC_RA - |.if X64 - | mov RBa, [RC] - | mov [BASE+RA*8], RBa - |.else - | mov RB, [RC+4] - | mov RC, [RC] - | mov [BASE+RA*8+4], RB - | mov [BASE+RA*8], RC - |.endif - | ins_next - | - |3: // Call __index metamethod. - | // BASE = base, L->top = new base, stack = cont/func/t/k - | mov RA, L:RB->top - | mov [RA-12], PC // [cont|PC] - | lea PC, [RA+FRAME_CONT] - | sub PC, BASE - | mov LFUNC:RB, [RA-8] // Guaranteed to be a function here. - | mov NARGS:RD, 2+1 // 2 args for func(t, k). - | jmp ->vm_call_dispatch_f - | - |->vmeta_tgetr: - | mov FCARG1, TAB:RB - | mov RB, BASE // Save BASE. - | mov FCARG2, RC // Caveat: FCARG2 == BASE - | call extern lj_tab_getinth@8 // (GCtab *t, int32_t key) - | // cTValue * or NULL returned in eax (RC). - | movzx RA, PC_RA - | mov BASE, RB // Restore BASE. - | test RC, RC - | jnz ->BC_TGETR_Z - | mov dword [BASE+RA*8+4], LJ_TNIL - | jmp ->BC_TGETR2_Z - | - |//----------------------------------------------------------------------- - | - |->vmeta_tsets: - | mov TMP1, RC // RC = GCstr * - | mov TMP2, LJ_TSTR - | lea RCa, TMP1 // Store temp. TValue in TMP1/TMP2. - | cmp PC_OP, BC_GSET - | jne >1 - | lea RA, [DISPATCH+DISPATCH_GL(tmptv)] // Store fn->l.env in g->tmptv. - | mov [RA], TAB:RB // RB = GCtab * - | mov dword [RA+4], LJ_TTAB - | mov RB, RA - | jmp >2 - | - |->vmeta_tsetb: - | movzx RC, PC_RC - |.if DUALNUM - | mov TMP2, LJ_TISNUM - | mov TMP1, RC - |.else - | cvtsi2sd xmm0, RC - | movsd TMPQ, xmm0 - |.endif - | lea RCa, TMPQ // Store temp. TValue in TMPQ. - | jmp >1 - | - |->vmeta_tsetv: - | movzx RC, PC_RC // Reload TValue *k from RC. - | lea RC, [BASE+RC*8] - |1: - | movzx RB, PC_RB // Reload TValue *t from RB. - | lea RB, [BASE+RB*8] - |2: - |.if X64 - | mov L:CARG1d, SAVE_L - | mov L:CARG1d->base, BASE // Caveat: CARG2d/CARG3d may be BASE. - | mov CARG2d, RB - | mov CARG3, RCa // May be 64 bit ptr to stack. - | mov L:RB, L:CARG1d - |.else - | mov ARG2, RB - | mov L:RB, SAVE_L - | mov ARG3, RC - | mov ARG1, L:RB - | mov L:RB->base, BASE - |.endif - | mov SAVE_PC, PC - | call extern lj_meta_tset // (lua_State *L, TValue *o, TValue *k) - | // TValue * (finished) or NULL (metamethod) returned in eax (RC). - | mov BASE, L:RB->base - | test RC, RC - | jz >3 - | // NOBARRIER: lj_meta_tset ensures the table is not black. - | movzx RA, PC_RA - |.if X64 - | mov RBa, [BASE+RA*8] - | mov [RC], RBa - |.else - | mov RB, [BASE+RA*8+4] - | mov RA, [BASE+RA*8] - | mov [RC+4], RB - | mov [RC], RA - |.endif - |->cont_nop: // BASE = base, (RC = result) - | ins_next - | - |3: // Call __newindex metamethod. - | // BASE = base, L->top = new base, stack = cont/func/t/k/(v) - | mov RA, L:RB->top - | mov [RA-12], PC // [cont|PC] - | movzx RC, PC_RA - | // Copy value to third argument. - |.if X64 - | mov RBa, [BASE+RC*8] - | mov [RA+16], RBa - |.else - | mov RB, [BASE+RC*8+4] - | mov RC, [BASE+RC*8] - | mov [RA+20], RB - | mov [RA+16], RC - |.endif - | lea PC, [RA+FRAME_CONT] - | sub PC, BASE - | mov LFUNC:RB, [RA-8] // Guaranteed to be a function here. - | mov NARGS:RD, 3+1 // 3 args for func(t, k, v). - | jmp ->vm_call_dispatch_f - | - |->vmeta_tsetr: - |.if X64WIN - | mov L:CARG1d, SAVE_L - | mov CARG3d, RC - | mov L:CARG1d->base, BASE - | xchg CARG2d, TAB:RB // Caveat: CARG2d == BASE. - |.elif X64 - | mov L:CARG1d, SAVE_L - | mov CARG2d, TAB:RB - | mov L:CARG1d->base, BASE - | mov RB, BASE // Save BASE. - | mov CARG3d, RC // Caveat: CARG3d == BASE. - |.else - | mov L:RA, SAVE_L - | mov ARG2, TAB:RB - | mov RB, BASE // Save BASE. - | mov ARG3, RC - | mov ARG1, L:RA - | mov L:RA->base, BASE - |.endif - | mov SAVE_PC, PC - | call extern lj_tab_setinth // (lua_State *L, GCtab *t, int32_t key) - | // TValue * returned in eax (RC). - | movzx RA, PC_RA - | mov BASE, RB // Restore BASE. - | jmp ->BC_TSETR_Z - | - |//-- Comparison metamethods --------------------------------------------- - | - |->vmeta_comp: - |.if X64 - | mov L:RB, SAVE_L - | mov L:RB->base, BASE // Caveat: CARG2d/CARG3d == BASE. - |.if X64WIN - | lea CARG3d, [BASE+RD*8] - | lea CARG2d, [BASE+RA*8] - |.else - | lea CARG2d, [BASE+RA*8] - | lea CARG3d, [BASE+RD*8] - |.endif - | mov CARG1d, L:RB // Caveat: CARG1d/CARG4d == RA. - | movzx CARG4d, PC_OP - |.else - | movzx RB, PC_OP - | lea RD, [BASE+RD*8] - | lea RA, [BASE+RA*8] - | mov ARG4, RB - | mov L:RB, SAVE_L - | mov ARG3, RD - | mov ARG2, RA - | mov ARG1, L:RB - | mov L:RB->base, BASE - |.endif - | mov SAVE_PC, PC - | call extern lj_meta_comp // (lua_State *L, TValue *o1, *o2, int op) - | // 0/1 or TValue * (metamethod) returned in eax (RC). - |3: - | mov BASE, L:RB->base - | cmp RC, 1 - | ja ->vmeta_binop - |4: - | lea PC, [PC+4] - | jb >6 - |5: - | movzx RD, PC_RD - | branchPC RD - |6: - | ins_next - | - |->cont_condt: // BASE = base, RC = result - | add PC, 4 - | cmp dword [RC+4], LJ_TISTRUECOND // Branch if result is true. - | jb <5 - | jmp <6 - | - |->cont_condf: // BASE = base, RC = result - | cmp dword [RC+4], LJ_TISTRUECOND // Branch if result is false. - | jmp <4 - | - |->vmeta_equal: - | sub PC, 4 - |.if X64WIN - | mov CARG3d, RD - | mov CARG4d, RB - | mov L:RB, SAVE_L - | mov L:RB->base, BASE // Caveat: CARG2d == BASE. - | mov CARG2d, RA - | mov CARG1d, L:RB // Caveat: CARG1d == RA. - |.elif X64 - | mov CARG2d, RA - | mov CARG4d, RB // Caveat: CARG4d == RA. - | mov L:RB, SAVE_L - | mov L:RB->base, BASE // Caveat: CARG3d == BASE. - | mov CARG3d, RD - | mov CARG1d, L:RB - |.else - | mov ARG4, RB - | mov L:RB, SAVE_L - | mov ARG3, RD - | mov ARG2, RA - | mov ARG1, L:RB - | mov L:RB->base, BASE - |.endif - | mov SAVE_PC, PC - | call extern lj_meta_equal // (lua_State *L, GCobj *o1, *o2, int ne) - | // 0/1 or TValue * (metamethod) returned in eax (RC). - | jmp <3 - | - |->vmeta_equal_cd: - |.if FFI - | sub PC, 4 - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - | mov FCARG1, L:RB - | mov FCARG2, dword [PC-4] - | mov SAVE_PC, PC - | call extern lj_meta_equal_cd@8 // (lua_State *L, BCIns ins) - | // 0/1 or TValue * (metamethod) returned in eax (RC). - | jmp <3 - |.endif - | - |->vmeta_istype: - |.if X64 - | mov L:RB, SAVE_L - | mov L:RB->base, BASE // Caveat: CARG2d/CARG3d may be BASE. - | mov CARG2d, RA - | movzx CARG3d, PC_RD - | mov L:CARG1d, L:RB - |.else - | movzx RD, PC_RD - | mov ARG2, RA - | mov L:RB, SAVE_L - | mov ARG3, RD - | mov ARG1, L:RB - | mov L:RB->base, BASE - |.endif - | mov SAVE_PC, PC - | call extern lj_meta_istype // (lua_State *L, BCReg ra, BCReg tp) - | mov BASE, L:RB->base - | jmp <6 - | - |//-- Arithmetic metamethods --------------------------------------------- - | - |->vmeta_arith_vno: - |.if DUALNUM - | movzx RB, PC_RB - |.endif - |->vmeta_arith_vn: - | lea RC, [KBASE+RC*8] - | jmp >1 - | - |->vmeta_arith_nvo: - |.if DUALNUM - | movzx RC, PC_RC - |.endif - |->vmeta_arith_nv: - | lea RC, [KBASE+RC*8] - | lea RB, [BASE+RB*8] - | xchg RB, RC - | jmp >2 - | - |->vmeta_unm: - | lea RC, [BASE+RD*8] - | mov RB, RC - | jmp >2 - | - |->vmeta_arith_vvo: - |.if DUALNUM - | movzx RB, PC_RB - |.endif - |->vmeta_arith_vv: - | lea RC, [BASE+RC*8] - |1: - | lea RB, [BASE+RB*8] - |2: - | lea RA, [BASE+RA*8] - |.if X64WIN - | mov CARG3d, RB - | mov CARG4d, RC - | movzx RC, PC_OP - | mov ARG5d, RC - | mov L:RB, SAVE_L - | mov L:RB->base, BASE // Caveat: CARG2d == BASE. - | mov CARG2d, RA - | mov CARG1d, L:RB // Caveat: CARG1d == RA. - |.elif X64 - | movzx CARG5d, PC_OP - | mov CARG2d, RA - | mov CARG4d, RC // Caveat: CARG4d == RA. - | mov L:CARG1d, SAVE_L - | mov L:CARG1d->base, BASE // Caveat: CARG3d == BASE. - | mov CARG3d, RB - | mov L:RB, L:CARG1d - |.else - | mov ARG3, RB - | mov L:RB, SAVE_L - | mov ARG4, RC - | movzx RC, PC_OP - | mov ARG2, RA - | mov ARG5, RC - | mov ARG1, L:RB - | mov L:RB->base, BASE - |.endif - | mov SAVE_PC, PC - | call extern lj_meta_arith // (lua_State *L, TValue *ra,*rb,*rc, BCReg op) - | // NULL (finished) or TValue * (metamethod) returned in eax (RC). - | mov BASE, L:RB->base - | test RC, RC - | jz ->cont_nop - | - | // Call metamethod for binary op. - |->vmeta_binop: - | // BASE = base, RC = new base, stack = cont/func/o1/o2 - | mov RA, RC - | sub RC, BASE - | mov [RA-12], PC // [cont|PC] - | lea PC, [RC+FRAME_CONT] - | mov NARGS:RD, 2+1 // 2 args for func(o1, o2). - | jmp ->vm_call_dispatch - | - |->vmeta_len: - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - | lea FCARG2, [BASE+RD*8] // Caveat: FCARG2 == BASE - | mov L:FCARG1, L:RB - | mov SAVE_PC, PC - | call extern lj_meta_len@8 // (lua_State *L, TValue *o) - | // NULL (retry) or TValue * (metamethod) returned in eax (RC). - | mov BASE, L:RB->base -#if LJ_52 - | test RC, RC - | jne ->vmeta_binop // Binop call for compatibility. - | movzx RD, PC_RD - | mov TAB:FCARG1, [BASE+RD*8] - | jmp ->BC_LEN_Z -#else - | jmp ->vmeta_binop // Binop call for compatibility. -#endif - | - |//-- Call metamethod ---------------------------------------------------- - | - |->vmeta_call_ra: - | lea RA, [BASE+RA*8+8] - |->vmeta_call: // Resolve and call __call metamethod. - | // BASE = old base, RA = new base, RC = nargs+1, PC = return - | mov TMP2, RA // Save RA, RC for us. - | mov TMP1, NARGS:RD - | sub RA, 8 - |.if X64 - | mov L:RB, SAVE_L - | mov L:RB->base, BASE // Caveat: CARG2d/CARG3d may be BASE. - | mov CARG2d, RA - | lea CARG3d, [RA+NARGS:RD*8] - | mov CARG1d, L:RB // Caveat: CARG1d may be RA. - |.else - | lea RC, [RA+NARGS:RD*8] - | mov L:RB, SAVE_L - | mov ARG2, RA - | mov ARG3, RC - | mov ARG1, L:RB - | mov L:RB->base, BASE // This is the callers base! - |.endif - | mov SAVE_PC, PC - | call extern lj_meta_call // (lua_State *L, TValue *func, TValue *top) - | mov BASE, L:RB->base - | mov RA, TMP2 - | mov NARGS:RD, TMP1 - | mov LFUNC:RB, [RA-8] - | add NARGS:RD, 1 - | // This is fragile. L->base must not move, KBASE must always be defined. - | cmp KBASE, BASE // Continue with CALLT if flag set. - | je ->BC_CALLT_Z - | mov BASE, RA - | ins_call // Otherwise call resolved metamethod. - | - |//-- Argument coercion for 'for' statement ------------------------------ - | - |->vmeta_for: - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - | mov FCARG2, RA // Caveat: FCARG2 == BASE - | mov L:FCARG1, L:RB // Caveat: FCARG1 == RA - | mov SAVE_PC, PC - | call extern lj_meta_for@8 // (lua_State *L, TValue *base) - | mov BASE, L:RB->base - | mov RC, [PC-4] - | movzx RA, RCH - | movzx OP, RCL - | shr RC, 16 - |.if X64 - | jmp aword [DISPATCH+OP*8+GG_DISP2STATIC] // Retry FORI or JFORI. - |.else - | jmp aword [DISPATCH+OP*4+GG_DISP2STATIC] // Retry FORI or JFORI. - |.endif - | - |//----------------------------------------------------------------------- - |//-- Fast functions ----------------------------------------------------- - |//----------------------------------------------------------------------- - | - |.macro .ffunc, name - |->ff_ .. name: - |.endmacro - | - |.macro .ffunc_1, name - |->ff_ .. name: - | cmp NARGS:RD, 1+1; jb ->fff_fallback - |.endmacro - | - |.macro .ffunc_2, name - |->ff_ .. name: - | cmp NARGS:RD, 2+1; jb ->fff_fallback - |.endmacro - | - |.macro .ffunc_nsse, name, op - | .ffunc_1 name - | cmp dword [BASE+4], LJ_TISNUM; jae ->fff_fallback - | op xmm0, qword [BASE] - |.endmacro - | - |.macro .ffunc_nsse, name - | .ffunc_nsse name, movsd - |.endmacro - | - |.macro .ffunc_nnsse, name - | .ffunc_2 name - | cmp dword [BASE+4], LJ_TISNUM; jae ->fff_fallback - | cmp dword [BASE+12], LJ_TISNUM; jae ->fff_fallback - | movsd xmm0, qword [BASE] - | movsd xmm1, qword [BASE+8] - |.endmacro - | - |.macro .ffunc_nnr, name - | .ffunc_2 name - | cmp dword [BASE+4], LJ_TISNUM; jae ->fff_fallback - | cmp dword [BASE+12], LJ_TISNUM; jae ->fff_fallback - | fld qword [BASE+8] - | fld qword [BASE] - |.endmacro - | - |// Inlined GC threshold check. Caveat: uses label 1. - |.macro ffgccheck - | mov RB, [DISPATCH+DISPATCH_GL(gc.total)] - | cmp RB, [DISPATCH+DISPATCH_GL(gc.threshold)] - | jb >1 - | call ->fff_gcstep - |1: - |.endmacro - | - |//-- Base library: checks ----------------------------------------------- - | - |.ffunc_1 assert - | mov RB, [BASE+4] - | cmp RB, LJ_TISTRUECOND; jae ->fff_fallback - | mov PC, [BASE-4] - | mov MULTRES, RD - | mov [BASE-4], RB - | mov RB, [BASE] - | mov [BASE-8], RB - | sub RD, 2 - | jz >2 - | mov RA, BASE - |1: - | add RA, 8 - |.if X64 - | mov RBa, [RA] - | mov [RA-8], RBa - |.else - | mov RB, [RA+4] - | mov [RA-4], RB - | mov RB, [RA] - | mov [RA-8], RB - |.endif - | sub RD, 1 - | jnz <1 - |2: - | mov RD, MULTRES - | jmp ->fff_res_ - | - |.ffunc_1 type - | mov RB, [BASE+4] - |.if X64 - | mov RA, RB - | sar RA, 15 - | cmp RA, -2 - | je >3 - |.endif - | mov RC, ~LJ_TNUMX - | not RB - | cmp RC, RB - | cmova RC, RB - |2: - | mov CFUNC:RB, [BASE-8] - | mov STR:RC, [CFUNC:RB+RC*8+((char *)(&((GCfuncC *)0)->upvalue))] - | mov PC, [BASE-4] - | mov dword [BASE-4], LJ_TSTR - | mov [BASE-8], STR:RC - | jmp ->fff_res1 - |.if X64 - |3: - | mov RC, ~LJ_TLIGHTUD - | jmp <2 - |.endif - | - |//-- Base library: getters and setters --------------------------------- - | - |.ffunc_1 getmetatable - | mov RB, [BASE+4] - | mov PC, [BASE-4] - | cmp RB, LJ_TTAB; jne >6 - |1: // Field metatable must be at same offset for GCtab and GCudata! - | mov TAB:RB, [BASE] - | mov TAB:RB, TAB:RB->metatable - |2: - | test TAB:RB, TAB:RB - | mov dword [BASE-4], LJ_TNIL - | jz ->fff_res1 - | mov STR:RC, [DISPATCH+DISPATCH_GL(gcroot)+4*(GCROOT_MMNAME+MM_metatable)] - | mov dword [BASE-4], LJ_TTAB // Store metatable as default result. - | mov [BASE-8], TAB:RB - | mov RA, TAB:RB->hmask - | and RA, STR:RC->hash - | imul RA, #NODE - | add NODE:RA, TAB:RB->node - |3: // Rearranged logic, because we expect _not_ to find the key. - | cmp dword NODE:RA->key.it, LJ_TSTR - | jne >4 - | cmp dword NODE:RA->key.gcr, STR:RC - | je >5 - |4: - | mov NODE:RA, NODE:RA->next - | test NODE:RA, NODE:RA - | jnz <3 - | jmp ->fff_res1 // Not found, keep default result. - |5: - | mov RB, [RA+4] - | cmp RB, LJ_TNIL; je ->fff_res1 // Ditto for nil value. - | mov RC, [RA] - | mov [BASE-4], RB // Return value of mt.__metatable. - | mov [BASE-8], RC - | jmp ->fff_res1 - | - |6: - | cmp RB, LJ_TUDATA; je <1 - |.if X64 - | cmp RB, LJ_TNUMX; ja >8 - | cmp RB, LJ_TISNUM; jbe >7 - | mov RB, LJ_TLIGHTUD - | jmp >8 - |7: - |.else - | cmp RB, LJ_TISNUM; ja >8 - |.endif - | mov RB, LJ_TNUMX - |8: - | not RB - | mov TAB:RB, [DISPATCH+RB*4+DISPATCH_GL(gcroot[GCROOT_BASEMT])] - | jmp <2 - | - |.ffunc_2 setmetatable - | cmp dword [BASE+4], LJ_TTAB; jne ->fff_fallback - | // Fast path: no mt for table yet and not clearing the mt. - | mov TAB:RB, [BASE] - | cmp dword TAB:RB->metatable, 0; jne ->fff_fallback - | cmp dword [BASE+12], LJ_TTAB; jne ->fff_fallback - | mov TAB:RC, [BASE+8] - | mov TAB:RB->metatable, TAB:RC - | mov PC, [BASE-4] - | mov dword [BASE-4], LJ_TTAB // Return original table. - | mov [BASE-8], TAB:RB - | test byte TAB:RB->marked, LJ_GC_BLACK // isblack(table) - | jz >1 - | // Possible write barrier. Table is black, but skip iswhite(mt) check. - | barrierback TAB:RB, RC - |1: - | jmp ->fff_res1 - | - |.ffunc_2 rawget - | cmp dword [BASE+4], LJ_TTAB; jne ->fff_fallback - |.if X64WIN - | mov RB, BASE // Save BASE. - | lea CARG3d, [BASE+8] - | mov CARG2d, [BASE] // Caveat: CARG2d == BASE. - | mov CARG1d, SAVE_L - |.elif X64 - | mov RB, BASE // Save BASE. - | mov CARG2d, [BASE] - | lea CARG3d, [BASE+8] // Caveat: CARG3d == BASE. - | mov CARG1d, SAVE_L - |.else - | mov TAB:RD, [BASE] - | mov L:RB, SAVE_L - | mov ARG2, TAB:RD - | mov ARG1, L:RB - | mov RB, BASE // Save BASE. - | add BASE, 8 - | mov ARG3, BASE - |.endif - | call extern lj_tab_get // (lua_State *L, GCtab *t, cTValue *key) - | // cTValue * returned in eax (RD). - | mov BASE, RB // Restore BASE. - | // Copy table slot. - |.if X64 - | mov RBa, [RD] - | mov PC, [BASE-4] - | mov [BASE-8], RBa - |.else - | mov RB, [RD] - | mov RD, [RD+4] - | mov PC, [BASE-4] - | mov [BASE-8], RB - | mov [BASE-4], RD - |.endif - | jmp ->fff_res1 - | - |//-- Base library: conversions ------------------------------------------ - | - |.ffunc tonumber - | // Only handles the number case inline (without a base argument). - | cmp NARGS:RD, 1+1; jne ->fff_fallback // Exactly one argument. - | cmp dword [BASE+4], LJ_TISNUM - |.if DUALNUM - | jne >1 - | mov RB, dword [BASE]; jmp ->fff_resi - |1: - | ja ->fff_fallback - |.else - | jae ->fff_fallback - |.endif - | movsd xmm0, qword [BASE]; jmp ->fff_resxmm0 - | - |.ffunc_1 tostring - | // Only handles the string or number case inline. - | mov PC, [BASE-4] - | cmp dword [BASE+4], LJ_TSTR; jne >3 - | // A __tostring method in the string base metatable is ignored. - | mov STR:RD, [BASE] - |2: - | mov dword [BASE-4], LJ_TSTR - | mov [BASE-8], STR:RD - | jmp ->fff_res1 - |3: // Handle numbers inline, unless a number base metatable is present. - | cmp dword [BASE+4], LJ_TISNUM; ja ->fff_fallback - | cmp dword [DISPATCH+DISPATCH_GL(gcroot[GCROOT_BASEMT_NUM])], 0 - | jne ->fff_fallback - | ffgccheck // Caveat: uses label 1. - | mov L:RB, SAVE_L - | mov L:RB->base, BASE // Add frame since C call can throw. - | mov SAVE_PC, PC // Redundant (but a defined value). - |.if X64 and not X64WIN - | mov FCARG2, BASE // Otherwise: FCARG2 == BASE - |.endif - | mov L:FCARG1, L:RB - |.if DUALNUM - | call extern lj_strfmt_number@8 // (lua_State *L, cTValue *o) - |.else - | call extern lj_strfmt_num@8 // (lua_State *L, lua_Number *np) - |.endif - | // GCstr returned in eax (RD). - | mov BASE, L:RB->base - | jmp <2 - | - |//-- Base library: iterators ------------------------------------------- - | - |.ffunc_1 next - | je >2 // Missing 2nd arg? - |1: - | cmp dword [BASE+4], LJ_TTAB; jne ->fff_fallback - | mov L:RB, SAVE_L - | mov L:RB->base, BASE // Add frame since C call can throw. - | mov L:RB->top, BASE // Dummy frame length is ok. - | mov PC, [BASE-4] - |.if X64WIN - | lea CARG3d, [BASE+8] - | mov CARG2d, [BASE] // Caveat: CARG2d == BASE. - | mov CARG1d, L:RB - |.elif X64 - | mov CARG2d, [BASE] - | lea CARG3d, [BASE+8] // Caveat: CARG3d == BASE. - | mov CARG1d, L:RB - |.else - | mov TAB:RD, [BASE] - | mov ARG2, TAB:RD - | mov ARG1, L:RB - | add BASE, 8 - | mov ARG3, BASE - |.endif - | mov SAVE_PC, PC // Needed for ITERN fallback. - | call extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key) - | // Flag returned in eax (RD). - | mov BASE, L:RB->base - | test RD, RD; jz >3 // End of traversal? - | // Copy key and value to results. - |.if X64 - | mov RBa, [BASE+8] - | mov RDa, [BASE+16] - | mov [BASE-8], RBa - | mov [BASE], RDa - |.else - | mov RB, [BASE+8] - | mov RD, [BASE+12] - | mov [BASE-8], RB - | mov [BASE-4], RD - | mov RB, [BASE+16] - | mov RD, [BASE+20] - | mov [BASE], RB - | mov [BASE+4], RD - |.endif - |->fff_res2: - | mov RD, 1+2 - | jmp ->fff_res - |2: // Set missing 2nd arg to nil. - | mov dword [BASE+12], LJ_TNIL - | jmp <1 - |3: // End of traversal: return nil. - | mov dword [BASE-4], LJ_TNIL - | jmp ->fff_res1 - | - |.ffunc_1 pairs - | mov TAB:RB, [BASE] - | cmp dword [BASE+4], LJ_TTAB; jne ->fff_fallback -#if LJ_52 - | cmp dword TAB:RB->metatable, 0; jne ->fff_fallback -#endif - | mov CFUNC:RB, [BASE-8] - | mov CFUNC:RD, CFUNC:RB->upvalue[0] - | mov PC, [BASE-4] - | mov dword [BASE-4], LJ_TFUNC - | mov [BASE-8], CFUNC:RD - | mov dword [BASE+12], LJ_TNIL - | mov RD, 1+3 - | jmp ->fff_res - | - |.ffunc_2 ipairs_aux - | cmp dword [BASE+4], LJ_TTAB; jne ->fff_fallback - | cmp dword [BASE+12], LJ_TISNUM - |.if DUALNUM - | jne ->fff_fallback - |.else - | jae ->fff_fallback - |.endif - | mov PC, [BASE-4] - |.if DUALNUM - | mov RD, dword [BASE+8] - | add RD, 1 - | mov dword [BASE-4], LJ_TISNUM - | mov dword [BASE-8], RD - |.else - | movsd xmm0, qword [BASE+8] - | sseconst_1 xmm1, RBa - | addsd xmm0, xmm1 - | cvttsd2si RD, xmm0 - | movsd qword [BASE-8], xmm0 - |.endif - | mov TAB:RB, [BASE] - | cmp RD, TAB:RB->asize; jae >2 // Not in array part? - | shl RD, 3 - | add RD, TAB:RB->array - |1: - | cmp dword [RD+4], LJ_TNIL; je ->fff_res0 - | // Copy array slot. - |.if X64 - | mov RBa, [RD] - | mov [BASE], RBa - |.else - | mov RB, [RD] - | mov RD, [RD+4] - | mov [BASE], RB - | mov [BASE+4], RD - |.endif - | jmp ->fff_res2 - |2: // Check for empty hash part first. Otherwise call C function. - | cmp dword TAB:RB->hmask, 0; je ->fff_res0 - | mov FCARG1, TAB:RB - | mov RB, BASE // Save BASE. - | mov FCARG2, RD // Caveat: FCARG2 == BASE - | call extern lj_tab_getinth@8 // (GCtab *t, int32_t key) - | // cTValue * or NULL returned in eax (RD). - | mov BASE, RB - | test RD, RD - | jnz <1 - |->fff_res0: - | mov RD, 1+0 - | jmp ->fff_res - | - |.ffunc_1 ipairs - | mov TAB:RB, [BASE] - | cmp dword [BASE+4], LJ_TTAB; jne ->fff_fallback -#if LJ_52 - | cmp dword TAB:RB->metatable, 0; jne ->fff_fallback -#endif - | mov CFUNC:RB, [BASE-8] - | mov CFUNC:RD, CFUNC:RB->upvalue[0] - | mov PC, [BASE-4] - | mov dword [BASE-4], LJ_TFUNC - | mov [BASE-8], CFUNC:RD - |.if DUALNUM - | mov dword [BASE+12], LJ_TISNUM - | mov dword [BASE+8], 0 - |.else - | xorps xmm0, xmm0 - | movsd qword [BASE+8], xmm0 - |.endif - | mov RD, 1+3 - | jmp ->fff_res - | - |//-- Base library: catch errors ---------------------------------------- - | - |.ffunc_1 pcall - | lea RA, [BASE+8] - | sub NARGS:RD, 1 - | mov PC, 8+FRAME_PCALL - |1: - | movzx RB, byte [DISPATCH+DISPATCH_GL(hookmask)] - | shr RB, HOOK_ACTIVE_SHIFT - | and RB, 1 - | add PC, RB // Remember active hook before pcall. - | jmp ->vm_call_dispatch - | - |.ffunc_2 xpcall - | cmp dword [BASE+12], LJ_TFUNC; jne ->fff_fallback - | mov RB, [BASE+4] // Swap function and traceback. - | mov [BASE+12], RB - | mov dword [BASE+4], LJ_TFUNC - | mov LFUNC:RB, [BASE] - | mov PC, [BASE+8] - | mov [BASE+8], LFUNC:RB - | mov [BASE], PC - | lea RA, [BASE+16] - | sub NARGS:RD, 2 - | mov PC, 16+FRAME_PCALL - | jmp <1 - | - |//-- Coroutine library -------------------------------------------------- - | - |.macro coroutine_resume_wrap, resume - |.if resume - |.ffunc_1 coroutine_resume - | mov L:RB, [BASE] - |.else - |.ffunc coroutine_wrap_aux - | mov CFUNC:RB, [BASE-8] - | mov L:RB, CFUNC:RB->upvalue[0].gcr - |.endif - | mov PC, [BASE-4] - | mov SAVE_PC, PC - |.if X64 - | mov TMP1, L:RB - |.else - | mov ARG1, L:RB - |.endif - |.if resume - | cmp dword [BASE+4], LJ_TTHREAD; jne ->fff_fallback - |.endif - | cmp aword L:RB->cframe, 0; jne ->fff_fallback - | cmp byte L:RB->status, LUA_YIELD; ja ->fff_fallback - | mov RA, L:RB->top - | je >1 // Status != LUA_YIELD (i.e. 0)? - | cmp RA, L:RB->base // Check for presence of initial func. - | je ->fff_fallback - |1: - |.if resume - | lea PC, [RA+NARGS:RD*8-16] // Check stack space (-1-thread). - |.else - | lea PC, [RA+NARGS:RD*8-8] // Check stack space (-1). - |.endif - | cmp PC, L:RB->maxstack; ja ->fff_fallback - | mov L:RB->top, PC - | - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - |.if resume - | add BASE, 8 // Keep resumed thread in stack for GC. - |.endif - | mov L:RB->top, BASE - |.if resume - | lea RB, [BASE+NARGS:RD*8-24] // RB = end of source for stack move. - |.else - | lea RB, [BASE+NARGS:RD*8-16] // RB = end of source for stack move. - |.endif - | sub RBa, PCa // Relative to PC. - | - | cmp PC, RA - | je >3 - |2: // Move args to coroutine. - |.if X64 - | mov RCa, [PC+RB] - | mov [PC-8], RCa - |.else - | mov RC, [PC+RB+4] - | mov [PC-4], RC - | mov RC, [PC+RB] - | mov [PC-8], RC - |.endif - | sub PC, 8 - | cmp PC, RA - | jne <2 - |3: - |.if X64 - | mov CARG2d, RA - | mov CARG1d, TMP1 - |.else - | mov ARG2, RA - | xor RA, RA - | mov ARG4, RA - | mov ARG3, RA - |.endif - | call ->vm_resume // (lua_State *L, TValue *base, 0, 0) - | - | mov L:RB, SAVE_L - |.if X64 - | mov L:PC, TMP1 - |.else - | mov L:PC, ARG1 // The callee doesn't modify SAVE_L. - |.endif - | mov BASE, L:RB->base - | mov [DISPATCH+DISPATCH_GL(cur_L)], L:RB - | set_vmstate INTERP - | - | cmp eax, LUA_YIELD - | ja >8 - |4: - | mov RA, L:PC->base - | mov KBASE, L:PC->top - | mov L:PC->top, RA // Clear coroutine stack. - | mov PC, KBASE - | sub PC, RA - | je >6 // No results? - | lea RD, [BASE+PC] - | shr PC, 3 - | cmp RD, L:RB->maxstack - | ja >9 // Need to grow stack? - | - | mov RB, BASE - | sub RBa, RAa - |5: // Move results from coroutine. - |.if X64 - | mov RDa, [RA] - | mov [RA+RB], RDa - |.else - | mov RD, [RA] - | mov [RA+RB], RD - | mov RD, [RA+4] - | mov [RA+RB+4], RD - |.endif - | add RA, 8 - | cmp RA, KBASE - | jne <5 - |6: - |.if resume - | lea RD, [PC+2] // nresults+1 = 1 + true + results. - | mov dword [BASE-4], LJ_TTRUE // Prepend true to results. - |.else - | lea RD, [PC+1] // nresults+1 = 1 + results. - |.endif - |7: - | mov PC, SAVE_PC - | mov MULTRES, RD - |.if resume - | mov RAa, -8 - |.else - | xor RA, RA - |.endif - | test PC, FRAME_TYPE - | jz ->BC_RET_Z - | jmp ->vm_return - | - |8: // Coroutine returned with error (at co->top-1). - |.if resume - | mov dword [BASE-4], LJ_TFALSE // Prepend false to results. - | mov RA, L:PC->top - | sub RA, 8 - | mov L:PC->top, RA // Clear error from coroutine stack. - | // Copy error message. - |.if X64 - | mov RDa, [RA] - | mov [BASE], RDa - |.else - | mov RD, [RA] - | mov [BASE], RD - | mov RD, [RA+4] - | mov [BASE+4], RD - |.endif - | mov RD, 1+2 // nresults+1 = 1 + false + error. - | jmp <7 - |.else - | mov FCARG2, L:PC - | mov FCARG1, L:RB - | call extern lj_ffh_coroutine_wrap_err@8 // (lua_State *L, lua_State *co) - | // Error function does not return. - |.endif - | - |9: // Handle stack expansion on return from yield. - |.if X64 - | mov L:RA, TMP1 - |.else - | mov L:RA, ARG1 // The callee doesn't modify SAVE_L. - |.endif - | mov L:RA->top, KBASE // Undo coroutine stack clearing. - | mov FCARG2, PC - | mov FCARG1, L:RB - | call extern lj_state_growstack@8 // (lua_State *L, int n) - |.if X64 - | mov L:PC, TMP1 - |.else - | mov L:PC, ARG1 - |.endif - | mov BASE, L:RB->base - | jmp <4 // Retry the stack move. - |.endmacro - | - | coroutine_resume_wrap 1 // coroutine.resume - | coroutine_resume_wrap 0 // coroutine.wrap - | - |.ffunc coroutine_yield - | mov L:RB, SAVE_L - | test aword L:RB->cframe, CFRAME_RESUME - | jz ->fff_fallback - | mov L:RB->base, BASE - | lea RD, [BASE+NARGS:RD*8-8] - | mov L:RB->top, RD - | xor RD, RD - | mov aword L:RB->cframe, RDa - | mov al, LUA_YIELD - | mov byte L:RB->status, al - | jmp ->vm_leave_unw - | - |//-- Math library ------------------------------------------------------- - | - |.if not DUALNUM - |->fff_resi: // Dummy. - |.endif - | - |->fff_resn: - | mov PC, [BASE-4] - | fstp qword [BASE-8] - | jmp ->fff_res1 - | - | .ffunc_1 math_abs - |.if DUALNUM - | cmp dword [BASE+4], LJ_TISNUM; jne >2 - | mov RB, dword [BASE] - | cmp RB, 0; jns ->fff_resi - | neg RB; js >1 - |->fff_resbit: - |->fff_resi: - | mov PC, [BASE-4] - | mov dword [BASE-4], LJ_TISNUM - | mov dword [BASE-8], RB - | jmp ->fff_res1 - |1: - | mov PC, [BASE-4] - | mov dword [BASE-4], 0x41e00000 // 2^31. - | mov dword [BASE-8], 0 - | jmp ->fff_res1 - |2: - | ja ->fff_fallback - |.else - | cmp dword [BASE+4], LJ_TISNUM; jae ->fff_fallback - |.endif - | movsd xmm0, qword [BASE] - | sseconst_abs xmm1, RDa - | andps xmm0, xmm1 - |->fff_resxmm0: - | mov PC, [BASE-4] - | movsd qword [BASE-8], xmm0 - | // fallthrough - | - |->fff_res1: - | mov RD, 1+1 - |->fff_res: - | mov MULTRES, RD - |->fff_res_: - | test PC, FRAME_TYPE - | jnz >7 - |5: - | cmp PC_RB, RDL // More results expected? - | ja >6 - | // Adjust BASE. KBASE is assumed to be set for the calling frame. - | movzx RA, PC_RA - | not RAa // Note: ~RA = -(RA+1) - | lea BASE, [BASE+RA*8] // base = base - (RA+1)*8 - | ins_next - | - |6: // Fill up results with nil. - | mov dword [BASE+RD*8-12], LJ_TNIL - | add RD, 1 - | jmp <5 - | - |7: // Non-standard return case. - | mov RAa, -8 // Results start at BASE+RA = BASE-8. - | jmp ->vm_return - | - |.if X64 - |.define fff_resfp, fff_resxmm0 - |.else - |.define fff_resfp, fff_resn - |.endif - | - |.macro math_round, func - | .ffunc math_ .. func - |.if DUALNUM - | cmp dword [BASE+4], LJ_TISNUM; jne >1 - | mov RB, dword [BASE]; jmp ->fff_resi - |1: - | ja ->fff_fallback - |.else - | cmp dword [BASE+4], LJ_TISNUM; jae ->fff_fallback - |.endif - | movsd xmm0, qword [BASE] - | call ->vm_ .. func .. _sse - |.if DUALNUM - | cvttsd2si RB, xmm0 - | cmp RB, 0x80000000 - | jne ->fff_resi - | cvtsi2sd xmm1, RB - | ucomisd xmm0, xmm1 - | jp ->fff_resxmm0 - | je ->fff_resi - |.endif - | jmp ->fff_resxmm0 - |.endmacro - | - | math_round floor - | math_round ceil - | - |.ffunc_nsse math_sqrt, sqrtsd; jmp ->fff_resxmm0 - | - |.ffunc math_log - | cmp NARGS:RD, 1+1; jne ->fff_fallback // Exactly one argument. - | cmp dword [BASE+4], LJ_TISNUM; jae ->fff_fallback - | movsd xmm0, qword [BASE] - |.if not X64 - | movsd FPARG1, xmm0 - |.endif - | mov RB, BASE - | call extern log - | mov BASE, RB - | jmp ->fff_resfp - | - |.macro math_extern, func - | .ffunc_nsse math_ .. func - |.if not X64 - | movsd FPARG1, xmm0 - |.endif - | mov RB, BASE - | call extern func - | mov BASE, RB - | jmp ->fff_resfp - |.endmacro - | - |.macro math_extern2, func - | .ffunc_nnsse math_ .. func - |.if not X64 - | movsd FPARG1, xmm0 - | movsd FPARG3, xmm1 - |.endif - | mov RB, BASE - | call extern func - | mov BASE, RB - | jmp ->fff_resfp - |.endmacro - | - | math_extern log10 - | math_extern exp - | math_extern sin - | math_extern cos - | math_extern tan - | math_extern asin - | math_extern acos - | math_extern atan - | math_extern sinh - | math_extern cosh - | math_extern tanh - | math_extern2 pow - | math_extern2 atan2 - | math_extern2 fmod - | - |.ffunc_nnr math_ldexp; fscale; fpop1; jmp ->fff_resn - | - |.ffunc_1 math_frexp - | mov RB, [BASE+4] - | cmp RB, LJ_TISNUM; jae ->fff_fallback - | mov PC, [BASE-4] - | mov RC, [BASE] - | mov [BASE-4], RB; mov [BASE-8], RC - | shl RB, 1; cmp RB, 0xffe00000; jae >3 - | or RC, RB; jz >3 - | mov RC, 1022 - | cmp RB, 0x00200000; jb >4 - |1: - | shr RB, 21; sub RB, RC // Extract and unbias exponent. - | cvtsi2sd xmm0, RB - | mov RB, [BASE-4] - | and RB, 0x800fffff // Mask off exponent. - | or RB, 0x3fe00000 // Put mantissa in range [0.5,1) or 0. - | mov [BASE-4], RB - |2: - | movsd qword [BASE], xmm0 - | mov RD, 1+2 - | jmp ->fff_res - |3: // Return +-0, +-Inf, NaN unmodified and an exponent of 0. - | xorps xmm0, xmm0; jmp <2 - |4: // Handle denormals by multiplying with 2^54 and adjusting the bias. - | movsd xmm0, qword [BASE] - | sseconst_hi xmm1, RBa, 43500000 // 2^54. - | mulsd xmm0, xmm1 - | movsd qword [BASE-8], xmm0 - | mov RB, [BASE-4]; mov RC, 1076; shl RB, 1; jmp <1 - | - |.ffunc_nsse math_modf - | mov RB, [BASE+4] - | mov PC, [BASE-4] - | shl RB, 1; cmp RB, 0xffe00000; je >4 // +-Inf? - | movaps xmm4, xmm0 - | call ->vm_trunc_sse - | subsd xmm4, xmm0 - |1: - | movsd qword [BASE-8], xmm0 - | movsd qword [BASE], xmm4 - | mov RC, [BASE-4]; mov RB, [BASE+4] - | xor RC, RB; js >3 // Need to adjust sign? - |2: - | mov RD, 1+2 - | jmp ->fff_res - |3: - | xor RB, 0x80000000; mov [BASE+4], RB // Flip sign of fraction. - | jmp <2 - |4: - | xorps xmm4, xmm4; jmp <1 // Return +-Inf and +-0. - | - |.macro math_minmax, name, cmovop, sseop - | .ffunc name - | mov RA, 2 - | cmp dword [BASE+4], LJ_TISNUM - |.if DUALNUM - | jne >4 - | mov RB, dword [BASE] - |1: // Handle integers. - | cmp RA, RD; jae ->fff_resi - | cmp dword [BASE+RA*8-4], LJ_TISNUM; jne >3 - | cmp RB, dword [BASE+RA*8-8] - | cmovop RB, dword [BASE+RA*8-8] - | add RA, 1 - | jmp <1 - |3: - | ja ->fff_fallback - | // Convert intermediate result to number and continue below. - | cvtsi2sd xmm0, RB - | jmp >6 - |4: - | ja ->fff_fallback - |.else - | jae ->fff_fallback - |.endif - | - | movsd xmm0, qword [BASE] - |5: // Handle numbers or integers. - | cmp RA, RD; jae ->fff_resxmm0 - | cmp dword [BASE+RA*8-4], LJ_TISNUM - |.if DUALNUM - | jb >6 - | ja ->fff_fallback - | cvtsi2sd xmm1, dword [BASE+RA*8-8] - | jmp >7 - |.else - | jae ->fff_fallback - |.endif - |6: - | movsd xmm1, qword [BASE+RA*8-8] - |7: - | sseop xmm0, xmm1 - | add RA, 1 - | jmp <5 - |.endmacro - | - | math_minmax math_min, cmovg, minsd - | math_minmax math_max, cmovl, maxsd - | - |//-- String library ----------------------------------------------------- - | - |.ffunc string_byte // Only handle the 1-arg case here. - | cmp NARGS:RD, 1+1; jne ->fff_fallback - | cmp dword [BASE+4], LJ_TSTR; jne ->fff_fallback - | mov STR:RB, [BASE] - | mov PC, [BASE-4] - | cmp dword STR:RB->len, 1 - | jb ->fff_res0 // Return no results for empty string. - | movzx RB, byte STR:RB[1] - |.if DUALNUM - | jmp ->fff_resi - |.else - | cvtsi2sd xmm0, RB; jmp ->fff_resxmm0 - |.endif - | - |.ffunc string_char // Only handle the 1-arg case here. - | ffgccheck - | cmp NARGS:RD, 1+1; jne ->fff_fallback // *Exactly* 1 arg. - | cmp dword [BASE+4], LJ_TISNUM - |.if DUALNUM - | jne ->fff_fallback - | mov RB, dword [BASE] - | cmp RB, 255; ja ->fff_fallback - | mov TMP2, RB - |.else - | jae ->fff_fallback - | cvttsd2si RB, qword [BASE] - | cmp RB, 255; ja ->fff_fallback - | mov TMP2, RB - |.endif - |.if X64 - | mov TMP3, 1 - |.else - | mov ARG3, 1 - |.endif - | lea RDa, TMP2 // Points to stack. Little-endian. - |->fff_newstr: - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - |.if X64 - | mov CARG3d, TMP3 // Zero-extended to size_t. - | mov CARG2, RDa // May be 64 bit ptr to stack. - | mov CARG1d, L:RB - |.else - | mov ARG2, RD - | mov ARG1, L:RB - |.endif - | mov SAVE_PC, PC - | call extern lj_str_new // (lua_State *L, char *str, size_t l) - |->fff_resstr: - | // GCstr * returned in eax (RD). - | mov BASE, L:RB->base - | mov PC, [BASE-4] - | mov dword [BASE-4], LJ_TSTR - | mov [BASE-8], STR:RD - | jmp ->fff_res1 - | - |.ffunc string_sub - | ffgccheck - | mov TMP2, -1 - | cmp NARGS:RD, 1+2; jb ->fff_fallback - | jna >1 - | cmp dword [BASE+20], LJ_TISNUM - |.if DUALNUM - | jne ->fff_fallback - | mov RB, dword [BASE+16] - | mov TMP2, RB - |.else - | jae ->fff_fallback - | cvttsd2si RB, qword [BASE+16] - | mov TMP2, RB - |.endif - |1: - | cmp dword [BASE+4], LJ_TSTR; jne ->fff_fallback - | cmp dword [BASE+12], LJ_TISNUM - |.if DUALNUM - | jne ->fff_fallback - |.else - | jae ->fff_fallback - |.endif - | mov STR:RB, [BASE] - | mov TMP3, STR:RB - | mov RB, STR:RB->len - |.if DUALNUM - | mov RA, dword [BASE+8] - |.else - | cvttsd2si RA, qword [BASE+8] - |.endif - | mov RC, TMP2 - | cmp RB, RC // len < end? (unsigned compare) - | jb >5 - |2: - | test RA, RA // start <= 0? - | jle >7 - |3: - | mov STR:RB, TMP3 - | sub RC, RA // start > end? - | jl ->fff_emptystr - | lea RB, [STR:RB+RA+#STR-1] - | add RC, 1 - |4: - |.if X64 - | mov TMP3, RC - |.else - | mov ARG3, RC - |.endif - | mov RD, RB - | jmp ->fff_newstr - | - |5: // Negative end or overflow. - | jl >6 - | lea RC, [RC+RB+1] // end = end+(len+1) - | jmp <2 - |6: // Overflow. - | mov RC, RB // end = len - | jmp <2 - | - |7: // Negative start or underflow. - | je >8 - | add RA, RB // start = start+(len+1) - | add RA, 1 - | jg <3 // start > 0? - |8: // Underflow. - | mov RA, 1 // start = 1 - | jmp <3 - | - |->fff_emptystr: // Range underflow. - | xor RC, RC // Zero length. Any ptr in RB is ok. - | jmp <4 - | - |.macro ffstring_op, name - | .ffunc_1 string_ .. name - | ffgccheck - | cmp dword [BASE+4], LJ_TSTR; jne ->fff_fallback - | mov L:RB, SAVE_L - | lea SBUF:FCARG1, [DISPATCH+DISPATCH_GL(tmpbuf)] - | mov L:RB->base, BASE - | mov STR:FCARG2, [BASE] // Caveat: FCARG2 == BASE - | mov RC, SBUF:FCARG1->b - | mov SBUF:FCARG1->L, L:RB - | mov SBUF:FCARG1->p, RC - | mov SAVE_PC, PC - | call extern lj_buf_putstr_ .. name .. @8 - | mov FCARG1, eax - | call extern lj_buf_tostr@4 - | jmp ->fff_resstr - |.endmacro - | - |ffstring_op reverse - |ffstring_op lower - |ffstring_op upper - | - |//-- Bit library -------------------------------------------------------- - | - |.macro .ffunc_bit, name, kind, fdef - | fdef name - |.if kind == 2 - | sseconst_tobit xmm1, RBa - |.endif - | cmp dword [BASE+4], LJ_TISNUM - |.if DUALNUM - | jne >1 - | mov RB, dword [BASE] - |.if kind > 0 - | jmp >2 - |.else - | jmp ->fff_resbit - |.endif - |1: - | ja ->fff_fallback - |.else - | jae ->fff_fallback - |.endif - | movsd xmm0, qword [BASE] - |.if kind < 2 - | sseconst_tobit xmm1, RBa - |.endif - | addsd xmm0, xmm1 - | movd RB, xmm0 - |2: - |.endmacro - | - |.macro .ffunc_bit, name, kind - | .ffunc_bit name, kind, .ffunc_1 - |.endmacro - | - |.ffunc_bit bit_tobit, 0 - | jmp ->fff_resbit - | - |.macro .ffunc_bit_op, name, ins - | .ffunc_bit name, 2 - | mov TMP2, NARGS:RD // Save for fallback. - | lea RD, [BASE+NARGS:RD*8-16] - |1: - | cmp RD, BASE - | jbe ->fff_resbit - | cmp dword [RD+4], LJ_TISNUM - |.if DUALNUM - | jne >2 - | ins RB, dword [RD] - | sub RD, 8 - | jmp <1 - |2: - | ja ->fff_fallback_bit_op - |.else - | jae ->fff_fallback_bit_op - |.endif - | movsd xmm0, qword [RD] - | addsd xmm0, xmm1 - | movd RA, xmm0 - | ins RB, RA - | sub RD, 8 - | jmp <1 - |.endmacro - | - |.ffunc_bit_op bit_band, and - |.ffunc_bit_op bit_bor, or - |.ffunc_bit_op bit_bxor, xor - | - |.ffunc_bit bit_bswap, 1 - | bswap RB - | jmp ->fff_resbit - | - |.ffunc_bit bit_bnot, 1 - | not RB - |.if DUALNUM - | jmp ->fff_resbit - |.else - |->fff_resbit: - | cvtsi2sd xmm0, RB - | jmp ->fff_resxmm0 - |.endif - | - |->fff_fallback_bit_op: - | mov NARGS:RD, TMP2 // Restore for fallback - | jmp ->fff_fallback - | - |.macro .ffunc_bit_sh, name, ins - |.if DUALNUM - | .ffunc_bit name, 1, .ffunc_2 - | // Note: no inline conversion from number for 2nd argument! - | cmp dword [BASE+12], LJ_TISNUM; jne ->fff_fallback - | mov RA, dword [BASE+8] - |.else - | .ffunc_nnsse name - | sseconst_tobit xmm2, RBa - | addsd xmm0, xmm2 - | addsd xmm1, xmm2 - | movd RB, xmm0 - | movd RA, xmm1 - |.endif - | ins RB, cl // Assumes RA is ecx. - | jmp ->fff_resbit - |.endmacro - | - |.ffunc_bit_sh bit_lshift, shl - |.ffunc_bit_sh bit_rshift, shr - |.ffunc_bit_sh bit_arshift, sar - |.ffunc_bit_sh bit_rol, rol - |.ffunc_bit_sh bit_ror, ror - | - |//----------------------------------------------------------------------- - | - |->fff_fallback_2: - | mov NARGS:RD, 1+2 // Other args are ignored, anyway. - | jmp ->fff_fallback - |->fff_fallback_1: - | mov NARGS:RD, 1+1 // Other args are ignored, anyway. - |->fff_fallback: // Call fast function fallback handler. - | // BASE = new base, RD = nargs+1 - | mov L:RB, SAVE_L - | mov PC, [BASE-4] // Fallback may overwrite PC. - | mov SAVE_PC, PC // Redundant (but a defined value). - | mov L:RB->base, BASE - | lea RD, [BASE+NARGS:RD*8-8] - | lea RA, [RD+8*LUA_MINSTACK] // Ensure enough space for handler. - | mov L:RB->top, RD - | mov CFUNC:RD, [BASE-8] - | cmp RA, L:RB->maxstack - | ja >5 // Need to grow stack. - |.if X64 - | mov CARG1d, L:RB - |.else - | mov ARG1, L:RB - |.endif - | call aword CFUNC:RD->f // (lua_State *L) - | mov BASE, L:RB->base - | // Either throws an error, or recovers and returns -1, 0 or nresults+1. - | test RD, RD; jg ->fff_res // Returned nresults+1? - |1: - | mov RA, L:RB->top - | sub RA, BASE - | shr RA, 3 - | test RD, RD - | lea NARGS:RD, [RA+1] - | mov LFUNC:RB, [BASE-8] - | jne ->vm_call_tail // Returned -1? - | ins_callt // Returned 0: retry fast path. - | - |// Reconstruct previous base for vmeta_call during tailcall. - |->vm_call_tail: - | mov RA, BASE - | test PC, FRAME_TYPE - | jnz >3 - | movzx RB, PC_RA - | not RBa // Note: ~RB = -(RB+1) - | lea BASE, [BASE+RB*8] // base = base - (RB+1)*8 - | jmp ->vm_call_dispatch // Resolve again for tailcall. - |3: - | mov RB, PC - | and RB, -8 - | sub BASE, RB - | jmp ->vm_call_dispatch // Resolve again for tailcall. - | - |5: // Grow stack for fallback handler. - | mov FCARG2, LUA_MINSTACK - | mov FCARG1, L:RB - | call extern lj_state_growstack@8 // (lua_State *L, int n) - | mov BASE, L:RB->base - | xor RD, RD // Simulate a return 0. - | jmp <1 // Dumb retry (goes through ff first). - | - |->fff_gcstep: // Call GC step function. - | // BASE = new base, RD = nargs+1 - | pop RBa // Must keep stack at same level. - | mov TMPa, RBa // Save return address - | mov L:RB, SAVE_L - | mov SAVE_PC, PC // Redundant (but a defined value). - | mov L:RB->base, BASE - | lea RD, [BASE+NARGS:RD*8-8] - | mov FCARG1, L:RB - | mov L:RB->top, RD - | call extern lj_gc_step@4 // (lua_State *L) - | mov BASE, L:RB->base - | mov RD, L:RB->top - | sub RD, BASE - | shr RD, 3 - | add NARGS:RD, 1 - | mov RBa, TMPa - | push RBa // Restore return address. - | ret - | - |//----------------------------------------------------------------------- - |//-- Special dispatch targets ------------------------------------------- - |//----------------------------------------------------------------------- - | - |->vm_record: // Dispatch target for recording phase. - |.if JIT - | movzx RD, byte [DISPATCH+DISPATCH_GL(hookmask)] - | test RDL, HOOK_VMEVENT // No recording while in vmevent. - | jnz >5 - | // Decrement the hookcount for consistency, but always do the call. - | test RDL, HOOK_ACTIVE - | jnz >1 - | test RDL, LUA_MASKLINE|LUA_MASKCOUNT - | jz >1 - | dec dword [DISPATCH+DISPATCH_GL(hookcount)] - | jmp >1 - |.endif - | - |->vm_rethook: // Dispatch target for return hooks. - | movzx RD, byte [DISPATCH+DISPATCH_GL(hookmask)] - | test RDL, HOOK_ACTIVE // Hook already active? - | jnz >5 - | jmp >1 - | - |->vm_inshook: // Dispatch target for instr/line hooks. - | movzx RD, byte [DISPATCH+DISPATCH_GL(hookmask)] - | test RDL, HOOK_ACTIVE // Hook already active? - | jnz >5 - | - | test RDL, LUA_MASKLINE|LUA_MASKCOUNT - | jz >5 - | dec dword [DISPATCH+DISPATCH_GL(hookcount)] - | jz >1 - | test RDL, LUA_MASKLINE - | jz >5 - |1: - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - | mov FCARG2, PC // Caveat: FCARG2 == BASE - | mov FCARG1, L:RB - | // SAVE_PC must hold the _previous_ PC. The callee updates it with PC. - | call extern lj_dispatch_ins@8 // (lua_State *L, const BCIns *pc) - |3: - | mov BASE, L:RB->base - |4: - | movzx RA, PC_RA - |5: - | movzx OP, PC_OP - | movzx RD, PC_RD - |.if X64 - | jmp aword [DISPATCH+OP*8+GG_DISP2STATIC] // Re-dispatch to static ins. - |.else - | jmp aword [DISPATCH+OP*4+GG_DISP2STATIC] // Re-dispatch to static ins. - |.endif - | - |->cont_hook: // Continue from hook yield. - | add PC, 4 - | mov RA, [RB-24] - | mov MULTRES, RA // Restore MULTRES for *M ins. - | jmp <4 - | - |->vm_hotloop: // Hot loop counter underflow. - |.if JIT - | mov LFUNC:RB, [BASE-8] // Same as curr_topL(L). - | mov RB, LFUNC:RB->pc - | movzx RD, byte [RB+PC2PROTO(framesize)] - | lea RD, [BASE+RD*8] - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - | mov L:RB->top, RD - | mov FCARG2, PC - | lea FCARG1, [DISPATCH+GG_DISP2J] - | mov aword [DISPATCH+DISPATCH_J(L)], L:RBa - | mov SAVE_PC, PC - | call extern lj_trace_hot@8 // (jit_State *J, const BCIns *pc) - | jmp <3 - |.endif - | - |->vm_callhook: // Dispatch target for call hooks. - | mov SAVE_PC, PC - |.if JIT - | jmp >1 - |.endif - | - |->vm_hotcall: // Hot call counter underflow. - |.if JIT - | mov SAVE_PC, PC - | or PC, 1 // Marker for hot call. - |1: - |.endif - | lea RD, [BASE+NARGS:RD*8-8] - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - | mov L:RB->top, RD - | mov FCARG2, PC - | mov FCARG1, L:RB - | call extern lj_dispatch_call@8 // (lua_State *L, const BCIns *pc) - | // ASMFunction returned in eax/rax (RDa). - | mov SAVE_PC, 0 // Invalidate for subsequent line hook. - |.if JIT - | and PC, -2 - |.endif - | mov BASE, L:RB->base - | mov RAa, RDa - | mov RD, L:RB->top - | sub RD, BASE - | mov RBa, RAa - | movzx RA, PC_RA - | shr RD, 3 - | add NARGS:RD, 1 - | jmp RBa - | - |->cont_stitch: // Trace stitching. - |.if JIT - | // BASE = base, RC = result, RB = mbase - | mov TRACE:RA, [RB-24] // Save previous trace. - | mov TMP1, TRACE:RA - | mov TMP3, DISPATCH // Need one more register. - | mov DISPATCH, MULTRES - | movzx RA, PC_RA - | lea RA, [BASE+RA*8] // Call base. - | sub DISPATCH, 1 - | jz >2 - |1: // Move results down. - |.if X64 - | mov RBa, [RC] - | mov [RA], RBa - |.else - | mov RB, [RC] - | mov [RA], RB - | mov RB, [RC+4] - | mov [RA+4], RB - |.endif - | add RC, 8 - | add RA, 8 - | sub DISPATCH, 1 - | jnz <1 - |2: - | movzx RC, PC_RA - | movzx RB, PC_RB - | add RC, RB - | lea RC, [BASE+RC*8-8] - |3: - | cmp RC, RA - | ja >9 // More results wanted? - | - | mov DISPATCH, TMP3 - | mov TRACE:RD, TMP1 // Get previous trace. - | movzx RB, word TRACE:RD->traceno - | movzx RD, word TRACE:RD->link - | cmp RD, RB - | je ->cont_nop // Blacklisted. - | test RD, RD - | jne =>BC_JLOOP // Jump to stitched trace. - | - | // Stitch a new trace to the previous trace. - | mov [DISPATCH+DISPATCH_J(exitno)], RB - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - | mov FCARG2, PC - | lea FCARG1, [DISPATCH+GG_DISP2J] - | mov aword [DISPATCH+DISPATCH_J(L)], L:RBa - | call extern lj_dispatch_stitch@8 // (jit_State *J, const BCIns *pc) - | mov BASE, L:RB->base - | jmp ->cont_nop - | - |9: // Fill up results with nil. - | mov dword [RA+4], LJ_TNIL - | add RA, 8 - | jmp <3 - |.endif - | - |->vm_profhook: // Dispatch target for profiler hook. -#if LJ_HASPROFILE - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - | mov FCARG2, PC // Caveat: FCARG2 == BASE - | mov FCARG1, L:RB - | call extern lj_dispatch_profile@8 // (lua_State *L, const BCIns *pc) - | mov BASE, L:RB->base - | // HOOK_PROFILE is off again, so re-dispatch to dynamic instruction. - | sub PC, 4 - | jmp ->cont_nop -#endif - | - |//----------------------------------------------------------------------- - |//-- Trace exit handler ------------------------------------------------- - |//----------------------------------------------------------------------- - | - |// Called from an exit stub with the exit number on the stack. - |// The 16 bit exit number is stored with two (sign-extended) push imm8. - |->vm_exit_handler: - |.if JIT - |.if X64 - | push r13; push r12 - | push r11; push r10; push r9; push r8 - | push rdi; push rsi; push rbp; lea rbp, [rsp+88]; push rbp - | push rbx; push rdx; push rcx; push rax - | movzx RC, byte [rbp-8] // Reconstruct exit number. - | mov RCH, byte [rbp-16] - | mov [rbp-8], r15; mov [rbp-16], r14 - |.else - | push ebp; lea ebp, [esp+12]; push ebp - | push ebx; push edx; push ecx; push eax - | movzx RC, byte [ebp-4] // Reconstruct exit number. - | mov RCH, byte [ebp-8] - | mov [ebp-4], edi; mov [ebp-8], esi - |.endif - | // Caveat: DISPATCH is ebx. - | mov DISPATCH, [ebp] - | mov RA, [DISPATCH+DISPATCH_GL(vmstate)] // Get trace number. - | set_vmstate EXIT - | mov [DISPATCH+DISPATCH_J(exitno)], RC - | mov [DISPATCH+DISPATCH_J(parent)], RA - |.if X64 - |.if X64WIN - | sub rsp, 16*8+4*8 // Room for SSE regs + save area. - |.else - | sub rsp, 16*8 // Room for SSE regs. - |.endif - | add rbp, -128 - | movsd qword [rbp-8], xmm15; movsd qword [rbp-16], xmm14 - | movsd qword [rbp-24], xmm13; movsd qword [rbp-32], xmm12 - | movsd qword [rbp-40], xmm11; movsd qword [rbp-48], xmm10 - | movsd qword [rbp-56], xmm9; movsd qword [rbp-64], xmm8 - | movsd qword [rbp-72], xmm7; movsd qword [rbp-80], xmm6 - | movsd qword [rbp-88], xmm5; movsd qword [rbp-96], xmm4 - | movsd qword [rbp-104], xmm3; movsd qword [rbp-112], xmm2 - | movsd qword [rbp-120], xmm1; movsd qword [rbp-128], xmm0 - |.else - | sub esp, 8*8+16 // Room for SSE regs + args. - | movsd qword [ebp-40], xmm7; movsd qword [ebp-48], xmm6 - | movsd qword [ebp-56], xmm5; movsd qword [ebp-64], xmm4 - | movsd qword [ebp-72], xmm3; movsd qword [ebp-80], xmm2 - | movsd qword [ebp-88], xmm1; movsd qword [ebp-96], xmm0 - |.endif - | // Caveat: RB is ebp. - | mov L:RB, [DISPATCH+DISPATCH_GL(cur_L)] - | mov BASE, [DISPATCH+DISPATCH_GL(jit_base)] - | mov aword [DISPATCH+DISPATCH_J(L)], L:RBa - | mov L:RB->base, BASE - |.if X64WIN - | lea CARG2, [rsp+4*8] - |.elif X64 - | mov CARG2, rsp - |.else - | lea FCARG2, [esp+16] - |.endif - | lea FCARG1, [DISPATCH+GG_DISP2J] - | mov dword [DISPATCH+DISPATCH_GL(jit_base)], 0 - | call extern lj_trace_exit@8 // (jit_State *J, ExitState *ex) - | // MULTRES or negated error code returned in eax (RD). - | mov RAa, L:RB->cframe - | and RAa, CFRAME_RAWMASK - |.if X64WIN - | // Reposition stack later. - |.elif X64 - | mov rsp, RAa // Reposition stack to C frame. - |.else - | mov esp, RAa // Reposition stack to C frame. - |.endif - | mov [RAa+CFRAME_OFS_L], L:RB // Set SAVE_L (on-trace resume/yield). - | mov BASE, L:RB->base - | mov PC, [RAa+CFRAME_OFS_PC] // Get SAVE_PC. - |.if X64 - | jmp >1 - |.endif - |.endif - |->vm_exit_interp: - | // RD = MULTRES or negated error code, BASE, PC and DISPATCH set. - |.if JIT - |.if X64 - | // Restore additional callee-save registers only used in compiled code. - |.if X64WIN - | lea RAa, [rsp+9*16+4*8] - |1: - | movdqa xmm15, [RAa-9*16] - | movdqa xmm14, [RAa-8*16] - | movdqa xmm13, [RAa-7*16] - | movdqa xmm12, [RAa-6*16] - | movdqa xmm11, [RAa-5*16] - | movdqa xmm10, [RAa-4*16] - | movdqa xmm9, [RAa-3*16] - | movdqa xmm8, [RAa-2*16] - | movdqa xmm7, [RAa-1*16] - | mov rsp, RAa // Reposition stack to C frame. - | movdqa xmm6, [RAa] - | mov r15, CSAVE_3 - | mov r14, CSAVE_4 - |.else - | add rsp, 16 // Reposition stack to C frame. - |1: - |.endif - | mov r13, TMPa - | mov r12, TMPQ - |.endif - | test RD, RD; js >9 // Check for error from exit. - | mov L:RB, SAVE_L - | mov MULTRES, RD - | mov LFUNC:KBASE, [BASE-8] - | mov KBASE, LFUNC:KBASE->pc - | mov KBASE, [KBASE+PC2PROTO(k)] - | mov L:RB->base, BASE - | mov dword [DISPATCH+DISPATCH_GL(jit_base)], 0 - | set_vmstate INTERP - | // Modified copy of ins_next which handles function header dispatch, too. - | mov RC, [PC] - | movzx RA, RCH - | movzx OP, RCL - | add PC, 4 - | shr RC, 16 - | cmp OP, BC_FUNCF // Function header? - | jb >3 - | cmp OP, BC_FUNCC+2 // Fast function? - | jae >4 - |2: - | mov RC, MULTRES // RC/RD holds nres+1. - |3: - |.if X64 - | jmp aword [DISPATCH+OP*8] - |.else - | jmp aword [DISPATCH+OP*4] - |.endif - | - |4: // Check frame below fast function. - | mov RC, [BASE-4] - | test RC, FRAME_TYPE - | jnz <2 // Trace stitching continuation? - | // Otherwise set KBASE for Lua function below fast function. - | movzx RC, byte [RC-3] - | not RCa - | mov LFUNC:KBASE, [BASE+RC*8-8] - | mov KBASE, LFUNC:KBASE->pc - | mov KBASE, [KBASE+PC2PROTO(k)] - | jmp <2 - | - |9: // Rethrow error from the right C frame. - | neg RD - | mov FCARG1, L:RB - | mov FCARG2, RD - | call extern lj_err_throw@8 // (lua_State *L, int errcode) - |.endif - | - |//----------------------------------------------------------------------- - |//-- Math helper functions ---------------------------------------------- - |//----------------------------------------------------------------------- - | - |// FP value rounding. Called by math.floor/math.ceil fast functions - |// and from JIT code. arg/ret is xmm0. xmm0-xmm3 and RD (eax) modified. - |.macro vm_round, name, mode, cond - |->name: - |.if not X64 and cond - | movsd xmm0, qword [esp+4] - | call ->name .. _sse - | movsd qword [esp+4], xmm0 // Overwrite callee-owned arg. - | fld qword [esp+4] - | ret - |.endif - | - |->name .. _sse: - | sseconst_abs xmm2, RDa - | sseconst_2p52 xmm3, RDa - | movaps xmm1, xmm0 - | andpd xmm1, xmm2 // |x| - | ucomisd xmm3, xmm1 // No truncation if 2^52 <= |x|. - | jbe >1 - | andnpd xmm2, xmm0 // Isolate sign bit. - |.if mode == 2 // trunc(x)? - | movaps xmm0, xmm1 - | addsd xmm1, xmm3 // (|x| + 2^52) - 2^52 - | subsd xmm1, xmm3 - | sseconst_1 xmm3, RDa - | cmpsd xmm0, xmm1, 1 // |x| < result? - | andpd xmm0, xmm3 - | subsd xmm1, xmm0 // If yes, subtract -1. - | orpd xmm1, xmm2 // Merge sign bit back in. - |.else - | addsd xmm1, xmm3 // (|x| + 2^52) - 2^52 - | subsd xmm1, xmm3 - | orpd xmm1, xmm2 // Merge sign bit back in. - | .if mode == 1 // ceil(x)? - | sseconst_m1 xmm2, RDa // Must subtract -1 to preserve -0. - | cmpsd xmm0, xmm1, 6 // x > result? - | .else // floor(x)? - | sseconst_1 xmm2, RDa - | cmpsd xmm0, xmm1, 1 // x < result? - | .endif - | andpd xmm0, xmm2 - | subsd xmm1, xmm0 // If yes, subtract +-1. - |.endif - | movaps xmm0, xmm1 - |1: - | ret - |.endmacro - | - | vm_round vm_floor, 0, 1 - | vm_round vm_ceil, 1, JIT - | vm_round vm_trunc, 2, JIT - | - |// FP modulo x%y. Called by BC_MOD* and vm_arith. - |->vm_mod: - |// Args in xmm0/xmm1, return value in xmm0. - |// Caveat: xmm0-xmm5 and RC (eax) modified! - | movaps xmm5, xmm0 - | divsd xmm0, xmm1 - | sseconst_abs xmm2, RDa - | sseconst_2p52 xmm3, RDa - | movaps xmm4, xmm0 - | andpd xmm4, xmm2 // |x/y| - | ucomisd xmm3, xmm4 // No truncation if 2^52 <= |x/y|. - | jbe >1 - | andnpd xmm2, xmm0 // Isolate sign bit. - | addsd xmm4, xmm3 // (|x/y| + 2^52) - 2^52 - | subsd xmm4, xmm3 - | orpd xmm4, xmm2 // Merge sign bit back in. - | sseconst_1 xmm2, RDa - | cmpsd xmm0, xmm4, 1 // x/y < result? - | andpd xmm0, xmm2 - | subsd xmm4, xmm0 // If yes, subtract 1.0. - | movaps xmm0, xmm5 - | mulsd xmm1, xmm4 - | subsd xmm0, xmm1 - | ret - |1: - | mulsd xmm1, xmm0 - | movaps xmm0, xmm5 - | subsd xmm0, xmm1 - | ret - | - |// Args in xmm0/eax. Ret in xmm0. xmm0-xmm1 and eax modified. - |->vm_powi_sse: - | cmp eax, 1; jle >6 // i<=1? - | // Now 1 < (unsigned)i <= 0x80000000. - |1: // Handle leading zeros. - | test eax, 1; jnz >2 - | mulsd xmm0, xmm0 - | shr eax, 1 - | jmp <1 - |2: - | shr eax, 1; jz >5 - | movaps xmm1, xmm0 - |3: // Handle trailing bits. - | mulsd xmm0, xmm0 - | shr eax, 1; jz >4 - | jnc <3 - | mulsd xmm1, xmm0 - | jmp <3 - |4: - | mulsd xmm0, xmm1 - |5: - | ret - |6: - | je <5 // x^1 ==> x - | jb >7 // x^0 ==> 1 - | neg eax - | call <1 - | sseconst_1 xmm1, RDa - | divsd xmm1, xmm0 - | movaps xmm0, xmm1 - | ret - |7: - | sseconst_1 xmm0, RDa - | ret - | - |//----------------------------------------------------------------------- - |//-- Miscellaneous functions -------------------------------------------- - |//----------------------------------------------------------------------- - | - |// int lj_vm_cpuid(uint32_t f, uint32_t res[4]) - |->vm_cpuid: - |.if X64 - | mov eax, CARG1d - | .if X64WIN; push rsi; mov rsi, CARG2; .endif - | push rbx - | xor ecx, ecx - | cpuid - | mov [rsi], eax - | mov [rsi+4], ebx - | mov [rsi+8], ecx - | mov [rsi+12], edx - | pop rbx - | .if X64WIN; pop rsi; .endif - | ret - |.else - | pushfd - | pop edx - | mov ecx, edx - | xor edx, 0x00200000 // Toggle ID bit in flags. - | push edx - | popfd - | pushfd - | pop edx - | xor eax, eax // Zero means no features supported. - | cmp ecx, edx - | jz >1 // No ID toggle means no CPUID support. - | mov eax, [esp+4] // Argument 1 is function number. - | push edi - | push ebx - | xor ecx, ecx - | cpuid - | mov edi, [esp+16] // Argument 2 is result area. - | mov [edi], eax - | mov [edi+4], ebx - | mov [edi+8], ecx - | mov [edi+12], edx - | pop ebx - | pop edi - |1: - | ret - |.endif - | - |//----------------------------------------------------------------------- - |//-- Assertions --------------------------------------------------------- - |//----------------------------------------------------------------------- - | - |->assert_bad_for_arg_type: -#ifdef LUA_USE_ASSERT - | int3 -#endif - | int3 - | - |//----------------------------------------------------------------------- - |//-- FFI helper functions ----------------------------------------------- - |//----------------------------------------------------------------------- - | - |// Handler for callback functions. Callback slot number in ah/al. - |->vm_ffi_callback: - |.if FFI - |.type CTSTATE, CTState, PC - |.if not X64 - | sub esp, 16 // Leave room for SAVE_ERRF etc. - |.endif - | saveregs_ // ebp/rbp already saved. ebp now holds global_State *. - | lea DISPATCH, [ebp+GG_G2DISP] - | mov CTSTATE, GL:ebp->ctype_state - | movzx eax, ax - | mov CTSTATE->cb.slot, eax - |.if X64 - | mov CTSTATE->cb.gpr[0], CARG1 - | mov CTSTATE->cb.gpr[1], CARG2 - | mov CTSTATE->cb.gpr[2], CARG3 - | mov CTSTATE->cb.gpr[3], CARG4 - | movsd qword CTSTATE->cb.fpr[0], xmm0 - | movsd qword CTSTATE->cb.fpr[1], xmm1 - | movsd qword CTSTATE->cb.fpr[2], xmm2 - | movsd qword CTSTATE->cb.fpr[3], xmm3 - |.if X64WIN - | lea rax, [rsp+CFRAME_SIZE+4*8] - |.else - | lea rax, [rsp+CFRAME_SIZE] - | mov CTSTATE->cb.gpr[4], CARG5 - | mov CTSTATE->cb.gpr[5], CARG6 - | movsd qword CTSTATE->cb.fpr[4], xmm4 - | movsd qword CTSTATE->cb.fpr[5], xmm5 - | movsd qword CTSTATE->cb.fpr[6], xmm6 - | movsd qword CTSTATE->cb.fpr[7], xmm7 - |.endif - | mov CTSTATE->cb.stack, rax - | mov CARG2, rsp - |.else - | lea eax, [esp+CFRAME_SIZE+16] - | mov CTSTATE->cb.gpr[0], FCARG1 - | mov CTSTATE->cb.gpr[1], FCARG2 - | mov CTSTATE->cb.stack, eax - | mov FCARG1, [esp+CFRAME_SIZE+12] // Move around misplaced retaddr/ebp. - | mov FCARG2, [esp+CFRAME_SIZE+8] - | mov SAVE_RET, FCARG1 - | mov SAVE_R4, FCARG2 - | mov FCARG2, esp - |.endif - | mov SAVE_PC, CTSTATE // Any value outside of bytecode is ok. - | mov FCARG1, CTSTATE - | call extern lj_ccallback_enter@8 // (CTState *cts, void *cf) - | // lua_State * returned in eax (RD). - | set_vmstate INTERP - | mov BASE, L:RD->base - | mov RD, L:RD->top - | sub RD, BASE - | mov LFUNC:RB, [BASE-8] - | shr RD, 3 - | add RD, 1 - | ins_callt - |.endif - | - |->cont_ffi_callback: // Return from FFI callback. - |.if FFI - | mov L:RA, SAVE_L - | mov CTSTATE, [DISPATCH+DISPATCH_GL(ctype_state)] - | mov aword CTSTATE->L, L:RAa - | mov L:RA->base, BASE - | mov L:RA->top, RB - | mov FCARG1, CTSTATE - | mov FCARG2, RC - | call extern lj_ccallback_leave@8 // (CTState *cts, TValue *o) - |.if X64 - | mov rax, CTSTATE->cb.gpr[0] - | movsd xmm0, qword CTSTATE->cb.fpr[0] - | jmp ->vm_leave_unw - |.else - | mov L:RB, SAVE_L - | mov eax, CTSTATE->cb.gpr[0] - | mov edx, CTSTATE->cb.gpr[1] - | cmp dword CTSTATE->cb.gpr[2], 1 - | jb >7 - | je >6 - | fld qword CTSTATE->cb.fpr[0].d - | jmp >7 - |6: - | fld dword CTSTATE->cb.fpr[0].f - |7: - | mov ecx, L:RB->top - | movzx ecx, word [ecx+6] // Get stack adjustment and copy up. - | mov SAVE_L, ecx // Must be one slot above SAVE_RET - | restoreregs - | pop ecx // Move return addr from SAVE_RET. - | add esp, [esp] // Adjust stack. - | add esp, 16 - | push ecx - | ret - |.endif - |.endif - | - |->vm_ffi_call@4: // Call C function via FFI. - | // Caveat: needs special frame unwinding, see below. - |.if FFI - |.if X64 - | .type CCSTATE, CCallState, rbx - | push rbp; mov rbp, rsp; push rbx; mov CCSTATE, CARG1 - |.else - | .type CCSTATE, CCallState, ebx - | push ebp; mov ebp, esp; push ebx; mov CCSTATE, FCARG1 - |.endif - | - | // Readjust stack. - |.if X64 - | mov eax, CCSTATE->spadj - | sub rsp, rax - |.else - | sub esp, CCSTATE->spadj - |.if WIN - | mov CCSTATE->spadj, esp - |.endif - |.endif - | - | // Copy stack slots. - | movzx ecx, byte CCSTATE->nsp - | sub ecx, 1 - | js >2 - |1: - |.if X64 - | mov rax, [CCSTATE+rcx*8+offsetof(CCallState, stack)] - | mov [rsp+rcx*8+CCALL_SPS_EXTRA*8], rax - |.else - | mov eax, [CCSTATE+ecx*4+offsetof(CCallState, stack)] - | mov [esp+ecx*4], eax - |.endif - | sub ecx, 1 - | jns <1 - |2: - | - |.if X64 - | movzx eax, byte CCSTATE->nfpr - | mov CARG1, CCSTATE->gpr[0] - | mov CARG2, CCSTATE->gpr[1] - | mov CARG3, CCSTATE->gpr[2] - | mov CARG4, CCSTATE->gpr[3] - |.if not X64WIN - | mov CARG5, CCSTATE->gpr[4] - | mov CARG6, CCSTATE->gpr[5] - |.endif - | test eax, eax; jz >5 - | movaps xmm0, CCSTATE->fpr[0] - | movaps xmm1, CCSTATE->fpr[1] - | movaps xmm2, CCSTATE->fpr[2] - | movaps xmm3, CCSTATE->fpr[3] - |.if not X64WIN - | cmp eax, 4; jbe >5 - | movaps xmm4, CCSTATE->fpr[4] - | movaps xmm5, CCSTATE->fpr[5] - | movaps xmm6, CCSTATE->fpr[6] - | movaps xmm7, CCSTATE->fpr[7] - |.endif - |5: - |.else - | mov FCARG1, CCSTATE->gpr[0] - | mov FCARG2, CCSTATE->gpr[1] - |.endif - | - | call aword CCSTATE->func - | - |.if X64 - | mov CCSTATE->gpr[0], rax - | movaps CCSTATE->fpr[0], xmm0 - |.if not X64WIN - | mov CCSTATE->gpr[1], rdx - | movaps CCSTATE->fpr[1], xmm1 - |.endif - |.else - | mov CCSTATE->gpr[0], eax - | mov CCSTATE->gpr[1], edx - | cmp byte CCSTATE->resx87, 1 - | jb >7 - | je >6 - | fstp qword CCSTATE->fpr[0].d[0] - | jmp >7 - |6: - | fstp dword CCSTATE->fpr[0].f[0] - |7: - |.if WIN - | sub CCSTATE->spadj, esp - |.endif - |.endif - | - |.if X64 - | mov rbx, [rbp-8]; leave; ret - |.else - | mov ebx, [ebp-4]; leave; ret - |.endif - |.endif - |// Note: vm_ffi_call must be the last function in this object file! - | - |//----------------------------------------------------------------------- -} - -/* Generate the code for a single instruction. */ -static void build_ins(BuildCtx *ctx, BCOp op, int defop) -{ - int vk = 0; - |// Note: aligning all instructions does not pay off. - |=>defop: - - switch (op) { - - /* -- Comparison ops ---------------------------------------------------- */ - - /* Remember: all ops branch for a true comparison, fall through otherwise. */ - - |.macro jmp_comp, lt, ge, le, gt, target - ||switch (op) { - ||case BC_ISLT: - | lt target - ||break; - ||case BC_ISGE: - | ge target - ||break; - ||case BC_ISLE: - | le target - ||break; - ||case BC_ISGT: - | gt target - ||break; - ||default: break; /* Shut up GCC. */ - ||} - |.endmacro - - case BC_ISLT: case BC_ISGE: case BC_ISLE: case BC_ISGT: - | // RA = src1, RD = src2, JMP with RD = target - | ins_AD - |.if DUALNUM - | checkint RA, >7 - | checkint RD, >8 - | mov RB, dword [BASE+RA*8] - | add PC, 4 - | cmp RB, dword [BASE+RD*8] - | jmp_comp jge, jl, jg, jle, >9 - |6: - | movzx RD, PC_RD - | branchPC RD - |9: - | ins_next - | - |7: // RA is not an integer. - | ja ->vmeta_comp - | // RA is a number. - | cmp dword [BASE+RD*8+4], LJ_TISNUM; jb >1; jne ->vmeta_comp - | // RA is a number, RD is an integer. - | cvtsi2sd xmm0, dword [BASE+RD*8] - | jmp >2 - | - |8: // RA is an integer, RD is not an integer. - | ja ->vmeta_comp - | // RA is an integer, RD is a number. - | cvtsi2sd xmm1, dword [BASE+RA*8] - | movsd xmm0, qword [BASE+RD*8] - | add PC, 4 - | ucomisd xmm0, xmm1 - | jmp_comp jbe, ja, jb, jae, <9 - | jmp <6 - |.else - | checknum RA, ->vmeta_comp - | checknum RD, ->vmeta_comp - |.endif - |1: - | movsd xmm0, qword [BASE+RD*8] - |2: - | add PC, 4 - | ucomisd xmm0, qword [BASE+RA*8] - |3: - | // Unordered: all of ZF CF PF set, ordered: PF clear. - | // To preserve NaN semantics GE/GT branch on unordered, but LT/LE don't. - |.if DUALNUM - | jmp_comp jbe, ja, jb, jae, <9 - | jmp <6 - |.else - | jmp_comp jbe, ja, jb, jae, >1 - | movzx RD, PC_RD - | branchPC RD - |1: - | ins_next - |.endif - break; - - case BC_ISEQV: case BC_ISNEV: - vk = op == BC_ISEQV; - | ins_AD // RA = src1, RD = src2, JMP with RD = target - | mov RB, [BASE+RD*8+4] - | add PC, 4 - |.if DUALNUM - | cmp RB, LJ_TISNUM; jne >7 - | checkint RA, >8 - | mov RB, dword [BASE+RD*8] - | cmp RB, dword [BASE+RA*8] - if (vk) { - | jne >9 - } else { - | je >9 - } - | movzx RD, PC_RD - | branchPC RD - |9: - | ins_next - | - |7: // RD is not an integer. - | ja >5 - | // RD is a number. - | cmp dword [BASE+RA*8+4], LJ_TISNUM; jb >1; jne >5 - | // RD is a number, RA is an integer. - | cvtsi2sd xmm0, dword [BASE+RA*8] - | jmp >2 - | - |8: // RD is an integer, RA is not an integer. - | ja >5 - | // RD is an integer, RA is a number. - | cvtsi2sd xmm0, dword [BASE+RD*8] - | ucomisd xmm0, qword [BASE+RA*8] - | jmp >4 - | - |.else - | cmp RB, LJ_TISNUM; jae >5 - | checknum RA, >5 - |.endif - |1: - | movsd xmm0, qword [BASE+RA*8] - |2: - | ucomisd xmm0, qword [BASE+RD*8] - |4: - iseqne_fp: - if (vk) { - | jp >2 // Unordered means not equal. - | jne >2 - } else { - | jp >2 // Unordered means not equal. - | je >1 - } - iseqne_end: - if (vk) { - |1: // EQ: Branch to the target. - | movzx RD, PC_RD - | branchPC RD - |2: // NE: Fallthrough to next instruction. - |.if not FFI - |3: - |.endif - } else { - |.if not FFI - |3: - |.endif - |2: // NE: Branch to the target. - | movzx RD, PC_RD - | branchPC RD - |1: // EQ: Fallthrough to next instruction. - } - if (LJ_DUALNUM && (op == BC_ISEQV || op == BC_ISNEV || - op == BC_ISEQN || op == BC_ISNEN)) { - | jmp <9 - } else { - | ins_next - } - | - if (op == BC_ISEQV || op == BC_ISNEV) { - |5: // Either or both types are not numbers. - |.if FFI - | cmp RB, LJ_TCDATA; je ->vmeta_equal_cd - | checktp RA, LJ_TCDATA; je ->vmeta_equal_cd - |.endif - | checktp RA, RB // Compare types. - | jne <2 // Not the same type? - | cmp RB, LJ_TISPRI - | jae <1 // Same type and primitive type? - | - | // Same types and not a primitive type. Compare GCobj or pvalue. - | mov RA, [BASE+RA*8] - | mov RD, [BASE+RD*8] - | cmp RA, RD - | je <1 // Same GCobjs or pvalues? - | cmp RB, LJ_TISTABUD - | ja <2 // Different objects and not table/ud? - |.if X64 - | cmp RB, LJ_TUDATA // And not 64 bit lightuserdata. - | jb <2 - |.endif - | - | // Different tables or userdatas. Need to check __eq metamethod. - | // Field metatable must be at same offset for GCtab and GCudata! - | mov TAB:RB, TAB:RA->metatable - | test TAB:RB, TAB:RB - | jz <2 // No metatable? - | test byte TAB:RB->nomm, 1<vmeta_equal // Handle __eq metamethod. - } else { - |.if FFI - |3: - | cmp RB, LJ_TCDATA - if (LJ_DUALNUM && vk) { - | jne <9 - } else { - | jne <2 - } - | jmp ->vmeta_equal_cd - |.endif - } - break; - case BC_ISEQS: case BC_ISNES: - vk = op == BC_ISEQS; - | ins_AND // RA = src, RD = str const, JMP with RD = target - | mov RB, [BASE+RA*8+4] - | add PC, 4 - | cmp RB, LJ_TSTR; jne >3 - | mov RA, [BASE+RA*8] - | cmp RA, [KBASE+RD*4] - iseqne_test: - if (vk) { - | jne >2 - } else { - | je >1 - } - goto iseqne_end; - case BC_ISEQN: case BC_ISNEN: - vk = op == BC_ISEQN; - | ins_AD // RA = src, RD = num const, JMP with RD = target - | mov RB, [BASE+RA*8+4] - | add PC, 4 - |.if DUALNUM - | cmp RB, LJ_TISNUM; jne >7 - | cmp dword [KBASE+RD*8+4], LJ_TISNUM; jne >8 - | mov RB, dword [KBASE+RD*8] - | cmp RB, dword [BASE+RA*8] - if (vk) { - | jne >9 - } else { - | je >9 - } - | movzx RD, PC_RD - | branchPC RD - |9: - | ins_next - | - |7: // RA is not an integer. - | ja >3 - | // RA is a number. - | cmp dword [KBASE+RD*8+4], LJ_TISNUM; jb >1 - | // RA is a number, RD is an integer. - | cvtsi2sd xmm0, dword [KBASE+RD*8] - | jmp >2 - | - |8: // RA is an integer, RD is a number. - | cvtsi2sd xmm0, dword [BASE+RA*8] - | ucomisd xmm0, qword [KBASE+RD*8] - | jmp >4 - |.else - | cmp RB, LJ_TISNUM; jae >3 - |.endif - |1: - | movsd xmm0, qword [KBASE+RD*8] - |2: - | ucomisd xmm0, qword [BASE+RA*8] - |4: - goto iseqne_fp; - case BC_ISEQP: case BC_ISNEP: - vk = op == BC_ISEQP; - | ins_AND // RA = src, RD = primitive type (~), JMP with RD = target - | mov RB, [BASE+RA*8+4] - | add PC, 4 - | cmp RB, RD - if (!LJ_HASFFI) goto iseqne_test; - if (vk) { - | jne >3 - | movzx RD, PC_RD - | branchPC RD - |2: - | ins_next - |3: - | cmp RB, LJ_TCDATA; jne <2 - | jmp ->vmeta_equal_cd - } else { - | je >2 - | cmp RB, LJ_TCDATA; je ->vmeta_equal_cd - | movzx RD, PC_RD - | branchPC RD - |2: - | ins_next - } - break; - - /* -- Unary test and copy ops ------------------------------------------- */ - - case BC_ISTC: case BC_ISFC: case BC_IST: case BC_ISF: - | ins_AD // RA = dst or unused, RD = src, JMP with RD = target - | mov RB, [BASE+RD*8+4] - | add PC, 4 - | cmp RB, LJ_TISTRUECOND - if (op == BC_IST || op == BC_ISTC) { - | jae >1 - } else { - | jb >1 - } - if (op == BC_ISTC || op == BC_ISFC) { - | mov [BASE+RA*8+4], RB - | mov RB, [BASE+RD*8] - | mov [BASE+RA*8], RB - } - | movzx RD, PC_RD - | branchPC RD - |1: // Fallthrough to the next instruction. - | ins_next - break; - - case BC_ISTYPE: - | ins_AD // RA = src, RD = -type - | add RD, [BASE+RA*8+4] - | jne ->vmeta_istype - | ins_next - break; - case BC_ISNUM: - | ins_AD // RA = src, RD = -(TISNUM-1) - | checknum RA, ->vmeta_istype - | ins_next - break; - - /* -- Unary ops --------------------------------------------------------- */ - - case BC_MOV: - | ins_AD // RA = dst, RD = src - |.if X64 - | mov RBa, [BASE+RD*8] - | mov [BASE+RA*8], RBa - |.else - | mov RB, [BASE+RD*8+4] - | mov RD, [BASE+RD*8] - | mov [BASE+RA*8+4], RB - | mov [BASE+RA*8], RD - |.endif - | ins_next_ - break; - case BC_NOT: - | ins_AD // RA = dst, RD = src - | xor RB, RB - | checktp RD, LJ_TISTRUECOND - | adc RB, LJ_TTRUE - | mov [BASE+RA*8+4], RB - | ins_next - break; - case BC_UNM: - | ins_AD // RA = dst, RD = src - |.if DUALNUM - | checkint RD, >5 - | mov RB, [BASE+RD*8] - | neg RB - | jo >4 - | mov dword [BASE+RA*8+4], LJ_TISNUM - | mov dword [BASE+RA*8], RB - |9: - | ins_next - |4: - | mov dword [BASE+RA*8+4], 0x41e00000 // 2^31. - | mov dword [BASE+RA*8], 0 - | jmp <9 - |5: - | ja ->vmeta_unm - |.else - | checknum RD, ->vmeta_unm - |.endif - | movsd xmm0, qword [BASE+RD*8] - | sseconst_sign xmm1, RDa - | xorps xmm0, xmm1 - | movsd qword [BASE+RA*8], xmm0 - |.if DUALNUM - | jmp <9 - |.else - | ins_next - |.endif - break; - case BC_LEN: - | ins_AD // RA = dst, RD = src - | checkstr RD, >2 - | mov STR:RD, [BASE+RD*8] - |.if DUALNUM - | mov RD, dword STR:RD->len - |1: - | mov dword [BASE+RA*8+4], LJ_TISNUM - | mov dword [BASE+RA*8], RD - |.else - | xorps xmm0, xmm0 - | cvtsi2sd xmm0, dword STR:RD->len - |1: - | movsd qword [BASE+RA*8], xmm0 - |.endif - | ins_next - |2: - | checktab RD, ->vmeta_len - | mov TAB:FCARG1, [BASE+RD*8] -#if LJ_52 - | mov TAB:RB, TAB:FCARG1->metatable - | cmp TAB:RB, 0 - | jnz >9 - |3: -#endif - |->BC_LEN_Z: - | mov RB, BASE // Save BASE. - | call extern lj_tab_len@4 // (GCtab *t) - | // Length of table returned in eax (RD). - |.if DUALNUM - | // Nothing to do. - |.else - | cvtsi2sd xmm0, RD - |.endif - | mov BASE, RB // Restore BASE. - | movzx RA, PC_RA - | jmp <1 -#if LJ_52 - |9: // Check for __len. - | test byte TAB:RB->nomm, 1<vmeta_len // 'no __len' flag NOT set: check. -#endif - break; - - /* -- Binary ops -------------------------------------------------------- */ - - |.macro ins_arithpre, sseins, ssereg - | ins_ABC - ||vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN); - ||switch (vk) { - ||case 0: - | checknum RB, ->vmeta_arith_vn - | .if DUALNUM - | cmp dword [KBASE+RC*8+4], LJ_TISNUM; jae ->vmeta_arith_vn - | .endif - | movsd xmm0, qword [BASE+RB*8] - | sseins ssereg, qword [KBASE+RC*8] - || break; - ||case 1: - | checknum RB, ->vmeta_arith_nv - | .if DUALNUM - | cmp dword [KBASE+RC*8+4], LJ_TISNUM; jae ->vmeta_arith_nv - | .endif - | movsd xmm0, qword [KBASE+RC*8] - | sseins ssereg, qword [BASE+RB*8] - || break; - ||default: - | checknum RB, ->vmeta_arith_vv - | checknum RC, ->vmeta_arith_vv - | movsd xmm0, qword [BASE+RB*8] - | sseins ssereg, qword [BASE+RC*8] - || break; - ||} - |.endmacro - | - |.macro ins_arithdn, intins - | ins_ABC - ||vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN); - ||switch (vk) { - ||case 0: - | checkint RB, ->vmeta_arith_vn - | cmp dword [KBASE+RC*8+4], LJ_TISNUM; jne ->vmeta_arith_vn - | mov RB, [BASE+RB*8] - | intins RB, [KBASE+RC*8]; jo ->vmeta_arith_vno - || break; - ||case 1: - | checkint RB, ->vmeta_arith_nv - | cmp dword [KBASE+RC*8+4], LJ_TISNUM; jne ->vmeta_arith_nv - | mov RC, [KBASE+RC*8] - | intins RC, [BASE+RB*8]; jo ->vmeta_arith_nvo - || break; - ||default: - | checkint RB, ->vmeta_arith_vv - | checkint RC, ->vmeta_arith_vv - | mov RB, [BASE+RB*8] - | intins RB, [BASE+RC*8]; jo ->vmeta_arith_vvo - || break; - ||} - | mov dword [BASE+RA*8+4], LJ_TISNUM - ||if (vk == 1) { - | mov dword [BASE+RA*8], RC - ||} else { - | mov dword [BASE+RA*8], RB - ||} - | ins_next - |.endmacro - | - |.macro ins_arithpost - | movsd qword [BASE+RA*8], xmm0 - |.endmacro - | - |.macro ins_arith, sseins - | ins_arithpre sseins, xmm0 - | ins_arithpost - | ins_next - |.endmacro - | - |.macro ins_arith, intins, sseins - |.if DUALNUM - | ins_arithdn intins - |.else - | ins_arith, sseins - |.endif - |.endmacro - - | // RA = dst, RB = src1 or num const, RC = src2 or num const - case BC_ADDVN: case BC_ADDNV: case BC_ADDVV: - | ins_arith add, addsd - break; - case BC_SUBVN: case BC_SUBNV: case BC_SUBVV: - | ins_arith sub, subsd - break; - case BC_MULVN: case BC_MULNV: case BC_MULVV: - | ins_arith imul, mulsd - break; - case BC_DIVVN: case BC_DIVNV: case BC_DIVVV: - | ins_arith divsd - break; - case BC_MODVN: - | ins_arithpre movsd, xmm1 - |->BC_MODVN_Z: - | call ->vm_mod - | ins_arithpost - | ins_next - break; - case BC_MODNV: case BC_MODVV: - | ins_arithpre movsd, xmm1 - | jmp ->BC_MODVN_Z // Avoid 3 copies. It's slow anyway. - break; - case BC_POW: - | ins_arithpre movsd, xmm1 - | mov RB, BASE - |.if not X64 - | movsd FPARG1, xmm0 - | movsd FPARG3, xmm1 - |.endif - | call extern pow - | movzx RA, PC_RA - | mov BASE, RB - |.if X64 - | ins_arithpost - |.else - | fstp qword [BASE+RA*8] - |.endif - | ins_next - break; - - case BC_CAT: - | ins_ABC // RA = dst, RB = src_start, RC = src_end - |.if X64 - | mov L:CARG1d, SAVE_L - | mov L:CARG1d->base, BASE - | lea CARG2d, [BASE+RC*8] - | mov CARG3d, RC - | sub CARG3d, RB - |->BC_CAT_Z: - | mov L:RB, L:CARG1d - |.else - | lea RA, [BASE+RC*8] - | sub RC, RB - | mov ARG2, RA - | mov ARG3, RC - |->BC_CAT_Z: - | mov L:RB, SAVE_L - | mov ARG1, L:RB - | mov L:RB->base, BASE - |.endif - | mov SAVE_PC, PC - | call extern lj_meta_cat // (lua_State *L, TValue *top, int left) - | // NULL (finished) or TValue * (metamethod) returned in eax (RC). - | mov BASE, L:RB->base - | test RC, RC - | jnz ->vmeta_binop - | movzx RB, PC_RB // Copy result to Stk[RA] from Stk[RB]. - | movzx RA, PC_RA - |.if X64 - | mov RCa, [BASE+RB*8] - | mov [BASE+RA*8], RCa - |.else - | mov RC, [BASE+RB*8+4] - | mov RB, [BASE+RB*8] - | mov [BASE+RA*8+4], RC - | mov [BASE+RA*8], RB - |.endif - | ins_next - break; - - /* -- Constant ops ------------------------------------------------------ */ - - case BC_KSTR: - | ins_AND // RA = dst, RD = str const (~) - | mov RD, [KBASE+RD*4] - | mov dword [BASE+RA*8+4], LJ_TSTR - | mov [BASE+RA*8], RD - | ins_next - break; - case BC_KCDATA: - |.if FFI - | ins_AND // RA = dst, RD = cdata const (~) - | mov RD, [KBASE+RD*4] - | mov dword [BASE+RA*8+4], LJ_TCDATA - | mov [BASE+RA*8], RD - | ins_next - |.endif - break; - case BC_KSHORT: - | ins_AD // RA = dst, RD = signed int16 literal - |.if DUALNUM - | movsx RD, RDW - | mov dword [BASE+RA*8+4], LJ_TISNUM - | mov dword [BASE+RA*8], RD - |.else - | movsx RD, RDW // Sign-extend literal. - | cvtsi2sd xmm0, RD - | movsd qword [BASE+RA*8], xmm0 - |.endif - | ins_next - break; - case BC_KNUM: - | ins_AD // RA = dst, RD = num const - | movsd xmm0, qword [KBASE+RD*8] - | movsd qword [BASE+RA*8], xmm0 - | ins_next - break; - case BC_KPRI: - | ins_AND // RA = dst, RD = primitive type (~) - | mov [BASE+RA*8+4], RD - | ins_next - break; - case BC_KNIL: - | ins_AD // RA = dst_start, RD = dst_end - | lea RA, [BASE+RA*8+12] - | lea RD, [BASE+RD*8+4] - | mov RB, LJ_TNIL - | mov [RA-8], RB // Sets minimum 2 slots. - |1: - | mov [RA], RB - | add RA, 8 - | cmp RA, RD - | jbe <1 - | ins_next - break; - - /* -- Upvalue and function ops ------------------------------------------ */ - - case BC_UGET: - | ins_AD // RA = dst, RD = upvalue # - | mov LFUNC:RB, [BASE-8] - | mov UPVAL:RB, [LFUNC:RB+RD*4+offsetof(GCfuncL, uvptr)] - | mov RB, UPVAL:RB->v - |.if X64 - | mov RDa, [RB] - | mov [BASE+RA*8], RDa - |.else - | mov RD, [RB+4] - | mov RB, [RB] - | mov [BASE+RA*8+4], RD - | mov [BASE+RA*8], RB - |.endif - | ins_next - break; - case BC_USETV: -#define TV2MARKOFS \ - ((int32_t)offsetof(GCupval, marked)-(int32_t)offsetof(GCupval, tv)) - | ins_AD // RA = upvalue #, RD = src - | mov LFUNC:RB, [BASE-8] - | mov UPVAL:RB, [LFUNC:RB+RA*4+offsetof(GCfuncL, uvptr)] - | cmp byte UPVAL:RB->closed, 0 - | mov RB, UPVAL:RB->v - | mov RA, [BASE+RD*8] - | mov RD, [BASE+RD*8+4] - | mov [RB], RA - | mov [RB+4], RD - | jz >1 - | // Check barrier for closed upvalue. - | test byte [RB+TV2MARKOFS], LJ_GC_BLACK // isblack(uv) - | jnz >2 - |1: - | ins_next - | - |2: // Upvalue is black. Check if new value is collectable and white. - | sub RD, LJ_TISGCV - | cmp RD, LJ_TNUMX - LJ_TISGCV // tvisgcv(v) - | jbe <1 - | test byte GCOBJ:RA->gch.marked, LJ_GC_WHITES // iswhite(v) - | jz <1 - | // Crossed a write barrier. Move the barrier forward. - |.if X64 and not X64WIN - | mov FCARG2, RB - | mov RB, BASE // Save BASE. - |.else - | xchg FCARG2, RB // Save BASE (FCARG2 == BASE). - |.endif - | lea GL:FCARG1, [DISPATCH+GG_DISP2G] - | call extern lj_gc_barrieruv@8 // (global_State *g, TValue *tv) - | mov BASE, RB // Restore BASE. - | jmp <1 - break; -#undef TV2MARKOFS - case BC_USETS: - | ins_AND // RA = upvalue #, RD = str const (~) - | mov LFUNC:RB, [BASE-8] - | mov UPVAL:RB, [LFUNC:RB+RA*4+offsetof(GCfuncL, uvptr)] - | mov GCOBJ:RA, [KBASE+RD*4] - | mov RD, UPVAL:RB->v - | mov [RD], GCOBJ:RA - | mov dword [RD+4], LJ_TSTR - | test byte UPVAL:RB->marked, LJ_GC_BLACK // isblack(uv) - | jnz >2 - |1: - | ins_next - | - |2: // Check if string is white and ensure upvalue is closed. - | test byte GCOBJ:RA->gch.marked, LJ_GC_WHITES // iswhite(str) - | jz <1 - | cmp byte UPVAL:RB->closed, 0 - | jz <1 - | // Crossed a write barrier. Move the barrier forward. - | mov RB, BASE // Save BASE (FCARG2 == BASE). - | mov FCARG2, RD - | lea GL:FCARG1, [DISPATCH+GG_DISP2G] - | call extern lj_gc_barrieruv@8 // (global_State *g, TValue *tv) - | mov BASE, RB // Restore BASE. - | jmp <1 - break; - case BC_USETN: - | ins_AD // RA = upvalue #, RD = num const - | mov LFUNC:RB, [BASE-8] - | movsd xmm0, qword [KBASE+RD*8] - | mov UPVAL:RB, [LFUNC:RB+RA*4+offsetof(GCfuncL, uvptr)] - | mov RA, UPVAL:RB->v - | movsd qword [RA], xmm0 - | ins_next - break; - case BC_USETP: - | ins_AND // RA = upvalue #, RD = primitive type (~) - | mov LFUNC:RB, [BASE-8] - | mov UPVAL:RB, [LFUNC:RB+RA*4+offsetof(GCfuncL, uvptr)] - | mov RA, UPVAL:RB->v - | mov [RA+4], RD - | ins_next - break; - case BC_UCLO: - | ins_AD // RA = level, RD = target - | branchPC RD // Do this first to free RD. - | mov L:RB, SAVE_L - | cmp dword L:RB->openupval, 0 - | je >1 - | mov L:RB->base, BASE - | lea FCARG2, [BASE+RA*8] // Caveat: FCARG2 == BASE - | mov L:FCARG1, L:RB // Caveat: FCARG1 == RA - | call extern lj_func_closeuv@8 // (lua_State *L, TValue *level) - | mov BASE, L:RB->base - |1: - | ins_next - break; - - case BC_FNEW: - | ins_AND // RA = dst, RD = proto const (~) (holding function prototype) - |.if X64 - | mov L:RB, SAVE_L - | mov L:RB->base, BASE // Caveat: CARG2d/CARG3d may be BASE. - | mov CARG3d, [BASE-8] - | mov CARG2d, [KBASE+RD*4] // Fetch GCproto *. - | mov CARG1d, L:RB - |.else - | mov LFUNC:RA, [BASE-8] - | mov PROTO:RD, [KBASE+RD*4] // Fetch GCproto *. - | mov L:RB, SAVE_L - | mov ARG3, LFUNC:RA - | mov ARG2, PROTO:RD - | mov ARG1, L:RB - | mov L:RB->base, BASE - |.endif - | mov SAVE_PC, PC - | // (lua_State *L, GCproto *pt, GCfuncL *parent) - | call extern lj_func_newL_gc - | // GCfuncL * returned in eax (RC). - | mov BASE, L:RB->base - | movzx RA, PC_RA - | mov [BASE+RA*8], LFUNC:RC - | mov dword [BASE+RA*8+4], LJ_TFUNC - | ins_next - break; - - /* -- Table ops --------------------------------------------------------- */ - - case BC_TNEW: - | ins_AD // RA = dst, RD = hbits|asize - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - | mov RA, [DISPATCH+DISPATCH_GL(gc.total)] - | cmp RA, [DISPATCH+DISPATCH_GL(gc.threshold)] - | mov SAVE_PC, PC - | jae >5 - |1: - |.if X64 - | mov CARG3d, RD - | and RD, 0x7ff - | shr CARG3d, 11 - |.else - | mov RA, RD - | and RD, 0x7ff - | shr RA, 11 - | mov ARG3, RA - |.endif - | cmp RD, 0x7ff - | je >3 - |2: - |.if X64 - | mov L:CARG1d, L:RB - | mov CARG2d, RD - |.else - | mov ARG1, L:RB - | mov ARG2, RD - |.endif - | call extern lj_tab_new // (lua_State *L, int32_t asize, uint32_t hbits) - | // Table * returned in eax (RC). - | mov BASE, L:RB->base - | movzx RA, PC_RA - | mov [BASE+RA*8], TAB:RC - | mov dword [BASE+RA*8+4], LJ_TTAB - | ins_next - |3: // Turn 0x7ff into 0x801. - | mov RD, 0x801 - | jmp <2 - |5: - | mov L:FCARG1, L:RB - | call extern lj_gc_step_fixtop@4 // (lua_State *L) - | movzx RD, PC_RD - | jmp <1 - break; - case BC_TDUP: - | ins_AND // RA = dst, RD = table const (~) (holding template table) - | mov L:RB, SAVE_L - | mov RA, [DISPATCH+DISPATCH_GL(gc.total)] - | mov SAVE_PC, PC - | cmp RA, [DISPATCH+DISPATCH_GL(gc.threshold)] - | mov L:RB->base, BASE - | jae >3 - |2: - | mov TAB:FCARG2, [KBASE+RD*4] // Caveat: FCARG2 == BASE - | mov L:FCARG1, L:RB // Caveat: FCARG1 == RA - | call extern lj_tab_dup@8 // (lua_State *L, Table *kt) - | // Table * returned in eax (RC). - | mov BASE, L:RB->base - | movzx RA, PC_RA - | mov [BASE+RA*8], TAB:RC - | mov dword [BASE+RA*8+4], LJ_TTAB - | ins_next - |3: - | mov L:FCARG1, L:RB - | call extern lj_gc_step_fixtop@4 // (lua_State *L) - | movzx RD, PC_RD // Need to reload RD. - | not RDa - | jmp <2 - break; - - case BC_GGET: - | ins_AND // RA = dst, RD = str const (~) - | mov LFUNC:RB, [BASE-8] - | mov TAB:RB, LFUNC:RB->env - | mov STR:RC, [KBASE+RD*4] - | jmp ->BC_TGETS_Z - break; - case BC_GSET: - | ins_AND // RA = src, RD = str const (~) - | mov LFUNC:RB, [BASE-8] - | mov TAB:RB, LFUNC:RB->env - | mov STR:RC, [KBASE+RD*4] - | jmp ->BC_TSETS_Z - break; - - case BC_TGETV: - | ins_ABC // RA = dst, RB = table, RC = key - | checktab RB, ->vmeta_tgetv - | mov TAB:RB, [BASE+RB*8] - | - | // Integer key? - |.if DUALNUM - | checkint RC, >5 - | mov RC, dword [BASE+RC*8] - |.else - | // Convert number to int and back and compare. - | checknum RC, >5 - | movsd xmm0, qword [BASE+RC*8] - | cvttsd2si RC, xmm0 - | cvtsi2sd xmm1, RC - | ucomisd xmm0, xmm1 - | jne ->vmeta_tgetv // Generic numeric key? Use fallback. - |.endif - | cmp RC, TAB:RB->asize // Takes care of unordered, too. - | jae ->vmeta_tgetv // Not in array part? Use fallback. - | shl RC, 3 - | add RC, TAB:RB->array - | cmp dword [RC+4], LJ_TNIL // Avoid overwriting RB in fastpath. - | je >2 - | // Get array slot. - |.if X64 - | mov RBa, [RC] - | mov [BASE+RA*8], RBa - |.else - | mov RB, [RC] - | mov RC, [RC+4] - | mov [BASE+RA*8], RB - | mov [BASE+RA*8+4], RC - |.endif - |1: - | ins_next - | - |2: // Check for __index if table value is nil. - | cmp dword TAB:RB->metatable, 0 // Shouldn't overwrite RA for fastpath. - | jz >3 - | mov TAB:RA, TAB:RB->metatable - | test byte TAB:RA->nomm, 1<vmeta_tgetv // 'no __index' flag NOT set: check. - | movzx RA, PC_RA // Restore RA. - |3: - | mov dword [BASE+RA*8+4], LJ_TNIL - | jmp <1 - | - |5: // String key? - | checkstr RC, ->vmeta_tgetv - | mov STR:RC, [BASE+RC*8] - | jmp ->BC_TGETS_Z - break; - case BC_TGETS: - | ins_ABC // RA = dst, RB = table, RC = str const (~) - | not RCa - | mov STR:RC, [KBASE+RC*4] - | checktab RB, ->vmeta_tgets - | mov TAB:RB, [BASE+RB*8] - |->BC_TGETS_Z: // RB = GCtab *, RC = GCstr *, refetches PC_RA. - | mov RA, TAB:RB->hmask - | and RA, STR:RC->hash - | imul RA, #NODE - | add NODE:RA, TAB:RB->node - |1: - | cmp dword NODE:RA->key.it, LJ_TSTR - | jne >4 - | cmp dword NODE:RA->key.gcr, STR:RC - | jne >4 - | // Ok, key found. Assumes: offsetof(Node, val) == 0 - | cmp dword [RA+4], LJ_TNIL // Avoid overwriting RB in fastpath. - | je >5 // Key found, but nil value? - | movzx RC, PC_RA - | // Get node value. - |.if X64 - | mov RBa, [RA] - | mov [BASE+RC*8], RBa - |.else - | mov RB, [RA] - | mov RA, [RA+4] - | mov [BASE+RC*8], RB - | mov [BASE+RC*8+4], RA - |.endif - |2: - | ins_next - | - |3: - | movzx RC, PC_RA - | mov dword [BASE+RC*8+4], LJ_TNIL - | jmp <2 - | - |4: // Follow hash chain. - | mov NODE:RA, NODE:RA->next - | test NODE:RA, NODE:RA - | jnz <1 - | // End of hash chain: key not found, nil result. - | - |5: // Check for __index if table value is nil. - | mov TAB:RA, TAB:RB->metatable - | test TAB:RA, TAB:RA - | jz <3 // No metatable: done. - | test byte TAB:RA->nomm, 1<vmeta_tgets // Caveat: preserve STR:RC. - break; - case BC_TGETB: - | ins_ABC // RA = dst, RB = table, RC = byte literal - | checktab RB, ->vmeta_tgetb - | mov TAB:RB, [BASE+RB*8] - | cmp RC, TAB:RB->asize - | jae ->vmeta_tgetb - | shl RC, 3 - | add RC, TAB:RB->array - | cmp dword [RC+4], LJ_TNIL // Avoid overwriting RB in fastpath. - | je >2 - | // Get array slot. - |.if X64 - | mov RBa, [RC] - | mov [BASE+RA*8], RBa - |.else - | mov RB, [RC] - | mov RC, [RC+4] - | mov [BASE+RA*8], RB - | mov [BASE+RA*8+4], RC - |.endif - |1: - | ins_next - | - |2: // Check for __index if table value is nil. - | cmp dword TAB:RB->metatable, 0 // Shouldn't overwrite RA for fastpath. - | jz >3 - | mov TAB:RA, TAB:RB->metatable - | test byte TAB:RA->nomm, 1<vmeta_tgetb // 'no __index' flag NOT set: check. - | movzx RA, PC_RA // Restore RA. - |3: - | mov dword [BASE+RA*8+4], LJ_TNIL - | jmp <1 - break; - case BC_TGETR: - | ins_ABC // RA = dst, RB = table, RC = key - | mov TAB:RB, [BASE+RB*8] - |.if DUALNUM - | mov RC, dword [BASE+RC*8] - |.else - | cvttsd2si RC, qword [BASE+RC*8] - |.endif - | cmp RC, TAB:RB->asize - | jae ->vmeta_tgetr // Not in array part? Use fallback. - | shl RC, 3 - | add RC, TAB:RB->array - | // Get array slot. - |->BC_TGETR_Z: - |.if X64 - | mov RBa, [RC] - | mov [BASE+RA*8], RBa - |.else - | mov RB, [RC] - | mov RC, [RC+4] - | mov [BASE+RA*8], RB - | mov [BASE+RA*8+4], RC - |.endif - |->BC_TGETR2_Z: - | ins_next - break; - - case BC_TSETV: - | ins_ABC // RA = src, RB = table, RC = key - | checktab RB, ->vmeta_tsetv - | mov TAB:RB, [BASE+RB*8] - | - | // Integer key? - |.if DUALNUM - | checkint RC, >5 - | mov RC, dword [BASE+RC*8] - |.else - | // Convert number to int and back and compare. - | checknum RC, >5 - | movsd xmm0, qword [BASE+RC*8] - | cvttsd2si RC, xmm0 - | cvtsi2sd xmm1, RC - | ucomisd xmm0, xmm1 - | jne ->vmeta_tsetv // Generic numeric key? Use fallback. - |.endif - | cmp RC, TAB:RB->asize // Takes care of unordered, too. - | jae ->vmeta_tsetv - | shl RC, 3 - | add RC, TAB:RB->array - | cmp dword [RC+4], LJ_TNIL - | je >3 // Previous value is nil? - |1: - | test byte TAB:RB->marked, LJ_GC_BLACK // isblack(table) - | jnz >7 - |2: // Set array slot. - |.if X64 - | mov RBa, [BASE+RA*8] - | mov [RC], RBa - |.else - | mov RB, [BASE+RA*8+4] - | mov RA, [BASE+RA*8] - | mov [RC+4], RB - | mov [RC], RA - |.endif - | ins_next - | - |3: // Check for __newindex if previous value is nil. - | cmp dword TAB:RB->metatable, 0 // Shouldn't overwrite RA for fastpath. - | jz <1 - | mov TAB:RA, TAB:RB->metatable - | test byte TAB:RA->nomm, 1<vmeta_tsetv // 'no __newindex' flag NOT set: check. - | movzx RA, PC_RA // Restore RA. - | jmp <1 - | - |5: // String key? - | checkstr RC, ->vmeta_tsetv - | mov STR:RC, [BASE+RC*8] - | jmp ->BC_TSETS_Z - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:RB, RA - | movzx RA, PC_RA // Restore RA. - | jmp <2 - break; - case BC_TSETS: - | ins_ABC // RA = src, RB = table, RC = str const (~) - | not RCa - | mov STR:RC, [KBASE+RC*4] - | checktab RB, ->vmeta_tsets - | mov TAB:RB, [BASE+RB*8] - |->BC_TSETS_Z: // RB = GCtab *, RC = GCstr *, refetches PC_RA. - | mov RA, TAB:RB->hmask - | and RA, STR:RC->hash - | imul RA, #NODE - | mov byte TAB:RB->nomm, 0 // Clear metamethod cache. - | add NODE:RA, TAB:RB->node - |1: - | cmp dword NODE:RA->key.it, LJ_TSTR - | jne >5 - | cmp dword NODE:RA->key.gcr, STR:RC - | jne >5 - | // Ok, key found. Assumes: offsetof(Node, val) == 0 - | cmp dword [RA+4], LJ_TNIL - | je >4 // Previous value is nil? - |2: - | test byte TAB:RB->marked, LJ_GC_BLACK // isblack(table) - | jnz >7 - |3: // Set node value. - | movzx RC, PC_RA - |.if X64 - | mov RBa, [BASE+RC*8] - | mov [RA], RBa - |.else - | mov RB, [BASE+RC*8+4] - | mov RC, [BASE+RC*8] - | mov [RA+4], RB - | mov [RA], RC - |.endif - | ins_next - | - |4: // Check for __newindex if previous value is nil. - | cmp dword TAB:RB->metatable, 0 // Shouldn't overwrite RA for fastpath. - | jz <2 - | mov TMP1, RA // Save RA. - | mov TAB:RA, TAB:RB->metatable - | test byte TAB:RA->nomm, 1<vmeta_tsets // 'no __newindex' flag NOT set: check. - | mov RA, TMP1 // Restore RA. - | jmp <2 - | - |5: // Follow hash chain. - | mov NODE:RA, NODE:RA->next - | test NODE:RA, NODE:RA - | jnz <1 - | // End of hash chain: key not found, add a new one. - | - | // But check for __newindex first. - | mov TAB:RA, TAB:RB->metatable - | test TAB:RA, TAB:RA - | jz >6 // No metatable: continue. - | test byte TAB:RA->nomm, 1<vmeta_tsets // 'no __newindex' flag NOT set: check. - |6: - | mov TMP1, STR:RC - | mov TMP2, LJ_TSTR - | mov TMP3, TAB:RB // Save TAB:RB for us. - |.if X64 - | mov L:CARG1d, SAVE_L - | mov L:CARG1d->base, BASE - | lea CARG3, TMP1 - | mov CARG2d, TAB:RB - | mov L:RB, L:CARG1d - |.else - | lea RC, TMP1 // Store temp. TValue in TMP1/TMP2. - | mov ARG2, TAB:RB - | mov L:RB, SAVE_L - | mov ARG3, RC - | mov ARG1, L:RB - | mov L:RB->base, BASE - |.endif - | mov SAVE_PC, PC - | call extern lj_tab_newkey // (lua_State *L, GCtab *t, TValue *k) - | // Handles write barrier for the new key. TValue * returned in eax (RC). - | mov BASE, L:RB->base - | mov TAB:RB, TMP3 // Need TAB:RB for barrier. - | mov RA, eax - | jmp <2 // Must check write barrier for value. - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:RB, RC // Destroys STR:RC. - | jmp <3 - break; - case BC_TSETB: - | ins_ABC // RA = src, RB = table, RC = byte literal - | checktab RB, ->vmeta_tsetb - | mov TAB:RB, [BASE+RB*8] - | cmp RC, TAB:RB->asize - | jae ->vmeta_tsetb - | shl RC, 3 - | add RC, TAB:RB->array - | cmp dword [RC+4], LJ_TNIL - | je >3 // Previous value is nil? - |1: - | test byte TAB:RB->marked, LJ_GC_BLACK // isblack(table) - | jnz >7 - |2: // Set array slot. - |.if X64 - | mov RAa, [BASE+RA*8] - | mov [RC], RAa - |.else - | mov RB, [BASE+RA*8+4] - | mov RA, [BASE+RA*8] - | mov [RC+4], RB - | mov [RC], RA - |.endif - | ins_next - | - |3: // Check for __newindex if previous value is nil. - | cmp dword TAB:RB->metatable, 0 // Shouldn't overwrite RA for fastpath. - | jz <1 - | mov TAB:RA, TAB:RB->metatable - | test byte TAB:RA->nomm, 1<vmeta_tsetb // 'no __newindex' flag NOT set: check. - | movzx RA, PC_RA // Restore RA. - | jmp <1 - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:RB, RA - | movzx RA, PC_RA // Restore RA. - | jmp <2 - break; - case BC_TSETR: - | ins_ABC // RA = src, RB = table, RC = key - | mov TAB:RB, [BASE+RB*8] - |.if DUALNUM - | mov RC, dword [BASE+RC*8] - |.else - | cvttsd2si RC, qword [BASE+RC*8] - |.endif - | test byte TAB:RB->marked, LJ_GC_BLACK // isblack(table) - | jnz >7 - |2: - | cmp RC, TAB:RB->asize - | jae ->vmeta_tsetr - | shl RC, 3 - | add RC, TAB:RB->array - | // Set array slot. - |->BC_TSETR_Z: - |.if X64 - | mov RBa, [BASE+RA*8] - | mov [RC], RBa - |.else - | mov RB, [BASE+RA*8+4] - | mov RA, [BASE+RA*8] - | mov [RC+4], RB - | mov [RC], RA - |.endif - | ins_next - | - |7: // Possible table write barrier for the value. Skip valiswhite check. - | barrierback TAB:RB, RA - | movzx RA, PC_RA // Restore RA. - | jmp <2 - break; - - case BC_TSETM: - | ins_AD // RA = base (table at base-1), RD = num const (start index) - | mov TMP1, KBASE // Need one more free register. - | mov KBASE, dword [KBASE+RD*8] // Integer constant is in lo-word. - |1: - | lea RA, [BASE+RA*8] - | mov TAB:RB, [RA-8] // Guaranteed to be a table. - | test byte TAB:RB->marked, LJ_GC_BLACK // isblack(table) - | jnz >7 - |2: - | mov RD, MULTRES - | sub RD, 1 - | jz >4 // Nothing to copy? - | add RD, KBASE // Compute needed size. - | cmp RD, TAB:RB->asize - | ja >5 // Doesn't fit into array part? - | sub RD, KBASE - | shl KBASE, 3 - | add KBASE, TAB:RB->array - |3: // Copy result slots to table. - |.if X64 - | mov RBa, [RA] - | add RA, 8 - | mov [KBASE], RBa - |.else - | mov RB, [RA] - | mov [KBASE], RB - | mov RB, [RA+4] - | add RA, 8 - | mov [KBASE+4], RB - |.endif - | add KBASE, 8 - | sub RD, 1 - | jnz <3 - |4: - | mov KBASE, TMP1 - | ins_next - | - |5: // Need to resize array part. - |.if X64 - | mov L:CARG1d, SAVE_L - | mov L:CARG1d->base, BASE // Caveat: CARG2d/CARG3d may be BASE. - | mov CARG2d, TAB:RB - | mov CARG3d, RD - | mov L:RB, L:CARG1d - |.else - | mov ARG2, TAB:RB - | mov L:RB, SAVE_L - | mov L:RB->base, BASE - | mov ARG3, RD - | mov ARG1, L:RB - |.endif - | mov SAVE_PC, PC - | call extern lj_tab_reasize // (lua_State *L, GCtab *t, int nasize) - | mov BASE, L:RB->base - | movzx RA, PC_RA // Restore RA. - | jmp <1 // Retry. - | - |7: // Possible table write barrier for any value. Skip valiswhite check. - | barrierback TAB:RB, RD - | jmp <2 - break; - - /* -- Calls and vararg handling ----------------------------------------- */ - - case BC_CALL: case BC_CALLM: - | ins_A_C // RA = base, (RB = nresults+1,) RC = nargs+1 | extra_nargs - if (op == BC_CALLM) { - | add NARGS:RD, MULTRES - } - | cmp dword [BASE+RA*8+4], LJ_TFUNC - | mov LFUNC:RB, [BASE+RA*8] - | jne ->vmeta_call_ra - | lea BASE, [BASE+RA*8+8] - | ins_call - break; - - case BC_CALLMT: - | ins_AD // RA = base, RD = extra_nargs - | add NARGS:RD, MULTRES - | // Fall through. Assumes BC_CALLT follows and ins_AD is a no-op. - break; - case BC_CALLT: - | ins_AD // RA = base, RD = nargs+1 - | lea RA, [BASE+RA*8+8] - | mov KBASE, BASE // Use KBASE for move + vmeta_call hint. - | mov LFUNC:RB, [RA-8] - | cmp dword [RA-4], LJ_TFUNC - | jne ->vmeta_call - |->BC_CALLT_Z: - | mov PC, [BASE-4] - | test PC, FRAME_TYPE - | jnz >7 - |1: - | mov [BASE-8], LFUNC:RB // Copy function down, reloaded below. - | mov MULTRES, NARGS:RD - | sub NARGS:RD, 1 - | jz >3 - |2: // Move args down. - |.if X64 - | mov RBa, [RA] - | add RA, 8 - | mov [KBASE], RBa - |.else - | mov RB, [RA] - | mov [KBASE], RB - | mov RB, [RA+4] - | add RA, 8 - | mov [KBASE+4], RB - |.endif - | add KBASE, 8 - | sub NARGS:RD, 1 - | jnz <2 - | - | mov LFUNC:RB, [BASE-8] - |3: - | mov NARGS:RD, MULTRES - | cmp byte LFUNC:RB->ffid, 1 // (> FF_C) Calling a fast function? - | ja >5 - |4: - | ins_callt - | - |5: // Tailcall to a fast function. - | test PC, FRAME_TYPE // Lua frame below? - | jnz <4 - | movzx RA, PC_RA - | not RAa - | mov LFUNC:KBASE, [BASE+RA*8-8] // Need to prepare KBASE. - | mov KBASE, LFUNC:KBASE->pc - | mov KBASE, [KBASE+PC2PROTO(k)] - | jmp <4 - | - |7: // Tailcall from a vararg function. - | sub PC, FRAME_VARG - | test PC, FRAME_TYPEP - | jnz >8 // Vararg frame below? - | sub BASE, PC // Need to relocate BASE/KBASE down. - | mov KBASE, BASE - | mov PC, [BASE-4] - | jmp <1 - |8: - | add PC, FRAME_VARG - | jmp <1 - break; - - case BC_ITERC: - | ins_A // RA = base, (RB = nresults+1,) RC = nargs+1 (2+1) - | lea RA, [BASE+RA*8+8] // fb = base+1 - |.if X64 - | mov RBa, [RA-24] // Copy state. fb[0] = fb[-3]. - | mov RCa, [RA-16] // Copy control var. fb[1] = fb[-2]. - | mov [RA], RBa - | mov [RA+8], RCa - |.else - | mov RB, [RA-24] // Copy state. fb[0] = fb[-3]. - | mov RC, [RA-20] - | mov [RA], RB - | mov [RA+4], RC - | mov RB, [RA-16] // Copy control var. fb[1] = fb[-2]. - | mov RC, [RA-12] - | mov [RA+8], RB - | mov [RA+12], RC - |.endif - | mov LFUNC:RB, [RA-32] // Copy callable. fb[-1] = fb[-4] - | mov RC, [RA-28] - | mov [RA-8], LFUNC:RB - | mov [RA-4], RC - | cmp RC, LJ_TFUNC // Handle like a regular 2-arg call. - | mov NARGS:RD, 2+1 - | jne ->vmeta_call - | mov BASE, RA - | ins_call - break; - - case BC_ITERN: - | ins_A // RA = base, (RB = nresults+1, RC = nargs+1 (2+1)) - |.if JIT - | // NYI: add hotloop, record BC_ITERN. - |.endif - | mov TMP1, KBASE // Need two more free registers. - | mov TMP2, DISPATCH - | mov TAB:RB, [BASE+RA*8-16] - | mov RC, [BASE+RA*8-8] // Get index from control var. - | mov DISPATCH, TAB:RB->asize - | add PC, 4 - | mov KBASE, TAB:RB->array - |1: // Traverse array part. - | cmp RC, DISPATCH; jae >5 // Index points after array part? - | cmp dword [KBASE+RC*8+4], LJ_TNIL; je >4 - |.if DUALNUM - | mov dword [BASE+RA*8+4], LJ_TISNUM - | mov dword [BASE+RA*8], RC - |.else - | cvtsi2sd xmm0, RC - |.endif - | // Copy array slot to returned value. - |.if X64 - | mov RBa, [KBASE+RC*8] - | mov [BASE+RA*8+8], RBa - |.else - | mov RB, [KBASE+RC*8+4] - | mov [BASE+RA*8+12], RB - | mov RB, [KBASE+RC*8] - | mov [BASE+RA*8+8], RB - |.endif - | add RC, 1 - | // Return array index as a numeric key. - |.if DUALNUM - | // See above. - |.else - | movsd qword [BASE+RA*8], xmm0 - |.endif - | mov [BASE+RA*8-8], RC // Update control var. - |2: - | movzx RD, PC_RD // Get target from ITERL. - | branchPC RD - |3: - | mov DISPATCH, TMP2 - | mov KBASE, TMP1 - | ins_next - | - |4: // Skip holes in array part. - | add RC, 1 - | jmp <1 - | - |5: // Traverse hash part. - | sub RC, DISPATCH - |6: - | cmp RC, TAB:RB->hmask; ja <3 // End of iteration? Branch to ITERL+1. - | imul KBASE, RC, #NODE - | add NODE:KBASE, TAB:RB->node - | cmp dword NODE:KBASE->val.it, LJ_TNIL; je >7 - | lea DISPATCH, [RC+DISPATCH+1] - | // Copy key and value from hash slot. - |.if X64 - | mov RBa, NODE:KBASE->key - | mov RCa, NODE:KBASE->val - | mov [BASE+RA*8], RBa - | mov [BASE+RA*8+8], RCa - |.else - | mov RB, NODE:KBASE->key.gcr - | mov RC, NODE:KBASE->key.it - | mov [BASE+RA*8], RB - | mov [BASE+RA*8+4], RC - | mov RB, NODE:KBASE->val.gcr - | mov RC, NODE:KBASE->val.it - | mov [BASE+RA*8+8], RB - | mov [BASE+RA*8+12], RC - |.endif - | mov [BASE+RA*8-8], DISPATCH - | jmp <2 - | - |7: // Skip holes in hash part. - | add RC, 1 - | jmp <6 - break; - - case BC_ISNEXT: - | ins_AD // RA = base, RD = target (points to ITERN) - | cmp dword [BASE+RA*8-20], LJ_TFUNC; jne >5 - | mov CFUNC:RB, [BASE+RA*8-24] - | cmp dword [BASE+RA*8-12], LJ_TTAB; jne >5 - | cmp dword [BASE+RA*8-4], LJ_TNIL; jne >5 - | cmp byte CFUNC:RB->ffid, FF_next_N; jne >5 - | branchPC RD - | mov dword [BASE+RA*8-8], 0 // Initialize control var. - | mov dword [BASE+RA*8-4], 0xfffe7fff - |1: - | ins_next - |5: // Despecialize bytecode if any of the checks fail. - | mov PC_OP, BC_JMP - | branchPC RD - | mov byte [PC], BC_ITERC - | jmp <1 - break; - - case BC_VARG: - | ins_ABC // RA = base, RB = nresults+1, RC = numparams - | mov TMP1, KBASE // Need one more free register. - | lea KBASE, [BASE+RC*8+(8+FRAME_VARG)] - | lea RA, [BASE+RA*8] - | sub KBASE, [BASE-4] - | // Note: KBASE may now be even _above_ BASE if nargs was < numparams. - | test RB, RB - | jz >5 // Copy all varargs? - | lea RB, [RA+RB*8-8] - | cmp KBASE, BASE // No vararg slots? - | jnb >2 - |1: // Copy vararg slots to destination slots. - |.if X64 - | mov RCa, [KBASE-8] - | add KBASE, 8 - | mov [RA], RCa - |.else - | mov RC, [KBASE-8] - | mov [RA], RC - | mov RC, [KBASE-4] - | add KBASE, 8 - | mov [RA+4], RC - |.endif - | add RA, 8 - | cmp RA, RB // All destination slots filled? - | jnb >3 - | cmp KBASE, BASE // No more vararg slots? - | jb <1 - |2: // Fill up remainder with nil. - | mov dword [RA+4], LJ_TNIL - | add RA, 8 - | cmp RA, RB - | jb <2 - |3: - | mov KBASE, TMP1 - | ins_next - | - |5: // Copy all varargs. - | mov MULTRES, 1 // MULTRES = 0+1 - | mov RC, BASE - | sub RC, KBASE - | jbe <3 // No vararg slots? - | mov RB, RC - | shr RB, 3 - | add RB, 1 - | mov MULTRES, RB // MULTRES = #varargs+1 - | mov L:RB, SAVE_L - | add RC, RA - | cmp RC, L:RB->maxstack - | ja >7 // Need to grow stack? - |6: // Copy all vararg slots. - |.if X64 - | mov RCa, [KBASE-8] - | add KBASE, 8 - | mov [RA], RCa - |.else - | mov RC, [KBASE-8] - | mov [RA], RC - | mov RC, [KBASE-4] - | add KBASE, 8 - | mov [RA+4], RC - |.endif - | add RA, 8 - | cmp KBASE, BASE // No more vararg slots? - | jb <6 - | jmp <3 - | - |7: // Grow stack for varargs. - | mov L:RB->base, BASE - | mov L:RB->top, RA - | mov SAVE_PC, PC - | sub KBASE, BASE // Need delta, because BASE may change. - | mov FCARG2, MULTRES - | sub FCARG2, 1 - | mov FCARG1, L:RB - | call extern lj_state_growstack@8 // (lua_State *L, int n) - | mov BASE, L:RB->base - | mov RA, L:RB->top - | add KBASE, BASE - | jmp <6 - break; - - /* -- Returns ----------------------------------------------------------- */ - - case BC_RETM: - | ins_AD // RA = results, RD = extra_nresults - | add RD, MULTRES // MULTRES >=1, so RD >=1. - | // Fall through. Assumes BC_RET follows and ins_AD is a no-op. - break; - - case BC_RET: case BC_RET0: case BC_RET1: - | ins_AD // RA = results, RD = nresults+1 - if (op != BC_RET0) { - | shl RA, 3 - } - |1: - | mov PC, [BASE-4] - | mov MULTRES, RD // Save nresults+1. - | test PC, FRAME_TYPE // Check frame type marker. - | jnz >7 // Not returning to a fixarg Lua func? - switch (op) { - case BC_RET: - |->BC_RET_Z: - | mov KBASE, BASE // Use KBASE for result move. - | sub RD, 1 - | jz >3 - |2: // Move results down. - |.if X64 - | mov RBa, [KBASE+RA] - | mov [KBASE-8], RBa - |.else - | mov RB, [KBASE+RA] - | mov [KBASE-8], RB - | mov RB, [KBASE+RA+4] - | mov [KBASE-4], RB - |.endif - | add KBASE, 8 - | sub RD, 1 - | jnz <2 - |3: - | mov RD, MULTRES // Note: MULTRES may be >255. - | movzx RB, PC_RB // So cannot compare with RDL! - |5: - | cmp RB, RD // More results expected? - | ja >6 - break; - case BC_RET1: - |.if X64 - | mov RBa, [BASE+RA] - | mov [BASE-8], RBa - |.else - | mov RB, [BASE+RA+4] - | mov [BASE-4], RB - | mov RB, [BASE+RA] - | mov [BASE-8], RB - |.endif - /* fallthrough */ - case BC_RET0: - |5: - | cmp PC_RB, RDL // More results expected? - | ja >6 - default: - break; - } - | movzx RA, PC_RA - | not RAa // Note: ~RA = -(RA+1) - | lea BASE, [BASE+RA*8] // base = base - (RA+1)*8 - | mov LFUNC:KBASE, [BASE-8] - | mov KBASE, LFUNC:KBASE->pc - | mov KBASE, [KBASE+PC2PROTO(k)] - | ins_next - | - |6: // Fill up results with nil. - if (op == BC_RET) { - | mov dword [KBASE-4], LJ_TNIL // Note: relies on shifted base. - | add KBASE, 8 - } else { - | mov dword [BASE+RD*8-12], LJ_TNIL - } - | add RD, 1 - | jmp <5 - | - |7: // Non-standard return case. - | lea RB, [PC-FRAME_VARG] - | test RB, FRAME_TYPEP - | jnz ->vm_return - | // Return from vararg function: relocate BASE down and RA up. - | sub BASE, RB - if (op != BC_RET0) { - | add RA, RB - } - | jmp <1 - break; - - /* -- Loops and branches ------------------------------------------------ */ - - |.define FOR_IDX, [RA]; .define FOR_TIDX, dword [RA+4] - |.define FOR_STOP, [RA+8]; .define FOR_TSTOP, dword [RA+12] - |.define FOR_STEP, [RA+16]; .define FOR_TSTEP, dword [RA+20] - |.define FOR_EXT, [RA+24]; .define FOR_TEXT, dword [RA+28] - - case BC_FORL: - |.if JIT - | hotloop RB - |.endif - | // Fall through. Assumes BC_IFORL follows and ins_AJ is a no-op. - break; - - case BC_JFORI: - case BC_JFORL: -#if !LJ_HASJIT - break; -#endif - case BC_FORI: - case BC_IFORL: - vk = (op == BC_IFORL || op == BC_JFORL); - | ins_AJ // RA = base, RD = target (after end of loop or start of loop) - | lea RA, [BASE+RA*8] - if (LJ_DUALNUM) { - | cmp FOR_TIDX, LJ_TISNUM; jne >9 - if (!vk) { - | cmp FOR_TSTOP, LJ_TISNUM; jne ->vmeta_for - | cmp FOR_TSTEP, LJ_TISNUM; jne ->vmeta_for - | mov RB, dword FOR_IDX - | cmp dword FOR_STEP, 0; jl >5 - } else { -#ifdef LUA_USE_ASSERT - | cmp FOR_TSTOP, LJ_TISNUM; jne ->assert_bad_for_arg_type - | cmp FOR_TSTEP, LJ_TISNUM; jne ->assert_bad_for_arg_type -#endif - | mov RB, dword FOR_STEP - | test RB, RB; js >5 - | add RB, dword FOR_IDX; jo >1 - | mov dword FOR_IDX, RB - } - | cmp RB, dword FOR_STOP - | mov FOR_TEXT, LJ_TISNUM - | mov dword FOR_EXT, RB - if (op == BC_FORI) { - | jle >7 - |1: - |6: - | branchPC RD - } else if (op == BC_JFORI) { - | branchPC RD - | movzx RD, PC_RD - | jle =>BC_JLOOP - |1: - |6: - } else if (op == BC_IFORL) { - | jg >7 - |6: - | branchPC RD - |1: - } else { - | jle =>BC_JLOOP - |1: - |6: - } - |7: - | ins_next - | - |5: // Invert check for negative step. - if (vk) { - | add RB, dword FOR_IDX; jo <1 - | mov dword FOR_IDX, RB - } - | cmp RB, dword FOR_STOP - | mov FOR_TEXT, LJ_TISNUM - | mov dword FOR_EXT, RB - if (op == BC_FORI) { - | jge <7 - } else if (op == BC_JFORI) { - | branchPC RD - | movzx RD, PC_RD - | jge =>BC_JLOOP - } else if (op == BC_IFORL) { - | jl <7 - } else { - | jge =>BC_JLOOP - } - | jmp <6 - |9: // Fallback to FP variant. - } else if (!vk) { - | cmp FOR_TIDX, LJ_TISNUM - } - if (!vk) { - | jae ->vmeta_for - | cmp FOR_TSTOP, LJ_TISNUM; jae ->vmeta_for - } else { -#ifdef LUA_USE_ASSERT - | cmp FOR_TSTOP, LJ_TISNUM; jae ->assert_bad_for_arg_type - | cmp FOR_TSTEP, LJ_TISNUM; jae ->assert_bad_for_arg_type -#endif - } - | mov RB, FOR_TSTEP // Load type/hiword of for step. - if (!vk) { - | cmp RB, LJ_TISNUM; jae ->vmeta_for - } - | movsd xmm0, qword FOR_IDX - | movsd xmm1, qword FOR_STOP - if (vk) { - | addsd xmm0, qword FOR_STEP - | movsd qword FOR_IDX, xmm0 - | test RB, RB; js >3 - } else { - | jl >3 - } - | ucomisd xmm1, xmm0 - |1: - | movsd qword FOR_EXT, xmm0 - if (op == BC_FORI) { - |.if DUALNUM - | jnb <7 - |.else - | jnb >2 - | branchPC RD - |.endif - } else if (op == BC_JFORI) { - | branchPC RD - | movzx RD, PC_RD - | jnb =>BC_JLOOP - } else if (op == BC_IFORL) { - |.if DUALNUM - | jb <7 - |.else - | jb >2 - | branchPC RD - |.endif - } else { - | jnb =>BC_JLOOP - } - |.if DUALNUM - | jmp <6 - |.else - |2: - | ins_next - |.endif - | - |3: // Invert comparison if step is negative. - | ucomisd xmm0, xmm1 - | jmp <1 - break; - - case BC_ITERL: - |.if JIT - | hotloop RB - |.endif - | // Fall through. Assumes BC_IITERL follows and ins_AJ is a no-op. - break; - - case BC_JITERL: -#if !LJ_HASJIT - break; -#endif - case BC_IITERL: - | ins_AJ // RA = base, RD = target - | lea RA, [BASE+RA*8] - | mov RB, [RA+4] - | cmp RB, LJ_TNIL; je >1 // Stop if iterator returned nil. - if (op == BC_JITERL) { - | mov [RA-4], RB - | mov RB, [RA] - | mov [RA-8], RB - | jmp =>BC_JLOOP - } else { - | branchPC RD // Otherwise save control var + branch. - | mov RD, [RA] - | mov [RA-4], RB - | mov [RA-8], RD - } - |1: - | ins_next - break; - - case BC_LOOP: - | ins_A // RA = base, RD = target (loop extent) - | // Note: RA/RD is only used by trace recorder to determine scope/extent - | // This opcode does NOT jump, it's only purpose is to detect a hot loop. - |.if JIT - | hotloop RB - |.endif - | // Fall through. Assumes BC_ILOOP follows and ins_A is a no-op. - break; - - case BC_ILOOP: - | ins_A // RA = base, RD = target (loop extent) - | ins_next - break; - - case BC_JLOOP: - |.if JIT - | ins_AD // RA = base (ignored), RD = traceno - | mov RA, [DISPATCH+DISPATCH_J(trace)] - | mov TRACE:RD, [RA+RD*4] - | mov RDa, TRACE:RD->mcode - | mov L:RB, SAVE_L - | mov [DISPATCH+DISPATCH_GL(jit_base)], BASE - | mov [DISPATCH+DISPATCH_GL(tmpbuf.L)], L:RB - | // Save additional callee-save registers only used in compiled code. - |.if X64WIN - | mov TMPQ, r12 - | mov TMPa, r13 - | mov CSAVE_4, r14 - | mov CSAVE_3, r15 - | mov RAa, rsp - | sub rsp, 9*16+4*8 - | movdqa [RAa], xmm6 - | movdqa [RAa-1*16], xmm7 - | movdqa [RAa-2*16], xmm8 - | movdqa [RAa-3*16], xmm9 - | movdqa [RAa-4*16], xmm10 - | movdqa [RAa-5*16], xmm11 - | movdqa [RAa-6*16], xmm12 - | movdqa [RAa-7*16], xmm13 - | movdqa [RAa-8*16], xmm14 - | movdqa [RAa-9*16], xmm15 - |.elif X64 - | mov TMPQ, r12 - | mov TMPa, r13 - | sub rsp, 16 - |.endif - | jmp RDa - |.endif - break; - - case BC_JMP: - | ins_AJ // RA = unused, RD = target - | branchPC RD - | ins_next - break; - - /* -- Function headers -------------------------------------------------- */ - - /* - ** Reminder: A function may be called with func/args above L->maxstack, - ** i.e. occupying EXTRA_STACK slots. And vmeta_call may add one extra slot, - ** too. This means all FUNC* ops (including fast functions) must check - ** for stack overflow _before_ adding more slots! - */ - - case BC_FUNCF: - |.if JIT - | hotcall RB - |.endif - case BC_FUNCV: /* NYI: compiled vararg functions. */ - | // Fall through. Assumes BC_IFUNCF/BC_IFUNCV follow and ins_AD is a no-op. - break; - - case BC_JFUNCF: -#if !LJ_HASJIT - break; -#endif - case BC_IFUNCF: - | ins_AD // BASE = new base, RA = framesize, RD = nargs+1 - | mov KBASE, [PC-4+PC2PROTO(k)] - | mov L:RB, SAVE_L - | lea RA, [BASE+RA*8] // Top of frame. - | cmp RA, L:RB->maxstack - | ja ->vm_growstack_f - | movzx RA, byte [PC-4+PC2PROTO(numparams)] - | cmp NARGS:RD, RA // Check for missing parameters. - | jbe >3 - |2: - if (op == BC_JFUNCF) { - | movzx RD, PC_RD - | jmp =>BC_JLOOP - } else { - | ins_next - } - | - |3: // Clear missing parameters. - | mov dword [BASE+NARGS:RD*8-4], LJ_TNIL - | add NARGS:RD, 1 - | cmp NARGS:RD, RA - | jbe <3 - | jmp <2 - break; - - case BC_JFUNCV: -#if !LJ_HASJIT - break; -#endif - | int3 // NYI: compiled vararg functions - break; /* NYI: compiled vararg functions. */ - - case BC_IFUNCV: - | ins_AD // BASE = new base, RA = framesize, RD = nargs+1 - | lea RB, [NARGS:RD*8+FRAME_VARG] - | lea RD, [BASE+NARGS:RD*8] - | mov LFUNC:KBASE, [BASE-8] - | mov [RD-4], RB // Store delta + FRAME_VARG. - | mov [RD-8], LFUNC:KBASE // Store copy of LFUNC. - | mov L:RB, SAVE_L - | lea RA, [RD+RA*8] - | cmp RA, L:RB->maxstack - | ja ->vm_growstack_v // Need to grow stack. - | mov RA, BASE - | mov BASE, RD - | movzx RB, byte [PC-4+PC2PROTO(numparams)] - | test RB, RB - | jz >2 - |1: // Copy fixarg slots up to new frame. - | add RA, 8 - | cmp RA, BASE - | jnb >3 // Less args than parameters? - | mov KBASE, [RA-8] - | mov [RD], KBASE - | mov KBASE, [RA-4] - | mov [RD+4], KBASE - | add RD, 8 - | mov dword [RA-4], LJ_TNIL // Clear old fixarg slot (help the GC). - | sub RB, 1 - | jnz <1 - |2: - if (op == BC_JFUNCV) { - | movzx RD, PC_RD - | jmp =>BC_JLOOP - } else { - | mov KBASE, [PC-4+PC2PROTO(k)] - | ins_next - } - | - |3: // Clear missing parameters. - | mov dword [RD+4], LJ_TNIL - | add RD, 8 - | sub RB, 1 - | jnz <3 - | jmp <2 - break; - - case BC_FUNCC: - case BC_FUNCCW: - | ins_AD // BASE = new base, RA = ins RA|RD (unused), RD = nargs+1 - | mov CFUNC:RB, [BASE-8] - | mov KBASEa, CFUNC:RB->f - | mov L:RB, SAVE_L - | lea RD, [BASE+NARGS:RD*8-8] - | mov L:RB->base, BASE - | lea RA, [RD+8*LUA_MINSTACK] - | cmp RA, L:RB->maxstack - | mov L:RB->top, RD - if (op == BC_FUNCC) { - |.if X64 - | mov CARG1d, L:RB // Caveat: CARG1d may be RA. - |.else - | mov ARG1, L:RB - |.endif - } else { - |.if X64 - | mov CARG2, KBASEa - | mov CARG1d, L:RB // Caveat: CARG1d may be RA. - |.else - | mov ARG2, KBASEa - | mov ARG1, L:RB - |.endif - } - | ja ->vm_growstack_c // Need to grow stack. - | set_vmstate C - if (op == BC_FUNCC) { - | call KBASEa // (lua_State *L) - } else { - | // (lua_State *L, lua_CFunction f) - | call aword [DISPATCH+DISPATCH_GL(wrapf)] - } - | // nresults returned in eax (RD). - | mov BASE, L:RB->base - | mov [DISPATCH+DISPATCH_GL(cur_L)], L:RB - | set_vmstate INTERP - | lea RA, [BASE+RD*8] - | neg RA - | add RA, L:RB->top // RA = (L->top-(L->base+nresults))*8 - | mov PC, [BASE-4] // Fetch PC of caller. - | jmp ->vm_returnc - break; - - /* ---------------------------------------------------------------------- */ - - default: - fprintf(stderr, "Error: undefined opcode BC_%s\n", bc_names[op]); - exit(2); - break; - } -} - -static int build_backend(BuildCtx *ctx) -{ - int op; - dasm_growpc(Dst, BC__MAX); - build_subroutines(ctx); - |.code_op - for (op = 0; op < BC__MAX; op++) - build_ins(ctx, (BCOp)op, op); - return BC__MAX; -} - -/* Emit pseudo frame-info for all assembler functions. */ -static void emit_asm_debug(BuildCtx *ctx) -{ - int fcofs = (int)((uint8_t *)ctx->glob[GLOB_vm_ffi_call] - ctx->code); -#if LJ_64 -#define SZPTR "8" -#define BSZPTR "3" -#define REG_SP "0x7" -#define REG_RA "0x10" -#else -#define SZPTR "4" -#define BSZPTR "2" -#define REG_SP "0x4" -#define REG_RA "0x8" -#endif - switch (ctx->mode) { - case BUILD_elfasm: - fprintf(ctx->fp, "\t.section .debug_frame,\"\",@progbits\n"); - fprintf(ctx->fp, - ".Lframe0:\n" - "\t.long .LECIE0-.LSCIE0\n" - ".LSCIE0:\n" - "\t.long 0xffffffff\n" - "\t.byte 0x1\n" - "\t.string \"\"\n" - "\t.uleb128 0x1\n" - "\t.sleb128 -" SZPTR "\n" - "\t.byte " REG_RA "\n" - "\t.byte 0xc\n\t.uleb128 " REG_SP "\n\t.uleb128 " SZPTR "\n" - "\t.byte 0x80+" REG_RA "\n\t.uleb128 0x1\n" - "\t.align " SZPTR "\n" - ".LECIE0:\n\n"); - fprintf(ctx->fp, - ".LSFDE0:\n" - "\t.long .LEFDE0-.LASFDE0\n" - ".LASFDE0:\n" - "\t.long .Lframe0\n" -#if LJ_64 - "\t.quad .Lbegin\n" - "\t.quad %d\n" - "\t.byte 0xe\n\t.uleb128 %d\n" /* def_cfa_offset */ - "\t.byte 0x86\n\t.uleb128 0x2\n" /* offset rbp */ - "\t.byte 0x83\n\t.uleb128 0x3\n" /* offset rbx */ - "\t.byte 0x8f\n\t.uleb128 0x4\n" /* offset r15 */ - "\t.byte 0x8e\n\t.uleb128 0x5\n" /* offset r14 */ -#if LJ_NO_UNWIND - "\t.byte 0x8d\n\t.uleb128 0x6\n" /* offset r13 */ - "\t.byte 0x8c\n\t.uleb128 0x7\n" /* offset r12 */ -#endif -#else - "\t.long .Lbegin\n" - "\t.long %d\n" - "\t.byte 0xe\n\t.uleb128 %d\n" /* def_cfa_offset */ - "\t.byte 0x85\n\t.uleb128 0x2\n" /* offset ebp */ - "\t.byte 0x87\n\t.uleb128 0x3\n" /* offset edi */ - "\t.byte 0x86\n\t.uleb128 0x4\n" /* offset esi */ - "\t.byte 0x83\n\t.uleb128 0x5\n" /* offset ebx */ -#endif - "\t.align " SZPTR "\n" - ".LEFDE0:\n\n", fcofs, CFRAME_SIZE); -#if LJ_HASFFI - fprintf(ctx->fp, - ".LSFDE1:\n" - "\t.long .LEFDE1-.LASFDE1\n" - ".LASFDE1:\n" - "\t.long .Lframe0\n" -#if LJ_64 - "\t.quad lj_vm_ffi_call\n" - "\t.quad %d\n" - "\t.byte 0xe\n\t.uleb128 16\n" /* def_cfa_offset */ - "\t.byte 0x86\n\t.uleb128 0x2\n" /* offset rbp */ - "\t.byte 0xd\n\t.uleb128 0x6\n" /* def_cfa_register rbp */ - "\t.byte 0x83\n\t.uleb128 0x3\n" /* offset rbx */ -#else - "\t.long lj_vm_ffi_call\n" - "\t.long %d\n" - "\t.byte 0xe\n\t.uleb128 8\n" /* def_cfa_offset */ - "\t.byte 0x85\n\t.uleb128 0x2\n" /* offset ebp */ - "\t.byte 0xd\n\t.uleb128 0x5\n" /* def_cfa_register ebp */ - "\t.byte 0x83\n\t.uleb128 0x3\n" /* offset ebx */ -#endif - "\t.align " SZPTR "\n" - ".LEFDE1:\n\n", (int)ctx->codesz - fcofs); -#endif -#if !LJ_NO_UNWIND -#if (defined(__sun__) && defined(__svr4__)) -#if LJ_64 - fprintf(ctx->fp, "\t.section .eh_frame,\"a\",@unwind\n"); -#else - fprintf(ctx->fp, "\t.section .eh_frame,\"aw\",@progbits\n"); -#endif -#else - fprintf(ctx->fp, "\t.section .eh_frame,\"a\",@progbits\n"); -#endif - fprintf(ctx->fp, - ".Lframe1:\n" - "\t.long .LECIE1-.LSCIE1\n" - ".LSCIE1:\n" - "\t.long 0\n" - "\t.byte 0x1\n" - "\t.string \"zPR\"\n" - "\t.uleb128 0x1\n" - "\t.sleb128 -" SZPTR "\n" - "\t.byte " REG_RA "\n" - "\t.uleb128 6\n" /* augmentation length */ - "\t.byte 0x1b\n" /* pcrel|sdata4 */ - "\t.long lj_err_unwind_dwarf-.\n" - "\t.byte 0x1b\n" /* pcrel|sdata4 */ - "\t.byte 0xc\n\t.uleb128 " REG_SP "\n\t.uleb128 " SZPTR "\n" - "\t.byte 0x80+" REG_RA "\n\t.uleb128 0x1\n" - "\t.align " SZPTR "\n" - ".LECIE1:\n\n"); - fprintf(ctx->fp, - ".LSFDE2:\n" - "\t.long .LEFDE2-.LASFDE2\n" - ".LASFDE2:\n" - "\t.long .LASFDE2-.Lframe1\n" - "\t.long .Lbegin-.\n" - "\t.long %d\n" - "\t.uleb128 0\n" /* augmentation length */ - "\t.byte 0xe\n\t.uleb128 %d\n" /* def_cfa_offset */ -#if LJ_64 - "\t.byte 0x86\n\t.uleb128 0x2\n" /* offset rbp */ - "\t.byte 0x83\n\t.uleb128 0x3\n" /* offset rbx */ - "\t.byte 0x8f\n\t.uleb128 0x4\n" /* offset r15 */ - "\t.byte 0x8e\n\t.uleb128 0x5\n" /* offset r14 */ -#else - "\t.byte 0x85\n\t.uleb128 0x2\n" /* offset ebp */ - "\t.byte 0x87\n\t.uleb128 0x3\n" /* offset edi */ - "\t.byte 0x86\n\t.uleb128 0x4\n" /* offset esi */ - "\t.byte 0x83\n\t.uleb128 0x5\n" /* offset ebx */ -#endif - "\t.align " SZPTR "\n" - ".LEFDE2:\n\n", fcofs, CFRAME_SIZE); -#if LJ_HASFFI - fprintf(ctx->fp, - ".Lframe2:\n" - "\t.long .LECIE2-.LSCIE2\n" - ".LSCIE2:\n" - "\t.long 0\n" - "\t.byte 0x1\n" - "\t.string \"zR\"\n" - "\t.uleb128 0x1\n" - "\t.sleb128 -" SZPTR "\n" - "\t.byte " REG_RA "\n" - "\t.uleb128 1\n" /* augmentation length */ - "\t.byte 0x1b\n" /* pcrel|sdata4 */ - "\t.byte 0xc\n\t.uleb128 " REG_SP "\n\t.uleb128 " SZPTR "\n" - "\t.byte 0x80+" REG_RA "\n\t.uleb128 0x1\n" - "\t.align " SZPTR "\n" - ".LECIE2:\n\n"); - fprintf(ctx->fp, - ".LSFDE3:\n" - "\t.long .LEFDE3-.LASFDE3\n" - ".LASFDE3:\n" - "\t.long .LASFDE3-.Lframe2\n" - "\t.long lj_vm_ffi_call-.\n" - "\t.long %d\n" - "\t.uleb128 0\n" /* augmentation length */ -#if LJ_64 - "\t.byte 0xe\n\t.uleb128 16\n" /* def_cfa_offset */ - "\t.byte 0x86\n\t.uleb128 0x2\n" /* offset rbp */ - "\t.byte 0xd\n\t.uleb128 0x6\n" /* def_cfa_register rbp */ - "\t.byte 0x83\n\t.uleb128 0x3\n" /* offset rbx */ -#else - "\t.byte 0xe\n\t.uleb128 8\n" /* def_cfa_offset */ - "\t.byte 0x85\n\t.uleb128 0x2\n" /* offset ebp */ - "\t.byte 0xd\n\t.uleb128 0x5\n" /* def_cfa_register ebp */ - "\t.byte 0x83\n\t.uleb128 0x3\n" /* offset ebx */ -#endif - "\t.align " SZPTR "\n" - ".LEFDE3:\n\n", (int)ctx->codesz - fcofs); -#endif -#endif - break; -#if !LJ_NO_UNWIND - /* Mental note: never let Apple design an assembler. - ** Or a linker. Or a plastic case. But I digress. - */ - case BUILD_machasm: { -#if LJ_HASFFI - int fcsize = 0; -#endif - int i; - fprintf(ctx->fp, "\t.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support\n"); - fprintf(ctx->fp, - "EH_frame1:\n" - "\t.set L$set$x,LECIEX-LSCIEX\n" - "\t.long L$set$x\n" - "LSCIEX:\n" - "\t.long 0\n" - "\t.byte 0x1\n" - "\t.ascii \"zPR\\0\"\n" - "\t.byte 0x1\n" - "\t.byte 128-" SZPTR "\n" - "\t.byte " REG_RA "\n" - "\t.byte 6\n" /* augmentation length */ - "\t.byte 0x9b\n" /* indirect|pcrel|sdata4 */ -#if LJ_64 - "\t.long _lj_err_unwind_dwarf+4@GOTPCREL\n" - "\t.byte 0x1b\n" /* pcrel|sdata4 */ - "\t.byte 0xc\n\t.byte " REG_SP "\n\t.byte " SZPTR "\n" -#else - "\t.long L_lj_err_unwind_dwarf$non_lazy_ptr-.\n" - "\t.byte 0x1b\n" /* pcrel|sdata4 */ - "\t.byte 0xc\n\t.byte 0x5\n\t.byte 0x4\n" /* esp=5 on 32 bit MACH-O. */ -#endif - "\t.byte 0x80+" REG_RA "\n\t.byte 0x1\n" - "\t.align " BSZPTR "\n" - "LECIEX:\n\n"); - for (i = 0; i < ctx->nsym; i++) { - const char *name = ctx->sym[i].name; - int32_t size = ctx->sym[i+1].ofs - ctx->sym[i].ofs; - if (size == 0) continue; -#if LJ_HASFFI - if (!strcmp(name, "_lj_vm_ffi_call")) { fcsize = size; continue; } -#endif - fprintf(ctx->fp, - "%s.eh:\n" - "LSFDE%d:\n" - "\t.set L$set$%d,LEFDE%d-LASFDE%d\n" - "\t.long L$set$%d\n" - "LASFDE%d:\n" - "\t.long LASFDE%d-EH_frame1\n" - "\t.long %s-.\n" - "\t.long %d\n" - "\t.byte 0\n" /* augmentation length */ - "\t.byte 0xe\n\t.byte %d\n" /* def_cfa_offset */ -#if LJ_64 - "\t.byte 0x86\n\t.byte 0x2\n" /* offset rbp */ - "\t.byte 0x83\n\t.byte 0x3\n" /* offset rbx */ - "\t.byte 0x8f\n\t.byte 0x4\n" /* offset r15 */ - "\t.byte 0x8e\n\t.byte 0x5\n" /* offset r14 */ -#else - "\t.byte 0x84\n\t.byte 0x2\n" /* offset ebp (4 for MACH-O)*/ - "\t.byte 0x87\n\t.byte 0x3\n" /* offset edi */ - "\t.byte 0x86\n\t.byte 0x4\n" /* offset esi */ - "\t.byte 0x83\n\t.byte 0x5\n" /* offset ebx */ -#endif - "\t.align " BSZPTR "\n" - "LEFDE%d:\n\n", - name, i, i, i, i, i, i, i, name, size, CFRAME_SIZE, i); - } -#if LJ_HASFFI - if (fcsize) { - fprintf(ctx->fp, - "EH_frame2:\n" - "\t.set L$set$y,LECIEY-LSCIEY\n" - "\t.long L$set$y\n" - "LSCIEY:\n" - "\t.long 0\n" - "\t.byte 0x1\n" - "\t.ascii \"zR\\0\"\n" - "\t.byte 0x1\n" - "\t.byte 128-" SZPTR "\n" - "\t.byte " REG_RA "\n" - "\t.byte 1\n" /* augmentation length */ -#if LJ_64 - "\t.byte 0x1b\n" /* pcrel|sdata4 */ - "\t.byte 0xc\n\t.byte " REG_SP "\n\t.byte " SZPTR "\n" -#else - "\t.byte 0x1b\n" /* pcrel|sdata4 */ - "\t.byte 0xc\n\t.byte 0x5\n\t.byte 0x4\n" /* esp=5 on 32 bit MACH. */ -#endif - "\t.byte 0x80+" REG_RA "\n\t.byte 0x1\n" - "\t.align " BSZPTR "\n" - "LECIEY:\n\n"); - fprintf(ctx->fp, - "_lj_vm_ffi_call.eh:\n" - "LSFDEY:\n" - "\t.set L$set$yy,LEFDEY-LASFDEY\n" - "\t.long L$set$yy\n" - "LASFDEY:\n" - "\t.long LASFDEY-EH_frame2\n" - "\t.long _lj_vm_ffi_call-.\n" - "\t.long %d\n" - "\t.byte 0\n" /* augmentation length */ -#if LJ_64 - "\t.byte 0xe\n\t.byte 16\n" /* def_cfa_offset */ - "\t.byte 0x86\n\t.byte 0x2\n" /* offset rbp */ - "\t.byte 0xd\n\t.byte 0x6\n" /* def_cfa_register rbp */ - "\t.byte 0x83\n\t.byte 0x3\n" /* offset rbx */ -#else - "\t.byte 0xe\n\t.byte 8\n" /* def_cfa_offset */ - "\t.byte 0x84\n\t.byte 0x2\n" /* offset ebp (4 for MACH-O)*/ - "\t.byte 0xd\n\t.byte 0x4\n" /* def_cfa_register ebp */ - "\t.byte 0x83\n\t.byte 0x3\n" /* offset ebx */ -#endif - "\t.align " BSZPTR "\n" - "LEFDEY:\n\n", fcsize); - } -#endif -#if !LJ_64 - fprintf(ctx->fp, - "\t.non_lazy_symbol_pointer\n" - "L_lj_err_unwind_dwarf$non_lazy_ptr:\n" - ".indirect_symbol _lj_err_unwind_dwarf\n" - ".long 0\n\n"); - fprintf(ctx->fp, "\t.section __IMPORT,__jump_table,symbol_stubs,pure_instructions+self_modifying_code,5\n"); - { - const char *const *xn; - for (xn = ctx->extnames; *xn; xn++) - if (strncmp(*xn, LABEL_PREFIX, sizeof(LABEL_PREFIX)-1)) - fprintf(ctx->fp, "L_%s$stub:\n\t.indirect_symbol _%s\n\t.ascii \"\\364\\364\\364\\364\\364\"\n", *xn, *xn); - } -#endif - fprintf(ctx->fp, ".subsections_via_symbols\n"); - } - break; -#endif - default: /* Difficult for other modes. */ - break; - } -} - diff --git a/lib/LuaJIT/src/xb1build.bat b/lib/LuaJIT/src/xb1build.bat deleted file mode 100644 index 847e84a..0000000 --- a/lib/LuaJIT/src/xb1build.bat +++ /dev/null @@ -1,101 +0,0 @@ -@rem Script to build LuaJIT with the Xbox One SDK. -@rem Donated to the public domain. -@rem -@rem Open a "Visual Studio .NET Command Prompt" (64 bit host compiler) -@rem Then cd to this directory and run this script. - -@if not defined INCLUDE goto :FAIL -@if not defined DurangoXDK goto :FAIL - -@setlocal -@echo ---- Host compiler ---- -@set LJCOMPILE=cl /nologo /c /MD /O2 /W3 /D_CRT_SECURE_NO_DEPRECATE /DLUAJIT_ENABLE_GC64 -@set LJLINK=link /nologo -@set LJMT=mt /nologo -@set DASMDIR=..\dynasm -@set DASM=%DASMDIR%\dynasm.lua -@set ALL_LIB=lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c - -%LJCOMPILE% host\minilua.c -@if errorlevel 1 goto :BAD -%LJLINK% /out:minilua.exe minilua.obj -@if errorlevel 1 goto :BAD -if exist minilua.exe.manifest^ - %LJMT% -manifest minilua.exe.manifest -outputresource:minilua.exe - -@rem Error out for 64 bit host compiler -@minilua -@if not errorlevel 8 goto :FAIL - -@set DASMFLAGS=-D WIN -D FFI -D P64 -minilua %DASM% -LN %DASMFLAGS% -o host\buildvm_arch.h vm_x64.dasc -@if errorlevel 1 goto :BAD - -%LJCOMPILE% /I "." /I %DASMDIR% /D_DURANGO host\buildvm*.c -@if errorlevel 1 goto :BAD -%LJLINK% /out:buildvm.exe buildvm*.obj -@if errorlevel 1 goto :BAD -if exist buildvm.exe.manifest^ - %LJMT% -manifest buildvm.exe.manifest -outputresource:buildvm.exe - -buildvm -m peobj -o lj_vm.obj -@if errorlevel 1 goto :BAD -buildvm -m bcdef -o lj_bcdef.h %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m ffdef -o lj_ffdef.h %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m libdef -o lj_libdef.h %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m recdef -o lj_recdef.h %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m vmdef -o jit\vmdef.lua %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m folddef -o lj_folddef.h lj_opt_fold.c -@if errorlevel 1 goto :BAD - -@echo ---- Cross compiler ---- - -@set CWD=%cd% -@call "%DurangoXDK%\xdk\DurangoVars.cmd" XDK -@cd /D "%CWD%" -@shift - -@set LJCOMPILE="cl" /nologo /c /W3 /GF /Gm- /GR- /GS- /Gy /openmp- /D_CRT_SECURE_NO_DEPRECATE /D_LIB /D_UNICODE /D_DURANGO -@set LJLIB="lib" /nologo - -@if "%1"=="debug" ( - @shift - @set LJCOMPILE=%LJCOMPILE% /Zi /MDd /Od - @set LJLINK=%LJLINK% /debug -) else ( - @set LJCOMPILE=%LJCOMPILE% /MD /O2 /DNDEBUG -) - -@if "%1"=="amalg" goto :AMALG -%LJCOMPILE% /DLUA_BUILD_AS_DLL lj_*.c lib_*.c -@if errorlevel 1 goto :BAD -%LJLIB% /OUT:luajit.lib lj_*.obj lib_*.obj -@if errorlevel 1 goto :BAD -@goto :NOAMALG -:AMALG -%LJCOMPILE% /DLUA_BUILD_AS_DLL ljamalg.c -@if errorlevel 1 goto :BAD -%LJLIB% /OUT:luajit.lib ljamalg.obj lj_vm.obj -@if errorlevel 1 goto :BAD -:NOAMALG - -@del *.obj *.manifest minilua.exe buildvm.exe -@echo. -@echo === Successfully built LuaJIT for Xbox One === - -@goto :END -:BAD -@echo. -@echo ******************************************************* -@echo *** Build FAILED -- Please check the error messages *** -@echo ******************************************************* -@goto :END -:FAIL -@echo To run this script you must open a "Visual Studio .NET Command Prompt" -@echo (64 bit host compiler). The Xbox One SDK must be installed, too. -:END diff --git a/lib/LuaJIT/src/xedkbuild.bat b/lib/LuaJIT/src/xedkbuild.bat deleted file mode 100644 index 240ec87..0000000 --- a/lib/LuaJIT/src/xedkbuild.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem Script to build LuaJIT with the Xbox 360 SDK. -@rem Donated to the public domain. -@rem -@rem Open a "Visual Studio .NET Command Prompt" (32 bit host compiler) -@rem Then cd to this directory and run this script. - -@if not defined INCLUDE goto :FAIL -@if not defined XEDK goto :FAIL - -@setlocal -@rem ---- Host compiler ---- -@set LJCOMPILE=cl /nologo /c /MD /O2 /W3 /D_CRT_SECURE_NO_DEPRECATE -@set LJLINK=link /nologo -@set LJMT=mt /nologo -@set DASMDIR=..\dynasm -@set DASM=%DASMDIR%\dynasm.lua -@set ALL_LIB=lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c - -%LJCOMPILE% host\minilua.c -@if errorlevel 1 goto :BAD -%LJLINK% /out:minilua.exe minilua.obj -@if errorlevel 1 goto :BAD -if exist minilua.exe.manifest^ - %LJMT% -manifest minilua.exe.manifest -outputresource:minilua.exe - -@rem Error out for 64 bit host compiler -@minilua -@if errorlevel 8 goto :FAIL - -@set DASMFLAGS=-D GPR64 -D FRAME32 -D PPE -D SQRT -D DUALNUM -minilua %DASM% -LN %DASMFLAGS% -o host\buildvm_arch.h vm_ppc.dasc -@if errorlevel 1 goto :BAD - -%LJCOMPILE% /I "." /I %DASMDIR% /D_XBOX_VER=200 /DLUAJIT_TARGET=LUAJIT_ARCH_PPC host\buildvm*.c -@if errorlevel 1 goto :BAD -%LJLINK% /out:buildvm.exe buildvm*.obj -@if errorlevel 1 goto :BAD -if exist buildvm.exe.manifest^ - %LJMT% -manifest buildvm.exe.manifest -outputresource:buildvm.exe - -buildvm -m peobj -o lj_vm.obj -@if errorlevel 1 goto :BAD -buildvm -m bcdef -o lj_bcdef.h %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m ffdef -o lj_ffdef.h %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m libdef -o lj_libdef.h %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m recdef -o lj_recdef.h %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m vmdef -o jit\vmdef.lua %ALL_LIB% -@if errorlevel 1 goto :BAD -buildvm -m folddef -o lj_folddef.h lj_opt_fold.c -@if errorlevel 1 goto :BAD - -@rem ---- Cross compiler ---- -@set LJCOMPILE="%XEDK%\bin\win32\cl" /nologo /c /MT /O2 /W3 /GF /Gm- /GR- /GS- /Gy /openmp- /D_CRT_SECURE_NO_DEPRECATE /DNDEBUG /D_XBOX /D_LIB /DLUAJIT_USE_SYSMALLOC -@set LJLIB="%XEDK%\bin\win32\lib" /nologo -@set "INCLUDE=%XEDK%\include\xbox" - -@if "%1" neq "debug" goto :NODEBUG -@shift -@set "LJCOMPILE=%LJCOMPILE% /Zi" -:NODEBUG -@if "%1"=="amalg" goto :AMALG -%LJCOMPILE% /DLUA_BUILD_AS_DLL lj_*.c lib_*.c -@if errorlevel 1 goto :BAD -%LJLIB% /OUT:luajit20.lib lj_*.obj lib_*.obj -@if errorlevel 1 goto :BAD -@goto :NOAMALG -:AMALG -%LJCOMPILE% /DLUA_BUILD_AS_DLL ljamalg.c -@if errorlevel 1 goto :BAD -%LJLIB% /OUT:luajit20.lib ljamalg.obj lj_vm.obj -@if errorlevel 1 goto :BAD -:NOAMALG - -@del *.obj *.manifest minilua.exe buildvm.exe -@echo. -@echo === Successfully built LuaJIT for Xbox 360 === - -@goto :END -:BAD -@echo. -@echo ******************************************************* -@echo *** Build FAILED -- Please check the error messages *** -@echo ******************************************************* -@goto :END -:FAIL -@echo To run this script you must open a "Visual Studio .NET Command Prompt" -@echo (32 bit host compiler). The Xbox 360 SDK must be installed, too. -:END diff --git a/lib/libSOIL.a b/lib/libSOIL.a deleted file mode 100644 index 45ae424e4a41221574ec0457a2f18b116867cd73..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 121960 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 KtHQ4z|9=6r@Uw&f diff --git a/lib/libentityx.a b/lib/libentityx.a deleted file mode 100644 index b0042ebac14f9c8db8e52914bcce6f7fdb3faa15..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 945228 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 E_cB?JC-K| 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 z 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

p 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

Mynps_vRGKZ&uK zY5l%CFa}Z}jw;H{?ut1e_gNJa@mjRKVzF;~MGK5IR+LbL?h5G&9Jj3{JhQvfPXhR( zbnD4Q@D8s~qi2QBNv?wm28m#@XEF*I8~e5@3M1#0b;1~|ZeNq9f~fZosdoz9vKi2i zQ#(06*dm$CiT~it$Js_Zlfkc`Zvc~GfyA;ub#f9L64-Xg1$o9mqvlQU{vEp*)!{%ZW55|e#A`^Uw z6*Kzru%@_0K75}X@qTad3g_Ye;??ru$BOlX#rMhk&r6)|4;Mcq@4qZ}-XAO8DDRt0 zx!pBKZeMSa+qYK8?fa|c_T&5H_H)I6?%?z0;vE8S;?3?veme&?=UV11DLJQc9L#kV z%?lSTn7^p0=$u9$jk*=VdFc^`2uxw<^Ezo}9}3qJ%$fk9Qhv=uXS8&;DgbgS^4fVxzH#d~sdKKV?6d zy8&34^E!)v3J>s^GUK`tS_%4n56{C(b1Ozmm_mvNE9<&4WlM8R8kM46+R z&I=TeuRxVezrMk^R_R=wvXv}$m#5{|X1|)zR5C0+GtbGA1+u}zj z?KPaU{M0L2hTm72Ul7gy3d~kljJ^@}n~7mSD%X!xys9`sye9nVI5C;`aXe#oAY+^$ zC)9$=bBfoE%nu@$oWUsh3&$5`uf-vZK%A(l9-V!K`+Yi(l1zU_bclRKlnd88{7a{q z$R}kJd27}1pd(*xc4tQUz>HyCpm@DCO!GpT-IF7{DwzIacU$r5JE8vX@e=z!V6!R3 z3--R7#4F!%rT#4ltic7&FNw`La5H{|Px3nL$=$ zayK(6kELKSQ}N?S*qaVj`K8OAR+}nE z5|3so9+mxa$a^hHWJY;&%Chrww{3s!`JKNDB4E)GtA?)`mhj(`^Nnog-Lce};-VhI zDGS*h$h^~8?{JE2vii=BsUtJWK{RJZew#nrgwUw=q|UGmi48-Ukrf!JJkni1M$o$B;xB--6QQCu#m!ObB&j@dAMJV zAL;8=oJ#uzY@WikO~|wG&TA2V;;*8Y_DjAnTnbe0ywQvz=}VPS%>wo9PK5^)u5P}B z!s`_vZ5FWaE4)zKiCNqvF)PZjP{g6Q)BA5(ariU29g;*$9!ou3sXw@l}+ z@jSElo0S^f%C z*>ck#90GrT2s|4+GVwWS2)uX*oSR@X@d*xrUp@prcLTAF|?b6FP7@?=-dr;wtx5lQ11$F8?RR^uRVP50>#ubW&++ds@pBCY`Io=z1 z$SWV_H8$#lT=7Pu^>tL4@DsU0aS~pf_G4Zc%90x*VI{|k)+Kc}$=RfeyskO2NCF}f z&AS01nAad43b3@bNxnAGVPw&~CAZKYd80Awd8s$@T-=;`oxiAg{)$voC>J*&z*@{Y zI-qbVVBUiHH!gBHfh3WJaGlup*TUlX)TQD1i{`u72vv&7QYeNNq~fA(A*}Mx$4AE; z@RGqt7+l0xb&df|216ZHcf))b{l^PDPag?@cb+1E18bRxgTF3oCXha4KvCQfX|7wi zcuCVml3(PUg7oRR&bbBpfCKrc&%cGga+)pwluxOX5QGr zAm-oY`d1fzz6<}Q3uhCg>AxoRDBBdwzPs=rDV$yNi(L4lL(o6#qAzvPA8^sLiPQet zL(sF{=Rdmwwg|coPRq zir$^>=4ol%Ezh@IxI6#UsQ#x87wv2CIz{!X`O2=Mmh)T}&Lmx@=%=X;6Xh>;(Z9*c z0+;5$SJ9uvNXJEbcmAL5!r8Ud{=VYE-SmG@{a7!bOD`n%S(edzIhg|%1r{hnCz!fa%%cT7v-$BTi7cu_EsQN{Z05o2x@H`UZ()d_~t74tP zixfV_Ay47O3NQ5FB??!?B}G48;YA+$QiT_L@J5A~c<_JA~kH`Wg>DSK+lDyk6lmJ-Cja zIUc-4(a-hZI)3UsxQ?Gj4<1&0T0Hm)g)i{nw=2BWgSRO>?7?FSU*W-5EBtm3zDD6~ z9=ucGF%SMe7f|6^?c7r7xJRY?8V`QI;-k9qL1c@D7AgYQs$Hhb`}qVM$JJ&OJ*5B{RU zcX;qU3V+Un?^Sq@2j8#o7d`kvh41m;NrmtA;BP5>zX$JA_(2c;zQU6pykFsOdGMnO z@AKed92?mC9(;_-C;c9LBbBeXjyktgzRgql2Pz}EbbVEzaK8s1qwri0UZ`*yyyB(# zj8!=GXKuVm;bS~_vBC>Ic!|QjXF`ovc#(&`RN=)Qe4@fjJb1anxjx=4=VXPKdT`xd zO!VL(MPKg0O@&YP;JUpCc<@?9AM)Tc6>fU)ISQ}w;BysT>%r?4KGTCYDtwLyZ&CPM z557R*^&Y%c;f)?Vtnd~OzCz)8u2biq+ZEpGp>I=o*n`IuuJuHk&uWF=?xA0!@HP*= zR^c%Zey_q;d+_@dzQ%*!ukf`Ve4WDY_23UG{5}uUxY&ndjqgZC)>DG&al!gqM^Jqmx$gYQ*% zj|bnc@E1M!L51(};7Nt=_26$Qe7^_pQ}{s-{=UMK9=u=SZ+Y;e3h(paC!FBaQ}285 zgc{HHd+@I*{HOCXZACxcLqA&4mwIqR;oQf@OY=EN z;oQsT#&vind+<{geZYhNRml_b;Abm((}U}HuJPa(D0;2u;Aj4>RQzXp=<81sv3+wq z_=8GsGS`E*DEfL2{@@sgPooEKRrD<${4vF!^Afyx<8O}Q)9S%*SA4XdL(?Y}zQRj? zI=T9Mw|j6);cXuLK843T_`fTBwFiGp;cGm2m%`V2@SO_3*Mlb&exC;)bA}`T{T_UR z!q<85kisAI;I-#Dd>-=PF@->-W@!$!C@Acq43g7R+%hY`BK@VP{@T3PH zukg1#c&WnsJoxnrf8T?bE4<%>PgeL*4<1mso^a)7{z3}(E4{bIO@-%r@EV2ZdGMPQ zuGdFtJ~I_Q#zTLr!V5k4T!oMI;9-RqdGIeO+(~_BxgJ&K6BMADRUex};!52o>+(pV z@ep5d6*{*Rez|%t^58SoyUJcE`q>IE_0V6d-pf7s_3Ay~!Ryt#>A@S+d#wj=R_}8> z_7`y}j)2b^Z&e?(JR0v*cv#&vzK##LRy(&8A6>t^=)v{67Vo%N zuWRvp`ZJwsUc~g^di}~=53bj*w0dy8e#P6*)azILDjYgodfmx*53bjjw0dy8Uc_4; z>UAgH`a!QF@s=08KBnB0|MmKkMh~vnm&81{UVqc$!8=tsD)u`GqrvcSHJh)zGv&Mt#^(z}axL&_fq|#sW*XvgT9$c>{_Lbt zNgD9r1z&LhQ!%ERiT>m&I$b}Wt8kT#)K|=}dHmHMRI$^qL!K@DN!@c=h&(S!adaNE z`^6qy`>*d5lh4dQ?rV>dzt|HnmHkts0X$`jzd3ad$sX0uW&ANJz43PyF#7ND2F5A? z;?ni4^XBsv=?8V6fqN$ZOP4qV-FP1 z&a}Z%p=XIHC}aI}nEu2@W7vK))_*PAOvF}qV$4RY$m9vsrz81bVf}H|OzP;SEqyQm zk)%&G)*jtR(DqG#j)TA$Dd=V|`9dVrmx5 z0KgVjF#4BH7{B^*uQ;RI$o`b z;|oq%?%;`VupsqPX!X3|L3oi>ofunC8G{9vlldjSJlAaB-UqhU&DbOh!!~C8i)OSN zTeA6V-CRgJe=x3&tSv8?Oa%ufhFq!E7zWg8~5TTYDY}| zz_`nRf5!T)Y16Jjm`bRDVTL@=F@otD?}*x5iCWFd?!`ty5*X{R#uoE!**Faek;>!J zvEdR%Do->mrbbnvO-nv77@9?DP>wXMg6e2hVXkacX2h9^seRGgj($XH7#2ae<5TdWN&4Fb=4A94X)<14$Hh!$u24-MeJpYFhTI>2cF zk`+}PzbVnYO&|+)5$6`Ss+hK)!(tumG-VNR8No=~h7k_1M%*ufQ0DazOMOlzK}Omp zMk4gyS<)9VJ0$M#Bipq_E+-;6qR5OdE42Rt53vWGXrMZ0d4ctcnOIR&Z7nZk%G4n8 z%1z`nOK3m`!{1}MW_JaotD>Dyr z4P4QIP?OLu0&8WP!g^Ef^@YjA!ua%lo7St5NU%?EdvPg_DPLXXk5^2#a9GIn$@ba! zNEv>F1cp!8F^%+qX@`Jsmi2qNtZo@@VZU&cr$B9U z8Ilm&VK|Td_o|8#yQET2!8phBvifTfXE{%0U)ipdH)73tAGe+lz&jin?tF>fR7gXg z`phYpk2q^*7R-~C?V?xD(GurJV$_1Dp5HX^-`t(A%A27`7)VJ>*~VPSBfX6lA`y254WiJ9Gx zBE#aeZ9RnteJ(!T(6h-{b zgmg&L7sb2^g-Ho=E(8(pmz{)jMt$4bMq*5qPT<#`>uRd!UTdt^HvIq@P}MATHCF^fl_6hU?Nyb0WIp&iSBCwyV-$JT ztylT7Rup8Nnl~bMEjoHNz{jd@4>QLPx#vvw!d;gCXm(CcPR2c4*bV8EeVhvvKUq#E z`xdc>P4+m>lO2E9z9>4Mdlg*+@9;N~U6Wt9hWlMtalc`77&fRy2JaM=^{3A%cN{3(@$I__{~%p$5+mtGuh*aO`1{v&904dq-|5QqO(I-*JP(@v$0jp*$CiN0#bem3J+0*RV>lngb*Bg<# z*s))3D0eU{ zZ<+Qiv7B*liN2&v;iVWqrla@bQqfE}ho+fu4*3e$i}YM9Lz!@noipLL4}q^40)Jo# z{O82+^IjahWWu)$f$t=qAzXh1E_-!YH{p^x1@~V3GV$kHB+~aOdZ}B0@wh7D^(u*_ z?f}k%sx$E^QuIYCYpE$TUn%J`$a#sP$KXybsY~#5*%0*98E4|tqWEZCw61TsH;?jn zD*jUEfIqGLW#Yqw{YYOVLlB=&&lUVc;cW`nbjXpg^OKKW+oo~WJ;V!C z!I1g}Zn(#Sc&);v&H?@b@J#W{5m6@jxg&*2hX&XF9S5pg(sbker8E;$S589c;8owKP$*M6u4m1n$9! zMiHeIg%A>;h9o94fUiU+0q>5}vTbeM-R@KS;?~`Dw|=^PC{l|FC;?k5LRHjS(6*W( zDrgk~B6+^w>zp%la+7K8_St=YfBeoTnft!K_jRsw&ULQya-Wy$G&D4~b|l(mV~@OU zZ$whF#I1-L9`W0ZU1FMr>=3JOkqF6trS_}`d8Lzs3%544B$h9N+~8N!#tom=Hj{FO zEM7s(x9}>vlk{WuHTQMtNWio8B%Wo5nH@*S!H^39o?F{nmNgFp!AQipyp6Dq;|kHl zxmq7t^jNFo15BJA0+sPOj=veaRnxN?U>$DoCp1nzEJ_CFNw9RJr=A*|<%^E^N%%MT zw=A6Fmj=I6*9~5JGbc=(0||zHpGD8M!{8rSxXnLY2qHN0IR*cQ{$DKoR15#Dh1>Bz zn+)K1vE_EPg?|+94FBa8&Y?PkKWO3H_H6J?7S8d1gAZz)$zz*q@KRkb^R*ox9y&lr z+~#wsh1>C5Vc|CY{T9x;+=Tld7H-SuQ46=_f03?#8K0oV=SB-Z)51F~oOQVg_iYP5 z+rlU4dYSxf`fKyxO%`tR*=gZ6p8{Pkd-+ed@Sqi+n=HJ{!XLA6j&GWDWh{J>g%{|q z7{i@x;kXq?ec*pHf8a<*XYgqn*X*-6KlSOxt4kL5YuvOshL2f0XTFCF{##w1soQi0 zKUbHZprAQiKW67n4E@78;`e#zO@CyE2RHqZ@j86NC#dy<{SZ2Xhcq7X;HJMY&x7}9 z`YsP{`UMYraMLe%+=H8b!EO(3`UT!KhNfR25x3%R`UU@Y=SaCP8OGv#lUrKjjgx0x zKKHX7@p^2XR+FcVOBXcJw44a?Z~O_uKSiL$n&lSKccVO?97g{PVZOOghm{Q6Zmn_tan9^8ZKBJ~0D$SXh2WitFqO=m7~9lp*60}Cx5O#H90 z?z2R=S@R*~f1~#AP5<56zvFpf;%~xg!p%tO-=@=Frz1-JVf$+Q8~qtc_T;@of8HVL!OTYfrMbwe z^UY-Bho6fKS;`TTsD#ibInh{lzFJIW|C}+yV0n2zDPpNhiOVLYR`v%@elONzPqp#ymJgFhy+U}wF zDd`zQ$-$z)ns4Dc{h-tPT&% zc#Jog>zj%s!h-j=9X!L@Kj&;>sYXl;?vEz7`kmDBk|<_gG0*n<@WIDN!)EQF-O0V9 zF%gRsjxdknZce_6^UA8AJyFibCifntBBaL`!rPP{r@A+A*F?Uoo(J2|({TrLw574s zb(K!_og$4muD>TM_ttU; z8gw@3f-!eNC5N{WlUYGNN4HZS*@9dx-$L)Y{u0u9lSCXM&=5;uIFy`({JEQ$Q&aQpQSN)EEvrKBa&p7ER z&(hPby>9Qo-|4Y`WK2*F+|i+n7CO+;q$G;sSz7!LvP~VALrJlJLJ{|Wt%SYl_Jd`kd+2b+_u!p1b+s-fm5;XBj{u{h_Ssq- z^FOKJBa7fuDseeCSk2K#+)p_?4q<{!*k#kBsy)W}I!xZ-RN>4<90QVzubzQYbFR*v z#}0rpu$K18o#e4o18eWWGtLB)iC_7i{zZ_8yKPthgM~Px6b~`XkJh?7qSgBXNe=CC zX+t;qJ(1LPH~{RWKsWbTL$6Al>L&up31pp`6Lc#2CH8=mzb4T@w3fs2fBjyl~_CQ8di0@<0PNNg~w3FDvPn)<8j>e$T>$l+4y;)eW za%?p?ulRTr0uFR7gZ}V%%j{&f=#j+h3LL`t+8`oV!}AW>Ko~=s*L)39QUd4?ti@a} zR!<g%p=@@?uWRBSsFzmK7ky(~R#5)U%0z9`VO-+KAhK)u9QX4W@575i|a zA@cgj8G$tqi*TMtJ%PFxXXYiJ#uOq7kb4Iz+qWc}Tr7QQ!<%73Qv9L_dpk~h!$=oa z$i%8QuN-hvHx)bn=VH}cSL|`pGq*c^y^lbU4`!Prl(R=1|J%`YUC^n1CUDnR8H4nd z!5GeejpF>{o@hE;5d@|}`vIG>iYIE*r(=;!Ka6}Qm1L+$+W=jMg&{N0 z21lxkLzKHzr$N{$$FZ`hq_m}d;o?v6l^aIEo{lv@BHWn!gE|N*=6-`jM$Uac_DW^x zPxaQ72bhg93fx8JI_|HXWPS0mSjASQNd71l$;ELYZ=*wjbz;)E1lHal>AHH%XiRmd zr|gnm!>(7mpAU4;hXRZ_;$rguotQflP4;y3-RerBZd+;QYzBcfB9Id5*BR1o;41A% z%!TpyWVG0yX@x%J%CqAhh~fYhG)d7zFQFuM-HNna!j>tpW+7vd`Zk-UD9*Thl+BaW zrq@E%a7si~&p=_Vf2Wh0jWj&%Bws)3RP2vc@97Az5$L)S#W;$J!rc)=W0GnwM-ovh z_p(-g5=-3Tqn+yKVu6~ssDnR4EgBoMKhSj}I`g&cyzo4wD9!_jxqHw;4Vf7 z<3J&N1%YLp>ZezXV%VJWZ%2)LF!4JH2{+H8{ta|Jgh8H|OTBffj|A5I6CP2x(K)F@ z=LFgExYRXR*&?SlUy07iPIgY}rlKm?>C~EzK7K@ z+pD)~(-SLV6;HC5M_rWLihZ$a9N?0Kwm8+dq9b^x)Z8nJLkG7OB)&i`bKgewSQ<_K z{^&4mUky#gQ3fa{TX7~T1PslFR=1VJ{Ci^l7x4n8B z5jKv2wQoUru;^oia&t1m$d;RHkj$$P!c{0Y?WLJ|2*Su;>@lLp^UkhUtG1`7o$MYt z^x~K!lXmS)LRe5Q%zdfl$q4m}s1BrMswt#bJUO!rVPa)q zIPmBe=RPO(%`FT$mYNRH?ufFJU(r7hH1!&nl_g(Ap+h!r?idwCiKDI^L94<(AIse> z(EB0wt607ks`3@1+NbRD^@n)faph|itBPu@d<}HXkXnPs|K>_q{a+|yXlGHvZieQ~ zPRCCep@iMaK8)&DCbt!4_K5U5DL)Y~4*uM=H!^8kpzHR*p&?{-4^IJ7@(|%S0cJIa zx~Qrrvs%iGmcKh#>;5wHfMg%?Gv@YYTI9jJ-zV*($$bbc`6LSFH4t(&E1L)^$4Khq z=;A4k?8FSoa*8z=O>1xZH6yx@+Dxj3lvN)&8#NzgTkNzHXD z_;r+KzK)2heox^Xyg@bK&Otl(Br^S~;>;>6d^P!rTBvtlv7EOGx$)Fk7NCDbAc0@( zblgMf*`ral@7nLUhm)_MgQU*icAt->$3I0q+4XvA4!$d#srW)ErzCL=^4fhQ(7hD| zV~#}qFW?~4nA`PBdZ=}s%33#6ivN<#ts+9m3*R3&$XvcZqPyPUiK$WlFH=Ew=;*jd(5)(mpj6Kk*~_*Z{T{aNQFq!@=T1r&;=PNB8nJ%5 zrpT(FJni}~5RR#zP&6|`lF3HDo`C!70re4LGZoUZe6dXUNMK89njnUBY!{@rc|^6{HGAEzT9uR=avRgyUyr+_Ja z<8V(1PUg3el7 zm;En-zbX6c$c<(Hm@fO!?6>W*|6I20zm~7;zZ2-@DvmMl{F$=<)}IiC)K5jMP*4%; zg%ImwBG#u-i~#O>ec()K5Ao>7`S7aehy~%l#&O_*u4fPk7G_ItkX^y*Cn;Ceu0vfQ zQ`NRZsg+!B$Fajort&=xnVx`7tmO6^s1==5Yh|>0Fwn)hIVW`mGAN7=0=@#-6^#qU z73dR=|D{tcnG)z)LCWge(PXW{UCga1mzX(&c>5R>uQU7zd*qLtf&0uVyv5S= z=b=Nn%Jq{_-zc_31T!0;O_Ih3QQsPwM_ExpmCy64@+6Ee9jC|7Nt_oz-u!w=q1|FH zp!$fBH}!a?*5kIE9*=>%mHJA319@+UyjA=+asa``t2DH%vXdQ8Jb?HGWB)@Lw!X(5ycQg`X1W7&eMF>8Bw*vkfjOK$-4Sk44ddLwPxWz10nqb?xJo7@&GA#5s?5f1apJwOJ0M%QF|po zP(YK|-2!hk;JB>bC=3KVjt2lEu)HWnM>TM#(k#>M`~4kG=^zgy>$oMWfZsLZNdBT5;dX+4$VR zw@iY4h9`W|A>6gMduyQkHM|{jz^y?HcHn~$f>A^3U{jj;2fRe&yKv#alUno6K9K3} z0XB91^(-!|^S9_af535H@YMObpYR%v1aw@eQQs`-C*T@n2;HdjIo``UzuzUzqtdZJ z^H%A&tC3-=(F0vxiGwD8OqpR8rmDvpDOYk1OSP=)ih*xt&Wf%)Jxn zdY}2B^+7s#IU&ZXF;MaoNZN60iU+BQ%Ow}Uj!qx|9f-o|K?f@q37CvRd1dmT4L3kn^|wp)EUO3+OfNW`;z)*sdj3o zC`bq@bS*xh4h6c-VLG{;A*=gP*6*Me0H}1|sop5HURNgqi&ozP-Mw9BWeVWhI3C9WrkvqJ{NWV2mQizARC^v{j)3FQC zWIx^UqI1GyLw=ug76(vc=?!We_0Wo2xL@U8{{Uh5cL%z!Vj!uSa;LhcB(R1jfI59O zt6OjiZease447*=Y zpFD3vComNo=$a&KYl1vzwYK6mFmQWg6-Usdmf-Uzj-7~aJBLv8Q3dTnOM&s6Upj6A z`S60{UXSh&Hd(PxkI}cjNQoXyswwyRg1*dFNvo=FoWdG#z8$5W`G?Lzu2^RL&?=}` zd6csyQs*M!*?v0aQLrUyw%t!h6`j7^^wW_Lh|iA>5A%5=!W`PQdD2{8<`|@C)fdp| zG<#YoCO`b^`E!7f{7r+H@MX?NS1ijPr7DP*N$Qm;M9#l5(Z{&zC2y@d9)je39(emf$+g6&|MNUYi4d>`8ilK=ue!A zQh9*0HpxN1a~kSp#0*m~42EB!`x#jEi%wwHE-4QJzTSTxx@-e$F>IZYBiC>2p!0X6<#7PoVB(e*z;Ga|ba{amj8y zVsXh{#L}0!3m$a6g+wB$9G2n$M|vfEGNGty-PfZ@r`X@`$7e*Qjy`hJ1?#xg6215W zU;kad=On;(6_a0rJDSK?8edHA)(0_A{1TD$&0x2^sz=X)Vu}Dd^etAH(Y`wuqJpM# zDh}V-yA%)TMq!(>(>JsDMm%8x$cedY)C9~LMO=XCnVBK>jk5B`h?0X5B`N^&FtH!} z$;(NvS%piqVn;N6cMmFij6#o2V4`Ikzb@UGL6x_6R5EW-rH$29+RUk}(qfz?e7txI z_F{4h=}DPF+Kh4Ef|$Ewpa<<&^w0}oRF<<*Q^wNh*qtOg5#s6T*thvzwn?IV(kecY z6QF|`om2;E@9Wel(Kyf8=XAf6cwJ4yuHzIOz8Xt8KQbvELTA~ai?^xB!o+~+D zP|iim?YYwDxGgL=JmQ`!9LN@f_oeu!mg0|6yk72Yv0|sJZC%N0LjIG zu-PoT6>s`DoL|W^8M6q^l6>1kR5LCs!{PG98JH)mDY~aHU4Zg0`>Gfx%yfubjNkhx zbGSVi{^l8&_Bn<**~>YGkqHY6zwb8(&p8to+UL#{q>(E#j@t=0i*gL&pUxAvVg4Dv za-qt_kGe4xWtOgt*Sxx+^K)Ur@)30d`|;Qr>e9Sq4M|vV|+x|N9Z6VqEFW^=#Y| zH_qS}03e^enw69*U|bt2IKDFJq zH#(cr^lFuo)>~kIujvh)xjv-ngF)QDi5{t2#K)vk16drC-5&P~dDe;byessv@C+DddZF2)wJC0xngp%{S4`RDnXu;O(Qmb1e{RW)};$qLv7%jM#Ip4`ydyf_Co zwKvL!GUbI&9s=xA<9b@P&2Ho!bqlx^tEF`T$m-+ET3aM;7f$glPqZL{zSg$J7Cdpo zoR3@B8hy*#8~MWQj585dJK}P2Til4vWv#MzO-E13ndO;|<;>pO^GQKjw$wXQ4rgne z&#V*C(2Gl0_-Pi-6|{7QkD>pqf{(+0@4-#Dlc5K6hL6Fy7u3ep6V9&o;D-KI3uj$y z;$!w~knUp^{%wn%?+l+_jq};w`=rh@RCMf@82;}w;&7z5<$MbJ8F0jHxxK2Z3X@*e z$8_&#{5U?ksv~aa%Xu0%d`ykCKzEwFd~ULEJ3c!;A;BLP|NR!uTa(^`V2654`dJj)mLdex5>sqZ}wp6Yj@@cz`pwX)%I=DxB|(Yt}c! z_;1>^N4>btr*}QLX{YYC^vdKdNxx&^m(DOXy}d}nK1lPO~So>G>*9d@I$J&T=-JM#4UFV+58ciGN_ zZ?JrOhm3#jIkBAy-&{j@$$PK-&dL+M@n?8mq5W4HKwqo1|G%{NXP)-&@$S3qL&|Tt z_OI1C%cf5I-|KndmEThMD8hdz>r>tIa6=`Wv2DWqXK&B=H~CL_c!B_ey-=T)i?32= zEX(q#`1krJPjBAS=fcnM7w02;1nzmvyZ2|?=am1I>XQBS`sd#B`ot=;_2)0zA*`yr z@ci?FbRT~2PcaLLb|JZ{y+3oEbZaT+=`h^zQ7qg_OyHmfCtu8*(ECmblQZsH{q&Wb zQS6sFCdWO8gkD2mzPVL9H?fl<)EhqwFHTDIU#4vwZV9=BjO0D09-XvQ-cE`iFBm0^ z^mBY&?iKV{MV49vtd2EBj#X6;BaE??xitB8bnYCpkEuA8nk+FgL*Ix4#%4Hnxc|^| z!Y7=XSmr)c@j~)&@#+(>?6G4kb_hBCC#qjuy<6xsRZ&^R?qm;a8p150q&++z%ek$Q zFV1Bk^moPJn0QKIs9Ko?!;mAErodGCEzY|0UCF86k}G z4oRLufS8+jZus6PwJR)n3`2?cA;hrzF1@>d!ZNJY;q=vISYq!KcOLPtz96vv`I_!O zVEV5#5P1>%cW%>(6@z2hsHw~yI6J$>?21ycpQQ;R?(elXNs*F64doy<6)|Qhaz*t2)Sy2)AP>Qskl2HE@@edeM(-!)l4gHDP5c3$sG9?~O%3f*e?q9osjm*m?2f z2-d^6`@?~n=d?XNtTz_>a4J1A6=29WvBQ&nK#cehOE>t1KbTb|Vl)>ixxLCCw|%)u_poXcD|7a$65Lc}JzxQhp|7pRy+Td^3*8cEO2RhaO( zkqg4Y*sUu4RPFE$;RVCho8?Q4jl#IzNXGosWS@x*bX&#Wjxu96eOQVjw0rof*gZ5! zfG855Gi-zhDX6Gf3Z##cMW%BucF$S>@^8LrqLKJ>EI&#ITY-@N1W+}Lb{vj?xEevnvIznpk0np#mTM$xcOPL0<_ zQ`a1bxW}@h1$(SrhhW9;b%&mlNK?8JaZ5v$-NL6-73LtaD6XHwL_^h1RF#Rb0~6LI zH)Bcz!`R8GzQmtQ2r5##HUnk+w1~S;O=&3k97NL87%@n%hqv&2ECE(>vw}zY$0D4Y zA%?7e&~#$|^O%`}a*j&gTI^qaqLZFcdL8PDPD0io;u+*)Xta;V6JFNG5{8-6|-$ zV*;h0%vc1R%O4RP7P_HKzn9Hm%3g~Db06^2q>>o%`6PXZFdrrZ?zgH8#J&i&(MXEy zojkF1C?s6fcqjQ z-JqkGSG_zv?R>4=suEBoA5qjOch}0TsvQ!W&9h=*2(x7Z6GX*!`wN4rjHXrY*Ugnu zC7D4BfvHyH9%qWPjV`7h&yEtL*K2qM|j{~%`3P=L#Z zW!g(7)B3;2*+=E0Y27eB!#w=!z*B6G(lar4!$lCIFz16z@p<%XZhB1s{k-tiXqmDV z`6Yw`YrYL~Nv}yB>&t%tShdqKJUNWQ#0L_G?P5tXW?rf+@<@8AAH~Z;s9q5>QK{`T zx-VJ;!-5;w%z8;U*Q6I0`7>X#%bN*5{0pEe^9R0bl_=P9jF}X(pX0ta$K55#T`^6n z7i~7xeNmoNo;74^it7Zu9)?lpOWm{1lw%=GH=p1ic*F{g?SZZ&**cwtdAs5Lx1RV( zTr`tDu?Q1^SeHmP6bIOL;g%2VSxOIZBR}Us$FkeF7=(&aZ&KB4qSX4%a*j@ zB!I?M%i=y`Au`_D8eCrAa&s`zwxYf{(Wp(7`|84%M`v6VOtjFXRbxZEad8lXdadoj zWi7!5jJ^fqt-)BLJ{Ycx2FnqCZK5L{#E4{2%xS@177S{{8_O$#P4IK!l;EOe@nF2Z z9hSAw%^YER%zO(DpC3_n7xZwBZ#om6vkwXTjWNtV&6rRE1CcYwEsz-s+KOc5P)Az0 z+xR1X3U0wGna^q_2G`D?+`LrI9%K~uAip?##);puKO{ZeH~1s-BVvGx{|&VQ8GsunGh=Y?TGV0v&UUM(j*nrXT}d7!o8Bqm0A0m1qs9l zVIn@5X~S*^{Qp$P=Lecz&zpJTGke0+etzsOFQ) z57__I_Bjh?X2ZQ~9K>BSp(Mh5q4Jts*1$vocd2?s(2KbkN#eB5jzyfPi;+xy?i zOY|E?L1{C!vfwh643vbLaW`h~F~>)laekhTHpS?ulecN?j|7mmH1$f$KQaM!RS~a( zcFeazO4%t`%xW?o^1*;>1O3Lbc1mYZpO6T7Jbv1az4J-XPLb*hs%ro&V0cMe4dehdAAe#9w1yl;goN$EW>Ey@dNuXncpp zr3~Qy^BOnyS)|Uas3Y+?oChBZ-i+ruU9?So@=@R;@i|k|m*^_Ow563A4{H2; z9iNcK7izpo<8^uX^N10~XNRWOL%+TzjhkfyX0Dbydq^MD5s|hMVRYuCdTo@JV^_^MNxy3pIaJ-hF1!yul}yYZoP&nqUI9t-fVhgRg$^ zm(k4^Q+bn@b+p${uAJOf-yWY_Nt?7ZqT37$v>l1&xPd3fW>jSj@}9@L^Z9cDf2Q!~ zLjHW7KU4FY=M}@Z&6xXN)&gs_FqIo`HBTM!#rQ1oHLYx47H{-5wI#3;g1-$o_MjOy za)rEg(U-*pE{*KAwqQ+y@3<8TU@o6GLQmtmO}XIggsFr!u4=^E1SV8H54Rpn@A54r z%wXd;-U|D)UJJi?=BupDVJv}YUC~H$y$wrYau=`L>sR7)Np9mex5+D=jF?DddF$dt zv)5p;Vw<&Ij6^Nq=UQVstOzrYXmS`9jXTtnnATOM4;kWctHLDbS`BD~L}FP>M`OEA zan`1?Fl}pZY}1M&&se--GRUmyATz+WR2iBr#U&kyMNB{bRO~>Xm1ArH16bCAPge<| zy|GCmrG&Ih?&GakIn%g=7K@emkXZEwa@3g+!@?Qkml3dh#Aw=CK3j83PP|J{5GYL? z18YiC# z7XB3rx7UPxOXK9j?IVf{RGtebma4C{2TskC+LW?Eim{67G7cD zGc4SWPo0I^{I9og_5lq477J(DF}OJ!l<_&&!tb}}?Qs9y!ar-#i|H*qlh0%ef7+tA z@mDO|mO~L4!13}q{F``QqH&6weGG%wS@dUH_(BWk`UXR9+sn4&v)ZD!Oi$iin@eCjRS4!6a^ZTg!ne3r%MyB2Q8 z=QkE^^WSUXHva(&k6Qf4=>9n6V268_g0&0a^F~Iup;mT3#kG1~=d7W{-!#&G&drhhuQ_ zJ>KlW&G)!>ZKV0`{*{N`e0THvlP=3&*B4WCJ7{q8eckNA&G&Vu2RGl>k9u(P{cHA6 z82;uvcf6L9!Oi#S-@JxX9gjU39~V`Vr~ZFu4d>mue5qVGeoTR7jv@&e0)3sz!VBl< z@-q(iRK;R~aBTDF&c;7+oehMx%csJi>ihGlOIUKbJ`(4Z;&PrLIseaVG`ZZ@s zS5;qFIaOYN_%)on+0beil4}Tk`IB*Gbg^0|hZ9~yLF|vma*iuXd;7;?)m)EM@K`!n zkUM)6R)$JxIwBn|rZHz69V-^@Dt5TxBDE0ES^~f|7?{J~^aV(#pMi2sjNT6}XMc)` z7aBTTQkq(QZnWa@RA`V3S$dDbz8Nekq}qbw4@Lz_C2m}VQ33h!fYCtL8Mwo?Vk|{L ztjA*OwVbPYVhTpc-|Sp9>f~_Xn@?1|6ocW`QmmR>y)3hpaZqb%uyO?!4RE5dT7(A! z^<1Se2TN2Ya?K5Ra!7)EXX5~V{TP)*$3?xsQkPO$k$@#pIBHof>T;^*mlfZ!2ph;t zV(BTnYq0X_UObdWQ>W@htXRs4MGrWKSC(SAbqB=wDr_03joR3uJ#0;hj@L3+IKe5- zOR{T^^rF|tSjDMmVaNLjc25`+vpf#MWgbIdebd#Et_3OKqG+Vj zv~KQ3mMp#ULK3dm|EL9zSTV%+Sh=GYyd*y;Ok9k$I7+GJP^sQ=pi1uqz9_vTY7;D& zse^5~GL|*PUI&?a?9R;(qWX z-;)Xk{v)@BYmOH4`zmEz7Yi$1GtA;yn#+aYi?KKk#!I17FqIOhIUvMXb~Fh=Z{*?` zy--sY;GP37y@Q3g#sk)U9X9(g}rOd~oti1!OLsR8TXAlSc&LUi2e z*j~mxr_D{l@Z{3tZNR>-?Hf-N}tJ4tl?tqgE(sW?3d`v1D8R2-$Q$3 z332t@(s(6~3Fo1?flC;z71?!PS_4!$Vme{+Ll|y)zzSKf`3qky2^T-ZL}iKxj$2or zRXi0}tPQ@S2>EjolZ7C%$zErzl%ja(>G+g+edW|;-Ee)`$fgomOr@cgKt+TbtD8gw zYMpY*s-0j*1@_ouS(#D=n(l#GMcmL}U+5^zZ47Zj1uFolr-o?YDP8ZRU@tQTc>3T5 zD%!9mkEk!h*KA~w7WtTkr(9yMB$^x?8|XR>iNyLcNvm1K8BWhV=A`G9B#)dKSo<~z z0_$PNDE(QmLRdQvMo#e+#7_bL!1~Lu2oy`y-E9XWC;AE!Z%zAb{30CMFzuYcH+ur> zdmR6k!1}_2krRAN6Q7UL90U@@m_mppDq)a57x+s00_$f8zpz9{yv4V31t~0CLVij@ zYFS|Qi}4=^)}IGMFb5+SAUYpIJ%D&%#UN3+S8o#gy0#~}P#p*E-jDc8QD+@egB7i) zSgw_dM52b$9~#UoLhQ_%v0+kyX%8G?AnF=e^L4O-`oa{O+`Jd){v`Z`xh667Ap11o zR1FpaHo;-3w;^e^3V1H?E5iHR7Gz_bgC2Zs0y#zl~0^Luc zk`jX-DD!B8dU&`1%0qG=R=GXA7c`Yw;-26^pUQgyI-iA}RBa&)E1qwtDB3+c3jD&3bBI<2X8>17_&i$G4&ho-;OSZhQ z@F=y{jgd6y!*(fn>j$u)t_zEi>W|~zOMid?X)i3A_NvVAwUUFwI|-_-$yFSPIo8Pv z2P}P8brh^~%;h=Ut0oR5J`-~f!ML#ygmJJ-^`6^5$ABWk*0GCxL;~P9ocy+DYG{;Z zf4Jhe;pF33viX|uLI+`9tYLtMTt|EVSU6CL{tV8Di23`o9TfIPK!&Xw$k756v}p2) z;z%{r?pA7B^$n#ff5m+vhlJrkA6jDILj%ulddaFRa}|`zzhP}IN|gv5n^A-b;)(i7 z-J-1wyFJn+i&XTu(_us>dx*T0SKVHj)vl^qVJCx9tgaCW79EODlUx92VT=CIcqrRP zU`*s(Rs(9ib+#Wh9<`;WWZJJvm3H1b%9ofQaT{PtJW^Ivn1DQ_kwcX*x71~8jCH=M zN})0cL*aLDMp03GXXVP)!@COsB)#XI`NG9o%xNA{CM9OxU zlS-6qWRD%5k#3=p>U{>HOUqvIGgX}9A4A<%^k7l^7#VKFysm-u==v zO3R(c>K@iobagLn?a!=CRPvEEtT4h>J*#xZY6NsRaWhmyZ`-Nv!@(l!>tOMl+TUV$Q#)mLChLZYYSsEmuN_x6OLjk0cXdQ2;1zQ0P#;*K#@Ko-7md^N$>2@ z)Y<+{wtka+XcB;Qw&ZSDPIB z5zMcJa<@=I`(UxY1{Dv$6s;d$ETLAHzC6iBmu!Vwdh$<|7D~-`BZFN(AMl6+hYAAUTk$ z5+kfySs|Kc1J;(4N8XE{pFHwzVhZz7eJS?MILeal&KL|Qk4}tFF=u{kFp|d}7pXeW z*~l*0uzWWCo4y&ePBxVD!iJIGGs!K;#Otv?LwAG+{zK}qP5g+;%!C)6pPZP>T$p{9 zR8S3J(+=P0PWKr1sA_5@3!)lO*~ zM=Y#_8QDIkVk<{rBz}5}MV9|uF-VI~T#6p&=rkj(hZ9Yyso@O_(MhgGP@h4=$Z9c? z>lnyKQVl+me5lCf8;QjL`)=1?J373<#HWw(p?Pel`ij!{Bf}$t7AM<&L5LDP*<%7L z!DytW55lS?zLBx#CxtU=T={UNK5(n5PJOD6F#=e zfC@2?frf}1)PZP;Zk;ho^(qkC{%aI2K#Fl`yeU!NJPP}kU;t@U2aF{(#GQDn3K2Id#wW;P zznV5Kja#!yF2xi$S1=awW-Nac?Wo1AghwrDSk}_iIzg+!lKS>V^-CI$78GOY7m~c{ z=51N#ZCI!nKU%nL!8J8k&52%dxtP_?pH2V&8<9ZWrCJc3S%HkOPmJ%_?9qAmij@H4 zS~j{*tBb6;GIKv?T3AHiPv8~%OdMP|*F*OoY?rVPW@I~ndVkfz!Whjaj%4ny9NvFO zMsWYkAK9OCmD-;ZwD#w~!Xo2q=BmG}X_Ey7U&5v(*=IEc*a6~jKjx3@J*v}tj|v*F zzX!3$uB^+)>CJGs4=Y=LX3m=HBUBu&m)$g!UxaCd`yziNerm7Xe2sSzm#|>fQT92t zW`mkFZkY*H;=fM&xl8lP#=m|-aR}JM`u$~WO~CW31+fXGY3_TvrwIFt)|`M{PD$)r z3l(&aolrSbHr{17h(QXR%X(MykbIN)79gQ&p3}^MdDBUM=Q2zoxC(eG4~F`=Xm z45^oXE$raeRkLdSO)J8Xh~VH>p8Nw#}NRmNX*wo8>iSd$)d9t=}aJR*HV{-4FFU zDTnZvENGN>)aM@kZZzd9Jh6u^$+RM9Efk~?JI=BXQsxJ>zsnikZ4*ka)cI9XL;yBu zbbh4^kYC!)Xm;shio~mirlA+LI`(i=USkXd+%rY@w(_Bj$>I61U262m{y~KTu zzv8#xa#4h4r7eu#eVRt}0e-2I4{7Xu`V+mb&Bwo7SKhAyId;Cn> zahk>}b;Qop*9$bhP(Mo>f_s*6@@dn!v?Ka{q`iXkG<{H)eQ7IzE!X%CjZ3?bGu^-AU*x0n@-9JrzF%nE ztYMP+9oSPE-#c0nM%2akqQ)yxZ_}Ch^y8lV>pb`ojkjrB>SU$NEJ@X6t3UX_&QB*^o?VJr0>zV)Q_OwX84>)EahjX$h$!~YzO zhqN4|{sF&gjaTYLIA4=ce7-Az`>_%wq@TCx>q5atXYtucC*4h&UOnaZN_A^`gPVNe z^GJI~6|R-ac+%IxZ0d)gwxyxyzvxdyPVg<@gS0&x2p=uKbIe)Db~ya4s-Nc0nl+YI#m z$MfJ-dGHJK;FsjVXXe4L&V$zz7a0wY>`i&_)p_`=$wU9mJoMksgFlo9=Ni$G;`ysQ z_{(|l{yaGQjU(|NgZ|V=`8Y8TJ}D1=ZXW!iJa`T95%T5gJoutKIQNW<#OD^`!?RqT z?#e^Yy(A;?`CcCU;XL@y^WeWEK0<-ynF;d5^u{DD09f9Am-&4WLc2j86s&*Z@m=fTII3pWA#`?*eNym+zXImSTgm9vfaDaZRa4w)KM^6gPCa7^_iz;#^0KI8&?4BR5kI z1MD;nBg!)5M*T|u$gcj}hJM+>FB|%0YrpL3$0iHVDQY3F68b8!08llB0pxb4^9iH< z3y>0wy7LK_rseSk*pS_h!F%irUyM1AJT?NpPSqfnS)#biTehP~6N z&Pil>hq845tv2=pmUVzi+dzmdSh*C&79_I64Gw4%2M{4=O%UhS8xx|;@Jxxq8UjOJ z(f|=R%8Q1j_3aB_pbe8!@%DIY0-D5VWIl2Ype=wQO(%Z&2^nb_gO;>JaZB@3F` z>z9ivBO#0G+uN5lw#(*xJNVXi%v)teloKAe>#Nx+^3!q8s)4eCko9H=)h>TC^(C+4 zt$I#OJ<&*m*0bz{l>nx`1B>C66aZBNX}!cVL$|q7=TI>k^;2dREP(nb6(?)B#sy2- zTWP~UNs%c-s+q{)Z3F8!rki|e;vriNfSSUg4`u;kEB#)r6FI)*b|#KQms1 z?wT)xf3wH)`+NyUyaxXUFVf%f#AjOg=^AGfKg+_+IU1yoTKENd=r6PQ&$j6Av2cEK zn)rOj!ebWx^E~{Yu;}ghU{FOI!+@@Ig9E-kIn;2h3%|j_$D)5u$Je$T&b06acxTde zsf91J@WmEhZ{h!H;dXkrShy|EJsPK;EW-Z>SVBTqkA5;81+o z^me*FuE(RvXR$@!YT=C*zQMwqEc|&3Ut;0=EPSbjAF^;eK1F({(JTMcEPR>8=OPQY z`OmU&oBx+A+@@b*;jF8T+-|XOoBl_6@JB7&&fk|U{6>qvy~p1Uw_*&4;3$V?{Ac51 z;ma-j>lPld@E=>aEeF}320E{tpS0*(EI$6Rcz`3lEr&@KZpZ&J3vY!V6aV`yyv@RY zYT>s2^jf%`u9q#`j?bGGev`%DKMoIYjK5ueueETS|IHd_IpR05iN9;%7g_kd7JjjX z|H#6pS@{3fIOEf9;ZIxiHvi`=+~&V051&B`x8-??o=0K09agwe3y)iPi-jjF{9X%R zVc}0(xLt3*VBsq*`qwOcm4%PdQw5CY%@+P~3%|v}D=qw13%|s|ZT>L}x8r%eh1>kU zY~iy?_2mC7X6Pce3^xBv2Z&dOZ1cpQfi+;6*zhL2ZyOyzVoBu}w@C?Uvb>iQYyBjRrPFG7F{0cKVuC{Qyy!_6>zijb8?<73Hk&m5^%Pjl~yff*&&B9wP ze2azKeBQ9|h(&+89@k^IcUkyi3r|}30~T)6|J=guaQ9ib-9LQK!tH+GSnT4UqyE@7 zc|NLf#&Zq+jU3Lh@U<2`#o}|Rg-^HW@3!zOE!?&6>nuJY3-7e(?f87nq7Pg2-_Aq- zfQ8%f|FOlV5`5S;(5<)d&*9nNJr-`uZHLAGE1)-Wd(omNe}lhb;pA`dehZ&&;cw>Q zzs35#h*|V<01uv-k8>>i00B5Ju25wof;wT=7wGO1N1#Pl%(?(wys|jcMpvpXS=>x@ z20i#f{ao(B&3wDzXTmk>7eXF-vrfeE;AUM$od>^PN1SyaU6#L2=t4nrxLIGY)PtLK z8EqcitRr9>M`!q(^&Opp=I}}#?%f{TtWR0z!Oi-S`#iW=Z*so}H|rf9^x$S)%)=hs zEXdg4!Ogmx9uIET?`-qnW*x^44{p|j?DpVhJ;+`UzJtmL*RL*FdFsdP`cot4pr#-6 z(3^ED!T|3Ky~)3zrl)t!LXasQyiz|q9(vQb*7=5nv;C01{&WsBg{%smx z?4dXM{ICZ%`oG(QoAPzKt`7}=Q%++Z+|+Mv9^BMd_jqtq|2*iyO?~*d2RHh5)PwKP z{YcK^+j2AIVxb2&sSiu6@eRt()Em=0xT)V3dT_Ij zjPu2Ix=elk9S?5iIUn}mW}fqJv#Evo9owcBrg+pNu8qz0leyu8cR(leAn0cEesV)c zJm(h=RhTYnXkE@@tbLPPaN5k|S(nfKtQy2tyc(D4;eM6wzx6i=1}tiNm?+CGr0?F> z{Q&c##N6oX$8lvAhxD_#tg2FXr2%!NKZc`=U$)&oTjN@76)}DEOsvL z$n(GIpV1`G^YCxGkPd%_4dUL!-^3#XY$X3l?VsNcwln_B^$NV?y{=wzq^GFcuNXr8 zCYYm;JJ$as@uvU&Qx#$HU+~Yq`$+k>E~NY$#>_va-K4)%zi!2qLFjJ3MzP-eqw3bs zn-}KUTyMjRk^Dcb{d@JzJew=~zVu&d0?^kU?cW;16p5 z-u&CG{d1j&?M%82_5<9ED1WVZ>vYC4z5H}G{*C+@A8*)zd=Gzuzo6IkKR**Ad?pBI z{BzjPt2=zZ;WPa8`5yID4BqsU?@0cGv&6gaC+d>@_4?<8+4B1M(hqCX?1J;EFH{!K zKD2f<5UHW&EM)CGHZIJ;mt`n3;hY7GtA}8`aZAySZ7t{rBA3El1W` zdwTU=-+VTb27YI4_~ssL1SDSi840svHpee(V+e$L$0zIs!9I*b8$;DIN>`r9&Akz~ zCu=iEmZ4$~a#5M^d?!#cz6_6%GT6T`{{Dw5GnRog*QsYn2l1RJ|aa*84;#`{k@ zcfNuM93vtmrHyUn_bshIuEPZY85&x($CuOB1 zMk*kj%@Oy>U9a|LAklffO-|sB9&F`~rHe|Ufmz6?t%&l>!C3WkiCulOg4Fi#hOzj~ zp2ru4d9cKLVq*n+q-T|gLU14b(x7CQlY9c3lK1zwLVmQAW2ulF`HM_Y``J^irA`Ix z77aSR9~6pBzE!ZIHkFnr{u2QTGsLe2**ae`y8F%5pRg@uAeW1g$!hyJwz;p<>bwUp zVr9z2L-GSZB!DN;pZF!BZ!pW(^ObdUNtZ`;5c=)Vn1jQA$A3<-sb zp>m=vqyClH5T3b|7;FfYBO#Uzvf;ax`$9pyHXE%aJlU3i{T5azcyo5iCuh_z>gaC5 zx{vm*hQ?*hk&c_%D{nF1yu6}>gn9%07Wk=p; z@}Q`zA77eS(s<-(0k-zGEN)$Xv|y~d>1b?RJfw*J`+g5xYT~r)+KH*LkDU-2>C8fg zZ@O&Wy{Kh)ce;+?g}mnWW?|1+lR36f+9bA7bZ78K=+r(9A)^@9CSa_H~9dE$5vSt=dD#$B`V#|0nl? zN!}q$<|X&Ygm9&kyux)d{)sQdmCoc-NbYlc!F1PF&ZQ*%IugT4Ug5eB|HQc`iO$g9 zgnQy8nz6|P&c6`v)VSmWF!t?;n{Rr_17LI`?Lm70xZfCq#(fC?bj*Lh^@a4Bpz5d4 z!Yvs5N869t`$C_dXw4$(CjZ`<@g7Q_?+HPU=kuh-i#MlAN*`K^cQK|8-IHYlAn2ozFgNoys%v`IQQhy zkgQD+ z+{nSC&+swNk9z2hd{q0O;zB>BzV7$Xn>zcb2RG?ry-sJsHFDtIVjDO0`` z{?84!29a1M*)yc#3jw2hLF=`8I=*dV9lPyympsqIzwL~FZ%@R8Z>}MD;=N90mPJs<-|m<3WiU&j zZfbF%e{cMQI^d8Z%l-zlcj|`aa3uMgH90++p7Lk!&ny3hz!<)FOw!D4n0x|>IOE@3 zmjk8$O7%MXYvw?_d`U}Zt}Cp2d7*#4;uXBcjXy)1!VNL6{LP%*JdXzxZ{vRrZbp*d z4hjs;j8*fIy91cGC}YEgQw}UEUjO;VIx9Iq19zn-{+>sS86K}Y^tYP< z!riMb*)fVg$w-7GCL#2Z1HNHn zi(+4}52gi4(9a(+BMp<|a+(A47Xv&nlt&xB7^;fkb2Mi!S4N;>{bn$ndmshZ*x29P#Q#36pEy2ahw-K9&N^s4!8-TcIfV%war#zZGQ4pY7o84Q1= z+KN*p74OKSG6`53$=OXOOJ!i4Mn2U57R~B%jFqMn^(d7x{RgYOZf~l6vHN8Nd&_*c zeSUY(&Ca10HcSlqeCeC~y|0yy*_u2YSl!wCN`ceYgQ2G(XV+fm(2mSf+-m!O9Fn7; zyy0y?+pbWJL(nj&dOE@@=isy04h`QB zUSQh~#W5Gf(bW7hoPn^nNRHBoq<+HcA~k0)u>Q-VqJ^Vs-6o9ILTS=9KZ`YN!(CCd z_wc1L_o;zT)AV~O!YXpyOcdtO$2=3QdZxQ48mQT>On^QWt$umMxlSrx29wW6I4JJE zV9aB~Z&CNon}05ppK2~E1?|e;h&+)ZL`s=LRwLb%tQcQ!a_2#`ON(Jyv~RiyH1jb? zRgFcCl%FFjysdG2O!iUZySFDQ5VP@=-p=?*b`fLg;@GQ<(Gjv%{dO_{M(6X{mn@b42X&sS-AbWIL$lbEPJyLo`($6Yb&;Ns*pOB54lz$o% z7yS%u`!B_Ua|gqRZ*60f8(38$#>HDuKTteMkE^llp3Rz2S&&v^g)k2l8CRe!gUJK^7>V6Q&tg|f?4^Y#1d~PZ zyb$)$W*DPdv&XHntffKd@bXjogOl%F_&?6pAB?W885N!|H930bgoOn)BieYoY@CX} zZuDd<>iD=6T#LxSDi>0Z=uaP4FxRr>#l2Rm-9Yz+^v>x_08R>{g=}} z#)H*JEFVU8B>(RmLuJ>TW01y4-s6F~Ks=;hNS@=KeQe?jwHL`#V3ZB<0~$AD6ETff z>Q1d11N8ZB(71HCaNmi4<3<|$RP*?`F-z0O>r@hm>sf29f(8USx>6LL-mZxjnCZLN`RH*uxHeT_Oq%vZA5BR0($gO2f!z_IUWJZ zj(3Jyk0a(`UxC|{FO=a&?2P4pYHU7lTBSEMTia)?{na=FokNOC8d@2aXCt-dE7dvq znhm)st&B=`=#l+_+CBSAPX{-A;d=X`>prykIe-X2psDCqHg%$Nn~?XkZ* zbh-3~`;dk6JH~`tS)c;&(!XHg_L!IXXeGVP=Net^y?k!WgPSop(tpf~j~Q$8^8X|O zI4}PzEZmOIT8%Rq{46r*{i=oY6UE?WzbEPW{c7-ku=umCG&pX>QLI{2@?5N7lq`iW z)N*H^h0frT5IlRoDNX$uBr%+!H}$P4rv?uRmCqN{SH{JTPsoFt=T#ou#B+lOH{o)w zgwF6c@icm9aFebs4}GVWaC_rpOT4haUsG&vdd8i;%=bt@m>eoYjNJqViVR| z$$5BqFO*?C#V3Ow94C z6?12_a*RozA*hC$=EYL0OJnD(E{XOI6}q>TogPa!msLh^SITh1938<}&*`$@3?npd zcxfuUIF`O?zT@I-A2&Q-!gO&)sz?mSV&JG5oQQIDS*7FO%fJ|k@JVD*)X?u39WPESSXK=Z4vmx0Mz9f6mev=ql%U9MV+60jIXbsk-^O(Mz7)XAfVh zvjpqPs_TM*r9?+3b10A=b_r+a6h zi(eVxgMB4|t{u2@+~>@QSY|Jl(RtG&Ny}`-8#Tr?^80`O3-8xt->V}G8@4#<+cpmh za|CbB3d-D&rE^lUf+rVTrk(HBVQ|dhfL(3CMZ1O|pf{Jws-f+B`QpyzK0rH{z z3#c){_?dDdCuGm#fXl@TIb+NdZ*jQGP=XnwaCdX&F)(24v62#61W!;%9K(mhVM?MH zmIORXFNU06EC;rTPsvAelz~9T1d2Jx6IY|qNSxh!HAX+($XJ{-33DALyv!#Nn3Yr& zi%knrVKZo`c2$qC|8r+1%8a zzfQM04p1IsK`h7g$WRb_c(RJe+LeFxRX8OJ2W=V^MxY;d?!vL+uTDzEh&t;>oacp71Ww`P8|t`d z6+qPOOU+nZ>we(QP!;4rQjg85xe1(aoGU!YukbZd_ZSa{ojZr){;_jfQ6Ya&7}3Xq zVjLIePT%pF8utyUW!JHQ9+IpGtl#l3KGbN5i|@Yr6PRb%;tyB<_Vzu|hG(5zQqgur zQ!_D4>^aX?PY-O_cp9q498WnTj)f-be!wWPby2!VP%;2DZED_lbFPu(0U#XptcJbQ zbNt;s>G352r`Nx)`^|u}Ps%3lF5g$ZJ8=2#>VeyCP1g)nY`OFO5Eihkyu;m%GuwjE zb8sqn@7_Wz)V|{~9K3g-)9_|Ab$dy=W2kCp%>PGI-vrjjP6(6k<)53C7L}IF5UDy#8_zn z^bkjY;SBDc0(eP0g&Q2;%R^YR^)vc6zW5l1Aus5k+eNbenZq%x<*!~@y82Vy2NSJP z><6fLCgwg(daT=zxmz>Hdn}IcbYFu5yP5Tz}3SvH+zJ?QfAobJJe=SJQ4^l60=94qgnR+n(*<6@ln9lua2 z|L~(!Oi4}5eH(>RoxpfD%EfgNcdt?NoIK3&uRMkN<*JvYJkcL3q626IR542Q5A&V# zo;&kiPa+nlW}ObHyR%NeWE)}<_}WGIatN#+8+G4}y3gt!SLflg0$q0@rmI(VZI93E zJY1F-7w){>k3I=M(wy|IX!+ji-+>khXW_;!ZYU1iRfrdX^~IfsKO5+p#rv=If`8}X z&jh-;&lQIWssy8f=>I6fM2Sq^c)DbNY}nDbDjzxzmj}AOD;z2kUv(NfN~7tye)sKU z#vi!*3PwV5^>+iODth3k^h=V5hXP$3&v24=lnx~_PQ!L^N8kt+U7jK*eeO8toSGnx zxGV2xe}+@b=x%qnv9Hxv!!FlQrU5@%e>x9e8tDEg5>T6N@#6ry%l(<(!CS8Whgd37 zmz4&(rbAwgWAgABfv>#-A5H@{pHTHs1vUkpzL~;2*^5b0M#sIZw4ePM6N9&yn>UvF zGk+Y$Kd`>WKW$NrB79@{B?w=-(^HpONd!yA`18esp`<&Fq66v@g z`_W0R>n9+^U4MW->QdLgA?d46K{1J!t)9T*(M6V>htG-EM{(S9t@~c)b^xY+ zjY91P&dn8QhTZWM2}S1C-|9bdShBXO9ikxzM^5f!G2;LyI~Bi#ie}|^V zuv;sH^R@rDaua1HPRvyQvi#J=$NT&&+D<61t!yQQ^zxZ@ak#D%m7AIL(7XYC^9!az@Zk&=hQ9}i5Wg8_U|9v zd%O;@@VuSLJ|_J33@yduojlc|r?SCW`&KL#xHkk!%z)Kfxw0ByNngrLdqy&jN`s2` zj|C-5pUM7`71)B+Z}?1LG9N)H`z@io)_Hiptr%X2EH=e6{(S!rqikLA`s67KFaF#0 zMb^f{oEbf9*(T}ot$QJ@gT=1@4^>0IgXof#ad;mWW}`RMdS|#DrNBI{!fg?5h{<5+ zE~L(Dy5V1fNY@u_#RJw9!=E7g=y_G@i+A)`eSr*r1BB9jTQ*@xNd`jY78KlnE)FkK zSVhttc+lRg8(0okvNuew;GRypb^zO4wV2^k8wXc&$EvaDxyI~?ldH?N zl?~b7jZA<~S`4)6wUf)buy%$4@Dk^;?DY=)0X4-e?m@NhuX-fBcQsBMMta-?i@sYc zn_<|ZI+k=dJ-`y#YRD}>uD1aVqGlX_vG@5r88K9f4-MEpnIuoYQhi+)u|b0M46mO8 z%J9@aK+FySF}iN04Pn_Hfr{(E`4cv7yO%Q=Z)+G*ld5->FTji3#)o^Z5Bpk!8Hi~$ zPOhXIZv2|!uZ6)hV|+biu#TF$~Uy(1f41`?ilXR zv0rDgIfjm)vvTz7!&r?baTD*~fJ(E0m~WpLreSaD1nxxj-(Q}Y_QTBJLds_DtlEc{ z(qd9kQnLa3R+S=42Dj($#^WJg)`sa(IrM++z$Fukb`AH)EW&tb#PEb(_#V8rBOOXz z(Ku}g3tq{*3E;LJjB589YgxC5>>vJ;rAO-=S}TKN_%UFc!lM&s?Ps6Ix`O9Q@8KN# z;roU^>F0MydP{&%p4yA@CBm?Yd>Wew8ow9Hpu&rj3^uz3!TmKL3^@pZ)(xz{%==aL z&b8>bfld5QDrxGnY4|y&$7LA}aCZC#hr$jrev8m}%EXsTXoH=qyQz|j)Tq?kz?RCr zbt|sxX{)1g_<7yED@wZBIu~@ct!wM*Zi6=QwQXG+dpkSZx=LGnukI{exu(5!6!fQB zR=+WNl^jb~A<^iSbZgx6W+G_IQ$=OL>}#q9B`D>mo^)!p?Cjw>a-iJO+}YC$e+INs zPaF9E-Qmxabz^z?&7NU(ILLR{8G8O{J@We$hJggxAy)le;+HEf=4XJP3%y>-I`t^d z*GkHV6_!=Y1X;CBMJ1=uG41?`GioPJg^$(9lWHBmt#O@w!1(bf`nko6=$w;ryNMyp z<)6sw71uCsDlT6mh9L4IlFs~g7T*%-^}=6k1~l>zh~raCAZ312AF4MNEHQY^LGm69 zNQT?_2VS=q*GK+iQAhP3TMSQ>Qz8Es)fXNuF_7^ydt0w-`oZFbk$+I6?;izOzv8bU zH9U|)QyDpknBhf0ynj&P$9^v5R6%G62MkxVonq3@=)2-;;1~0p@xezX;wR%bM`;Fe zPB}d~`MqF#n-DI6@R()^p`93MS1&2cZUK;)jbDZd0B%95MFm{ zo}b6WBCmtS4t(#boZ|vG;Qd%ZImZQ|PhV4Blsk*_s-HOZHn!s}@Z$@a$vW^tf6M~+ z*eFCRvQJEJVO~@&^vOX!c18Yj!NhI#C07+EjgVC8BJjJDa|2;J|D?^(4(ek#H%1mr z+*MlqQ8*a}41-TjK2aL!XCMtB52;e#Co23fms zd>TLEe1Tw)H3`T4_z8}+mciB*-s6eyQry~&HWr9?jt%s(ri4?pgN-l+aG0$0=EhRi z7T{|XH(TYhP5_^&xY@vyIS>3S#m$DW%wOQ=DIToJz#b~+3j+O#OF1bxh+rk_P`poZ z8~--}r|(Y-OZDWVf{#k2^?Icd;8^159SodzfP+IJ-;jL8&y_Bh=8K9SmV=_RLiPf_ z3i?7at=v~HgnvH)e=GriCINpX0Y3!&P$*yCuL|KOCg8kx6{0^k0dGsduTQ{lNx(mm zfPaB_)DyXrZztg2OW^a%1pL_q{FMa${Jc=8eI_R0f0clrkbqYw;0qIQ>bn;zPfG%x zhQ3-vGcg$v=s3HZwiIA1gh@i{C3e^&y2LIPf$fG!_X{d59Oo2P~7?@hpWCg49IjyV$#Pbc8?@kw2QO?qFDXCNlV zeYX&wiUj;!3ApGMs4!kjO5RkPTGqm^p+ASYkj`+uq6@CH+Ij+o>KcU95X+Z$;gqME1-VNEOl?sHNCJxn=2|gsGqwW&B}sEQ}4l9fe`8>qMAZKcAa_t z4N-Un7)PIb?euGxV9kbJ;NWHtp4&R4`mQ)QWfQ!K&p$ew6UT^o&j08mj&NI-`1NDo zm;=1fQ|1*>`;CoZjtp0{sL#c?D@SrcIxUlS60R_5WWW+>Y3`YM5CN;e$eu9LSvYko zc#wO$xKBF0MoYJ$fr7_8>HJ_x7(=9mOxc72N6ze!knJ9#LTz&#P#6qbD&vr>!zDsb zw6^A5v)$-%b8VpJ<+|pzy}>D9zOTTXS4UwJku^4TqKTMkr~+KPqK(w&V{Uk`Fy5Ob zn|5_`cV}}?Pg|E5b|Mnyn<^9;o6wDsP7&Ihj{bBCIG=yIVE>gKxrFm++TK6rJN#Ij zV}nz|JMkRKfMq;&9DcG#jhI;upX%@?#f`twdmSRr=ckU(G{@&yy~i+LzH1tvQyhMR z!)H6(^YM0z_%3dIe(&f{a`--nPj`3`o;w&=o|Ex2K1Vp*(;wyV8IGPl;u*-t)7Ltj z`Vq$e3Wv{h_!@_w;_&MgXEjcB_(n&6y2C%?aNm#LaQGRH{uzhQa(FQ-gup{JepY_l zBO!jK!@C?kMcs}5R)_ok`WuIHkHP4_=x{%-zL9|c*5PM4KCd|3^BIHZ4hBa1arh30 zpN%*x4}FL;kp8{+8U8m8uW|TS9q#MZ!+rVBakwwf`yIZ(@%fm; zk8}8!9Paz^TM78Zx|P9lW*ndE9PayNs_y5I-s7ti@Mjb7mlN=^abS$V`F;$3)^4XO z&V0{tcxwXwW5?%M(A)Yy{SaIrkWV9i#{ZFtL<8>YH5O9ch48m0;8POtQxfpn1bmXd z+_0RB@UwCrn}E-D__>bW`^GxY;eX@k7dw0m4eB5;U(cu7;pZdH%5#_E>@VNW7wLu+ z`CQ=WFL(Hb4qxN&g%1B~hjSm@^8Htb`*nDm!P<|W`u9q!kq&pP~a$NwRRFLU_E^}US=onn@c!SG4?yrRo< zgzqN-!h~>$@NX%u(>=mxD6ZWb;jPMF*iy67N4OTeQW+U;-yza5 z+`g|&jp6n^V@3?OeR)2!F&O_&?WY<+bNFU0PbP-jcLJ_~493U4-=qc2wZC4%$@9WBEQ5!>#S*ojUHdud8U^K?Zv(e5p1d&BhX_XA8rvI(&sZib}=6vPLT}=K1&eSZo^p! zXW4>cfF4Qf1G6E|zcfAHDan)L!iO5of13w!o{n8t;kr=$GiLka7ApUvT7FUb1P#m2vd7Ec28{XJ zx{Xr_>otFU>@rwrd12*mcjpliPCgv3xJFt!qwU8Dv3UP&()62j9vi)t->z@ONum1h zo)svjDr454_gqVF!?RG{OqqT+|Ise`9Kgqaj`etYM#uXOP--zBwh*T2dvmzTwVPe@ zvAj_FGQOlD42DDWA8$YIkYcxOZJS!gd@Gv(v;G3Rn5(rdScn=aNe$MKatM6OOWGDb zmqGmS2RIBf+GLU~{)&Y7d>z|?OeM5GGZ1n;1IqWX7BJ!GBZsT*!!r;pABNFCXtlkw z|GLrxJYQ1DQz!HAlkrPz`?fkBkxB!t5@pG4~vC)A|Vq4!m*T+C$)S zB?GrCO%Ku259HQ|GS&C@K1v5K5ZkQTFE`iAc2EZ|C(oNv5nk2ir;bFPUC*G92^mWf z{59oQ=(Pb-ZFs8g32zEjQYKosi(qslw<)QS1S$eUY)ld26p3L0zawBRbSuQe64aQh zmjp531HB!lHeH*g0&$%vz(5HLim#$YeEsF7{7MkiLu ze`(kKuarYgaSP``ro4VvW>6+gU3Pfu^*GB6OxlH9A^~~GxP~l;uf&Eh$^oTZtNF;M zoYZ*%9TwA@MQ576%HYzXhJgi@4JRz9=-&@n=6xtd|NhGIjiWKwOu0p>*x0hSuKI-= zKhW4R(s2LNB_lIccdl-rt*n2fXi?F#)jPV+hJ0%3ELx;a7Je{W=Gfd?60hLNZ-4y7NXCk+z=-haOmAySKV8=?g|)YT{u|! ze8a#c(7wC?!n`mY`b@fidujhG`_>&ZklI&MTGI0_=!})#RoZhngqh3wcfWdTed)m5 zIobLN*(>L8DCUIQMbJCd*zy9oU;Ej*?DI}VW8{-tm!KO=!yq@`FmSU!tG%c;`=T@x z1o4A6FBE)IUG|wU^hMQEmIcT>hq)2P3v{#~<*kEfuotR4;amoM9w{%_29k~!5SBiW zn_xkk6!WS2=jDU+DO!6;P+Q9WT&7k~t*XpEBeTt_fjZ`0Zy{63h7`djNco1_ar=0S zgmu{$rj7K!3Zog6ov9rxoo;+l#M=9xeNS!C1GPVX4XW-^{unngCZI|w2Zp|gLQvP_ zK5#+;V^k<%|EnH5L8BBQl><+tCjv5$vg@a+*8ElE|6l;3`BoDGJ)vB*9q8HT3d1|WOj z?*fM%P@ezbWMl$N=!Gx9*1OOnnGj?D7S)YMi}+ z2pNjZ35m{44N;vlEGxXdq2HmCAP)#w7gTfH+pVQ-3ZzBMPocM^F$0-k3?&!&iGw4< zeP~C^+BV22@Qb570EPeQ(e?BY&t^&p@2ejBav8)c+L~KduSpg2QLelKPl**pV^hbLnpRSjD#34Q$;7@AC~GV&nE=|N)DfjcMTd3mV^3-@_y>wJj zpNK`3PDn{sqbmE38ify>#U-hwqf7gWS&Y%eeWj!wJyx3>MZi1EBE+Z1jT$?9{Mb~@ z_;ID@jehNeOGmR?iqS1apgC}$5KSYhJG!N#9YO-7-5p&$Z@lqlIwbLN@?X&1u=k4! z@U(X;!+5OIyf*U~^dtV3`VrjcTTTo?zL`V5e<>m+<9fZIsnpp#iafX2DqbLd;O2|A zfyhB`R=OpemLkIroe3|)E^`0Hn}c3LB;VW$67$CwUux$;4!@OoBTT`(NiC$l z0n*)G0^Nnd(z(W{e_~?Uj-B8C!4H2FbSK0v1z2*gI=>Bz zGvZ7SrQx3RZ#93u+o*0!aHhxWguo>KowD-GwvcQ(7g@?iTd;9W9TJ~Bw3;rLbjysx=5t{Lvb&)ZwxmunKV8y4&Wp^%I_$qLD22b^Cm z^23ki5;xgc__^ZooF7+Qx7MOmyA|h};ltB%F-mOCdYtEl>^VOJypW9J%L({cv{NDa zBNFgqi8J$9n3I4vCh&P*0=_x{?@que>tCq+wbvbJg5zZhiA#Bq57eP;qLGPPkd z3l_Uo-b}6`TFYlW2$@0NGY`q5Qt7jZCVtJwrhF#yWRM4ir>Ybm7Mie)-7OtPo8E^?xnB&0_*U&{Mwvr&+AO(aPQ%9x0!vrJBQ zcvgkXWJ~?V>pX~5^ z96rV2-*x!04j;<~Lx`9EGR1i~4nND+%S=vn_zjNFG>3o0;m14t8xHsFu-)OlUewWH zh?jFdpFI`#GN12rxX<@D4)^rWJDlIUtiF?&Ap#F4;b%B?J{Wj789&44C*T((;HLk{ z=oyaBHIAO&zl{G)4(InQ!>OymzyqHh4SzTRf8ODI2Qd0#eMDlk$EzIf`P;Ygc)nLU zde7&&1pMO;_x#OnHTnB?{`Um>?>XG(`&a`0yu*Ea;xhkO2867Yu|?(_YR1l-F~`g~8<=lXa%T<&nse{BMOqr*M_zfHjJcDSF9 zyBzM?4La&OIW-r{l!v1DgBpTcdzx zizms@Mw@kAwr5(yYxI6&@2!U0dtzGoF}bo3#L8*7(Pd)vHG16|!*}cT4KZ8_4D53; z+{*de7;g14*&-{CG$3gC{=;Cny%%qb;a1Y6`y{+h^UsAvIA{8J`Asc8?Pz%# zzs>+F)c)&L_;Wep8QA{p3Tswt|K-4#Kc8WINb6P%*GwNs%V5Vf?pz}DZ|1>UITB;( zjP^#H5R13pEK47Yu<~1a?uQks|D#%e>~Bk8{mIhOTm1{=%>=WU0AZ;ASV+v{OzGax8zk--^_% zDEm~6oYr73guYw38f3Ds4iSXQ$4Y!I-#K@5QD)$rih+jx0}W-_g%z0xCCP&|(sZ!h z9@)L49q@hfeM`P2^HWw%hF}j()eU`8zB|&+p2=+Rb3Z@-AI8sNu*53gz+plT-^8RC z1GD51%o|6ByY5#B2m7D~6Jepy`AnRE1NhMvGrqy|+dC{DzYuC0l`t6nl24Je`Bl5K zZu01&feVIc01u{(VTiF3b!PYboWfU3l(r5n23{FT8JutlL=0Xj>3?O;2aiCJ?3^L*4ipYY|*k5M$g36v1;!WU42rrS1YKhpy$e=3= z`HS7Yt*JCN_0e)LrVcxzk&{;#@T)+}962%zf-DMrjdnMU$5m3kT=Sng+p+@6g<# z$_e4?_&>lnv6`+Vwb+D5%}|2|nEJ2FvTOWN9>fVXE@9PVd!>r7etX@jL>X5X0jz*31Evb-@bh`zGQOq zBYM@o(5cc9QThLC<#_{!f2$5)_Jr0B<|f6i;_pMNhSI$=Ub3Dj7QuHnYl|~ zNtA*;ITQ34l(RAeO<1CuU|15v;MEdL;z`qfB1PKxc<*cxDMGdD2Uo&6?Vh2R&`mU5 zy$5t*I#NuHRxv4f1G|zNufUo(Oq(==-IGjqA-l)KwP3??@>E*Lh2c%undCfcX!(BQ z;Hf{5p*pYx7E7NWm|NPv|JCvhp9Mzq!Dmt4t^7ml!8AxlN%6%04oqGmUvXO@U>%K? zM^glblm&$ya}++i-E4`fZ*Q&_bPbYQFQVn5y#G1yt$L)MUYNFH-P-tg`G!##{4|}p zoLTM|o+m43YT&T)d*)WmIli|P$3t1(Iqk5CPMYogPd(Z9N@MwkK3vUdF5mba9P6tN z)XFkCQYPy}ebGLycDi)bWg(RUkJ!U?(_YCGJ*bntP8+)sCPK?sVgi+ zhra()>NE}6hq`Q>gTmW-N4cplaL`~XJz`cb`yZI)mP(8(qsC~+K8VJbmgRsQSX2f9 z#s2%(!r*cloFG9qt+x`bmMzm&c=%hmABi30N{E1l>2KWn_v3jYEZyvio@%}QSUiVT zE6PeDwYQ2z95zbn&)k=A6C_hHwqU^-;;DyfH8;EiNzqmR0AZf0N9L@RlG!=nX@7W3in;(E(%SSsD%+w#@?YqXE7m%K4&26F4=hw$c}uwL4O z2cHxApDO8T>VKuE_xQ}f+0w98`}+4Es44&W&dh`I0Ls-w`scD`VVOgFF2Eg6Zuns! zUsAb+dlA}zp?i?(o0vAROS>b-Io!BLKA(4k$6ehm-L%?XH_)-aexNN4Q}WBkG{B&D zC1x>h1mzpPE`#L*l~^IFX(V{h(BENQXuu7>62erHGj7s1qR$}t1o7cImcA}Kq>o48 zz6%#A*+<1e3Pw77q`WuN@_55w@6^owzbSzY+fe?ZWpHqWoJa25M1k1!zU`$w|3Yi? z6o9J7E$|+6&d6qc{!tI|nSl>fj(kmq75(Du&GhdKx1Oy(aW`puw(35dYj5u%y1tHr zk^f2&VAj=3rl6E2zr93g^BWwR{j*X%#c;ghxnsS(h&|Leu&M%-uu-3VwW0cf?rORr zD}@sZ_<4Kzg`NxGJ!|L@*o|!*XsLu_1Xgl?_Kv$CJC%}^pG_8?CkHNsEAvd*z#U&? zWCqS5(9_`w&{L*{=$is|?Q!#IsT}!IbU(D}OhM-jH-RRvIyJauybUp_t&!ww1$Gm|l2(c@~|*r?jWgC-U?+!1Z+}I=^ywB1rNwOvU{M zNqc^QNwa&F4R1x87(W(*&Tc^t-*#IKU9!%ISer!>cLlhB_L=Qn?! z@w53bbU0~D9&b;Owd9;?9GDsgDeMKO(r7tORFnFHcwaCe-tv$TSz+j+$2~T>0)^Sf z)nMrF(O9MefM(`WB#%*z18HHF-Oj0n(NK}8UR1g6Oo;B^^zs{&&p-b8O!^tUdF@n&=;`Y$$Y2?eGmPC-Ee$Y+&i{v+cJGG;yR1vf`F^O^ha>dbn}055QIlA zeF~KKK^^91XB?$L!|;w}Yhv!<3+u7;@7r0PfeN^->v<1|b-mQrMd8O%^`VW~$Rb^@ zG*YjKq7Je=(HM9gof#&J5a~j*b?>9h3$EGvx1nG-1{ye$32zNidP;6ej{3SL=L2CS z7qLzPLzlA^;wbL&v_hTj3l3nQCcnhePkQP^MwSr@ghgOH<5mXskazb#1D2W$)UxrEAx; zw-vW{q)PBDxum7Hs|2R4B$xEmDV@{wEMzz>wWb3$t6JBz^S`6FhX;J-W|i~9n(7I! z6>oc`v;zj2Ms@Ok3~UmyyrYCwDZbgajuP`nqgJkkrJqr2+VM4hG69rwUmLZquuDni8HRtw;C<_mER&gg3Kw%fv$vYXBv-A1ACMa2siOhY-q1R z?ELZT@V^i=8NjbG4&hn;Az!uGoS_V5&d##f9G*XMdGTEkp@d{;%+4}wHnXiVn1&3Z zmL~ZvM^1~z*8pqPxNnd^+6tnSzO5jb*$;cpHO22g*km#)#2vc3ln3wIsrOB+VEIi} zliMtz-5|$$TS>0nP}*V`yw0<(-7p?a3h~m&0C#8$+2jJ7PrMngr7>RT9L$StaS`vE z2<`lnw!lazn>W4{my~T{SjO9EuFXYmRoYzSR@Jt3XUV$?%dOUpFTSIoK@T5wFeGguAY41KY{B@|(K*Kw$N6M=HczGYGM$W1$OOmR z`NA;Rqh`gpU^$j++L=t-Jh6i9)1w$=TtYd{L;KWSB* zoQ*R7S%+B~$9ItscYYLSI_J{%(*GAnah(b2rh*OMz8Kp07i(vl=Ef99-NTykO{JAJ z0JOIiqvda5Ulw10rpXBDLQZ#WGIS=_v%Q**;~|tAEs1sE959{%h;}X+qGuX?&~3-yg*n-^Y5qS>Sa4@067u2mT^!tc8#@ zUe623P*dKE^fgK&>psqpQGB=JvWDZF-?N2Y*DYD2fz45T?^v85>gW}s1 zmvs@?zbL+3`&8CAVA~YmrMRqbz_{Zj{I$N8@8gOuSNvvNGq62KzndL|AnOK>ui{7C zzUj%@0c;eSfOriTJ_IX2-2@WfrMRsN$0)uxhMOJoiV1;_jDMW+zD7RF6)z6asY?{^ zRQxc-uU34M;<7#y+O5)#7MxocW$) zfFAo4=QnyEHY(oeL7abB@e5*jkYyYtJ}7+D9ZJ8#gE;?`;vF%3v*P^b?884QZu7_D zzO49%4bbDiD84C%%RU_1!PW~OT}T&!Z~PUWNY8(ofd7`b)C9aX0ly%DKcABdm1k7~eOChg`ULtU`|7tR@cDQG{`my{w98qj{Mz`u-cEyU;11p1+beD^2dMYx|8;?L*5LU<+d0^@CJ0zL1eh4@TQz)wrS>xmc0 zcX0xJl3n*J66o6!_^(gEvkCZ}3HV(JIQN+gwa-1I&!5tAbzcJhPy+r)0{#?m>Y!AV zhfMC*yq+U{fp&g9flmpZZwi%jTmmjSD-dpJ!Hy6NC9iE0?Fl>Qeh(wCJCujZwoa5{ z4U8>QIRSbrpv{lt_7IU=yzCN1X(PkgA#vayK9UR%^m615N((!384Y=QR%}Ni8Epk z)uEYjO(I~Y6FY-{v-nrdzp5GXFN#N1lBi1bkE%ogsp>R|Jw4exJV$FU)XQn@%nBsx zN!U0{t>mye{nS(wHGprfn_8oa+9x zu;byFkGVO8A+U6MN;K!blEaKth%!|rQ$<>-ozLtzNX?3RWYYgyB%;CnmC<-$Uf3{} zVXHb)pvkLqbNh8sG0jlBD5N263I^7t#*sbvU?$%B-n6z>%2@4fN8wx0aBI3dTB@s? zR(4}|TKqj|F;bmj{I3iL8k_G#<}5!{yP8&Yb)W`tC6V7sS9gmJnN>yft90x!f2e&~ zeN+Q%CHICq(1j~|+Sab+i4JF+S%<7dGpNCM_BWO$V-hJ)y~z%^zTS!4V=dNVe8G@# ziLT37eq|5B@M|1C&(Z%chu1m$PKVb!{PT))$)E1u_&p{yc}j9nVt?%y%(<#{Ue5`|@vaINxQA{vRBEp~D|=`1uZh!QmG%rNla`Fs2Ap8tr_$N87zd4Yk^zCGXR z@QV>=<@Y*GoFj&RLFvhVhQq!6_N5Nr=IHrOYJ47Y`Fi@-9e$~!KV~#85Lo{A;b(m2 zE6(z8@5b=+9XSgAQNj=zrmGKc2hvg`eg0d^S1U^YM1qJ)hq> zdSBmH9PY>MB;DU+zE`+%9_8>Rhrds8wwu?nTH)xIJNla)?#uI{!~Og%)eR1o$K&sC zc(da_EdgKba6j+f@9-6l&lePDy|^c3{l3l7`|O@>1u>5|VzuDneBhKpk3&q(E)eiraqi=WktB(FmheHKG0`v9baFXKWe*%77n;6m# zKOWbHPjP%Yfm=E29K9buiyVE%(O=}~nXmD=!r{!<@HU6@8-U?gI{v;q*EsrX9R2kU zpX2ZkIlRl^|I6WLIsA(b?{@gt9e%dMk9YTXzkdEJI|P9Tk6-BSM;`x_TQ@wu%grN? zH@k7@@n0n1UvcBg(@P=o$HzF175k2&%W#Bm)B03s0;BI#zLhcDzBi;}xY?VX8pEZb zfX#^G+P<9243@8b|ELi(huilOj!6ci@8b!=;&6y?`wp}`hF562ua4pNU4&zj!T8(v zkM#kLaQj};7sKuQ$E`8kzL#u@;hkEZJ7c(gFWDT!?Yl@?arP~L7C1*346l)^oUW7M zyA|K2N5gBhJ)el-eTqv1AkOG*kBYW(7!0@Xf2(7-egC7)nml?PhudPfjoS%ij9~n2 z+%Apb*6%$r+`j)k5yNfV?v3I0{coy{Q%3V=-$z?xxP2GoJ~xBW+jqe`Vz_-5{C*6# zalSi-+q^i)&b*GF3EF;^Z!}M1xQ#dSGiCHP{+Gt+ZJhVSaGMvKVz`a-Z^dw%7ca(e z8|RaB{j~Df`jd&_HvU(~aN9rq|BLSMkM+J4M%%%Azwbf>o4Upb^!Ux=!im|(=WT^k zu1w=?y+2lQ9flg4N*!7eo#vhBw2iP6aYmkhY5FRpB~QMq`C$3~tp{;#`P;EZF^(r6 zwrTnQ$%8mg$F3LQn!MuW?>jUQ-W8)y$F4KDF4X>gTA|%qP_{o`)#B~H92iMv;OE2C z!@`vwq9|o2X$bO}+OUWSCuhbJYGj=DMok}YzZy;7r}NKvTlwvp-*F4of4K?(RBFSr z{(RN2^fvxjo_OAXQrq6n|5PN0!N-&u{Nm~P*cI75N=ZO5dA0(C z)$3GY3Q9qZlglU+zn_2qX>{QT%}AAvc7o`XWmhG++U!p=Fm}!DSCJ-X`Q!>Y2?q$x zPp<8M?Lf~A<_$f8U}?Kf6_+7ezJY1-6G25_WEWJ3x1NNiKsuF1cSYDlZ4t>JNa9}@ zB=Mgwzf{JIlsPlF5K`vn(CmIO)ULhgJIXI=&1`yTAVY)rlFIJ!(5f5El=Qz`v~GIU zBdS*xY5`II3KR-D!eyE2dfLQ)|Ag1q!4UcHr3}#X?ce`KZTTG!j67i#A9>2_a!lRa4KZp$P?tLi31x}sE&$Vi2u7ln_QXf@3WUr4vH`tj+2w64YPYhTSZu)_cAg}p!O!?tx7H6 zgS_|0ZZJ8jJ~Tn<-#OJsHbGam>fz9gK~n>ovrap1btrT(8;t`zXsWP7E(fMdQ>~|Jze6D=M5=8aQKE8azU0_>&Pf6WCZ`lSY zW?l-sVes6`p%RCQxb@wVDb}=mxzgGCGG|Kmq4GLtT5T_a&HVCviZ^WQ9jVQ>uci|O z-URChZfva`Shu`!+8ed7P5&Vp)~3S!FxZ;qcW7IeZ=8t;EMNT(kx~EJ$)!cTP=lLXtD-4p0}2KJ%qxZrs*PV_v{SED-O%CV zg<%a;RqHDk4bF$=Zd?<3cnnB#x`VXk0QFZXBF7OlscQ%3w`Qj89R4@vL7ni(55=FL zihT23k}A}B_-}BLcR!Ikm#W+ytScpBkt_6$Q7sh37=!Q9ZCz_xN_*B^-8QDBW9?de z@h!W$qa7AKyRIubP(q*U-EA$YtD$wYx}&!%)!KYr3h_OwQ`gZt>YDD>?w-_?mejS3 zxQ>4v+@ebiJ=NpKw5@Mz>FsG#Bl0-VZ9G+!cpQzd)otzTO54`2>7kZU%T=Wi2xyZM zmbI=~xspX4i%8P_;o zz&M|FMpuySM+vC&!Fo^92W`He1zPCrh<-tjX%q+@Z8|e>?>V1tMMTFsnGO*5>O-Bb zm2&YlrB8Wu@F@BN(D~?x&d2hSDX<-{S_kvT=QI#9<1-+Y8G>UsUm#GQj}$L1V256H zX*L%XzW|k)`2`f1CLuZe07zgvrJ!ihBBcvh{GY}A@6=6TeuZ=p#sR0ywgnlJxcDo@ zmurNKL7aaAq$1<3xQsoVpNt>z8f7Kp3>f$2iT5ckV+>fM;*=$4kgGUv;*Iy@&orInD1hxmvIA(bA$M{(m*fc z0;gN>D~jG+!*?E1JSaGK1wycP<5jZV_cEo=*-{P46~9^9VKD6Y*GCEBBSyv8po9e=i=e%E;zt{x$8yD|#PGK%ZsXFT-=#Rmdpwk+Cd8rCQJ}Ydb{~0i0{&j&o>0#Z z$FUH;B!Ql5VusTOCfT{4l~B%~k&mtczIqE1 z=#%W?(|Apx@=*S!5Pl$m{`Uzu?Nb*j=eh*`ZzsL4ke=U?K!02U{TT`P*$Mc91pMLz zyfp#;LP9yON}#_s0q;-1Z%e>Goq$vKq)>a_n}9!@fImVUzj$~u0e>a||08h9kk{yf zD9;LHiu+I@{v!L`(GA&e2xvlfx1*b4t>IZX2ibFS4v{D6+$Eo`b64S!J9n**;yEBZ zqWf#{yA%~cpXhT0d`Qn-@d2J!Dw&Ko1icWEWL!deScHfFH;5W5=X@swB1TM+)MQ5n zov?$DlRj;v-vYcGt)P^ABxaif;Ju)GwYx+M=0uCvbh{YzPESXtNVxWNz&kh5W~x|1Tac_Pa~>7|cZX7ICg-PbW)D22L0 zXl#;J5s7?e+0$WO53ar{be~E|x35{7k^x4vsf!ZV@)9Q8^87z&f~c0bK1k-;GFf%C zvO`7a4x+uSt#u}A1@>_fYZOn!fpY^V5(l=q%;yZ=tFd7w!JZ2^Mfp9=aQy^;XYC+^ zV|XpD8Hk^RpW%E?WgtEsKf}8SA`s`ZfZ-bnA`qW}pW&Y(h(Mgr#)f~EAOi83_!<5S zf(XRD?A~t$4LIL(jQ&-Jdzqkj;6B7aK3+!5>_8J|n;4&ZN6&k$;q;rs!1m-jqv2n4 z^nAuP{9%WC*{EMSoX_e;|C+<+INaW$SkAK?Ue1Cb5cmBuU2z`x4rBb!a`b#BF}%Uy z?{)Y^4)^@q9bV(;Kk9H_{?8@gUv+q`NjeME5<>)noiv%}xxaO(0gkUou{@&A#-k8=3$9e%XK4>F=>Oi~ z=Q#ZPinCsPN3nYCcJy@)-|KK+uTi5wgurOOE*&CKHe_}_e^YDo#psUcKE^sK9@P%&#xOC&OIgL{~r#& z(BWPN|00JUug~eMFW(7`&jQ6+-yTr|UC;v+v&i4=o;&bt{e8=c| z7{^J=P=p_o+CG?O8{xZ@Zv}}FjJ{8C?z1u&o>n|9Xb!i1Jl2K5==*qrFe4lyyhd?8 zV=x%~HdX|oM*efS?aO6i_;S7GSYj|f;VP9%>j{gkMHj^Q7`|NTR_oF5ZF+r247c*% z9mD&yUb|wrwa>FL+}g8J(^PVg>{TP0RX;L|ecX1Es zd7Snx;KbtnS2ivrsEkEey_KEVh$__nn~n+;vou52cOrh4-rB!V-b|UEz<>0sCO8!5 z$Kw}I&t{H~9YCq&llY&zkA|y*+lqV(rGMz?km6q~p&qq55y~yHPAFS9uWAzk#Nd;J zvW02&VG@wjPYn`>RkKb#?R1I#(`64U>!R#*oY!DIDi>L;hU|-5xq(9QuM3Ar2lMc^h%O*bg`AdEZBrAuIdQUD6K-?nv4y3{S(yx&Nw0_A%Doz+OpD<53m{{5qS8e-{tHyMASAGv)~kg|IN^$dl}J{7F4 zXR_v|W#l%>SZ*z?k!~@nymJ5Pg@Op?GD}*pl{05Cqw)=0lPEMI-^SGvx!4Vl*O9w{f9x#`(kEv0l^Ci`S&;3`Nd?Zn8;oN$%7-Qa^e=E0Mh`(H1~WvFV2P7m~6~GEh*s>M~=g% zpe#B2;2~}hRy)P{N9Z5Wsw6onSO!NXjf1kSwM@G|$Yc)JNfyjMS3i?2AGt3#e`+trO)mSxsDCNqt__mA zT?S+3b`uLd5=w;DU6xlw$iKov1l)G@&&DeI6}0OdNU^TNn5d_(h##<_2WDfANQI>5 zKgx9>3)e|DBy4iR(^vleWNVr9Q^-2%wms@~%tUX+9~bKCM}iKNkTS12EU1*YeB%YE z*_`8L<^5(cM{#yfdEMSzK_8ObON4rOii`!&P#j%n+0Yf(!a((Gc(QsMj{;%f0Xh|b zS9-m#P0debWwkjerUFGO_-S-1o>I1?4jlMkxQz;9vA};BJW#Rk%j>tJ-6B~{yNL^7 z)wbc!>bN+lL=Vanp4<+HKLDaQfs|sn1u^ah1iu#U{zH@hXrh#?g-#s49({p7 z-P&C0ku93u)}wk;l6HCut%4?C%1KoZ%M23tHVYvhirf4VwNln)by=yl+3kmSfu8Z! zHt^mcOGbga@clOb3Y0%uGg%Jy!X@k=l;iCz2b{gJ9DL5Z4>*c4ewh@7t-nLNbmJcn z9B`m7DTM-dEr+qYBIG zPVMcT(%Lq}Y(9d`z0&@+xN6>ctgSr@)-SI`hsxmZff*f^Yf07?EqQ2+CD$*`uc6c6 z03;T-foW2aE`(@4geJh$jczZ<=0q^q`UkAATFIb2phXfac%$eeKY3=#$*VIdTliqc zBmX4Nae2BR;pGCOn$IyvYW*nE`MIHgE4+zicgUE5&zwWlsY|F2E6Z{)W6ZUXasR7D znXt+OwjoenAC{)ezR8)(-sSz~Lamp3xEz>;m67i1Mg`7crel#s0?}>yLG49&MUop& z_7@k{f!N%&v6q&ijF+;f@+Giy<)q$#iL!@*WGh(656`b*^avcDyM|duy+2x&M}8Kb zXCJmI@SQpSngvY^R#)0VSBvlh=UY8I3;@xQVErI3d3c1tQ-&-h?|F$!Oz>&4NCqUz z8odnkA)ja*<@JY*ME0@Lx)l+Ae!}BKMjyobX4#n2v3 z0=k7y3Nj+C)wZ&ga`#TK{UqI~MEOV`WFL!l$&R9ifm5G=`=;KX<(e`#;G+KABlpT^ zL`GA=nnSf+YT>(yBl8ee*%F764}A*j^_#`NKgj-X;bw}qU6dbZfU*}p%LrlYqzoyY*h2*=sR3A1SH0^h59yL-|r z+S1MGp5_&B-4eoaA?xGP;-iH!IPlHF5;Uh9dz;fMd)r&Yv|z*!1t7~Le&fcrccApJ zESRX`Jo&WgRc{%6G9{~+8S`eo-5ow#>@qP^WtAMqTBCiCI@Q#8UTs}{9XdtY782R6 z|JaZ#J9^t&&qT*Hom;!8KGn1+)wH;F-Z`}k>QgIIO%T%1X3{=Sy%+v;q88>L$aR*= zVV#^}o{bH2#ruvF02dTH5@{f0h0}!%7d6eD*My6f&gP!gAs1h^HSM{PmC}Am390&_ zNs(KM4VIc+G&?nWHa0ND?xuETs&Pqe)4Au>pL?;KEyl7XC-da&WJHMBK}XtY1nYMQ%RR!c!(8Ig)M|JR2DaN^xXC22C7=N!9Gl|^)KxW~h=ntzgBbZ=1ZTS|+U zn(mF3nRy^ws(F2cYCgA@%+2?SBRVAuC+@B({#rq&ICIC(0uQs*LV024dwcOh`n`d# zm)lBF?psE|M-aT^Og(>M8jS-2(EtiIc5c;joTBY_dog_5Xxej`7QSuzM;Bj<nd~^V-5AJ?a{MPh@^1N5e9FKQvn(J{Mbcc!;i1QI#vJUnQ_BO`n$|7Sn=NzSBe0Rh(=uwsNX$(R3oJ9xg zDjD1C*U1_;NCNO2 zVGl-WGvhDKpA{+T&o3)4%E5=ap>1?Nmi(y5)rgrD4ovz#q03Z`e5tErLDm$#D5UfA z4y9kLG_tPX{A9&<>o|}#0$82myZEq#AY%&0$;guV*2w0P&U4_Dk0Nd|J~C&4@f#!Y zw91~yd<52_xY;j~IR)%Sqt|a}GIxM|T=7kc%iI9QZ%pLh$w`M`<@_GbiSJfi#y7Ct ziksab8P~w}DZY0CP7q|=;z$p@Qhs@a4Z2p0KSJ@l6_@b{oVqUb|6yUOo>13?c%NR^ z=QHv#QEnGkAIsFvcaQMl&kXLZl#~=L7el89?QdLe;CrNeebhKvzecN0UoNIX@uzc;oE@RKY&f{MBNczvVLUxr@jt}ysfxc4 z!-H)0Xz{z`qfQliES^%oT+EruhyIv+s8RYbZ*nogj`e6+pK>UknUqgujL!v%(|?l> z!7knC)bTO=3Z<`#;Y?e|4^1oR<7)$H-=Bcrnt*>S0snjg&gYjx`F=YA|6T(A(**pt z3HY7_{M7_}9G*1_mGkffJe`1_o`BCwz{Otz#LB|U ze@>wPb^=a&=Y`tyhY9$v67b;!{G|k(GWmt_9gXLtLinTv{9Oq+W%vv6p$vZ^{Okn$ zyac={0ly{zzcB&dn1Bx^;Gaprzm$M)Nx;9CfIpsqKbwH>Pr#G>(;SW^yHNYTD*-<` z0iOw+I*?{JQrhN<6Gcpzln;uS>u;Cg7rbX*+ySz?7XZbv*)AOpR%Z zHhM%s)6lRbm4X7_byw5Q34A-Zw^Cy-wRSDMnKZX@+mZTjj#J2?simuP7eKSKAP@^~F;x7`R0aPsqAu!u&v<_`=4pmLX@c(=A*>4N#aGSDpl&L> zW=h(blI_fpn{b#Z+0T?zGlj!UNqb5trEoYUXsk-wQzY#vlJ*oydy1qzMbe%kX-}0@ zrwWHtCGDw__EbrG>S=GHpxV=6%ADxHM*6Gi@Vcokl1i7RbDF1^np5!vi>65Ple(-v zIrcH(Tu0P9yPB^Bhc$AZuOTbStAelT&gspHUhLX6t5)~qJo&`6Kzp#2Z(e>>W7L#F zSuAF=u6b=QCI;)tOPxE6MQPL-O}JRoz7jrSa85;2*bSm~Dz;UnW#I9qCECmfu5e@1 zs_tHlYt75~oWax$ddB3is*0q@P zQGPk6L!ilXc|;zl2K+O@0}?-1XuXV!>{GWwV>s%0&PA5fw3K-r))ew;p(CECm(gt=Q zYQgfyVn@2YtbR)eeG%aVBM}9Zk=O`7OYN<>FFGdEjN4ag5q^*~kT6+q5OJLQZ4A7H z{1tvi-$oFD^prz4+} zJZCuE>o_$ye5vDevBN!|)egVZ(O>6q-(Ld`_v0k&YlQN1&(7-mHAnwGhu`n;%N+iF zhx>Z{%Hh6VBM$fVqD>J7wwv!?+dC(IIeu17+dpJ~9qn+h^X%(&ISCQS$Cp3&rwzF0 zPum*|JRF0caIyaDMzW`mZ?r3Wtjb2(IJh+3)E6eB}Ef1L>RaGyd;XoXI9T z`~*ku+jEw~efuwRxF0{}f13IF@?Y)fm%DtgSDfXU;_!Y)-|X;@I{ITB{%J?=+xcG| z?#r{y;VT@UA2{6CYsBH6&;A5_3>yG}2S1*Va=7PDKcx&jc>eTL%E0zH4nOP1xsKkC z&qWUR^UM5j#rwV4(R)7a4sUV!-sW(>9-7WJ`E&2u%DLImd;a%2yw%bF-r>C07@t2V zPX5yz&i5_`;@kr^`tgc0*-D4=y^DePD*TN81c$G7_$r65aX8bTM?){a+ zdmQ~dhx3`!_^eT!<(%p8>m0prpAR{l-yDt4M;-3h&rdr3r#SkrI(pClK8O2u-tF*f z9iOpdae=`0@y`R^Pn<93WJmAId8WfXeZ9jyeW%0y^MmPvvOI10S^Ip_(ff7mE{FSh z_f^H&FQ+;_W5?kFf%s|o8UMo-kB^fX4)^6e!}0O_Kbt`RHAjEC%lBSK@7I%^4)^o% z5y$5Y$H)7#^XtR2j*sX6vco<9!}a?!+sBW$sfx3G{CG2eJH-9CI^Xf(JDs)jQpd;7 z$D1AQ+d1p_R69OjaP;dPzQ^I$Is7$;zu)19==XD$->(BlD$aKBHj<8V^!~YGw!^P? z{4);s{FgYK@2b{59S-;Ha8m;Qb%%ez@wwmOH#+=#inCs`9sVe(C6sclgr@^xl7>9}iu^6$i_1ZT!1nazKh)v3BF^%isyN%t@Bhqn^uAuzj()D=GvCqs z_4z`F`+cVs4)^!>4#$6<4OHHR;7^!F&v zcJ}x2?>PF5qyMg>_wD%~j{e<_{x^<3>+t6teS^baa`c}6=n4=auzwfgXZ>EGILq(( zzunRM`}<@^@A+3b{0hf^w&TO`&$XCguA}$k{5*#*2A!3YV~m02JQqL1?{w>oFAr%M zxV^A9!DVDv`UCuok|_A5DO8I0cK=r#p7;(xyKztiC?ipk4ub~wv(xzgX|aMGLnURrTt zS|vdmW4M*y@-=#Eheu=dCf``9`5V2-H!hChn@0x*x5e-@D}k^(hFgExH(cXy{hQIs z7;fXFFNWJV`Faeu_M!X=gYmI`nV|bxhMRn2++So`$8p?Wr1jU`F+TSF`hUCaB-%OR z=N4K#f?=iUqC4_`&M;CMZOAUvZpK*%HF{iDp(lEXT_)N@+Ruj*guC7rj%;q`W9va> zfW;0SacyozQ>o9yGtw9xZV}yyI3v%$G(DeL$dm8hK5W+fza7ia%5QKD5*13n?6APC z#R!$TUD}cNFrLTDzwPjlU|Tpu|LN!~oScUP*XWvX8U1foz~(dCpHtS#Z|%Pd81tWj zpAUVL!j)Ddin4Osu@fqnh4hJde}zS&10us}FZ-`bT38W92v6KAaS)|K8d_ z5#(J{;{KGcaF*WcUnp;;>{J33vvY;0k<*&g zp^y$5xCD;$7F1>iK6)$A%wPsCsm_CimEb;b2Xx|{)+#9Ba&JLp_vrrhr7!nf*pPj0 zD=Sm=cur{(`l-~kT~PH%WA$@`-NjHwEWcy>5VM4`YS3oS-Y?gY5_F`dT9c|9m@1!} zM9p;Mu1)mdmucCNxqo*_W^h7rrg~B3y3b_>>xxm%`pP&5>hRZIEKNV-gx7UmwtTILsR+?dWN(2qp0@}SNv07AJlp4?uWa&VwgJl zv1)>5ch;n!X#1;7|6?VYX^%+-pyhoS{omzutWoosjRPkkC+M-}>9)d#04g8qJ-}V3 z)O~zh5+Ij8Ga&c0Ega_3v@mL-X=D-J`U)bac=L3Xy%R|EZ$h zlj!Gdd?vehWai3ETT8L(SbUx_3L)SlP5^BeLISKCcv57&Qw>XWqYP* zZ~t#fd&ciftsR_Ol(`evJ9F%eEsmKMwOv6siJWWZ|E~6ud=GXU%`!&I`;S8X>ERJW zl`bCZ2iHz6s-sDkP#M^>xcztFREyda=fF!Hq8AoBhXALz5u(>;#ErhEf$Z4KFHYjv5c z%kBfShRBxAGnk$_NHBle2fL#|5>`HRZo>dP+R+PLL-wM{l??-M*;gUO$7;aTVQB={ z$Z|#hvwh#h&{c(e7(k(Ifx3ZoZEj&4?#2|~auw5DaL=EA^06>NyOC zs>g+=jN~vYFr48!uVQZh4Kqq#D&O#JkkTNP)cSYkC$BO4JnYFt6))fL0LbdHufT{8 za4Af<4fIZ>AHD}`0s8F4=^Y3Q!yt& zm$TI`^-RxXU$VkVO*uZDO$ZpT7-mwnA(FF0uoboeXbVpgjXZ2NMx?(Qvae&tU8n}n z;{CN8eADr5=cPEj^P@WMd#{=q6{E z0(ihcv_85hKrqlV`Gz-(XXRiCY~yq^%J3EV!}ChdWDJM5$QMKve+pmPN*f*xzR`GR zy{5hue=F7}nEXMm>(kAjD$AFCtMt56&w8`+u@p1jir~~YB|teU-;BWO@Dog%;S$y% zj1L-~{_m&|s?A8aI3;IBx01&y^e#8diwiYB_0>Eu4|zNp zcu0Qpbafn<$10&R2g2mSoa#eHNFVYG>Gk4C$&c2fG9ew3S-QOJYl01#O!kHF+-SCW z@*W(wGPPBZmO00BiIoSw8qDj%o%x`FQ+G+$nU?OUNU?F>`uBuuB*3-W(Yb7yuE=%z zygl+{G@qjOqyOnLNvth|8*;G5Q-05d`k*qa@A}cH%$+^Q<9T*RI&&`@Bn1OzcuA?u zjD0ARox7h!)#XU;+XHp|lSY0fk0HiaGO_sxfASn~c8AF;K)49)y$5d0bJuv@vj)Oo zq)D=UJ%<<~*|Qw9qXhoEUx<~%sDgpzlLxa59T~AaDtgmEw`K+w@5PuzyDr|J$_%VEsf8y5{Hc9B$cSi9RF-}oCv5e*2&3J@!HII)J zqr7T!W$whOw~eZuIOCSl>c_XHWDE?P%$j$QAK$w1+|N6aJP@AYpOhDNQ{r{sfVz82 zF>}YC7emB$ObuAvp!}o`;CDOAHb{FgYQshBu++f-P4S1uO`I`5-yBQ5_$l6|JpP3G zEtt5isQ6>3AF2!!F~}w|?XqC}RFuc$$}hz^>vvl*+En~9(>rpbSY&C$juG2p7FTum?LxuHyz2w@<0_%Yno5u0GGSl@J2j9<(dqU&5Zy(}(zsh#*ZvY%RauR?f)U0~{rD?! zevX_kL_yg`Ggx1Q_571^sz2#;@%&(aMiR;xy|{-^y&bJvcxKP=c9!L4ku38E3QPUv|dzth|k%3$Y-1Oxy%P(*DGFuhgk-hyEuLfKPkWNxf}nx6yK$| z@!VkqG0^#KiY1 zF5?_HZ50roq3s}J9QYjI-XFD$72vd`LVEeQfomDRI5sQZC;P$p76FW5z2dtSXZtdI z1UUKE$WxwV+AkK@635-guj^SmBe^TOL17p#L@Tcwun;hXnl91bh_kmxcHomVndm zW+D2M67Vw<@P)(+wC80B^!zqaC|~;BEQDth_5#!1pEK z2NH1Vf)%RoI}`9}z-en^@x(A#>^b2K(idodv3Vgc#na6?gaYq9d$t~Kx{527{gsg-CPu>;Hj z$p*i=x%(bF;Fb#t~dzisT4F zV~890oK1>+s~2kQKuUr!!D?Agx6r18nTnC2KmbJ{!K#*~70q2;YudVGMxhOxxcSHe zvzdCZp_Rv{xjoocKptVjC}r+qz1hPM`x-QHE!@1FjC^wsu({FRd-aN7kV0w|+1I!- zH%B6?9dR2JY*%j#qz8L+J(xv_|{a|flQEWEabhGD=wDtJY6w+-X`vK#q2$exR>?*1+E#m zRP)^%pNAw&k>~n=ryX9cIQj4$$LRT9$UuA+eukT^1@h-Rr{Qgmp8F_m`fZy4fyg3ZZL{<9Eo^j~uHXFL3xjz8bMjs6vf*El@bR1ExU z9exxGg22O3_!*yRinBfEI=sQ*^BjJ$!|NP=r^D+V&i4QY@}G~N<@+UvFL3xihi4pq z2%h^G$fp56InCyWLWLcE++ z3HaF#&nv&fF9AO*{~ZqJ-i6_R=Wt)nFFV|ipFcX>^B2KqEx+eue#}`fU*EHJ-;cO2 z&q{~;e7ha~K3D$x73Xw4+TmW8{W6FD!tuG>;iJlMfj~aT;Aibqt~krN%;9wo_qsvL z9Ny&UuX6kkb@y&#w%N!p+9$For;~bxB9KGjrqr*L)jgHS$$LFJt-t+mk!+rZa;P^~) ze17ccJ)hSd?#ojOxm*Ue^YQpuJ0Gez`^EElx5GW3DUQzxj?YX-@Awm=d;}5p3f@B=Oo7m0s#`@^}5O7zFxOFKGPkak2`u_o}W1SlO6pZ96rP0$Lp3j z%hT-eSq}H>akw9E z|LO269iQ?;aDl-3`sa=JINaZtdmQfjag)P+`+UaXp3gr!+~@mkhhK#O95pc;a^s~f=m#M&)teo3UGvf zUGd5o{!PU>RvC=X1TAM;&>X%^=_kkV2Na(g!yi)o|7q`Sz^kgxwBeH;iZ(&CM6o@A6F7mOQ9y0c2@n!M1Bv7Wu+7JQE-9zrrbRWd|d!3&H%qp@JczV{GeP{h42UE zx;lhECf6~8vu>$N$O-im*Z2KeZxz?|0a`y5*YyO;Lwfq8Ki2xD^16;e>y_fV9zyGn z;&@f;Twh4Pt{c$$pz^xTK+9e6i1aI3zKZL*jqM@*gOW)*Lb$FM*%`tQ%Jsb=yjrgH zsO?%{H%G^F#Z|74Ae`c=|C=5TaE;HeLb%4imI;MZJ(}LW5U%f6DI7cqWy#ss~Zj|B| zQvo?9PWLCuVL&wur(Et=$&t^<#HAPn#rn%oxO#)K)^XfGo&QUcCd`X`Nugw1`$p_Hbpx( z=nuhvb#UfS7U7UD{2{&!fb;8n@GUN!Gwg8q?Z6m*Eq>MwO89TLAkH;A^tj$&R`ihg zw;0dWpW-RO!ukKSrazQ18h`cA^;P-Oe|VOccvu2t`YZ5L|5|@}I~+EB-gN^1G2W7K zGONRR_=Wv*SP+UL5V&ghADJ)xpT8QPekL=Y{~dfu0yp3f!GAda`1T0jgq0op)zyD; z&wl*}K5#)b-Jic_e=rdQFLok^wE@RR#_zF^Py4!;DBO~<-|V{K9!P9m%=w=2AD7SF zm( zL6L5J8^{bQaf02}nbKRE$3-ZDjh5**-FBaU#k)D#mh(&^{ooMu8}XYE>BFk}Ex%1x zTs(F&G)|~*EZ^k5=g#C^qkEyqP2lompkkkFE{pDJm=N7HvzYs!ejh#SK>GF6b0vs< z>_~L?Wu+7bx{ttUbocSRjt|@#>BCp0qw#~O-&8c*%X%v^5%_U=GjKmeqVXT9=W^UB z^Fb#-*07LaIjxl}eILo}oULefpk5BK-rm!z#M# z`2Iu5McnY3ekGB9Y~;j_ZP7g?MZZlAy8ZwAqr2V#f$0rfUPwNd80aa|O>=H5H5eb< zPU@vq@pJ^6Q5pWoppSmT)eTHS9Pd@Md^2631Gus>^Y67VHHm>a*t;~p>R#l*So(LV zXN%5!Sh*eMl)8PZLzm;0NT;8XoA=Xr49&tF7HZ;b?3hF15_?BW3ULrr4SfU~=XAT5 zZX-jzVy>g;7MIoU+jKItAQh-ijJRym_xX=(<_E~9#t>k2BC~8-^T70Nb%z?GyKX9P z%(R2CV19A>KssLI_p7l?8l$@#OXHdD(S}=wSa};VmsD+eB-;Nq6lX(bUb!ov2H%n* zP_(Wr^+r+jwnybQ_jRergDlX-En~^VB?HsHT=$ca)2IMD-k$cA9UH2D4^0nHtfBsy zjqe#)T-=yh^@T|NqZ@vJ9pGAZ7=@9?*u1!)`9BL|t&tnNK;TGE7Z8v4)I~<22Da zGV~QxqC7T$&3~#h1oe$on~w8_-~<*TND-h0=~rBMnVy>FBJ6PQsT$sZ zC}U4(!_ubotJ#h2=^rjmKjzFM;)0Fm+zp=)o&wL`qF2)F_p>UPNCz!nWx| zU{~B`XIwu6LyJ5_<#uDLW{Ropkz1_8J4$;`WGt0=B)caRU32R2n_C-8GjnFA8!PGt z)7Q?Xq|p9sYq-)45SqU2;><`}QjQmf~77&UJRfNM{ zumuGyHPbX3497)gDf6MhXG8;XB94q0`3m|+(b$lFykSX0`pE?P9J;ZwrHP3LvAG*X z_%d5DczaylJA;fgWOlOrT&|GQA$fwy)@=XJ?aA@2oi)cfGm?HO6LAKdyZn!PXpT!> z8dhpfRr(|456!7?nSqVxv_F;3rn&&?9#LkOPy?wu6lxn=1~ZN2y>Cx#PomyqAA3;J ziA*0=k!xrIvTp3)w>hkK+Kq_@=Z32fu1UF@;SzTraL_&DuArR_ak7iH{3_Xj(u&tq zHe{}@sc1r#s08iAsoDHU{|E$7MSJ&_6+K*s@kTMIC0>vr>Pt??z|@~1Ub)00NYa7W z&11{z2HEI6*8n|Z(p@ziiLRug5qo$V8)aGNaQ@HnM8SJ61|9~lBst%49p$9lrOP2B_Xc~q>t4(8 z+xq~D)DaA^i8H;w$E21jM}LwUeJlFuK~Q_721_RHAGxjWwc&a+p+Mgr_D#cQcnJOj z4kwNfr^PX9YZ_?87zoW3>BW!>X~u91*Hb~c(ElomrYU{Q5f?@8EQ2oT{~e)@%g5-h zmdfUV&6NWS4)(ne23Rb!1^jNf?OXeD2D2pQBC?z&YII9B-;N1#1;)CPc3RJ`YmeOsW1t>kA0&YC@6KB2hO3Ik!ZHQ zLFO7L?WIzLEY+fSas$*|9PPh`@c>Q9qJhqL7d52biuOLyoIbkeeNc%0KuB3QZb@XC zYpOE0bfZ<#0Apkm;cLIKlC;B6D!Eoi`-8rtXZOBKlb#sZeEjeP=6%2k(s%S6&+SAR zM&8LdJ}9Z@2sfU7{`EsX@b~PCPaJAU4`M)8xn(eYup!zw=%bK&u&BPXW@>ccdJN}= zuR|z|cikg>M{AQOV`?7X5jXz9MlB&#YISHHiaM}SQ|8tv0 z9eLMxbbWNod?-h0c7fi;oxS}WjkvFNO#?R`S3LY4-1GIbX`uPEqUfIE2R0mx^}RK5 z)2UKl21@%9sl7!5@i_;xcQ+3AABt}I7(Bb|Zfbif-T#+-5Jkz9MYo)cG$jUZh`B-> zu3$cb^F_M+`bgZ_l+|<$6d#7hm<;o(-|gqwQN6LK6D2{4UbsCrd0zzhq}Rd{Vz5-&MfI&QJ+CYqOB7wbWXpA zz|7^YnlU0p?;?aw&b)JQ89d^#z1zWui5<%q(F;b?N04#hxPjhl%i!kv%+gahe6HVj zvx}d9N~QnIBG|NGS|L-qSBW&d$Tkc&GmEO|_w_?CY&Y%Yc-zG%Q*kSO@~Jz$VD$Ba z={d(3SMM*dH#UAPdEy7ne89KQ&aU3ejEA2&X>fcO;3(r$nS0)j?m9${mgw%Om!YeS z9g)$nf4b-J+(ac?_-?%IEUXNZ-AMaBJTM}YqW#=oD6}OgGaVq-z2=@zf#4a+6&bsf z%);rEk?|=;<}Ry&o*?nS~(d`ArFK2ZQUOlYmEeEj%uFa9rfk(2#lLW$NHaJga}` zDF4;JS7*r2Oxr~$wfZ{G+uvQdGz+5qRvNm^_&jnsoxaGqPt%6NeUvHCCv)N zgv1H_HYh-}z-))_a$@l`D3e=CRwY8{Q#nl_)gBf7=MeP)240M|^h@q@Ny2>S zjP|`z)VmU~bwU!O=1iLx9RDchk>5Ar;atMygBc5b=$#0+V0?o}azH%v;_oo0@(I(# zy?rC?=fqn!<4NGHv5jxr!^zv>HjIo>pE)d*QAAFUdH)3VRQ~zJJvUeRag%!@sY85T zn3WJNKUDoKTq2KFJywF}g^p;Kd)UAcJsgPGqFt_xqQ~DlguzDi_)m7v25yY*2 ze#hNPWSk&aYHIyix@A`8V=_~cer8apT0h_YOT~C*PyZz{GR3|7IU64m$emEN zH(j%Yz7zVNXH7ky@po#28yAIcxZqtnr6{bgMC!UKnxfHO=x1|nOrhXlpI0Wd|6DB^$iI|JAU!yZQ^WwIKMe*Jf*@dT{ z?|ZcG^hoqb^x`p0*GK0+pPF4$w&~3D(A!uV!|R~i*+UV2qUiJ^(Xr^ogBW^6uE1p)z)6pv1wJws-E_;_1H1fwW+kTtE;8*ZTFBntGd-_X_BIf?h>v<=%<{OLplB4<5oKia;ot!q^~BjHXW>)}1J z9y@pt!N__lcBgJXMU7W9Ub1AdV-70BR^+w-^>lV&%akw_t-K+LgslP*(dssr zECeA(+1b*QLvIu?8nvxi+qnv?M@pB3JwuW14PD8u2tJ#;DuNH>ZiqCmUEjMoviX9U zk>=hN3!0Wx&p5a4+}d+i;sdwmMeufmzjNWqeX^G4y~(wm4#cLS$oj7J?GgX!Yh;$A zK{|&Sw4sMv`Fgv}#j37N>&+$i3~j(Su<@^aO1@;+R8Wi1B)8+m&nqwpt8mRD9iOrJ zT8Ji-KfW7c>qSM2#PD+`IBc&knSh+!kSy)NXO<_f>Rs3EGIp%PufF;F`XYZHbuyp( zbp7OVZsFoCs4||cY@5Ktb(8qtyODbaJp~aZPOz7yuhO08f9^Y#&Tam;Lu{Fmg?Ca_|daU$; z75HHC(PJf#ZESZr-im!)M~@XhB$r1EY0sD9|C_Pyy^;SQ2h&t!*C~=^@8dB(rSdPp zd_#O@9-Qwyn+0#+(edHj9B}2Vk$X!teALQ1E+!uKaaTbl^f@)a{ z!XgA1VoGYlIvM8Q*F_h)u5odNm(+y$Q)+ub{1nfj!73&@RD*%$aoG*iuKUbdaPHII z$h5=zZKd<658O%D=lXSgM7qA`Me%n>F|y`1`b(7-|5Dk5yiHp}0|vL1f1&(!d|UA; zvEpTjVJ>%9Bmr^dVESs{w>c;qNpGxpb%^O|!Q@bBVRQrkMp+&e?wia{mm8oa9v;@8Yh!O%-f1NldsoPzb?fM!6T7d$N66o_?bVM z1YO=g+uuy_9EV6|8$S%(aXSh2J~^`QAXihh zTwf)}_d6VOWOBV$j&U3vr<7c)9{RJKQtU72*5g-%+8pBr+&ldtavP4+vs|tl^p+T1b6)puwM$!r!hL$$Kc4>SEpa_>v&UKKJKw8&`bI1 z5-+6krwP7IaMxczWR~DDsT0oj11Coq^|X|EJuUv={_}BweMIE9i@dYlknRD_eC`wf zY^QX$iu^V)99umc`8&a@%RS(1Gfw~A={YX)5s|~Ca}Nvt;Sl~K(W7hkwW9t`aakL! z-+?Ma{xZFX#b`NO37sbiu4_XFC7kyPzO%vuYX4Y%)H5i!+CYAZJ?pA+@d|7Z^8>fBVHw5pdL4{lB z50S@!v;M1#$;rjhsL!Z!)t8p8da`m$i}h~7?#e76E}Bxe=lxg~^uQt&%N_+JaI z?MH8aPVm1|K#pG&{7WI+@9{5-+z`V5Mdbe_g#Vl1J3=_QvKaq=4dI>>pe*2q)!Pq> z{5KVl<70wwEf)9moUY11IJLkGzLcS7hKI~pDfR~`l&nNG= zxbo;4_Hl3HRax@?3MAPk(a(d|3f}Z2`Qu0RHg;IG4ZVi~nZ} z;Qv@a&sPh`?u{{fWKS-FG5$8FF%hbo~K;iTL7;GPENH!87H`B2DGo)1>_S2 z@MXmFwA1Sf$UAN}PMbPySFB!%`Oem4SF5M#0tZ+SnxD=z z0CU6>k8$2K?~UssV1&ZFafj!)3UpZw&YcLsXLeYDiEsiW~ z{BUc_<(JNDYHn;@lDNFFA)W)xTYAadyk0Tg?D9;Nagvt|^+wpw-!dVH<~mI3n|qk- zwO2}o$Mj&X9hpe|t~^?s5d^03vuSgAke!;&cgIE}5MQZ`fea-;J@;3T!EOfHr;OiB z07qEIir!8~XXco@T-9Qbywb|2*HXRswjdJP$yK{c({y1Ttqsgmt zgm^O?Mcxb_lJhmg(d^A|?0a?fjLQrc+zdy#H^cdz;r+V1=Q$1MISuFe$eyRE3V6gM zm9C(K^lhytKGST)r4~I}M(g_aO@D-`FNc2Z+Ey^6k>?GH*Dz$Ly3Tz@fn;mWO5oKF zc=tAR;^dM$xXccY1Nu*ng}S=LezX#(6yIrIGPzKS*O)k36~YD zoGuPXZgLG+A016yt}a$^Q3iH6C+*n={hKtB5#kdctB|NpG#rUpkbI%!TPvY#b_y5( ziR7fI3E!Rz#_-W0vg_N{IkS^RH!?1(*7kI-zzaiPukp4}2nLlY&%X+yMDbv7ow-Prb+O+P}h?0a~p zhN`Gtls*BotE|OOpRcBf0P*+ZccWap7w0&~@F{X7e#+VK0lBYw6eoWho$8tGFC&d| z4C}ep;GDZsJp+PM59dG>msPMXK31OG>vYs_an9e+h4H@;occNUqWV`8fTO(SaQa;V ze35&e@ag5d0o8M@!TGjdam$fr<2jiD!trnoek%VZgImt01A;SJmTU0E0`laXrQ>a@ zr=|e@7Y4WSeAM84w$*rEi17{`^)JUy@wEnDVem}`xB0xq;46*%g9f+xb5L;R1M8%Q zd(_~w4E_#j0F?8$A~p{e4Eh&ERh71g@!n zmBAl3^0r(K8@%1fA2E1`!Dqzsler z7M%HTzQNZS`Ar7jZsgg=X?++hAaA*sHXHdZQCz?=KAc-qJN(5EHyQa03dqL|{&6F}*yvec@T-ix4R^JX zUufhzjl8XIA2s+&Bma*EzuDklG5VVg{v#uA>(v`Zevy$cmiZs%n~hJU!EJob5S;mM z%YCuI`Hn#A?cWc+$v!*WkAp{5ioHF8deN|56ASGZ=Y2gr5RGbk!&Lqw1ON zFC%A#@R@?2FF5n(R{S*FxRJlq;7vx}jyJ9{@-0UGnga6I8a!p>Z!mf;Gx*1iybX7& zk*|gPPw}Jsq`_T&dN}eKgI^9z)B8E2-#!O@)yOY4@?SUd{RV&7$S*PY;|1h@Xyh4x zDb~o(4bJ#qjUU~w4ZalD8vo}7XF1yVPd<^pe1Bx?+vf`4UYhSZy^YrQ&@!wGaDC4$ z-AI7zd+{n!6zGwPTOGpn{qD37uJ41HCv>W3n*=z^!vU`En`0q-dzlAlOX*Zkj3;m{ z{*cAx`G;+pPUUs|!E%RY@me-CxHbL|$nTWv?hw9QuKNtmqBtVgTSNG(a=k5tAC>F7 zLim_mZx7*IUqQFSA6z^c?z;rn`0|qYS%TjilD|Ok!4Q72;D-&)tkLxZLm^z(A85Mi zo$~r#e>5atU19*7s=TgysFvH*Aw}YlSs}buu3JL*a=Gpd;hHa6E`feY@7*E!nBY%` zaIGg5a$oiAl*qd|#D<)Tk?s{yBICuUfOV4p@=7o5zeNAfzX8+rL2LBiTtKpwjSuEhcBXq(9Od zm3kt_cj3q)ipjMe*2q96CKH@d++aB6B2XpAGXz&NB5>rjP`HXqv(rnr{*XHVv;OPg zmpW$z8vV(rg#Szk*Z6BZVz{5r{|`^{9@T!R8uh0~j^TLD`f6SEJN?ys6_lIRRtV=D ze^4Zx{=SpFpspA9SCL4yp2(47l6>X2V~!VaJ1ud_@?+XH{aSuqz!<(fHsQ>>t*jVu zD(|nd*NWeW8}zUCU*)!m|FB-l(&=%FId?bY?@Qv}Vmw!WivO)(;r!nr{vQ_mpz<1T zz5Z*Qw-QX=pcbxR;#nHbWObwNAlQQ-u zV`F3b*3Uzm-^z#GkP*tY{py3i^l~FlIVB_C&F)>6jg@~GVkGJw!Cq)?8%+#!gX5vM zYU9MZM^c+B{t*4l-b@U{B`;;V{Z>a8!ZrIHcLX+Cc6;K8n?W4$Q1rG>K$Rnpcr*F_ z)Elq%-jvvK2#g%{Kisq;Qwh$ZIb|IUsnHX9!6*gJtkeVD@${f@Yh|!k^0`F1vj$r? zlQl7JfF{36f@}>f{Hw-Z{8em0F2W#9nCXa{sO1`{*?<2s)GkSsY{T`Nd2_Jz0o|l) zHln({=9(W&lnVl^DiWXP7@N$e*xnN9YY{JvlFKo~lF=<^{Mf*FJE4($FX%loiJJOE zbLx$r=2!laIL zOBqRF(pQzI=Zqrh56wCDDm+RKoW0D~9#2f>^Fg_5=8?pwAw3V=H5+D+{2lh@`$8Of zY|n1AX}!Fk-zUf^QQ=&WP4C&9V#Rd1MJ5&I*a9@8Y{Vtc{@kcn22mGo5{;0-bN1qM z?=m8jXnUe5{ct?9)m0uBr5n)5njZ#D%cWHt&uYrlr4KcON~XMF?_rR?{i3uv{oO>- zQ_bl^E^8CqT8oNPwg3MA0n-|nUC)kt(d&PzDSdFf{)1kBO;e_b+(i}CPR#>5w`r+C zbH#Ygy4Sp6$^A5^E~`CZ&RHl(t#RPS8Tu%$!Qisrn~fHbQ!RDmR8z-#-_FYPoJ)Z4 z+H6yfpP{+%mOe1@vrzkMxDxf<(KCU91sl1+N#p66e67C;mHx${+p*!kDYGb&-k%;E zDR+B^qq_$^VdV6pOruu!^5l?FY2x80W(>}Sns-~OerWDK(dHhok;(v;a*qw2X>PB+GlBI z6^ZtI1wrJS)4ia7c;1s4IEjbmI&Ot@N!EN`g50e1{hKfw!hpm)MHw682xh5FsLgFd zj7Jc7bxz(aDc5I|i^G$-v8|yc z!UP`3u3C0j5KytiBB;h=$zgJtfb*@wQLITX2%@O(F$EcrJoR|4H?RPr@uwd} z-+-jd8%-UZnEYz$=%n5q>4z!0cNm0XH>aMxnRJ1Pfq9jXa;=8$#EAb7hEw8EpsG= zrqPi{51ce0?>IZFKZXVw8nynwcMlf~BGw#Dkz)^^%6UV^9 zm)^>OV950B-{!_&*K+*z2RHt@7GyR7drxjfBWKK5Q~d+Ue{RUkuE~_A-$G4!@f1{+ z`lpifQ%8$??*J`W@9l|9FZeTrYbd(=k;L9-LEKw91wL4_Qb)^^!%*Ym=LwX~+&jD& zx|t90OsurAK3-GW`<3+3z0bd!W0d!%elt0`WjZA4-oW_v*|D*2A5-7(T7?_;mAjU( z&)5nlf!l8&A8dQ`_G?LF-LI5G(dFu0zSVuKa_BxZIWor8&kZ)?^)neD$dw`m8$E%N}ldYUp7V3c|gJ$MN==Gr;R?^4M`WB`8%g!?;9m9yE7$XTK@tgQg%q0IW_fjs-vmzBP<%App^%t zx_!74^goD7<foJd%CGcp&CE)G zANQ8m=9iU5w`_u^%%?b)>kSG+V^2?77AkB43t=^E9Iq3+9=HMzY5@sRQ)VfQQDt=3 zTn^da-_UnyY2|P=uWpr0}*)1=A5lI_n`m*hJX+ToK+|Q{W^q8P)dV6}`>j(E9ji!#iRc* z9QjJ%Uk9c#F2%5dGgs(V+)#kE(?2RB_RSY{RrRcAXW6?ZQ`h4x<#I$Hx#i9g8PubnoZV zshk$I=MPA&wmObqXeVVTSSa?4UgDxFtD-4dJfD;KNPRZ#T0DK2gIJ$fHxD#aiva*{f%gwnD~BByvBrGlvGGZx z{deu1Ho=jI?%Q|{V*7IM|H#z#eH`ZCG{+s9I)G`SM>oF5J*d13b6l*1uI}A`oMxBH zN!Mv*tseC=w}$=(Z7=~=zvh9G4n@aPGCx0^W ziCcbyV2gWCY(i?9)8E7RyE*-YO9N+ma?3nxEMU)EdLBZRVyPzI$ypO==B}gREKwg+ zGfA0RpQ7mQE0CZlCkYZv(A47_z>$e0HKax>dcPIjeW)4yz3Hc6bIqOMYI6;##BoaomE5J+SkGMUYL2@=w9Haz!sE`+PUyyn zW_cMJ4+f;iPUyWMo>^Z04KAj1MxUMZw_U1q?v}bB^Jqcr<<(16kkx zFezA-dUIlukBWFMcu9=g3Oo*M69^$1lZSH91aBF$=2`}`oZtFk$B z+{kgP-zYs6Y}3HZ%FK!B@9iBvCG`fzLFw-;N(N!>MjgKkMfoO~$fbZmy}{j8WJZAkTn(;|L}YW0BYQ;m)z>7BZ$LFiFky^aZ6V zjMDKe<><&i`|;1B%zGpn?g@4qa;`Ml1vIF4wmf`hqCAG#WSLIme2*6G4r00&-nPr_+jZ{&&M2UF(1c+CR>KHY3T$OHh}2v77&ECqtCc0GBVNYk#>+6s5mKe zeEKOocc$J#zNg+Qj&AuLf=Jy^S{~i<5YAZI+IsOkQNQJ3fYICT!9Si95}7T7IO~{` zn!Py^?f(qU@eDDov3`Bk#`797SClukJ&1?Zef)IB1?~|DRw9_;zKpr0qbN6T2byBk z&!Dr#BiN&u6^ECxxULnVK~|FQkTx@HLN(Q=E-B=8Qva@0obPli@1}&3p7H7<3MzEbv%t zn&|%Q1gDCc9>R^^0(M_y8^}uCWDq7$G}3&##g94wh}TR@3@ktx3#-z_;Fjm>2q*5U zrO;ZE?o#IMIB>#5ofApx`-}8CKg4vL$XP#lsPbC)kpgJ&&)?)bM>9Y@OFx5GATp{& zne$QkKx5hKO?X*V?L8u%n0c{2GMA60xAmiri$95`Q|OYEgJUj<kns zy;EZKOppLKC5f?IrW+5oi~X~eB_4%;=O_0e-eWd)If3i5{xfb6CSe{xdNTKJMe;oW z3&QVCyplXAC}Qayb(}KI2a3->fJionXEY~U`AmVwR6LjRvj@qqg}&jy4;Or4ZnfjK zbUPc#hZ*TvyE5YT-L~<@?9+Qb7-{2I`gnF>_37O?SF0k|MOyu?xhxN5YxAWI@y0kg zDp{uE-Tn0^m9}9IY6*4{mbR_vNtQ9Fu8wjZ7?ZNKJv=RAgt|J8ThY08^?KaK{#xt= z?CO|+Eq?2}z^J%k?fTWFZC%|rl!D!|vt-4}wa3Z_kCv|k_a*%wJ8tl3@#?l?69$ih zdUVCAW2JlNf^5-IFBW_1MYp`}-ujZ#jt%YYCD4AX=%H3@6ugH;m$ zJ-sXOzpj_as|M<6qo!VG5zespKT zhLW%DPSU{*l+2k@eMc$y>TV-9WU8$A5zp=h-bl!R9x~upbY=@)Z>194%i&2xNF;KD z{QSvHdg{|y&G6v3zY+YK)y2)o0k8$S^vgY$R^FTE@458Ly%qH5!dn>dGHyn2oa zP@LsyEWXs!=^>r23}cij=3gZ8JpUknCn-6{7WgQnCSBMVD z+Xiw__8>?UsVjX=-kJ9uALPBo3~8froAHf?+)&x zR)WEoWl$+=>fXnDOQuv(e~n-x#9Y13rc>*6aWa%g^Cq*EAg_a}o|t?!5adpPAQPIQ zvS0LH$jSx%carzl+92k}VXqB$d?^1PPp4D+PIkQ8uiO8=c) zrmH0$Try0~#%{TGV-7jb$L+~JnDRSCX0IGSAb1}W0@v>kZr>f{E16GlZk&PRhw&pG z6We(!Z^B)RAMt~NyYT_AO@h~o?YRoqbPR{`+XP?X&`9L31dm9YbYlQuUlLr~qwCLs zeNFIfQpa7t4Q!v_eNs1EUkvP!;93t{zYFZwf)AGC1g^~=BCq4fc-C_66VCOaIC8Bu zacvl`e+2$c!CR!p=-!d(g6p0M*RMhTLcw>++Id+@A8@E15nTJIl_FosMcQyuJdurp zSBG%Udb;?B@Gl7-3*oy3ZwcYw5qxpaOCsdCtK6m{G@Xrcf%}IB-ef|*n zH`OEf-GV*Yeie3k9E{fE@j}bwVT-!k3EtoDlvI!J9(( za=|YR;T?i64&j}GFAL$kEQyE_Hup9_Ui&BmM{X^Ef3g7n*#h|81@M0>fDabHA1i?W zqyYYW0erLoUWTfcFCR`IZZk&C&n|!$;@+H7K)$H}-a;HUF6;_%Z*~@tzp()R$pZKn z3gG`z03ReCjwG%R7LfmW0sMsm_#X=36);Kp^5^6N_~`}knFa8M0{Eo`@M{X-*A~FZ zEtN0+TMOWyDS-cD0en{hoE%m8!aY;~|9Js?qyYX#0lXXrJ72gb7QoLafL~YuZz+Ix z6u>tXz;6dm&ebDg=-qP;>hoU}kpE%<{GI~%Hw)n3A)col{j`9*<7nk(GUdX=c`IH9 zkaQ31mAvBgKVL|AI#l;+!`$V|2y?0L4-DjAP-Hc9gO4##CnS*)6kkOcpM1YzFY&g* zT>1%o1GrZk=33u*7)V}+7{tFPF@S%6VgP-!Vj!|sW;3Xb8}j%@!(hw@VC~nB$2@tc zq*&xg=@?|VVE*OCcpNV|#)Ek0F&@M#knteih>QpEf@D01_a);&ygnHZl5mqn>R#@+ zcPHaz^xe<+JIKkJ5YLdpIbXVM7}N>kLo)i z7Zvw1XuOPnNi-f0i!%h$-;#gRNCzxg3=hpeNGb*!g(s~HqZmNJN{Cp%qhmJJIV?3x?JyJW2bw+oQ-DJIuNtckdg>CKTEFW zEnh%0KAUq=$%54!Lh#uff^ZwYvgfi{vd?*BntRs=g|uSB+TquGlvKq@8uaJAHD- z<4fc+{M^nUtQ7gE+z;b-8~k!3e>SE@=qS%;N7Zww!Iv2P3c>j(!e>^MZ!_{s4ZhCc zoHJDUI}L8*ukRPb@zHN*66aoi)q}|t=ZIVVA2Rq=M*a?ibM963DAxe>e8k{WF+V~V z4)=Wq=d-oy@!y#7@;2XkjJ(zVb%Wbn z|HF8`qT}sW{1pFdgWLG)dm_r)aQXa3N8F}M$x?{h_*l-}<+!KeejU#bbm9068Qg~Z zs=-&lpX!-}aWftDti(_8c7t0zNrT(?Z#8(E(Nih&+|+OD^Qi`3W#pF{yxrh08@$8d zt7NK%`mLUy8+^5quN4D9d0UP*7~JZ)y#RiJOvO>p8l(Ro4Zhak-x8e7Y_7o%7Oqrp23e#qdqKD=!3bw>WZ@;-$5w%*{24Bln%q`_@| zW(;oI^^XkRZS*`V?->|wkHO33p_h2l;PnRYHF&^j1#FYS9~XI+?`DJl(&)Lt;1gux zm*HCc-3GV%KW1?DxoS_oZSap7{AUKg(csS;-1Z|E%li|?$Le2c@SBXDyA5v3`n z&)|0(+?LmFgWK}GMP3B5p3FCT?ka$PQSfklUNZ6tqvx2BxACbw2|{qxa|?c&KbIT) zR)cR8JRHwm25&O*4;VdH8vMrwPZ@lvy!Z*HYpcOG8Tl_6+~((n?}QK>_4MPX>H24b zf7sx~C*uN+^0xk*Z163(r+Std-1cj`41SxDf7akj4E~nEw;H_iUATZ_eA4)7xb+3_ znBXjz1x9|2kzZ->q>*1}@S6+B4;b9`7oRbDJ_J4A#E7pEB}R&#w$_^Rw9WztYT>5)0wFPKJF1orc>d&lN2m4sczEb5#h}bvw&LxUTN}XtA$eV& z&=YRLu|0$zk#WP05U%S(c7||W&odapb^Xc1Azat191P*Q{^#is zuIphAhww^i4?`imTJR$wyjJkh5U%T0T*2a==6_7&m1|P*7QrhC82RObSB3Cy!K*`f zpWxF%_%^{wl4SL77kpL-*L5|qFka>TCqlTctEu+4UE5{*RTq;JV*GW>_0=I<>%rC# z-Y4PR6T-DVzYxN;z1N684OiFKX}T2G^>tT=L?*dtL|SCtNpZD%cZ6`Yt51h;ZI4GnxVEoScHnTT zzf$T|RS2&Ze0m746+9NgV}dUU;Vpu%3E|5HzcGY&3$Ep<@$3_v>r`y~w+Vi42;VOF zcS871!4HSkq7cwF6Iwa9v+FRr)bam)e18Azatj%?{zZzE0=aRFC!}cZcM)-?=x0Yyb7D5Pn3) z{r@$N>OX^&`oD>Xx*CN;lOx5!qH-=K$BK8$i5x0(FC!d=vx>$-c!YymxFMOp;q(#1 zDJKXgWtDXG>2q)z|M4vhdW2&&z6`&x|B1lDWd|ryc>({iZ%yonzZ#!c$Kysm z|FNas$5!7B*-bN_$AOwas$-pu+7{O#qFZf)b5xc-WU6*4Ta<_-* z1Ghjc_FC@~LSFRJo+D3#9>en?i-c1R|8+t%n|^5z_ylr=u$vze4qtZ7Fg4>7#*N%c z&7~X|Bw``Piq-8Ax1l$(wky)r!}s;r0UcSlBDp5wzCjwn2b=kwUwZ#P%>4)V(AFS% z@^~NlGL!1|_F%tbs$?Pd>hw>kYI3_^3*`dq%Kw{tZ5VF8y)zZSxkg=`j`4Y2cn!I! z#Ol$>%YfEk-Zsbp$l%_jPsp?Cnc=Es$a;7$PPz6^oy%if(AHKeXpZv=;EN03s|w(p z=gz19#sWC!!}7`hO#%Gw0{B-8;NLEQKVATTx&Z#m0{HI>;9~`Fk_qKYFZT-N!`<3Q zXJp;VKAK#&{so`P_6wW1Y@->AVA|K?UQdB#L;6+Yl`FWaNtS4|wRLv&^lr!kVvgK$ z9xNa6nsdJQ9DLxKGH%&Od#C%1G%xt&b`40aonCvZr&q9kdI~G3r`h0LFwQFKJ#QWL zidIt3#ae0$U|-H|Pv;h8swQ$4Fh0I0&TBe$(ad+nrR#J!`$xqaaZX2hj!P6@Nf3_V zvNbEdnjjqI83)DJ6NF>@xM3ti3S(gSp-@a z8CnFEgO)-b@0_UCMdFl~p>!~ICN8gIoP4$W_hSsoGi{Qa z*Del;8JzMmM0NYad5iJU$0J_1@DEPoPkTsrl|MLKrtuxJ+~CxIrd+QvxW9Brv}qR#mtz6?LbtlTg1fq7)vPAQtxCU89@{$n_|PUElGbvVhF{uUY1X*!vH z+JE)0c)qZydzwZ_3WoNWzp#G>6D~VIk!dsvaHogzA#~~X1m^R

bTj-1X<}aP`yehi7`# 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 z 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 gSD4fe(FC_-|#swct@n#6#hWe!; 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 A!vFvP diff --git a/lib/libluajit.a b/lib/libluajit.a deleted file mode 100644 index c82e81cd8914d68135d55224133655172bcd90a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 866936 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%0A(gM*_8YigGup&dD z(rGWybdRSNKYGfj^2lxU+(z}_ESBVVS??hb&;r$93~&|-Lh;acQQu`vhZQEYUcESl zr}O!b9ido|skY+NprSww1}G3=?!$f&4TS0)iw0*WN<~J_nWZfmIXAhVoTJX2kaMDn zKy0O{G02QK1vzYw52U}2t1gde^$E|xQ&HP!n=^{cDA|fH({@E95H#YK;CWYP5$>^( zLM8`oeehIc4J|u_>~?k!e2F?yD~!6msISKJZRQ<2&tgB|!Wn^}cN?s#;ddi4h;770 zJ3>WAlT*Fcyd9|{=*;hQI`c=*DcV;5Msn)kB&QEC%6Hk@Av{w@bBcB(%df=ffi-^` zZIsFH5wdsk`^>>_78{umx)EqopcuY5urO?IQT>NVa^$0Sv#_LzG1a1`1uvcDG40dB zrQ4!o5JDri&&Bs$Wp8taVEOiIj!nqa2SdH+_j?vK(?h6qYwWdf>C4gU!lf@oBN%<1 zinq48s|-@_Bt5#xkIsrMhu#JKvy zvE7JItR)0-Y=sg?0Ois&Bx@E${2WRqgIWEY$YpTeOIbdeQfx5FAznR;^3^N90`~-e z12H+z+!RE-qKNuP3MCj3By$R$Q|S%0ua?~7WSU7YL#My)6DUuasL?f zd=t-!=#@?|>bde70m+=AZD?&oE>lx_%|{?B{gnvSs88b~;;jfUj`4Z&0TE~f+MxG2 z5ye(gri4jb%rwoRHtMv_+z(kTaTiHG9$1U$M(jVMdHU!Bp<0YhUfiZEv{yyFb>fWL zST8IsBm0Y49_BDXi)-#3ao>33C#jm}Mv&8Z;~$zPq>Q=>QNY?jmVY7YT=yPiEcyYZ z&Bg=w@)Zh|70Ov0m|z}$u`qgHs1#b`#sjb5l^Os1Gvk46xT7>|xC1H1;B}|yK@@?C zi5Z=KihT}jSHd@9uuR-&nNcM0cLtCcx#c<}s&q8p*z zor~e%Zz#4gFhJt+QJzLPosdv6TAG8$K&CeWTb3XxFdk_}NyH|Uou>CS?CpwwKGgV! zX53?Bh+$%F|6$@>(bLZKPyQKw{zPB@q=R)QGfe!e`X~P(^1VHhT!rCU1U*Ej@IZ-~ zS>)(@i)=wZfd<{sAaajc-D5~}OV~Sx8&;swzQu=*2|u#fxH1CWR#R*eqq?-MSp}MWX0hN17tZi9UEW8)kdUldFAd76S7J9fk3xu-Pz#Ilg+R*;3{!21Sk< zq^7Sx2@xGRqwXr0+)R(b9}?8B2OAXC#Oizok(DDr3OKYaThaT4bl_M}6n{$!0U_7Y z!UiBpgCiUv@`FMyQb01B0Yh9eD}%@`qwe=;En&cRBWHq?RN2)72@(W}MFEf~wh!$( zVCRd?e3-x6)dAT=|0eccozr4Gbud&4IT!u5Xin@M3}qUdn4oF5l1b)!a2FHjjc^+F zqv6C%O8H#}yoVs|z=s=TP2;KVP-$E2HA?qjpLFNA?L0&jQ)<2B;1nDac6VvGPUhqz z5ZLKD{As0jtSE8^yW72}j+o$Z7sO;!fo7m1+n+kILjBOY3TD(WJ#5VS1Ft=o9I9awaRq!q34j-q1 z5dy1wN9Wuw#tgy>WiK;kqOfZ|gx(e>{L=S9awq%)jV$9W*zGO`m!E;!!neg%w0?sV zcE39CP6##>SrG@sMU_Yy4e#rndyqxsP@rOiviPuQgwW<|V=`BfDh75H$igM7V%0W&i;{{$$D}mk4mr?%E;5frs#_j!8KloXdkJk|o1JcDCuZI*d}|>zWxt(0_!PSC=%rs}Z%b9z)_kHAy zdXvt1A4h_4UQ!{Uq66R^OxIHK^bPJgk1?YJ21Y*XjG`Wxh$6PpV#{YAiL+M}#=qnL zkG-#tkE%NJpCkheCNQI-#+Uv&YSd5>gHlau&>1ozHxMKh5Gp8ONPrqhOlA^Pkl+N( z-Ro%DbuGJfTXbzpTepj?RiqRXKoYHGBfczcwMJ@n;-CaX2rrV~_c`Y|Gbe{++wOjL z|Jw6O=HC0g&w0*s&UwzuJ@?$_*`JG%Q<~=}wLd6>>FWUE4D!)vE`2m=ev?!_SNlv! zez#P+5|fm{0`)@h{z=9s z!#)}L$b-CN_dc2!C_UBazU7{u{%P*p^{<_~{I`!k z@j=a37T4VIoAl4_I=j&`=Z%)MrKbXu=ib`=yNZJgM&9+_yB{r>{OX?b#>K{mL7=_ms%G=)K82Mz5Ov z?A0A_UBCPNTYqrvxgT8nPHX$F``X@i@zoY5gv~icOAHM(l*Z=N{CoX!`Dw_P! zrBB`1`smyBpMUv>=e^#!ZsWgSc;pS=vu#i(hR0^y9Plojv-xFa1ZK_g{A3 z{OmQe_GC^CZT<9>kGe-ZVqI|W{HqUSymsonQ-@9s??1nPT>nk|GyALh@9B^AZ|MI; z|E~Vuv&LKj&!W>^3teH?L#}^v{mj+wdeilh>x64`+QsOWT>b?c(kGv~=lkVnhu*l! z^*7o*rOr(4%lfq}46*kvkI%pSPJYuQzK;sYZ@0QKGMeb4rqe&(nv5ibJwdfki}rBJ@0DhX zZ*p>RxtB16eELa!%Tzi#ur&EC6WtmrQ1<>Ozulp|3A!CrRmPVv-i9LuQO-Ehqae}u zl3)m`T(8G@nzqAeoVY802KxqRI&Kl4O&HTDh`PY>cKj0`n$A)Ph+mg$3628iba5fV z-3phNM3f9e+hxVW)F2^akZ*2?Y%m|Y_lx+L+8ZItIB!8r-faRLYz zW%8CWyrFE6{OKae` zHnjn!QG8E#1|pr>yK-7Cj8k#>a&c& zZP3!^63d0F+vGO{<~JUx&l4&A|(J3WU>sE4;N6;bsjdol*FB z%r+>Pe57RxxgY90+*kA&SUI7f=nLrt;S2*;^uHPc|1Q>(C{Xg*_*e8H-qT6Ap6-2E zaHfzF#(GO$gP4XA1;d=<`xDbfX1^8F=2Y54^Dd(Hq zAWb}r5<^h@6`%K6@l82L@SZUfznF32LvJn=pH5E&(RsUPd_Z7YBPgOjHtM+W}9aio6zrWX2Y;V;)j{dK1bM>PfNcC8)aVA56k1bpe ze0f@*NVlnu0*Zi-wU^41Tq;NeQg=#+o5^3aC){bIOFSrWGm#hgrSXz@a(9r#|JwKy z5QBJLlZ+`(RQ$^gT&1s$0o9pz z96v7^Q=YVPe3P$|TOIG<_(pWsQykyKRXl~)b9^J4u8k_b5kbkV;;+ETVEVKEGD*?O zgrq;zm8$sE$5J5nX4-^rqz}Iky7(q_lhps3@#z`Q)Ez*sm6y=3%XLH^lD|fF#8&vh z;^(sBtWL(1CuV#M(Ti%ANq?Vsqx~1{5nuDwi4)~M*1z5!arc6h5CL%-z!*CU&)o31 zC0&6zB|ccfbOL=%D~EZ)cQ|v#!C3~|C$gOBuyMCA+lFD?y=7!ir9FOiN6?Kmf&NIo z@_~Wn1E&~!!rFb-$Tuwe8+{!CT3o?9ptgCIJzZFE;&yE6M zwf5A(y>LHTz4p|nILa3YYftrx^Jl=$f}~D)-`Z0L0EK677F5qq9Wl1IpnX;D=1+j) zO~-ny7;pDub7K=_m*Q9zM}YPASp_B8jUU3sr!{N?ZizjYxSuWVyX78CXNJeQ#bd?R zlJeQ#qTi0SkKq?<8~xgv1Z+7wGsao52L#>U3AzVTbgd$l7D`3tuhc%c_BaU~UX5i8 z56m^MJx+t+meFi#{Bbkgi8o}d$SN88|V=SYJ$=$v_EvO6O@{KyoyJ7U4S zkl3SZza4)C@4ZVM__FZ@*Y*+X)%&!FZ>xyEpg#hgkJMLf5t{ zP#tkPORc$J@oa={Ff}*}{)pC|3ZQANfygsZXm69vv@21(?R^>8<6%t_H_vB>IY;jI zIwgMWy3DX(!>*v~{!#SKWxlExkz8Uw3a6P87W()mn*@`ulmGxU4ZGAW-<*}SGQ28;iwiWkS@Vo09Z56!Q2$xJ50^4=R^mI_&cAU%Rtc)_nET9iNA4d-dWUxBL%VBl{C~-2huxeg(e{ROq`VF~pYlEi8+)y250agc zeOmcdyj@0375u?FD0$EF^_3NDuk(^&^|jkKKyF;tpM#o(JQkRu?raOGZLd2}>Ogza zljUEQwmq>&TZWt|D#Sj4jl!|ozW8*^MXl&v*)a1f+b=iT_$;iqQjx%F8{Vn)Tn0KW z_x+yu^|*=mI>f3J`J#*>Z_XUQD9D1Y`jHe>)Ek|M#>f3s`~|Q_owh=DciI8r+5r^r*9h<4%1%F{6UhA)<{McOI zD{7D4)(sQFU~@-^EzoJj(JJYC?uG2&tKAm5Z*nsp#WU*pMn>-ASzb=B`@#e+edbhhatM} zq|yqYr~NEE3I$DR^__yJH6fIi11^u(XZEod~V~5gcEUhir+DGKv+!=LJMT=H(s!IrCXXQ`~k{@K1YD)vcJ5+az{Rm z9y{4^IYgM3(*6K;mV*fdL4mXfFFuG^lwWM=Iu6Ttr@{?EC(rQ(g;mdjx5GaHarD^X z#-}E{BAYdQNaAw|?3-(N)QSb9k0xsQb`e_ubBeMlfmnHObmhq}s5=UJA8+ru1Dc0) zChQ?+lh}|m-Zjtr-R&W72xM+wFD9-HMKDdl-O$k6-9nXWi!bMVd9h1^c5r9pT!OU zPohilL*GvZ5qE$zpSTR~pigkHtxT}@QKkg{3yD7w^mK@6XyX0U_^r1O zr1#c9KA{{>;yJAX$ewtR=7ZD1kq((pC+53_JxF}L zphj$s|CxUc|LF1laL->zAUQ~8}q3*u)lDuoC3>V z|20;ym+%4^y>6+!Q}kg$ymEA7C>Adh6F(E>Ltd2s5PsI;ma(KH{A#70|{BZE&(1#zzDn2{Oyhz@5amq|Cn*GV>=pT4O`~2+t(=^o!jR{FZ8V z!X6Q=6se*qebsVcGabIH*k z5%G4#S6Jq^uuWW4pR~>okHCqiw6dZ6C+$;v$kWLph=KJIZsrwA+vLUr%uxihlu#&D z>V6=oETfcM9@%{aAU9RZ0bB~n@Vruz&6Sbpp#G97J@I%_pHt;9OhiEa=2Bj=$>uI{ zh`m|K9A%RsUp$-vLo&INe(ip`Pf-H2W7neH#^q!`c5ZW9_-kZ87N%p%$aL&uIZdD> z6SB0bK_+B3h~qPCI`+AoHgUZ*rwhlFV1;B&wiggKVCH0_56HW=ExSw ze^i7QG@sgO zPBE_9JsrW5wA@7tS$J-(A0?jtX&viv$c^=_WF?Z`sHA(U5Jl6e347Mzv8W^)dzYdg zlaE!8U4Bw~GQ?ub0R0!Pb>de?#_4NpXrLqC7LoF#V#yYpf%P0w$>m~UO%(0l*nThs zBZDbD9kTsEf3m2mL?YPHlm%7uB%a3n5h;E?6O|+U5*-aW8(L5|vYN#riE1XI(Y&Xw z&|f0qm&0GS@LYk13Pi{H1~!>uSqpP;*<8>sh_5YaT~aN!%*@6RMq*5`CW{-`0EW$qN4C4en_&z(y6;4=1=r5k3xkx2kiDod@%?1`;{FiB)(JbGI~6>d zK{i>&=Q%|lr>Tk5tzgGIxtWagR%9@-Pv)QO*?UqA0?gQ%hci1HlM}cJB8}Sa>6m;{ z@}3Qi+FpM)bp{w_WoDa^1~nUws^3C6$n<{LO7%0={1SK{ zxgYmpcVLwm?$;*E_z*()|AlN8R&B9{ICh5>n}V*am|VI@#Q~9p6<=DCvFr%?y7Jz2 zf4KireBv4X6g7U}C_7LQGmOYjt%^Tb?SI0`-|cGIDp|ky0A)WttfL8{2CBJ-mhDhm zp{Wzk?epYtp*7!DQjGWF*7;8Q7WU|<9dszd>v5L#dQT`j!j0sK1R+qQLZ#F642*{6=KAt_xW^y?%qU;`dO}G~YfPE~RN%2=4+mUkc6T z>0-A1w(wNhe#$$xYYV-*j-EPY!Re9n*jhIp&>>^w0<4k`Sm$=Il;tDoKP0V@YvZ<$ zXHW1SAUj^!$7HIQs-0`sXz#SdE!Kxcd1I=K2c+aWaI(Gz^tD1+i?W@StgED^(AP_- z*9~998cSS6ze&a})bl4*Bc7Q^J7ppR)DzSkZ9zX)8lacy}v&5i(Ye@0CwOBAhx6Q)hJ2iQb` z;!s=k$IB^6n&V(z9gNkc+8I)%7Y*p`EeA`zl<}#3ngnNnt6#3$qrPZnq$X`RQ}<;5 zkL2R<4^X_=JswY+ULjUXBO@m}p{6mU?^9!;Hox9pQ6E@RgzL!ovxr9DW;ogLA0|1_ zw|w9-z2cS0&a9>}MfNObjCij!B6y?-FP6MW9?O%-{Nnu(zS$yB)|VLHg$BmI4yI6` z&%&9>0UG*%50@Rk>>_v z7B7OJTR>#AueR`T*-ydIing{y^DfapzwjqiOtOELE8P_90?|LmruJISEf`4f(!v(2 zXlQ5DPh(Ocje0m!;+BmeCVUJBXj*OX)JFCfmuK9;@tybhK5P*p@o8 zQ2=-}Ep~5oNASsE1-Ea}{X?(dP9xfVqNUjFOfIyGv+Qpco<<|&qy9RX+)YT%$qf}0 zXE)4oiqUDi(P^XSh)v}z;vM0~{^)k}tw$Ozaa>0Nc%gZL6e4`q=}8WF9VOcXUbZN= zhKYaS@lnlzJn?O?*dS&$CD~Zd#jE3W$ZN=1*atT#(Z0jsV92TQV3FUuj)ZscMb|G#kMmWp4mR_%V*S(9|R#bKks#6q2lZw;LarQbH_%K1tFMo@X0`tq3a++P* zZ|GV$5kZHOnf->erz&atfVze`KyMUp#AVV8gqJP zpo=B_cQWwK9lTsUlYroxe)|WDaUX|;M3yVapzoqxOI;9dLbt8O(y~`s@SS@WQ$O_8#~-?U&vMUtNS zYu3-)`1jxA4x4&wblPeWjQWO>l&039X`pWqeYicrnR+tX?v5Ti(vX8*L-dswIuRFT z13G&j`gU~MvS=`1h$n6FPFCuxm?KskfmbuD{X@)1(Fk{mo|K^q4yh78=gO$mYYxw`qM=Y~2Rb?(~ArGH+3vQ<76U79ScD|1!L; ziMc<=O{@X!hL2+*6LRK-i_F#0KlQ>T(#SVjZpXd@Fci?qRsSPKH0Td%{ zk?<5(C#xR};wz$`rqL&#H>+<5oiTWak4Yu^6WITNBksul88LTf89nE9l+gNwODw_d zDj5O4k{A=C`wm#q?vuhnPq5|dt6_4*z6WCCeP_@IHf3YCN4KZjU&o3yBmo2D{^y|e7U79<{@@QH!BCYY4 ztYs5kft3xY+3lz6nQGb`J=H#B#V^3~*+}n0=c12*Z1Bk|owr&Q?nm(vR)2Sr9*d^; z<9^MwQ;{E&X&#%ML12Zb_Mj`moieI+=D zixm;Kh3+Fjtwo@;sf|*YLq8(@boheti1cy+Z6zFGJpH8PgYTf}5Dp)xz+q1i{Halj zri9~@L_00%r>IEer8-Gok_qQEJ9fP$WKuSKJroCl#>YHpItAW3?F!&L#Mm~vA-;=2 zIYl!dN2O$pZ)1ux({D~*SeYy!Za_fdOa3V+d|e&{_5@?JPm==eTinDL?Z1}(n8@3X zw4wPL-@B0Rg+}|zaEHqA1I7y&Un0sqB;rxpZt7GKZj}d-PBvpyhs0|Z;!s(V3={d@ z)qL-EzDK;u`JUQ4O4wq?cw42AX(eORB@ZeoPf6xCk}|F5`(L8_2*l?Z#)M3`ro6Q= zCO+PRoOgrIw9F}j59vrZ-^XVZTwV>JD9uD=c<#(h593fq`b)G~=oct#q#x<)>Q+I# z48J9rMffewM4?g{TZg zFSbsjB~N3rD+*=ivZgd#DT7f^g@q&{pB#eH7@9-+9gjAHT&79zi3$X#^!s-zPz8C%L&#&PeWbVd1+R!t&S8u`op?^ip!227^EJjV)8cnCc9Vu3X6!1)sC+%ViJ!jh zBH15IhiuQj;Md;L3JV1r~-G{zi;4sVZQeuiHe@K1{68K+W7u=>AomK(m`lyoe*;>F)GBZ zIMb~qI#I`Jj7|;3#hGhR4Cv!TG2E<*L5wrGBPk-YA<+tb zpb>XUCbeZM=W@RPeY$U?OZtET)ei+gOt7>vzo}gb--oRne;LPTeL`3Lpc}3%Mc<7S z2lU;c%-aS6h)el;hk30gUIXep{ToSrM{hy>jE5R5!fcu+KyE!<^!rij_tWPfVR*Jo zDljHQq`x$#Q}{Cdh;-yU#*fQ|e2=!8(>=KMoQeV~&b&+f3O#6M8lhXdoPqRZN(o61 zo?$xv>`m%FWA`%u2g(0tl*YRB6)G<2TAb;wP10FRSE0y6AK}X)0@f>0f8h5Z&1F+_ z>Y~gB(M(W-qMr?M9FL4D%49BM;+cx{GlKl0yhs)@phw{$`VsjR^ZL?Enr+>Zc{8=y zRk-y8(@my25p*bdk+*x3)i)(`8qSMETPY>yoO}*1pUHD86Hgl4y_IO^Gcu_z_(mvG zKNtDBXcP&U^2tMWkjEH{ChiaRLn8lAenb8y#xeaH^1ovtNaYD{xq0AGgg9P_|G~atrnWd3UNi)L3-Gg$ z13%C6d1@oRX(v37aq$cZ+Ug8%=Fz%ubxAH!nli7TIHAa!&CXF z`C$q3-!%mPH<-SO`H1IJ#2LyjWMT+DN0?75D;nt^g$(HBVEH19?&yFEQTA zxOjHOy(<~_@mRW$>FHZ{;#13bCF9c=?`FK5aWXY7%7@3HrHn6Sd;{YP8NZit@$oOP z<&6IwK7=y$#^T{;@J}T2gFBE z4E#Ah1fGU=PI8u$p#lUY=UKo9<8waY;AMu(m`^wJxr+(%hM>QJ>6O2xJf@$e=%)#@iS_hv}Cv-fiF!;DgCY{T=03W$rTO^DyIioavhw|1RUTj9|#AQ04p<E7jZ(uyY^fxlz&3FytHv=CmU-Oy1oCb6R@f?cdiXrG}jb$)C4>2DfSF9@k#}$9Z zl{`-m!RJ|~Z)1A#ObU70hoIlh^b6V6!%oTs!taKl|1;C)ohRw;ln2+LA?W*=ego6L z#PnGhpQyeT(u5r$R~}sF0UxYVks=xi-5cL1X^c#4Ba5?k;HRD~3FJSz) zia$LRB2>zQ>m9|1@o|jr2R>LipJ4hfreDbPv>r7W{W-v?9`krW{yx)R!gv?s;`tHx zt{Q?*KGO$i0*oM@5pfI+K|hn}+n8QFCxU+Q5cCa0;I!67^85XWjPPZ7a6Qg=z%POC zF#Z(d-Ha=Jc$V>n7fV7`FV_~vn;5^B`RoKfSb26ay>gU(Ez|#D2>LkF2QHC>N*|6e zzJYNM^C8>YqMu}Z3*$cEgURzHrdKvVRKHEOcn71ub_hJce8dAM(iG2-IF<}SKa1(h zFOvdt_v*Tn@mj`tdVvQCX?&r=wQR-W%9YnFT3qLi*ws*3SHG-g#rUsI zn3zYDRgo1HWUQ!&E-LHl7A&t{LZ?eA7Tme0u5MXn9ULo17A>d`FA7KM#c9RT%8I*i zU2zu?(hbeYGEtN*7)U~FD;8B(SJpKM1}m4>G{E0BxUw|jd`V?ETm$<`lvwJtt};oy zY(;%#9o$fZpsupEdQpYsL3tA(`E+hrR2^Yg-UGyf?`K3KZ_;$a0?JF7?L~D<1Z%#v zXoYZ$O_JkIGO}<*jZBjd>ZEIG;=HWBf=V)sq7}r;>Ie9|uCG|Mg1lh!Js6N$wnB1U zRv$sG7B31f68GvBHCEmoSyW9WONsCWQb@wfE5q7V!*WryB64+QeSLT-Tt*qNiku?GlTf0Wech=NYSCUX7 zdbP^C?hBlqgG1-)!<9l}7Ar|jf`>SWfn;zC4qrTPs(f)dA+2;W=~ zp$3sGhl-jN6^n%bd8yTOj@(g)p=1;{!a&rWs%4dADh_05QUaHvDH4e;QxXG4rHBj? zUoC%>V@8-~l99-<6r`$hg;c5)l`Dm$vKZ)G5=3f~UDM*qJ0nXLL>j0wk&*c3GAS@$ zeG{rhvC9^OE9=9eMC7IDT=_cHd2!b!`p$u+g1Qk>;5eXE1THh9NKh&`O_mCst5U(a zRw{^AhYol_RW&pUT|1Rys+*T`4vc|f0FW#voF|I}w`h0}Le|Q&Z!SQ`#^-cfht&lY z4N;R=BJQ&Kd#KiB?h#8|DaoLDHB#4LB`~sFXf{dAYK!C)j+je?g+la4Rgvmyx*!b6 zR9B;S5Lb|&uP)_z1E%+4?}f7U_MnE-qp-ryN|!f?UdPvJI6b;4dUAC}f#~T`PvK(2 z8RIl3P`I)oNc1|NdOR;uAa=Brl0z2=lZX((q^J3>!f7t3`1>%QQaDZJ6h2MEsZ11p zE8~YnCH$DWe-Ww4g zoxYmakqFnz;g=e&)4#6aI=!FQmrVXGL*U&*;3qX)=U>bdLzDk94cF=SYIvbup1i(9 zd?so5QVrMXS82FT?`XK5uCn<^{B=H;@;VaXK`q@p4cGbKsNp*QB^pj^NlM?ot>Hx) zzC*)98vcfc>-=-PAVM(ZFVgTSxUbTEf!B+OzFfo8c|C`4Jzqf$*UMpshU#q*^Lmjf|2rB^MX2bHYWO!aJjf3^CZDAmu9riD zhU?|ftl{%C{=d@j`5Ioz>qV3%7LhJRDTpX7xHlmD+Z{4S0DO%2!cwNJzKd>z#A9# z`)v*1ui=w4+(Qfyh+Z$Bb=tgCPqzx|VHAjd9R5|h2PrZF;nVQ1@QZzfN?hmjjUn)V z90ET$1ny|#tj>R{hU??({vq&kZG6=E{NoV#>qFoZwDC^o_^%c?d`D&E6D*tyi{b|*3suK!S{q%2X`k~{C8TSx~py*o}=V@#be}-|ct|Z>Z zI2TV6e}{1%UXr+<9%2wUyGeW^<9=~BC6C28vrE#?V!)*5=wePt=gEBWjm3OaxY{@K zuz~xD0AYjpP4UTNyv@K{8Q*Wq$&aJ8RflYy)K96JqM?dPEP{Cc`---a(^Ag=ad6dJhNZ!y=v)qaar2Cnv7Y&3AS z-{MUJSNkn`4LpyZSI4*q%Bl8S1Pom5x2QI7wcn!2z}0?>XAE5JpV({QYX8I-u74_4 z`d9lQlpZNu?Qb9tofH(V_Aw~^Qg{=OL*yu3r*C6?vw?Rr-eurwzrqIwuJ$YR8MxZ7 zki~kZb-u8fvflWPaC*; zf4|ef)qDE=2Cm-IkK=VJC69U^UuNLyeSDLFtM~334P3on-)i9M{rWowp2q{Ahu5`~ zJR2CFXyEES`YZ!i@5>)EaP_`i^&g7AdM}>E{fENU`)_;-GEkrW@_Mm>2N+lDY>H1e z-^&WbIfvbgGKP}22 zsC3o)9Lx+{(u7bxXF?yTI9Kv3cmhra%fI@_vX==d z|HJUF;;VV^jld{} z$*->G;AF7;_ueWgRR2x+r!G&$SNR_-ZHj4KOTR8xAE!^vl1|O|#M7*MK(0WLelf4+ zaY$aBURLy&I9U9Zv?z&CB@fA8v;6R;uC}hGYFTxq^v@yvZumuz=koWui4z4jal&=^ z^6p>no5RxTARr_OVEUE``v~-e@1m_?$QV2^tlqdGGS!(ecgxKH*1fXw+-PT$Ee7hA zlGQy#CBCKKQi`+avHo!PmLhR>Dh&7G(PLl0p?GZ8EhULg`3<}NVLI8;AX{Uw9V3lV zz$(jXm`wfCnvMSOxokB8AJI#jtRk(}UB#>YA?GSe7j8RovqMNq*Kzuh?=C|2$7H2U z=A~aqOT44qO(S2$OBATwx?2K$ZzC`@;!)ULs|-I@~#w zhy^QWqSK-ip*?gW)K3Tja_YmZ*jI^KKur~^*CY)HLh9(#JQzu-1)(DZC1d6H!BFI( zu`~Vlo_=^bNM%t!l`;nBl-m8m04^B`g6Z3}`}ZPE@3!H>+GsNzP`?EIf`f|SuW9&} zR=^UMDq9YP)za5VVU@SJRYWX;RgceLmveeqtUj%9S>#>swxYCHc~{eM7;C5mFStfd z85byu&H7hZhuxJHidC0)1(B{KZTJul=)tJid-MM0w#YB6sL(4{_-6QS7kN%1h1S}g zB(pNT8(g5-f(pWL9%9%JPQT95t zAzKK+P{@wMLc|->@AM5?z#7;dzuc=rLRc3f!WbzNh}wo>A)zZWYlq0TgJ@4Ey5O&=W9YdX zn5?^=7fjO+us!9-?AgB|oBnVhAv8(mQ|4T74oNck8-n>3vaJj=^HMDR_rKxqa}o2& z$5D+vVZw}W;>5Rj_$H1%iNnWc$xq_w8&!%|O>q#~=tuu{D=;(p$rWrO{ImM}$^zL2 zqD44JWrp+~O~-eLk7P_HAEA>+=RQ0P{y-lb&OSn0)6<_D)J5pDOqv?+Cq@W2(GSv( zrmv>Y%Kpng>bw8)~VrLz=YY;?iy${{w+VV_TU*>db-Lz0Vl7vt$$d`y0eup1K*Dwo%W z@422=kW82OQ8*?KNnG&{vi=aA{*Gk^ z<0{>W9G|{1qd@eu9HjUx)Noz?It?eiRP-wi{``pUy5GRF5r@L#2Cmk|pEU4343-q; zk>ChQezNaGp^9;mpUOp4SLvp+;wt{C4^Vbm6t2oM#Pq~hulGs~r{^XmXSKm!>BBu5y{-?xFz8kN zZZ~jMkDUhYN7@v28@Qr>gK?6dFeT^j4SJPsw}C4@S5qPg#7EcL?+WyE+|M|bCs&0) zCK`AxU#p{{?`8aHgI?JxQuh`8CYJkeUkmwPTmBF^@#B}8;&5@5`U&vq0hJHF_N7R~ z*-&dBe&d?f zFoW!>asLdQ)*iqyYu+QN7Dp$=6i= zv>c$~tMVuIX4({GAy2XTIDKkk^l!!|zGm42a?Pd05Dv*h^4G}Dkp4mA+yQ?h8B?B^ z@iB?1u3Y)o`v;v+F!36>8u8b!L2M{V2@w#d0m$tW_H?l#0Mm+%bK!>&9x-8JydReF zU|16NYjHtFt$9kz8_h26Zwp``u5;H||Ij?h9wS!_w+ z?3qpt9tuwc?N1VZ`K+ZlguKt^hU~lYg3&J~Me>7qsC9}8otXjh`!y}p0t?b@X?9T| zyao8J8;WvauN@u%$OvlCep$r}cZTfVP{AkjZa>;Z##=+);$9%ZJG5t7Va`$c@kj`J z`kzmDMHxkO9$$~Lu$<>x#Q{qJ@H>dL0IUQ!|Ior1EfV~)i7wjrx%p-!VZ?_ zlPd_qnxMVsc9>I4+E=y@!B{^k9L_W=cEJ`W*dV<%o+IwGw8&Zf2njQVgwq<$K%}a5 z?Z;_|opiak$8y|V`nrzvh|mFGUDj167V5?Cpu?tk`{pqQc^! zaV5S3dy7fizs`a@Siyucl;qamCbeh|>0z|*47)fF&gPJJ}nBYla(&bL%gcJZ2LQFi7l{`Wa7PG*A2_sn29raxX!Da3T}8 zJbQC53ZRvS4aYnP>?UlDL5w_X9aX_oEI5_6Yq>c9S@R{QUKe9@u`r;F3Ov906=(dwC_^bWAD4r`&b)g5iYmHVj46i z*-}A_LJCJvK;hbCgM#yv_u{88H5Iq}Bkxdj&0Z%pJZBoU_;m6|`hHXXuOja>txS6< z0)MbG;f(av`o*}JA-jV>x?po@`1_D0@?7FvwdO^s?0iEU3{*@23bag(F-m z&kaUTjSu^Ru_Hj)BD>}0a z6F(i0qr~o3is)^g3prFTyE?Rm9+K>0SZM!HGzl!*_rWxBJ5ZPwZ=OR!JIg&mm}GZa zX|TbFJvDkFJ-jq}V%Rnx$lw^x`wu%rWbgBTi0;VT6&Q8~Y#LYDbBC8Y?i_d~A;Z>i zI|gI+{0<;^M{t1{mcTb>x)Z_81Ep+rnxL|@-cs0fMmmx8+o+qzeQvSaiT!3u*y@;! zy1*0)&O+TeRrciJa0WKnm-3%XsVWu0VzkJAc*QQ)=>=Cm9`0dK7ZE?^4tW^oMKy-( zNFHh>+Ubw>t=wFTq`aZMJ=EhMBNzj-;unzf&e?^q_ML@_OY9m@;ysURS|!LyTB7Y) z3GLdl71D3}e<)IL<6d8Tqe1<^oU+)O!sJT<`09z#GNDwjk`Q?yvr7uCijq9|5b!?l z&cIuOmL?FC$<^Z*(=2o>7#q`~eQO%eEUj=qh=T1$7t>5^FjtV{l{fk|>N-WQuEs1X zyO7ph{KzRT z#7s)`K;Ip}HkFZ)T1LFj`|R0yp@MzhW?IGJLPR}8kI(n6>!*rJ7QnN}ohksti%m{L z)M(#*jhV?(hI|#Y<2;%lc%$1z^knO|DmpPuIO5Lqgy+S^d^JunR$O(Ne{8$buXV3@ zoAXd?G9jd*;(4Qsh|7TFf(37S*L@o;Mw9X=o}QACQ{9|5`tyNh;zUBo9%Kn_^&>ru z7nt)$KTeNJEk`pM-Z4eE)9cB>*s0{x^rHt1d6Wekh#G%Ss9IjnVlgT<5vMg5ilWFs z*@>b!4)I{1+}r#vPEum8%R&_H3Hr%Rm=J^fob`zJLdp5NjIsswPq<|`m!aP7-9 z?Mqd{ED>92p~vpDr^8;pcXDh@E?8tzD;|q9DgH+&A1Q8h`^d5FJr@J#`rZPqgZw?C z0dYG|Hj`KJ=si$Av=Q&Re+0Lb82@k@5#CHD&O!SbFg`~6R)?qKg)m$dtViym@548N zJ7eUlLHjM_GK-`Pf^RVT^2p#?)UppPB2P=GZWAf%Qn<`SF@ag+7et1__dZeq2}B%f zMIX{dY@G}4E+&cF4}J`ykljQ1j|AF}Wi`FhZ58xlQU|;RV;emS6p}CZ9vGTGHazoaO;J{>wy7e*5JHuA3#I~Z3ZS7+al7Z&V6Xfwa7L1Rxs#0(Y=oWCc5{D;L3C^U>K@ z`q3}ecpuq|DCjuQZ8W{ow(f{`-EYBL4FCftjlU47hJ=cVbf4JI>H1~5RGvNmj&3-( zm7ZF9^5G<1tRrAVqoJf)(Qg)It@mkXHNDa+`ZU_(UTnu@w-#*g%c9<@Js9o2DcIE6 zR8Wjg?J1CiTHx5EJX!rn$kb z*(CkFAmi}_^{^?Cs^Oj(ZgDxU2i`ME4CX?2hT|b|?KbNj= zOI=&IhQ54;6oh`{<66!w4=4Lk(hEPuo1Wt9qwAfR390&5@t~1C@1^MCACtZn_LQOu zFl_;=v4`TM9Mr^<(-dg_!r?)F`q&W0U3fx6B=GMNga?d5ae8J(~}^i^*RO_H0InlhYG&*#KVxpn<;{a&06&p=qLc2vzhW z_K8jz&Hf8!i@l*mqdm0XyOHiA(B4D}B->VT2AkP*6mg3v?o@b?5jKS0;rmY{?lE7aiaoZx=e2ZndB&OGlMg={ z*nW#5PIALeS~yzCM_C&;sG3|B{?+%oKc|%hv9}iGJow()X`{>27lRv8Hn_o=6P5c! zk`Dl{@TVnrh+uyz z*ZWxD#AgGSi_leIv;~}S^?kO`FJPE53S52fDf9*y?Uf<=0IeV)h1?~m9vZOSBN%`$agRvU|j75t6_X0SZe=MRm=J zCGwd--eQ}e6c^@UUE|A&^5|y*{aj1?yzh)u3I5m61#zn&L#h!NNR^i&t!vnTAw3N( zxN}(;=?*Xr3Uh^$8paOse1i+JdI)X`7nT?m&di8}4JKk^`l7n}$^~~-R$@1|V1R=# zXe-19!{wFBDWgj&YKTpWyh50@9em3<_KMfkR<2l3RVA!V%CeHCGwHm#rsl3iONE_P zDgCk)%dpv;4ZMmB3iF_-m>#YiH;(7vAFCQ7)S~_R99 z`0L!&(QTc7&k%SycfCaaWsT1dG+gKN!VviHHC&hf9K461V3xnlxGCo*4fi9S%GW0v zezAsMgT)UD#3u*;ihhQM>+~lyT+i2;JT95?jMs2IU$YoD^QC;I5l&MXB~LpK9Z8(^ z=>gs=N$Kk4KawINnDP`4fuG>ci|BPZr_e+I!Q?ZRGS9f4u5RB>FP|qhdL94u5ctKK zojINU+9B}LA@GVJaAyeo$3x(|G+ZyA-w%O*It2br9yh2Ssc2RG)@!)lKRm%Wm4B{A z{}T-#tKluI7er5{mlXeh8Up{arq7pX^f(oPyd&5YB0or1!Z-3h-yQ+ONG=NR}-#;I&6C_a6RkCSi` zf0)~0o`I{W9X)GNP<)i{L3%czpz!s~N6j}BuIyt31a*qOo8<`^_y>$z2CnSTmKped zrY|?}UdCq`_+iH7JUAtfDxdiV{Yj=@XyB@R78|%KpQQ$_?15Apcovsit${0hLSX|R z!}Kc+Je%=V27VFaO$P2~yxG8&9g-FU&t>|D4P4n9X*KXXrhm-9Co;a?!1Eb@!oUj| z-(cW=e&l)Dz(Y*G(ZDUnpE2+<#y1&wIpfb6xGJB`242Y%>a7N@?Ao;%_(JBt)4&%q z-f7@V8Gp^dmA&OI1FvQJHw`?@_+A5F$@n`4zKZc~18-vd0|RenJZ|7EjPEz_>0EBT z2Hwi_hYft6PXc`gehp1p5l+fOvR`_DaXe~^p!%f^%-?O`PcyF8mlXX*#01n(_Igry*ucjz-fG~=j@@GhK9T9y8+bnBPZ)S1;~NY-!1&V!9%6i>fm@6} zW8h_sZ!++5#-B6rS&VNs@VSg{HSqb2w;A|C#&;U{V#YfSd@19v8F)40T?Ssu_?reE zW_+)KuVnlk17F2>w}Ce?{(*rvGafha7RL7*_`{6%8h9(?hYkEO#`_F>J>w@0{CleZ zr$&XK`hh)J^4e|SZsud!#q=3<^QrX5h_AED6TquOu4z*YMV8F+~KTLx}1 zUS{B`{gxYeIn%3m8+4ogXE8q4pjYj8zJaUuyU@T@`(13{i<$pY17FH`wSlYlTWjF8 zOdmGzFyku?T(w`d{zkXyU$x&RgI=}YW&>|#{w)UH!uZ1mzKZpy)xcYs{xJi8jPdmb zuG;St2L1%oZ!qvyPWNd8f12qx8u&)WpE2-f7~f>zn;3u2z@KA$vw?4Be5-+PWxUP6 z+Zf+z;5!-bH1JNwUo-I681FLhF2>(9@HZLXYv6ksf5*VzVZ7VGyBYt$z&~I-Zs2jo z_Z#?r#(NFCm+`{}ewgt-1Mg$}q=BDg951Uxpxc5(_5TL$X53@o9>#TB7Q`ouanr7_ zkMS`EA7%HF_T*Af@?v=XMC1{&tiP8fzM@pzJV*d zqYDjuA=585@WqTTHSnd3R~vXW@lFHpWc)P)SLM@X;9X4rrh&V; zJog%Smsi&BI|ja$@ood}X8s=-cp=lr4Lr{D`wjeM)@PZzv|mE6wwOG*pTM=%h&k^el=eQ4E$QYwhX+GugeWQ z$k%fXJjB-v4ZMV}mm2tVzOFU!uk-av1E0;;O$M&yXff~weBEl`ReZhP!0+Pg4F;~{ z+i2hoe7(uQSMl{`17E|}Z3Z6Y>rMlIkgvN8+~(`O2L3Q#cN_Sld>uFNZ}WApfh${1 zeFpv%Uke4qxzf*{GVbT28Xx&m>?@*kg_rY#XrF9Ib`5!A5^n}t9?-BI)K^-mCxxY{%Rk~Tmx78Si%Ob_Obl!wyLDb?(x`7 zF=0G*n+OBl%8a+TpnV$z!?^c&xkG;Z|DJs-KgynplD8G$Oojj-ck%mEzD)Ly>Ut>K zR=&$6g^%|`&@fNwcsODr@6f}gHUmwUQu3?o`*AW@{`XSFBII*|lz*B#sQ5}f2TPmcwfgDT z88$A5v<>FtfjlPJB!A8LY73dN4koRU`$drF z@>kg>zxKN83$77&|9abCeNHlY*7E@DYmU}zgRSw|VORoluBA`Cgo&^?MRCgAFg23x zObb}HCl-Whold(bfbWugAu@Oza`1H%tc2l$zm>92klkcwjSs9e4(B@43c&%%c~u9z_(`eZto#p_!b_Ya@mKR#)4MfGrT?S zo79g9O!(Ybb6Q#x8QAI%pJBHr{wTlkTf3d^j(rt2Bl=yg#>^`F)^rr0%RYBUIoS@| zb_=vJ{s<%*_^lazR3=Lmrm8}qfpC`HuI!eyIwcc>vnJ73is2EH&cGq!4LM7EB1)Ov z9h|>o8{LdQ2hQ|uTS4Q*$S{$&^7sZ|(NoBX<(y~PT`&$dA~vPpin+HtF1vm0`=?L> z(PLTRGrZ65oCK*|k&EqK?+c;r=`yQXvFGwcR!{XuUYa2FK~$1vtF6@TW4>iEcSq21 zd7tl$_GCqmr8P_h+u{kYNY0l?V;bQ(LGSZ{k-?VowBU=>ZVI;7jfief128gVckXCq zvTVD(y~kJZYS=5uD1x{jZA)ilS0K$5Y{AF2ouZtNNZ4^7z08HYjGBw~9<;@6t;AbP z$+F!cDwS(cE!GywcF2A^J`rVA>fC3A>@Ji*2baL;DY3_VR0KijMP$#8s#e7GHb0L@ zFj8b6Dz-adM#g>{#`As+2K~WVLHo6&`7=r&kt6jZ7<-TuBs8{bl2DMwD!V8>2+LC8 z+l%erBh`?-4{}(si(UqES4xH{u_uHC#oo}n@ki+UPiM7drJY#U7Wru~_K?oB;itIA znkMaW1gJ6d2Zv-EXvdBe1$~oQ)p|o?ew{m7Gcj$4l(S$?Zusn=-Sr|BOwVZKN#gdL zab>ZRJo`|Yy{qRxu(L~jQ|`>L>|T6Pc~N`Q4Rc#&riF*iqx!I%IhLkMqeC&6ED;6S z*B?1+Gl{(`;~FXiA`iIiLm_)t{C=dT-%IS1wxE(e5LS3X&cBJi!+EF)5?bwlc9-Jc zN_)99?d7t9PwH=nz5i1Ci261Y-)^G}UWO^V*}Y^3s{nouzS!uFlx$27UsdW1x5ye( zCpeK&D&dRataMNLC}`=eSuL|q29Hb`1#=xVqLmhW()g@VoK>wI#bVZun+<=m>_lRW zDwpUEUunU+-UshPmYj^zf}N55M~X(Jhd+b>Crh21oO-ul9)|t5nOXVU8^20LW*_Vj zBUel4RalTY9AAzKPy7Pq=|m1AQapz1o;t8p`HSBNB*ikZrPLYW+~T&J04(}t%vFr{U!SRbw?tj?bj!? zZFzynP&)87@e0(&KDgy~Kqeev{;=gGG>MHZ*`L#gyTk*XSgzBUSLQT&itTPFfBY#Z zRYy@C^41?Js3>nhc@&{J?n8go1;b^F?OeOuEvzotMKCqF6Xrj3GfG_UrP3~B8JcqG z*rU_!FG}0L$Ox|8wjLsab4KG0@E+j{Zua2%Mf|%i1v*Pe~s)N zHdC_EzTx4;$OO!B%J$`4*Z!d|y8Ej5Z@{mk$b)Ke*%^|8+J|$iJA|*D*X>zZ$!3Wj zv_ayGj{ThSg~;}+?fbGvz8&5DwO~PK;|tWL6VJAGO!3eZEAjVAFP-bQ;PY~fi>q=x z@!i7W1J2sJeXyaj`?{W0xF^yZeRPlgHh6yMW3~l}ACVqTaWhMMc+U-jxC#7SA#~)T zA8|6<_xbGI?H^{3JQRI3-+sGiIjE3HIUjIl;c>#G zjl6>P#$6aXVt1z%?5f*JF$;D#KyA|dtAcib#$+KcNFv`07PN=Q2V1{qDPO`ksZ{dV`pf3cF-dJOQimGV;&@&RXab;pg>mjc%1EyGm z?SJ+h@{ViszSLE)J#tBv_rNQMykB{>$~(UE-Z7E0sL0yxBUw75cEy7Gy6)Y80kf-KVv<_Bv0rEQEq}&0Lb$pX$Q%3MdGE_U{hJnTsMet z4|V`QiaQ2TZsMPW{$v!y!|V0joRwHh`g3+E%mrA1mg=swo=8f6w$Nn2{**ZW4&~Q# zo46Hlq30(TGi3O0PA)o)yp9slMUd*mCijyOf`XE9Yeu4%Xm85DCVV|ieqss*q1W!7 z>*`+K@$z0U&+UdJK0Q=b)brujkzyCdT*vAhiNVSnUO^d6p$A|G9$sCBD(sy)V5 zTk$!NhqR!Bv;a)E5PcZN{tm=XA{~2svHfRU&_tdTA!L8LcK4NdM2mk9{jbRMpt=gCWrfcwD9&%V zz_MXl^+3D^!a3CGV#>trf$V*Vd!JFO&PeRj`g)Q7DZYX!Sz%A&aoPX$oIuJNO>lOp z{kiNSESNo|p-&7A!@bS441zJj+nfvCx9qnuRD>7Cr$L6GGaC46Fp;4X(X>0uS#)SwQ_q$ zyc1?H+W#b4`Htvsu9rPW5%UT^C(DD3HDmsZNeVLHw%WVhR>lKO5TwZ(l}3q%CqitI zDtz`pDo*%UVy@^CJ=DnEBxhmb`>FbeB=MEdlf-uJzh!oh?m+|^Lw3=KHmT>EC>7bS zar)5ifg;4~Q1#AiSk#QbcwBnpxzul=7f197Jy#;Sv>7Bq6aqbCB{bD-MsARO(> z3|B<^vci`Srqea7(^BO&K$Vq_99=bGPiW*m+ecJAPa!%*I|J-e^)aBmTun`{$g>5d z*B`S^MUSO7oKI$nr^1$L!|fAbB1$xkY}`gWiPigv-xd@GdKYIVx?IuQP(SknfE`6- zz>oStYF=EvPDZSptQJ{K6T8x!vlA~eE*{L7|9Yq*aqdNVz#!t|TJvh9iDjw%mVJmG z5z3tFo$u4rK``Ui{I$oaJ8itzd8h?P3?c=48zxxtvBCbG)&9OaWRLS;QZWD4`7qvM z|1(9DN(*b`YQ8dQ2TH&3W-Im`;u5qE2c?Zv=Y=NXikb3@J3%3)j~HDjVar}e_Y(g^ zCU;An`#oDaiB#GVkN*m_B%*8~_r%GGvPzF_B?qa~2#$S=<`quRV}DlWTp?^hNBc%c zX2NyY{nrMaaLzUQEr@|{B6@8aRimipf<(Os z&pcxjX>%tgb1K_~W$z}cxmG~IPMBVmruYi%#ZFhVw611;fKGf0k~ z27yeBg?#-|7RZq$J7`}@1|kwQKIq5qg{4J;s*otNz6A`B0ox}Tr0u4G5ji-5AFeRY} zX^*wO%n^NU0#*^@Y3tfnF7>{!s%XB|{*gQA6y{q6ry?KP#V&i7wV4*QNes&__H+~r ziPpUm$-%=^HlB4O-o*LbkGgOf&hkEAo>lO6T`ziZ51!ZS=i9~ZWDCW-7tcF>*v!XN z;1)1l*LKfny1SWDpfR%5`+WVppxui#pam25Bt~LAZF^e5+YM#j7apET?~UyLDCmrQ zY_E286brY=%sZKXOFW4YyN=01STbuY*jx5BOdM?LyPl5``k0RL&W+`o)sJCv(QrK<9R0GV|v)N0{Cu2 ziIZ_du`ALm)-XOUbqaGZZFGB|p9T$@okc69W%lkFF?VPF>vev)hCxwj-42tP_z%cz zU%|VLFADAVzA$UX{GemGX({3(lA|=^v79D|?3@*Z<*rUw)dyo%|8%EW@@&kt>{sE-V8(naRyO0d z(AZb4v^~~X^buGye*xBdMD0_Q!Uv|@RPk1KQ zjIP<37QO*C_P4kpE!#r-DE>U=56DT-Zq5-(6Y<#Fa-^-o?tapf06#&yAX1t_>T#|8r0+B=cU*ud0PXJSwN zyu&`)vVIN?(LEh{lDoLiM{<0Hdx%d?;=9N*%u;iGk?UfgIagj2GOi8=;&&d$&at8R zGN)0J49D|71W|`i+px{odK_tdW0Xh({f@Y~C~{_X*#Q`waDd3~yJCqD6#2@BleB|j zo`v1>3&bA$`gYWa3wF7Q9b-U_yXwadVDrQG22e>`9cb;9;MG!|8Hw{T;~oal&NVC+K>ywe0Uu8NrM@^1W>GFl^uignz@P$iHaCTRs=*EmJtZ(opp3 z_)moLNMO6RNWQN+{&?j_P$nUcdjA4_w((T`uat&>vG_FP3Nyz*e6{1){nZI`COVYu z0sZ|z;qeM|O$ZI!AV!wk1BLIKPcwa3j?uTlG_B(V&ds!b(mYv>(=7De!NLK*zWH#) zNu#6hi{bjw(JLP|no-CGXKY($**0zM56I1UGm5uY5WG6>_V%xl`k?SAsG=S#Fh6O3 z5h26z70zvA&`+RO#UU?K0vFsG2xlzKFTey;M90>osIWY2FFyv`sW<3N=R#Y0S-*2* zec$I8VFDkn=iO-D-M~966_q!JjFmx-VIVP;J}7u7U01NM*T3DJ#d3p*1ymOvNz66H zDdK-&Pi*gJm@~yT&l|g&@qIBYN1Pi=y38e}Sg#ArZ6^tbk-N>W&uaH^2iYLZKnH>b zWRB7pcD{E7*Fm+lOHoY9Y#XNfe4dBrkZ~m`k1y^)^!z+y73>o@OJ!+(4!Xjkq4Bga z&5iCi*RS_rsM2GMI~3B+@4cjW;uCv~3O9Q7ciQgEI*vnApbb~Pz!(_VduH{ z`40#3-EOVpa&!r?JF^C&PoTkjjON_1(b@`P+J>q57zun21B+n%I#)10WhyeD_!H}y z(xBt4+}DC-f6&@jq7fs{E^XuJhS26oh8=R2&vTvXb1H=;nN_&aCi=hI>u8-*tM7&1*4YGm#d z1o;-Dbe{Z}%S2H{IF>k)@AVsZ1*)N@pz+aKbHmQ}{b=$N#R!j8RI~|&#K;|^W$pee zKtqgwFlz11Dm>bmi;Wq3VEA;4U$(y6gF7GRhPh6~3{TG%x6SFlf^ zJ;igMVK$wEZ7^;)9YL-7XtEHmLWU@JFn$|`ejf}3^^OK({T(k1BD5v zxh|!xeF!DOR5-TdB0om0$zsH3KZycCA-pe+D56F#GFC$_A^D;pVX!So-WBoqsl4O^ z=nqZ(CG6wyFj+3x=@a^>sGC;w5dy6jg=!_kc`&t)H~JB=hpMO_(XY$= zZcly@Bvb97?T-9hF5un$WiuaAjvDmbN-0PmCVz#}OI*)gqvR|3uz*E%>L;TTkD(5a zB};%}JT&@v10IhjCx}3D-Y6tN&KqOzvjXq(bf1r}91|7quv$>hv_G43c374suPTXD z>c20Wu^@68%nqUi=qfNC4C!0N6O4s^{f)4m!~s4}IY9~U)LOHkm$+3>7K2w)Y?I_p zs{AT7<1C}RKrf%jc?CueZpp0!iRp-MJi|5+G~%uN!K{R%G|W}7DwP*>zG$Gj(ZixA z50)Km&hEb$@(-@f2(lsjFEn;tJYONK17Bl&>_|Uo20|>TK{J3EJ+dqQ zb(({4URGZ0lP|5(%r4~RzMqY8xV+I*jFlevJJ71kA>H?oleVL$Az7~TT?c!!IZ?>y zASW11D1N4I1X@*s;~_!RQ#Y7KjV9 zzQ+jWmj%5oCrf2R<7GQi6!j~rM!gXBY%W*}v!p3GZTsnw6g18X<52D*G;Vj;s0)TK z_^DV0(~pPs#rd94?=fUxaehvs@Xtsxkl%>>g|WKYU4Ue^1@gb@K(`Hf2;`Rl2JFp!01PuKN{XM04HRPEcRZOM51GQ_LF>2*T05xE z%g@t)k3<7FcRlegG9j!_&}fMx7)i(OESadae~7p+?idJ53!QOYDHCYF6a<_vg^dSW zkuT$}f7xwD+=C|T? z;_bZ_O^Ktn z(7?hOKW1GS9bD$T0EURLUWcWJn#6~1i6FwZ8QXPnVi{8OOS6C<7K5Pp77BE*W?q3s zxc2-`P>A)p$Cc0RET8+BGn#|x&raWCUaewtY=;vVbA&JsoJvozvGi^1C!`7L1q9$Q z?uO)RXgqA+sEvSeQ)%*X^I6QF17)lB1mjE;r{lQq2|9NV_6gIM{~448BmYbIDjZ*&@15+< zU-`IVY}mLH$Ax@`rS3@(5Zq;J?RS`WSoXNw4JQ(JS3$e26o!I_L@a##iYS{x77CmgffDQQF$^XxUiOaYs)#qeru`d{p4p+FQU9)(=Cq zUxx{lKVIP#BN#3R<|N8NUIr}yv&}b&7v6(f!Hinw;mZs}>X~NHjypkBzWX7AZsT&2 z*8UpG#1OdsHEy9YJXpLy(-$kJnV2gk{s#RZDc3VvJ&2HQ%sHN!}iWKTVWIVCsFDyH<1{g<|qD+b30Aexn1kUxiZKyP4UFH!BaHwUE z$YAtTzpz5NwAg2(G zazb&q^pI&)6BEAzELQc+BFI(n#P2yF8CH_#{>YMu1^S6h@HRw5N#>1iGB0~MVCl-*5K zb|M7UQM8WV;}r&va4HQtad6nveAJ#AxC+zLziJ^nFJio;#2BmUI{9a-CDe9P`}vH9*-nmXI3swK8&2gf0QaC zNhS!rY?eQUwx5wWh?Zii!Q^9jFS|;r^W<*CmCu}$CVPgSsjiaiho0HA^#~=7 zv4JDm#b<`}KSMOxIuw2^pPTq>b{yzv9mxfJW=#Jx>>83a>KPWMB$xJOVDQ9|yco|) zpPDs)HS1WEFLw0bwDvE9X4}3o?17GcL0h{9I$9lzT<88q(79vi>_h6FGRy(Rb`HFMGt#9yITVJFK-zRI_${!8ky z`j>c$7|3XAm*G8{t|tcD+bBw3vXNBe{6}aY8L7$CU`d~-ymrJ!fzW@Wp`Xr%eh@8E z=?W~VW9{76*_6SCkEU`Onm5K1Qr_R&ZH^OU9=fqmj_&1jB%hP)!9z-Z0!Bu1w-A3b zJ*ow>!x^R({A0H!u7Pe&?h|?QDfQu!ZW^Wzf%*`=>R8w;|BjW-L^iUK+=wWaCCN&; zj0PKD6*}S3W<9F0S#m#|EpX)O-MN1^k2dBZ#M>*y%6zQHt;0#djMo1GmX!`y&2?$* z%Te)gy~1M1oEyaY7S?#Peh)&^D~P9>=X=b#8GCpwJ0M^@5Z`!5pm8CCiaf^E_rokmoQXf7{IhCeIgS#0dEe zw2b7bB0L8^BZoiAag&g~k>9^5#tTpaB$3>TnY?kasUVUM;Q=p1OM09yG8$s5N9SOY zab&J1`5hpMcNwWmyn{mntYyNXA$b=Nb2U8Q-&uJBPC%kR8uah#oU4)x@lu)tq%DBj z?)FzO%h-w%vC8JZ2w57E{)R5|dkVVH76j=O_EF+?%m*P=9+-i}>D|m_(3s3u7yeni z!V1@x0^xGugMGp3Z-t`FLIhyZ-BptK_+^eU&(YoaL;i6T0`xCXyh1*ptml}@ zdZi|%%LNtYhj?K?QPTZyNJoetvJ0|Vi5z4|OmFVg+Ii-pk(-ZB$BSU-|HuX?I{@q} zF-wVXSuyKXJ^-ZR1Bb(0D}u>ajQ(N+H)`#9cq3+#T6-7No@s$-@4zh$_=s6U@d<7s z0p8)1-1D~tk)NPHw#7-xOc}pITxjXf_Z9C6>*9d6T@Y;46%3w(@Ilhnu18SeCwd8o zy|eNg;f|!O<$g>s6E~IJk-t>y*o&v?jt{l=FCq+%b=TJJMcOd%2l8=JHa^RV&*J&< z=3)zYINN=AGrIkk5lB*8b&;YLE#MGu&A0K6quB+_MEiC==|Xmp9Y_CEju!)Z0jx_9 zQ1;`wsz`i~(Ng0{TE}!?xDC3sH8j|JiuKujC;lWZ!=YZtqNigpQV)SB2*DGchS{ZLFzotRB-{xjiXSB%48nc7h=X?r zCK(G@Z;SnH$6zvdti<|D6+FW~#9RaG%7Y2t??Dz`kJ~CfrAfPYuV*Z58CU7EF*c|w zfT0hwR;_&+qROscuz41q5z9^9;!CM<6=n5#+CBVs6*ZTO#fbCaVwUSSsSm_JnnKH7EYuov^ULOXwb+k9045VQ7RzkA3kRM?&KCWO$Z|DC z@q()qAOuDK_Cx9|PCbSkN(K{KF=kG7;tjLh@l!K%-r_yT-l?L?gNIgREW}KEW)BQm zJfh3pO?oU1x>v=Kk^9IedYJ`yYd&oTpOzB?|_-Qy^>l)g3h zU|>oszfTBmF^h$oC`~p2Z|E}I`JCBeUIU(Ts3S5+qYvJYGP-K`&Sz~d7N_!kh!8N; zcst&ToEiHR2V_5Qavw+fI?b&2?#&##yFvH6lHDMJ`J8Ee5+_X3m3gS=!z*yj2a3oM za*GGiRuh|cLZeGJAc@z2#GoqJUIm+z*Ng7mhnOaPrB`O4RMZO{3F>WR9=-R0 z#0K=}CPUC%e*nt#Sh_<{R0$=Tkw%LAQN$MGDaa}hKi$MXEOF%Yj9@uY?#@XOi5~p11;t=&m*3MCx-XWD&Aw}7q)Kk^+_TG>tgKRN+w1!rFRbf zzhOu9Lw}3n%ieP#x-1S!;79#-B3DIvO+_;KZu%d7COSlrkL~xOLxbCxQM({EPyl%b zGk7*{JN4xiUi{HIIA$6WTQEX&f0Rsf$mY%$*$5cRsB-Xq%twAWh=^}To)P4-qm9D* zFHi{Y{G7np!)?2!Vz5OU<-O0dpIrv)*jAjLi)4mIToveSVUm~DUolES{p<5~yDPA6 zO-E|so93Sn_s7)uHOOi52Z`Bx;G%1QPi3`>wT^Eg7b1&(SltVw(@_KuZBP0ePZi)t z*u;4lUM(y}$xDXG7rX+Fyp{nSpfc`9#*Tg0pCT6@2VZ<6q&XBwcJuxX#4jmDhiL+rNcaiP`y=GNEu-WrcbgVd= z`A4jD)3w@z$qR0&NS=Xsn#~J1F!-$>oE&PPFvk?Ker8 zA5ntHBzh1EG)uU3$99z^`q0?~^b5>#%Pu(a3n-4{PpJD$eJNAOu%_@h(h(_C#G@`t z5&<~!L9Rqfu^s23(03vUmJL}kv(VcIpK`RA*sjvV0=)EN+6Wt56ar| zD;5YzPt8p-v5*et;%wO=Sx>CwLJoulMM)e5)g&FtyMIktd>AYv>wdI@DGXaL5Za>B z6HAO{SGx9x;9KnOl8IcI(_hirf54{1ZYu;?&)-5aVh~BU0DUw35hK@z^}m|yyNNAO zR?Gp1(^8>uCDT1@xQ%9taTb4V@658CiMlElric#FSgnU5_FPu9lz_D|=66pmaz=tdolMmHsEYkRI2fAz!d6mYOTlUxBj31}19l54q7vWFaxFJ&xP%&%hk=tLJw@ z2*N0;xhhX^I;h}FUD0iXb$l?jEs=-L)1*2nim&rpSqo@{3>}AFm#-rGi}&zw@%9|Z zevs@#84-r;tL!6Da1yTkVmR_+PHoBy(20|c0X?$YoqQ5P&{b_*DB>a_KF2Bb8}s2J zH-943@f7go3TFt;0wJS1&*TW;d7MHOfg`2(KbNcYMdVKnLeGchS!VJFQy$DQ`B`0T z*X+c3LKzJvI5=iSoGdGXtKx}U{$w_dYY#w8ZH4pMe5|(2#zdawt%jQN^V_q1A$%MH zidcl6m{{A*CIzR{c%#=s;o#+8VOWJ~*BWkL!wpQT$l1@bxR`h@-9j z7KS(t`cw>m4kZ2r`pNakmg+yN>A^qv4E?ngjmi)y$y-wTs#S}tO@G3<|QrzKa7@Aj5{U6H*6L>#RTnXC}569--U8P zD}p`nZAe%pgpL()y0t~T^A_d#?Zk5sKgbHd-ix=Oa^HsAP9paiYN2vS6q${#4UUUwGkz>|vrhaCnlu}8Gy2RT4 z!%v$M5Re7~Qvy1GB8kLT1<7qBDab{B$4?Jw-o1ho8m)ai8X(r5Omc~?g6=sqfG>2CAeB%8t%pmi|&e_X#hQve%-2)>oA##dr8B--*>M3D?muoym_2Zj2j4pEGO~(T9xt~FL#*0-Q?lQ!Y03xE4f^Q*1Gp;E$ZYzj4 zXGlFN{CE5*=GA18p{5HDnD>tUHK;AK2?pRml$-eDQ|8#ji6k-NJ@AFYF$@^tE4+fQWq1P;s2KlG1Ay{UR1ay>HZJ!sbZA5iai(dDS(hKh{&CH}H!SDx%| z`_$yxcfpg2&iOY~=<_kK9!xxjXSTDxUCcA)x$q9o-8`fyRih3d9GX&&RF-X99jySs z;@C&7SWkr*muF&tP8MW168vPB<8_d3+jT9Oav=~V05lI~xx%e_WTzYJig0eyo84_t zyVS>jg2*)Jw?H3@Mo2rT*+ti2W3{k`;$kSwTCTBUOjW! za|~Rnwf_vwPfBoX;1sR>5eot6VuskJ`3}m*8WR08aZfs8@E()Lo;E{ zbbA z2CYDcB>Weomgr4<6FMb%I_9pbUocsos`uo#uzq7|GYAZ;g4#?}WghwuK}-zgS+3DU zsI5{e>|-(49a3TM;#o|d82p0`COcL@Zn`I$)DwFocmqJG?EV5SW2A#dWfrZFqlU|c zzLTmqV;;G7=69Xbkrgi!9Pk?(+iA+51WyZ<5DhgPlz z2&Q_SjBHUpnFqR=kOOVIs>$T_&|TTIL$Fq9k_c)Mh;lT?1Yi>Eh;AXT9e%N*O-P~boNLwjK^k*4B zuXH7!K%Xs#%Qvy!DIUqUP;1CfK<^hVHyMCBVO8TDWvAM>EYbS}?02-PvkQL(W3~!o zx#)_}}lN-VR%BZ>cn7J;t;!e7S)2!BdABxxEy|BBv}xlWBK z%{G)M?uTaBoO}p+4_ltRho5Iq5khInQYUu(8t;Uz)HkDyke!^wn;1Jv`OZU^I=nM~ z0TD2=v3BM=_t`u1Mq%|ywSWwGQ>>W=ekU)*AJq@PD3p#=S9hb1QtArU{@tx*Ra$!h z6-j$bfzxnm8xq*3YtRwf>KeN>S%EjAlpo+r>_kE^X=#3G?_YAT-No2H#a@_}{0f5f zewaf~xs8De(c$|Ix6`PB<4{x1lN`?kKRB+~nK%Z;Og*x-?S(LQ0!h9#yk|(vLw6$_BG8rOh?&#y6=`OS4Nj((ybXzm z^?q)HWNvBq+w}wvB%b{Ze~%=7D}E0oevMx?e>2pB2qng^vtiT72^tq-G<6buzBxnB z!sh`)Qz7^ta5M$O6@2G0luGQw9E#RV7ur6IB{}%&c*y+PWv)bns7KTb1HOUDGJd;H zMZWntKoV&aZ-XrX1mJhj2eX&j?*=i0#+a}%!=sIq-kafzi0eh-=)~ zQSJ=O<#NHLx~jbVa&JM^)w2t|Ws{006*&it))-G0q&y#(81Uma z%K3!Ni`vi;3g<9{=F| z8drICUMvH|T=$I2&I1BMegw}8h+Eit9sIC^7w;W_na{_0k82VCxMpSZ9q}!E#`R_X z5%kUT!~e)rwMZU?mc} zQesp*L5X21>2QGF{jOkk-hCMr+1|K2m|bx1s6cknn$dym(%6_lw$Ig>UFy#+@@E%J z&Gt^s&YPN@GZi^|cH8qW?0V6k?Td|BGy2|9arb>0_d_KyZ;wg(FvW_Cm@tOpx6p(f zUi_-F))o*$6~$cDD03k5R{X7?p%t(?x2%aYk@Wp8WZ}LHWF_vN%Df_LYexH3UOUE( zl-cr3kuM+e$4l(djCx|eW=ZTqz5vEF8zuH0F_C7~2x*ox%_{Jx9BG1MHUA7}aR%?M)dC zs_dFoBeEGq7G+jvhTND+7tMv~dRHS^R5X%h{TAT8I#=Twh867rVMTj`6v*a=;t2jY z+ze#yE6rcZa<0S%Qv9h%@h3q3Am1*KDgeh){0U{E0K+&|p1BwZa+nH(!jS(FN&hEI zQ1DQc1=M10S3`=66`40#?h%w_Q+xM|_BgC;E>yfM9MYMBuz!^4?7%(KxsUZ6C(rJ6 zL$cOT&SRq~Ys`158HT_b5q~^~&$!;@9}ypXh_g-K>jodzj4BuLQSZazleHqR^JM&X z#<%9RXkjX=egvj|>Xcz`X4oOQ5h*0@9+BfRVW6!FT; z>u_Hw8b*0$B!y4Q9F_sLPY)*)xHj<*(w90x=&y>DP7wO564|L7v3)}B^ALTOq$Tu{ zDEB<{1ZFv#i%nH4yg*sL(0lJ8Gaw`Eqp&!no?P@MnmgjeoLFYjwJQH6r_hnfZv`C~2`>nr%Uj0es6< zs}*C8E*b7Bh7(IzhC2edYtIbteR$;*-x~~ zwBziT{&88VvYRrzBUhV0llj>#Y4H=|^t903xFAU*^slU|Tsg=n!2R&Lx*=6pLA;tG z!@b3hR^%IPIo&v7y_1S*gi%jr=6FQ!l(Yi4SGv-Br_fwNE*_KbFXwwvKeFHTE)l~< z)(FRf>TKvq42QAD5;+D{XEc9tgf@uAKic(|aTX0bonkTK#prIwUt#z^@ydYtbfhZ- zs|zDt8LIQOykt{zS?I7`^Ws;j#B0Qp9BbqLEQxnXT#T`Cf1bpPWR_S(ys*85pyQMH zB7tIoO5*D!F2>TpswA$)l@n$784?FEaVh%OOFT#7YAn4};!P5N)Qsk6m$+B5NR6pk z9+r23#KpK8*mosfs}bcS~H1g@OH1;y&4T zh;c2jk0j3Jab99S{5D#k(&^e4W&5+hq8B zi8sl1Eyk>PS1NHO?_xX(yj{kQ|3KmgCB8%AKa+UR$tLiw#JLngzO9!P z(k^kzrKop)*@o+8^T+X)3NLXnPQtqnBwi#7B*r_y4@&%?#FhLUleqVEldu@K;Fj{u zbo(T}&wTATQ{ubjnLA?afp-%mevl0om&)gb5?|mIutSUya64Jz-mjRr=+kjacTJ|- zbCrn;-HY36CEhf_#6_QN-ahxhcfF>6f@wkMPYwiAy%5V*Op>NMr@`l@!50&^XA;l1r@`CO(BaviBjxjlY4BgB!RZ4s5}lXQ z;O_uG1#XHxXPbpsAj@(nP595!;F<1`(>*;6er_84vNU*Q8hjRT=D$dG6k?o(GTbcj z1ritIEa2>SN2)JJ>d>e<(==Xtv$|OxUFK+Lsa>*sNyJg#++5po+w#c5)s9=1HPtR` zYN}tpSfG&=x7IIrEUjN%3+uc1t!u2WyHx~RzCsw?CoO4dUI-f}V>T^})HO!x5w`wj zE55jS1ugVLVfawLx~aLgp}D?ZhMd&2usLESVj3{2KTdp45iQHylcv`lwSw2L#EMwwWk%1_&s!`~=Tk9chd|0}qB_auBRU zxWz(Iq`vm%<`t`OS9fbMF-khbXa!{5d=L%bA|d=HAhLv)%j%bjxQ^PY@QkVcaP5rB z%9$0jYG?VUhAV0vcwN_Yo0&{=!?H;2s_4@CMa37D5@K9r;^w*)d|DK3s9gq8xrh%p z*VQgs*xbCNzPW*qE0@);1UG7%n(M)adMkt#u%&!9*>h`seUr>3euPZnoh-O~0opB* z`X-Y|ZNrMCi?M(ffdH5#qckmStY5g80AoUoT9(`{66NE~^$|&ED9Jh=iJ8iU1Mioj zY8+pZ`W9-*F%AEZVSSQUZ5sUV7JRxT{1l7}d65qLUPb3O7W`@pzSDwR!zU~_=TwT$ z1#-w{r#~eP9!-NAY49>R{~&!1iB!5vCC;IM--54}<8gcVM3M$1^IQbP#dI&mf0h5`Hhdxj;A)k)oqqB>^Sz?;uKDPA=>qe{9{vZ?&|}AMl>~wBRgU_5g za`^G=3~<@$+>r*K#Kt*7_$PuR<7J_d@oWkcE_=F9~lqhzh^ff?LDSkvPj`)suA=e1V0|w=8t5^dGi_x6=8k1-H^E z;2;B+ou6R~Zf)a{>nexa|2^Y{6NjD&6yC z`(Su0KAMcjWv4UKE8r7w6E*9LQ41`3lkbS}|G83+D@%>S&zE=>1LIQoB#Gyka0pAC~y*HvFi>|7gRHOT5p9yQCg_*M|R2wwHtr zA6;Mq`)&BSlKw#(e!j#%w&9Z`K48NylK3$jeyPN<=prtq2QHVm*uDmD6n>?|g)_PZ zpDJ%94OPuSV)^wXCuIw`^{7Q-YY~fXZ6tLlU$?!oNex{VGunpHF zUSq>EB(CO3DnCcQYUX>cE&Q$`6Q5_p4@rE14S!nVi*5K(i8tEt;}TzL!(DRT)nvm* zOFUx3FPHdg8=fukJ8bwV5^uHPr%SxuhJR7woi_Z-62I4mUnKD^8-A|DAF$!)OZ*`l zK1t$_*zo%$-`3giOJ(>+ZMfpkV>bLs8UAq_K2_rDZFr@`pRnO=GC!Ma_|-D}(>DA@ z8NSDc7x_$i+hW7jyl#gL?~>u4x8V;+e76mMNaC;9@JA&6x((0sJH+)z8-B0E`)s(% z&$~AKj(|xgVZ+zUboblvS#sWZ(1vf4;Xk(FPfL8jhWAMPm<^vY)nQ�JxMMs8RD+ z8~(gc1apYpIW6ILOFYXK{uPOg)B;srMRpv0BEO3@EjO8VwcDqZ;~=C-_7;cMiJM)|AoF8OR9zZJ>)SZ@pO zllTrBuG(Rr4OjAQ@83nn5H`nF@2WoXZFrO9OQ{X_W|#?vZTJF-+x3R>gR-}4pWCEk zZ+FTM$}YFc4=Nz@rTD4*pyt|eR# zj`DX>{7|^^cY53wUimw{Zo`$olUwph(NX?R+!mFW!j-?%YCEo(;hwPJ%HOHahAV$3 z?<&X5V4Of0m zS<)3q@h3;xZ38x3`6+eUaOF4kiVau(OL^ml=U@3R`E0oI@4DB9uak=JaT~7unqINt z%1>jz4Oe~|j!7-IEyEfrek0B1Z=P-&(zy0+hI#r|;!xS-}yu;^g z!>*iRPY%bKcxKb|+3=?2CeSMRm4!#9BgI90-@p*(N?fWHLgISLmaf93I#-Y4n-9|b zzm3mf9%){bqG;Zz^yk`emA?9|zuGgA3;)|erhq+VwEDM~7Sp80x2-t*N%3(Nour2Zfqr{TXnK405qhcO41@Gp*V zm;H|UbYl5W#*2~Sw;E=QsER0m?fioy2Hl(%E}pdFLNBf&{*jk?Z~ncsq(q>X6<>0Z z`Fg>)yDP$#{1{bTPREre)DPdSSIok_j{yFjjDQoC_`h1fh7`^L%-A7KDuzUY@&x9WnTweL=DnNvgg0oPP}&tFUd#-Pjdq#uV(K=pUR@6T-$u zJT&+t<_()!6a;zXZ6BVvxl<>8oiA4yD{u;Pm9Oki`k%G(zlRGGJV2MWI=^u@2<-|x z&HYLAgkP`4k+O+ueT6rq*A@iJo^4qWF6_s~ApyVsXOfJ6rC{!@F~^d3Q*!^5VQKXF}3%UWYvktecst@XRp| zGcMb@YW@j{^#2F;@W!4DI89)-e|uFCeSvIbAV1gwmnVUmdjksQ@C492WFnb?2$HWN z9JVxK{;R=%l%fAVaJotCkMRgJO5z>teuOgxhW5M+##eZ`?`0#l9`$0Md?yYD^=ca+ zs5LI$;y0rcdy{J$g5njP-FP04XY)O_cf#&O43mSi+(g#ZqMrRI zkWe6KM%XC?2PtpHLCU!-8utCcDa^4x^8jTWzI@^d${>}GLNhdV24zj~Q}WJL zJCF?D^1w+Sk8YTY&2q52S`1t6fF1qIh29aHWL<_Hi~MC%{S*xz%1&$F3=q4OW54=t zcGNtv%*<_UD~^{t0KSjoS=8Y5Xgx#81zBe9BEq{Yoa^llPM(*a6S-JvAkbdVMe1FZKa8%{kP1^eSyFo&8w@zV^Y$X1^Y#?j!-TjC#c} z9zfoMgr`8xgeXkJLn(_z#n}D}#7CA&&GXamIs-3Jxi}-i1!NF)GV78DQ(^n< zRbCv{8j8EK!p^;VFX`YIS#07?@;n0F$^%qpN+_ziOIeZFEcz}#H;(qin{jRrleq6{ zG#Q+geLl_|69;6Le8VCy(7i(u><#zHJ(q3JvRG!aM5_R#~F8@;*Lf)V520)6$<@*5nb#{wJqVp z8-LlKR=v#gDiQyjWII%%8NZv&RRm`J>RTwbn<&p{(>N;~fz?Ysr#8UhLrU54Ax8w` zU2gJRP-jkx_t?tO-U`Jnst8>$%7R0x`@xm4elVzG%cg2>@%(DFek`PKH+O2{4)Zu$ z-jlc!dlUuA`d1~OuEyiYd!C?<@E@>5Mb-Mp*nFIayuJ>`C(lG8UHWTJ;%6}S{#9l< zp|BmX-Z2z(?8q0}d-uzG$G%q4-n07saPV+w5SlrQcZW z|KpEehux@V)wq(&K*s5Mjxh&kPT_G&^qQeMt;3L{}HlS-}*B&rNQWvkGUgfRD%>wJE+9AQXEOM zl6&xr(;v~v^HaWR$Y>L{twL0EA4pSdtZeSv6hg%}QlCHpdi!rm$q&hNAv_~Pt8S}y z{=IrKWL;bPCQvm>7O^mb(>lsnV(bBB-T#SsOzr>ltVkRkHTGLvIkvUTfouW_#(GBq zX<5s2gFfiym^tAAGgO(8kB-%>GCBU^rjR%@2bsmF&e?<4_ji*Fk`C1c@)sK|7?n&L z2s#g<`_(#r$anhmJY(trH?^|t=v}<0n`7_9!`NJpM7_!BXtZ5I5$fAmz&5<8#_?D_p(kd<^8mehp+&w8Y8981xlZ^IC?(Z|Jf~-%* zK*u5tLJl|njq0f~zuLG9yG$Ml6>c}R8lbRqAf#93CBKAd&}t&P%Q9cx7gFcHT7et9>(_rKE$ant#OJ5Dv!z+?peMhvP-a(C2Sp^fnrVHz+5x>$L>D$%-VySf(E1_9w z@Y*!^vNZUeY4EQT$A9~^4!}q_d(V;ZUlONG*{-MYEWRC-?}Qu!dmjHs3jbyr{Jk_d z>yPxCr0rA4HL#-$kN@_ICY+Jd<+k`Eh3D5e(r8qNug_>bs=XC9=Udf-_`XSfQ6>X4 zEWyV__*_bUQAHB?DyiA>%@Qop>Z>AtXNQlEmbKi>wD5x8H#J3D8pS6|d>d)RS5^P` z%P4#UwQR*o@o^E8T3%njSbP8_Gt|_)A|k$y8vd;mzeAFrZ}C=s)Mds|UmuA)*+1=y zF2sj#%WE4Nq~&hN_K7K@BOCvf4=UxF7jZ5-DSR9{%T+@SMV^{HwJ>dp^&VDvr1{yw8GL^HZG$uTO)ovEWuY z8An4rE_?pJZo#empCVPaJ$zLfyxD?(0qH0{{I>;XAENL-TW~8MKDFRhK6pIL{fYTM zEe-yaH2CEf+?vmPX>+%iH<$*Wl?ES>`qNHl3LBNoKgU&y4`B;#t*^xv+{%ZqTktb1 zboN_tYxs6HT3pNzKRZ+D{?LM3!*93X*8B`u@Go2FcyZ5*%}h2m@!TZ-4&m$MbEgeI zD4+M+@E%EQiqr#&zUrU;pVuz`mzFENC>M($o0%-7!{L*6=W!rrx$J#sy0uELTgrKWR!em%{(q`03UvReXDSRr>1JhZK2VluFsW zStaxTd259s8Q&J&q5qTRze&co$~I{!pO99SQJH|^zkGCDj~iBzPXY2*`An>q&#XVj zRq?44d6B$5ZQ?m>oVXJ5C7VCnu{}Q3l)df%IR@A{<2u`xf7_$z!$*oAlo@O^$)x_; z>Cus8O} zIBm_(5X`7{$3FQqvIMp!XWJ*o2agY~s>UI>XW|I=3fifkJEToK2s`yIoY%fXGwwr_ zZ4S2)HRqB>6!!V;2_}bMeKO1oIkx?ykG$0B>3?r%1Mh%Q?=U7CGqG{`QrO%JkH({; z%3fP#9;Ot6TH}-iyo2wJm`g@^5 z90pU8-+I@mFvtnnC8b6LuWj!zX>-;TY}<4xwd1~^y>W=mn6K!A=t z(QC~UGH@ud);<%193GUEYgBkcg&ze958?m@god3;RY(QQ?PnR$iQ?Ia7Fkk(p|G9R z1`>B-tt}d;h_4u|jOYI+F)WBG5?FdVTrmOL+`j_cn3-iX!*cnNPn>aN0P@G@9QQv( z1>=8m0^~j%4}9C*KWnJI@32}M6u-whV#7_;-L_0NKc z*SpshDtwiTTJ_+Exit15nhDnY`j<6y`C5-dklqKwa5qkCKStI)O^qQWJa%-PwwAtz z%EpE|!-9*_de)_*~UDmvbc{0s-C$yFv} z72A+CBT)lyk3|7aNZuj)h9FkAJ;m(hjI40nI>)35LB1L4=Z{+5qJRN&(J4M^z8|>Y8 zW^8X>tZ&TN&7E_=JRE1MN)v)b73v@|2Mc*Q?tGy#1KPv^9uxl}lxFYk-;F*T&~NWYYYV_9}WpA9Dqr8 zZ6)|+Hhvynb4XDPJCEp-jq-`q55GngLLV1c%)PYbiz9VZcnDG+>To=&T5G4Z1ajel zf^))v+Go~ZY_)q(>o|;e#DlQ}-X9x`Cb;&n9w_Ro!kCd;QGB?#hxB!EKDs}4$4iL! z;ASlGXdCwUov)Q0T=}l5L>$|yghkI_+8s}l60{Z8539!Gcqt!#bHnlc-Tj$rEhe@< z4^;ErgOQJm_pqbjQF#8?N6y3-u!bpZz*w_-J24i|AQpYz$VetJ)))N;SEOb_aHJd- zTXK-xA_AHE&?2YrU}2^UQs`vdGY}W~M>z%atnt}KSol^H!dygT=YwUqAbKEA;&vw9#M5kCDG^xiRX z0*JZRf~@XR@{oKiwHAqb6{3=C!3q}g)lCCLvH=gKTrl4(Z}L<#-|86^oBX zj_TOMVA_Md+JlQbAS-dYyRbLu zrK%cIHVEgR1y-OZ#z2QMG>hlU?`7|RT%GiySkS;y30yd`(DifT;RtSb=kpiO9{vip zQ?0$N~k{={J6q2lLotXE-;7e~_O>3ari;7_mxYrB1L1RH4qM2s## z)xP$@xrSQ%IEmfU(4Mnm?SmV>*V(p=U5sEg_|HrDJBu|2+nRvbTVL#%T$Q~b<4^7p z*DESAGu|J0wSfD%E;&NV=3XGekG&t83XnXJCWDS?7Bm8#a|44L9Te>-^ zqA^|ErL5`ZlWD20YZ6al-!N$rPwn{ic{_v++W^dF3>Q?Hjg`x4>zeAg=NB%{b$LM> z46`A#ZSb<=oP_bRu#6{d{v)U)n6X}S_^9bRsHfK()6#bu5;BndW zvndV!_cZt@S@(82sxIw#sU^I%yicQ_Q2DWzce@3*=D*K^Tj>OtATE2lHEHlgY4GJ~ za3c-=`!x7Pn3s%{pX<}$52V50x8Tl%=kATEl#RXxrU=n$^-{?j&G>HUK?Ti2S>>fTD?rhhX3Gh}?L?2*m_8Q)_guK1_YnuZ&)*rx#byIa~)7szMwpG{cB z|2$i6Bb5uT^)h{Chmbu!=}HxkyP+#j*8hV;khrrIC#@~FNHSja--?VqKKlEmD^g#5 zeExSIm%y0&uYUK@WDx?N$cXvfM-UEf_(UOcMo@PJjnTpFm4Z9ZD%(wQkM*cTo?RH! zUkmB4zykakW*u3II+%Q#8JBZyVcULnX3)4YC_Vo{@%*5X8IIR^o^p6$Q)BfFrCTA22G_qnG1J2w z_s02nz|=_0`TVnkanYTchdu_|_OCW>yoZp05+k=?3 zg)!e>jaeJdVVr_Un6<%$pErV|!r2gK)o&3`JpQsKzpTdFavBa@T!%oIpMiD$`DQ*8 zGwd%bihGiC!2?y_{@G?m#RR);f1a0_goG%kON4ijR{aX&HJCuVFeI`V6PI z$E#xMCEo${ocbkLZRuW}C(9UO%UIRH*~Ysx~<;BU=AlUCanW(Vam z?N2C}4>1IHWg>CWVv*1#NQlQ)nh}Sk6xkSzEz9%xpJsPq@~+ej7Nu>KB2 zh?L@&>_DRl>-n%|!hB!`K+2+>;=7)zyx8hvN1|ilF5kL(v?Fqo80Mq0TFKUc5ri4# zC6T2=p;*#~51f*Gah0Qak)v+ma(w0LrSlHFD}{%p4_=m6v_uv!S+3sF$4R{%$^1ZS zY5gzR_m3AL9FBA3ZvlQ)-}weHF^|Vtdg3fN*8;d+mJ5GN9AQ&}*Yg+#*L41|*)XCA zY#Io};fuI64FPPxY(u=(@eks~T{sWv-VE3m*0_0~k_%_Md2uuoUcu+HGINIIiTQqo z@o;&}A90qKU_YMY)JlRTY$K9pfahm{u#cw%4Lew_LY&vA_D_(*V!<=ze|a|3fK`U4 zjOF6ChV*ge^AGS^;Jj~?_?5&3FT~kW)3S?hQH&6C{4N=;jN$&l#bE!Fwh{LKR@;b@ zfiFmWm>dB6ip15}S=2c&UL)B$Ok8nP1WWxH$v<RDjaWUGvS#S_Aynd#MRhG zJmSw45?8XV@Tn44gB>cTJ_(9;LuPRuz=}#oC zXo+?WjAQ7L@=3WI3HPSK&r5?(N`sfA!7I|>R|99c*2w|2Y6?ncc;X2I5EH_^b3B;kCDpzfDEr}FJ&SY&bDIs5$cOZHZka~bFe?D$B`J3<|WH- zcGNYA{qCC;3}4xLi?1xaW^D%#2tQVFW=4Gk2UU!0{sZy4Mqw@#)R}riba@@UTf?>W z%bIYm0wC$xiaWa1A`ZbJ58H`dJ!B#sO*wjr_INatA#ZuJLz+k#UEEBd1#XS_)N3;3__FI#Y{pXOu>PWyuj z&jo&76j}CF3g2J}|0N5q_84QjU$)?CFD~L|S@4TwTi{QY1;1S44F44ievKu()pm8G zCHy&-@GC7i`y!S9dn|aq1^=l9pJ2hCl{kOSwcxugxYbtIXQ5+FcfSRMD^p3NMn+3v9R=*F9vzRlonb4OfZmx8bUfDX_F(rmgxx zyT7gK2WQ#BtA22)4Ojgj`#D~!T&lnO*KM@6J%|36OtxO+okd7ztJP&aBZ#={eSJDx zZ6B2xF0YJFTOZR=<0>^?rY<2a#S(Ys^_(qTg-dp;$F#QEe>T3d)n1gMI6VDJZMaHb z{rd2p_e!2s@Ije>_L0_0#Z$i_yj1tra3_y65f~xtO%k)VHPXqG@z>diEB-SKuj}!j zS@q%nuuIx{m93cd$G9rKsy~vqr%gJWq(HSwKCtg3FYNKh0<+gWAV(=9;CjrKf7@eP zTdzklzR@I;`fHDmA=#2xS!{@TU=6nsTt;<_uI`eCyyczKKb`#^d8bnb*6ED z0ND!a*uCf5obO}n1o%bmH17A|!I9AfWym$Tc{Wm>}uh1LyWbvNj!@cjg z6UwCJ=TWpf?gy7LkHRd858hB39QF zIHnjPLZI+a+GFd~EixmJ|HnvG-=|m6^qvF1 zHYBnm7|)uaZT#xP1~t4&jrul_WV|m zrzyKsY_)<-SNO3#wl2|M*EYO7fkmfr+lP%YxCKyf(;$i++cQXaBr1G3*PinvZvydK zVB*{n%z&qBtj9xpqv4Dlb*{QY_yxY%yDu+xbYXPNwvO*2w6nKA2m7)7nB|1AvO)hY zi`k%etiz94p4gVTDdVw2e<`-vBWTl#YMlI}qb?O(#E+ZtA0$B$-yi$X8R_I6B(b9x zuKZmPo|LG9YhZz$g&k#{8RnMdb2PN=a#V=21$+0o8uX1OIawp$CRJhjRJLVQ(R#2Z zXw1mLqQlAkXGy+m8>f!O@=1>HgM6v%qUc9dwx>Qz_U9P2d6U0Sab0;yeC8nbC&AVg zkcyX{JQdRx{h|hanp@j=Kk4EYl3^x+>J~I^d=~2uaKeSv`OmQG()GQFRU|fXFbqerKK)=gKCud}x8J4cb-Wclwf{1i z|8i~PJkRltw<722Z}7YRa6Ib;#Bzkna(6`c(zh_~z93aCJ_k(5@wvy%QZ-+pzpmHj zVc(b@EChH0oeSL9*=W>u#>bvK8y_@fzGgH?U`rE`I4MeU!W#}ngeNg&`Y7BlxuX=? z4!q=0(p(m!{}JVXc&M9WPPzXSWav;g=UU0X!2%CIJASude!n2TUFg02etWu&BOLw@vP?phBI8YExNCF zZ=Q3v&=+L6cc`8(j!z%dXP};UFnH%RZiLi}xA{lqX&W~(fd>6+tZ3eX6<+6V)bgx+ zd=MbMgdiUd!NF4S0c;pgC(;~ds{bd$1lS?5~OYHV9iNhoYa2-_^WLceDGTMusOPq zwMkhW1?_3p(-12z8O93zrc zG8Nf6c}spe4_caLxyYf}G=;$ar&wE@-McqO+jw}U{_5DjgQuwewOpKJ2%$eN94=ob zUw4!hMn6IdV!$SNI!WoDA--OUEI&C4_5@R(FyH$5Qk5_XnOWXiNtqS@Al7aLKSfr5 zGt|Fo8>WtmB~G6*Mq5j5iY@)nrvENh8s*X(7nJMV_n_w-?8DmGQ{)lOeIGP3f@9Io zjYeW-C)!FpNcDsZ$yr|c&`xv8u@TnEL&4icII)kH(Bn^Ww8yQG8uXgc@B)Scukm1C z!tE7q?2#fCp4nG#D0j#D&N{MNuXLwUMtkO7Tljt{V^|Wv8QwS*G4#`|aUc_B`uZXL zAbYI6XT|nq$BvF#IY~d%wih`$tL-TMx}#^Ik64Gh?V_u8IPRN2tbcg6Mtsj9N+9~b zzqY+2Vt<0a*^wIkkfN@|j=EQR+lafPlSii7&@~Ky*_nNVNNuRT^n=zE8@hCBdhUpC zC_R>D)y13K^C%jk2+%)|BK6`Pk%?^WfgT{K9?xvYpnvU9i5j|MgJZR|h=e6r_BRfE zno#F{N(h6H_u?LY{2+uvd$>od*evyd#376h?K?L7!X4VT;lhxLe_^lo&0)_wY|p(X zg#UM2_-_q+?$w4r@6b}=XX-DDx{7`3id?YjWPS6I-M#zH>P?*0@z#x6VDqybJ!VZ<3_Xw772Q=qvuBLd-#e2=?ql{aASrCgYgiX6}|y7N8*8;QPuH4&S(0eBYUu4 z8As=ZyHo8xhyf!;o(WHbe(xNiZ_9e334N7E=qY^{@5t%@nak~Vd+=ZW^*Eg_7w$do zbg8w) zsh7BMd54F0o$VeL{&SzbqZSOO_m7{k?l>&`|G=}Ye8bao{fqgvhqvc$Us&eBN{B%$b=pXXZ1Xd2nZ@ z-Z2>!jD`F{i(g=+*xD7X>+pjQkUqdP427=?ADeC?`=c_7ok5zi-|$0HxJLs zo<-A_)cm9;$q#NE%h#NW`9WLKyfo)Y%}?@Vg;G*?Xz>u07SE&RC!Nqim0Wb2hu;X| z1E=I$o0S~~zq}2Ia&}e*?fOP}lFu}66CoHjr(!PG7D~g$^w~5g%9B-+T5{5qs8o+7 z1@WU%s1WlzmH5FCCf{L9Ova9{P*hr8wG122)b(|2(DLTrqO*wj=K=0w{zXJ1`M4Z3 zb5vHVIcMqWebM1~Bu0akXkp}I!5S3H?5u1Q%bd)H*uC(c!Qs9~;W+-hZ^YxL?_}jn z^OG2F- zb?n}qiNc^+b4bJNLHCOUcJJG-zw?hsBO!G;JD}@S7F0jRGropAQ>$Y5491ngN?oLI z3bTmugG3KUSPf%*QS;kwRnPflE`f4Nmq*Q#s<>6TFE#KmXcF;4cB$}5q$y2p==qj+wmKj zN*bVDXsEstzeMuf3!M1)IU~v5lKUxsgtsy-^6X+fpWm32Jp;Cf@jNa{u|Y2iy@mgt z@dC!hKJ_pjV*E#VCihqTNS=I7Pmx0LhkPMi(y43_V6w@I{uE89Yz=P5FfQi~Df@5P4B=b{&CByi@E4Qdhm+thC&9at z;GR&~007noaloHMtv6W?_!>?M=R-g% zZUk0nFd?xaG7&-~3lU*yGYU{3>xqD$n4F(1Qg}ii*Hzcm$F_C`1438TuGeK1XHypR z`%l8^s`Yel9W@=6$WaGsIcDAjx~!sxy!dH~+*j#o?gZ1Uca=1zSy`=W2R*6T<*~`| zWjE{Ufw}R^D(dQ1RM!R95x>>6}H26R5$o9cC4z!Hrchy)y74d!mpehGK5y(8R-pUmmqXW(Ri1z(JQC^?({ zJ4tZrZwft47Zg4>F-{kH7Z?1W2EDl!;Hzjq$x*x}{(XKQpKeiC4z-0{k99d?p(F?@l8BPD36uUBiudP5hiB_{Jpo{f3#+? ztI+3iym=OVAE%Sbj-1e^b9qeAa157oEhky{B&N@|@B+rCTKFQyr&+k{V=%+QZ)5rb z3-4n2Jr>^2IK%Whuk=cuC7%huKtNpc_?~b{BSDfb!Y?F%T>)PSpUn4kDdBswJ-=?0!>;GzTME#uteEn_-_7Z~(kC4gOt zfzw!;xN-w85D-_tfx8VnWZ*Lmyv4w08F;IKi%ydF4g)VV=-Ul^wt;sVIF0#<>oRb! zfVlPCRo@?Op&OrD%2A)R-0FLmh)SdpzH*gt~BA)^SpJ&jQ82Hr&UT)y? z4cu?wB?cZc@M{db#lROBc$a}MH1IwHUu578ZeJ+9iw!*6z-4TUyz>nFI)gsnz?T?! zfq`Fd;3WorgMs@Ee5rwl47}99TMV4Wdc~FSI47mc{D4_*;O0aFzk!zv6I^Ayl=xH_ zc#A>5%)na>ywbpT7a&^FN&7vr9QV?cmXr(w{R)fZ00BNwsQGRwQv~+Z?y0{PA84Ok`q4pj6Y=I z1&p^_c!=@WEnLRIGdLZ>U&g^DeS+sx=LoLKqL*>-do4V~{g!M_x9|yZ|73!N%ec1G zBcYdZ?IjkyjBCr{=^c;z5qpQa|9I`eMYBiz$YG-tg47A)YK|EPOe~|3(baH+j}G^~n;Y zf7=92DE5HTPgToKKlM!#<$oc6(6ZBIr=Qw5!fd*74lnf+B+BLSRW8&vCz9WLzNQ$% zib3*|?6&;WR#5!;_?fP2lzuwR1aU9&%eBV9OwtcIyou4hgcJO0jM?RPg2O*%WsJx# z;Tv$1DE;M}pb3Wll1fPUG0cGEvEwGM9rWQCE`#4UXe@w=#12p9%@Pp^*7A*07e^-v zXE;0kGzO3;{APYB*kpvITRS|4IA|OcgCC#o42>!Iu1lw3&0b#K=UB5oR8&Hy`?k$W^)P z!m&pcmZEh(LUY!!g5+Rqmbzocg2yN}>@v2GK|KeW9%xhQ!BdM19FgOZm#~WLBOJs0 zJLm4TLz=JMfg{j|gx@O(VY$^v?AL^y{!`Xxc_Qs&osUNRC@-ULwdHett8cTH2A)Acf*k8>)Jw}q^&09~$;10HAFfqBij2i&1s z$*0iSmN_4f&fPa*HOQsSS3MW{IA#411en@K>kyo6!^7P!XWO9}8XbMWjR4g1J{!@6N5)09~Vw}33013ZFrW1D~#s0Bg)_@Q`!r$TI%22uIGaf6}k=w z9zgNzYf%}yG@c)d_rAD(fZ0q^kcRK$Zg^pIbUQJ~BxWx;o4im66}7X8_7d-HY;j+Q zwR_hVMgFNac!TmmE#8^tjn-xtH?MjYOBXiX58+YzbC8j(EhtvCbkF1ZOZ~Op=5OFg z`7X8L999n%H{bRwExp3=@{68zbT2^i>4fXmI4NB%`v{%|&p9|`V*3mrkIg|ztYG}h&a~gtw!H^jx0pE;k0ynrL zug3JlOWWT&+d|)jq;A(Ub$Jw>-ff-Mnj%82@3eLf{`Fn7cy7^evBqe)>*ZjNC7jP4 z{#vS|;Rm5lT+T*XHBsn#tA1fo^VhSlZmxO*ixuCa^@?L48TPxQm1H{U*I^e3B;DD# z44Ev+FNS1ef|;Q8j8E-3j@&_-tHuun%er46Jsa->f1InbH~i+=SPFuQln{ufHkwd8}CavwxHvLo-{d!GtbJh3>BouZY)JJ(xyctE&+1cccpxM!> zopPE7qWvyKi}*r_WpyT4BT#996cqFQs)-}Zu~^$>2q~sdj1~6bv{1l48I0Q z$wUh1-0gWb9SdG&WCj1&b0d7Pl=NIMJbPm25UM>rA0dal(fn9MZ{bxTnQQPxHkxz>vAJFPKtoJK}6&>*_uj>Pxzf9?K?snq{oee{#ygOr} zvvD4vDaQ*!1GpcF`x$3C8-GDLfZS6$-Oz~Oa%^i?jP3kSrv-=V7Q0V&pMs|%S9@UAJlZqyLBs=IFx4G|9UrG*-@x{aV%Gs@_%2W>+j%J1>)gF$Nb^EvJOAWXhYgT9_e46? z!r~Cbbc8kxIn&ux2+kvu9&buF z$>Hkz`VMc(i|Y38Zs)zUu8*1fuoiAD%*}D<=D!f5wqa;@{)z*P#!{v_8?zv!xAM}S zXJh(;5>o*hX5$W99cpT<{M@H=zVTP!x{yo2;kL%!St zd~Zt6&y+X?P=+1{ZsYcbwx}#6sjeXyfdPHO{4_Pjr z0f~ON9T|beiezVsv8J>*@_V;yU){OAH^k-f=&D|gwS=f2XnCW>$i*aC4aq}bO>us*h?#*KRHcPcT=M^>Q;?(o^ zAQ5_QSV+0Qdz?yB;15gH-nMFI1YgTiWx3Rbt=K7n>f2Vz9+cRT`fnq;(HvcqYw!B~ zv^+bu#>>+|5jn$jgpq6Sy7zh?pnew?ZAbp9GMzJ8Qa~AwgLAI*ME+v-H*pRPnbyB! z`6Kc>Czjti$Zgb)wvj&9;ovJ;WU{Z&C=Wzh>WTc>6L|$Y-u}*A+H)QhTk79+W^aQQ zr|#ZLJq%QXAF0colwrl_e?YJ&)!H;4)+Z15Ht$pq*cJfiQLXwlD$LaJ9@oe9>x!F~ zqZe|*OKtI6Ma`w?v`~gp7vwjPTD8L)!4vJUvuU%6!!v%kZ~ClMXXAJAh(v6>4_WGQ zov5FPQ{Xeg-6=)X?eIePu0-Dq3qfa$_eDCRt{fFs9{KX z0BhH~(YxJO-x0#Ov>SSR55@F{T7MOJ@F{Qetf5HctwU);T8|6IusFYY2@0$C$H+(G z{}{E!@feW31yns+fzp!eg$R7-7-Tj&ZN+#KK+n_>!mQNuU`gwTc+~C>dzFz*-&=6G ze@Ngg1SlHHWb6Ovew@gA^ORn~t0Wb*2f5Nl+LabqTsWn(u(3UO5MG;xBbq{2NBt7- z(~xk$fu1)7EI>((-dhw+D;oEqcU)hQYj5C8kh{^T>8PKCjyswG62XV+_**=p<67wI zbT*N_AiC7vw^=Wia{d9`suQ?A+YMu)5(uSrw(VUEzXyJV#4jvvPT%i#9ju>=7Iq0z zdf40i2xSB%dGvnO9ZKKtxqQixASJnm(&goJIRaM{PU$IZd_FMN**15mxA|t&l7n^6 z>TFg*sQiGDTb7E0_Y9i<=zRriV+&n9!Dp4Pv+)rKgUliA!K=)ZIM52ZgTC^9uWN5z zR_|G=97z-Q);pCZe9*f!RzGJB#g+#?EG{%h7zU=L;vEsCIBpv@hQx;pCKD+;#{B^0|J3})Rk1}v5;rP3Qf z7dLMrcF@kaeWlv@v3?hz?53iiBB80C&bCK>ghw1ySP0`&PF*KYbMR9%b&JUH9(oo!1}VZkZw?#OXZ^R1uyT98^;K1wZ& z1f_NftjbRmJ*D_);6kK$V2E>56c~DXWUpYqGP)n_L)Qy8*cxO6Y*JtiWr5%4o?Zky z^aI79Nt>b0`mbQuZe@ki_Z6W?NB365><3vEVD`!8gccs0L1F zl)H?zIRxgY(ugSdDzf*Qq4SzoP!>DCc@Y$%_khZGB*;xFW2$3OB&GMKtgp%Jk=xE+ zG~=y^k6J%e4W%&6fs^h_v9j9as4?RFo$g)rcyS$p7l6qcDr4F zz@^s{Sv7t{q3a*cF!dvGmgCQ~mmB39|NLg{@19#*P=$6zudw&hPfcOhg2;J*` zpsZwi2WpJ#m0-7XcS-ui_fR^~H4VPpaVUi97m8^;X@Fzl!=@)XJ9R=p73F~=9#MS0TmE9&rKE1Qfb$|1v^ zQTR01`)l;4#t)h3Yt7Dt2G7?5you0s^4Gy9>lW6|{D$y+%MH0k5#HILsf z0e`LorjI95zcD)q*3)QAnx9h{;%Sc9Gd@7>6{|Gp__OBZn*&FGL97PXo{TF&( zj`#NwqypvGYawzhl z2RpUz#Y3c1jSIj8slfy6_(OStmWleRcwy{vM~+1HVvNVR@c`r`z34sF*>*h|;8&gD zU4SCTuyYOC?VU3Kw!N8v{CJ=hGSaSB==MLLt;yCrWD$)x z(ntsj=NX^JIZOFrHzLHK3=@JXBjf|o7ro7!C|lL&76l-_+9Vx;EqVTCt8JTTt0$xlCh0@no5z@J2Rvt`V=S-xj`!Ib-Gd;i1G*JAR4u-!JD|Gj%ZC3% z{lzf+v;`6OBlc1kv{>0^-4DHOe0GA4=!BE4eyskZvds?so>~p+k3P=*(StGnm@L8F zNHO}N=#;8Fpp<^|i_}1TpX?8;)j`>KlV*#zBOvQpytR%i+_&!?oITsJJGrx}inVDG1J9i(} zlZK&I4IqDr!$$E;>v`{_HN`zFZXjn)- zm0xpd9V{(|eieD-Q5l2yX_c#fn3b6}8fQ_CnWMZsnR=e+-OT3&Vy5^kLR?p6Vl{2X z{LIu_X|XAljjSo2Xwi8^Fe-Td8%U~%*$LDyZ2K0Awra2F@lhNB=;o! zA-|KXDKEux=~+e&&&qTInLP+mYnN9szYWZ93zgqS%Aat0DlG}tr)zjJy(&l4ff?nX zy^q7Gy>nH$qcjtjJFV#cC5q9LpmM{q100TW#L>y=C?z@Ld4(Ea))93^D&^H56XsQMCQ2r8 zUQrxV)A0vaL)Xua6#al}$r!#Vy${nM;&Oa@|C0-IYyD#VU5HHdkfN(l?$=oc)T5 z=%EGc|H2WQ|H(DrG-ttF1AaTp@&(3Q_*rc9`Hbh0U~tM#<9a!M#K+HdQQ2T%g^a6- z9k^Hak*`EwJ_HYN$|mYte5>aP75prhL~GB4A} z;6DdWYk~Vt!3~_M$GFlPXQFtY2Tt_uu-W94t;Y2g{1hL?m5m10i(eu>$CCBpPw^*9xY&iQ}zMZJ;LV<1?&AW zaQhPD+@uJpZIB^ zIAJ6kiLKVN5k+OaTD%h@hF{s5T3#F_XaI}zBx|bbtC7(9KyBTifI*Rf!VpdHB$C)7 zLXLOU3bm4q7XPgY>IHui7|YNs{td#P$gz-3FLx69hLh-xbzMY6>0Vz^zovH0niVh- zSF??$3#l;PI+eTGz)2+qmwo5Sn^aQp4-I;nZzQ;%O&OWR(+qqz+Xoxp&mC@JcaA}S zG1~#ciA4Cnkp!<|J3#cL+Cm>mf~%b_L1**-gzbQhe?xsKKAHX;uD?Y8MI&CXfuC*Q z^SEBy{GXvrgtPHkTz_qRF4tc>-lYa^=3AcPuIHt3lckVy3zzmUVBvYN8{~HA3)()- z%g@XvvA^Kb{*_p`w13+yT-uLz3zv4H%fkCu5AryEiC5YKkxOuC54KzM(jJW9exlGz zdoanur9B8(xU>gHEL`mSG%6_0Gm1m(`@I$}c3kpLG?QdEh}sX!mpqfRS4{MqlNh ztBE`&om1TUB~5aI^@FNA-LiUo=A7c6S@BAQ%uXJY&ME%9;is@%`7w_AM#7V=G@ZmR zSL$!dy-D}f=ahdwhbO%;T|0-bVZ9PR$v=6XiyKna0s;8C?Oc5$^^@|SOud8`@kn+% zZVEYpj3!(Q*Bk1#QM+V^C%#OAySS4%v2R(KV?8E4pQ7PB&C6VGLx>$-dJ)(gKuwC( zXHTd}uY6X8MlPK?Re@74yX2Bf)!pZx6FXsNJY5Cqw!kq8t*Cw0aCFml_+l&NO|7`{ z49NJ9eM@N1{lJGu+lVZB=VSPHZrV!!GMiC#7Gpa~Pic3(h=IFsdm4t~JecrB&-Yr- z-?yHBU_E2A-a+BNV?EzxJ%2a;tmb1IbAF;*N#rT*7_Ps&y`wADo|7AXdtCUF;j$&N zYM7ChZ+lY?40NfnTFi!+*cYF(;>EM`k^M+qBlyx7_X&KgAM8KOdY&@)Ir0HMMu0(x z!bd(h{JyvHIg=mxcZ+}c%_}3HL{3CL_~_-sZ-cmN*j{g?+LT$xZ~DIm|8C14BbJw$ zY1ZX=iZ|Lut*x&+vlO&EOF_%C6tp}`LCdogv^+~e z%d;+M+_*=$tFsn(rBOa>q@=#oSz>7)@qN>g1+!4&cNmP z&kp1|_Z+~@NPNw7dOFMsfw5$a3!6xM%>U^@IL_u((GH@GS0`T!r4;*EuEnZ9h+GKfdW9kQW3;!HbLn_8f1;MSa!Whw>4B%p_O-ruO-i zKfPZU1it`(s+;@OtZ3|fuf8K`Hb#zNA9&=!rgl)?Ivm!E^C$Q>k<3U9H4 zKc-AkaxgXi_}+pbeP*Z3z;^{-_(WD<7(OT?M%b~&mp1&BzRFOFdwb&Y0U~|E2O0_o zHXSF1OzFhjb@dI0sENfOdL~31;qFnGzOXJ+#}WcDealwasUfNd$2a{Lct&6QhveIixs)CT_SPFFxgAqLbt^rJpiX($CqUKbmV*xs;2N zNLuXt3hkkM$q8HrGePwqW&-JKd?`3ICNHtqoGu!qyQ-YEVZev(yZ6$W8f53#-Xuwn z${K24wEuIe^eAH8mWK8`h5MYq*)R<4xT7T`XCu|#@QH!IIg|u#U%izoV`!rCpUpft zIeq^PJlMa z4*`UIy^{>$6B#qh9f#kJW`$p)Gl~0 zi=r3?wz_>}{fRw$E442Fj^mZ^R6Z156-|2ziYH~=*;)xhfHA#7Rei&Iy(*_x_-Qg7 zUs2>l;gsja1|rSMF6d*V(mQFoMqmV{6UO90rKS!R+T(V0X~=L#Uh4K?`YIN)ggzOE zIny|tA@~BmNrtEry455COfCww;;DBhR~O%OC0-yK0^*)bOdws#n<%x61!Uhz|Nj+z zyO|!&KhTq{7XDO@G5!|4nsSJ;rf47xCIn_0_Rkkl7E9@jFS3=0%mxDAl+Ex69XOXF zcGPkGO%z^#1K&#e19PI6UmSvQQ(e~#w1K)e86rNM9z;V?qc%Xo&OokPMN&T+BDDh7 zIz3pKb@{5Jri}D}A5CSF_VzCN2u7|C#)eP&lHp+RdUHAa@U}8L8l+0{3xjtM!ycexs$xzpa>&Bqpd&oC^TJU{LFD*z7cB}aoXy5Gj z9~8+$VAoudGX1)Yz_1?hbdWxw07G84X{P$buL4+0TVu0{@GB5d(Vb0s?Jr_sy@-}LO@`;fRm7tHH3qf__0 zA5RB6mny}tXL7Z|i9e~@$mzq^3>hRpYtc<=Qgv~A3U&IFTKZgDABF^h5v&9uJistx89>|ALq3;!16De?sTCgK z11WP+u)YXZXi2+-L|Yl|SjY|AW7M$W=)=R^;jR=kF1jCd=JD{Gn99{2-hZWgTwh?B z8$N+t%z+7B216eDB{dBb0+_T*v%OXSL>sm7NTcp2>ULLpx4oDcj(J*t>PEPj5exqa z4~hlqBjs-^o{1-P+_67Qah&(jF@zeo|KxDJVWaR=eWv;f;hNgNeoC`{plLs~XT(a| zM>-=*%QQ}(R0V2eB9`;nHkIax?rVuE&B0p9PjSlIX(C+weVWtv(I1s)zKBYUYCZIt zQ9dV1wSIIk+PA%cOAdEKAxA}LW|$V0>a90g zm!Xpu=SDd9G@MO$seHzHf!yQ33M1XW=YFg1Unw<=UaWiRqKjv?hr7DM?N^T5KW=Zz zQCHvBa=2I0JoisBlq4)JCboMFZK2dsQ^5jLoi@E?@P==0SBi zadvQ&-8qIn(Hbx~Bfn2h!dRm}N1DQE4y0iXFQ#}Yaisrr3l@9dMJf$dX~m`ctoLYj z;GZymF@XkQPMZ!$Y`xGxWS_1cV*gqHyh#+0&OuYEL+|B%;IQG;51pk$5V1occ9E&~ zcQy2)eJFnFc6vWLssOBcdnW^ZNER#BJ5=v7-SaUyk0$0JF<2F?0%&`h61Z$38&o7j zB@}H6+H9Rsin-+wq_hD(Tp*h99(lv3{qb1!Kd53!xRMS8Me4kPa%gG-ESvjHpMB@zF8z zcYPG;b6y=EpHq3^?rxSJO14B4X8^CmUXIhBOB-i(~tL+8t5D)Cb}Ub zGQTD|zsehat~BDL^-R&J9r$|0>7XPb8Jqx>nkLGw&yf_B4AKyXy=Fc^c{HHUs5-aw zE`_o&Eb6Btfyq*Blp-7}8P9D$C?Qaw1hIM~IROgVf+#`b=tk^>z@rYgads)Lgh zyR)si71>Ff2%&c2&~(p1S~I8D_H#e;q&!_yQ~qPDis~cmhU!1XM2h#y;`U6o4*FC#qiV2}!#j7YclF3WI^M`eS3Bj` z$HRJT>MCfL>tl>a&7u)0=gi+=5a%*)v_89c7~YR&4#ndH+L{Mzn$Hiu=iI%3Pg=&A z=Cr&OC!ojU_e57_c&7iX0F3IdbvGAc2Z*;Lv#^kA7JV}6oZFmU>1^9f@uIb&neF$^n@k?>ZHCdb}&`#(gLsRwI62h_9)VYez5fZ*x+0Mb`ogz(->f ziqzt9_|pDta1NGbdLun_hIP90aRPD*ej+Upn4qg2L^+3CR;U4vlHXi$v@271P#8>Ok_`;7jO ziEi@guz54a2Gs6naeZVv$xWI)hQ!15hW^Heu(++ zEnv$qG;ak$kGi|59l@!)<#S#~FISQ#Rg0B6Ssg*nC)INgd_I1y#Fj>}gdf=r=~ya$ z@${W9AJ)dj(?sF%M0R>`3S<2%WU@41XMmClRe$Ur6&R1+&uBaUX}pk>Q`#GTj1@#H z{2qIBcq~4mGwr1jAC~;7_#*oeW3%^NtS}B^bm>$TMEb*A&=PIrP)E;@@So3i9S9ur z-Tqov8tjcKM=iiGESPPV&qykNjQD6QC!W4jW8bUn^u%dK>F-;V4LLf&YP>XQ`n77^ zz^e6F0M(weU57?J!Dj=qh7gNdzN`RBO~1;a)Ko8xGZdAOGpTz<=6WkK&#roU0VT(Z62PwKDu z_uK*#6(1im@*7Hx)U;B@PFG)4>PORi0V#=RZ+d|n-v-_ITBl1Z1Tv&keE>wNe?+11 z{qaJ|)!6sPP#g7P(o~(~Z;^xa4^0HcANvmZJold>ot@oNI%(`5Guw;`Lj8l|>XU4$ zno-k=z|qD{#ZV>Hzt)Dp)wB&w%er@Cty^q-!!FOuq!=fo13`ne#1M(1L~v2k2hTA+ ze0`dQbfdi+L;ZN21qIMw{o(d_veA3u*SkL!zZB7n3G+WI0R7bZPWnj|313PnXGK3r z$|?UcGK5o_7n@nYA~%8yj2Dc^ds$d@pRxWn9%CwS?mmt=e7{h0_@Wo9<|ZbumjTgN z``P)l4j}%{J=SxZ^}Jg@%ea9am~`p|?L9X^F^$4TKF3Q$>sM#s+|T;pz8n)Qu>8!}~A^y%*RLh@8#WU&S#ECs{tqKS4Pu2qXoHx1}ozA9r#%RF=HI(f zw-@@Q58pM0Dj!GB%E2lv)q6O;I_o`MFwST6$8_zBm#1{3Ft({WQMXQBj3nTDxqfs; z_aQU*Tl|J&35#6`F27fd{=OrV!qKXM`OxK3}!n^V2R zbnooskD5K#Qbhc{rRg#}U?U7C4ENJC3te$@wms5H_u;NS@5B?{<`$akuJqw#c1WNv zqR6#G7g5sG&=Hk?Q#M7WvqJk%ltx!+M$hvoQTpCUmLD%VTz)5Y*Nxgm{oQ!?Fpo_K z8V|DDu@1nYKqi`fr)Mt|r2sHS&*R10V(ds4-AXeJoV$NWEoS5peP$VO(r1=|G-uOH zq`SEJLij-S)de%0cDLfu9ld%?vqd)PDX z+yCb1cjEcY+us}*NO27NW8}k*gQ*kocS@wwyP~~g$@J0Qj_y2cI2!4kc;HZX%7KpV zVJq5qrD3J&-bg2+xkqJ-isyr1Q^(u13*G=W&_&d+)SJR5(w!S=(P~lj+Uy7>jx0Ku zj(7GHY(=WKrP>!c_R(H?H4RpHD}Uu}{t9Rv$J4XQgV!ttE2iq%j-6AazC+~^e{*hX z!)zJGe0_~5v)9U*&YGbGmEqUfS2z`skQ8$CY(t_v{JK?RuU2%H~}5c`~Fh5uY0 z`nVuCdd8eUwiz`-J8pjsM>#rf|AhXXji-Q@w{jnkL1IVI)Noh%jB;nwdw4bM-518j zuBW1qe?Usp(+!N~hhiJpw7@tu>7{1?4BSzrDt1gyk3k^W2Upks*d8}(kk}J_fC{}Z zip{XZat(Ed|B?Rn9A!B$6e}Bk@p~>R0Tny-8bJ~HG<4g+Aq7Q|7lY`c>oFjAXduJc zI3CIeT51z~P0u$x>TyjvsQ1b$YT2TaQ!8P=y@0U>}yf;rh5KN_p03y zVYQ?w4(Du%Sqp1RT6$bb+Pj7I3L9uCA@F5~^6K%sGE_2sk*F3^eR?vb?Rk>oj=jGQ zj(>>bwAnqkk|K+K$L-gJ82VXAX^Xe<8>N zbESqmb+Z?Bbl2R6wl^x76ie@I1!%y@vPn|>dt4}Y2xSkN3M3w#BQ z0It8L>GvC^_0Zs{=%f3wtP517x}O4}dw1wlr1yTVX=;F6$%yPazAq)vdFa#N42;#$ zc%<637LC%<8}ZDKE%AhisT%x#v&W3CF!Ba(I){iQS`{564_?%Jv#;fGrr#A8FVd_^ z$fLKW6Y{_nutQ)-QXYKTjD>hdcIi@WqJ&9;+>vK{f5`Rf2^Auu{FiEJeoj&PB5H#^ zPHxXrFl@@s#MAlF?=`>2vnJ_`q$o58Eoh{P7)hi(y9U{dxIMT4JyZ$`Gp&@p0gKwG zK+(g-L>6O3L_uJ9e7?Z(ndt?=KGjF1y{nvU=RYxOB8jbP2#@?&@5+x4DIf}^ol2>= z8;5sm$|c>6i`g5s`~?PzWQ&bH=*guWf6h)hgpGvHDaPmH-VwULh4K9T_1TfV*io+2 zH9Yv9?yoB?0EhqWZs37M*NzP=IrYd*JI~GOFD%Uoc(Y&=V=kw^_Nv$e-wf@KHV(#4 zp-pv9a%c6AoHDNesvm4ie#-+wlT+##o}qN@+e%-?28NCtsJ}T){N815^x?g--2y;s3 z#^e>uyarjn1RJ|$w$j}o^lKQ`y_|=x^<@=fvXei$DQM|dmN)vXT>oi99OX}3bjFsB zT;Zdy3uF2~&$)gdjiY>SH@1J)(y@WrBg_DfnvD%9MqcIg-}qJ2|Dq?CTyaVNiq(Q; zS@n2K`Ds&f{TWK1i6*!I`sulyHLSk?))!YuSU>dk4A1&+(6gie$J=sBM+_fs@EaRA zEvC~%le4Y(=3q>>2!Y!)lQyQ0xt#um%EmdSMK{L4e|1w!-Ubh-Wo z$ln!)PN#Amyz6df`L`lt0~sT2207)S({oC%9a`wWDMkEp?w(mWHc+bcI;X$rrkp^r z(&?O*nU!miCyv{``jxXrkIWZ(y5{tMf3*2LFpycFvw3C}VUEC8ou*$-<4oVU{`qAW z^)J5M#N|G_I2x7vMAw|sVx`kL{ioNG|JcBSK{`TM?vsmLbRAf^<<1vx-ZfL*^Pi*i zs~L1#*j|3g=vaG^Qa`q4!P$-@H(y-%Wck!oTn7d&xQpn;p=X!kM-qM@A9Ri}`j>Bcah ziT5qKVT7S)BNODu;Tw0JV}{N350B}ziL3kdS64i|VwZ>Rb8FfP2L^&)6PldTETtnk z_g)RV`@?Og$MORdQO_XVr7%j7R_CdEdQx*DQHXb{*!4hLvC0)fKsZ2jtCB zZNRXCD9)W4>~b2frbC5bGZrbEaVqCWPH8&p^gVZz|JcBAL#OvBeuR@N^p~gHaq}*> zei|6~LjS@%N2uT{IsI4NGz{s?30ys>|8dsnQA(!|Cuutd22O=edwj&t5h$QRzJZ5X zw{jXiRpa`vDI;ulwLi^PLB;N8Zl7+*oERx*W4$sosm`k zt<5GT_m0v6+CJEFY4sM6$%^ndKCAqHcBU}MDfPtU z9gB94@SM^$C+W1%|Ep_`zbe&H{;ejWIlq7L5=C2f!=haO2&L0UgFDY#XY1Gcl9-*& zX)S^7u8;K-b4rotcg|ihFz_GSQdB+uSFxY$=S2IG(|_GHV;{O!wS^`{POPtkKBeeZ zGQyz1(%MQHj)kvQZ8r9Y^A&Mtgp_Pj@)DA zaW>kF!LU!Vq zxjFr-Roh6H^@VNe>vWfktuTfzS*VKF$eHBN4guXz> z-EV4E4b+!j83%s;1-Z{DogI@mj`?FcJu+E-2r*yBZk}0fLF#dA88Uq3MLZ{Ho;pLrT44~_h7aOanUO2_ua(k0;&U32>9$NK*{E#8~&sM~q| z!1UYC7&C2DOs5BhD-(G}))Ah?{Y1x>r*d-8wiA}q=v8%)?#bmCZTmWaJwuy3wtsQSI_MbY9q!Y6fc$TN!~ehZ|6dOL zUk?25$bo6IbUORwdL=*a;q({qHN;m(!j1UhN&8olv-jf921a|7lf#EmJ=wbOXDa?`5ktqT9~cP=ikPBR1pcWdAQ3bg%P$ znSq_)`%wl)`x=w`s=g?h^B7aRxdA6xrZP6(pz|^|#=vC1;S2-wGu_z+*2tJC%QnWo zY|zn$4CKzy7bQ!30y;Vph1{k3qUgF4(DgHh?+40J+GKy_2Mug|s(vujHjS}TgN`QW zk(;M4D&F!0VQD@nxjgl+^K>&~#Rhh70&E9k_^zfL$@~ms_Tryl(9K{v6DwhCszF!9*!2e1z}RI5wuLcM$6FaQ^L{5|rcNG6fW6At zmy9_27|S=Xbgq16I>s<|jzKqxvAYbcfUz?TY!PD}1}1xK2Mz2tru&+KwJ^4fF_P&% z#`Y41qatvAhZpB0%*nhB|DMbubq_DHNu5kfdvQ9dvhr@mxfEo_x*4BAIF7yur{V~a zjJcUh;ZHi0p}wX%9A}U}9AUYPnQ6;s3`-Q0BRUUbvkYtrV{XPswpENhM_B6Gti07( z86;aH<7)`7AlYy*1m{W|p$-&#?b^@`odtjxk0vtjH1e z4r9D+vbO!KZ23flBL^zLGY_|87*}bUOL1PS;#`PRAojtZ%4G)Ati!!N%K(RH&{+og zsRcO8040S33~;~*#a+X+W?tULSTlu(Bf1vGC|}6Y^*+X~BS4ow9obSy2cb~Cc!vE| z8sNV%wHm2F8u064zYB4%&m&nD^Xq57DKS5v@*_FMV8R=@WBQ`ny-AFvrvOy(@Yyu^ zI3?qjC;&JMoE!!KoTJ`Gvz2W@=lwg=yCkt;%y~=T-Yui8nwp%8MOL za}Ci{P`S_vEwgcaNrp;qC;Q`DEa%m7l_t`Sci2yrsgh+*Rvv=WAriAQuTfWuV>D$R z+-&+&bU3;Nb>(V~V=DWf8}lbkM7xMz3HuGi{BYiiKL6z>NbqbG$=pm&Eb((QRk}8F zxQ(%Jskb6hPbOrea^24UKZyAY-x{#eC)?lvlxrmlO7E*2=G(C_*Q>lrt;D5JWtoaQ zeHamNyQR+lQChC@opfkC`(wfa=ZDrI(vt%AlR8E8ix|5oMz8gX+7mzf{b$UNjM!Cl zAWp_SWyX}rH0YcY(tCZjNg*Bmqi-G4K(>X$ETQ_9iUV)9P#^xK?-Hb^an+Lz`j4dQOqdmHjEF_>j{9gDRG<}~zqwL?QU6UoF6xvY((K-QUdE8q)oR)P|vns8YxI zxc8T!mZmO-p+@DJlbPD7P4*lrN{Ztd4m%F_!MxHapXSBRPlCAN^a|CW!blbF+y8-Mc0Md1G*E62aIO!C*RgBB~pNwaO882sgk@Mdf4>A5_&Bn2l@g0nx!}zZl@3QFM zU|i3BjgN64(^S5d4ABgP|5=QO7@x%a>DX1u=N*hc$T*E*5MIs&DEUw+d>Aif`db*6 z_YA3H_b{H%Dkpp%X1s*)Jm&K}<9^1A8UG{W?H2wa1&q7|-VZp_l1t97E*;<9^0#gb(AApBor=aQ|uo(|?EYd<%a__%lwno!l=OZ)N;? z4Lg1%{Hf7{Q~eiQUuL|3aV{PQjdPIv(jSxjKLz@v@`vfAUYy5xi-mg_-@*8oRO}81 z={ND|VqEOg2F9fyCHe4e#tXRraSrp@&bXg(8C%&Ue7Ma%lj-*`p3is(%JIAf@m39mew+pT+!t!FY&qH{&lb-pTlLjQ@%8R_>6lVftKrZe;qAu(O1hbH=N23;3PKxMQp) z{5I2H#&|2^^B6B;ypQn<7{7_}JnlG%zO7|EpYe;BeiP&6j8p%E+z*5gH{h&Bjz<_T zU|ize%ebHMFKafABaFA?Y2bRs=`1^T%mGz4PPtRJ1EZ-@*n`%H>Op zcQHPd`CP$x9vkMlj9^S;Tm|g|A^e?*dII^qUzEF)ntjCRNL`gYhNI|9ecI%>~QV-a%t8B!52RY%U$Y zX1s)PE>6dv84oe8-tQ5|r;PWpAY2U`BS&cdd6TsuqUT=%oj5O+UQLg`CBX-h;8~|8=5tmO{DLI- zv?TbfB>447@aiOZFbN(?g5Q}0|9%qufh73uBsh(sCCdN9N${>D_+OLYLs4H7@gI`} zKR*fXN`iZm;PaE<6-n^ABzQOpes>c5{v`PBB=~bl@FPj^*MQSm)2-YOd6z5AyGiIj zO@fa^$0<>{oDH1#mrvG=)tD)6FGxavX%c)E^J(FRcOJ`mO%nQLN$~n4cw-WLYZ82W z68!Nb_`xLjAClnjC&5!-I1}Zw9Q^E~Lmw+0bSYb@{#R91H~39p84gi3pK(qz&Q~2o z!ce|Lvrs2FSJbTt)J(1fV=M5bQxgQ&U~=+&lS!a<*@{6TRo1Rqrw))Vt8Pf_ap}}D zNL981Crle@)#2zUZt}!6v1jm-i*3)9I8s{^*Vok61uBDqvbx&f8cu5rTUG62d16pi zU9CR>OppPuSnXf6!nc8*>VwP5Rwjmx03x4CET`29q`U@YLA^wS z^Sx{9%7`FQnEF_L#{z&2No>mncy(}9B3Pv&LDGeh6qy;r>RQB*Ak4CgH77^C3<OZhxOOha?Qgj_hrFYJtQJ7H}Z&U?6RQGkLp?B_gBa2r)ak> z@fCJ?ld_VA=@?DLGpd}Q4hS`nP6hupYP?82sZ~Bl`fRAl25C&~t)rxhW z=^4|#7*}N?&|QhwFw4vA%?$SPtul;J%u98e46_*XKrMm%lsIaKDl67hR&%3bkx(jC z*8B?^upv$+1sUcQYfuk$zNwZfUV^aeW%a9SE2QTnmN_ofXGKY38ItQ_Z6KDDSJc;4 zOwQNwD#TDvB?ol_tm4!WYmikW*1L>#ALB|z&1hN8>WX?Ue9OnQZzNJ#%<`FGVwNw~ z5}H}B`b|=WPV%^ftIHZR?zQVx0aw>ar&Dq>u8D)JjH5`s(Vs<<(`?Yu8kl=_)UVAtsx)XNh`JO0Bi1R=z_-nB}sS391+24TA+&wq8Z= zm|Q&TV)~m(e_x@$OX=@2`kO}YIV9$g(Q8#5e7a2k6aURD3sz~uL$dSPmltqImU_%E} z0ALD~E;57V;p|3(KTV#vs~3*p`oJV&=5(NeqBW+l)p}8 z6-TgYMJzhfnhIskI2r;}M?A(8K+vWjokAbkq#>PJX##^K0~ck{grW+4-in&~Ky958 zlO!W3coKqQwrCnOqDDw$+#bX8YSb88O)7UbkADl!pCcUS5&$RoBK_!i-N1hcO!&No zaSC!YT>b!lf}hO;yf(fz3I0S9d@+9rvHA2H_=85g(?{U}j_6I?$2cXU6+e;l4TJut z2L9F2cz`25Kf_Pxml*g%27a4?|J=Y^4E$jO-^w36i2ox7{$3LNEdCB`)6Y+W-^#d@ zV*qiG`;mM%#=RNuQ3Kx&KS}QeJRnc;n&rDU2|k)X@DTkk3_dOcH~FtH@c%UEZ#VFr z2EN02L70VKWgBQ8~8p0f5N~|;qTS9JQpx- z%QM};O?jR+@LwAIe`nxky52Hylh1Yh-J9Zl(%`e)z)kw!8~9TO{ZRhyO?;j<@c9P5 z$H2d1;Oz$fsDXDF`11z7*TDa5;QI{x0|S4?z=!d8Hp%&{ftMNhegkhb@aGJCQyw1R zh|lx*Nxiry4-asJAHYxWPxJ5qXXC^8!zAIRoteYm&q+`I13%%jgmI!b>&w<8^xKor z|KdC_fV1VfXhIw}>-D`!@INt5a%SN7j1KMyo*(C9rt7y!@UL8un7+xtP5b$}ftzw} znWXuUJU_xu^6h&D{$m3_V&L}~`0NYu0B7g(JqG?O_zV9#`8$T>L%#~`aD3Om|J|Vf z<3*Z)=zneC^Yatq(IohrjFX%%8hjp{qWKX1f`Pwk;AXxJ7`RD)?Zt`tG#a?c=jR4) z^6_4hn9ubFZt~e_;3l8_25z?F3#KOKe_IlKC*zd=X1Vtzp&!QI;cb1m+rUjZ(=JUc z&&5gb>LmCs1K$poqHnJlxEb%#%M!;+^Oea_dWYjDd~yhY6I?$z9C@eeJ4)|Q@Duuf zPlB(_N=*N868v1Fe`xZ5&FJr$=^ZjM&fmnplmx#j30|87f6Bm3y}IkPc)TX=AC(yY zRucSsN$?kv;JZf0`9F+X$^T1@exQjLCBbWw;Qa<}=I6vS;_;gJjY;rvM*nb!A?Gbd zf9z2M|4tITBMH9M=tr4)vcTxinE2Kt_*q83#iY+M`U$3-7Z|u%?n{&4KS+Y_NrL}2 z3I2~H_;-wch*>Ug&%W~#^ZDz9IBweW^oeoY z%+JvVZl-Izft!4$Cc!;P@I^`RzZm#~5KZdWbfbS_;tP}D4;uXtvp%k!6i@F#ga4_M zcQH zu<(cYIorb9`I*gFjL#9q`86?ycQek_H-_KFcphIxPMN1S-oj|T;$(w;j%8^Aq#(o<=kQ6<;;Jlg}=b`k6F0n&yyB@gz4KYyn*>YW8qsE zKVae6Y_DIiaA_wxEqn>nAF=Qmj32Y`62@P(aA~)?EIfnhU$^jF#=9*%k8y^T`6AuQ z=lscF52~Jo%X*M(8|UXS7B1@r@+@4|n@q59S$B|c;j+GCnuW`HmI4bG`MegM$NiNO z3zztoSa=^lms_~3>#4DDS!dz5a9NkpVBxZEC}iQXzGJh6>q5YODHh(Y3diBtX5q4a zq}9fGykNV9mvH}khlTfDs)5HWT-L3$TeySYqYl_O_jfxjT-Jjevv65o(`DhZzNXv4 zJGsB!XW_C=>V$>2jy3??ik{0llnic{1n=T}mUY8|%X&9?pA}rzyX9GYFezTS2^KEv zAo49-*2hh=a9JN$VBzJ=-)rF^#-)Ej-jt+v#+TUiqqLmm7GA=*wA;c*)=&9udM+2~ zrwF~Q&k7mzqB9ipW&Bk8lS-&IwO~GY7c)87IsODc|;Vs!3_glEE6K}Ba{8Kc2$ilO^er>jJS%1`G;n|Zk zpKTT{>vmf$yoBT3ZsC30AJ}2x{&O||$1Ggdi?v(0tZO@9;j-?m)52xF+c69Gvz%QP zF6-jEEnL>c_gT2CYd&G)89H4KwkuNZvR*#J!ezaDwuQ^OsxcPsKU4G1vv678D*Fpc zyye3*eZEC6>tt!&J~^S6bYTuVvw~PlB}D!Y6x#rk`ff z%RUSR7B2fXcr9G^4Jfg2+5cgQh5IvgyyXUN_D^aI{I{A^{re4^@?X~BHduH$+uM+V zA2s-FHgLr!PkXjlcnQn7&BC+!yGW~n|IXmQ-N2>qP2M{U{AGjwF#~_az}pR+#`nbK z@eRpNKXFs}MsRL6)xJ^WC3rs5m0I+D{Oq^zY*HAwMtxCy*fc0)n}I8NSSWM+f#^9o zj&_T_o#~~niJV=G%lnAn4z6$g7N2s)MP8u~F+QHtA$U9E(=5D;@nQ?l<^+^mcs}C+ z3ol??`r8t3IpgF+SWs zdDWtq{)zN+gkJh5>8uxmOTS`_g-btSl7&nAUSQ$UzAv(HX_sp(T-xQ^EL_@OX~#uQ zX*ch)=*7NC`z!QfpI@-(Ti6~-{Sf*cjQ`D|mv$tB^;GDk-O06ZyPXnx>F3b?L8d;4 z9hUY*=%pQBWzom_MHVjaFLztGjJJqA7yi=kJz~+zd%-&vF7GcR_`OQ_$oNK{h0FNH zR125!3a^FBctxp&OS|m1aOszBws7h9ZntoGZ#rP%GG6hjh0A_EeHPxr{hxHU6Os=y z?w4!f(qAgDaOq#IvTzx95<4XP+j%_dZi`;V<+fY6jDOO;Kc>EQ@;Kh>7B1tr4t}qa zcxAjd*TVfg4lMRh=;ghj%A%L|lokt@_nn;i^i~BjLE~}OVcb| z#-kQlxQr8Sv2p&c|B!{tcw?7^%YHr?{Jtgf$hhbP3zzX&kA=&4?-C1_abw!Q#w=eM zXTHzEWqkWF3zu1tdV+yXwrqA;Dit zNBM|hhWjq37#9h+n6?s#U*}Ddp@Da?{K^7JYzgPTo1Q-Z5l)gL>*W*q?-BINcRm>q z_fp&kD}UR4W&}CEqw>>K%wGO)0!I1U`QKX(ATBXnm=E~3m;V|8vzOnenMt;Zd9Xy_ zlL2wBz<*p4RlR%u&LVgGwgZ*yvTuQz&8W!O~F>%Coe5@+o zV6o>&c@fo?k|3Sr$I7^E%Elf3?Xf>bln-C}Sh;w6L>a$L`QhbwsU#=hA9y{TWk{dn zASnR)x$d6FlrhM>rv!y{*4#*0*KMX&Nio(Tk;4=gD-FbkV6jW@9uv`fM=6OL5N&V{ zDXTv{+1J_Qr5=afY6QN@+0L#O-GbC2=E35=pptWbWXJ;~>DH-#z+FCGjjm!PNI4*`HM^_io2) zWIM4q$o89ZUH_SoTY#g*5asqu8gXwZ2`?{zBo-p3QR%qh;*jG3PHeV&o?Mr*0> zyW979HCF3!?qcU;`j80q1Ge!j`WvTGPs6hm6c$4%IdRE9@@&vvL<8wW-|BK?S^(y4 z*~Zt2)Lu^IYu(9PE^s(%UavcREAE23FJ-w4u97U7LeyD??jKpqMi%-er^$ow92Y#u zR3Zo2zo_$+)(-VrG)eZFI!9%n%+=Uuv)Lca&g*WkmMZL2TBhXcy6eG!q4em3w(>qGZLHZ!U6B6|wSO&rqwa0qymmnpwo+%Lu}w-#u+we!c<3#t z({pyIH>wL|dpg|diH!=f?*2}Zzim=lrn}d9rYv&oO0!LPukUll-duO)b;vu&o@k~T zU>`=5Q(6H z=WGPl8HDU?0USBL*i0F)4^`I2_Oz#S0ZLNVXo%|Y4m>?a6r}NU7!Nd|=&9*WEj8yg zhyJ$0QUpMppAyR=Y&Efl{TH!qAjz8}{rwsBogwxos-*~PZ3f=X2FlRkxaS6*jcQCT z4zu@Ewv|67+oHpRENu=e8)zX6YWW*;JTMxX0K3rP@S)RcKv12>rGXD&$F;fxlORf3 zDpBmiJ)BxnJb|PM%^_IqQ(79RbYZrnxCjLXXk2Mqd?WSB3!=l6R!*4G`b;wbS_-L3 zcOuT%bnj8LPu5o2rlQr|b)HtYg))&nDwhF=l!Hi6+3*zQV(3)Nun{dTim2_MDO5*c z){ScVTl};N|9iFPWV#VSW#dr%-jKe<9rAZ5^)FM>vEkGzH{0L7-y7Y_Ue}K~m4q7| zWJEvaQWD=VLpe&~X~dX&W>)xgg62j7@)*S_}z^qG=PEFl; zrb9L66!%8h3q+;H_C^?|G{V+46F$)CF)Ie4-bnI;=$*z|s(8xD6E=#AQ@2AT3U}%6 zE9?a>5vC-d6cP3d5{)2RO+t~m1nm}yCS<6C6YWpGvv}N@T4j}6OD#j|-y6MAWacg= z9%w9``GiDOws*=9m@|7hihu+7@+0giA{D7aspZ9Plm31*>;NVBHBVrQa!+#>ALkHK zcJe|$GvdtaP=3OeE%OOVUBy!e;mh2AGCE4FYoqZc^CE}F5!(?-wyjEsjjO#=jr<*T z?SKSU?I|n$AoD2VSmd95#11K~yHOtw#~4%vX0XxOno*06Du1`q@~zxpYRYys-s`N% zg$M7%F(!7@b#Tn@>ibVKoao^7?W0&jGhh++Ak|+6KL@27(70~BVC{AM zO{9q(qMi}$#WChe{JEp!=~fV(%MP`tsTJsHMelXjE_{Ba%i&m0D?Vz>nfs5K%W4Tyc~8KbV_xF|Aj%ACg*=3ra`9qdz%f+klciC35;eut&4 zBq|LCWs12BJ7^M1%kmpC`_Vf4`=0yM_rz(zf^#5igzy%C8X`| zDzoy6p>Sa3&Ov8^0u2OS1t85-Js&Gxrzt&rVmhu3lT(^~wJSe77jcy2nUp+r^=ZiY z38Gj~^eawL{H3*$qRdSceGCQxjK&8+o5sTE)|k6E{VmjxX3&#?o|J9P{02=~W81^j zC2B0cIQ><`2vawx8Tp8@C3E}0#tyt#PaO);)WobpF+YK9dql;(0OC;iAbZDJ)Y{o7 z=D0E}n;edK^y1RPa@2c%Eu@?ZMFokNT*W-08BaY6NS^v<5w;p)o3&I@flO?mH8Yh| z?>?lJq_tF2H=vxG>kGb0SRWyD5%vI88IV&}5Ob7S)STIu@OfYQl3p4Nw`3-ne5CU7 zsn~$>hLL%Hkyo86t8_Hc;pC5ykuQ3tT^8zp19*_VCwX926f!j>pufbZq;&=3IL(~& zAmjDTqam@$5J>&k1jj^~FF^_s6|wru-HdE`l;;aB=24y?NI%p65noOb-O1pOX5?tj zHYG6u;r=S!K<5$=0fe0sz$aaT@tlB-qrPG#;6-ccGPeO+c0A*}`7?3qM~A6mwq~9n znauVlkl*ww{$@*N72fdrlETTSWwQrX*3VEggbuV}aaCctr>GEvrQgtJ<$ylxvMn4S4n&kC@g}6 zL0f4=-VV%*G^5OmlH^isjqO5T672FQ2KADbx-ms)7(|FOWPJh2jyYQ&Ty)F?x&1PC zYC|&h8mDvtO1(lA+b`WFs#`BzYj)3UbLJo_P_AQ8ug#zI^|6l3461NBU*e_Z@~|3j zsi9U3kOyEn&niDe9%NVQahjCmNs2F|(nQR0$Ctvvpm_-uro(yrH4f)0uk+meVV)*PH%-_^i#TWD zna(Io;hag^Ik15$^YB3&1B(baPVs6it>z;-{pe~W1tve=5NWOF8{*hTJ&%r0Y#mWB z0Vf_>50TVHx}v8-gFwyqFp-vnt|tUt_tM#v;*7|$g0XAp?8N%KV8JAP*tCLKE*wZK z4v8$|Mb&lhRUQ%|iK<230tHhfdfv&e2-8${=r2o`%j*wN#7FaEE;+7HjM{# zv>fgeuXuX}?3)7qv>O3jyshD0fgj;ng#MN;F7IX#x?4W#iKqTsjx-$V2l3EgXS`JM zH>cuRCg2_$j#~trWYT(7^M~B*w@~Z5oKwCCIvll#;1zOXjjIm_2=k1&#pk4_c$AXbA-nMZs1bi_1 zza-+%qD}#qY~N%Qv+z6k{tqwhRT9p9zS@Bz zvV*_G1N@f4jpz8P#nn*^sBqoN|4J#uy}Mo}9bHPFoJeDJpBlCMTZQ7Q++WpxQVz(uSjVeD4v<@LJ* z9g~W@;gnS5%(-Wymb{z~s4BRktzM2TeB)a1sR>|GzD8GS`&w zvqZ;Y$FE!9G)SJ5;AdOlBSgEj>j%8d{bY_NtJ1H?P8d`|8l5ZCaxSgKx z5b*yV0`3?69O1FjzrX^gq%z-|EpTi6dn|Bk{FWi$<4KrsQMsr}CH~14I8}v&FR{Rh zwG#eQG1S}n&^APS`STF)B}24}uUq8bTCUYYz@@FCot}$^kgIPFAtzSfY}R~zC_7!m zH~Pto)&+D)xSWrzGr?K7oR8V}?#THV>BQ)gc;q}}j}0#OcG&mO$oYdDqa_|Wf3WX~ zk@JLEqA)VPoF_bNgG*b=JvO);_Y1{*S>lo7`w|;mj_?15Euqyeu=4+mC7{FML!D3+ zh~Wnz^9qRjEuwvhM{biO!*r)Uon$hApY>`Ii*#v=M$Lfo5yMb+{(F&t3pQp^{K}TE zd?Ca|K03xBL^%K5^rc8kI7N4Yka;~V^7l!AxJ&xwoz^3ieu6EY+(Ti5I(QgXT@I=F=nt z*D8@eb!*h$*wa(DX(JI3hePgZ*l1&p?UCagEd7%ga5RpHdCUIW(~CLXlFFqpM1zsp zKeI(EoiyoRwnbY+3>H^_-vbzPM>_EJ{%O>kmU?hC$bvq%xKT^3DSi?#)8>SEVZPzf z^i3|!zb$qMHZLi)?@C7;@9UofBJ;ayAzwR%Q+&k2cl@(X0@Yc0sryde4V8TRz8tOO z^`5Uom#OdD3%h`q8yjbxR9a^pi$E<^t4Cw_eQT#S`fKK>pQ&3 z7uyJHuY6D4cA)JGp1)l`w(#y&e80ulp*b%%mcB%3puQYYy0fhGrH(+Jqa!d3->zr5 zBTRGQg+>@-zlJ#hl^VK2Q*G&v4HG&<`h=pimgj}oF_=YsUo+r6$)&-LTT?;>@ZU9x|%E@oF@WdCCAj% z56K#!J(Kfy?I}_#Z~j+xnbd|vH|aP@nUoi-%XJ+tpf*D9CJ_u*7yZpC@VZ{$ujpye zi)8yhsjH!>hE-R?X%>_Wrn{h5L+e-?^3^q1*i2+ZRi}*hb zKbc2DP_VffBY;27S;H7wPz3ktb-rP7`B+OeKs&(r?jFgv2Lsh)6Z9qhdOBFw9H);CiWTrknR=W*Q0 zNYBgD;nVW8JUop}MI9&AD_Uq3r8M-SLSVZ#He}53sm5KSQ&al%{VpvvI-s?`gZspD zU=Kabqbk4Y3bVFg%6)s;74?gF(mx_;g)w8Sah8_4DL<4NeIJHUU1QgiWk;}hRwvQX zXSj>6bjE2mLGi!hLQwrZ0btmr<~IUbZP)0#Lle?=G&n?8?5oVM;uX z6AgO5WF>MGCvv|aat?@$1GNLjgwC*kN%4Fo@wN-)Z7p*LVfU#8{oP7KIVLp~#*JeQ zGD5x~pTuASOzj~LuoC662Ls1|#@bQ4J_MUI|1Kr*5$ez=gYdX@$k|+v8sG3JWksoq zuu&o}*f^*73OtNs9ZKU<6nn}in!Z0@HD-9!j(Q#$^D&*dB5b-l&{&mNB+#ZcN~u6eZ${S*$7qdaPmBB*RXcXb&CTbc2H#>qq^?xIa~1G zG?QXSOYy~>zK5&E1QnJ-uz3pl!J(STDlCgj+VL_$JcKp8+o=*dlnsmvi|@069kS-KNaAJkIU7cU|+ z;}H8Z^?NkMDzChhy2KQdd(lvxUbDs_5C+u%S~?WhWPEdmC>{0nn*?^ zXzZsza}8PR?z}B;3dgIoo`FnOz0uPk7B3>?~SDex|&wiXn6=s zP;*-DC$^k~+2>jW_?Sff1@-;^XhfTV$d_El9?)Jsb1Md8pT59rkrDdl3 zaJw%$5@c;4L28_dofvJdkiRX~l{_4KwygBso;iZwT&B=-1pQlA(m31}4{ve@An@y|69$MiLNQwlv9aj{ISN45Q-;#(Z}@e$0&KD z>PEEMH?VrA;kUG{-^P{OaidzOK2R-GJ5((VH=!3nv7;{&>P$J522?+0JhU+pl{YdT z-;emTw<-<4;P8`Mp zFZ3SR^WcGXmS(&_7KfU1XUW<)0)1=Asvf3&u`{3^z);mKc?R8wX56t1`}|xn3~%K{ zb*s?to$RYU4Q5-jdi8yu>Bowq`LJ!{*-*RIpW1_5ovV7dX2zK9(~PUfVmA@(a@xu@ zBok5V(1$?%(GvWfC&&Fec92c3gXw>etsD*Y%guQmIv_6Q zzgC-Dx)XC%u62UOX+I>`)Syg6cC^=ME0rDUrPHyWVb19%QYll%^fq)%+qs;_eUF*C zqpsK|m`fsd1_kRIN;TprB!sx^c3xq?q;BLjT8O~r!i_S_%WfcYJ@Kbtm%hFqLj4RHFUBOS29e5V5Ro9fYtGIP> z6+bJLpC(HvR%Ri$;1xkmF}9!_=>^VTt*oj_r!aG(>h=3x@ZF`T^K2`+U63|s`w*s! ziY|ngx}A$3@ic&+^*SWJKg;h#R4pVzqWb^o zcfNaV`AXbE4CUjHy1>tyekfg_Oiwaly=4CKK9nx-C!dr4p>%;yiu6xgGe=nRPlBf- zFc|*>qM{~$E^uYl@|&Wh4E$%hK>wvO#^?7LG2cRTfD;}7FTjZ*Y}94h>~})* zug?Vrs~zImU|b`(=y+|J=Wr>p0WoCI7Z8(qm5zVZSDoVGXsB+=mc_sGNPPiM4+iTKhHBH2DA6Nf{;%ry+boq3;A8|G1(KZI^wnG zD6K19SZ2nzwjD%IKZ=(NZb-JN$^%=FNWFfu(u(C~ z;gN`byUVd^3cMubrqs^K&YG*RBmd}CwU>&Wxh}^;n)0((R$c%_0~ArI@H6#Hg_PJAJOxi91qs3rEOO{NP9`D^UQqdTRq#I zehzCpY%;sQjXr=YEksm;b2;m`Kyh9P{h>1|)2*YdNvDXf{93ZX2LXQ7-{gP;T$e2hb5qs|Iwd<`)U9qG4M=Dq8RtnxUz=aFsK8 zZfzmTrBy;(?%dPYE%DKN=tq>qW#~OXR89m7Wim9l28ITkpaN7{r@A=oD_L021^xO% z6~czpxn}B7C<)SaxqTtM$J4Vq(u5*SI>ize##JOu6E%wm(n^4-0Xt9Z7Y2V z#u`x5PtT38>b!4gxk>^8>xfTx`{J70m$?B|XY$ARky$Mu6D))>KS^6RI1k;O;nck} z1XlRl6~2jFeE}8j=()PT{F61M;UOfL3}-l1bf2sw>8lrraU6#05ucL05|10m#sJEy zsyv|=3c<((XlrMp0s^^{r`NPhu2AX=5LHjlnw+CF4C6>z0#rH48iIGj*` zEl{9#Ou5bpJT>d2-qM&-L=7$kn7V-+nDh+e`c&41Ht1%5XWMu6z<`Fm(KySkzwKO4 z1%h!)o|c;BiH?Y`$~`v4? z(5Fo7M7aadi(U&H`Dpd3TV=b{(#@*=jxRPsY5jIy#D8O6wD9~ceY>ymTKAEzc*yP3 zyM5~Lc3wI{9sONTqpaV_SH~u+@kQ>v&vQam)M};;8O!%PKPoV!$rt-GF_SZ}_SH-y zqBY_DgmgK%q=9|S3p~73B?a;_H}EXbe)R6W zyw1UP`kFUCFEa(N`s*KG{FoQ=nQ6m{3;ih+;&-@mmE;LLX7+Pf92q$D%&hp)9HstU zg2#{`s~>z_OI78i3qhi2E3;i_A;~l%g7}@OyPvPKyh>3gyNF{`S;AbQtKkJ{nYBa^%FwmTc%bI%Pia zA{~ZRkH>ic7|n$VE}vx?FBR}^-09-wG=u+O4M4NnQ?DGpvKtIev%`T`IUY&Rwul&l zi}R5J)=68XVbDY=hq^;srSH@o_;CI^M z|6ai3Hh7zWCv5O70^VqYZxiq}Hu%c|-eiM!3Hbds_@4y)Asc*;fIn=5|3$!?ZSZaZ zf7}LtSHPdN!P5f%OB?)vfIn@69}@6qZSYS7e4P#6E8xGk!A}Tyn+-0N1zT)zc}B@L z8{8xMtCwx?d;#yW!L$3kZSaL6{vI2=Qo#RWgO3*QZX0}&fWK>luMqIG4L(-D57^-2 z1pJT<-X!3k*x>gIc&`nf5%3c>_`?D&hg_--`ZWtUePE|c!h-@XZ5kz96YzXn{IGya zU4@K4OTcL#vK7BPBc{j(PmB1YZSd;_+-HMJ{ukTeav#xH8~ho8XPgbbT)-#T;8g-X z(FTtS_#_)#?$4NPgUd5+0ycPD;0fB`2?3`?p_Olq0#0i?EBtiF#2bohy~g2zaQ?gLY5zar zr24jAGXMFu4Bgg92-Ei`KQ)!FZk-wJY z$UDuiW!RejzfPTs4@fWLUN6$y%ik>0H_M3PF6o!xq4s_Cl2RAfBK~iF8zz>>^s@em zc6;8GBp@QnekLC<`q|SHPJ7)07M5c#z!n^DQHiR1;{OxE0%~| zU;ljH*Jb|8#RsL&|2=6H6c-xR5Kpau*A`lZ$`ffALPq6Y(&*Tf1IY6 zxQ7^wgv+3mngx^XxiDyTbOzkecJz^|6-t-|H}rLzIwS%tfKzg*+nLKgg@5zoY`>XJ zYd3hR85_6Z#*srOSje8*LQpfM(5b*yD7^?7*xtbwejU-o&Ea1hL!mk0)P)4%Zf>FQ zHVahw*qvzoVWX9Df{FSFSZrx^o5{DZ27B5=AiZR7i0!RN9@dm#Z$-)bf_^A=XB!XX zBNf*z-n8?U869ffCO;Y%>uOJ*-rf!Ue148r2Y-Yc@2=g;c-&Cx_h`YsHdX(?8GB&^ zt)M0QOuSICJ%0h9>q*cw_LjPimXw0OomwgYR`z~Yn}lNgD(y;mrMjvHzE``ol3ww2 z783F3nH!NX%U`I?#%Syj&Q_MB9#c!<3j%wQ%H5eH#+o@M_aGQ%U)R_|kLG-Y`WBPp z}!E@L^)Thb+b^Eelv&U)T%?SdzF*DwGfs&Q@ALQq0~666#u(KOF{OU;+mBKCu;uAl^I^`VfMb1`BLIN z>KDG2&2Jd`i<~3T_aQcBnKwc0V2MTIG!vknt(@P;8wUayHJJ>;$iF3xi8MEw z;iV%Cw-5$$QAb~fNU@PwNz&9`=Tus8AOSXe+IbbwDwEW%wD#^1S}t!)aB2=Z{d=m* zw8{tK^e!h!k^)QM5t_fN=9~eIffJH`A6-Y!vqaBVK*EOePy%|u&9Py$#y(0)7mX*TZ!UPf(#gNr51`3|OEY-p(ni8=4@x}*`FJ^t;^L~HKkmmA2hBKDUN<PZJOquVXWajuhfO$n~%6D-9sMcaX`-)dU{| z_u?Vo-x~tY4~BsMa0op24FP`$aMHO-T1EBpGh7Jn6J?;eCtalD;5u3XmwetT;B5ka z0Y%338h#XC>PRG~6EZH7fc;&-y>0|>aXF(vcJfr|;FBoYcN>i?zG=DTacN~# zI-oM+aHa5Km`_S`MmU{vEG!StoT7#o&YU)FcG;YTbJQu}vW1RY2pfp4e9+-B0uYUORWasy5CDN? zC*d6g#6{I&wQ;;rR5Zn>?*lUa-4-~>sf5#ZJh~`8&4VR;wy1AAT)Bs>~JtFGSd^)vn zr2da5-t*O!A9}c;rOd9U-?3ylaE8%fPUWer6T_c zS&U{trvGPa_MvP*Km45Z&lLF!vCC3%NTgq9E3o9Bj5r;E!T3LxIv-qz%$tMwPig>} z{-3Sc*h+UfjY^vU**7ed>-P*;bwa{o7bX{cR zsQPh_lK3^!BIJ&ZR~e1~+cK7x=>2}mQ&TM7UgSf1V;Ti^3Ta}E4tJQjTNkdj;jd^jei zBaVAdJ@)&wT9n|M0v*hm$)zw)uQp0_=Chv0lHT2s>E#9^0SES7 zVHuA-dizyuH7tyd&lFMGEWcpV@jaJ+fAuf~rsTmsO5cwS$%v^WKLiRuFIN5OSh{Do ziC<}%0SmkRlZVyDwA7g>G`4_~71wIb*#*4`_Fr8Kd$o@;{0-K)WO~E8u=x+C9bE|E zn3Aqss#>|WH7@5-fjmJ;czgll$J*|sUx!|<4R&P?x=tfC~5nEbl8sh(rsFW^0RF# zw+B%w?BsOLq$7+>MxNgDEUn?Q{E9t+ErVYu^Zy}s0D7+)Bs50YPRNU`KYvkGg6{a5^*d0FZeT z(LHI)`keTeQd`luPuDYHGT3z1WPKJH3g1xc-l4R5O)DxtjOlhvcGlvAB^QG2rEQvj zH%uh0YM!R-F-{tLjcq4&9rPW1wx;3YIhUTB44hw>in*1R&8X`_ z6?^?zSEN0iqjxJfkuE1ToQ}sTiWd(%$>GBQ*V8$8HKG>Iq1r-~?s(YQ)^Gnv(NW$u zN}=x?W**g41ZhABQt$&agpN!{2>PhZ9pEtNPpQArd-Ifr`vF!rhCo_K`B~@6-v?9Q ze@1EPRP~c?rG7j{832BbCzn$HT|DVWFIAFXK%l+Hi|n-2vyVC)C;KSd=ugZnPZL?j z?t|jg*{ig8vEjJU+q2s2f7o8Q6j0kg^s4O#i{QwruM9hOOM>jvGN_tT?yr`Wd>VGX z7IuDM_8)QIN!W-wHS{T;l%;B&W&Tf;`cWuD8N-IkPs>V~N|JTWQ{5&*?Z`k(&4gmc0PnjvaXfzJJidX(Ol!i_$>)7^^KM-F?2vYf9K>M-L0d8j=MMS+V z2f|Zx2}X@nv=~GbDkU9Ys{)R{Lj9N0G6KHOoT>a!<8)B8J9ZH9Rb|?i%!{Bu$c|;` z91OVm=t~8?eLcU!e(TJQTrAA-4x?8%RS2y-AEavL^ASVuj$auE+oLKUey&cw6fK8` zIv8HBcJ~x;zL^f!c1OR8UH`4yR9KjQfPThEG=w4kIC}I%U$hWoY}TGV%ywr2bmR^; zGsAEcCym9iclq9CXnkKOuJm^eAWZXbSR4WZ%0xHdz zJr*4crWj^LpTw3Wi&QIE&0U)F9U45~~HBe>*yciGyo$w&j1|mYrlx-pZrj@~< zp^+IjPOO9Hn9+}^hud?at!3;L;8OMXhSBI0n~6v#;OJu-%WnwcRLTf~f+fEz|`&QOK|`oeVgI+jDY}M*!O_Ie5P-O zgdo#}C^RpT&!&yGV;z0<1+Y_Zrf9e#Os9rxrV0?^0qubfw5&VeK&=Ih|A(X%?VyUB zC!7hF69gtc^?&2k*gI(JG)n57%jh%RQ{>43UEmIMf%*ZACWRx>59K@6k}cYiH>aoa zFM^rD12kNX@59j)&wm%>PPtKK!AC*;Z}W z-?ZWQe4X}C+~~g24|)_+?jmJO%?s)6@Osvw=1wk;-Z~lnwpzd~j7Y<2xInM64ST4z zqs1)QoL9!WSN>sO*3r{?o^O)4V;3QwBZ#i&0|WwC4s}$&gV3Tp86)}@wLjqL(NRwI zu! z@@0Mt)DJ8(8lD|41&W+NSA z#>}B7!TC!3CK_d$iMh?$*LZy^nL94*m zXv9Y|=^%9s+7K3Z2zYy-3JHQyN48R_a7HWjKK&IK#xgI&9hLpPrcyIv-g0Byvxu`b zoSNLB#_!JiEVhL>1-i zt4N@){Ry>)P>SQwSWlS!l?a@`9lAXQGPKlGFP%Azg7t;iU+CqeFncqMdr{9BV%{CX z^f>6hvpB!zYGQD0S(enZ6bO1hX%-76o7*2T#>Wsq?SleT63 zogbfNQn`&J&w-F9c+MK*V~1Ir>_d@3l8;~mQ4Gfjg+_161H~U(ky_yi`_oGO!;lnW z*@Oyqpo0Ass*_0?+Z<-m;y?xKfGk4a1=|JxJ4!tngsSm7i}Oy#deCBn#lt4|DT%Lu zDVSPe``Q-nX0Z*cw3kT?P^IBwR|Pv1W*W)%A)cTlUcum=IhVIBbQPzh z`7P2w>bS7=CnK?2O)lkn?&tlj(po?VHy4$$KL-8Vm3rFmh$J&yq(}4bQ1tBpKuU6F zqX5^sV>9%9k71?oR5MjIo$|c)afC4G_^GUFQ&KXkY3hOfZ7t#ATqG@o$rlc*|Ew|a&|N51vOf*p@!%1Y}^ zuK2O5qBTKea{ctw#5A4kIxBwc8%pA1;6ZnnKC&OvLZrQ(j(MGh(=BPt)YE<_r>;_3 zPv>ZPw}`h!unQ}+ImPqQn-j~>t3TK*StruB^^b2jw%Lv0pn;+Q1&s_M6(0+D+v05+ zIpZAgK2U$Pi)tGV8n^P^H~sUE_}<~feV`T_TnU{VU5H0CtVlwrDmhAGTtg>sEyu%X z=33?%*tO8O3`w{~Nj`>G>&dY!vQ#@cbx6t!lf}VLv4#FS7n}{V!&LW^(xVTc?o+(( zO@7CnJEEFIX$$88OeFJL=*27 zOu`Oe5H)#BbwoZKslJ*K=2>Mf0V^#NeCRtv?6_R?VxmvIsPW*_G{rF*svrTF_45f2 z`aGX8u8H(o#$3#MunKPPh8}gYiw2TKH0v=GngmV4%s(F>xHIj5p(IAi{KgP_RcWoj zp4|Kprs6+@=0!>T2puN5*_>p|&WCE8T-&DHO@wTgQRX2<7EVS5sEbcaFXD~_O@C<6 z2k{B1hMnrW_JxMOmYov5ts0|SL&nNwn3GM=QnPW6JH7~M?C%=L$Iyf3iqnTruvu8m zPlIwcT099KB!7zR zhcU*WY{W;DHVqyiNYC(mI?s)<88i7+cq3+U4K&-L*8%9TQq$Y@qa$h+IbZwvnQlx- za`j{LYhn}!;}qCIgDGkT)yug$4d11x3#{8h($haUlm3Y2ZwpehA(Lq=tsWRKe}gq( z^eO|+g0}}r|3pZGffB6jfaQ!{AR9F{B81kyEsIk=j}A#&`;skk#-O zIE*@9Xx8UUaGTw5YI0YF|AnZdFjBOH{9Ci*$SXV>lwdAo4(>m1&%H`Xd<(6fTzU$~7i0Kl zaRxn5DKRcmE~4vzcUcp7%mhF+hR;M~)rb~%Y?e)8PWxM5-?wih0vi^h%#o%r#>pyb zhO09B(eX4Hb4O=xMW+RVuEDs2>B*_A6C2j!C=Kzyg7`ldJv;BR=cjLix+!x3u=9DD z){BmlCM90u`>4JesDj*wloq(MoLXe4BubqnvKz$w6qI-~cY^?9o=4VP(D)rG8c61s zp*3Q@ei!CErXNbfikr)Mzu=f61rh3H!9%l~^qc3jI8=}Tdrv|)^dF4~34^r8C zK>*coRhYd~!A?}L*Ly~p>q1Pn;pYI~9BAfAlVP)dr}6s5cS$kZ>*%jvC~jyjcNRD` z!;QSUTH|=p)6m!M zokfHGB=BNBZ+_`x-6-R?)$1~gQCONk&7k@?OU$0;r~mves)H@*nGOs=sTm*f?ty=|m<7c8!PB8~ql1S}VpW#8 z5+MEwI-E1zlTrI~o`Rg;M-ELW8A?H`r~yR@r!-Ic5-QFD^~THsWQB z=U5-HzupV9hbRMFLG#AX;gx&#oGY*Z!q0)m?+6=NMYR1n)e8u%>9{zYf{byv` ze7cqwbUAZ=KnLiw2&*=jseDOjDOpwVD=i15XBFO z`s8gKFtQou_^IvT3Ys^^wYU>}mVooN30ReYb7L}uWjjL<`I3;FdO^>3DiDytY_;nE zmv)@iM8**C9}fX<9s>T$A>cIHQU7GWXv#Dgd^f=bFRf|b9s>RW;ABhPELbr`B%&c^ zFgznsuY=AJk=Z@jeCjyCfdLJl=l*o&tQZeE*k-A2^4wh<*U~pAQlL*&*Px zOdAaU_95VZ9Rl7n1e`3sxv?R9oRG_2n2kqQR4-k!IJ#H@s+KRlZ6S_aUKy1T9;IgS za`Sm*48Bn~=u+wSgrkbBT)JdwM1Z7?JbzPForP2WaPxb!d6Y7R#A(SC{H}CAd~+2J zdzMj=act>O7WGSSS-F&3wST8_;pg*IOwNwKD;y5@Tigq_m`;tQ3uBvKWL}oVOXP9N z@^EOgh_UMLa^rjcv~pQB9LPvsgUR1rStTs_`TOdn#AI2(mCIM~B8XRxD;>Hde4K#Gv01_c0xs885*`$AAr4tQa$YXmpNxM%(COp3_UG#rQ>$Vde2ain zozf-o6btw`6P$(55%38%_&5QdXoF7>@JTlKL;;^{gHIChfDJxbz=JmU?`htROEYg- zIvYiNpA9Y^9e3K`PYb>^+28@e|4(diE--+RO#xk!Z*tx#_d`m!oJuaU#h3G{gbjX3 z$m=g{a5*26^(^trd5@GY377MpRRplmDd#-Sn3uE#VZ^i;#KweC9nYp5=|oYQ1Q0(O~6Y^c6GKHbF3zpPHJz z{NDtOqR4&%L4GawnRn{5t(QQ@(-6EIKMAwOyUS;N>JQuFUXND(*k9Da>ml=BL;Qd+evk6Sfdu`rMMC{7IKTZ<%TDR#Dl_UcyI_ z3gbGjcH}L5bJ&a%jDm+e+C$tq!?u;bP+A)vMg}k&SCUU5`SVGh%Ws+q6}$Iwe&Zi{ z>7$qkql5J3Lp@b}rbF|JZHP*Xf{*L1c*p=MJ%t*u9jHjEXmJpyrUq&tdwnpb%^u z=7cNXgO#FD4hzHMksQ-B5#P3^7{PA$l_&d7_SGz4o7#^l`mvJ=cGfr?N4nO#DJ^Sl z#*J-_oE9&Sum`EALLzuB`e&}%e3r%@sgg9`9;F#;iRvlL{ZkSU(}s23J?M>ux#v1U z%k43qY39iK?J?|WQCO3I>vW{=*^qr!=i(&AIZDfxx%h4kNr#b)FwO>-dG?0;Nl3@t zKSvH@@ExQ|d0$qQy)+{luTD{L=Kck-#dIMQB(FZ=EP3{^w1S796(vEn z!-a}IlLqkF8ei3x;X50jI`ZvrsOXYS0<}Rk!}epn>2fgleFkTmuD=VY)BhSaTI@cu z)43mC>3*v@u>)kzeOX`aorppLF65nPgE=M06YbLY4e`IHUdqedaBA8Ka+(tdIGkD# zsPJ!IIgPz0_CnD)qV$GaMdJ%+ONT!ly$oKn-4ySOD!vT2YznbW_?kuL+t|z0>x%7C zT6X*Q*S@++F(7QL%H;X&%B(wwFFuE`BAVjNf*9 zW2}C`4ZOA&L^S2D4l|6n(X*9}I}vr~f*TNdC%xQl##1(aY{qIbrn%MUJt#2thnqA-iV#gc%3hjZ^d3AJsW3`-GdU2H_hV!w)tiwyheYpBx3#QG92N=Hd+CRVz?~ zeEcA%NAORC*Gl4EU@tw)Wu**$`>%k3d8F=@I8NSu?s2?|ut%EtEy)EK2=FOUe)8wk z^tUf04a8rG_iT~%f#VKPnR^WP9y(<9ufVebE%I*h{dfIZwB!hTfM*kAzoLA4eheFe z(!)WRP~~%)ME>;slC_n#fkc?A!YGWB1DEIdYa=X47(^rPA?VNi zNxsh(4lgrbqz)*%cXr)c%x?P&BnU@genq_H1?c4EayUkvfw#?oW*86)ev)l+h@DjD zhS;ZK3oGh+tno#&GkCBO@xeGWqrGH7!QKiQ#lNG^?_|^B(U`j!cKk}>HAE|8`{+bo z6?;g_*pAdxXV4hEI>b8pv8N{xAvM(%G~6Z#=FFF&G_cbs4zk@rvOPQ!WQE0L*b+Ib zFxXg;k22hVgCCIhk(~&ajcDILrg83RO3TjlJbX@mo-`Wl&tZ0uKI6ZJ54|8HXcQJ> z`$e9TSOetvIt)wYePlZQH9Urld#E(2sX6*)3>(FDK}H*D=3*bnqoUKtKJKjhE^~aQ z{MF}4VXm&Hf3omBA2pyE6N@=_L&lE@D-I!sq1eDeCr9$yj^j1#dUmi)Cb7Xre2pi& zv%>TjK{i>672=#$0CA`Y+pHvd5nrGM%fLb68lPnS5fx{{G$sfe1A*>Un46jC@Sz>p zIMy)`awWNzr`-8GO?iXtB=PJ%cw94M(4O}qo)B>}%Mdj?K4Y8Kc1H=!_x`&XDUl4p zAM@5##x`U{Ot6+8lo`Z<&TJp?H*=pw&Xm@B{%bhpy_3BKH0`iEZ}+87BN|X?NSUcX zY}kfbX|%BF9c&ykxx@+0vVC*r2}nbhUW={$r(%E`YoK4edl@=K^nzrDDhheI0crF7zCRem`jB1L7_e7b6!x1e6`b;FsP3y&9&WcY;+)%ktvU*l+Be=B57v z`n%Tiu`+)f&c`l>(W%i{d*X4|5R{n3eJR1e+K(% zf)C6wc8?vc!*S0Iyab#S!VPkg-$#9;ho(*bIMg0n^iN5bJ;r_jIXt1+ACml(!SoQb z5R{+9rHtrmKs(B|SF-pL+smj)?(vSYoD*YJ$ z*?zW%WmL8o<%hu}v7mcQ>h_OPRUhen?pkd<4JWigz2Qd)z}|IDaWeuqA{wVFzmHDu z_r=r%&S{HW=x|1I9iHJ``Ef)`6ldE5O?R?X;>DZ`fE6q7{_)thv>%+My3DUJ9 z*~1(=Fsq#jjyNj^G~3`KjmkRB#Ri`*aQggR(XZ30V7lI05GwHl!dhg-d3+u4Q1*^%gq^9STVw6H7$lL8HmI{K(D>Fk#_1;gF#6&2JQnOCek2!1Z)O(LcYcXf*yKOO&#(@cb0phDJTv)pVTOU@f_W*(^ zn2G*{Mm(ao`Bk$CMeq@-VpIpFPb338UY3Sq7$4E4uvsT~{t^$VM7AO_aw0?SLbd%p zPil2&-#3r5_R>x5+fHk5FDThw+SR`4w305RdfZcHqW+o;Uh*OdoMt@Gh+C+#llb`=_=!mu z)gsye_Zx~?6EO9UshRI%OG#6Xxf_Um$T}o>$b?gd*yy>$>^q)&F(inSzacq{lm8;| zozpE=MagCWcofvcI6qQri!pL+eI|rKc6RXHn|kLqtH3)2}EEkl-brILi3T zS6ge7)+Pn2{_Yr6KY%sx2~W)(9Z5M&$m&ak$6AMR7H!T)Pt`aD)2b)EO7a`H8%gpV ztQnKYnN3d~`Z@Rwf$cu_vK0<9T&%r4Gg?3DiDvYpxk|%*=-~C+-Cm`>0in!MYk$9v zyt!NG7L-cbdFeCP^WG?qlA(GZX~qpDG#Q!gCoy9LLy0wF`awNxKWe$?xhF^}1|+vs z9L1CR1xbpGuLpa$PX#u5b!l7B{~}GblzWe(2rBJrV;qp_F^h!$65ZNt?ADtFrB!Fc zpAebGkw9bZ^$|Aj8ff&+FdC>#ISua;q6G0BlT3neJq|YN?srDN&vxo*S2*?fS`CfX z+!OIja~E967IWOi=3R1^T$B}p+RNzJcBOR_7Gv#vLnoAxE^ll!CTq>Wf9ec_d;;qq zxWoRx#eOTtTs~4^^6)TH5QjD&=Hp)=_7(~?2WnX*QGv>cu<~m%K?It3->q+?%^jFP z-a{GrTc5;}*>6EBQ4^`V%hh*xv;zB@M4D&5cSH=DAsmF(T33K) z>;tA9?KK4(2qmw7>R%#t&*$Uqy^fmq`S^#9JUYT?(9kY1C%Q@h&0i4Px$1k^{>wO& zsu|-G2>4XI%)VO1WdNEU)YpLONK)C50)x)HS$tq5EE(<}Md&MynVu4CXDF&kZGdju zq;G>qhTv;T@FIE*@Lb&4um`W`!mvhM(fs9A(R10yy!+0)il!vSNvU_T(i3|olI(nm{FHfVZ5}ipBaxy-d64~COKH&A^#;k2g49k2F4VhSlb!lboJiM}+ZASb$vOY^5S-CGCb2>ERH;G&NV9h{acOr*~e#b<(URcB7cLZq^OWX@dF5L-F z2Iz;lgj2ivf7yHg_^67je|$GtU=id-i5e@FXrm2EX;Pz-f|?7v;Vvdf1(m8TAP}J< zq_6?1s0q6pxL%gxN3iy(+B~ha_Ni4{m0vK@E}neQh(8B0#cm7vvC~C?J+j2I z(baeZS-b!Q2VQ}HeT?|6P}`7m=TJqH5?Lw6X6eh%W|~k`NlASRIm74^4=XtipLQH) zCct(XI-ck$rj%jn7wd%mrshy)62q1uWAJV`@fU4FmRpT``@oSf5`4C00}bi~jm4cX zS{NT!DdN|(w>Tq9giQ_l`iEiVn-G?hHJxklRq{4t(JwK!Y(95C@+)5>BFr&+TlmfR zI6T7iJ%mQP6L#hgpaHu$eKV?YF51N!Vs6d25*naeP&6_bm>+(L*viR5+e!^I^SlL)3#!_6u(w+y_BOP7FVQ)g zu|wrJ1QI4GcIZ1s;-BECJy0|fkwVTz&fKA3lf4ep2?xyQsShdUXYw&t^gK9)Lnh{F zu$>3?TT1v)tn|rn{BpcR_j_;=cESnStC|p$WFy>9vvqGU-1`^}B2eQ+3Mk}?Pe9kS zm>A4o{5CjY#k&Jm#EhNDF%};{eIj49b#Fm<&@r>&1)6qpcLSB}OMmobL;Q8rxXZbN z7>FGX&Oa3>eH`W+h~sWyve6{&Hx^w5`ey8|zzHKk69ge=F7*6Bw0AY_TXB=Mbh!*gcEnRCs;yBfHk!|F*tcX5oipNkW&ecQht@f+@VOzShYBY9`!X&T9 z{$&G&s;p`PXRROM3tm>1-rJ=&!Sa9r>I{5+JB*u5^a_IW2S6ziQ?>QJ8+5&NMwWG{ zivc5UAwlUY;nPC*AIK02cmxuya&9Yj&xVJ_L&0_p zR6|6mt-C*nGRU}$xRp+R#zj?1pXh^hWO-=`^!C&+nZOGofweM$zmc$n+=MTz_hynS zN%@*-RU(3LMAmt?7g8iUC>7hyMKF3M)sqB;I5o%Y1@aq~d;sAQ<5VBH#*$m;PRBor zAEJK$7xZOV0s6@K==+Q5VfyMFUvL3Nzaf7~;t_B}0}Sp`W<!~*YmRCuZ)eM0q0^Zco-N@{Lj`J+-BZ!lBY4DqAP(Q{Z!%drl#TG#M z<7ZH+YcL>E`i@Qq8Flzx5Mc2#S3`EHND|}K5>Kl5LLpTqA0Owv) zrJlYXU5qtS}tpd;U$Gi0bKf zo9sUG)`s{Hl0MqS#){6>6?V|My2Q2u&edhMh5Lf`5dn-M!8F}A)INpxOdO2~_^aX4 zkIth;H%>F|A$vMLsveogY<_0hBMSI{2+lpc32Ndp{y+OALOD7) z8bXsEQw0mMkxo!Y_s$S`DUB#Yvf%MGz^KjQF(lDsoo=_O#)>6tgtude4F?@(>J*(7 zY$r+ad1y?VL30O#GHk+vn?w`ZVkMIcnN@UN5>x388(h8>9WJJYTkH0_#0#i3iQIWC zj6HHFdfTZ2_X|h>4V1eLzq+hX@%6Y$*HMV0^nksIi*0>g6-iX}D!Z`+Zf_(``nT17 zNjXO3Ud;Ou(lFQc7%p_W^aL`mOf@kIQj~k4E11u?3|wW;LtDq+o2jn|-Z+NU)dW}B z`9c#gk^y_5$r-mN+3zZ7lY1$eBV7tTe0{pqWu(+hOSE7PIK^fs$b|paB-rRif!#Tn zb!n!x#){46eC>fuyStvYK1t6{wvGy7mk_wjMVIZCytzy<^9ZTSllgkM_cDvh*c!m3>>G_^g%J%Y^K~n3|kg z6vPAof80$I0hq5-hYZp8uYiUkLHfqN4EL~qvi$#on}PO7Y=_hW`!nGtY_OD>StL8` zU_Xb|bFjtOFJQ&s&hnnA_yX35)7N2gz*7u@_Vwk3nPt&triYQF{b3UUUb-p15zaFz z+bYju_c7Xu?l7wS60jLNd@$NOcK913LEl(fsEV|?)VPAu9gxmJ^edc_r5hQ zA32=bRb-9_4>)_7yvetq!MeuDt|vuf4tazSwx}F^KlH9H6lHLqdQsxu~X%Oa-?oA4Fot%r z15ak;?VuprXwi*bi#-qy*L^{;Y2Wf<(;gV1lcPB6_-DU|ZM#-i_Kdege=)qsh|{#( z@awTbj$nsJ^;yC+f1{>K>`iNz1fh3o;s!Sl@%#&iY7d-&Mp1Aa z;NQ&4!zcTDCsrpbTju?S<2Q*E)l^OnTKXzGAj~%$J5~`AkTARJNJ(^_Kw~M-A~9F# zCZr0*u^wXt6c#gH%pmV)!Q)r}Q~TeBL)`}o1-=mXq{*OM7!C_+!%=C$0yBaA6M8bT zo(zbGkrmxA;_fA#r7;Cc6hA&qXT_ur4Vwg0wDBWWK*SPz5C&W1ZOVQ4LEQ0pra!R+ zw>AU050h*gj__JZY^KZ0(|G(RT`AJ-NoKv8I7UnQl(anVBR`sh{i%zfqvTY|0eq0K zw_poo+B7?vzX;W(mE6ixs82bX-AeKw#}!yMM#{#)*x?91XB^x~jGTcJcBrsCs|Z$r z>bJ}vhHfZ_KZmc4EoG1vt&%&6(c6!DVNdM38Q8Wv_BYPmi^v}eGy2G_0ww>D^5Pcd)nubZ-ymkjPsr|rGP}gPZIA~$HS3I zUd?$3sUEb_!Ftgfq&F^xx%6gP6XoHcWrX*qK7c}{#Ylrya205+#PCHllVf3Y0P7~& z;A3EchiQ)rpv#OO$PYWWR^n%55Wm7%#yHdkm~6<4RwEFCi>^NnXd#qki-{aG!9y?v zCdQ6f^4Mqt0kAuVP*KWymo~vOv{ga#!`OyXELy{^Dl{BV>qi@S6C!CM$0UoM!j9l` zE)UtqI?fPs#8!l6`Db%rQe#|L`$A4&Io8V4B6W@SVrV z8aF`T_V%aLMzg`Hh#5W*xx+Vq)rPtcwB80?yrynh3kA94UGr2Q>d72JyT z6Zqm{yj=XiFCeA9RBuhE8fO+>hjs?d8A8|CPg7zts9ZbCF{;Zyo%_1P4Q#{KcYWY` zPD}0!ha~Yf&0E#QewZ;D*rZm6BT#0{f#Vfsufl;MjQQr6N^d-eqj~4jbt<2 zgY0fV{z6DfnwtT;v`A%nwS5rV!vx#_Vn~{9IbKvla{|@&CvFEGv>Gn_ZT1(`a!pt& zZ09oy>H%*7?U0q6&}m^@KZ0tAPCTmfN@T#-aT>{qHh#pi6D*hgHd-uuwqApSxHN!7m&KFYtX+hsX{B5aLpZ;kEliH+~;W@_y>8-MJFjA?tD@8Je4dzTeU zn8mFllH<=iF(|2;1{9E=&P5p1E)8UR;5Wza@#Q!p19G}ylXG=Ir4@a|QB>n4plZJ) zO>ikXYlkzb8cXQwvOy~;71O_yY;5eqPHPZP@>)|~vB&6^m3Xmk zpcUI#PcforsCI%j7Nbr7;+rshh~rW39%4C3QlZk8(aGW1aFfHYC!ZPvpm*mw`HO8V z+og#!I%(izjAEDA+-9V6zU<5#v=b@6d2oBA^^=^CpBtL0K|;VRA6U);ZO8+aH%@H9 zqmlew2L5V|)gTkWp#by0j}5Sm#0)B@*hZe+tINlhQ$xjTWAQb3L;4c?uvhF5LOu^Q z6g$*HQBQPff7m~fO=C{o9&5@t3~tl>jSsCP4hawqWzK?^R71HXl&m-|8cR$JK1(6d z$7KUL=rySnmVL-dUO}%c?EKFgg=)`lV!?~j2!XWUWru|{J|15-2f?d5gXd0x{6S5<$75PG*YMz2if@zmhJ!JiYV=BKP$hA12Zv zSOg<+HPUD2lIk~9h%KQrE+Fk}dXQ^<0v&37@Ifu|$P9AD5)>JWeFH_KllfeFGE;Ks z99mwF>T;CRkY#QqM;*n)L~!o4=7DxJC!}~hV-bQS+%oE@&mD#v2(p<9hongzy`CZe zZl|mP?MzvNl52m2!=~Ogi`nggC#xOtabXX^!07hS&`$C232J|*>2Jrz)~#RUVvX9@ z)?eK>;m{G$;SJCWEJ@}hGWxC^xAQELLouHdY+D z`wmHfdhl3lN@XpjPERNy_f9lLQa&Rf8y1xN8bF@ZMnn$J-yWqOXy!^iP_V>i)rM5#uv}UuUX&Bie@BgVHvTPSmW;z1}jPu3otzzb{-&8S?yHTVzQ*}EPQSe zxwvsFAhW!2JARDDFE7M{(-=T#qIoY-aj?~4<#bf%eN_&eBJo*@vHI0YV@(mYunQ0q zZps(fP}cr8=B#UCN3e?WEJVdJ8PmpU#Jn1uh(qhsLF8XGI0DCr7veS69w6YAG*yN5 zG_5H*90yo$BR&O~v6$v@MVKGaFdSx)>TV9%yAEzg^InA;ERqVzRZ>8r(CJCWVq(S; z?)B&?`A^^*m=hmKJI@E?(4lhj%JQI7wulF@l=A^?u()Jt@ib0eKu}^APGEscCzYe| z#JbSKIYwgndDN&vUiJI@Mq&}3Nb<(&S4?cZPX25%(82>li5k3fO0az$775*mdv;m{ zKgGmMA+Jp5R4KtiUS*EatBBLM1k5At;t@`uo`wnfpvW<~_&oQ`<-&6GXqz8JI9hXV z+Ko+|--(9eT!l}`5RnWc96T+P z;~2VJL=rc*aNWxR2V|;HDg4HYP4qnmwrAfI$2zyaL&;IssxW2Q!(UI8uo4sc8wUDt z$OAoI+&C7mfEE~w{sa`g3F0r){HS#-As9R-zm(qcDnm1| zi;*j+5J2R$6O}b$H`5PqO8a6Cy+`xVf*TaC4~C5V3Ugik8JtndWDte8j1&X`n(#wc z7lx_I1l?RDfv-ntEjz|zpFfJmcFWRHDoD{V&RP9Y?89N6b1{V2hJH@fl7QONl0BAK8$8|CX#a+xc##@z$u!Ed_$V32W(RNf(&qA~4H=^NN&80$Y3-ihI`WVPQ8 z+)GERq~T2r=Kv<@Nprc|a>k~3xM?iB2pVo0+eyPsShmF|V$<0yg3;)co|Q3ZSik>{Lyt_by{e8>)|)j2D5#w|~LE z<3?gA>Id>Ca#XvS=7}LU7Aw@VXlxZmjx7k9Ma%E-0VsW$(F|HxQ)na(&}1JR2psED zRKaZ~=wSwlNs`^7k?yh7gj8gRP@A<85$W9ow5U}f=h32iuw>zbfaUlF9;G>zcU2PmTNeQ1ypNFJsN*Yu4ac zSI%a4wbGr5T7j_L*I9QA)fv(L(9sT>i{M@&>LJHXFW?nYUC@_A-DMDQ8X%S^&%J|E zY8Z+Rk=?6Mp@f4oqQJU%1kTIq%q8Xrb-1(~kZz6Vzor;aKiI5I?x~1@U)jJ$4!*G- zxg>iEFAhUI52gd|!2$~oxU8O{I_xZnt@ZoZ9GQvhB|Ki-EzBt4*dY-fcIN+$2mjt&3?6P0Ck2p&G zJF^_)u83>K8p%G;K|+he{y$OrTn*7wl8uYl+(5YH0nT7r&eNN@3J0NIwP<6cb-{icBt#fALz~G;sK~y8*40nl@GESiS~un!)>N#(k^t%VC^jQk+G~~QUTgSe8Y<- z5hKhm_^JneiWZj&j~aTMFM_EqvXAnEQ42$MPN0Fz=|>o7fbnd>OT^fTAG*rlG-6?- zgip7UfjszS==(jx6fjCdYjl0KI|%z8VDKBqP=>IVy1kcFh8C5iNA$%q0?sB9O2u0>~wOP*u|Q|A$P2`kR(A*FlAMCeIjcSx!3U*?EZ4cvn0qUnAEQT8f8i}uU0Ly{`6aCC@lH)$f- zSY6xGi5$hO2G1OPiK9rYWCVUcj0`%0%gzWQUgAY_BjWq2jEHOT>YBBvkakM-q5Ru% zi1XcjM zpmrQRhKZwU`}1o1g^sgH&XL$=KYA^LX!cPT&v4JzWYOr;tX;^J*cPk zCYBZ9w3mZ#h5R3<9$rJH=+|VMIyOKydaVqmeh(*$HBYZ9vMxS>Lt{**5=OU?KGJa? zp=UM|X?Gr8IKOBSW{f`jpr#Oo#PUbgh`Rq!wT7LouI7nb z1Pp2aShWVJneffrF+7UF-z-rx1UCVT-tdXzC(x17cRKoGJO(YZDP4`m?SNG|?!sE8 zMGbfHE?F4&OqOkq-HkPS+sU>Nzxb%F0~T*oZT-+mM&kpB=}tg)WToS_()|REFlCD8 zQ4o=`)sBCsHPX(KOoqqK6-}x?B!4QQ6`P=RE1~1=D>y}}W_eeGmpF`4abLl|wEV<~ ziD;xD``d&Q?i!GqEI2WC2+hX_&`{bg>mp(D1_ed;5yIxaC)5-6yec_0(>>+pMJ;6H zt{(LUQ`_H_)zdwXcxAuAfy+e66c}sZBe{prNn>1STY8dyUjMF2oS4r|E50kMqO_p^ zvQZ$JlTJOwgesu>@6#?B=);Qg(DeEt1X+$9+V;SDGaZl!gWf=xsDNL-MX#Y=q zJ%UzB(d&+{0?8NhjR_AJNUTdRRwMuJsd!Vf9JUiFW6~*ygov$#R`P%*b=Vh}vCUYJ z3DjF8{7njU-&-UYF~FQU=rJvHxLKFdeecv&?}!3nZI_KsBl>fqa>uD>_Z*FsxffAA zcN!_Wnah13BQb}Z794*!R*f=qsf!dyZ`|RC-zTzzI{f#CD#KjIK&)+ zJcFr=5RSYRY(PU83L@x!O?gj-zf6w)lD>Cdd^MVg*dg2uL8GDMovQzb6fZ`GVa7u^ ziB6C`0s#I_I;VNOdji_JVC-u@-`l&;-FoB?5C^E4r617Zb@*~k0D5m{D!jV`cgUDb z#F+v7~0mAwu=nff~3Y)aeO#}q@-sSebo+9%({kJpYM^aQ2vznXE(i4D%lJ`M&y!0>Pdj zoy7}^!7;lej}1)d(>sz;nh9+0gf_OyK4jv=)6&l%yF%;WKO;Cxj(UPu;&etVa(M+* zF(vpdF;I*na$yKqu$Wb$Obm7Zi1)DPyIVW4x*vNb?ti&c};k4BjDIv*Ev|?-(;6vqMq^hvAio-};28ME~<}El$Ku>chVA5ios;9aJY3HO!w= z=Qvb)IQEsF_6U39DM{VUN22D27)0f6$NY&liwAAy$^qqK7QsDhAc&?X-f|$LOl=T# zfE3YcN8LkCg>G8IFid%ODOX78wA=eIZENMiuwgi>0gdE+N8#t_`+Z`42eky;BhY%b z<}mIY7>ze^2TTmNT!VYn{D{$LcOjZW5A+tSQ8%ST1;izVQd$HTiA-rDP5qk~Ux~j1 zvw?kXXdf8fs)kOXrLAiIieF@YbrS++%9FnHqw*8WJb`0b^TEf3tf3fWdSQ!&0p@VA zuLEdqF>Dd~KyLIytmMf(Zd&YJv9Ej3=4RntZVlX6G~9($-Es2a=WN<2H1?f9y>=f! z@d?i~^$ofr@OW!ETUZ@nH?BqdhDNM~eh`1Co#%cBoloqSW5i#CsQ7CIlg9siF8TNT z%#8tOKE4WJaM!QyQmiO1MaI=su2kgo2ac3ynA4PB<=X85a-v^Js{yHRN&5yFi~j?s zpMXg*YIJ!$)%`J>?nzGEFKn!-UuM!OHykvme)z-)IGT#Eh>svCm3%8#5hHq z;5=Sb4?y+A09D00zlma79h%mFYe>uC%IW;h`0;??M9@=N5UFwv!xESxIge3ocglGh zZ4v`|5dSxbpm&fM1gTQ-7LX4s#QQz+dqP<7q$gXK6rmsiSyc3e2t}f*+XU8G=ny`$ zfL~R)9cuJB1n4cK`*gEMB%#i5?np9BAXWRiEHaImHR#K6&kM6L5HM61E5qelCthIR z#iq!u^SlX_anr_)oclW-=dY}FtU&!C6T>3!lY2y6WS{E4K-tqB7uE-NJSqk$I(Bj@ z$DA8)WufIat#o7lB6OT{htUsM4#nwghj{E;6~-b zjk5P)(?%XdlRgjM!x#{!qFTY=uK-;OO?VJnB8)|2)(q;Z8We{H35U6hi1g(U>Cym& zp<>|%mRcBz$wUd(iOdo)Sj>rn3_EaI0r$V4OQ8}c1sOW=mmu5NtHh5Ypz6HRkp8?Z zBh3fRDPgrbBG7h^?WvzXDm0>)vOuBqv@aqeO#prM875`x1NSHPxoASW$$gKmsnYlc zDF=JV#r$Oh_U5oIMw5drv|h(vmWP#J(1@W=sQZVlhm6=E_%sF{RbG0O!?9roh0Y^k z?=lkZ%usmB3t~3B#2yXj0+Qs7A6Zmb+K;_F$6BQk_Vk5Z|_Dco|c3l;7Kf94l#EQ4h1l_(w-@7D-wUCO2Qc@hc z&!T5c*(FLyNoH`?`S;(5IxAdl3R?^zL_bU&lj=+Wpu&U(Dpc}0D(9Rtafi=*uz<9ao~`!9pOUQTHug#9pu@>~ zEwq;QzE(FEi$|^G#(SZ;R(oO*emGQnVgv~Dt&A`l&su~6cqfREhaV2ro>-!8WrXE; zR`e5OGI`Z;u(fl zHc^cB#BTi1)t+Ec@f{7@(uLPs#T{PLs3}Y~ed{c`K3dNQE6DS#W(w*j$=MI4PUK2a z(m7d{{nUN}><2sP2g}U`bM4^*40-@hJO-ZZa2c(Yq6t6Cd6wpH?bn?F%W$MTwx4>@ z;By6lJS+IG9^W1wIsswveL_EM15jB1D>Nr?2;d7 z@wl3?=5_ZP$V=%PcHFbC8}H=V*9~=o#_HFN)yHD{uupiw{7dB!wlyXH0bU`BeZ_5@ zX0UWQO`|!d)gPW<#K)05c+W9fU`5}<*kOz!3ubtQcjq-m{B3X;>kJ$5yNOk?#bNz| zUY$l`6vmVGMKy0@AptRtoMMk^^?yPmVw9gjk;~vlw4O8`d7gEEH>6 zGJhp+B)^iB&HWB(Tl)JyQX83ACT;jvAxiW#1O>_Dctg^6-y?n@Dc(C9pR#dYNph>N z?J1XtuSXF3Eo?grwOi6e4__U`80L!m#3s5cN%wgjJGQnL9NmdP)O*E?|GoZK0{<(4 z|G!9}>{lG?F}hy~PQES%v)ZZMI7^&Ptkw|9e}M9b z>l*r3)30!9zo4%Ow*w@8BjMnsF=u4If>(7UQ5pPF8&B7G z{B4u8UHXMgmeE<)$=qcU<`GwFlUw0(-}%nL+S>>sC;gg@#tK5O@3L* zI(J8}ZZjS3Lw4dZNvkxQ-at#F4vy-#+@Es-w4jzyXkBqo7O#jGp0Y6e+ztHXqF~mm zkbW_bEctw^y4C^C3)cZo-|ROu)~k}vhF{pdGLX9Yit)EV(!(dz(hk6W#d0hA72YWd z5GI2Pun4aom0{Ulvdv)oG6sckeZPWAHXKBAn+*4KSDF^W!SIna1yNZKJ7w5+DJ<8+ zNWX$*xtX%b$a74;ikyeLl@1sr*@VdR$MtPmHhiAF$3C!ZM&khb+&@tRtR>-P((%-9=6h7Xrkvcba=T3k zmR*z+etccqQN)V%YV5hRM>4Q1_tzvIs#8>l=?aP;)`umSa-?f0={c8iHR;3k{R(r- zkUv>?EFuo){YO32nOPt$pVB`-__$FzqxGe@&De?Uh=e8KwSc#97tUiWkx^BiF z^C|V4+gV^_)0iJw=BnMCCvny_+;iKB-?+pl$wK0`57>PYFQG!m#qAh=e~Uk&-$Dh9 zi`xwRuEHPT%hA!Ni)}D|Dc^)Q$+Mi<<^pSzcwPZ+aIwwB?@s(t`2F7}RN5i@{u_UU z`z|Il<5PW&d%`QEvT;4900>HW;ScCR)>(0ja+gAr&*~?aPybd=;y1{2GU1gj)7xA= z-Lh+VflHxzUgi4wdJvrB&H5zADLij;X+Xhq6(YRSHT~7#EO>bqoP4?N=#0&R-<$=X znFU{v1*h#px=VLi7X0BX_~Tjd=d<8113x_n|7am9F7~DHOFL0?#}CyH3STSrT=`2! zvxM)7dfpwKeBeZ<=?qTR$G!}1zn3Nak7W2sWN>gPOIRWCr-}s5{sC@j;Ig}PCuYIt zX2BO_!Ix*jf0qUSGjPr?mVnU3?LK~2X9?ey1*a{GyUW+Vv*2H5!A}4ue(I&&V4nf} zoDMrHi-s*>TCUnbsg+l$*9vxJ|M1+UM7-hsoE8Cem#@#V;D@u|Jzg}s_T;G|Ky=!inS3{8_U*M3Yv)X>_0`Ot zGh<>p#O=3BbjGZy6K|U_YeqB^yk^D%P@{wpXX2FU)27^(ewsOZcKQ{Ab+z**&#arq z_w;h&j9ExrgyH93fHc#XIA!w8nG@?~&6zz@@+!7d;7#&rrkPYmW*;+ZFJ5=y1xZ%&7L||1^@1sSFAxBOz_v|rXu=8*C& z_?sJ@QS&Q$k1X7F>lAf|bR`!u=-enu1i?hMYi8EXolcMPEmTE&f=E#&x1n??!sJ^f z-a3slq_GTrn8s0%ES1zPlTrGa&~u}l36|fS$@GG6X9*q@_b5hsMVvz^(@E6KpE_~= z{6Y<1uF)Y^T!lYJy23<< z`aTNZAp08>jhcRiU)&21xCkGFKZTFYg5Ry-x}15fOE+{nwD3Cppmfx|>0YJbI{k;G z3r^vwE1~%OgLJ_O*TZ*67oYGVEqp)e;(NpYCJX+xhU;_+sUwQZOXm&^r>>3SbFYT$ zd=96ncU)dN(Jc5U8m`M>p!A!G&JXdY(*3iB>*;=$1uv6MmzSSYX;W!jgzNe|Q^QN~ zPNlm-!}WBZ(QtCrRQLhdiGeO}y0uyGby@Jd{uw&DzFnf>IzK|GnW) zmHi(tewK#Qn62VxhlZ2Ot?R$qvKa-xX$Md8h$zAC^}DSIE~>b{8bIt%gc8T z0^y=`b$n44{K5eo{G{+ZHC*TavhQ{uz9tL)S{D3W4cGP1e{T2mOS0fsXt+-277f?s zFi*q3kEE15pU`kU{HGdTu7y8qV1`c}AEDto{b?Gm({I%9A8YitYPcT0L&J6Y-!07W zqld51aJ_xJQ^WP}4`;#GNSxZ=Vfa&WYu51L8h#}a#YK8}1^!g{#Tu@s`+$b)<+x76 z_3&?I!N1n>X-#ea*2>-^+Vw}kGYh^~!--|Z|1k~M_2>K|X8$DqM`gip(C`Y4{v8^w^S@NXb$))E1s_JvBCY`b z^!E2U4cF_-3Jur8Kds@Hf|im)kep6jL|^CgObyq|rCh`H@DUBy`MFoab$(hjyaH(} zem>T4oqhoo5-u;Fmuh$g-YYscX}C`3|75}cq~Ua{=)A1qI-U14TrbBp2ca9KOne z2jn8{CskbaS^Vk`@<}FSmKnfZnuA?;Z#LbexK3k=;ip& zEcjs!*X?HkbrNuS`TUY5s3fk-vp+fa64%Rju!ig5f1U+TX2GBQQHH)Qw-+T&@}VlI zl(!d-|D%)2*WOFgank zDBaQcQ@BM=6)wWbBq%(o;iP&BKb!@>umXW_dFjN=3|@&_Mdv>?e58hN(D17@{E`tF zI=Y_Rtl@h5-atfg5kF)SRJuJwgbG}j=TE6JOI(*{gNEzr&Zf-B@OrxUYPe2+7%7ts zuk+KJGAVIg&gV#+>NTm7;(wtQUN7I9tB8uom(IVf;X3~Vsx#sBagr$-PEl35wHkiD zhQF!dMH+tYm<)YAU&}R|qAL22YdGC1{5=i7M#GEg0T-3;Sp2E*Q#D-Y=SdCM`8kau z<03kGxm0MlUXJ55T&I7VyR!}aj( zS@3r?T&HtX!*x0f#&NPIrTd76>)~I_f)|hPo=&xf>vU#k!GEXWl$4V577f?w9Mte3 zTKE~)bh|PH4cG07t>IJ@iq4-j zoK#ie|Il!q&)r$@oSP6Cm$!Vsui-kKh=%L=ovz_}_655Fx7{=SCmba;VRH+;^x znb|*y|NFDxuW7hW|FoZVPiL@(>*33@;L|i*&u_hk>vaC0;d=NlHC)$+bAR4FpP?*x zLl*pxS?~|C;FnL#q^t82%7Q;QDHC4z--b`l;8gXM-Z~n7iH5%~ajHk(!Czr6{^2UP zMf{T97U56PsnT$r&&3+9hyR5jbCUi%Ce!iK@5qAxvqy#>y?pm-ICa4lpZ=bi@H*Z{ z!*x3Jy&YY|&&BvtbiUGXU4K^PQD_mq6u&C`vl{**4Ih67g+AF1JgfDC&c=I1hxni? zNB%u&@?-j+!na!j@`m3j@t};M!tauJUl0DS#3lRbba!1T0_J z@g*L7x5Srv@I4Y=?!hO>{I2le=R^eXpa<_M@rOKkzU)^tdGHS;{YO3cHi&Q}ip)1M{7t8eWT{;9M-w4R(Ug>RGc@9V+OmUb!6gFiGv z#LxHO3nl*r9({WIn;xnYYDo;J@^i(ZxtT=&ys)jt)k-RUy^^z6aG4hS9$QKB^_E1PnV)IO4^h0 z9{g;HPw?Q+OFB1u@GoS(CVB9!5})e9|0eP29{e>)f2IeI%X(Vt!FNf$ihA&OB%K8w ze80pOdho%LPQ3>&k$BvLZyhe=xWt3^lK4^&ev!nNd+;F=U*W;)CH|lXf3HfU`;Z5} zLY8}z2Y*A#`B4x4w!|Ov;O|KMaS#51#Gmru@5p-kj0gWf;%hzlza_rGgMT9N77yMb z@y#Cm3yE*_;9pC8n+HEA@$DXbn6zU%J@{1;-{rw)OF6&m!RJbRw+GLaboO}gUJ_4v z@PA2t`_zM9Cd+-l2j3;_%r_o9U*eq}{OJmzKSw?I8i})EKoDggo|AZh09*=xzJecp zK@YCRwflPT-%I^bYv&c6KT4dwE1^r_f0lTG2mhG1-KJ_iMqW^)! zi#_50E%Ct~{1b_nc<`G>2>N9n{9I{2hkEed5+CltQ$H4TDm?f{BLp7u;IB#C^5EY{ zI#nLLQ{rPi_%Uf$>AM@c=!gDXiBIt0Z%F)R5B|2qCwcI9BtF%He<1Pc9$fivGd;NS z-)cShZzP?l2OlKc(*+(}`ELt7xbolXJ-G7U;vQW2Z%aJ*P0|i5_29~XTkgS?|F*(| zEC2054}P1Z|BwfNNcwM09$fivk9u(Bzdh!`m3@BPgDd~-DG&bp5u`Qvw%vo@Bkk>4 z53c;T4Ica+>A$sjaOJ;k_Tb8Y+v>rc5rUs>9{kr5-|oThm-tQ({>{IzmoaFN1%Ms zYx;Xx;sFo-l*HBk3o5+w-}-vOFP8N*&x5}+Qlyvf#igHC;K4T!6XDe!4=UXsN;+zM zQQ?EQ?5BA&}U_((}-s0S~S;fH(hVu@FH z@WB!fdGHd6TOK?-Mesx4>(P}X{~{6}>%prfKHh^@Ncs~zcu3+md+?r;&Lj`6#&f57 z@UfE4bPpbobY^<+2{L@G2ftb3Q4c;$;tM?ZREaP2;L{~u@4;tEJnq3Cn!@7s6^fs< zoaLi$ss~qof4v9K%Mri^558OCL64u-B>5=x;QJ+Rd2sceebj@iPsY7|cwSGzh}Tb6 z--i}UzUYVk)OYq#53atmZ}H&jdu6YEP~RmNdgQFW%U|ok)%V9K53at~&kKlrC_dHq z`o$hxeXl>sgRAeAANSzud*#7$UO>@T-}f){;7v3+fa@_2uD<) zXrxP}tM&tU(2JLdaB2$x6<&S6yP%hNPdLpBsB5W)(>wKjs&B~LU)_$c1@Rl5BYvl= zyE)TlP974Swjk;oGIervvTw*ObLaYoq|qUDvu4h?ZQ9IVNo>w+5lZ|HnKCyz)Q2xQ zZ@+ySzN{QFYj$+nkWpi<`@!5OeRU|vOq)KjX3pf>rztM~-+v1cm8yaiSDH|TyjwCQ z4e?E0*GK*gf>ffygRi|)0_Td~e)yquf)Xx}zZXhes;xwQzO9~g)eBi|)gyn)MKu3k zV;Gr2LZ#D|!kiH;-tNZt2%{ng1o8jLGVk4jRT? zcj<4J>6gfPFiM|P*_%GiwNv`1<4?aP+$x?_c=b*_t6!QfrTD6Psc@5Id@o%kKlM9Z z##iyw?;IIlJ*!_8Pd(p-8^XNuTOi{<)k}pGzlv{#F2GH9^7B0@LMVTfV=G8;Ql=PdE@s6<|$$zKHv2D{Nsyw3f!Cj(-5q?_^H2(_>09)`oA|m zzJ{G5K93zT`-g>vg(dh?m$(=IFDol!_>!SNDjCXmlTNuOTveIl&rtOHuH>>vCnj%N z?#mz*d|Tn`=R4JBj;Gyu$Az4lV2%BoCcJ51{0IEcQ%6YPs10mJYHvzWB(b}?{cscR zf!4^gF0}n=anJ@GRE{Ic;}pSX?>EO^fZu_f3{6O!Qis&eud&xO;Xx$U&v$y5>ErC3 zXb}!I{l8DIN~YJ`2h^BGO=crg?A>bGU)tM^H9Jf?ks?q^)%}b4XPW0ZE4>Q+b#7AdVDupY)!%8a!%IZ8!#(Qqv3;`Dx;tRy_M+3Oef%P^ zqpr%iKJXWC8>lToGei3ph3 zYJOBQRB?)UDdZbFoD=2mN4^n+NWx`xEly=1)|nSQjbe5N(=j{#Y_6qR)bV>&J`~{Y z0Eei=ad%`MI~HjoG;fI5Uz*pO*O~S!=6KWI$>oS0n+u%hC*kYtR3H2cJLPohTxV-) zK;6995ge%HM}4q&;hdNnJJ|%9DAM|EmDteuZ=_r`VqarXkyDNMZLl7(Bl*~T zpKdzNz#$z*JhvzQfY&GP zx%XPI+=N^6b+HYw{ZGo#Yt{9yaHjZ`y#<+l6oGJDOJ5xMq8&nmlTZ;}oxjuEdk|y* zSx_|KHS*XRtr}s|`@W?ou%$Gm&q0{71LvuCX5`4w+(t z!hwxdlm?TCB)8tHh zizow*zW!b;KE(TH>3zo35Z9yzppj7n7od;#LdMBGX7ZULD8l*cg8;+!=axN6oScFJ z=y*h)8NH$3jiB1_a*LmmXhKN*t|H+eQQlr%ChF5TtKrjPM5CRzm-Ikn%eevjLAN>s z+UUH#tAR8esRt!v@h1pYjpIBn2s?SA`r&9iRJvGauBbOAX?#64=l(rn;jo-MMDVR8 zHiRrnca-8(LY(#jA;f{AmLvmbg~~S>sBS*r>-%DX=_L$K(Uztw8}C}6dI7^q4{ z&&0ol{qm{Yaja&5YXB0(8BuhsiO_yiw0@NOADAA}6D&AmIuTfKUAaHQX*I>Auw6K= zEokOb;hg6({>eBZpAA!c_YR~e*lZ{-76KWzRvVuG$b@nfy;r~GKPCz|krE=AUA z*i3qKQl+S;Ku8LkZ`ZY)6iBvT*dE=Oe=kl8G-GXktM%i6<^SBiGGw>gl>zr{D6`aG z%Q=hNC7dz1BLc~dPL`b>a?VtG7>s_LI)u|yVx4FN?nE?*IC&{CK-x&Z#_Iet-MM&! zvYj4Gd}hRHM{x_s9pW7M%juY$V8=O`COp>J$4Gnup-{+|5#MUv8>mhW9};#9P?(LQ zLAG)Y=v}un?2N*>=Pl8l)b1N={%N)TJ5c5SI^^_Gfr8ObuunZJW$IeR=6#^fML{ya z!5Vl3C7kf_RtS5;LloSMd}HO(=^1uU2*gaz@pG$E7Bx)!E0-EV)earU5n@+?1RWj{ zq}UK>4)&UN<_7E$f!9Ab{rf|9j{5^dQ6h1ZSOF*F+gr^Wa3m=#1d8H1oE2$~PmcZ4 zw6}?N*Zvw!@6eF*Bqa%-0LS#9*BEg~L)I@R@%V9cW{a`9g(Vruy$&b1zwKON?`I+P zsOuMTe&#dQ91unPHKdV>-~cN$P&id2btP^gEoWRH>`cTTa@W#;Gn!6ZWh@>6FWyuS zm*T-{K5zfQ6W^Y=?3-5iJFOq)SoVJFja0~fksf#F0*UQjV7>8q>|?{fC3YMnPJmY{ zc`B)aH6`$O%fI!+ZesZ zx`L~@%nMc18Mq6VzhJ}@2+2845MTALf}xcpaQ7D({T7igOGlxbkT|IrpQLWgmZxBu)NB|B;w+I+o3z1!f(k$NC^^)J;+UrowT=nA`m zqAUwIM?UjF8)SC??y`{VyL87bHlzw!eh$;XWp+5%XuJoEp@3RHf@*BX4T`AaPSO6N zPe5iZAAS}k&%XAmCSq4QSZU=_m4Qs2R9t(rNPHr*K{|0A?$XK9{DPh=YUWm7UPeEV zpvr6)b-k2%=NgElL=rT|BPzpJxC`O5>lal;Aim)u%C=HCR++lX6$(LcRFL^P%KCj4 zqjIG=tIUV+D70EbZnSjLGTwB8L?g-s+QH{}=G&X779{=)d}X&iA>oRUtc6V>F_O~^ z!-J~GB-eXA=aak1$TQnAW|^6hUMCYkt-S!}6OkW+a>YrP2*#4o%T=BY6VkdF;vm-n z5PRCc6S8iE;)>!78u3z*!L9YDug`}M>|RC&LivOCOWfKG~!j-wGw z-ARW&BY^@F$AzVdqI2kHGjT@;>a5Xt8rAyb9iP#|;>m~|JKm$NkFjRE;)fj1e5k=o zzA%*$D$%3R7^&uK$&u};_rkpoUImpK)sac3ukTL+ev_N`I0EAcwXS^v zSt_X8PjeALhg?+e`d4m@z0_NFCv_dk^p)JVkrK{Uwm&744Yh0nbp$nA_w+#34ENrw zx=gZ%m)2NP*i5TNwU6?Fdey~Lk#)fND_=41B0o*1uRnwG(?iP-n_0HJ>DmNa>;4+2 zO0u6=dVrN7r@~mVg+mBYtuG;N;Q$5ki?lbpKY{B(ejBXb{8P|KLQw;#1FW^3{f$Hl z@3qdMyGw+ZuFq~F*Twa5eF#vqoXvOa5DY!79*Z4$m<6^ExJz9>li)iXX&nk7ox@5Hm2lT1>hV<9d zfTX(-$x!|sU;TofVE0_aYA#Tuo@bL{Z)7Euj)PP{l=**~S|?7C6)o3#+Dq9TPi}$M zo@JUdcQ9UM2C$6yROIafuyFJW{KE(eZN%D4y3Yx!0fJRcKv+pn8Xu5_UE!6$RPbaq zqsp8(agU_7zV~@lr-Z|CHeNt7^|D}AK-ELeIY4j zdLYlEGuPe^@oE(Wx7=^k>n~LT%7qy3In~!Y?5;v-BEcG^9C=i+*Bs=2H0(^ns~Gbw zWH|_HvmUa=5FgnO^17WI_}%PtL*p9pN)6Xg%TZu%pz`F{#v1faDSc^Qs4imMrwKo* zWT}aPIok|#28wkhs3WIDand1-6OE{>l3{TxjFiZQq>p%_6x;(i;Jd3?V=J1DCVJLu zX_Q=-jWni|y4}iN-TsC{@a+og{v2@@1S3uz7+pvPoku%iv3qjRR(C+`P%xT`9qM9P z&qP;)?DQLS61&~zexHik8A^xM55{05URBwLSu*Pb;6#j^v889QIUeNFOlSJ!u`@bG zGq{!p<*met=-JLy_F?ds&!e(^qSvRZqTMD0Lq+E9_{u9BuUv?rE*BA*OxMGRi$f8? zKAqc@I6xZ8%;F`VPFyAA@1ePgYgp9O&ofRLs*9>`%;iZEvy@t=#(r?2(nLP#3( zY^He#BfOu(uIqoXZWU-iQ%X;gmlTsDp$4zgLA-f9Sf0E&P{?+W)Cxl{FNmQ#>rKvni8 zI*QSBN|H2vaA4jDjQ86wg%f+CSE(d$&MEv2JVC_GHzOG-wJnK<@!%K7^3mYD99N1R zKT&t4Y!np@=Mq$mj=yE}! zIDLySZegc7PLcH~ZH3C$Z9SRon({($4a=%9zKOf#*?GY`H1-jCMh!EG!{jy)Rt z=!g-&7;PQD$nzQT)hKt%i7i1eoDq!L5`PU2B&=WJgpt_Hy+pV&5odT&=?*gRd6t8L zjy1~>9?4e0VNHGSa~fqiP`U%WtFuzqgDfoE0fxjVK7xk^rEK9Vt-pULm*;a$f>4cp zzi1_5X{E=>xQGI6;JmH7A9LwYfTzF4XcH@d1!O`CKA8 zAAU?vc5CV*cvmvL^$6tSQV-e1oKXwIeEppuBpV=!bK#bvM-Bb6R0YN4P|b3)^|QRS zl$6P5dYZAleT~FDko$TP0l4FQ5~C-}wqapWSv^ul#*M{(QbC~tA!jVIzax5T$gzT9 z(uPG49@LGx9B5|HKBM#V3nYR&xN`4<{Vq~co>N*#_DRK*DH*A7GeLwK6UYcE1CFa4 z47RrfQ!jSFV(dVrCVM7Xl#$L>kx1<*4lAdMxEvA5x5zWs%BdD549oc|={m#{^A?^R zrr8%=$n57^&i!0FMx%DrEv00FvCcqryjHeIDcG?>)>E{XWr`mzQNak#0iHtUDcyd_ za2y0Oakrz8Jv7}bP&5%IzlidmuK)QtrjtXOhE64B2ZGVPrgKMt8h_L&XwyPuJNEH0 zBT)>BRPkFs36!@Ri_XR)orvCmUmBGjDh7Q*7^N>n1J9El5qmQ|7ggJD;-}a?)-g=k zQ+7ULFZjtmJC|1_i(aj^cZcjRai%%4oBA%io=`5*4h@5H8L>Gipb(7;ePG45hyew1 z2n$U$QYq!1u>hH>Z@X|erBMnj!4cuH*s+}Ga?=U>%w|$~auyp{SSXIcEJBpQV6f)i z3X!F)GHZo4n&Ey*c~_FkNV|%}A=HmX7(Yl|<3jT$pf`xwfV)u>P8jjgcw(`Ue8Toy zRrX$T-q2Ua*yItGV#IFmI9tgpb{ymTR3FJ9`96Lvry67Y{|;Em{Ii`LW6h00IWEw< z?u|50&K-T>+HKRv35sCv14U{KA^J(hfi0L-UV)-U*WO4B0O^SHYtm87ABUX54PneE zB%1I{hfbq)K|Np*vA;{B_n5|d!I=}lOY)QRx)zWacrxuZTt7_vd7^}%n2h1|6KPU7 z(B7@GKgQw#`$X#86a;oUtE-2Vy0c@)bBshS-U)|$BbA`L5YMbqG>66t6%d6NLBAia zTOs~1&vwM!!PXLukZ4Z0{TYjKDKO5gK&2BmqCf4<#lI?NDu%@=D*lSy2M`xDl4q}{}nm6Y=?55M{zp+iyRXfQ=Kgm_Y3A58J8*?#G zC?`R!d&rr@+*VjPYkDmGE2Pr4kOWN~O+6jIG9z^+*};m?ut~u=m*K82>`^TleXIrW zrJVO5F?$P69qw5Z>pY_l)es) zQD<0AE+)OGw_y3VJ9#utR)5r7+XtM{7)QOY&Y;y43&d&)GuDD>r9EKH+0oa^Es9x>RFYJQhGN6jQ4V~y1_VsDB#XLa;sy?>D= zEv@9>Q&3^#92oVsXdMI{@15-WKFe6zc!rw|IEpPf|9-x@P^XU{W?`0I$R zG?*kE9|VP$1Kr>7@FW%horgBhjNQ=}M)*v+#p%^~^@rye@iB;9e|UzGIDw|ktiR*5 z+l|CGxUI6^QYunK?v9Z8dNzJtWd6WOGOr?62&D36)Scpl1Fxqnf2gP!<$ayceTW@7 zC~ht)n^S>dm5QDneZBIEB=d8e9J^HxvbZvPtVr<>P@MKw)G{~#?loYQ$HbJ{tv}$ETx6XnA6m9f<8u^=A?M?^ikZQM+wAnF8 z(HVhGEQXOcpf14|HR5%+VLu$A;HV+6Ie@tnu z7$b0DQCncn=r$c%vh+gijzF*Zr#d-*p(etJlOGT1x~HRDN)N>D3Ir=KG%m)~l4Z~K z2%|OO;WZ$6O3YK!`Qnw_NOS7Fz+UM(C$x?v* zgH(+*XiKOK!>UhV(cB>DvZ92|b$O62IA+}gEw;;~Gh7eCqClCN(jE7C=(>!(o(3TQ zo7fMWquK7u@W<2ZN@GU!vAfo6!kSt%pn0<6&bV{(*h+W#GIn5#2jbSFi|&BO<*wc1t&>yEMB-rH&Ai?2?e8y_T0dN(tTH8#n2t zj=hnf={!JAYI6yMgP!QwC>#_@J?yUEI{SbX`*^?Au!SUtdMx13!NX{@oP9&K6_+QjRKptPx&B3>L^AFTyJ3oTDSWbT z6qg?rR6?#Q0dI zKN3MVj~1hD1s~{($Xs)a@T`u(vHCS?x9K!efGXQ%qYH1F z#DrO(ejWYv{<)YHYH$5wK}LF*c0fp{1K^|>w44wSSP0R-@@Ikmeb$< zz$rULE?*1MntEQk=9K+NVbM>i&$H$L7VD87VJUm~TTyJ}Ot5!y7WhQJ?4Xg@PQ$kU zZF3Vrb1B-JhRq}iZ8VX_mr8e-v3mkRV?|pse zmAD9^lAR43&iz3eb*O(OZ1Sv|L-s}VD5N8y6o>NzofVY?3|dYJCfPFbwUT{%I(}P; z*X1z-%YK#Ula3Uoro4ty#1l%VICi+V5&v@lq6i1A^~63Fxr48}r(3dwb}<_kDVIrP5sFPo%@d=Dq(!08{#XM?ji`UCg9ZbiQ$UWgKTz!iig-j9 z1y#W#yZpVV>C^=x$q7N~!Tk%V(wtjC#Qs3irRAd~fJK5>LuxsgOb863MX1IapWV_C zK4aRvLtv9q=Blas)N8MGZ`Kmu^ z#tva|#X3|F^d~V+MRXQ?49Dyk2V!{@h_Ys1AbKCKsNiW?F;ZkXeR$O}x+tM8`J9ap zTipI+8!#bT0G+8YV@LhbirBs!T1OtjLi81u>Esug8+}ta2gp|d=8r9*5)OVd5{Z<5 zTK5V(*kbh-?9!C>5c^;Dd-bp0LNJMsB0Y*<7708CrLo*6^>uQeFBq*OO386Yc)o|$ z)+fhx(13m8JGf`f#-}8&;U2sf$2w0n;zcOBSSLPGIR`h4ri|EbREsOs^X_B#?nbQI zS3@p#VcKdx24^th%$klt&OGNQM-Q~+8i_05Sk~Wh!Y_jx@n?{t=``;F|CUo%Q0-LK zhMWaQG48SKG=#-BOTRc4v9GVS?AI*2y1-2S%+C|~7%_bhao~WyhXGV9$Bm-y4|}kZ5#YTP{#o;!C$0Q@U>?B%t zT>%XWS7QLZkzRP!4M0NuY+4e;Mb3K1uB3olL`}oQv zobF~nK`NSN0DZ9?aKceZv9?Ny2T>-Sf(LF5I$k!{dSB+?C3~wKPjqoIo2gAwwB>lC zc^y8)l5@Ob$Z@)wQ+1L{5WdnGK8Q!}Kf{CiZc2=!(fVMtnY8TBWFyg8?UWU%@k4`* z|6=<1G19Pw2ByZ?(V1f_?S+Fa%-jbev17ry-_by`MWgNUA5twDUsM%x=H`(`jU|7b zPKgeQ#T1lEAB4doC^?Xy6P;zZ^9Nu@`Ae;m=+CKJ@iA4A*zr@0#Jjj7QWLZ|M*M|7 zuyv{qES;3rBxe3NFWtR3^Tm6R)dp3j^k)rwR-QbFKN|VZ?(7dR(Y$21e6zR zDT1}uwid0@8RJXv1rd=v-?jGMXV#qLJng;r^ZfOD&gYZNIp4GP+H3E<_S&y!FVx`D z9@=t8>+SK^y?Q+#oiE(p+l`cbx|i1`8Yf`G^oU>ivi7GSFhzns18oOqI_e;mvKZ8x zF5N~Ggm{FB-wM;UTNUegWNxf2#!ZqhVAsNd`c*Pmy`Ky3lcntNY!9RuWR1h3B>ZnpX32g zpnW9t74soWvpR7HJ~ zx1WJqK>74*&;2LYyvG}1--Uk1Q>T;4HDFy#t#wUrdp5sgFOAEm1}b+ouKS(mYv{!N zyc-Nq@{~g;wD_J;)ljF2S}Q<;J5tmd^e!QQE-0$}Z4@7gQyK_E#$)(aBED~wE-bz2p5vt$$|$~4Frm31m>L)# zT3AS-J{JTwd=>VQH(XNnj!wq^T;5#}hRFHhKqb2Ohd;q|1-{zx_r01QqQCe_Op1gL zgbR*q4Q2fZSqF5~8T|>-zJI+9FWm>Lj``?Om;n4B(EhJb8*H1P?&%D?z)bT8fsPAt z7m4q{%GW!o13Rd1P&A$@5xO?>l53 z31-RD)6Kd>CmE0~(Qo<}Bt5O>`cGB$MEBRLlT)$YpPQMlQ_G;K<;YZP2XFg*0|~%aBGB}}`m<3>le6C9`?3vKRr{vne=DxccQUM`$NcEQkM2-kjCodFWJU?6%n@Wo5SB-WKyM)PA!AktgFqB5-so~x}VsArq{W)o_-F(XbKf*$WCOy zYBS^Sy~XsQRW}NenWeu=bC#%oS8e~_*1z^zQYD^eco36+dY*xJBQmsP+>$t_wbL7U z&J;y|l&0;&yej(lIf`cSQOQG$vH`i7x0Z*|V4;$R zc=4d^S^WhA7q&5)^0N`8z}B7#u(Si0;9psw;{ud7G1gj)`h|Ug(DS`o!7(1!Rcs{k z4f}ZW5P&)hnX;oEgD#YC!ACqqL4*4svclE`7+p+Hpd{4{awzMQZ@fTwvv;5y;W!^j zU&zjvlEu3Ldd6ML=aJ#mtxW$C6Jw}P2x*jCm3zQbP|4xxh>3jNOQD^3qK5)GsES>l zGj)9WBJgS3hnX4P_nYB{^idMPzvCxHBydUl6#aIZ<2R8TTKhA87J!TeOqD(+BG9qt zeV$kwu%q4#;2+elRfvt+t}PZ6V5@~5dZ4mTm#yl(*zGk}rA!l*J`XunV7K(#xVJr9 z!i{~VaYqV%-c2b{spN(prIu;oxh?0Go!fX6N*Pp+q%KW=8iiuVP$pw26)~s|td4*) zh8u2f!m0I6UjjCWQ?JzF%a~;Ve}cT>PY_JC3Yi^;rnn*c54eOJ1yqOa@7t*}jrEk@ zcAti_Q3*8t8A>vhD0O1Ev&=G)I3<)S^rF*`BXaIIQs*Jieh1pH^eP(e!A7D}x*q~p z4Dd8bpuLxJ4`+;=iZMJs=id>ZxyuuT=DdB_h@Qj7=@DxQ0cV^lrEW+Av z{ISC{-7NRMltvP{*z^)=yLo&r8WHrXOSAjc*lLOeVgB4Xl0?PD7No7gQX1mEOJ5Nn zKG;8On1eAwy;9Hk;$b$-%51eGjW(BE-tk(XeHCs(n3wcpn;LD-)T{T@lyEq0ptsTr zJ}}zgp}+Z8S*A5c)4~X2!c|q`!ssn@-a-60_Lhg169Snv=c{0W|eC3}`8>oF**p-HcaeCwC$TFYHy|#psEp zZ@_DO&&OXl*`ao%=VOkKmIMI}T@svxFg?^=Gyxp@p{}N72b3!9JkM-|!g|APe}tIv zr?8>zFoIe;u)!<+@^gqOqg=4_^CF2KQMwa3SavGuS%_P`Bi+imZYNKTa^mdyPNRNm z&s8`v5w$UTQ#i4impLMSnjo=0sZQipC8qIioUyTbtX^6e&(K7(?88#UwvD1A9Q^Y`V z1gj-9`AV9k6UbW%K1C_$gBGi3vXg)z2Ry$H5-zpinHYP%JD4$3l{@ z9KQsG&N)5p6ZD%;qefMtSh|s9R*uX!W2#5FZPX+bq;3Mi!fwYiO+H$KnS&VL34?|+ zk+cGb6F8z_A@+#F()<{apcDe__u~d?WsDgY1eFX8w?3$XPduF30utmUb<=T93731S z|4B;cx3kh|zASi$)43NE$Ywe;p$d7eG6h-h$n>9p3^PHQEgvfLQ{Vgz*E5IRr3qeb z7W(?1$y7PaOYn{)$M+UESIZ}cUulfEqL|g7&6$(1QwOt8*i)c4_CcK}xx5b+=VfJ$ zmPia6A-%e-`kCsSpG^5? zDr`3jLfb^8kvk)axodi8FV5}_?_)k2?d_noVE}hbmdPK;_ksR!#fS)jV9tK^Jmk^4 zwOjnwyR$1%g1_D5HrXG8oy_G1527Hn8I9PD9r{CZ%#_{M@uaEhLS~}AVJAL=&-+_ndgveH!Kc_zx)d(W7@^=UG3DYS}1Z96B3Vk=7 z90X- zc(Kz}iK%bF?D;62CET(dRyK+zbaG;zM1E>;3&Lahc_i`yOX%qSzzBDAL!iDx`33uR zONxDVq7SRS3IFfcYu<&DUO)w&$!)bCLU&Nvo~v#8`mn8pmyQ?uDw2;*OU0kCs#4M0 ze;T*L$=Tk-)O8VSC#>+rG-ZXwk?7REuk4thXb=xB1r7F=!L{a zA;(H9dPNHid9X%Vf-}q#1y~svNo(J#r~ZYC1ATv^&Hl)$f}N?SH&f1|5mX9C->60F z8!>7q=5+oVMguz)!qizFjqe30R5b)dS0jOtG$bxYR@*};)8Xa0E@>|i2Z>#D8>Mt_ z?3euMm1-x<*gbQ|1`m|ojA|(hCey0=Gpc{a8fGjRPH<8K0Nx-^U7AvS--HciJY}Iq z9ayL8LmFwWHCmX-!<`9iGkPa=4)(6_tW)$gset$zkH6By@JA`&Et_DZuA^NR++<_w z84EIVMk1$?VWvY+uoHLOm(vG}a0cPn9nkzw^{^UxsLKcat>i3p0@2~(y8XuET&eV| zdCd`=`m}nSP6cL{!`4DS&oFo7f=9ZD83omm1dXRGq$BDc>P9*!0a+%VrAEJ@|5vKL zVa)**CaKM<^dLI#qI$rNsQp4mQAMoZng~FK)M5K(dCE*0- z7+wJX&=WX4u7IPkc4m6Zs%Li4eBVmvNm9RGi-M1b=%Z7suZKn~y338~GEpcH=U>I2 zB8hJ=r9CWTFn3ne;{!P+tjFL-HPsj_j=>CC5vCaOF*u{I34##T+Gir8&qH~{arO8j zjvaFwMLl$g04VG)YW3tnrbD<5siKbF+G2F9w~a1CAK^uc!&J$9OeExolMB5#prbTY z@H~C*^bUepFJGR>RfZ6)2tItO${98YY4ckpl| z{hv>k5XB7DPwfTZ;81PjlXE^cna@PNF>)h+_GF@>p2n)BO+C7 zrwReDVgb|hK?}XW-rK4~F6hvIrGX6fOkrIvAfg@VpHbXgJ|drW;_?D_9mU)siWbE{ zd5nX@4jwj1+cwIPG&3JaEtgiJ^d^MY^U_8qNfy`*{&JX3NBcXiAgJQZxAyTtGnk_n zGn};5NWDSZq>YyKJ6?KzA1BDctY59p3XP4g!dM?I?;#~F?_f-Y{|iarQ5~8|*jc0l zeO}t9c>H0zBe0u$H>9#4YDaL4*9T)8QDywAe-<6B`BL`v|GQ2PZw&Xu?&yD&$^Y;E zH+S~zFP2TjLF|*tW=yG=QjXl9T1S`nn^$?fYf8MIEy~O9f+9@>#+4qw3y5G=amgLN zP;u${oN#ej-0!=*xHME;GOHN%dNN)|hz3_H{RSjWQyL^?!rFZ7cDlSXODP=b6)t?tj=oB9N!;hFA)US- zk7M+^J83fj_}}H@bZ}W^(xG*tCFhUB3tLr~GjI4eNZ{9UT*{XEV!aP}7AM>7Tc)gWh_Z%# z9{92RMb|3&m!U=e#%$8c!W+3FAr!X@bVemznJ~U@aApIe_!sE+14NX?)AtpdDdH#E zc1?TD5ZY#tRu-2a(g<{c+M|t{_M4g(^%Z%YA1=J9IG^kmZBVC+ZNgP#w@{W2yH)Ej zTbF_NLWC)zx`gYS|6Kl4QO+LH0?aP-y;MAX&JY}YNxl{x$9HucL-des_O~5s7-Ic+ zREPans#BRdnrS;Sbu?VO(8Yqlc9I;&G_RL%uj-U&+t;WPLd!X)5LHMUP;M)Ue7K8} zTTcYt6U7xsr0PH4>)8<^dxII_5NR=km&-8OM{z(2d+H8)C+id(M z@yF@<457Nc#qR_7BfLxF+?E1+T;pYD;RYA$IevTbNAx9U;|3SEXX+O6iT=20j_<1h)7hUiw7yJenyvYT>*#%$k zg5TqUKj?!0mkYkj1>f(29|C?FGP_0V1NUK2Chxk?f8v5uSq)cS6I}3%fm6K3nGW|) z5O3Ip{;Mu{gXVMS3kZyh`z83LdPDq!a~Sq;{{pw2E_}#V4k!OlHJ`SK=A(W*k88YF zzV0bm8Lm8NVZPhL@8* zy(0RW%b8rYx450C@%;{bnxVf!(R2HY+pxxiS1O#_THJm`;9H{omA& zC#La|uPA`qO5Cp3c$YRj+`a+7ANX+j|EQ)fzgqF(HVwBuF7*2~{eCStw_6lcIRB~l zkQ<=d`sNkzViv29Hn)1}T9>T4sGfY2O=()$T8AMole9L}tz6k$U)$WcG7GPdUeweY z&4Qw=4FfNzNxkL#wIva!)>&+uD+qRp|w@u)27lxJ@Kgp zSwrgz{jwgh>sx-g65^R~D`LxQV=5#?wW6-IwRv@Iv{}bPQMN=|YcrgeG(;Pl8kQ}- z$#7UwpLyA|qOm#iv}&1&NeQ*Q0iNVYL=@4g+U2oj(IyDm#0jcLl2@`+ing_Gb!$VT z2L;;LSj!~{(!~vHC_H@C)j|xqReqmTnKw1AB}gQr-VUOevN)2Z$(ee(LDn@bu3c5v zit-^wD_7LD)YdItoFznEYg2ToL6$Ww%1EW6fLtrct6fG+D5IutY;3As(Xd)Pp#WDj zi)YX_tym&}`ex{yl9)o1wuwh7&E`gq%jg5-K@ns^G_52e0n{yO5>IOoJVT74R1aDs zoAH~4#GoHW9z`<*Sh=*Rk&8x@Lv#qEX!BB4mi3&Wwe?FI>TlEv3=x`J7efc3n~NG$ zkM48IOmNSTcEe!5GhgQk{0xC>^E!n7c0n)s{F}ffpC<$^>Guhox^zaKZ^ORRMZ--= zPj;Lx!X^KU1up3qx!}fED)A}BpNaQw7y3;u_%4AUAkzeM0NT@Sn9dju}?|0g6gE@!-d6}Y5tqWRHb=%WIc^hX6Q<-C>#j>GVI$OZqk zz-7L@EO5#H6BqoF!0_?b2wd`CDR9aEJ1+QM7kn0Nx5nkn=d}Wt`v17VWxVgW;G<6) zp8sV6m-@3@;Ih0P6FAv+qi<)>r`EVgewjZD1b!yo8TtnVF6nm(T&C*_dcniV|7!x5 z^c@11{C_KON&gpt%k=t)2$!>5zASKQ$G$Ca8E?11>DJ`KUtI7rNeEodc<&Q9&7l}R zj|#j@;J*{NjCUF-6D}wJuL_)k8vZeXOFf)KiNxjPGhg76&$k3F<#|xxbZg?>EpSPH z#04*=!oWrHNc-F&aLMN}7ksb4r95v6T=JPrk>R3vWqQK`m-4g-T-J+q0+;!`P2l4Y zhsmF}1uo-VON|gNlIJY^8Tvb1@P8G!ZZxXnS_a1@EcrTzr!sX=CC~(QAL*P=*hh6Y(F8G~P z$#uMv|7L+pIr{}J<1H*>HY`6yW%6gDz$JY#DH$$Guf#7DxRmFs0+;f%g$wZ zh@3YGT++WSa2f9?J<;amKSSWMooWzx8ALGobGyK0yg8J)xQM@uccQ>0{WUK5E*Jbu zlI{Fn=V-sB8_Ss&*LoJ^pR=OKYh`A-O3 z@;UQ@41Y;~p1>u2wZJ9)5`oKl*D7$y=N^GeK92}o(*IWAlK!y3C4K&s;nOu*;F5lu z3;vqGWxVeRT=FTqaQJvD1TN|43taM#yWkJF;7%S%FJE`O?%3Jr$|p^D}`6}ob`oFypsOgF8H$om-+BV7d(GPhQFj=E^sm-CcQ5RT*~vlz@?sy z`C^8@q>s4ZO9cLD5${a`m-%y#z$O20{YxfZ*+02zW(Jq^&$!@EU6P@f`aI^#8C<6K z%L14DPY-73CEg-%na>*qF6p-mT;{`T0+;lkxZvTChc9YhWV#v!UWRw3+#eLUY=1qo zn9Y!O>YFaOC2%SKe+pd6|F#QWFgp{k)RU0FC7)&&d}=tuN78q?;7U< zflK-`t22BgeY3#F3Hkpfa7q8J3;x;5GyG+|vjk2i*_8YH0xuKz*ehK42wdjpK7mU< z#|19s8Fyud|2ZPwnF5#mzw3e*>h)(ocu4+Fy5P?UT;}I{0+)QoUzL$l;&TKp`LqaJ z(pSzKp3hYRmwdh@aLMOm7yOK?GyKUkn(|%ig5M)>$^XX!m-1{8xU4U437kxwiMM$E z@bZimxa40ca4Aopz@?q}o4_Ugs%wUi_xl2u@%9K@@_Ad}Qa|^QqTzDto7u3em&y1Ll-QyO33;Il{L z*E{fMHNMb+@7MTZ2R>EHztn+G*Z49A{;V#S76*Pv^N%|4*EGJyfu}Tnvjcxq<82On zK;!KW{C$mgI`Cr}zr%r_(0G>v_nfAHdmOl5+-e5fnTceCmi?{8t--B<(mIf4t%P{_c-wB8h_S- z&(!#S2OiY;^A0?$@fRII@`&tsd-eFC%YmDHo_}`WW}jz% zZZ;pYpL3=IH~TrSci=U;pWW%e&3?|u9Jtxf`Md)+`#DSUvgI-RIin8T?C0F*z|FqR z6As+$&-6@Lxpq1B>ESops(zQ6yVizfbyK1ZYoeYhv@_E)Wzou&o+*sBHY=pQdHM1N z>~x&6qB+_y1z#*)urgX#f1{>qSX$fIN}KHd_g5KMP!-VGWHSuvyPsWaLwr+`{m6TC zNOgh^{NWoFuyKs~C9_QNNthkrbc>c{@?43BND zjg4x<=9K0O%gV~jGMBnn|EEoz$}cXy`13O^;=6?-Z>_AJd*Og5v4MJf5o=Dq`evNY=)qYrJTzE`!%$BSt{P?S|L{QHF`To0lE0XY1S-iL z{2FuWS#(DkpMR6080f?^aau!HVvhe3;<7sT-N5ABon3TR4USnWi68qoIx73T8UAKH z@g?@L&AiNkb1za*9JEk!!_F>zTMrTWygxpSW?EvTIDrGFk^UM&(7ba|^y>CT{{OJg$lcHh5I#i78In4uq%c}wfBQcV=bqtE zpWSo77GDmKrDX=Y;y=KxH>)uD>>ZqqQe}Ha;wNwqH+tT6YyyZIR1lU+)Bq={G*dXZa^l|At;X%Pjy_!DdtdBVn|ilFx+NQ z*2|+uhMe1Q9nQ%xhv4b6hUyQfqXm=q+($~mqJgtHw5@24JhTmmR>P5T1L(NqnOJB) z&ZL00vIqIn#5E;!cw|v(8_uEVnFKkZ4%QBHP$2wH&0ZQwz|~an#KSqU+_p7?Ubv>Q z{#tRAxo+d!`6u+qK9dWFsloU7{7CY?Cn!eJcho&+dPZEW({n=_1Rk6vS7i-mpN~0F zi#{ebh%+wOQ?WVrm_1bG4vCD92gC*b0^ zTM@(8#(fXs7S1SsYU{s_KQXlwQSyQ3=OcPL0|}I#o)JNQfY=Dli~^fe0XT6PiD%Rm6%%smjlnnXYPSF)v-V#Tgk7HXAp@` z`cskZ+*F~(jGUbxnekDqIj|XL(xiLNRqSnb03)FeBS{?s?dO0WWaz<tdbW4Gg(^f{1O?TLN1iZW~ZAUTfK z93`XA4#LrnWD!{J)w!frpUGZxNJ@~;60*!GfURt(hYj!rzn9V|{_JP-}wfH*@-ANZN$W;8k6wQF)5 zErrvw;2%4P17v$CT#*U)67jQM?V*(*Bv2=b4&K5^MWVA*CgM}1ncw3ix+K{y>YzLdJHrIw zAm9kTwSq#y$Y60!v#hJz!0n5msim-Dfg zA|hpfLR;?kW#^1Jg}9w+Hw3b@ZZn znhs~*?S0YWtQtN7D!TyZQQ^?0!#J%gOoAs$aOcMX*Mk;L(}PcEYN7eCWO7bd!inqO zEu!xt-}G<*qt62dQF&sXIxP~yOr?%#VGJiR#_|wb&2>BBn?uJpo#M;Hi-_`N+~A}R z;kR;B$jn(&I!f*n<6LJ%Y4^bjqXDL-o~!QPB#NmAZoRi|EskkBIT+aRIO0VIJCsky zC&zoe?*`86eK&9_;!Ajq1o+LCuhnn)$E&i27Lz(4-l+`m!LN?Vwe18A+vQScVTxmj?H0na&l=MW z#J1v#sAl}2TP0vfV?_0gQ^Z-0#t5C}A!om4jLol7T8)mOxh%L-|CP@96y^E#5}W_$ zIeUpgM%^-uDH><-1`CLX*!LXl<0aCQ_S z9HFkx)eT$blvr)Y%-Q1eQa8bln1jU48I8gg|ARE}iEWLrFUq!r=~!-Y=5Uk`9ENmi z1a6;odL4J`Gxjkwe;ZAM@GzPOCNODp*Cdvf!CRx!mE`#DhapPw+%_#-T!Rds^C>G z7XwpWm2641bEsdatY9fJWva3w4_RSs2jwqir=3sqQfmaTjFy-H+lnVUN@a-TTOApr z^hhdE=1^gEh+!Kf5UQud%!MQ>7ZZ1P;yq3iCh9IVwAJVRqcU-SKV!r*BI_DjnOMvo zZ!y?|=g^AivTaH}(`sN|!zFg8sZ4QFF!S9;CFSwoT4q-RdAp4vT0m3{<`t zhF7gE#aS(gv2B?CPzc8QrtW;`Ks;m=a+TMdHH7CUDR3~nvvu3Lj?c*t* zv<7^D+rHQH`OMxl;imr%lNst61;B2IR!zalmUPZ(sE5|YF~EFud^c`FyW7W;m%6xPRbLMzZE4v%|z5jH?_xQ~K0=FZ@*G>iOPe4SMSD>AnP=%#Vy1q@=V% zO5IR!msZu3iPjrgy=G_s60@UlU-7YY?0`vGn#iX!lMf)`edzLTqbYOrv*AvsJc5(N zP2bOHY({uSe3=siYr@?sHZaRexqt<{s%&AGm+YD z$`I@2OaQw3*RnL}<*Z;HV{tsli5$$&&C^-&F^wCj@2&;}GE+KwbxRmK4V~$kRtcv> z_wRrN4MOG1T_x)e6-T#0tyD%BMbPQyattT(c}ik$lm;UsiJ2;I=r;}z#zDj%+nTNI zEgaQ-x|e)Cdq$9-0DY!=_V^s9Fef(9vg-&>o5wR_Zhqjl?T{m};WY>Yql>AGQ>zor zOE1UdP$=>B6GwOEL@$6l$~?S=LFAmuI6u!mT3Pj{mIOBCSTDs>UydIe8CZV>n8W+u zn!u)D?#x8=@tNO={&ME1=+6V2W_?n%dp8^z4PKtSBLDK_oMUimQ*Hf@oGOve?Wgk* zW3^Q@zG~9$Lco?s_>K4a;QTmANXVK~6iL!b9p?O2pNPbF`w`9M)|W!o*Wr)0vZMt6N)=~#x;3*g zoce0T4Vi(>Sw67JV;FfvA^;9qbHR~ENBQxN`vLmm9hALr$J)_mYzg_Dgx{VbIG{v= zIW7CDt=-HEQk>jn11Hx{`#ogLrOh<9)76j1?Tha%)gi98YB4%vA!%S=v@;v%8ePC6MG zQ*j)#a);s^tjPuyhCOVJACCf_YKE;!X7&n1!%Pfr@g@xR81R}wF4Neeb)kcvnuzJk z^cAYUaz`2KRi@sScKj(e>eu89!ot+@QziN!Wm0Z5ok)_Jri(ROFIq35u~f#A8_Qxi zreA$3J7)Dq;gXBXuz!mJVyh^%>|QD{on=B@frA*+&oJu`cizA+(T=F_>6nsJCAFiM ze0|M_udm+t%pEw7eih!TF-Phuo*L8=+x4Ae9~pxiPs$*^kg8OJ17WC1tBYQE?jf*7M+GnGP#Ea zT22+yre{!|+T*irBnkM_gk;5Ac2|;lXNU7rIIPd~Q1?Nv(3rt7bJk8r!ilrkaRAjT z60Bm77#sU8PPFg28;07XiwlM43bQ8^Ga6W(!(PD5M1uc%87WO0gpzZ;;l%jcs;u4B z$;lmvp4$9a5)H>{sw;Y+$3SU zCD0+sX9rx!KOah5eJ>cqb`8JQAeD)PcF0BR)mWO2o!tdQx+Fsn}kScc;k*oTx9ccChx+9>VayAjUu^`NXBQIjW49WB@Tl$j7*Wm%5(x zUjZ#foK(q8?r}bawsCdDf)~9aaVphHAv9d)GSi`{%qRY^frFu6)6yUaf5dVR#};9K zK`)76$odiSu2OR{SzLM2aJsNks{g`mDT1OQnoJEHOMvmmEof(X{Bb_gj9zY4{aX>Z zXuNZ>Nqi5b9Wih^RowPMWw&7jS16PSs0I*i6ZL{0f^N@Jez9Fis{Z0uNuaTIJ)!WWr21k>kD}p*j}rGJq*Xab@loXP zJc>BE?SYiGR_aQ^Dh`IFCNC(4F)X=J8ao+d5CPtf-oovwWI#DV8A(h?H8}_u9p#NK zGHCp06ANKBVK_0Laz_bT>3yRz`3-OSN^~4-du=Bh?3lNbq=+2sC0j~TMSq4#f`zct zj8S}g59+qI=c*#BJkT+dV36AA5=qaTb*;kds^sQpQ9tA^BN$w%2ey1_*+_8C${ak{ z?2Q*X2PZl_lj=5$K<%yC55YyC7m9fnC8Di3wFo8E$z|iq%q$Wn1yDLqr+$eAG!_|; zaHby7GfF+=+Y`C|3z7t{aBEj&yC6t_(97hljGV;4JNi?RB>agcKZh`=oZ<0h5$}Hb zooGCeq7CSUhj+Y=e*$mY<6&Gv$vNJt`h9E@Kx#H+gcJTwE=EowjD?koAHtGCUSLC- znu~gWoV7LLeR1#*=DA-P(d=N|!W|3ZGPC3_aMnz&11@ZD^OA^oG0J=@2;n2^^8KKh8K$UELVdp$1h2-452--Wnikf;PLbcGM5IG~%O6WhZgm!e- zQFL~HFT{JxkczCehcBCI8~-Fnd1=(P@!-fazLt@W^L(T#iuCQow=1*_<3uEwN{Rd@ zm$HQH#aNXQN)0}b($|BU+LsVd|EIr2rW6UJHZL`OfIBc*8J+1ba-=k~mo5bld;g37 zdLvi*P3GMW5@mO~@vG^49{=_IFQ6S!{kW_=Q#(~;*TBxRb77X1UYYu*x1G?yb7=nw zTO81QJ9;$GB;I)jF>RqoRZ>0REXwLqk-ti!L&N#;2W6f zT5QK-Z{@fWHY3YMo7Uax<4z7bJEEtv6<&=|DrgWU&!{X4-1bM*C)F3%wi}YzMgciS z)q(2kXkE0pGa}UFV+UUQL@>Y%NZ{c!1MT$90ac_Dtk(xw{VC`e=$C4&b#_xV>jqzD zX?J=|lY|hZ#H0wpel)}`lW`!1KP3i`l|8Z-jYOaF=F>|;llF(L9Xg{h-wc2Cfp(f< zrC3LA>wrmsKw&hqMaTk^C7cqD7tPv4+*YKMW2NSV6cM+H}_byb`YHngu1O04AWOQ9y zP4}$ZPMfLstk}#9B}iQ>REYFhU`KWea_}okGh)(pu_W~UREXUSaX6iSnTcZbL?7V-6x(-sFl#fzsFqhhVmllwiDB5;tIZ0$mNfP? zJu`%nwds)zw>=K8$q2D~%ZI3NAO|nT>s2OryNvG{h2b*E#=Ny_vF!OE6Fbd28wutN zF9AiCS;Fd|II|+j_Ni%ay2y?%zMUp(y{q%|{5N;WhVyrO>(WFC?ft32q})puR=IN{ z$y4?n<_)ZgiPedPm=#@$zcQAZUEL z3^L*ay?4OgfJCGCVJGxsG>5-Hb!^l+jGp3;KnBP;Ek$x-({_y?mX0R)*#$N_drOfL zn92ws>m{e?5WBQ$x1Z+kNbCi|z2#0VyL10$wb@@XX1v(DJu>>KOOVZl(Q=V`9w#N{ zkm#5~zXr7-85vEJaOn@Z1JH&Ln2n#iW?MdP5-lcY@9o4RZSUa?_SV<@aOhrw3E?r; ztbDRk)ZrGn^z15Kk`4QelXU?0U(1QFX+UHSflck60CnAM>p~pWHW6mq6z)JGIw_^Bwf$8Mboz ze?WYZ88CmSO{z50{ZKLBTm0DLo0&W_datTeMX!>yIB-v|oWizp(sNLBQoqbxk;mF0 z*4;+MMq$hG8u-_}mgagBqjzA+tSH^gakn9ro_SkxLzJy=Vit)F;qDFHgyV`>H|uGo z2pm!7<9#=wY7RpU$^G^x2ejL)gdOp=Q&_eCiJURMpw)#cKIw`-HZq*>h1%AXoE`lP z&FcB~Q4R;%X@8k23uw9rp2mx?lbL1*&CYh7aj_@5GgF{;YX)v=){$ol#Jp?I*~FW7 zE8@nZz929&gl6VkW-!S?j#)G7U04?4lI1d0Lo^#HwVfYt&6 zRO~x5{d+jt#!`UwGSp0I&;96vM4KA1jk2>1GA5F|R+}814}8tY$c#Oaz?FRwY|)+c zTot+{fDhdANTg%$E&m=#Jl=^A5$|(Yu=-x)!(oR)gieQE!+H)}~ZXj>PUX*1SRbXCD+q-%U z-a!Dgq5fIscGI4~rl%rMI9Q~mkQZi%77ill@v{3roj%?siS>*GFLLbmQ$jq02gr6& z3fGKIbSy@%3|VuAsOj;i%D8CIt||B1n4tFbzf58O7nc|7Xk=sjo)KO@K2pr{N(AOTF$8aQT|Z{qehM@9ChL7^3fHe$Dcmo^m8bu z&cN}Rr5@UG{+WwEJN2{dZ0mDl&n!E0{MZR&&l!8}*okAum7P^~cA00K=Pb|J-m^U8 zM@<+#;dI)sd5#_LxwxC?L4VJ4o(DUWa834Hz`u@v6DCg>7SAG^lJ)dIeYntjp}%}Y zd2V@Ld49R4Vq|$?c~SW(<;CTJ@)GP?pv!xa2m2}Yb+PAS&s5xhzIR&Rv>nqtUx34` z8J;hC=wz{(hUowQ{l6#&hVh$9sUNMg!09`+1o#;Jj;bkLrTEjz=7EVor-FS=vj0?~ z#g-7h_!y+GkiR~1zsIic*k9W+{eBWGkMP$9f1L2en(@~bD)e1%J8Xk{J&yNb9TttM z$5Th~){=`$R_3SlyR$T3?T@aKe2B7NMD|DL>w`l&_ztxFBC`ezvV7gzK1AVe2(-sEZ8!a9{P4{pAFd90 z;R_Pp28Z$BT2<(~uQ(Ec%Ubk=LdC)GuvC|_-@m1lFSy9(mV12KH)qh-H7u)H%HQc@ zniuB}yaawrJ8h)0+^^p?QDm&2AXqw*m2g(!YW@x4)iF&sLZ@Hn73*TSxa9`vW_50% zZqOZth766Q z#}m|aSOjF5@1W?6e`UqdwhzlREq$-A%4RW2?y^Gi$BEv$=MMdz{J5#~&$aztq8=-M zz1q8}$N=9`}W!$7!1v*aVO-)M012)ideiwkGFnH@iUg=TXh;b0i1KF7CUI?az2T?$Pg- z>vzIeYMm)Cvh@R+ZXD6Uck}h&K)lV_9#p0t*zUOR8s;6u<9O-@;=25wt1Ca0b%oCU zA^DbS9#qbXe|7P~8&$oWTX-q!C&_2d3ZVH$l5f72?_nbY;n2sp??#r7^7twJ?rpa` z&h{yK#jv&o6)6Z_=1h^daIbWP_1V~ks7xDN;eJ;>!#pvMtFaPh@Ho*H^%?8H>YX%NZW2(DdX~4DXg2-6ELFVVdDtg}w)d!G>9`*u0T8$L zB@BDNp87^?Q!jVePw4f{PWw3#!6(zw7p_+N2VPnIizOMGN%eh!rd>p|nRbTSqj|<2 zO~ZbYMk_tuK&Ux;l@pJx0d&5jdyF?$o+L-FKB$fu5*U}-!xvMGm`t= zzy>tlt8wmU1EZsIDBk^AKe+D<{4|Z1pMnQm20vTlT^fH#z4lzJ@gU6|;o^QTe#08? z*0@RUe2oui{2Lq!Q^XoyNQ!}r`?2_4rSXj#=RPa&^@fkexvvWReuLAO6}Y&MiQk_Z z{4|DD9}>5;G(h=qXq3Xae~8;>G+xd#e<)w|+Ve+^*Jzykd3cx7c(2CCX?hyp5&r>= zll`X45B(#&>oi_|F~iE{<8}pbFY=*G!SfR=|HcLXvkTr&xKnxX>_t@{4lf{l7=0^s!6&-l zpLfCMy5Lv2;EgW$Y8QNi3;taf{D&_1Mi;!#1wZJ5zwUy+>w*uu;HRJ;L%!t8FH(ic zeOug4&^S+^;`u@K+A|IKaOD_w!LM<_Y5rn3K5Jd@+gK!MC~KdtC4rUGTIE ze#`~W%Nstur@P?fzuP`U(Rkp7gZhS6<9wT4c(d1da?7qY=HnuBmlpZCz}Q2A0=Fm)0(Wi+2;20VHk3 zMUrB9^J3$&oC%h~WxDa0&Vck$&OmE(Y=v>+4yWaCEKa`1l@#hZq zS#wqtbX*9Ix9Nozk?jwQfqe5r%!y!!tYdh;kP)rTtD%mX7I{E^@0%8{v8gFeJ8Py* z)vD_ZpHW}jF%=;?cCe_8O`9rNE^6R}2^mOR75$PWjmw(rICWYclPdkVe0lA%=H?q? zEfhdw(YmH(4zlJ&->6?MX;wyINNVR+UpXsOU3=x6IrA#7uDv=mtGcq*v%F#X^5#_y z#IU}3MHD&S6s=!MkE@o~)~#G#yQpDF(+Vx%ja)eNV3$&D(~8DsM(P&TE^A=QdLx=q zcLYF5HZDiL$Cm3H&_GLF>q?Ft&$VRV6m2aluD)Mdx3Z-!8f|D@kyRks%8a~ss520y z&|rha)T`Q#2Pjuh*tL$N07H4?X?SxZ3V z$k(P7#)1-1-`uiRyl-qm#mO+MTV(7P(V|MK%gjfhJL;K*KkT68YrTF?_-ujSFYvIy z&(z~CCm*v8O?aiCzgE!C5x5ywJLw-5^pej(7ksqtD-)l&g8wRkOFrub9uf5aA#h2* z+XerFz-7AVBRaaA>7wzp!D+6}Vn@da4FA0foH`l@JkVg$%kIfBmyfy?whC2+~-hzp*R zpW!d{^BjT8{HbxlZxXo7H~PkaE-HSR5BIp>eC&m$mwXPo&=(gFcg0_(_lp9T@_$9( zl7FkfBj9Js>xTlDe17ACzwLsTjASu~*oUvU;B^9*@~juQlxM38{v|yhPWex5fl1fT zUGPivJh`*Ht`NACCn|6$&z%CV7V-88e73;3v1umm_W?=O+S}e9qVN|4uot5xC^DUf`0?CV@-(zY1K^m+AEaidWLl z61b%QrogWd>3Trml764SuN3sB=*caLcb34<6nK@uFBG_}zq1AY6+!h&FG`F_p?pCNFW-uW*0Hw69_ zk^f17OFqAF!T;id=j(MSr~G3CF5|sQ;4z7x*=T{sDnY z{=X8q?4P_Ka7iD~>vt5d# zi+20tB6?b5H|6yujngoI)-nx#oxo|0+2A+3@VP_a(oQ}g@UII#2L=9BfxjbgDd%~5 zJ(T3H74&xsT-xCW1uomcT>_Wo^|HVh3jRL5-b(Sx{=oMH9v1Y!61e2QSKzWg8PMyt z#J^7PStM{Ne}}*&|3_T#H(c;D^tv#`EBS<6@Z~P}LoWDkflK*66u8WXF=s*$Tuymr zy5M{g+c5OUTEAx4wz@KLsx7UlF*ZA2~h~uf#7AxRmEUflK=T68J2zH2Qf| z;FA6`6EgAE3i>MqF7(y1*s>e-*ft^RU1rpMrBaT8>xBQzr1mATjw|E^wJY^93&B{izFnK;W|f^W}*d zc_bgp1!osS2txTL%kc$4FYylqF8TW=W#WzC)};3;7yRb}mwfPzA73Po#4mKgZ*ale zT<{+Ye6Eo5R|1#)iWdalAm~S(&teX-pO?7ci(K%V1TORK2LhM*aKHukPR__9^=h)f zC7-DRZxrcTCvZvseSu#l=-(E&q#t)dMxG^tzEa?FTpV@5zbkOb|2G0(D)=7~xa9wV z3x4jDjGU7H5- zpEm?9`4n87kw>O$yufFJ#N@;E0$(oh*90!(Et{(N`|v|qqPxeQ^9BAT!KYK>l>f~F zFC+k$(;mJW$lx`&HF7GH_B5)$k3~B{?+iYu@q8V?;GfZWkpsV3<9hnX=EEPIfp)Zm z{&`KWhlw`*9^HBNmZ1~=hNyaqRPWtza?X20e{2X6LB zmpgE?A9uO~H~V*k4&3bTB;BCP#B26v*C^P=&3^6$4&3bPUFg8gKGCHP-0a_Nao`(u zg4Q^2voE>Lft&rWoetdWd+u`JWv^C34&3a6f6;-Pec^{3_<*j5DF<%$sSh}Cv(NaL12_AUSrPEg=!x0K zoKJwj&HnfjC$7hbr4HQe&n|P|=DUK44!k^9#aHgY&3^0Y4&3b94mxnNzuc^Y(`%~p zX3MhiJ#X-hI^G2iK8N)4LI-ZXyIAVL7v?DWTO7F2r!@j^QKbC8P2e{Pyi?$<0`C&| zN`c=m@TkDM1s)Ul!vbF=@QngrE$}S@UnB5dfv*+#9)W*T;QIysErGu%@S6pGNZ{WV zc$vO8_T0SE&6;ihOZ1Bx2mM0*Y|6s$*{JbH9rQ*HQ?CtuIV%^wpVe|2+~`BO13#qo zq}qWSy)xx!_?UWO^3C8zZ%;V*7(HL6h9kG-HH|<4rel~yeJKlgUMeZf=5P9eEe_oDmrOk~ z=`#JgLk@bg5581)pbfq0r(N&B&Hi}Ll$C3jV`nXXqpj+9skv)ySXMVB+OQ_-nL>N< zJX02}TSpWmz+J<9VjkH!ok_fL)_gRy0Q&rp&!!{sq{STYsYt z-LSN_v9)e_gUX8k)&DYtCex?Y)aDh`cMqC|KtG#yz!1{11y%K+0rYSA0(G-rubZ5L zM~X+QAAjpk6z6DMn<;|$dd(59!L^w-k2q3F@%*2LpN8`fxj>6Jq%spKC z*XT}EP^6!#ya`{b84MRUy_#OB2=;3`QH;k~_;ZFQGw3Wk3Yq^E`tR|arR}qN8k&A; z7KaPJ6#HZZ`JPx#JsZ!*@PwuMGz_AGjhp`nkZSD{?~@U78zz<<{t|#9eQKdd6LQ z@PF0#8PBaM!10ntXZeHCbHg+GR-L9891Q_DL!YS~*c2KOPtBT{8~7eM)^+-b3v9}( zR_?1RD-J}GT%)U%yrICRA_#3g)Axoye!O7y$C3Kc--~$P9efpMJBF?8+wl>B zcKRy24UYZV_XD(j(h(OvxBcjj>9Jph5NC8GdtHxz)EIrh+J_kWzYlqmHQx9~ErIsu z5je1Et`Cm5e3SsMwLkqu?0Pn5Izm40p7^VN?|yX_EAbB%JOg)82;rp=CFzlZp5B`` zr=|yRlBmj8;6AucLzp3H>==XaNEOa(r1W%@9}^37=)P-lKhI#tM@)zG~~Q>Cp(l`RtGP;_S}d zIS_?Cdx=9u6C3^vZcwxPiRq3=-yvV$8zbU}ZjR)%Ki7#CEt0sejb0rI;mH420ytDV zGUL87ltpxW@}{=1H47fd-pCDhwt9E@0uhUeMR`Y(myU=Z_3qyA1ej1YiA>sK9RZ_A zd^?XvtXbaZXOcIy?3y)*qe0*B1v@V?Tqs?Y6}|oU33=&=(MV!*30OtW-%OH465C1k z$huv`KZRS5ps!Bc)dnQ~QCXm!YLd05FP#(G)=NcjC@=nsH=OkU9ymVM-yaV2yby{X znjZG{RtI`^g*ron*8b;G!M2l61=L*8WiZ z_=!L}eE_}==dKQV)}8#s)98uihdN8PG$LfEGdNfkPkF1Y4Q+VLoH-iU#7AI<6C1jL zTYK6*Y74Yq2tJUm5=Uartqk<+ubiohD?FtQ!2az{D7EekaQF~{Oi0!RJnnK%x2uSbyw|2!3`7cj~kea?%PN~>O z2@@iQnap3Y7ooWk4D}t#@oo5b1V>)Itn-TUNoOK5FO&@X{2}WA(37F(-q2#IJiLnp zPWeLXP`|Lmm7I;U?{7LDKjgc-zBgR3A32*0dxP;~L1Z^-lAX67p9pk3$ma@stN~;x zSqZ_Woy8xz4Lj1g!Ut_94Nq zAb}z4H=+37NOJ=1zoh3tPj6_3e#q7!Yadc!?TH`Giy!ia;vf5Cqin^=Bsf{5YsU*n z*v|MX)4fLmJ@17&s|Ky-o=dlVjGAE~o^`L-RpYBVg;R72<0nxwI*8_PC=t)PkKJlU z9*!37LJ2{Z5rK{yK%A|u=}QShIal;jfwGkk?eb2bLY&oZCDY$u`Jllq%krVJgl?uhJK5BuI z{tq~)^&B!QWJNwEHAk7FwC$4adn0Fp$Cr=R%3H9@8h9?nMP9I@Dj7VPyfhd+rSI($ z+<#KAFVxxcNdy9^^6QKYa-4&GujI=(`)^n8aprRyB8L+*$erKzQ6T#H_$vc#AGO40 zST!fCcd31NBN9KH-&ylp|i! zPM=5qHSGFe!MyK?HbJI(9P7(*_q`1hlUFrkfAp;QVQ)MgiC8tqBJtG7_^wE2#2f4^ zk7%ogc9toEVJnDcA(gjoR}dAwGvbTygIwO-S+tZcPx`YcIZ?rMoDu6t1VT>gi_{;9 z%s3J&McIJih+UqPiA<$yS8#AYUid1G?(*Q^Viq|41=a@UUuEslwKS3lpw8~2S_&OP zyBV_f?+Sf9A@p3TGjyB`RP>7>=#F*M(a8M~?;d!KQCb})Lr?WJ3`_r9DE`rjXa$N5 zvBCq0DMwhwQzFUG(a^d>9z-0j*hPFYde>QEy&KrHuYZ?FE46Q1p=I#CGAlo14Fn!I z(mEDLLC3zxB|}97A>hLzy&g`JRC;?p@dT~~P4pGCtoc1B-VNXkcB0#nJ{76%3a#5i zYRE59yb1I2eQhU^zuXKepRmxFAu3+xq z%rVikW}XtAGxLmS>&(wZr-TwEVe92oJ=7*_y=dxHHJQ(sQ`Gzr3Sry9fSh>M zH96v^)|xoqreu4G5}Sx5JFiFBR5j#OY*lzoAGTg1YD2n!NXKbXk)!0JDP(;Zx~9rH zsZNKteuE>X1MSP9hG-rZ<%X@-Km2{L_pLlQLfobVypsf~N~~|g&wJs(6a5{3s!I0I z6Z~$!ft;;Uogy@MH&^Rk(XQafw^dE*MO{NjCIzlRUzNoiaJYB-FA$cy+F>hw@KC5= zJ!R&sWYH)1@xWDePu{w?C$$cRS~=s*=!jtZTd^e&faKWPrb&<~=ZBMRoGG6=PMMOX zkd#-UEoC4|d4X0XSbFm&vMx=fm&!$Mcl;@Om2j7&?O)h>MH8Q&Du+|5{+}wn0*J2G zR%#?Uj&;wF8l`>!k~FoXraVD+9SCnw??cyfh|mob#v*Ty=^GIOcHl{5xF__45C7BO zVck>Z8M5|JLB@{}~8KeV>?KPxtD~ ze`|02@K_2y!8+m+TIto^^dW>oy)NEz;=Mo#SCv5J0KH7_`Um{1ENKkCF2V0q;&-ay zw@UEakK^|zRVTUId2|Enx5pbDMc#M}Dmk?; zuz8NJ@shz?1L581U;C|D{ty_3$P?#FAmK`&-tVxyI|G|X!uQ6yj|Ojz!UJv5?^uo7 z){dx;ozD3m*jzwkA-o|lIuO`=DSREPrx?z7pBC6$o*07LQ@AtER`BUP@ zy{qPQ9KH1bk;eOcppG2~%}Dfu?%U`g@J(RTY(M+@Jq3OwKHVEx_Y{d0KLj_y@l=~h zU&r7r+v4wd`)}9vvtn=mCSlOJ0-Jnj5Y7v+s#`}A8z_#@!4!-UjhiAq>n=jpeMEzw zTc>vVV5`8}li2(e;EtowGj?yFJG$UcX`ui2NkDz$FZ;A+o0NSSv zd^fk@Agoi#prp63dbSfK%1^f^k>nVR~IPTc4YFd?Se12iq(0XWBaF z<+3kwG&A>-p$Z2cIJ~kbY#n0H36%c@_mZt7Mi_4*9Q+BeiAm*Pmxmz~@~uPRf_}pZ zgbE(rg*k&uVRI6Bxc5c#6W97@><`S{fhRvb<(sE`dMYwcW%M-KJO$~g)I7D((-?k& zJ7;7vJ(rnh#6{2J&9h%UPc+X^EP6lLJeR2Fa`RlKo~N4Upn9Hep4*VN_Rk{L#I-XS z!?aKD(WlVc9|aJu-qPe!4&_a*roEt@Nwjl=^yuTL!-f^6I7yU<{hZIw)%J4PLE$(mTdy^&YZy_rZ8%W{C?FzL26;FEl3~e}S?{m3<2lfYU+YS7^z!OKUqX_8V zOnLYzG?%*mZGq+vrk@0jswe9CKS7}F>b2V4vh{)W0{Qr{(EFw-39bf-?WEP!$*KFT zW8($_?JwX7hU1#tw&N#OPYqdr2wA@m#s7Y5DE|7bEX-d(fJ$(3<)z$RFWsQD7xnjxko!x#Q_WeYH>fndZjq5`! z=qFL9D5c`)|2LgaNiJ9WaCoY(AQb zksG~CP5!Wg?Q%RL->+=g_`f(YQ_tmq?oSaKx!?yOiXl8?=6z-qA9@ZlxJ5?wo`?OS=C*uUb#p#+r~&4G`-? zJcTyeyXs<9G=YvgnD4wiG(ITGT~v-y?z0j9i__G(G3h5qOoM~5v5{nDFp^}I=r4jj zrk(+fq_;H2r+d~MK`)DR|DDtm==2|*?GMHR+z>*i(G-$SLxbArXGTXSegf+Y5D5h+ zgd@Feq%r-yi4K~*rdh<~_`a$ce-5mF4J8q3yLo)>$!KvE%n-oU@1*w;in=pCZ{}d^ zdcGTxta*&mo)=G5&GfE52rcgduMjLCb@O%vHhTk`sz$`qGmxJ<+CG9)wZLY|+a1V6 zc&0*iz?k#=JN)hz`h0>kaa14wS_wlrHvgoQvqNWTT)7#OJ zo0zx=oj>%$qE*RRgQ2UdtP>IM0K5(@Tj!sL;{Ij-$S!z#M!xk&&rDp5HmnWJ;ajj5 z)z;tXMe0u2VZ4pKYWEkM>lO2$IM&B!Zy+ldJu9#$@MLd%pfr=$cav$8_T$$dX4wxI zj!(E3319DlO>=UsKG>i0NMrI$&qWN7E8BZxvtdO`l^ZGO=Oxq;S$(={2&`T4L$}5c z-#YFOfd_uq3fHTYb6+DM#n(< ztx|G?w1!gBzghH!*xt^^6ondmT^&03ddPZyK89?WMCGUcANIaIJgVwyf09f>Aea*s zHMX>d8ZA_+V5t&~nt>UZ;9$8bRTMA~LAj)10;s4HW+vn~jG};AYn58t^7YDBl^_C= z2*agb0`Y=);Uel8B7%y9dw%b`_C7O{5x(#F{{NllN#>k&_FjAKwbxpE?X@rG2PofF zvcBfLr1ejU*SkCagLwH4W(PDy;nF2OXm&lUS%(7o%|Y|sk%0$upytO7a|7}Q9_-{W z!mr}awK{@Ei#e2Mtot z8-11c2vZ=wg_MiTL0wZJ>+;^b?iF<+{FBeO&B0N1Q)HrK~yfjAVNx8e~nz zvudz7)AWYT+5ww|kMZ4vH)-v4GvXq)d`Lfea%AK=YD?z^Hhf!4k8dmcewgS_5k)BV z$Y;6e1$^s9l&ZlWc368Mnr_p=cZFMawKey6U4PvR<|_a!GdEGvhoL%=mx)`I*!G^Q z$01L6uiur7H}?GyDZh0Yt3NWgE6fio%!ow+v8x9@FeVmJW3K))5Y%j@{=05>-SPU$ zKmhGC%4NR6kszH0^>Mobl&ZgW7n2DKM`if%oW7XNqTPc@i8#M88fqNDbp`61cYJ+4 zfEmH1NRY5E<`%jul`sok#a+%%NpxF+LnSHuyMZvh5W z_0=21&y0pXx5JMt#~h-F5cL&y-D5P2$E4z}O0a*<72fEROM#B~qpy)GRzLVB7^prV z>2&WBiIO~IiiQ7-8{%*biS~mp{$O@lpuO0CF8=rOBW~IcyxZk5*K>}MwK+TpmFY^W zGH15(yQMZztOM2#xQ@CJTGrJ^$zE5F4e_&}dMKbsmwi*zxd)8M?q!6(MGX`wz>OJZ zJPNmr@CUplw+xegrd`Ll54d3bvrCKpJ;2c*!X%Z~4$3sbv+zPyri`PGcqJ1uzJmFd z`d{NA;%o{Y$ub@tiu=Z0IY^XKFO`p9%cS_`;V8gjkSTn~b+q|r!gI3amV82Y`L(fP zKz6CeKfbh=-whXpCVZ#0^AH+R1PIO4uNXpS)c=hcREQ$tJQx#k3t*ZqO^%I*0i<%y zixFodD9BW;-ui;kaE=!-e=H;j+?PG9W^rZknu6Jn1YcvzwfnO}LNVd=Um) z^M8X{i0ws|QCqWH&qhcoH*jBWsS&yvui%@M#Hw32iVhVa8=~6EvA5+t7NjVwllmAh zHd$SzN(miVIGX)8dSDq-$=V0{fr0z6LDmv`j+C9hkMyw5-M)9mOFWgqU=WNHR_F9ZNP&AtCJP@P@b?6dZ=7yFge77}# ztjY(+fWQZK8li3&4=}?!2zH}EoCtaDxd=tU3>o3)kiN8F_DqcD=FddJwFvZ{jk$`> zrTI1YNPza0A|w$9=z#V0PU$A$tI@FO`8PFOG3L{=hDgKL(gv*pemAr_d>k)0@Zq2Y z<;H)?hUR*b1L%A!O*++2ud<`qrt!z7nGsj*n+`Y|t@DsBxX;j@J-^+}z~KX!%HqIJ zGI4IE+F`FgDS#N#Pfkm`es{>$wOGd&97u6)$e@k7Je^wuV zgs+nCNatuy6&>%C#>f$W#D;x+rJa{PCWQ5isIv18t-BplI7Z7?42m?od zWP}C*r)?odKycbb0bH+84cvxjOW^2WBUFw=fukNH#P$2pd)J~^u&O#)!0-7wQ{K*8MR7FMzj+9h?0*D*8NEizxc!Dcm*x`YHrz3t&fBXkYO_5KfB zAHw(G5%Au2d;EdDoT#E9TBgz}xMvE*sc=`~u(OMS(jJ*iqPaBJ`%){YGbS_eIfr z_XpcEW_1l>IndG0#{AFlJ`$CVTQT4r08$xX_s6Ke&ueZ({gD7h!~w}LLVqUuhKCXi zcmmIg0dH%9+@?@8G(pi&W`S7)F~PWjC45HRcz`+(@hbpQi0A`;p!}gy{x9$@QU0Yw zmQw!tcutgW3vDA@2gQx82&!m15#H>-P)DOMR9WF`bn1}WvJ8J-d^!>;yAfXm`;PMA zbBmWDZUW4&H#}3`S@PZs}LV1{}WxE>tITKvrx(hBKD=v0k=e_fM~U@D)w+ zzRXIqOX8LAjf3pjun1@~x}WAfa^HOIlD)uf)Q!a>>jUbH6;+s)8P>`A*Jp&S2_S(4 z8E%Ka-FF*F|1kdIheG$t5AeBpRUYCzPckV;N!oNh9|Z51T|YX+)AjJy3J{Gh+=IT| ze;veEkAM$YXTd#UZ>pRHuIrrt2Na=Kz#?w#t#Ceu#TV_nbbD%X6N^a|_y}W})-_3b zI09aQ0q-8Xls*idd%V+j)`he?_#gKw{7*_R8WLKeV zw*-|Ww1!kId#v*jxrlS#c%fduLW*|p08lMMEW>&cVJy_@ls7sCU9zZ3tnAcs3D}|a z3+X-f1P;ugw05)Ytt+@6vFW*JeLw62q`+O@6TM|mJD}kjm#S?TkB?rv(EukHUphI` z7yU;7tpOn`w63IKfV;?{0lx80xOMqEfayST84I9HGg_j*oLR&C+D+2=QPibSG zYN7cENkV8eRu^D28fjo}dTj#-3dXz*#1VP&2!0~-xAVn-TqF2A-zmG}jSMO9MF#Zr zMte6#f((W;+JsPh85VmL!7$ewE9T_7Be~&r|IN`~wciMcF9Xs#x8B)$ZqmM~d4!Gr zD~$#?a5V?@P#@6%;6MkbE&IC==9P4Q5v3wgm8K^%5+q?*tzpUyDV#Tny#k!GM7&xB z>RW$l*Vh|~FhAn+rcmu=2-pdt?a65noJuKBjpaQc z@nWd4!jod8E~Qz;#(_VgRLJS=okE-My#{OAUS}x1X1b2NIc`Jz6^L%f^3t*K_d%#` zr@#Z4hx&(31v?;i!&tGE0odtWyA>*?psFBo-_3lc#Fj@_7YFcbeF<5yOY=W|n+?BR z?A9s=Y?c@+6gmRBS-H@rV-+ntpgxe2(!DO!if*=Oo%J?;>hxx`KmrR8OY%i4a((6= z>MFxdGD+}P2)Q@%3sH2uqX2XL5Eze@Ca$rm=7jypXk7va?$L&)K!q1;>uSH`#2XfZ zsNP^|ae*&75e8vDx)OK{0yX1a^Aod448uc-rhA=H2Kl22C(Eu~j_}lDGqwwHpC) z*o5{~7$8B1#DOszt*ULTdB5V;i&OL^QkC1fEalnkSIlnsUp_Ogxl@j*JgmlHg|+6V zGyp@f<~9UlDea@n&E}Djp0EJ0eAsnBHlQvao4ubbZ~QdNm+?vc%{ks+%(;;yE7^%G zqP&|w$86oSXy>5ZTB`>H<`%-O3vo(AwcSEx zJG_xs*;1=`)JUcI5nEW*@5vGD+~E9kJg}X-*cM;s-J(K z^yw-69|5-~yAv%4Vp9NZLe)q8SW!4m~0 zWExdr(CR>YhNE^LSJqfrpV(DwRPkYL=c#5X@ubc&ZYFUc%zR6c_Lt;%t~~ev*4-4e z&8L)bQrHMjS2nr8Cjonv<1^`kV2@mp(Na|f{%UInYe9VmZ{HE8NgM=dwN-+3_8f^( zW!hZP#l;R-Axt#MKuBv(3ubOUSeAhp#2(7vrEgP#&xNwVmHvb-w3{jozl!T=H;I3% zC%F={qfmqgq46@Gg34Z?04+t>#5rRL^RK z@gZV25rbH_d8EZM8@b=(XvT#Y>F)}zyTNsFj?0WmRTrUDOqCBh9DW73F=y~N0Inda z5$=gQqEhrmm#|%Qdyu@XY?R&7D44m~XFc|&Y7}Ukn#fVsN>HMKcOzrjw> z2ZjrNl%x2%`wg^-VyO$k2x$p~i_k#GDb6+1N08fEfu!*wyji$bNri6K>v!pjx;6F!!`z%~`TqwO^HX4;k@dFv!*?*pHiC7+In#{m%A0xU{0-4%>FXj$DsG z%?|o@6NI^N#B$a}=~$ElnWB z`Z*@lk*hV-p?;{`$rMA3u8w_duJx~vQFQSBOgas}kX20^;Pb=9Fb`u&FD}S2&aoxO zYG>SnwkG;}DqOiED=NVZQ5tjCsVC{2KmHBHkhGmFgoRo&oBoXX4*gCg(@geozE3 zxAcP+k+sf{29Nm_tPJbzdW9wk zIZ&qX3kC*4m~LGPWiW)~=0|R2PJ?hGfVVYV4vo%b3p@Lfqxe%E1QI`XL$KjbS!C zFFlnMKPlD){Suae#`_{YT1lH&Dk}8!Hq56$gP_UXv9q@xR`J^%A?a`gDOw zQX=C5dwWB!T+wdbwF%g49S0yy+QqM{ZKtdn^BLxW!PC>89&DcC=ne9V(yTk+DnW2V z(Wco{t&@##x@7@<2+U3I{~{CiOr zy6`)k9&-n_>R;pv94jzF7dq*)4ETB(mVfdS;MkE_(un=LLfG~cPQcf4*N-aB3vN2s zT|c(Ci>rPRdRTT2Pr&7c$pH-inc_$hnBl3v1IGn;fnGWeS^Jw&?=J2VXXsSvN2RN6 zgQLuU4)n0H_VBRr9`h8M9SR8-hZ3v$i%PiTipRc)^ni_DLHpKQYuAC>Kv0CmhF804 zKjY_nQ6jMG*p;s&T7)Mf0BdYyU`hBqY93yl-Xh>F{CCUt>csSN(1UtbkRX?lsH9Q5m zUH&n&HrAGQ0rhpbW!Rol6=q}?&2}GJd0@0#4{dJY_8`8TYkdfL^ObySgy(}IJA!A5 zp@{p%Is|}>elMjd{+NKu9KpjQ$@lnSacmLK?Yk}>!#i0eXWa~<;@lFx5CQY<8mlMc z4P)(=k}XE40oB89STI&7tW9zjiwYd{vgsr2somXvvaLP1rIYnJ@qLb>7Pd92K^SLB zD~phpTZvWR-@UBHYCatxa&}l_KE>S2T*# z#VXbhgCU2cx}b?zvukh*(c#+9GaOH!sQoId{kLQ3WN(<d^@OWepZNzaB8cZsLVCf^dlFSku;m z>S@Pmu0z00Iq-_T4%+s5Si2s3s`uD6hC+?-_26NA1_;o0ekG!W5?Tvk`@|+=UNw1K zyBV8a9PvurC-4W?^Z^kF{jSD;ymk1yBMy!+HRIs-X-SFC7O{gqZ7gGGfUgla$#^*C zz?l}|03h*ENP>BoAGrd@3vg%$NQpD<1@4>=fut~FWka)?vBzABvEqK5tCA7DWo_VC z&g^p`8#5sQ*spyNmV|H}$XHXYU#Dm)eY9?X8T%eHZ(WU9RI$gx!#40(D}WYxNVcZY z$_L})`NwFizCpU+o?XE$=hlyOO0%l+th+x+E5u#T%~p-DnKh4FU%uL|)`GCT4%_-G zOTJQt6Rz;{pez17o$I7`jd+jQY^>diAP;%wGQTd_>hG=gZriFUZ}gT*S-czX4^d9E z7m8xhkO!Gj!P1o0Z7C(dKYfkunX<)KdD}fH?sQP^&GYna=Ne>}v1B8>EvdWDY_obG zT&TJwbnpPU%?&cRY{8D;+RtbZG3cHvgYJ=;Dk0+l*qF=4#fdzXK#vft1g>s(8udl& z**?99UI1&0E-9Pydc4=$i80aBwR3s&p9FD+1!nU_%-47$V~YzIDhdDINwFDuDmJhk z23iK};n=`aHE6tY^9g2ScxFDD6>o7%)?oiHx*6>MU5kc90l7mXYnjpr@xzE-$V!1L zHu#j^*Xx+8{+9Og=q;x-E?Dzy_%WNH2E5I}Jamq_#e$P_0458CW(y>`@(#6umEmY3AkMjR4u87CsjxH>Rh3Azm~wt`g4v2>H9Q7*%}>|M|uU9R~7Ns%GDF1GJB6nU1l z8fnZAbf#Ze|43%h&HueT*;YLg;jJk<_EKTP##?*WZ^B zUnM3O_7o%g;#?>RH;&{`LtL0t!Dgx+8v@7C@N0n9+(%?t=!$Gjf~FJ(j)VO#qXhPY zg`B);GhU2Y-Qkhqb@%wwe05PmvgU$V(3hJ^U)AvheTw2VDv`dcZk<&WcI$>@2Cps4 z6k^D706#{s4AmmBvl{Gv7mb>=3X&+A0v~F(wc{1G)-J6ReGl`Pp(8lIihl5bsPi+V zrK-mUoQ&cu3Y@GF_2rgD-F+~kVk>*2)hFu*oC1c%c;;3sxI6O_9<9=O6W*!AexmMN zo{{4>RO%Cr@q*5q>Ia-qO;v8L2%rR`{u%<@!vTGS==A<-hA;b|8>oLWV z8ix7{s-XK>$n#S|Fk2kk+t?dhcL7g%jspgGb(d~_Y}!m)lf5$D+l6~y)m=B{gkc0%Ir9kSx?(k^G368 zmW>Ya_k_d{sIirq=EAOi`~*@a;vZ|-mTclrUqbixA9SV4ze>RW1Gpv=v*-sj8*Cd+ z+pTK|{MK8L6C}2a(uSL>=d{g^4@C(akC7jWV@MCYWW%-AkC8I|TS$6>z9hCRs|wh) zz0nk<8jn@kaC{-2MV1%osO>sY#JXAm3fb}i-o_?-Fma><_f_B^hjWk!{dvTb>xoS3 z>dDw2p9WgRI!7kw#^(s(_QH@hYhX+ivoP)>xrulR#4S-T8PA|z7h8i!K*Frr?1|Hf z({guOe(0?_xyT)_KPqwuzY1Gm_h-Z{^~__$)|R0SAv+oI1*9cO4ChN2+ZxH}Tx5PT zld0uj@YK{g^Xzl6&jF~kn+XGRx8m+X>?ced29Rkyjy(hr_}14S%?@_I}`iG&{a~yf4&9+hjiEn%4a&A zYE=#x6z6Jrj&&2UzLnU?*VtW^5JeHi*25aw@ihhf6~O>kZJSOMgZgvmAfgEocT zn}z<+LBJ~)M#8KqeDYmJa5DLbn4=2DV%v!um2dE%4;e6C>?PJ{$Xu>kr{{pYV%;+p zP_26gAy)U7|EDtFP^t^Os$9fh5KH+Z#!JO0n`^{F_rqYRmuO6rL0oQR+7sR;Gw=w! z>`8fE-9hIYv$8>?AFpXgB1yo6cw$6=n!xA+nXtu043A*KWOtfQjp{yEqezY+z}`(?L|nUkKFa$~L)` z+)rmLc^&K1qGNxTuVvB0O>IZ9%-8w@)Iu;g{o~-lV0oF-7kxQ^3XAJxlrcMtPXb+0)I^SBiX0eh1I5sAs*r0yK3ij&w(KUAFm1KsT~-JWLkO;zG%e zpe%*MK{!+)z19ekUu*0R)Sn}Tkw)l)^Q3anA-(QUjtL5P{sF*pC<2bpL4*`aFV@^_ z{ItND`maPE6J6x!0%c&hBC!;)2nT0vMjM|UE6b~mm37IAm37`7E6WXH1tTTf9ERP1 zi|Ww`v9hd7%wf(|#tKy5#A+50!(m%yS1lg!q8`G0HvTxWF0!h@1?UHxMkW_lG;m>J zbXcxLqPb7Cv-C}!!(5XSo3EBFLK1$v9PGOf(kJ$fJK{yUq&$pBidYOvC{27ZKz5C4w}7;#5E%czvqJvli1lnK9sWVjmxN4~{>VhC_Dci><~_kkTkiSn^kta1~0>;thF+rS>7SJ_4)e$KJ?u0buZ!JjY2Rf4+DDSWRsN?}rlg z-KIp*x*svH_?K`l)ycH($fMMKbN(*;_i(ad4xIPkn!R{z#{?9k>%3CtqBe#_!U6Pm z*%)R*UMg%9k?qKl-@gP1*Hh;~BhkjWOu==!*TZ}G+?e-gL>JLxEpZ%nH#>`Pjtibq zUCfifU2fUsHvYDyGje%Co83nFKJI@uLi{QfTnydo(#iM~J+9HPU^JI4p_BJ*%JGdD=$Qx;`@h4HT^^86B3P)fa2GnsKhe?2F=Gl9G$c9Kps6GfGZy*8q=PsN2Rj zE5>9;M=lQ>%bNWKwQelB`XKt&G;tSHRutk+$zk=mYW+Ljg=s09d?8y7<%1KK>i6x z2RmeSqk$@Qt=SOm|g! zx_?4NB_PEHd;Sw7ITuO#Zca4fv*c$xHncOr1mgGx4@#1%nf_Beg1>NkT;|7>!Q*g2 zGSN{4kHedI`z%`5m1xK^BV2>llBUjCi(|mJfch*sje>`35Wv=RKvhtX41D<9{3hz}OpYwYwfi%|U(~pp( zI6cWvm;_uA5njh68R<#RW|AzOGM49JO+OaYXGXi1aq%Qp6pLEH6rB&piTAXA zU3i~x&#ez%LStY(BU^}#bM5mY?1P-j$E;g|svDVhnf`E}PlJ z%3X^YY#mWq@uw6dXvu!(uy1L0MRMAc{^jlfef}j`U~nb^xG68vjwPyzVEpb z1+Ss%c&m?rx;VU)G-C*YD}Xy3C=mKBMlav0hT-O-uf29IE%@Wh7T@y!Am|$%_%#n~sGEfv%Q_=B>{YHZ}j^98QgQhQv~P8>IP ze8}b+?O|X$jW&;8bY8>JW9Kz=Y*B>Xl4GrtR>eR-=YS95Z^kDjl*(Y$f3GI2NAP2= z8Lj}rT{2{em7UB2li?L&#tUvKc%)Z;=!}tWTj9WWa0!A0ia$DC-YKp!;}!4 z@LBEMPX{43Ao3}2L5CD^BwGD5z-WC3RwQ1jQ*`ZDJJhRywGr7z6p%nCHkzwY(H5akK_!-!i#= zmFq7g-8aSHPw}_D1h=q$aTI%o-_hc(1_TevjFiBPD3R8PxQJWEx7M>T#CC7PflGB)yJ=0Hs%%F!IFup;Sq`k#zHE#^6^&kDJ+eXP+^{cXA!(ckl63M_VT^DQB zU#WSVTr)Si4)enx&2X_9?AXJWE@`YeOYKcT+sEM0yUgt>;4RvKj@nvAh4>vZ87rbM zfRnD0H;vG*K}EvWs2&o!G1dJt5c5bS_pS%Rq$=D_nr_nuILOvv5Zz8IyA{Qc;A?Q80C? zAJ{2=1yY6G->(6a_L@OGFxTc3FN`!`FaGhfgd&Kt=h^Sf}d}Mu1CX^cEe}RIEYrpM?|d# z4m4cq#N-f?EXF`F5rdsqhbL^c>5Les3}n_XX8k|obcVb5h!=}WLx+y4r-OK^$&ar< z4xE3~0KdOGXGurZe2c?(GHUi$2Cqe*7ei|5p{;VSL)azm!6R>thCFrZZTvYTgYRNA zaJ?c92Jo2Mu{;Q0QQ&W$Bis&^7kagRRs~lEnQEx*u1AnpyEe<0 z$e7XyKaYZ8c(}#xm=Rt~%OfqtqJ9P}U=2t2a-7D`pq|#Hi^w(1QXbSUey47~Kk&bZ;Ro*m8&YF20WeY;y`ot$dig?@yi1p?@mcjc$I#{y0z@_vxdk=HuMYiL_k+W#QQ;rMJ#bhhO#;Ed zQ|&V9h3EJX7LK^Q_{)P|1EfD7<&m3n4LS-qc^%=G8shR1{)=(}w*o2Bs)61B76qiI$ ztia!w<6m2ee+{tySgSz$t_oSG3Q9oBbINyQ2WkV3P-wUYA>YMw}%K!g`@kPItCefsV&gg_f!XhLUe zt#~x_s|W>lc78|y1(i5qT$3ji*QisFf;4yi%{!058WGL zu{<#_97ct(c|HuQsAjPM8mUtxrEEgI^V_~1=} z7vEm+UfhM}e1-cl^L<3~Gr1$0B0+NwBfn^S3?_?`&guUtsiPms-7y84z?Z-@RD2d7AQHFMboB zvf3#<9PAW#dfvh(p7`s>hYgQbUi;Dm{n4S~977ls9+mIUue>%iRKeZ_j3~^XAQPwk zw0%pQ1Kgw83@-RV<{R|dJYR+nNvKmgs=MmI>{zsJgm@*|HM4?m$y#6V~I6fJ# z;YTYVPGz;uMh{@Vz6_RXC|&`PXq|MQir>}^Kw|EIsb^6UocN(9`)`3{#|x1uG4Znj zL@8Vu0HX!OKng;Q>s$0|9h)p-T|u&C*QwEP0SK`2QDFSF57A%b=yv7jDbiMv9DSG~ zpERNOq0P-FH-Sl5s#1(&B)3|BX542s@Sr*0)YeG+#(%)1&@PUq!8DI4A0~bWo_vw< zm`&InKMv;$W#gb=Ij_aK_8H`mrN6Q|1iOE7l)R0AiHWaA*^%f{N|GJ7+9%(5P-?6|Z)nzrjig(-P9n6X{dDipFAEtf36{KM@gD&x{q{VX(lvx?5x2NO_ zBg9!&?eN88P(F^NPC+GQ0t@%;P|9mjUi_Q`!- z!;P#LfD~_3j?A&+vhh`n%klg@l*_(wZTtv^e&z?54{%_eJAK`s(zNZ^3sJKVTHb%0 zi#6Gx7c!stNZdOe0zCc_{;4G)oxjy5)wf(M2b19>{MPtGoVsAV;W5_ibp;P$!wbk?APXO8yJ5niC-_Q)EMt8&P~qGO zHCByf%|tNej4M-P;+3U_*^JlPlgO@hE&eDZMLZc5bJ02@^A*;ldYv$ygHThdb}`T$t>=;>>!7U@@#ldG z!x0rgsBPs)B!1^UiU{?g>O<&*EF3cGCgNU>aKQQQxaHPx5oT*7NJ~+JKLG{Ls>D(B z+JZ!!=!%vSbJbB1@tf@PvA|?hF4Ap_slEJtRyMH7hE%+;r?ZA{MNRbfMKmY(ENctk zpB`MZ8ko82Np?5l)_)WH$K9*AF+Q8!gVbq9**bdzYF}F zu|gJnTGdRPtrwprZ(b=wI&pN|>sivGQrF2G2$1-%{)7V$-9m3cY-_hI`wQQ`olQm=`5;_X-; zn%QV&2S1%#9to}Ix6OUgxrN7g`hC^0@@V&~g2%FF$JO~$^mX~a->E>mKqC7e%2j9DOnKxy!JeEP<%PwQqGcboafxQPSuQLKQ zyIWt=^9eXGFz1A~;sS5RH@=K-%1ho?pD7WPzz>Y35x)w&*6CBuE5$Yl9Qy`8Dsl(9 zmO%wx9F-Ow*^Z+tadtCSaCd9wM+kye*JW)+=q@pF7t?L?nlBYUg_3_LARPs-;#M^P`b(Ux z6DnQ~2!9!)@kVf%AAb>^CX7abFw%z6pf|^b?_T2Gm|t6n(u0i`@l3NqS7RJe**ry0Sl@Np8H)spRv{xb@=x8#6P zHy?uqb4x7eZf|rDzMpx=gN=K#-O)Sd*590gsa42_+uRv*wD#JFm3Mbjx6110oWw*u zUgCpHHP}(KD>mrCyHR?5BG4ZL;4%mu@9sn4J+Ry|~8#IxgevPWT&Kz<)*j z*C#RGvk_&m8{pT(Ua$Gu6&X+nj}uGB9qO%v;RDlJt(IX2gm;wXi85aGyz|jKv>hWONYCc|lvs=V<1f&;CM2+nd4Jyy#+6LE+3U}_Hz zfW12YOC(9)53MumIkI8H_e2tJiL$-MyywAFIfV6q)$kuFkdgv522S2xtHjBu`v5%) zEtisk-c7PPcZJ7!?;qu`*5Bh>zObd&p%8qGsdn>2px#)~?SdX#g2%=gkKT{R!=d6^ zfzes>G{`Z314x2C4i9=_Xe}S3gq>X(0GdjdIVcB9Agj^(K4j!t!#I~eS1!atj_EMa zQW{(eF!fz8EN9~`=u@};Y=iseBb`RjcWA|aZxr-HRvSNa4v4sW<|dA}U5Bq8WOG`h zvnnNiKT7EPVcgGx?EO9q}J@nNxlq`N|8#ZOfKNu9;8d<2ZpL(U9G}N!e!G5NOgD2$L}Sy z#yY~)CPkxe0p3Y1%qI2iaC|iWd2wnN<_uO#Yr{%d_lE(Djw&7xZiBt( z$0u7CV6>oFY=k_>m7ob&eu-xptYS&*gAhefRLo#0KS@if=_a^`0i2odmDGhYxSaC^HtvK<|}D>~18!8ty(4EB@NL zgKShBUeFpNd=eO`BhsZb;M^dWwv$EP2mRSQwz_x11xXj56wCXp-A2Qx`a zWpK_2;9Md)Sk@D`Mj_IXh2=q!?h7e^{ecum*_YmeZ(c?orqOS-3P23HnEvQ=`Um6X z!J|%}F<`s5wux@XT1-X4U>~shKA@*Y@W7}@4?GM09N_D<&sec3cyyo`BnHI zJbHr>F6ZNl^}U+)uicSEs>hrC z8uhD~yD_`aWW2eD`#6z%sh0v=?Y-sy)0yV<~u zoB^Z{|AB@U>?lHR?mFv%cQ~2~6F^ud-XUX_I@yceP;j5q6CLDyg&kj8Gh5~0el^%0?PJ98VT8z zrIQ#bEsi{tTXG)`QQr!(nW|&&F%kOW26Qpra{0}p=immBO>P~ z^v`50P=YiY{N?Dp8OQky?sMd&&{EblMyA!^+k+xrA49ypU-%ct8F@$|s%c1+EK~ok z)u6&*Zm9WT{8BKRd_f7E=3;PYgApnK6rXos+1~+C$FkqiWluOw*)tpBccbv6f5Qe) zV&QJeDLrA#zYMY<_ATBUcch&r1#01qloer)!Ku4f>q<j`Rr=sJFjANma2GFB%n$Ht6V zw-_f;Rf2d7xq>*_GQ0vFxUu35^f<8Gy|zI6do{(MmAB=X+i=QTyvo=FIKK?V_M$@w z`>w_aFeKL^szo9YK#G8lPTfjo#h{}R%T;6e9xs9td|Tc5@H|<$?C%tt$K1dP8jKZB z@}d7$Bh&@{b78$5|Y*fu2aMP3j|GWQt` z&y3=rX=uhF)$^)#zUJ1@wtN4?GbUbi1)zCFESl^pX{q^>+uVjPek>MdwZ4Eg1yju( z(P#!@Q-=mFtGE3ew!kzG@ zbxG%EL{xe}AmTFs2_7A@5~MneLCx|0Vl~JzwB9hb-Watdo+)uC)D({*4j9X6$rJ_g3X~7q}dW{ zAZE)}LVioU^WlJPv;tzZ0!K6b=SgRiVv($y&;V2big-FpjfN4!$V{7s<}j?75EirZ zNOBW2Qn7+ZoW>(vQR`^8u&CCagXY$@9mGoP(sZajmhsXhzyi3)?`Fn90dXIznhDEb@h3f2|zT0Hr0+DLQ z-`Cdfeg}-qBmU~;sCQfQ#Y#+(`4U2n&<{isJ7&BS8Od!iq6y{pVY&-IN;!(}fqnmX zf@GO`M{!&D`D*{D@pd-}zTx<9NYj8E)r%Z*^}x=hYMgoew{;L4C=fAOH~XQfHxAEjd zF9w|)KUs$m^@%@>Ofc|O$m5MX2%ollF>MaK3`7-oXCYYJtJ#}%BNnQ6+rWx?&9_7- zFpDuBt`1po01mJ@5R3fT0g!-|@~hl6BJ`RYy}jOt6C*~>YmO{4JR8k{Ou7I`VIuC7 zWO!cAte4q_&5u*<29|mw_m?R_#20Ct9gcvpUA(mbD`D-sEq)kHka+PE`$ejbvlOG@ z#t}wC^-X45_;Ag1Fm()zZrpP{~C_50xE?uEYYHcARpD2s94tDvnRbW1?0U*|kDS@7h|Ttgk+WbnD}T zr|IUF$xJJk|e8liYBNp>H z^%|)!8>Z5Z7}0O|FNgE8;r8!H`{oS4i${$bg;yi&*Mrh78*cxiyhV!_4Ii$4Z76?j zQWq~;ym+y$0}}t=t`U#p8sQl}T>loOJ!^Qu8Gj4()lFZ*ln(zMf4rdJoU=W3BTx&e zhs{FyT~xPd5zDl%WY)oQ`)gd14>ZcJ&Yi8VMT3VN0=ce-{v}SkFpp<2 zpu>k33@<1cKD?q*kfB!B&FJ0rp&8S={^Ek4RL{PkvU>C-?tYckNjd78TaeScAh%m# z_nd;9!kpaPTn`7XH=S7qj+W9H^PxIry%2pT|4D2M3+$j zSa*5ja6G1e36n@Re&0nJUWAD=g5N(8fQzs(a_4ZsaYBOp0>Y+hm>XUcFTw)6!S%5E zaTMW~BPd?g9V7a)Hxu(=Ynik zexJG=SAPFsr_A;)`F&jZJqP3$4ahG<+5!2w-n>jVpzi#h-u$A$`GtcuROsgrnb$Sy zM_?~$*pL+1rqjSa(y-Ke9@Ma^l)O&e9;x+YG=f)u_2Xcqqql~=Lm1knF7u}R!eG{r z{H2+hPj<;KL^HeCK9s33I<4?Mb7DSuSBAeT4PSzL@@he*E5EQV%bi~obe01L(1ImH z^D@1O2T$Gv8?M^4%ScF0Q`L<3w%y(0}tDvJijb+RhRt!XqB{< z@Z>oPk-ZzD!o05Lzaf;rv5>nVdE`YO{cf@@XF=v5(m$B=XU+!As`bkAGW~eCF~49$ ze(qpw{$k##I`3JeRq8&Fd0mosLZZHd@-lye2XGUdC`aDjNWM(x{SEFNQ^_|-N?q0< z=AB`)$MbrOI>0(?PpyOK&?KotKfF7n-*F*;YDYKQad3X0dlV69#ld-*zfL@WFXVA= zI=r~<PUcHOeL^)=yK#Fzua*3V_Fa$()LLdUlS1ps%N(2_ zd=PhHBKdfocfXbwO)uoV&Y5{9k}DEDdBYR;1M@t%FSo6Ls`oOD=c0t%-AEb~zs4tu z1r2{pFpPZOrSpA5+C^s}uR-dYtzn|FBY|OHet|nb7laohX(57Pyu$n^@>2u(xs_x> zHoW<{0FTFCnNHVN%XE}{)$IZ83WBd?nVZvu0>br=G!O{CBMsyR3x$U-=rX3T4Lj6f zrm8rq03-Sc9tMdC8km>$gA6<=gG3b)yZNQY^K(4&>cfAC8S}b?d==c8zd{v(&LuS+ zh5zon%t81WkvA$om%7+b=P?p(k+fl%kD^?kw4IOTQg0^e^gMD{*(T{9lC}x5r~3zY z{`jnZnWwW&$Vxe0u5r!jC{H5)kmF$XjrnC+H=^<#v~W-!W#LPmcW|PvpqqMMl=)VI zk!YKVB0*p(@{GZsI))E+F;U+X`M*o$6kP?&X#XHZzPwabcnEOF^Kgm|ibRsZL{44? zSO~5W{0Ch~?GHxf_o)`kfp!6YRezoSyhQzz@+S2kmA@`C^Xrb)2WqLm&if(Df^00H z{j&9VPNE+0GhkD6nao#=KnAZ0{u3Dyz75Ln!^$g>8fEKk-CY*IZ6>oAApWv$~I z2yoh)8^HrFP>;v_B(LrKC*^<;?Hi?)#>V%_x*IssY);nwgrTcR2(>Sd`1~5*+};Y` zqwF)z#Is!)S>>najo5Xz=X#B=MC(~9K9Mo8ujQ0wFJuh;1lfSfb`Xp_$1vb3I1B%9 zefIZC6}IKMeJYr%!5Z8w*08o_nCe~Y*Bc+PNSJBn;nngsTh0=J7!AuS8()309wz;XlBEnI(6 zKMogu3Ag=cmd9%-{sBp7F5+P(#x)6lOmF)gGDZY!mWBs(A7_sX>omNG zI)bZG{m7V>cou57j8pLLS^N=RpzUM1PXAvTK3>CZe&QqNl)vLN?NzfQxCX!!Xy9LEy!dS3lF zdT4l+4z^G}c>P?%%YLMuSE?V!Kn-{NSOH{Qf!kpkevnamTry6;??eqR=pkT-j012x z(}w>m#vp>exM!;3CgaPfz6dqBgNUZLRP>*DsLh9B&s z;Nr{TmScUkSHYDEE`BI(FVgTT4HthC@Ln3e@E0n*_>#E&g`J)bBd!Yd<8W#CE)5r7 z5bw%0yzDBKP<%Grj@Iy{8ZQ1B;CI@1v|-q;vN^a9R^;tk1rXl|w-0Fe!cqknUkA4j zYk1WS3NC&NZWjSAc3!u;RvX82I(_pXm43APad724%k48*0mKKv?Q1svUn#iw47lB@ z;mb9HrSDfs(5q=9te@?lEQdC>HXxB+8~GGC;~fQPHGr&7RE>D;KJi--;9sXZ-1~^aEI~^X!)Vs$`m^tn83J3m= zn>l+z)r_i{azCg4RpX{ipE-5XbjP#_RpVw<_0_*u%ImvoCR9(XP}!zcOr0`qir+B_ z|He(Lo~CZ9t1q82vw8x;?EA(pS zCsz5Z1#QKQsZ%Fa_$O4~mB>e)k-RzMDyL592%a+Yo?l$4@n2pwq1q2V2#Y8AYpNvE zxS3OD_-B&#nN?G!PPJ)~x(F?NHEGtA3O{d9%8ZKYNtKEFzJks_%O-E;bhMJBQg4#a zQba}d1b@Y3-cFn}Q!w(kdeU8jhWr>eb;@0n{WTN8PZH{%F=e{{E@luKW=`@8xUyy@ z^MMkZU?wJX4ym&rCY&b0gvm9jNh(v4R8E;Rb>cWMUm=*I>Te?>bqUOTm?lqi`d^)V zGbeF-*QDuelT`BVs?g#Pc0C1of)H!_1ng{?r`AFhvzA4NN{%Pnteq+9b(U zHF?UoJF6#6xQFnmlPVQ&rcb(S-1Hgh{>~}>nUkmJ7nKlzDgMcl6f;8FYC26UcQFX6Kk-}L`wVqNvZrY5A zlXyF=0yk)1=;x$rdFij7P%&woen3j8@AS$UIwLifw~1sh1?pvm|K6%eiKkg;`l&N! zRF9iEQwqX!#iS`yQy%@*HPb6no~vfeo?<_;HL56nZA{{q*!t{w#CrOp1-68NZg|mu5cU8}r?VnMV#0a6Bf#u78<*82;?^kLgZ;@Zl-&o_4y0+Ml%H z#R}{gtNlsB>8gAQKcCm+H25J6@2>qrJH1VhSNnUUXC(e?c#ZbE>~gzndUj~P$cAgT z%`tcsOJ}UW;oz-}=Q{0(rI+i!nWd`Se4X&HjacDxv^d~f(_CV0Cmp!+dJ+Wi@7j*jb)8Nl&_$6s@JAK`x zj(AEno!jo}2=A)#Y?|B=9@6mbY4Euk{zV$xPTy%tM?5d-^cSVU|E}Ser@`&??r9zI z_|&80o;0{k|2xX8i2kx&{;u`qi!}I48or=9iT~HQwcGuUnk1ZfPN+vm?yQb*zqT)h zX>fb)_NQrZJN*Uscf@1IQMzb9+=qr)^mpRVPJhjO1t5N`a@=ckYwP^r?3BvEL@)R1q6b_R~ptDnEOrz*F00 zz!~88YdGs$nS#IYcS-!Ic)m_)$JF*!sTH4zi)(FovHrXWZTJ|Cr+XUQwgW|J@B*E_I1S!i!+WN|m+F4kwy$=% zehu%FmVUB^+jiGZ@6+)9Y3Ubgcxf8^1r0AtgBP(=#pPB%3BDC;xHk>nQ^Re$Wz*AJ z!-u7%@1x=RCxO482Cxs}W#j3u;gnTgHoR2B#|tzGAFmNiOoLC<@X2X#uf}8BCma7C zGy-i_6Xjl|)BDr#+@axf(%^S$_}nyj>8%P7NP`d3=|gGoJ7~Od)vKQbJ$tE4xE83N z1iZ6`FHD2qr|~aNgRj-}Je3BYr_(=^2CvibrD^boHT;D%_#+y=EDip+hW|Yc{)C1v zPlG?L;V-4ZpVjb{Y4GPYe03W99bMmb>2NJ*>(k&d4d0XoU#a15q{08H;mv9ACpG+? zGqv0Q=!6$0?t~B@}?a%E^gZs7oSZVOR>>O}?seTgjGgsp|mkj<&~h>eu?U9--FKBwzxqmw2hA_99xV z8ABBTAs~|f@3$^9JBy^Z^PKZN-}8Ly$z<>S+wZ!+>$>0fUBw3d(gvB%5(9sDzQjun z{P{YGPc-mOg_j%nzuzqBD-Ha&b0l76;CmE4*}$i&bcPLlnc|bEfuF@e9?mxKIcnV% zH}JU%uQl*Gh0iqbnQC36$6H;_a}++;pwCzBy3W8GRrrex{BbUZ;2I443572;@Fx}C zXyA1!JqZI}r0_KczEhR|T?YP~!kY|yl4_65244LYnf_J--=yN*Xy6Yiyv@L$R_l-l z41B-hhfM}vsN#Ldz;9k8)3e#Yt2k+ed(^X@LB`+sqkkS_^XOu%gOUKf4dbv*P#Ec!s`tDH5L9M1Akl5 zHyC)Y!j~HOUWGRr_&$Xv4E&(N*BE%e!tXNhiK;xC4BV&o1)2>!pzu}$4=Q}4ffp#e z&A>wnf55;i6~4*9s}%l_flpTWW&z*`mmTLYh~(z(aL z+Z6rV2L6D;dkwrng|pYd?^5k(pMf_j`hy03P|^1r_$Ebv%)lR4>4C6=aD2^Qn+hjj z;IAtBpn>mJc!7ccR^ha0M5n{wqj1W(c=6~z%I9Kv$L%B>xvw>@Qz9$V_%k%9sa4pYQI(l%v8Y|_q?hkal zTAr`Rpx5$z#|&J{^DP=PIQ%`A%I7Bxy!|qX_ZzsD=M&0NAkpd3@_dhv9UQ)v+iN#) zEw@)%Fqpnk$?dH%a4omD)4;Wy*?1*yoJ~)Y4A(blVts-|PQk_+^-^Kd)<7@y}HKjDAQC7G*hEeLd~Mb}eU@+K ze|+CE>d(wShv%XExBgCe&+1LcrxVLh%ScUH{)J+?a`9jOllSuf#g&x;thngHi{)M2 zn0ssDQ}g_}6#0E$I-!0TZ_gKW?7E$WA^U0hX4vkua@%>uc2~ea*`?j#@%-rAOJduZ z5~^swX?uOnQfGaeJG(0CUQ_N~Q`vNMPNF*M(tvDxs`t87|CrUEQ%4BI76#VE{XGMF zU^@>+7q3b;uMPT+4>VQHOpbCw!ZsP~Cr8e=wp>$NU%fMNB~9CovE3`&@f%=%`;_gT z7^^!HR|AGQ_t~IIez0BIs&dA8Lr89eiSXGl85%i1`yQt&b~S&^hj^#=eJyKyPtZA6 z&fczUbm4rBAT8o|Z#W1xVBT#U^?;KgyM!rTln!ju*TSUx4MjL}Pns<96bS4E?M1oW z+rTjXf-jlxS&^ADkO-V@b-Y%O)75^(SA zu+wYmwvzRcL)gc4r@(IR5!}x#sf8s{T3p1L8159D-ZZnMC}=dy2bX1M~!o4>)OQFmY+ zJy=_2kBp;O+^N9}rlN2Pu17v#hba#hr~VNK38rUu!Zz2mP}vQ|ai<$RAoA^qu=<|F z@#5z_7D~imMXTxF@Qv;b!PaT#B_c4Oz3Pjp_YlUksGUxH!~R)}QJv*;gE-48^{bazb){{sS9{gb};J=Ig+)^aFuR`r&<&_Gt5 zZo3;AapN3vE1v*9sy=nkOkZLISRw4Q*LL$=W&$m)=GYHs!A?D&<#EZZ80<5qf53v6 zfx6SScw_GUgn0H%<+|SALv#W~P9MoX-h?u3^R^zw<4y}k#Jc5B`0lXPLY1J%%vrYc z$&9GGiGq4|dQN*R)#sny@|$~Zv|YCrSPZAU#M7G@QQsM|JiDjXvNF0wp9}gx;`1=? ze1@BcwC;1dMAnk8FS*n7cq9~-F|0x zJdJ~|@z9;>1rc3Yf4a37lPd5G&^>B;)se|RV1EyFE%*sxHiBG|G$@ax*0%_|?Ble{ zFr`noCU_`(Z(eddjv2n`=BU#inafIT7Ex}ieq`rA^VlRlu_+*bzryp=?34BRo_r_I zw2L|Iwp*i`>?|A(2-@|PP-diPY5wu59{IVf$XhKkj!si7O7u%_yJ;9M7 zc`~@UvB~EL`|xd(eO{=$CEe%XfcgsTr;BbCY6_B{QxS`&; zxwgBe$kznasex6wmRh{&t_don7|0wVEsGci9LP#5+UuQ`CIEQb1k9-^r&)1PomR__ zNrmD;ZOIbK06?2=;>B&TF{<0{-3@8mzZGXq`fyGS{#(;_isf(WNS<}&&PerhD^3zs zpK)L(6a9hh{ui@srypc#%0rX|ftx0PQ=0fXTK(p#iRdSyI6S%RO_cBxb~;`NYxIFu z6~AmaEN#2GGx?$WFpD_z5F(N7OYj|=4-*@Mb$VL#odibmGM;|V&fj)t!M^46MhpVm z!G$rDLy=P}%<`ohi|q>@Y(hY=E*Az*Vk8L%VYV($jT)WqgJdaU5?;EP4j?!RjdPGr!R<0Sw7V{#7GVM{AP5 zmP!61UtxS>ur1j@V;n|or?Ir}hpZrRri13s$PJO%Y%@Hl%1(ct{?Q%2g4R>&u4ALX zX&^AGxq6JfFxrAIz`X-|L{V@MmEm^N59%?s6`5eMwrs`xzB`p;tT*EB$_7#Jw!5;< zMpr!^y-L5n=cw0Ih>ac7rwO_>W*sS%88_0Ejz*(F&m&j&?kp=p#IRaVWj5TMX*ItDzuhTeLz2@9nS<_> z?m1)zQ#;U#Wb=r8IWlj%w_G-fa?!hDhf-fh+&DRuX|J!Ia=q1jFH`5dAwr6}_mh$b zF*JV`>5>tRhZmU!v@Y1?e#3TtFUZ{)RqmaY?$zZeiiNe-Q?MHR)w)z~B-LMJZTK#H zslL@b%S8su880K=Mmv|Ds&Pf`QvKts4F@rhW{#|T(0|IV&W z<)`mQP7mgeUCkRfg}WxznTL~aZpmvsofAhC`D{GSKOYPd);3OcNDvqE^dsn{BKb1`lfmRsW%m*eKEVQbv2Vce{&wZCqutVE2($%gJQMR2R&yfToYU+M37KQHyp z74^=>l|f7wWOIXwZ=`@tCi7d7lqh_CIS!V_5b_tk3Nb{d5gZw8Kf^wr8>+`sbK4 zogKL9jYTD8{uu$Q@!^i6=RKf1S{@z9@d0Ir>EDc6#v^*Yxcj4hOpE)yeq7jh+wKeu z6JkN!9WG!$kAnkk_x>j2718?YZEIPFjUN9~wtICW#wXeHm%SwHyB^IG{r~-MOX_e) z9UW#RSDV zjj*X);J~Q#w2&yO?rCCnNp5P7<6Q`+Lll9R8*oxZ2o*66-BDw|8}7&1M!w{EncpEV zVxEXp!P;x!*&xczF6(kflE7-FNoIF;Ac7GUCo+3 z+S6}ug0H@vx&XvThjIqfgk{lSjUx-+y`Kf>iWcP-tdk8m?nZQzZ|Vw<=Avb$8(4=E zW9HPS!f`)Fz&R|^Ihk+C@cI)2$#OiW%ao&)>iVl_ z?<*ARt5mz+PW6Wq*SQ|9a7Z!aUpK&oo3N7W!@8JyTiVwpM0Bnuv#9$|DiHB1-a(BbclS{A~DW1 z(I(^03*FPiG!A^gwpL`9bz*8!!q&!_9~&x`;PJAT$t7T!0H%u5P$$#MB@3nYAtQh= zp_46+?U1ZkL>3ecav{>(l@jUAJkB!TlH#W_*`6|gz}tF^9UH#QQT1uGN4k4$o*#hv zVz-mt@B_Z%0gN70?Rr&Bv7HT^i`xp=N1)vcZ13J6zgah7Ua^6nySHO9h-LE6HX|K^ z{oMPxHDTX>4!Cy~aSSY*Q9Ljs|#jwi?y>3Ni4~^(IG>+X<(1$M;s7}1ai~HS>4Eu8*Wv&wfz{9k6sIe?<964AunTN|+VQxZa%q)+-zAG`mh7-C%Tb2mp=9Dz_IC~>Me=MN`? zML36PT64E=%@|C#VUYY9U@>=AIge5(wo`8%b8ehK8XUxRH_i_@1HES1k}hOOqcWDy+Rh50ZNUE^Hho`U&os((r%v^t#Xzrt$X0zB0pNq)+DstenK)7`~I z(=S+zk>TZ7$FY2WXQb>^lx-Di!ZQ<><4CF>=f`{l{ql>NVz0FGA54 z<78#~@^+M^bsxtGj&l|0lRhWd3VoBG2%pvRFcREvg+?F~oUTMT#zl(I9||hl`dsrV zP4ZQA94fFgh*K~LB;U}zNIwkh_kAkIzd0JK`9`aK^ud>w@IlxE|#=*eoXbW1cry`># z<75Kb;m7dQ8X1kP?8{mfp=nwh{}W)YC1KfwmStnU6cjv6yZph-dd~Oceum)i!EYPz zw#{DKQH)}ZJ6)jQlu~%loGyH#{pI}dY! zb@IDf*yH;%ryvO2{C~jJFHNp&@Zsa*iUj^cQ+ob_<+$~@eLs^A<>8_1Ec4xXMQz$z zE&@J5y*rmzm=R3n%@_6;`JIu)OSem2guRQny07FFhW$ua$9uTX@gJ~KTyzq@MQo7m zHrT6e(^m1M4UNsDfvXe$CHADcU+BShs(TSP?u+sJt->O_!e;LJJlH2q<=-Ohac=Jt zv|u8-W?p9vw)L1l5=P!=Ke2}P6Z2{dgVL5Q^T`c9y3&078 zPJlwUI8DXJI#1=Q%HIWcsSHO9q#M ztiv@btO|w&$1>fhu=`Y*dTr+AY*s6~g^hVThcq2X1A%|Wu^9d*ZQSu&C~XjFcdojj zsE)8rq@H!V;p0#?>m-huwBcA@B78AaDExx&j)r*wjk0QzY#CoM3cF7SNJqFxZq(iO3bK0jbz&=BQEUR}weC?$bP0?6T$aV5w_< zV#)GlOoe>AGO>i#x3bUL;1QC&G673ecp+jE1%*3^`uTjPD@G6C%3TX=0SkAX!r2r! zT57x;{RAE9=~v_R!{85jaLyex{U;ur^K*?)XTWg0oP(dn|HFfy>%rR<&U6-f@Mk^r zB_2HE!O!#HkE(&6ug~`2&wB9BdhoN=6oT~L^i(UH>9IWY5f8mLJ-a=)H$4NMaM-Wu za=1cGfpoo;;vL<$6wdSz)AT>^;Gg#3cXECXNBT1SH2t$4oO1<@AN1fCc<>3>jiS@( znJgcDS1H^K|3MEv5wtq|ZV%3{#u}fmrf>|$%O}ml;6L=>lRV+<@!;P4?otythVQM% zw-wHOaVXR2$$02XJb0OsVPrVodW?8*Z}_Vf&hWkU`)d!qH=I#qZa6cYl^)#7w{;$z zqJ2934IaGQg9~QGGtw)&%saAPgCPE zaY`F#{5B7Mi3k6^2j?77)7PkRoZ)!smwRw;_!)L~aHRLv%O$4?Sd;^!(&1mEI!e-e z;laK2c%KKq%tL>xr=L0BgX2~>)(d~T<)cV9Z#90G!c}w6;!O%yY@5Y* zC|u8(bU3XFSH+g4->C2+b=CAe>X~hmPUAW~#RARYdfr!J;18*1_FZ&3oITu7UqX;dKW7hQb#a_%Ri4gMsUQVX1)!RQqo<@DEh@2?IZ% z@HGam^QHMk*Vo62zR92;P#8T48wvjI4MmTz{v(>;GnGv|> ze>hznoj~0_bkNMJ*Kw{hRQ}sJsf63D62|~W74$p^C-R5Qqy z!*q}lQ`4zz2<^(h>UOfYj$dDIRQ`3pq6xJwrx~sp|3c+o`_tFARQ&o`U$uYzyaqSK zR5R1CuUGl!Cw#Bd>DJgv+zeIzn?5foo=_38{MprN|2la?#Z8~>WNbLizZ?!ZMKt|$ zx?u7iAYa|t{EzQ-M*3B9QJ_ zn&Pk51)AfDG%QjQ_Kjvq3~|P3Hlah@Fqpsn8--DTD%|1E=TRMw5&ux<_HYM86&~35 z&nQoxpf@>O7i~oPcRrH!SXRUJ$!4&g>JhKbR{l-C3Y#9)v+4h{z{%%-uYdN*4AbmW z!ocYMQlG+gnVBZ~yPp4sa3(FEhvJ$!%I{<9$}JWC{@OOJ6UDy7>&*CvYtttw!Wyq< z+?)QvmcrusU$5U+UU6|T-Cy6Pi&X!@q=fko|1Ip8L5k3|;_2w9vUqjJidfX0R$K$= zpK>USbx$j1O4C;kK-?5E98L6PJvDx0>v+h6^-^4KAPJcV3z{vyuE+r7IWqpfE-4q& zJ*|Y~+Yfi)zdvyeVu9>hgc!f#~@`DPmA`PmH&YD;CNr_ zO#gt2u|N5zxMQt-2mbOBSIAH&A=DKYBjrf=yliNZk1N`ha4*s)(wz(D<0P~oMnV5d zr&G(dogjWIiL%`+7byGvd5D%bi*PJuQkZ{eT&S=!|;>bO%0d zr)x^>>TYZO6M#_&5PYifbxlKgxp(8a<|4dYu^cig5W3qR+4}r*&pl^f0MWFg0mSF@ zK&m_Sfj?&bpxy51JvUv@dmwfHhi@jyAP?ix`)eY;dX-P!_3qK10+LTaS%Cpnoercco_52;xwhQ7|+ zd!Zfm5ryWW?k&M+^(_UfDsA`lNIF{Lccug(G6nU+0F)M)X}cRGfHLR~izbMdl&6yV zb?&{P$Xe{S_bP8+H-F_T{*4B+Vb7q@D_F6tZ8{WaTyZY z2XRd5WkD*vZVbWmb4ji)O7>Pa1d@Na37F8~ihLP~ZDPzd?&4rg_2Pn65y+$YM0O)i zjVHeqFFQp}L!cgVl=Y512EyF*hJfm89FYhuO13@b-kr^QSTQ$qpiFJ5P$hbEKlDrfg^2wW1a6k&gD0qGjzUPZU`5GQLp zFd>AA(CUNrs1~dF6-0&R1zjRExam$8RpL-@sM19xibS+8w+8BvZwF%j9TCW2A>vo8 zX12$OTUp}lU;7r6c=xS6iovcax!u}w2>K3o$2);|x&W$a70&*S_a>x{29uL?e?TPE zbkv^=)Qr7701rb@CtjcK?28LQPssIZ9Sk8!cQcyHbSNn0*NpxW(-VM-V#Gho*EdG< z5wt9!0|#|T%@0uWLAg-t1!CSczP>#k2}{W9x|XBT5UA)Yfc~j0<#fOwaeYpwOn;)+ z>10-$L{^)M6T9Q0xWkZlyF&VhAnheN|9BeZ=20qfLh48`k=e?RK&c}mR_D7{2D}Q9 zZeiRVRa3Fc*$KhxRKGv*C0TFKezH5>48+ovLATI(5fz;pKsfHyfb+6#{h;TnbYP5- zF}5#9$oJaTv`*3Pq2e8c!g!!%S7J6)rP>%s+~46=SX*L2=P(Lf1U1^WqFpV!lA z``g{1N`Pe>gfk;tTu2a}af7snm24`}^O$>+cjS$V_op>BV&(~Si>-VCKW z{G(s&`!A6$wxqRt_$??hx}QW5E82e^&b}KM-TyPBZXk7hWFp_aJ>Xm_%43!T>FZBs zu;mD?xgaXc_V@RVSLtN>piLtB)P7Hezw30YeN$BU5&SPs{3`C&l%|g6B~Mm4as#78 zjg3s$hku_{#zjLNnOYM#n6Su&)HGA=(5<4Lto!69Zs>>}2>hIQ9kc@p3d2IF6}o8D zjp@d?u~bm>J%Rq`hKO@OssKt6;GeM6IghZ{?wyl|aq(Knl{c4ArGo;%Rd)KWl42@U zK-M{0QtYlJF@=G{d@iS|%c)WKN{mh`ASmD2do{$?Z8VPZ8t3;FyU=|^p5cfY6OA}t zV#o8#?KHo1LA^+<32WTbYTSDQQL2kgh^&RW!oWXS8zwTAg#oCR?56NHI_4hKitpIv z_*ZVV)L<^$9W4oqgr}b@v5|7H=#`AQI9|QeTE7r0K`1R^FrQgc+!Y=uwIO$3YAaeB za{NKN`a>(#hZ(1xj`&3uyZmJgL1Y!L_gSgu_!>S@C|R1Dax_q#f&l6*AVSYSl2WDR zqVDtaTpMl1YN0J68|C>WB+#yoLZg4fkAn;nw{Zx3pVj3nx1Ii{nUQ$ezF4ZuAFn=a zTUU14evrthkyw#@nc}hlgUqJp<_gRaM1bY!Y#|Z-Rv?}qn(n-o`8UiZqRz`vryqS} zbaXqq$*2`=?|TLGLloZSOq49V^&-`S3Xi3t3y%f!2xK1b8sgF;!n!n3ZN{jhCcnNA=y^{|?4Us&m+LuTp<)>VH85tO)&gJx$sfxpXky+k(YIakK^}AnP_M>=9M#` zk!`KJABhv~w!g+X4(%h(kavg~a%GeMP^9co)Hx(($QMSP;}NGjb$s;dm+5_x2#7JD z*3o7+0KjwtN)0Dt2ArEw$)X8Z%|8JRS|bYSb|f2jz?NgJ!s41Kvh%O-JshvZ z)AmOdh@MMbBs+}tNWp2X@er0Z?_nWz^dqiE;w8ly%9`^%8)h++dyQB!jX>y~`Yii}l%{b&lP9bd^N z^j@|J#nUVPSkW%pr}b0Y~feuJRZ(m5A27s8rX2G?hQ z^8L&!$Yr*D>3m{ska+`H)q!PR*Y(>^6EVjRe`u#4P@@FY5UdUCk5DdHQaIhQ)cb5c zui72&VS)K||E@^ci&5tY-Z(v}j`B!rAqr^pY8U~6*SNES!?IUhfo^3!x|N15-$L1~d