FFI: Add callback support (for x86/x64).

This commit is contained in:
Mike Pall
2011-11-14 14:15:57 +01:00
parent e9eb4fdb4a
commit 71d00a56db
27 changed files with 5469 additions and 4472 deletions

View File

@@ -377,8 +377,8 @@ LJCORE_O= lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o \
lj_opt_dce.o lj_opt_loop.o lj_opt_split.o \
lj_mcode.o lj_snap.o lj_record.o lj_crecord.o lj_ffrecord.o \
lj_asm.o lj_trace.o lj_gdbjit.o \
lj_ctype.o lj_cdata.o lj_cconv.o lj_ccall.o lj_carith.o lj_clib.o \
lj_cparse.o \
lj_ctype.o lj_cdata.o lj_cconv.o lj_ccall.o lj_ccallback.o \
lj_carith.o lj_clib.o lj_cparse.o \
lj_lib.o lj_alloc.o lib_aux.o \
$(LJLIB_O) lib_init.o

View File

@@ -1,6 +1,6 @@
buildvm.o: buildvm.c buildvm.h lj_def.h lua.h luaconf.h lj_arch.h \
lj_obj.h lj_gc.h lj_bc.h lj_ir.h lj_ircall.h lj_jit.h lj_frame.h \
lj_dispatch.h lj_ccall.h lj_ctype.h luajit.h \
lj_dispatch.h lj_ctype.h lj_ccall.h luajit.h \
lj_traceerr.h
buildvm_asm.o: buildvm_asm.c buildvm.h lj_def.h lua.h luaconf.h lj_arch.h \
lj_bc.h
@@ -23,7 +23,7 @@ lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.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_clib.h lj_ff.h lj_ffdef.h lj_lib.h lj_libdef.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_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ff.h lj_ffdef.h \
@@ -69,11 +69,16 @@ 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_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_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_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_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
@@ -86,11 +91,11 @@ lj_cparse.o: lj_cparse.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_bc.h lj_vm.h lj_char.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_cparse.h lj_cconv.h lj_clib.h lj_ccall.h lj_ir.h lj_jit.h \
lj_ircall.h lj_iropt.h lj_trace.h lj_dispatch.h lj_traceerr.h \
lj_gc.h lj_cdata.h lj_cparse.h lj_cconv.h lj_clib.h lj_ccall.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_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_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
@@ -188,15 +193,15 @@ ljamalg.o: ljamalg.c lua.h luaconf.h lauxlib.h lj_gc.c lj_obj.h lj_def.h \
lj_obj.c lj_str.c lj_tab.c lj_func.c lj_udata.c lj_meta.c lj_debug.c \
lj_state.c lj_lex.h lj_alloc.h lj_dispatch.c luajit.h lj_vmevent.c \
lj_vmevent.h lj_vmmath.c lj_api.c lj_bcdump.h lj_parse.h lj_lex.c \
lualib.h lj_parse.c lj_bcread.c lj_bcwrite.c lj_ctype.c lj_cdata.c \
lj_cconv.h lj_cconv.c lj_ccall.c lj_ccall.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_mcode.c lj_mcode.h lj_snap.c lj_target.h lj_target_*.h 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
lualib.h lj_parse.c lj_bcread.c lj_bcwrite.c lj_ctype.c lj_ccallback.h \
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_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_mcode.c lj_mcode.h 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

View File

