| @@ -0,0 +1,226 @@ | ||
| 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_ctype.h lj_cconv.h lj_bc.h lj_ff.h \ | ||
| lj_ffdef.h lj_dispatch.h lj_jit.h lj_ir.h lj_char.h lj_strscan.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_str.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_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_err.h lj_errmsg.h lj_str.h lj_state.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_arch.h \ | ||
| lj_obj.h lj_def.h lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_tab.h \ | ||
| lj_bc.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h lj_target.h \ | ||
| lj_target_*.h lj_dispatch.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_err.h lj_errmsg.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_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_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_tab.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_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_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_bcwrite.o: lj_bcwrite.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ | ||
| lj_gc.h lj_str.h lj_bc.h lj_ctype.h lj_dispatch.h lj_jit.h lj_ir.h \ | ||
| lj_bcdump.h lj_lex.h lj_err.h lj_errmsg.h lj_vm.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_ctype.h lj_cconv.h \ | ||
| lj_cdata.h lj_carith.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_str.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_str.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_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_str.h lj_ctype.h lj_cparse.h lj_frame.h \ | ||
| lj_bc.h lj_vm.h lj_char.h lj_strscan.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_str.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_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_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_ctype.h lj_ccallback.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_str.h lj_tab.h lj_state.h lj_frame.h \ | ||
| lj_bc.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_func.h lj_str.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_jit.h lj_ir.h \ | ||
| lj_ccallback.h lj_ctype.h lj_gc.h lj_trace.h lj_dispatch.h lj_traceerr.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_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_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_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_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_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_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_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_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_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_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_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_str.h lj_tab.h lj_meta.h lj_frame.h lj_bc.h \ | ||
| lj_vm.h lj_strscan.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_str.h lj_tab.h lj_ir.h lj_jit.h lj_iropt.h lj_trace.h lj_dispatch.h \ | ||
| lj_bc.h lj_traceerr.h lj_ctype.h lj_gc.h lj_carith.h lj_vm.h \ | ||
| lj_strscan.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_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_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_str.h lj_ir.h lj_jit.h lj_ircall.h \ | ||
| lj_iropt.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_str.h lj_tab.h lj_func.h \ | ||
| lj_state.h lj_bc.h lj_ctype.h lj_lex.h lj_parse.h lj_vm.h lj_vmevent.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_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_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 | ||
| 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_state.h lj_char.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_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_char.c lj_char.h lj_bc.c lj_bcdef.h \ | ||
| lj_obj.c lj_str.c lj_tab.c lj_func.c lj_udata.c lj_meta.c lj_strscan.h \ | ||
| lj_debug.c lj_state.c lj_lex.h lj_alloc.h lj_dispatch.c lj_ccallback.h \ | ||
| luajit.h lj_vmevent.c lj_vmevent.h lj_vmmath.c lj_strscan.c lj_api.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_lib.h 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_lib.h lj_obj.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 |
| @@ -0,0 +1,4 @@ | ||
| 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! |
| @@ -0,0 +1,104 @@ | ||
| /* | ||
| ** LuaJIT VM builder. | ||
| ** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h | ||
| */ | ||
|
|
||
| #ifndef _BUILDVM_H | ||
| #define _BUILDVM_H | ||
|
|
||
| #include <sys/types.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include <errno.h> | ||
|
|
||
| #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 *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 |
| @@ -0,0 +1,313 @@ | ||
| /* | ||
| ** LuaJIT VM builder: Assembler source code emitter. | ||
| ** Copyright (C) 2005-2013 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 relocation for the incredibly stupid OSX assembler. */ | ||
| static void emit_asm_reloc_mach(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); | ||
| 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) { | ||
| if ((i & 15) == 0) | ||
| fprintf(ctx->fp, "\t.long 0x%08x", *(uint32_t *)(p+i)); | ||
| else | ||
| fprintf(ctx->fp, ",0x%08x", *(uint32_t *)(p+i)); | ||
| 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_PPC || LJ_TARGET_PPCSPE | ||
| #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) { | ||
| 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" | ||
| "%s:\n", 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); | ||
| 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. */ | ||
| fprintf(ctx->fp, | ||
| ".fnstart\n" | ||
| ".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n" | ||
| ".pad #28\n"); | ||
| #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 (ctx->mode == BUILD_machasm && r->type != 0) { | ||
| emit_asm_reloc_mach(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 | ||
| fprintf(ctx->fp, "\t.section .note.GNU-stack,\"\"," ELFASM_PX "progbits\n"); | ||
| #endif | ||
| #if LJ_TARGET_PPCSPE | ||
| /* Soft-float ABI + SPE. */ | ||
| fprintf(ctx->fp, "\t.gnu_attribute 4, 2\n\t.gnu_attribute 8, 3\n"); | ||
| #elif LJ_TARGET_PPC && !LJ_TARGET_PS3 | ||
| /* 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"); | ||
| } | ||
|
|
| @@ -0,0 +1,229 @@ | ||
| /* | ||
| ** LuaJIT VM builder: IR folding hash table generator. | ||
| ** Copyright (C) 2005-2013 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 int 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); | ||
| } | ||
|
|
| @@ -0,0 +1,398 @@ | ||
| /* | ||
| ** LuaJIT VM builder: library definition compiler. | ||
| ** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h | ||
| */ | ||
|
|
||
| #include "buildvm.h" | ||
| #include "lj_obj.h" | ||
| #include "lj_lib.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 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_ }, | ||
| { "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"); | ||
| } | ||
| } | ||
|
|
| @@ -0,0 +1,368 @@ | ||
| /* | ||
| ** LuaJIT VM builder: PE object emitter. | ||
| ** Copyright (C) 2005-2013 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, | ||
| #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; | ||
| #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_win64. */ | ||
| #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); | ||
| } | ||
| #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_win64", 0, | ||
| PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN); | ||
| #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 |
| @@ -0,0 +1,191 @@ | ||
| ---------------------------------------------------------------------------- | ||
| -- LuaJIT bytecode listing module. | ||
| -- | ||
| -- Copyright (C) 2005-2013 Mike Pall. All rights reserved. | ||
| -- Released under the MIT license. See Copyright Notice in luajit.h | ||
| ---------------------------------------------------------------------------- | ||
| -- | ||
| -- This module lists the bytecode of a Lua function. If it's loaded by -jbc | ||
| -- it hooks into the parser and lists all functions of a chunk as they | ||
| -- are parsed. | ||
| -- | ||
| -- Example usage: | ||
| -- | ||
| -- luajit -jbc -e 'local x=0; for i=1,1e6 do x=x+i end; print(x)' | ||
| -- luajit -jbc=- foo.lua | ||
| -- luajit -jbc=foo.list foo.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_LISTFILE. The file is overwritten every time the module | ||
| -- is started. | ||
| -- | ||
| -- This module can also be used programmatically: | ||
| -- | ||
| -- local bc = require("jit.bc") | ||
| -- | ||
| -- local function foo() print("hello") end | ||
| -- | ||
| -- bc.dump(foo) --> -- 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 == 20002, "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. | ||
| module(...) | ||
|
|
||
| line = bcline | ||
| dump = bcdump | ||
| targets = bctargets | ||
|
|
||
| on = bcliston | ||
| off = bclistoff | ||
| start = bcliston -- For -j command line option. | ||
|
|
| @@ -0,0 +1,20 @@ | ||
| ---------------------------------------------------------------------------- | ||
| -- LuaJIT MIPSEL disassembler wrapper module. | ||
| -- | ||
| -- Copyright (C) 2005-2013 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 require = require | ||
|
|
||
| module(...) | ||
|
|
||
| local dis_mips = require(_PACKAGE.."dis_mips") | ||
|
|
||
| create = dis_mips.create_el | ||
| disass = dis_mips.disass_el | ||
| regname = dis_mips.regname | ||
|
|
| @@ -0,0 +1,20 @@ | ||
| ---------------------------------------------------------------------------- | ||
| -- LuaJIT x64 disassembler wrapper module. | ||
| -- | ||
| -- Copyright (C) 2005-2013 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 require = require | ||
|
|
||
| module(...) | ||
|
|
||
| local dis_x86 = require(_PACKAGE.."dis_x86") | ||
|
|
||
| create = dis_x86.create64 | ||
| disass = dis_x86.disass64 | ||
| regname = dis_x86.regname64 | ||
|
|
| @@ -0,0 +1,167 @@ | ||
| ---------------------------------------------------------------------------- | ||
| -- Verbose mode of the LuaJIT compiler. | ||
| -- | ||
| -- Copyright (C) 2005-2013 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 == 20002, "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..") " 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 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. | ||
| module(...) | ||
|
|
||
| on = dumpon | ||
| off = dumpoff | ||
| start = dumpon -- For -j command line option. | ||
|
|
| @@ -0,0 +1,167 @@ | ||
| /* | ||
| ** $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 <stddef.h> | ||
| #include <stdio.h> | ||
|
|
||
| #include "lua.h" | ||
|
|
||
|
|
||
| #define luaL_getn(L,i) ((int)lua_objlen(L, i)) | ||
| #define luaL_setn(L,i,j) ((void)0) /* no op! */ | ||
|
|
||
| /* 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[]); | ||
|
|
||
| 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); | ||
|
|
||
|
|
||
| /* | ||
| ** =============================================================== | ||
| ** 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))) | ||
|
|
||
| /* | ||
| ** {====================================================== | ||
| ** 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); | ||
|
|
||
|
|
||
| /* }====================================================== */ | ||
|
|
||
|
|
||
| /* compatibility with ref system */ | ||
|
|
||
| /* pre-defined references */ | ||
| #define LUA_NOREF (-2) | ||
| #define LUA_REFNIL (-1) | ||
|
|
||
| #define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \ | ||
| (lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0)) | ||
|
|
||
| #define lua_unref(L,ref) luaL_unref(L, LUA_REGISTRYINDEX, (ref)) | ||
|
|
||
| #define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, (ref)) | ||
|
|
||
|
|
||
| #define luaL_reg luaL_Reg | ||
|
|
||
| #endif |
| @@ -0,0 +1,356 @@ | ||
| /* | ||
| ** Auxiliary library for the Lua/C API. | ||
| ** Copyright (C) 2005-2013 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 <errno.h> | ||
| #include <stdarg.h> | ||
| #include <stdio.h> | ||
|
|
||
| #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 <sys/wait.h> | ||
| #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->name; l++) size++; | ||
| return size; | ||
| } | ||
|
|
||
| LUALIB_API void luaL_openlib(lua_State *L, const char *libname, | ||
| const luaL_Reg *l, int nup) | ||
| { | ||
| lj_lib_checkfpu(L); | ||
| if (libname) { | ||
| int size = libsize(l); | ||
| /* check whether lib already exists */ | ||
| luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 16); | ||
| lua_getfield(L, -1, libname); /* get _LOADED[libname] */ | ||
| if (!lua_istable(L, -1)) { /* not found? */ | ||
| lua_pop(L, 1); /* remove previous result */ | ||
| /* try global variable (and create one if it does not exist) */ | ||
| if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL) | ||
| lj_err_callerv(L, LJ_ERR_BADMODN, libname); | ||
| lua_pushvalue(L, -1); | ||
| lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ | ||
| } | ||
| lua_remove(L, -2); /* remove _LOADED table */ | ||
| lua_insert(L, -(nup+1)); /* move library table to below 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 void luaL_register(lua_State *L, const char *libname, | ||
| const luaL_Reg *l) | ||
| { | ||
| luaL_openlib(L, libname, l, 0); | ||
| } | ||
|
|
||
| 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) | ||
| { | ||
| while (l--) | ||
| luaL_addchar(B, *s++); | ||
| } | ||
|
|
||
| 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 | ||
| #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 | ||
| 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 | ||
| 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 | ||
|
|
| @@ -0,0 +1,74 @@ | ||
| /* | ||
| ** Bit manipulation library. | ||
| ** Copyright (C) 2005-2013 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_str.h" | ||
| #include "lj_lib.h" | ||
|
|
||
| /* ------------------------------------------------------------------------ */ | ||
|
|
||
| #define LJLIB_MODULE_bit | ||
|
|
||
| LJLIB_ASM(bit_tobit) LJLIB_REC(bit_unary IR_TOBIT) | ||
| { | ||
| lj_lib_checknumber(L, 1); | ||
| return FFH_RETRY; | ||
| } | ||
| LJLIB_ASM_(bit_bnot) LJLIB_REC(bit_unary IR_BNOT) | ||
| LJLIB_ASM_(bit_bswap) LJLIB_REC(bit_unary IR_BSWAP) | ||
|
|
||
| LJLIB_ASM(bit_lshift) LJLIB_REC(bit_shift IR_BSHL) | ||
| { | ||
| lj_lib_checknumber(L, 1); | ||
| lj_lib_checkbit(L, 2); | ||
| return FFH_RETRY; | ||
| } | ||
| 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) | ||
| { | ||
| int i = 0; | ||
| do { lj_lib_checknumber(L, ++i); } while (L->base+i < L->top); | ||
| return FFH_RETRY; | ||
| } | ||
| LJLIB_ASM_(bit_bor) LJLIB_REC(bit_nary IR_BOR) | ||
| LJLIB_ASM_(bit_bxor) LJLIB_REC(bit_nary IR_BXOR) | ||
|
|
||
| /* ------------------------------------------------------------------------ */ | ||
|
|
||
| LJLIB_CF(bit_tohex) | ||
| { | ||
| uint32_t b = (uint32_t)lj_lib_checkbit(L, 1); | ||
| int32_t i, n = L->base+1 >= L->top ? 8 : lj_lib_checkbit(L, 2); | ||
| const char *hexdigits = "0123456789abcdef"; | ||
| char buf[8]; | ||
| if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; } | ||
| if (n > 8) n = 8; | ||
| for (i = n; --i >= 0; ) { buf[i] = hexdigits[b & 15]; b >>= 4; } | ||
| lua_pushlstring(L, buf, (size_t)n); | ||
| return 1; | ||
| } | ||
|
|
||
| /* ------------------------------------------------------------------------ */ | ||
|
|
||
| #include "lj_libdef.h" | ||
|
|
||
| LUALIB_API int luaopen_bit(lua_State *L) | ||
| { | ||
| LJ_LIB_REG(L, LUA_BITLIBNAME, bit); | ||
| return 1; | ||
| } | ||
|
|