diff options
author | Mike Pall <mike> | 2016-05-07 12:32:15 +0200 |
---|---|---|
committer | Mike Pall <mike> | 2016-05-07 12:32:15 +0200 |
commit | 35b09e692ead67181755795352f1df12547fd4fa (patch) | |
tree | d120dd561f649f955ddbbe844fe00a97f7b9e625 /src/lj_err.c | |
parent | 6a9973203c55daa4c1fcd611718bc5df09e4e5b5 (diff) | |
download | luajit-35b09e692ead67181755795352f1df12547fd4fa.tar.gz luajit-35b09e692ead67181755795352f1df12547fd4fa.tar.bz2 luajit-35b09e692ead67181755795352f1df12547fd4fa.zip |
Windows/x86: Add full exception interoperability.
Contributed by Peter Cawley.
Diffstat (limited to 'src/lj_err.c')
-rw-r--r-- | src/lj_err.c | 38 |
1 files changed, 30 insertions, 8 deletions
diff --git a/src/lj_err.c b/src/lj_err.c index a847ca07..1314c8db 100644 --- a/src/lj_err.c +++ b/src/lj_err.c | |||
@@ -46,7 +46,8 @@ | |||
46 | ** the wrapper function feature. Lua errors thrown through C++ frames | 46 | ** the wrapper function feature. Lua errors thrown through C++ frames |
47 | ** cannot be caught by C++ code and C++ destructors are not run. | 47 | ** cannot be caught by C++ code and C++ destructors are not run. |
48 | ** | 48 | ** |
49 | ** EXT is the default on x64 systems, INT is the default on all other systems. | 49 | ** EXT is the default on x64 systems and on Windows, INT is the default on all |
50 | ** other systems. | ||
50 | ** | 51 | ** |
51 | ** EXT can be manually enabled on POSIX systems using GCC and DWARF2 stack | 52 | ** EXT can be manually enabled on POSIX systems using GCC and DWARF2 stack |
52 | ** unwinding with -DLUAJIT_UNWIND_EXTERNAL. *All* C code must be compiled | 53 | ** unwinding with -DLUAJIT_UNWIND_EXTERNAL. *All* C code must be compiled |
@@ -55,7 +56,6 @@ | |||
55 | ** and all C libraries that have callbacks which may be used to call back | 56 | ** and all C libraries that have callbacks which may be used to call back |
56 | ** into Lua. C++ code must *not* be compiled with -fno-exceptions. | 57 | ** into Lua. C++ code must *not* be compiled with -fno-exceptions. |
57 | ** | 58 | ** |
58 | ** EXT cannot be enabled on WIN32 since system exceptions use code-driven SEH. | ||
59 | ** EXT is mandatory on WIN64 since the calling convention has an abundance | 59 | ** EXT is mandatory on WIN64 since the calling convention has an abundance |
60 | ** of callee-saved registers (rbx, rbp, rsi, rdi, r12-r15, xmm6-xmm15). | 60 | ** of callee-saved registers (rbx, rbp, rsi, rdi, r12-r15, xmm6-xmm15). |
61 | ** The POSIX/x64 interpreter only saves r12/r13 for INT (e.g. PS4). | 61 | ** The POSIX/x64 interpreter only saves r12/r13 for INT (e.g. PS4). |
@@ -63,7 +63,7 @@ | |||
63 | 63 | ||
64 | #if defined(__GNUC__) && (LJ_TARGET_X64 || defined(LUAJIT_UNWIND_EXTERNAL)) && !LJ_NO_UNWIND | 64 | #if defined(__GNUC__) && (LJ_TARGET_X64 || defined(LUAJIT_UNWIND_EXTERNAL)) && !LJ_NO_UNWIND |
65 | #define LJ_UNWIND_EXT 1 | 65 | #define LJ_UNWIND_EXT 1 |
66 | #elif LJ_TARGET_X64 && LJ_TARGET_WINDOWS | 66 | #elif LJ_TARGET_WINDOWS |
67 | #define LJ_UNWIND_EXT 1 | 67 | #define LJ_UNWIND_EXT 1 |
68 | #endif | 68 | #endif |
69 | 69 | ||
@@ -384,7 +384,7 @@ static void err_raise_ext(int errcode) | |||
384 | 384 | ||
385 | #endif /* LJ_TARGET_ARM */ | 385 | #endif /* LJ_TARGET_ARM */ |
386 | 386 | ||
387 | #elif LJ_TARGET_X64 && LJ_ABI_WIN | 387 | #elif LJ_ABI_WIN |
388 | 388 | ||
389 | /* | 389 | /* |
390 | ** Someone in Redmond owes me several days of my life. A lot of this is | 390 | ** Someone in Redmond owes me several days of my life. A lot of this is |
@@ -402,6 +402,7 @@ static void err_raise_ext(int errcode) | |||
402 | #define WIN32_LEAN_AND_MEAN | 402 | #define WIN32_LEAN_AND_MEAN |
403 | #include <windows.h> | 403 | #include <windows.h> |
404 | 404 | ||
405 | #if LJ_TARGET_X64 | ||
405 | /* Taken from: http://www.nynaeve.net/?p=99 */ | 406 | /* Taken from: http://www.nynaeve.net/?p=99 */ |
406 | typedef struct UndocumentedDispatcherContext { | 407 | typedef struct UndocumentedDispatcherContext { |
407 | ULONG64 ControlPc; | 408 | ULONG64 ControlPc; |
@@ -416,11 +417,14 @@ typedef struct UndocumentedDispatcherContext { | |||
416 | ULONG ScopeIndex; | 417 | ULONG ScopeIndex; |
417 | ULONG Fill0; | 418 | ULONG Fill0; |
418 | } UndocumentedDispatcherContext; | 419 | } UndocumentedDispatcherContext; |
420 | #else | ||
421 | typedef void *UndocumentedDispatcherContext; | ||
422 | #endif | ||
419 | 423 | ||
420 | /* Another wild guess. */ | 424 | /* Another wild guess. */ |
421 | extern void __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow); | 425 | extern void __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow); |
422 | 426 | ||
423 | #ifdef MINGW_SDK_INIT | 427 | #if LJ_TARGET_X64 && defined(MINGW_SDK_INIT) |
424 | /* Workaround for broken MinGW64 declaration. */ | 428 | /* Workaround for broken MinGW64 declaration. */ |
425 | VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx"); | 429 | VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx"); |
426 | #define RtlUnwindEx RtlUnwindEx_FIXED | 430 | #define RtlUnwindEx RtlUnwindEx_FIXED |
@@ -434,10 +438,15 @@ VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx"); | |||
434 | #define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff) | 438 | #define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff) |
435 | #define LJ_EXCODE_ERRCODE(cl) ((int)((cl) & 0xff)) | 439 | #define LJ_EXCODE_ERRCODE(cl) ((int)((cl) & 0xff)) |
436 | 440 | ||
437 | /* Win64 exception handler for interpreter frame. */ | 441 | /* Windows exception handler for interpreter frame. */ |
438 | LJ_FUNCA EXCEPTION_DISPOSITION lj_err_unwind_win64(EXCEPTION_RECORD *rec, | 442 | LJ_FUNCA EXCEPTION_DISPOSITION lj_err_unwind_win(EXCEPTION_RECORD *rec, |
439 | void *cf, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch) | 443 | void *f, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch) |
440 | { | 444 | { |
445 | #if LJ_TARGET_X64 | ||
446 | void *cf = f; | ||
447 | #else | ||
448 | void *cf = (char *)f - CFRAME_OFS_SEH; | ||
449 | #endif | ||
441 | lua_State *L = cframe_L(cf); | 450 | lua_State *L = cframe_L(cf); |
442 | int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ? | 451 | int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ? |
443 | LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN; | 452 | LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN; |
@@ -457,6 +466,7 @@ LJ_FUNCA EXCEPTION_DISPOSITION lj_err_unwind_win64(EXCEPTION_RECORD *rec, | |||
457 | /* Don't catch access violations etc. */ | 466 | /* Don't catch access violations etc. */ |
458 | return ExceptionContinueSearch; | 467 | return ExceptionContinueSearch; |
459 | } | 468 | } |
469 | #if LJ_TARGET_X64 | ||
460 | /* Unwind the stack and call all handlers for all lower C frames | 470 | /* Unwind the stack and call all handlers for all lower C frames |
461 | ** (including ourselves) again with EH_UNWINDING set. Then set | 471 | ** (including ourselves) again with EH_UNWINDING set. Then set |
462 | ** rsp = cf, rax = errcode and jump to the specified target. | 472 | ** rsp = cf, rax = errcode and jump to the specified target. |
@@ -466,6 +476,18 @@ LJ_FUNCA EXCEPTION_DISPOSITION lj_err_unwind_win64(EXCEPTION_RECORD *rec, | |||
466 | lj_vm_unwind_c_eh), | 476 | lj_vm_unwind_c_eh), |
467 | rec, (void *)(uintptr_t)errcode, ctx, dispatch->HistoryTable); | 477 | rec, (void *)(uintptr_t)errcode, ctx, dispatch->HistoryTable); |
468 | /* RtlUnwindEx should never return. */ | 478 | /* RtlUnwindEx should never return. */ |
479 | #else | ||
480 | UNUSED(ctx); | ||
481 | UNUSED(dispatch); | ||
482 | /* Call all handlers for all lower C frames (including ourselves) again | ||
483 | ** with EH_UNWINDING set. Then call the specified function, passing cf | ||
484 | ** and errcode. | ||
485 | */ | ||
486 | lj_vm_rtlunwind(cf, (void *)rec, | ||
487 | (cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? | ||
488 | (void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode); | ||
489 | /* lj_vm_rtlunwind does not return. */ | ||
490 | #endif | ||
469 | } | 491 | } |
470 | } | 492 | } |
471 | return ExceptionContinueSearch; | 493 | return ExceptionContinueSearch; |