@@ -23,6 +23,7 @@
#include "lj_frame.h"
#include "lj_dispatch.h"
#if LJ_HASFFI
#include "lj_ctype.h"
#include "lj_ccall.h"
#endif
#include "luajit.h"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -114,10 +114,13 @@
|.if not X64 // x86 stack layout.
|
|.define CFRAME_SPACE, aword*7 // Delta for esp (see <--).
|.macro saveregs
| push ebp; push edi; push esi; push ebx
|.macro saveregs_
| push edi; push esi; push ebx
| sub esp, CFRAME_SPACE
|.endmacro
|.macro saveregs
| push ebp; saveregs_
|.endmacro
|.macro restoreregs
| add esp, CFRAME_SPACE
| pop ebx; pop esi; pop edi; pop ebp
@@ -166,10 +169,13 @@
|.elif X64WIN // x64/Windows stack layout
|
|.define CFRAME_SPACE, aword*5 // Delta for rsp (see <--).
|.macro saveregs
| push rbp; push rdi; push rsi; push rbx
|.macro saveregs_
| push rdi; push rsi; push rbx
| sub rsp, CFRAME_SPACE
|.endmacro
|.macro saveregs
| push rbp; saveregs_
|.endmacro
|.macro restoreregs
| add rsp, CFRAME_SPACE
| pop rbx; pop rsi; pop rdi; pop rbp
@@ -206,10 +212,13 @@
|.else // x64/POSIX stack layout
|
|.define CFRAME_SPACE, aword*5 // Delta for rsp (see <--).
|.macro saveregs
| push rbp; push rbx; push r15; push r14
|.macro saveregs_
| push rbx; push r15; push r14
| sub rsp, CFRAME_SPACE
|.endmacro
|.macro saveregs
| push rbp; saveregs_
|.endmacro
|.macro restoreregs
| add rsp, CFRAME_SPACE
| pop r14; pop r15; pop rbx; pop rbp
@@ -760,14 +769,18 @@ static void build_subroutines(BuildCtx *ctx, int cmov, int sse)
| mov PC, [RB-12] // Restore PC from [cont|PC].
|.if X64
| movsxd RAa, dword [RB-16] // May be negative on WIN64 with debug.
| test RA, RA
| jz >1
#if LJ_HASFFI
| cmp RA, 1
| jbe >1
#endif
| lea KBASEa, qword [=>0]
| add RAa, KBASEa
|.else
| mov RA, dword [RB-16]
| test RA, RA
| jz >1
#if LJ_HASFFI
| cmp RA, 1
| jbe >1
#endif
|.endif
| mov LFUNC:KBASE, [BASE-8]
| mov KBASE, LFUNC:KBASE->pc
@@ -775,11 +788,15 @@ static void build_subroutines(BuildCtx *ctx, int cmov, int sse)
| // BASE = base, RC = result, RB = meta base
| jmp RAa // Jump to continuation.
|
|1: // Tail call from C function.
#if LJ_HASFFI
|1:
| je ->cont_ffi_callback // cont = 1: return from FFI callback.
| // cont = 0: Tail call from C function.
| sub RB, BASE
| shr RB, 3
| lea RD, [RB-1]
| jmp ->vm_call_tail
#endif
|
|->cont_cat: // BASE = base, RC = result, RB = mbase
| movzx RA, PC_RB
@@ -3699,6 +3716,103 @@ static void build_subroutines(BuildCtx *ctx, int cmov, int sse)
|//-----------------------------------------------------------------------
|//-- FFI helper functions -----------------------------------------------
|//-----------------------------------------------------------------------
|
|// Handler for callback functions. Callback slot number in ah/al.
|->vm_ffi_callback:
#if LJ_HASFFI
|.type CTSTATE, CTState, PC
|.if not X64
| sub esp, 16 // Leave room for SAVE_ERRF etc.
|.endif
| saveregs_ // ebp/rbp already saved. ebp now holds global_State *.
| lea DISPATCH, [ebp+GG_G2DISP]
| mov CTSTATE, GL:ebp->ctype_state
| movzx eax, ax
| mov CTSTATE->cb.slot, eax
|.if X64
| mov CTSTATE->cb.gpr[0], CARG1
| mov CTSTATE->cb.gpr[1], CARG2
| mov CTSTATE->cb.gpr[2], CARG3
| mov CTSTATE->cb.gpr[3], CARG4
| movsd qword CTSTATE->cb.fpr[0], xmm0
| movsd qword CTSTATE->cb.fpr[1], xmm1
| movsd qword CTSTATE->cb.fpr[2], xmm2
| movsd qword CTSTATE->cb.fpr[3], xmm3
|.if X64WIN
| lea rax, [rsp+CFRAME_SIZE+4*8]
|.else
| lea rax, [rsp+CFRAME_SIZE]
| mov CTSTATE->cb.gpr[4], CARG5
| mov CTSTATE->cb.gpr[5], CARG6
| movsd qword CTSTATE->cb.fpr[4], xmm4
| movsd qword CTSTATE->cb.fpr[5], xmm5
| movsd qword CTSTATE->cb.fpr[6], xmm6
| movsd qword CTSTATE->cb.fpr[7], xmm7
|.endif
| mov CTSTATE->cb.stack, rax
| mov CARG2, rsp
|.else
| lea eax, [esp+CFRAME_SIZE+16]
| mov CTSTATE->cb.gpr[0], FCARG1
| mov CTSTATE->cb.gpr[1], FCARG2
| mov CTSTATE->cb.stack, eax
| mov FCARG1, [esp+CFRAME_SIZE+12] // Move around misplaced retaddr/ebp.
| mov FCARG2, [esp+CFRAME_SIZE+8]
| mov SAVE_RET, FCARG1
| mov SAVE_R4, FCARG2
| mov FCARG2, esp
|.endif
| mov SAVE_PC, CTSTATE // Any value outside of bytecode is ok.
| mov FCARG1, CTSTATE
| call extern lj_ccallback_enter@8 // (CTState *cts, void *cf)
| // lua_State * returned in eax (RD).
| set_vmstate INTERP
| mov BASE, L:RD->base
| mov RD, L:RD->top
| sub RD, BASE
| mov LFUNC:RB, [BASE-8]
| shr RD, 3
| add RD, 1
| ins_callt
#endif
|
|->cont_ffi_callback: // Return from FFI callback.
#if LJ_HASFFI
| mov L:RA, SAVE_L
| mov CTSTATE, [DISPATCH+DISPATCH_GL(ctype_state)]
| mov aword CTSTATE->L, L:RAa
| mov L:RA->base, BASE
| mov L:RA->top, RB
| mov FCARG1, CTSTATE
| mov FCARG2, RC
| call extern lj_ccallback_leave@8 // (CTState *cts, TValue *o)
|.if X64
| mov rax, CTSTATE->cb.gpr[0]
| movsd xmm0, qword CTSTATE->cb.fpr[0]
| jmp ->vm_leave_unw
|.else
| mov L:RB, SAVE_L
| mov eax, CTSTATE->cb.gpr[0]
| mov edx, CTSTATE->cb.gpr[1]
| cmp dword CTSTATE->cb.gpr[2], 1
| jb >7
| je >6
| fld qword CTSTATE->cb.fpr[0].d
| jmp >7
|6:
| fld dword CTSTATE->cb.fpr[0].f
|7:
| mov ecx, L:RB->top
| movzx ecx, word [ecx+6] // Get stack adjustment and copy up.
| mov SAVE_L, ecx // Must be one slot above SAVE_RET
| restoreregs
| pop ecx // Move return addr from SAVE_RET.
| add esp, [esp] // Adjust stack.
| add esp, 16
| push ecx
| ret
|.endif
#endif
|
|->vm_ffi_call@4: // Call C function via FFI.
| // Caveat: needs special frame unwinding, see below.

File diff suppressed because it is too large Load Diff

View File

