Hi! Thanks for the patch, LGTM as part of original [PATCH luajit 1/6] Cleanup and enable external unwinding for more platforms. Sergos. > On 28 Oct 2022, at 12:26, Maksim Kokryashkin wrote: > > (cherry picked from commit e131936133c58de4426c595db2341caf5a1665b5) > > This commit enables external unwinding on all platforms, that > create unwind tables by default. Corresponding check is added > to the build routine. > > Also, GC64 mode is now enabled on MacOS by default, as > non-GC64 mode is forbidden. > > Maxim Kokryashkin: > * added the description for the patch > > Needed for tarantool/tarantool#6096 > Part of tarantool/tarantool#7230 > --- > .github/workflows/macos-x86_64.yml | 20 +- > CMakeLists.txt | 3 + > cmake/SetTargetFlags.cmake | 22 +- > doc/extensions.html | 22 +- > src/Makefile.original | 11 +- > src/lj_arch.h | 27 ++- > src/lj_err.c | 321 +++++++++++++++-------------- > 7 files changed, 214 insertions(+), 212 deletions(-) > > diff --git a/.github/workflows/macos-x86_64.yml b/.github/workflows/macos-x86_64.yml > index 840806e3..dafd1796 100644 > --- a/.github/workflows/macos-x86_64.yml > +++ b/.github/workflows/macos-x86_64.yml > @@ -35,7 +35,7 @@ jobs: > fail-fast: false > matrix: > BUILDTYPE: [Debug, Release] > - GC64: [ON, OFF] > + GC64: ON > include: > - BUILDTYPE: Debug > CMAKEFLAGS: -DCMAKE_BUILD_TYPE=Debug -DLUA_USE_ASSERT=ON -DLUA_USE_APICHECK=ON > @@ -69,15 +69,6 @@ jobs: > - name: test > run: cmake --build . --parallel --target test > > - test-tarantool-debug-wo-GC64: > - name: Tarantool Debug GC64:OFF > - needs: test-luajit > - uses: tarantool/tarantool/.github/workflows/luajit-integration.yml@master > - with: > - GC64: OFF > - buildtype: Debug > - host: macos-11 > - revision: ${{ github.sha }} > test-tarantool-debug-w-GC64: > name: Tarantool Debug GC64:ON > needs: test-luajit > @@ -87,15 +78,6 @@ jobs: > buildtype: Debug > host: macos-11 > revision: ${{ github.sha }} > - test-tarantool-release-wo-GC64: > - name: Tarantool Release GC64:OFF > - needs: test-luajit > - uses: tarantool/tarantool/.github/workflows/luajit-integration.yml@master > - with: > - GC64: OFF > - buildtype: RelWithDebInfo > - host: macos-11 > - revision: ${{ github.sha }} > test-tarantool-release-w-GC64: > name: Tarantool Release GC64:ON > needs: test-luajit > diff --git a/CMakeLists.txt b/CMakeLists.txt > index 8b49f9d7..c4f3ef62 100644 > --- a/CMakeLists.txt > +++ b/CMakeLists.txt > @@ -176,6 +176,9 @@ endif() > > # Enable GC64 mode for x64. > option(LUAJIT_ENABLE_GC64 "GC64 mode for x64" OFF) > +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") > + set(LUAJIT_ENABLE_GC64 ON) > +endif() > if(LUAJIT_ENABLE_GC64) > AppendFlags(TARGET_C_FLAGS -DLUAJIT_ENABLE_GC64) > endif() > diff --git a/cmake/SetTargetFlags.cmake b/cmake/SetTargetFlags.cmake > index b544d2ac..36896aff 100644 > --- a/cmake/SetTargetFlags.cmake > +++ b/cmake/SetTargetFlags.cmake > @@ -15,6 +15,22 @@ endif() > LuaJITTestArch(TESTARCH "${TARGET_C_FLAGS}") > LuaJITArch(LUAJIT_ARCH "${TESTARCH}") > > +string(FIND ${TARGET_C_FLAGS} "LJ_NO_UNWIND 1" UNWIND_POS) > +if(UNWIND_POS EQUAL -1) > + execute_process( > + COMMAND bash -c "exec 2>/dev/null; echo 'extern void b(void);int a(void){b();return 0;}' | ${CMAKE_C_COMPILER} -c -x c - -o tmpunwind.o && grep -qa -e eh_frame -e __unwind_info tmpunwind.o && echo E; rm -f tmpunwind.o" > + WORKING_DIRECTORY ${LUAJIT_SOURCE_DIR} > + OUTPUT_VARIABLE TESTUNWIND > + RESULT_VARIABLE TESTUNWIND_RC > + ) > + if(TESTUNWIND_RC EQUAL 0) > + string(FIND "${TESTUNWIND}" "E" UNW_TEST_POS) > + if(NOT UNW_TEST_POS EQUAL -1) > + AppendFlags(TARGET_C_FLAGS -DLUAJIT_UNWIND_EXTERNAL) > + endif() > + endif() > +endif() > + > # Target-specific compiler options. > # > # x86/x64 only: For GCC 4.2 or higher and if you don't intend to > @@ -25,12 +41,6 @@ if(LUAJIT_ARCH STREQUAL "x86") > endif() > > if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") > - if(LUAJIT_ARCH STREQUAL "x64") > - # XXX: Set -pagezero_size to hint when allocating 32 > - # bit memory on OSX/x64, otherwise the lower 4GB are blocked. > - AppendFlags(TARGET_BIN_FLAGS -pagezero_size 10000 -image_base 100000000) > - AppendFlags(TARGET_SHARED_FLAGS -image_base 7fff04c4a000) > - endif() > AppendFlags(TARGET_SHARED_FLAGS -single_module -undefined dynamic_lookup) > else() # Linux and FreeBSD. > AppendFlags(TARGET_BIN_FLAGS -Wl,-E) > diff --git a/doc/extensions.html b/doc/extensions.html > index e0f136e2..777e9928 100644 > --- a/doc/extensions.html > +++ b/doc/extensions.html > @@ -395,29 +395,19 @@ the toolchain used to compile LuaJIT: > Interoperability > > > -POSIX/x64, DWARF2 unwinding > -GCC 4.3+, Clang > +External frame unwinding > +GCC, Clang, MSVC > Full > > > -ARM -DLUAJIT_UNWIND_EXTERNAL > -GCC, Clang > -Full > - > - > -Other platforms, DWARF2 unwinding > +Internal frame unwinding + DWARF2 > GCC, Clang > Limited > > - > -Windows/x64 > -MSVC or WinSDK > -Full > - > > -Windows/x86 > -Any > -Full > +Windows 64 bit > +non-MSVC > +Limited > > > Other platforms > diff --git a/src/Makefile.original b/src/Makefile.original > index dd1c6a76..c9609700 100644 > --- a/src/Makefile.original > +++ b/src/Makefile.original > @@ -320,6 +320,13 @@ else > ifeq (,$(shell $(TARGET_CC) -o /dev/null -c -x c /dev/null -fno-stack-protector 2>/dev/null || echo 1)) > TARGET_XCFLAGS+= -fno-stack-protector > endif > +ifeq (,$(findstring LJ_NO_UNWIND 1,$(TARGET_TESTARCH))) > + # Find out whether the target toolchain always generates unwind tables. > + TARGET_TESTUNWIND=$(shell exec 2>/dev/null; echo 'extern void b(void);int a(void){b();return 0;}' | $(TARGET_CC) -c -x c - -o tmpunwind.o && grep -qa -e eh_frame -e __unwind_info tmpunwind.o && echo E; rm -f tmpunwind.o) > + ifneq (,$(findstring E,$(TARGET_TESTUNWIND))) > + TARGET_XCFLAGS+= -DLUAJIT_UNWIND_EXTERNAL > + endif > +endif > ifeq (Darwin,$(TARGET_SYS)) > ifeq (,$(MACOSX_DEPLOYMENT_TARGET)) > export MACOSX_DEPLOYMENT_TARGET=10.4 > @@ -328,10 +335,6 @@ ifeq (Darwin,$(TARGET_SYS)) > TARGET_XSHLDFLAGS= -dynamiclib -single_module -undefined dynamic_lookup -fPIC > TARGET_DYNXLDOPTS= > TARGET_XSHLDFLAGS+= -install_name $(TARGET_DYLIBPATH) -compatibility_version $(MAJVER).$(MINVER) -current_version $(MAJVER).$(MINVER).$(RELVER) > - ifeq (x64,$(TARGET_LJARCH)) > - TARGET_XLDFLAGS+= -pagezero_size 10000 -image_base 100000000 > - TARGET_XSHLDFLAGS+= -image_base 7fff04c4a000 > - endif > else > ifeq (iOS,$(TARGET_SYS)) > TARGET_STRIP+= -x > diff --git a/src/lj_arch.h b/src/lj_arch.h > index 40129d9e..730be5bf 100644 > --- a/src/lj_arch.h > +++ b/src/lj_arch.h > @@ -152,11 +152,6 @@ > #define LJ_ARCH_NAME "x86" > #define LJ_ARCH_BITS 32 > #define LJ_ARCH_ENDIAN LUAJIT_LE > -#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN > -#define LJ_ABI_WIN 1 > -#else > -#define LJ_ABI_WIN 0 > -#endif > #define LJ_TARGET_X86 1 > #define LJ_TARGET_X86ORX64 1 > #define LJ_TARGET_EHRETREG 0 > @@ -170,11 +165,6 @@ > #define LJ_ARCH_NAME "x64" > #define LJ_ARCH_BITS 64 > #define LJ_ARCH_ENDIAN LUAJIT_LE > -#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN > -#define LJ_ABI_WIN 1 > -#else > -#define LJ_ABI_WIN 0 > -#endif > #define LJ_TARGET_X64 1 > #define LJ_TARGET_X86ORX64 1 > #define LJ_TARGET_EHRETREG 0 > @@ -185,6 +175,8 @@ > #define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE_DUAL > #ifdef LUAJIT_ENABLE_GC64 > #define LJ_TARGET_GC64 1 > +#elif LJ_TARGET_OSX > +#error "macOS requires GC64 -- don't disable it" > #endif > > #elif LUAJIT_TARGET == LUAJIT_ARCH_ARM > @@ -566,15 +558,22 @@ > #define LJ_NO_SYSTEM 1 > #endif > > -#if !defined(LUAJIT_NO_UNWIND) && __GNU_COMPACT_EH__ > -/* NYI: no support for compact unwind specification, yet. */ > -#define LUAJIT_NO_UNWIND 1 > +#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN > +#define LJ_ABI_WIN 1 > +#else > +#define LJ_ABI_WIN 0 > #endif > > -#if defined(LUAJIT_NO_UNWIND) || defined(__symbian__) || LJ_TARGET_IOS || LJ_TARGET_PS3 || LJ_TARGET_PS4 > +#if defined(LUAJIT_NO_UNWIND) || __GNU_COMPACT_EH__ || defined(__symbian__) || LJ_TARGET_IOS || LJ_TARGET_PS3 || LJ_TARGET_PS4 > #define LJ_NO_UNWIND 1 > #endif > > +#if !LJ_NO_UNWIND && !defined(LUAJIT_UNWIND_INTERNAL) && (LJ_ABI_WIN || (defined(LUAJIT_UNWIND_EXTERNAL) && (defined(__GNUC__) || defined(__clang__)))) > +#define LJ_UNWIND_EXT 1 > +#else > +#define LJ_UNWIND_EXT 0 > +#endif > + > /* Compatibility with Lua 5.1 vs. 5.2. */ > #ifdef LUAJIT_ENABLE_LUA52COMPAT > #define LJ_52 1 > diff --git a/src/lj_err.c b/src/lj_err.c > index c310daf6..298e5434 100644 > --- a/src/lj_err.c > +++ b/src/lj_err.c > @@ -29,12 +29,18 @@ > ** Pros and Cons: > ** > ** - EXT requires unwind tables for *all* functions on the C stack between > -** the pcall/catch and the error/throw. This is the default on x64, > -** but needs to be manually enabled on x86/PPC for non-C++ code. > +** the pcall/catch and the error/throw. C modules used by Lua code can > +** throw errors, so these need to have unwind tables, too. Transitively > +** this applies to all system libraries used by C modules -- at least > +** when they have callbacks which may throw an error. > ** > -** - INT is faster when actually throwing errors (but this happens rarely). > +** - INT is faster when actually throwing errors, but this happens rarely. > ** Setting up error handlers is zero-cost in any case. > ** > +** - INT needs to save *all* callee-saved registers when entering the > +** interpreter. EXT only needs to save those actually used inside the > +** interpreter. JIT-compiled code may need to save some more. > +** > ** - EXT provides full interoperability with C++ exceptions. You can throw > ** Lua errors or C++ exceptions through a mix of Lua frames and C++ frames. > ** C++ destructors are called as needed. C++ exceptions caught by pcall > @@ -46,27 +52,33 @@ > ** the wrapper function feature. Lua errors thrown through C++ frames > ** cannot be caught by C++ code and C++ destructors are not run. > ** > -** EXT is the default on x64 systems and on Windows, INT is the default on all > -** other systems. > +** EXT is the default on all systems where the toolchain produces unwind > +** tables by default (*). This is hard-coded and/or detected in src/Makefile. > +** You can thwart the detection with: TARGET_XCFLAGS=-DLUAJIT_UNWIND_INTERNAL > +** > +** INT is the default on all other systems. > +** > +** EXT can be manually enabled for toolchains that are able to produce > +** conforming unwind tables: > +** "TARGET_XCFLAGS=-funwind-tables -DLUAJIT_UNWIND_EXTERNAL" > +** As explained above, *all* C code used directly or indirectly by LuaJIT > +** must be compiled with -funwind-tables (or -fexceptions). C++ code must > +** *not* be compiled with -fno-exceptions. > +** > +** If you're unsure whether error handling inside the VM works correctly, > +** try running this and check whether it prints "OK": > ** > -** EXT can be manually enabled on POSIX systems using GCC and DWARF2 stack > -** unwinding with -DLUAJIT_UNWIND_EXTERNAL. *All* C code must be compiled > -** with -funwind-tables (or -fexceptions). This includes LuaJIT itself (set > -** TARGET_CFLAGS), all of your C/Lua binding code, all loadable C modules > -** and all C libraries that have callbacks which may be used to call back > -** into Lua. C++ code must *not* be compiled with -fno-exceptions. > +** luajit -e "print(select(2, load('OK')):match('OK'))" > ** > -** EXT is mandatory on WIN64 since the calling convention has an abundance > -** of callee-saved registers (rbx, rbp, rsi, rdi, r12-r15, xmm6-xmm15). > -** The POSIX/x64 interpreter only saves r12/r13 for INT (e.g. PS4). > +** (*) Originally, toolchains only generated unwind tables for C++ code. For > +** interoperability reasons, this can be manually enabled for plain C code, > +** too (with -funwind-tables). With the introduction of the x64 architecture, > +** the corresponding POSIX and Windows ABIs mandated unwind tables for all > +** code. Over the following years most desktop and server platforms have > +** enabled unwind tables by default on all architectures. OTOH mobile and > +** embedded platforms do not consistently mandate unwind tables. > */ > > -#if defined(__GNUC__) && (LJ_TARGET_X64 || defined(LUAJIT_UNWIND_EXTERNAL)) && !LJ_NO_UNWIND > -#define LJ_UNWIND_EXT 1 > -#elif LJ_TARGET_WINDOWS > -#define LJ_UNWIND_EXT 1 > -#endif > - > /* -- Error messages ------------------------------------------------------ */ > > /* Error message strings. */ > @@ -183,7 +195,125 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode) > > /* -- External frame unwinding -------------------------------------------- */ > > -#if defined(__GNUC__) && !LJ_NO_UNWIND && !LJ_ABI_WIN > +#if LJ_ABI_WIN > + > +/* > +** Someone in Redmond owes me several days of my life. A lot of this is > +** undocumented or just plain wrong on MSDN. Some of it can be gathered > +** from 3rd party docs or must be found by trial-and-error. They really > +** don't want you to write your own language-specific exception handler > +** or to interact gracefully with MSVC. :-( > +** > +** Apparently MSVC doesn't call C++ destructors for foreign exceptions > +** unless you compile your C++ code with /EHa. Unfortunately this means > +** catch (...) also catches things like access violations. The use of > +** _set_se_translator doesn't really help, because it requires /EHa, too. > +*/ > + > +#define WIN32_LEAN_AND_MEAN > +#include > + > +#if LJ_TARGET_X86 > +typedef void *UndocumentedDispatcherContext; /* Unused on x86. */ > +#else > +/* Taken from: http://www.nynaeve.net/?p=99 */ > +typedef struct UndocumentedDispatcherContext { > + ULONG64 ControlPc; > + ULONG64 ImageBase; > + PRUNTIME_FUNCTION FunctionEntry; > + ULONG64 EstablisherFrame; > + ULONG64 TargetIp; > + PCONTEXT ContextRecord; > + void (*LanguageHandler)(void); > + PVOID HandlerData; > + PUNWIND_HISTORY_TABLE HistoryTable; > + ULONG ScopeIndex; > + ULONG Fill0; > +} UndocumentedDispatcherContext; > +#endif > + > +/* Another wild guess. */ > +extern void __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow); > + > +#if LJ_TARGET_X64 && defined(MINGW_SDK_INIT) > +/* Workaround for broken MinGW64 declaration. */ > +VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx"); > +#define RtlUnwindEx RtlUnwindEx_FIXED > +#endif > + > +#define LJ_MSVC_EXCODE ((DWORD)0xe06d7363) > +#define LJ_GCC_EXCODE ((DWORD)0x20474343) > + > +#define LJ_EXCODE ((DWORD)0xe24c4a00) > +#define LJ_EXCODE_MAKE(c) (LJ_EXCODE | (DWORD)(c)) > +#define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff) > +#define LJ_EXCODE_ERRCODE(cl) ((int)((cl) & 0xff)) > + > +/* Windows exception handler for interpreter frame. */ > +LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec, > + void *f, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch) > +{ > +#if LJ_TARGET_X86 > + void *cf = (char *)f - CFRAME_OFS_SEH; > +#else > + void *cf = f; > +#endif > + lua_State *L = cframe_L(cf); > + int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ? > + LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN; > + if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */ > + /* Unwind internal frames. */ > + err_unwind(L, cf, errcode); > + } else { > + void *cf2 = err_unwind(L, cf, 0); > + if (cf2) { /* We catch it, so start unwinding the upper frames. */ > + if (rec->ExceptionCode == LJ_MSVC_EXCODE || > + rec->ExceptionCode == LJ_GCC_EXCODE) { > +#if !LJ_TARGET_CYGWIN > + __DestructExceptionObject(rec, 1); > +#endif > + setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); > + } else if (!LJ_EXCODE_CHECK(rec->ExceptionCode)) { > + /* Don't catch access violations etc. */ > + return 1; /* ExceptionContinueSearch */ > + } > +#if LJ_TARGET_X86 > + UNUSED(ctx); > + UNUSED(dispatch); > + /* Call all handlers for all lower C frames (including ourselves) again > + ** with EH_UNWINDING set. Then call the specified function, passing cf > + ** and errcode. > + */ > + lj_vm_rtlunwind(cf, (void *)rec, > + (cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? > + (void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode); > + /* lj_vm_rtlunwind does not return. */ > +#else > + /* Unwind the stack and call all handlers for all lower C frames > + ** (including ourselves) again with EH_UNWINDING set. Then set > + ** stack pointer = cf, result = errcode and jump to the specified target. > + */ > + RtlUnwindEx(cf, (void *)((cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? > + lj_vm_unwind_ff_eh : > + lj_vm_unwind_c_eh), > + rec, (void *)(uintptr_t)errcode, ctx, dispatch->HistoryTable); > + /* RtlUnwindEx should never return. */ > +#endif > + } > + } > + return 1; /* ExceptionContinueSearch */ > +} > + > +/* Raise Windows exception. */ > +static void err_raise_ext(global_State *g, int errcode) > +{ > +#if LJ_HASJIT > + setmref(g->jit_base, NULL); > +#endif > + RaiseException(LJ_EXCODE_MAKE(errcode), 1 /* EH_NONCONTINUABLE */, 0, NULL); > +} > + > +#elif !LJ_NO_UNWIND && (defined(__GNUC__) || defined(__clang__)) > > /* > ** We have to use our own definitions instead of the mandatory (!) unwind.h, > @@ -232,7 +362,6 @@ LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions, > lua_State *L; > if (version != 1) > return _URC_FATAL_PHASE1_ERROR; > - UNUSED(uexclass); > cf = (void *)_Unwind_GetCFA(ctx); > L = cframe_L(cf); > if ((actions & _UA_SEARCH_PHASE)) { > @@ -280,6 +409,9 @@ LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions, > ** it on non-x64 because the interpreter restores all callee-saved regs. > */ > lj_err_throw(L, errcode); > +#if LJ_TARGET_X64 > +#error "Broken build system -- only use the provided Makefiles!" > +#endif > #endif > } > return _URC_CONTINUE_UNWIND; > @@ -292,14 +424,6 @@ static _Unwind_Exception static_uex; > #else > static __thread _Unwind_Exception static_uex; > #endif > - > -/* Raise DWARF2 exception. */ > -static void err_raise_ext(int errcode) > -{ > - static_uex.exclass = LJ_UEXCLASS_MAKE(errcode); > - static_uex.excleanup = NULL; > - _Unwind_RaiseException(&static_uex); > -} > #endif > > #else /* LJ_TARGET_ARM */ > @@ -373,132 +497,22 @@ LJ_FUNCA int lj_err_unwind_arm(int state, _Unwind_Control_Block *ucb, > > #if LJ_UNWIND_EXT > static __thread _Unwind_Control_Block static_uex; > +#endif > +#endif /* LJ_TARGET_ARM */ > > -static void err_raise_ext(int errcode) > +#if LJ_UNWIND_EXT > +/* Raise external exception. */ > +static void err_raise_ext(global_State *g, int errcode) > { > +#if LJ_HASJIT > + setmref(g->jit_base, NULL); > +#endif > memset(&static_uex, 0, sizeof(static_uex)); > static_uex.exclass = LJ_UEXCLASS_MAKE(errcode); > _Unwind_RaiseException(&static_uex); > } > #endif > > -#endif /* LJ_TARGET_ARM */ > - > -#elif LJ_ABI_WIN > - > -/* > -** Someone in Redmond owes me several days of my life. A lot of this is > -** undocumented or just plain wrong on MSDN. Some of it can be gathered > -** from 3rd party docs or must be found by trial-and-error. They really > -** don't want you to write your own language-specific exception handler > -** or to interact gracefully with MSVC. :-( > -** > -** Apparently MSVC doesn't call C++ destructors for foreign exceptions > -** unless you compile your C++ code with /EHa. Unfortunately this means > -** catch (...) also catches things like access violations. The use of > -** _set_se_translator doesn't really help, because it requires /EHa, too. > -*/ > - > -#define WIN32_LEAN_AND_MEAN > -#include > - > -#if LJ_TARGET_X64 > -/* Taken from: http://www.nynaeve.net/?p=99 */ > -typedef struct UndocumentedDispatcherContext { > - ULONG64 ControlPc; > - ULONG64 ImageBase; > - PRUNTIME_FUNCTION FunctionEntry; > - ULONG64 EstablisherFrame; > - ULONG64 TargetIp; > - PCONTEXT ContextRecord; > - void (*LanguageHandler)(void); > - PVOID HandlerData; > - PUNWIND_HISTORY_TABLE HistoryTable; > - ULONG ScopeIndex; > - ULONG Fill0; > -} UndocumentedDispatcherContext; > -#else > -typedef void *UndocumentedDispatcherContext; > -#endif > - > -/* Another wild guess. */ > -extern void __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow); > - > -#if LJ_TARGET_X64 && defined(MINGW_SDK_INIT) > -/* Workaround for broken MinGW64 declaration. */ > -VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx"); > -#define RtlUnwindEx RtlUnwindEx_FIXED > -#endif > - > -#define LJ_MSVC_EXCODE ((DWORD)0xe06d7363) > -#define LJ_GCC_EXCODE ((DWORD)0x20474343) > - > -#define LJ_EXCODE ((DWORD)0xe24c4a00) > -#define LJ_EXCODE_MAKE(c) (LJ_EXCODE | (DWORD)(c)) > -#define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff) > -#define LJ_EXCODE_ERRCODE(cl) ((int)((cl) & 0xff)) > - > -/* Windows exception handler for interpreter frame. */ > -LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec, > - void *f, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch) > -{ > -#if LJ_TARGET_X64 > - void *cf = f; > -#else > - void *cf = (char *)f - CFRAME_OFS_SEH; > -#endif > - lua_State *L = cframe_L(cf); > - int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ? > - LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN; > - if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */ > - /* Unwind internal frames. */ > - err_unwind(L, cf, errcode); > - } else { > - void *cf2 = err_unwind(L, cf, 0); > - if (cf2) { /* We catch it, so start unwinding the upper frames. */ > - if (rec->ExceptionCode == LJ_MSVC_EXCODE || > - rec->ExceptionCode == LJ_GCC_EXCODE) { > -#if LJ_TARGET_WINDOWS > - __DestructExceptionObject(rec, 1); > -#endif > - setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); > - } else if (!LJ_EXCODE_CHECK(rec->ExceptionCode)) { > - /* Don't catch access violations etc. */ > - return 1; /* ExceptionContinueSearch */ > - } > -#if LJ_TARGET_X64 > - /* Unwind the stack and call all handlers for all lower C frames > - ** (including ourselves) again with EH_UNWINDING set. Then set > - ** rsp = cf, rax = errcode and jump to the specified target. > - */ > - RtlUnwindEx(cf, (void *)((cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? > - lj_vm_unwind_ff_eh : > - lj_vm_unwind_c_eh), > - rec, (void *)(uintptr_t)errcode, ctx, dispatch->HistoryTable); > - /* RtlUnwindEx should never return. */ > -#else > - UNUSED(ctx); > - UNUSED(dispatch); > - /* Call all handlers for all lower C frames (including ourselves) again > - ** with EH_UNWINDING set. Then call the specified function, passing cf > - ** and errcode. > - */ > - lj_vm_rtlunwind(cf, (void *)rec, > - (cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? > - (void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode); > - /* lj_vm_rtlunwind does not return. */ > -#endif > - } > - } > - return 1; /* ExceptionContinueSearch */ > -} > - > -/* Raise Windows exception. */ > -static void err_raise_ext(int errcode) > -{ > - RaiseException(LJ_EXCODE_MAKE(errcode), 1 /* EH_NONCONTINUABLE */, 0, NULL); > -} > - > #endif > > /* -- Error handling ------------------------------------------------------ */ > @@ -508,22 +522,23 @@ LJ_NOINLINE void LJ_FASTCALL lj_err_throw(lua_State *L, int errcode) > { > global_State *g = G(L); > lj_trace_abort(g); > - setmref(g->jit_base, NULL); > L->status = LUA_OK; > #if LJ_UNWIND_EXT > - err_raise_ext(errcode); > + err_raise_ext(g, errcode); > /* > ** A return from this function signals a corrupt C stack that cannot be > ** unwound. We have no choice but to call the panic function and exit. > ** > ** Usually this is caused by a C function without unwind information. > - ** This should never happen on x64, but may happen if you've manually > - ** enabled LUAJIT_UNWIND_EXTERNAL and forgot to recompile *every* > - ** non-C++ file with -funwind-tables. > + ** This may happen if you've manually enabled LUAJIT_UNWIND_EXTERNAL > + ** and forgot to recompile *every* non-C++ file with -funwind-tables. > */ > if (G(L)->panic) > G(L)->panic(L); > #else > +#if LJ_HASJIT > + setmref(g->jit_base, NULL); > +#endif > { > void *cf = err_unwind(L, NULL, errcode); > if (cframe_unwind_ff(cf)) > -- > 2.37.0 (Apple Git-136) >