@@ -27,6 +27,7 @@
#include "lj_cconv.h"
#include "lj_carith.h"
#include "lj_ccall.h"
#include "lj_ccallback.h"
#include "lj_clib.h"
#include "lj_ff.h"
#include "lj_lib.h"
@@ -384,6 +385,50 @@ LJLIB_CF(ffi_clib___gc)
#include "lj_libdef.h"
/* -- Callback function metamethods --------------------------------------- */
#define LJLIB_MODULE_ffi_callback
static int ffi_callback_set(lua_State *L, GCfunc *fn)
{
GCcdata *cd = ffi_checkcdata(L, 1);
CTState *cts = ctype_cts(L);
CType *ct = ctype_raw(cts, cd->typeid);
if (ctype_isptr(ct->info) && (LJ_32 || ct->size == 8)) {
MSize slot = lj_ccallback_ptr2slot(cts, *(void **)cdataptr(cd));
if (slot < cts->cb.sizeid && cts->cb.cbid[slot] != 0) {
GCtab *t = cts->miscmap;
TValue *tv = lj_tab_setint(L, t, (int32_t)slot);
if (fn) {
setfuncV(L, tv, fn);
lj_gc_anybarriert(L, t);
} else {
setnilV(tv);
cts->cb.cbid[slot] = 0;
cts->cb.topid = slot < cts->cb.topid ? slot : cts->cb.topid;
}
return 0;
}
}
lj_err_caller(L, LJ_ERR_FFI_BADCBACK);
return 0;
}
LJLIB_CF(ffi_callback_free)
{
return ffi_callback_set(L, NULL);
}
LJLIB_CF(ffi_callback_set)
{
GCfunc *fn = lj_lib_checkfunc(L, 2);
return ffi_callback_set(L, fn);
}
LJLIB_PUSH(top-1) LJLIB_SET(__index)
#include "lj_libdef.h"
/* -- FFI library functions ----------------------------------------------- */
#define LJLIB_MODULE_ffi
@@ -428,7 +473,7 @@ LJLIB_CF(ffi_new) LJLIB_REC(.)
o, (MSize)(L->top - o)); /* Initialize cdata. */
if (ctype_isstruct(ct->info)) {
/* Handle ctype __gc metamethod. Use the fast lookup here. */
cTValue *tv = lj_tab_getint(cts->metatype, (int32_t)id);
cTValue *tv = lj_tab_getinth(cts->miscmap, -(int32_t)id);
if (tv && tvistab(tv) && (tv = lj_meta_fast(L, tabV(tv), MM_gc))) {
GCtab *t = cts->finalizer;
if (gcref(t->metatable)) {
@@ -650,21 +695,21 @@ LJLIB_CF(ffi_abi) LJLIB_REC(.)
#undef H_
LJLIB_PUSH(top-8) LJLIB_SET(!) /* Store reference to metatype table. */
LJLIB_PUSH(top-8) LJLIB_SET(!) /* Store reference to miscmap table. */
LJLIB_CF(ffi_metatype)
{
CTState *cts = ctype_cts(L);
CTypeID id = ffi_checkctype(L, cts);
GCtab *mt = lj_lib_checktab(L, 2);
GCtab *t = cts->metatype;
GCtab *t = cts->miscmap;
CType *ct = ctype_get(cts, id); /* Only allow raw types. */
TValue *tv;
GCcdata *cd;
if (!(ctype_isstruct(ct->info) || ctype_iscomplex(ct->info) ||
ctype_isvector(ct->info)))
lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE);
tv = lj_tab_setint(L, t, (int32_t)id);
tv = lj_tab_setinth(L, t, -(int32_t)id);
if (!tvisnil(tv))
lj_err_caller(L, LJ_ERR_PROTMT);
settabV(L, tv, mt);
@@ -745,12 +790,16 @@ static void ffi_register_module(lua_State *L)
LUALIB_API int luaopen_ffi(lua_State *L)
{
CTState *cts = lj_ctype_init(L);
settabV(L, L->top++, (cts->metatype = lj_tab_new(L, 0, 0)));
settabV(L, L->top++, (cts->miscmap = lj_tab_new(L, 0, 1)));
cts->finalizer = ffi_finalizer(L);
LJ_LIB_REG(L, NULL, ffi_meta);
/* NOBARRIER: basemt is a GC root. */
setgcref(basemt_it(G(L), LJ_TCDATA), obj2gco(tabV(L->top-1)));
LJ_LIB_REG(L, NULL, ffi_clib);
LJ_LIB_REG(L, NULL, ffi_callback);
/* NOBARRIER: the key is new and lj_tab_newkey() handles the barrier. */
settabV(L, lj_tab_setstr(L, cts->miscmap, &cts->g->strempty), tabV(L->top-1));
L->top--;
lj_clib_default(L, tabV(L->top-1)); /* Create ffi.C default namespace. */
lua_pushliteral(L, LJ_OS_NAME);
lua_pushliteral(L, LJ_ARCH_NAME);

View File

@@ -10,6 +10,7 @@
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_ctype.h"
#include "lj_cconv.h"
#include "lj_cdata.h"
@@ -290,7 +291,7 @@
}
#else
#error "missing calling convention definitions for this architecture"
#error "Missing calling convention definitions for this architecture"
#endif
#ifndef CCALL_HANDLE_STRUCTRET2
@@ -649,7 +650,13 @@ int lj_ccall_func(lua_State *L, GCcdata *cd)
int gcsteps, ret;
cc.func = (void (*)(void))cdata_getptr(cdataptr(cd), sz);
gcsteps = ccall_set_args(L, cts, ct, &cc);
cts->cb.slot = ~0u;
lj_vm_ffi_call(&cc);
if (cts->cb.slot != ~0u) { /* Blacklist function that called a callback. */
TValue tv;
setlightudV(&tv, (void *)cc.func);
setboolV(lj_tab_set(L, cts->miscmap, &tv), 1);
}
gcsteps += ccall_get_results(L, cts, ct, &cc, &ret);
#if LJ_TARGET_X86 && LJ_ABI_WIN
/* Automatically detect __stdcall and fix up C function declaration. */

View File

@@ -81,7 +81,7 @@ typedef double FPRArg;
typedef intptr_t GPRArg;
#else
#error "missing calling convention definitions for this architecture"
#error "Missing calling convention definitions for this architecture"
#endif
#ifndef CCALL_SPS_EXTRA
@@ -99,6 +99,10 @@ typedef intptr_t GPRArg;
#define CCALL_NUM_FPR \
(CCALL_NARG_FPR > CCALL_NRET_FPR ? CCALL_NARG_FPR : CCALL_NRET_FPR)
/* Check against constants in lj_ctype.h. */
LJ_STATIC_ASSERT(CCALL_NUM_GPR <= CCALL_MAX_GPR);
LJ_STATIC_ASSERT(CCALL_NUM_FPR <= CCALL_MAX_FPR);
#define CCALL_MAXSTACK 32
/* -- C call state -------------------------------------------------------- */

461
src/lj_ccallback.c Normal file
View File

@@ -0,0 +1,461 @@
/*
** FFI C callback handling.
** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h
*/
#include "lj_obj.h"
#if LJ_HASFFI
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_tab.h"
#include "lj_state.h"
#include "lj_frame.h"
#include "lj_ctype.h"
#include "lj_cconv.h"
#include "lj_ccall.h"
#include "lj_ccallback.h"
#include "lj_target.h"
#include "lj_vm.h"
/* -- Target-specific handling of callback slots -------------------------- */
#define CALLBACK_MCODE_SIZE (LJ_PAGESIZE * LJ_NUM_CBPAGE)
#if LJ_TARGET_X86ORX64
#define CALLBACK_MCODE_HEAD (LJ_64 ? 8 : 0)
#define CALLBACK_MCODE_GROUP (-2+1+2+5+(LJ_64 ? 6 : 5))
#define CALLBACK_SLOT2OFS(slot) \
(CALLBACK_MCODE_HEAD + CALLBACK_MCODE_GROUP*((slot)/32) + 4*(slot))
static MSize CALLBACK_OFS2SLOT(MSize ofs)
{
MSize group;
ofs -= CALLBACK_MCODE_HEAD;
group = ofs / (32*4 + CALLBACK_MCODE_GROUP);
return (ofs % (32*4 + CALLBACK_MCODE_GROUP))/4 + group*32;
}
#define CALLBACK_MAX_SLOT \
(((CALLBACK_MCODE_SIZE-CALLBACK_MCODE_HEAD)/(CALLBACK_MCODE_GROUP+4*32))*32)
#else
/* Missing support for this architecture. */
#define CALLBACK_SLOT2OFS(slot) (0*(slot))
#define CALLBACK_OFS2SLOT(ofs) (0*(ofs))
#define CALLBACK_MAX_SLOT 0
#endif
/* Convert callback slot number to callback function pointer. */
static void *callback_slot2ptr(CTState *cts, MSize slot)
{
return (uint8_t *)cts->cb.mcode + CALLBACK_SLOT2OFS(slot);
}
/* Convert callback function pointer to slot number. */
MSize lj_ccallback_ptr2slot(CTState *cts, void *p)
{
uintptr_t ofs = (uintptr_t)((uint8_t *)p -(uint8_t *)cts->cb.mcode);
if (ofs < CALLBACK_MCODE_SIZE) {
MSize slot = CALLBACK_OFS2SLOT((MSize)ofs);
if (CALLBACK_SLOT2OFS(slot) == (MSize)ofs)
return slot;
}
return ~0u; /* Not a known callback function pointer. */
}
#if LJ_TARGET_X86ORX64
/* Initialize machine code for callback function pointers. */
static void callback_mcode_init(global_State *g, uint8_t *page)
{
uint8_t *p = page;
uint8_t *target = (uint8_t *)(void *)lj_vm_ffi_callback;
MSize slot;
#if LJ_64
*(void **)p = target; p += 8;
#endif
for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) {
/* mov al, slot; jmp group */
*p++ = XI_MOVrib | RID_EAX; *p++ = (uint8_t)slot;
if ((slot & 31) == 31 || slot == CALLBACK_MAX_SLOT-1) {
/* push ebp/rbp; mov ah, slot>>8; mov ebp, &g. */
*p++ = XI_PUSH + RID_EBP;
*p++ = XI_MOVrib | (RID_EAX+4); *p++ = (uint8_t)(slot >> 8);
*p++ = XI_MOVri | RID_EBP;
*(int32_t *)p = i32ptr(g); p += 4;
#if LJ_64
/* jmp [rip-pageofs] where lj_vm_ffi_callback is stored. */
*p++ = XI_GROUP5; *p++ = XM_OFS0 + (XOg_JMP<<3) + RID_EBP;
*(int32_t *)p = (int32_t)(page-(p+4)); p += 4;
#else
/* jmp lj_vm_ffi_callback. */
*p++ = XI_JMP; *(int32_t *)p = target-(p+4); p += 4;
#endif
} else {
*p++ = XI_JMPs; *p++ = (uint8_t)((2+2)*(31-(slot&31)) - 2);
}
}
lua_assert(p - page <= CALLBACK_MCODE_SIZE);
}
#else
/* Missing support for this architecture. */
#define callback_mcode_init(g, p) UNUSED(p)
#endif
/* -- Machine code management --------------------------------------------- */
#if LJ_TARGET_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#elif LJ_TARGET_POSIX
#include <sys/mman.h>
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif
#endif
/* Allocate and initialize area for callback function pointers. */
static void callback_mcode_new(CTState *cts)
{
size_t sz = (size_t)CALLBACK_MCODE_SIZE;
void *p;
if (CALLBACK_MAX_SLOT == 0)
lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
#if LJ_TARGET_WINDOWS
p = VirtualAlloc(NULL, sz, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
if (!p)
lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
#elif LJ_TARGET_POSIX
p = mmap(NULL, sz, (PROT_READ|PROT_WRITE), MAP_PRIVATE|MAP_ANONYMOUS,
-1, 0);
if (p == MAP_FAILED)
lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
#else
/* Fallback allocator. Fails if memory is not executable by default. */
p = lj_mem_new(cts->L, sz);
#endif
cts->cb.mcode = p;
callback_mcode_init(cts->g, p);
#if LJ_TARGET_WINDOWS
{
DWORD oprot;
VirtualProtect(p, sz, PAGE_EXECUTE_READ, &oprot);
}
#elif LJ_TARGET_POSIX
mprotect(p, sz, (PROT_READ|PROT_EXEC));
#endif
}
/* Free area for callback function pointers. */
void lj_ccallback_mcode_free(CTState *cts)
{
size_t sz = (size_t)CALLBACK_MCODE_SIZE;
void *p = cts->cb.mcode;
if (p == NULL) return;
#if LJ_TARGET_WINDOWS
VirtualFree(p, 0, MEM_RELEASE);
UNUSED(sz);
#elif LJ_TARGET_POSIX
munmap(p, sz);
#else
lj_mem_free(cts->g, p, sz);
#endif
}
/* -- C callback entry ---------------------------------------------------- */
/* Target-specific handling of register arguments. Similar to lj_ccall.c. */
#if LJ_TARGET_X86
#define CALLBACK_HANDLE_REGARG \
if (!isfp) { /* Only non-FP values may be passed in registers. */ \
if (n > 1) { /* Anything > 32 bit is passed on the stack. */ \
if (!LJ_ABI_WIN) ngpr = maxgpr; /* Prevent reordering. */ \
} else if (ngpr + 1 <= maxgpr) { \
sp = &cts->cb.gpr[ngpr]; \
ngpr += n; \
goto done; \
} \
}
#elif LJ_TARGET_X64 && LJ_ABI_WIN
/* Windows/x64 argument registers are strictly positional (use ngpr). */
#define CALLBACK_HANDLE_REGARG \
if (isfp) { \
if (ngpr < 4) { sp = &cts->cb.fpr[ngpr++]; nfpr = ngpr; goto done; } \
} else { \
if (ngpr < 4) { sp = &cts->cb.gpr[ngpr++]; goto done; } \
}
#elif LJ_TARGET_X64
#define CALLBACK_HANDLE_REGARG \
if (isfp) { \
if (nfpr + n <= CCALL_NARG_FPR) { \
sp = &cts->cb.fpr[nfpr]; \
nfpr += n; \
goto done; \
} \
} else { \
if (ngpr + n <= maxgpr) { \
sp = &cts->cb.gpr[ngpr]; \
ngpr += n; \
goto done; \
} \
}
#elif LJ_TARGET_ARM
#define CALLBACK_HANDLE_REGARG \
UNUSED(ngpr); UNUSED(maxgpr); goto done; /* NYI */
#elif LJ_TARGET_PPC
#define CALLBACK_HANDLE_REGARG \
UNUSED(ngpr); UNUSED(nfpr); UNUSED(maxgpr); goto done; /* NYI */
#define CALLBACK_HANDLE_RET /* NYI */
#else
#error "Missing calling convention definitions for this architecture"
#endif
/* Convert and push callback arguments to Lua stack. */
static void callback_conv_args(CTState *cts, lua_State *L)
{
TValue *o = L->top;
intptr_t *stack = cts->cb.stack;
MSize slot = cts->cb.slot;
CTypeID id = 0, rid, fid;
CType *ct;
GCfunc *fn;
MSize ngpr = 0, nsp = 0, maxgpr = CCALL_NARG_GPR;
#if CCALL_NARG_FPR
MSize nfpr = 0;
#endif
if (slot < cts->cb.sizeid && (id = cts->cb.cbid[slot]) != 0) {
ct = ctype_get(cts, id);
rid = ctype_cid(ct->info);
fn = funcV(lj_tab_getint(cts->miscmap, (int32_t)slot));
} else { /* Must set up frame first, before throwing the error. */
ct = NULL;
rid = 0;
fn = (GCfunc *)L;
}
o->u32.lo = LJ_CONT_FFI_CALLBACK; /* Continuation returns from callback. */
o->u32.hi = rid; /* Return type. x86: +(spadj<<16). */
o++;
setframe_gc(o, obj2gco(fn));
setframe_ftsz(o, (int)((char *)(o+1) - (char *)L->base) + FRAME_CONT);
L->top = L->base = ++o;
if (!ct)
lj_err_caller(cts->L, LJ_ERR_FFI_BADCBACK);
if (isluafunc(fn))
setcframe_pc(L->cframe, proto_bc(funcproto(fn))+1);
lj_state_checkstack(L, LUA_MINSTACK); /* May throw. */
o = L->base; /* Might have been reallocated. */
#if LJ_TARGET_X86
/* x86 has several different calling conventions. */
switch (ctype_cconv(ct->info)) {
case CTCC_FASTCALL: maxgpr = 2; break;
case CTCC_THISCALL: maxgpr = 1; break;
default: maxgpr = 0; break;
}
#endif
fid = ct->sib;
while (fid) {
CType *ctf = ctype_get(cts, fid);
if (!ctype_isattrib(ctf->info)) {
CType *cta;
void *sp;
CTSize sz;
int isfp;
MSize n;
lua_assert(ctype_isfield(ctf->info));
cta = ctype_rawchild(cts, ctf);
if (ctype_isenum(cta->info)) cta = ctype_child(cts, cta);
isfp = ctype_isfp(cta->info);
sz = (cta->size + CTSIZE_PTR-1) & ~(CTSIZE_PTR-1);
n = sz / CTSIZE_PTR; /* Number of GPRs or stack slots needed. */
CALLBACK_HANDLE_REGARG /* Handle register arguments. */
/* Otherwise pass argument on stack. */
if (CCALL_ALIGN_STACKARG && LJ_32 && sz == 8)
nsp = (nsp + 1) & ~1u; /* Align 64 bit argument on stack. */
sp = &stack[nsp];
nsp += n;
done:
if (LJ_BE && cta->size < CTSIZE_PTR)
sp = (void *)((uint8_t *)sp + CTSIZE_PTR-cta->size);
lj_cconv_tv_ct(cts, cta, 0, o++, sp);
}
fid = ctf->sib;
}
L->top = o;
#if LJ_TARGET_X86
/* Store stack adjustment for returns from fastcall/stdcall callbacks. */
switch (ctype_cconv(ct->info)) {
case CTCC_FASTCALL: case CTCC_STDCALL:
(L->base-2)->u32.hi |= (nsp << (16+2));
break;
}
#endif
}
/* Convert Lua object to callback result. */
static void callback_conv_result(CTState *cts, lua_State *L, TValue *o)
{
CType *ctr = ctype_raw(cts, (uint16_t)(L->base-2)->u32.hi);
#if LJ_TARGET_X86
cts->cb.gpr[2] = 0;
#endif
if (!ctype_isvoid(ctr->info)) {
uint8_t *dp = (uint8_t *)&cts->cb.gpr[0];
#ifdef CALLBACK_HANDLE_RET
CALLBACK_HANDLE_RET
#endif
#if CCALL_NUM_FPR
if (ctype_isfp(ctr->info))
dp = (uint8_t *)&cts->cb.fpr[0];
#endif
lj_cconv_ct_tv(cts, ctr, dp, o, 0);
/* Extend returned integers to (at least) 32 bits. */
if (ctype_isinteger_or_bool(ctr->info) && ctr->size < 4) {
if (ctr->info & CTF_UNSIGNED)
*(uint32_t *)dp = ctr->size == 1 ? (uint32_t)*(uint8_t *)dp :
(uint32_t)*(uint16_t *)dp;
else
*(int32_t *)dp = ctr->size == 1 ? (int32_t)*(int8_t *)dp :
(int32_t)*(int16_t *)dp;
}
#if LJ_TARGET_X86
if (ctype_isfp(ctr->info))
cts->cb.gpr[2] = ctr->size == sizeof(float) ? 1 : 2;
#endif
}
}
/* Enter callback. */
lua_State * LJ_FASTCALL lj_ccallback_enter(CTState *cts, void *cf)
{
lua_State *L = cts->L;
lua_assert(L != NULL);
if (gcref(cts->g->jit_L))
lj_err_caller(gco2th(gcref(cts->g->jit_L)), LJ_ERR_FFI_BADCBACK);
/* Setup C frame. */
cframe_prev(cf) = L->cframe;
setcframe_L(cf, L);
cframe_errfunc(cf) = -1;
cframe_nres(cf) = 0;
L->cframe = cf;
callback_conv_args(cts, L);
return L; /* Now call the function on this stack. */
}
/* Leave callback. */
void LJ_FASTCALL lj_ccallback_leave(CTState *cts, TValue *o)
{
lua_State *L = cts->L;
GCfunc *fn;
TValue *obase = L->base;
L->base = L->top; /* Keep continuation frame for throwing errors. */
/* PC of RET* is lost. Point to last line for result conv. errors. */
fn = curr_func(L);
if (isluafunc(fn)) {
GCproto *pt = funcproto(fn);
setcframe_pc(L->cframe, proto_bc(pt)+pt->sizebc);
}
callback_conv_result(cts, L, o);
/* Finally drop C frame and continuation frame. */
L->cframe = cframe_prev(L->cframe);
L->top -= 2;
L->base = obase;
}
/* -- C callback management ----------------------------------------------- */
/* Get an unused slot in the callback slot table. */
static MSize callback_slot_new(CTState *cts, CType *ct)
{
CTypeID id = ctype_typeid(cts, ct);
CTypeID1 *cbid = cts->cb.cbid;
MSize top;
for (top = cts->cb.topid; top < cts->cb.sizeid; top++)
if (LJ_LIKELY(cbid[top] == 0))
goto found;
#if CALLBACK_MAX_SLOT
if (top >= CALLBACK_MAX_SLOT)
#endif
lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
if (!cts->cb.mcode)
callback_mcode_new(cts);
lj_mem_growvec(cts->L, cbid, cts->cb.sizeid, CALLBACK_MAX_SLOT, CTypeID1);
cts->cb.cbid = cbid;
memset(cbid+top, 0, (cts->cb.sizeid-top)*sizeof(CTypeID1));
found:
cbid[top] = id;
cts->cb.topid = top+1;
return top;
}
/* Check for function pointer and supported argument/result types. */
static CType *callback_checkfunc(CTState *cts, CType *ct)
{
int narg = 0;
if (!ctype_isptr(ct->info) || (LJ_64 && ct->size != CTSIZE_PTR))
return NULL;
ct = ctype_rawchild(cts, ct);
if (ctype_isfunc(ct->info)) {
CType *ctr = ctype_rawchild(cts, ct);
CTypeID fid = ct->sib;
if (!(ctype_isvoid(ctr->info) || ctype_isenum(ctr->info) ||
ctype_isptr(ctr->info) || (ctype_isnum(ctr->info) && ctr->size <= 8)))
return NULL;
if ((ct->info & CTF_VARARG))
return NULL;
while (fid) {
CType *ctf = ctype_get(cts, fid);
if (!ctype_isattrib(ctf->info)) {
CType *cta;
lua_assert(ctype_isfield(ctf->info));
cta = ctype_rawchild(cts, ctf);
if (!(ctype_isenum(cta->info) || ctype_isptr(cta->info) ||
(ctype_isnum(cta->info) && cta->size <= 8)) ||
++narg >= LUA_MINSTACK-3)
return NULL;
}
fid = ctf->sib;
}
return ct;
}
return NULL;
}
/* Create a new callback and return the callback function pointer. */
void *lj_ccallback_new(CTState *cts, CType *ct, GCfunc *fn)
{
ct = callback_checkfunc(cts, ct);
if (ct) {
MSize slot = callback_slot_new(cts, ct);
GCtab *t = cts->miscmap;
setfuncV(cts->L, lj_tab_setint(cts->L, t, (int32_t)slot), fn);
return callback_slot2ptr(cts, slot);
}
return NULL; /* Bad conversion. */
}
#endif

25
src/lj_ccallback.h Normal file
View File

@@ -0,0 +1,25 @@
/*
** FFI C callback handling.
** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_CCALLBACK_H
#define _LJ_CCALLBACK_H
#include "lj_obj.h"
#include "lj_ctype.h"
#if LJ_HASFFI
/* Really belongs to lj_vm.h. */
LJ_ASMF void lj_vm_ffi_callback(void);
LJ_FUNC MSize lj_ccallback_ptr2slot(CTState *cts, void *p);
LJ_FUNCA lua_State * LJ_FASTCALL lj_ccallback_enter(CTState *cts, void *cf);
LJ_FUNCA void LJ_FASTCALL lj_ccallback_leave(CTState *cts, TValue *o);
LJ_FUNC void *lj_ccallback_new(CTState *cts, CType *ct, GCfunc *fn);
LJ_FUNC void lj_ccallback_mcode_free(CTState *cts);
#endif
#endif

View File

@@ -12,6 +12,7 @@
#include "lj_ctype.h"
#include "lj_cdata.h"
#include "lj_cconv.h"
#include "lj_ccallback.h"
/* -- Conversion errors --------------------------------------------------- */
@@ -603,6 +604,13 @@ void lj_cconv_ct_tv(CTState *cts, CType *d,
tmpptr = uddata(udataV(o));
} else if (tvislightud(o)) {
tmpptr = lightudV(o);
} else if (tvisfunc(o)) {
void *p = lj_ccallback_new(cts, d, funcV(o));
if (p) {
*(void **)dp = p;
return;
}
goto err_conv;
} else {
err_conv:
cconv_err_convtv(cts, d, o, flags);

View File

@@ -15,6 +15,7 @@
#include "lj_tab.h"
#include "lj_frame.h"
#include "lj_ctype.h"
#include "lj_cdata.h"
#include "lj_cparse.h"
#include "lj_cconv.h"
#include "lj_clib.h"
@@ -785,7 +786,7 @@ static TRef crec_call_args(jit_State *J, RecordFFData *rd,
did = ctype_cid(ctf->info);
} else {
if (!(ct->info & CTF_VARARG))
lj_trace_err(J, LJ_TRERR_NYICALL); /* Too many arguments. */
lj_trace_err(J, LJ_TRERR_NYICALL); /* Too many arguments. */
did = lj_ccall_ctid_vararg(cts, o); /* Infer vararg type. */
}
d = ctype_raw(cts, did);
@@ -853,6 +854,12 @@ static int crec_call(jit_State *J, RecordFFData *rd, GCcdata *cd)
CType *ctr = ctype_rawchild(cts, ct);
IRType t = crec_ct2irt(ctr);
TRef tr;
TValue tv;
/* Check for blacklisted C functions that might call a callback. */
setlightudV(&tv,
cdata_getptr(cdataptr(cd), (LJ_64 && tp == IRT_P64) ? 8 : 4));
if (tvistrue(lj_tab_get(J->L, cts->miscmap, &tv)))
lj_trace_err(J, LJ_TRERR_BLACKL);
if (ctype_isvoid(ctr->info)) {
t = IRT_NIL;
rd->nres = 0;

View File

@@ -12,6 +12,7 @@
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_ctype.h"
#include "lj_ccallback.h"
/* -- C type definitions -------------------------------------------------- */
@@ -315,7 +316,11 @@ cTValue *lj_ctype_meta(CTState *cts, CTypeID id, MMS mm)
id = ctype_cid(ct->info);
ct = ctype_get(cts, id);
}
tv = lj_tab_getint(cts->metatype, (int32_t)id);
if (ctype_isptr(ct->info) &&
ctype_isfunc(ctype_get(cts, ctype_cid(ct->info))->info))
tv = lj_tab_getstr(cts->miscmap, &cts->g->strempty);
else
tv = lj_tab_getinth(cts->miscmap, -(int32_t)id);
if (tv && tvistab(tv) &&
(tv = lj_tab_getstr(tabV(tv), mmname_str(cts->g, mm))) && !tvisnil(tv))
return tv;
@@ -592,7 +597,9 @@ void lj_ctype_freestate(global_State *g)
{
CTState *cts = ctype_ctsG(g);
if (cts) {
lj_ccallback_mcode_free(cts);
lj_mem_freevec(g, cts->tab, cts->sizetab, CType);
lj_mem_freevec(g, cts->cb.cbid, cts->cb.sizeid, CTypeID1);
lj_mem_freet(g, cts);
}
}

View File

@@ -151,6 +151,25 @@ typedef struct CType {
#define CTHASH_SIZE 128 /* Number of hash anchors. */
#define CTHASH_MASK (CTHASH_SIZE-1)
/* Simplify target-specific configuration. Checked in lj_ccall.h. */
#define CCALL_MAX_GPR 8
#define CCALL_MAX_FPR 8
typedef LJ_ALIGN(8) union FPRCBArg { double d; float f; } FPRCBArg;
/* C callback state. Defined here, to avoid dragging in lj_ccall.h. */
typedef LJ_ALIGN(8) struct CCallback {
FPRCBArg fpr[CCALL_MAX_FPR]; /* Arguments/results in FPRs. */
intptr_t gpr[CCALL_MAX_GPR]; /* Arguments/results in GPRs. */
intptr_t *stack; /* Pointer to arguments on stack. */
void *mcode; /* Machine code for callback func. pointers. */
CTypeID1 *cbid; /* Callback type table. */
MSize sizeid; /* Size of callback type table. */
MSize topid; /* Highest unused callback type table slot. */
MSize slot; /* Current callback slot. */
} CCallback;
/* C type state. */
typedef struct CTState {
CType *tab; /* C type table. */
@@ -159,7 +178,8 @@ typedef struct CTState {
lua_State *L; /* Lua state (needed for errors and allocations). */
global_State *g; /* Global state. */
GCtab *finalizer; /* Map of cdata to finalizer. */
GCtab *metatype; /* Map of CTypeID to metatable. */
GCtab *miscmap; /* Map of -CTypeID to metatable and cb slot to func. */
CCallback cb; /* Temporary callback state. */
CTypeID1 hash[CTHASH_SIZE]; /* Hash anchors for C type table. */
} CTState;

View File

@@ -107,6 +107,7 @@ BCLine LJ_FASTCALL lj_debug_line(GCproto *pt, BCPos pc)
const void *lineinfo = proto_lineinfo(pt);
if (pc < pt->sizebc && lineinfo) {
BCLine first = pt->firstline;
if (pc == pt->sizebc-1) return first + pt->numline;
if (pc-- == 0) return first;
if (pt->numline < 256)
return first + (BCLine)((const uint8_t *)lineinfo)[pc];
@@ -124,7 +125,7 @@ static BCLine debug_frameline(lua_State *L, GCfunc *fn, cTValue *nextframe)
BCPos pc = debug_framepc(L, fn, nextframe);
if (pc != NO_BCPOS) {
GCproto *pt = funcproto(fn);
lua_assert(pc < pt->sizebc);
lua_assert(pc <= pt->sizebc);
return lj_debug_line(pt, pc);
}
return -1;

View File

@@ -67,6 +67,8 @@ typedef unsigned int uintptr_t;
#define LJ_MAX_IDXCHAIN 100 /* __index/__newindex chain limit. */
#define LJ_STACK_EXTRA 5 /* Extra stack space (metamethods). */
#define LJ_NUM_CBPAGE 1 /* Number of FFI callback pages. */
/* Minimum table/buffer sizes. */
#define LJ_MIN_GLOBAL 6 /* Min. global table size (hbits). */
#define LJ_MIN_REGISTRY 2 /* Min. registry size (hbits). */

View File

@@ -113,6 +113,9 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode)
frame = frame_prevl(frame);
break;
case FRAME_C: /* C frame. */
#if LJ_HASFFI
unwind_c:
#endif
#if LJ_UNWIND_EXT
if (errcode) {
L->cframe = cframe_prev(cf);
@@ -145,6 +148,10 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode)
}
return cf;
case FRAME_CONT: /* Continuation frame. */
#if LJ_HASFFI
if ((frame-1)->u32.lo == LJ_CONT_FFI_CALLBACK)
goto unwind_c;
#endif
case FRAME_VARG: /* Vararg frame. */
frame = frame_prevd(frame);
break;
@@ -464,6 +471,10 @@ static ptrdiff_t finderrfunc(lua_State *L)
cf = cframe_prev(cf);
/* fallthrough */
case FRAME_CONT:
#if LJ_HASFFI
if ((frame-1)->u32.lo == LJ_CONT_FFI_CALLBACK)
cf = cframe_prev(cf);
#endif
case FRAME_VARG:
frame = frame_prevd(frame);
break;
@@ -591,15 +602,23 @@ LJ_NOINLINE void lj_err_callermsg(lua_State *L, const char *msg)
if (frame_islua(frame)) {
pframe = frame_prevl(frame);
} else if (frame_iscont(frame)) {
pframe = frame_prevd(frame);
#if LJ_HASFFI
/* Remove frame for FFI metamethods. */
if (frame_func(frame)->c.ffid >= FF_ffi_meta___index &&
frame_func(frame)->c.ffid <= FF_ffi_meta___tostring) {
L->base = pframe+1;
L->top = frame;
}
if ((frame-1)->u32.lo == LJ_CONT_FFI_CALLBACK) {
pframe = frame;
frame = NULL;
} else
#endif
{
pframe = frame_prevd(frame);
#if LJ_HASFFI
/* Remove frame for FFI metamethods. */
if (frame_func(frame)->c.ffid >= FF_ffi_meta___index &&
frame_func(frame)->c.ffid <= FF_ffi_meta___tostring) {
L->base = pframe+1;
L->top = frame;
}
#endif
}
}
lj_debug_addloc(L, msg, pframe, frame);
lj_err_run(L);

View File

@@ -160,6 +160,12 @@ ERRDEF(FFI_BADMEMBER, LUA_QS " has no member named " LUA_QS)
ERRDEF(FFI_BADIDX, LUA_QS " cannot be indexed")
ERRDEF(FFI_WRCONST, "attempt to write to constant location")
ERRDEF(FFI_NODECL, "missing declaration for symbol " LUA_QS)
ERRDEF(FFI_BADCBACK, "bad callback")
#if LJ_TARGET_X86ORX64
ERRDEF(FFI_CBACKOV, "too many callbacks")
#else
ERRDEF(FFI_CBACKOV, "no support for callbacks (yet)")
#endif
ERRDEF(FFI_NYIPACKBIT, "NYI: packed bit fields")
ERRDEF(FFI_NYICALL, "NYI: cannot call this C function (yet)")
#endif

View File

@@ -138,6 +138,8 @@ enum {
(&gcref(*(GCRef *)(((char *)(cf))+CFRAME_OFS_L))->th)
#define cframe_pc(cf) \
(mref(*(MRef *)(((char *)(cf))+CFRAME_OFS_PC), const BCIns))
#define setcframe_L(cf, L) \
(setmref(*(MRef *)(((char *)(cf))+CFRAME_OFS_L), (L)))
#define setcframe_pc(cf, pc) \
(setmref(*(MRef *)(((char *)(cf))+CFRAME_OFS_PC), (pc)))
#define cframe_canyield(cf) ((intptr_t)(cf) & CFRAME_RESUME)

View File

@@ -77,7 +77,7 @@ int lj_meta_tailcall(lua_State *L, cTValue *tv)
TValue *top = L->top;
const BCIns *pc = frame_pc(base-1); /* Preserve old PC from frame. */
copyTV(L, base-1, tv); /* Replace frame with new object. */
top->u64 = 0;
top->u32.lo = LJ_CONT_TAILCALL;
setframe_pc(top, pc);
setframe_gc(top+1, obj2gco(L)); /* Dummy frame object. */
setframe_ftsz(top+1, (int)((char *)(top+2) - (char *)base) + FRAME_CONT);

View File

@@ -192,6 +192,7 @@ typedef enum {
XI_CALL = 0xe8,
XI_JMP = 0xe9,
XI_JMPs = 0xeb,
XI_PUSH = 0x50, /* Really 50+r. */
XI_JCCs = 0x70, /* Really 7x. */
XI_JCCn = 0x80, /* Really 0f8x. */
XI_LEA = 0x8d,
@@ -203,6 +204,7 @@ typedef enum {
XI_PUSHi8 = 0x6a,
XI_TEST = 0x85,
XI_MOVmi = 0xc7,
XI_GROUP5 = 0xff,
/* Note: little-endian byte-order! */
XI_FLDZ = 0xeed9,

View File

@@ -88,6 +88,8 @@ LJ_ASMF void lj_cont_condt(void); /* Branch if result is true. */
LJ_ASMF void lj_cont_condf(void); /* Branch if result is false. */
LJ_ASMF void lj_cont_hook(void); /* Continue from hook yield. */
enum { LJ_CONT_TAILCALL, LJ_CONT_FFI_CALLBACK }; /* Special continuations. */
/* Start of the ASM code. */
LJ_ASMF char lj_vm_asm_begin[];

View File

@@ -52,6 +52,7 @@
#include "lj_cdata.c"
#include "lj_cconv.c"
#include "lj_ccall.c"
#include "lj_ccallback.c"
#include "lj_carith.c"
#include "lj_clib.c"
#include "lj_cparse.c"