From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id 89B6918B592; Mon, 5 Dec 2022 19:02:00 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 89B6918B592 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1670256120; bh=ahHYEDVTwxwJAroHTey0oc2EXtOdLwbj7S4CN4CZrJI=; h=Date:In-Reply-To:To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=ap5uejomAZZy2+gbdrRa++N3Ub3j4dNi9v3XgE4hTQAdhwnpISfeoYbPxHJb3MiE5 4MASSCRs4TMjqcin9tKnXufuWIy8bMTAlW8s01aMulJbAXmQrANW6OeniZooat0V8Z i/NZvHLSSN0oyRHoIBg094ITHreyYwgCjNzDzNpY= Received: from smtp50.i.mail.ru (smtp50.i.mail.ru [94.100.177.110]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id B0D12189E01 for ; Mon, 5 Dec 2022 19:01:59 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org B0D12189E01 Received: by smtp50.i.mail.ru with esmtpa (envelope-from ) id 1p2Duo-000580-Nb; Mon, 05 Dec 2022 19:01:59 +0300 Message-Id: <122D5C22-F75B-4468-97AF-D69BCB93EA3E@tarantool.org> Content-Type: multipart/alternative; boundary="Apple-Mail=_E22EC3AA-2BFB-4158-95FE-A4E25BB6057C" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3731.200.110.1.12\)) Date: Mon, 5 Dec 2022 19:01:48 +0300 In-Reply-To: <20221028092638.11506-2-max.kokryashkin@gmail.com> To: Maksim Kokryashkin References: <20221028092638.11506-1-max.kokryashkin@gmail.com> <20221028092638.11506-2-max.kokryashkin@gmail.com> X-Mailer: Apple Mail (2.3731.200.110.1.12) X-Mailru-Src: smtp X-7564579A: EEAE043A70213CC8 X-77F55803: 4F1203BC0FB41BD996A88D35BBB5D148F8A401AFE732C4A01F48F1C9F911CE43182A05F5380850404C228DA9ACA6FE27FAB340A3C9CB478ED92028FF0365143C648A8E90287160C04451B9BDF1056E15 X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D34431D0341F6B74DD39076837635233CC75A480791C72D8AF406202A0D2A78FA9FC72588DB3A8CF26C1D7E09C32AA3244CA52396D3B13E61A07959DDCD0804619D5A1673A01BA68E40927AC6DF5659F194 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojniwsktXAgUPm66G5zUQI5g== X-Mailru-Sender: 11C2EC085EDE56FA38FD4C59F7EFE407A402EA5051E5E08BCE2FF812F8362E94676C286318BA672019381EE24192DF5555834048F03EF5D4C9A814A92B2E3B1BA4250FC3964EA4964198E0F3ECE9B5443453F38A29522196 X-Mras: OK Subject: Re: [Tarantool-patches] [PATCH luajit v4 1/8] Cleanup and enable external unwinding for more platforms. X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: sergos via Tarantool-patches Reply-To: sergos Cc: tarantool-patches@dev.tarantool.org Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" --Apple-Mail=_E22EC3AA-2BFB-4158-95FE-A4E25BB6057C Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii 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: >=20 > (cherry picked from commit e131936133c58de4426c595db2341caf5a1665b5) >=20 > This commit enables external unwinding on all platforms, that > create unwind tables by default. Corresponding check is added > to the build routine. >=20 > Also, GC64 mode is now enabled on MacOS by default, as > non-GC64 mode is forbidden. >=20 > Maxim Kokryashkin: > * added the description for the patch >=20 > 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(-) >=20 > 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=3DDebug -DLUA_USE_ASSERT=3DON= -DLUA_USE_APICHECK=3DON > @@ -69,15 +69,6 @@ jobs: > - name: test > run: cmake --build . --parallel --target test >=20 > - 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() >=20 > # 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}") >=20 > +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() >=20 > 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+=3D -fno-stack-protector > endif > +ifeq (,$(findstring LJ_NO_UNWIND 1,$(TARGET_TESTARCH))) > + # Find out whether the target toolchain always generates unwind = tables. > + TARGET_TESTUNWIND=3D$(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+=3D -DLUAJIT_UNWIND_EXTERNAL > + endif > +endif > ifeq (Darwin,$(TARGET_SYS)) > ifeq (,$(MACOSX_DEPLOYMENT_TARGET)) > export MACOSX_DEPLOYMENT_TARGET=3D10.4 > @@ -328,10 +335,6 @@ ifeq (Darwin,$(TARGET_SYS)) > TARGET_XSHLDFLAGS=3D -dynamiclib -single_module -undefined = dynamic_lookup -fPIC > TARGET_DYNXLDOPTS=3D > TARGET_XSHLDFLAGS+=3D -install_name $(TARGET_DYLIBPATH) = -compatibility_version $(MAJVER).$(MINVER) -current_version = $(MAJVER).$(MINVER).$(RELVER) > - ifeq (x64,$(TARGET_LJARCH)) > - TARGET_XLDFLAGS+=3D -pagezero_size 10000 -image_base 100000000 > - TARGET_XSHLDFLAGS+=3D -image_base 7fff04c4a000 > - endif > else > ifeq (iOS,$(TARGET_SYS)) > TARGET_STRIP+=3D -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 >=20 > #elif LUAJIT_TARGET =3D=3D LUAJIT_ARCH_ARM > @@ -566,15 +558,22 @@ > #define LJ_NO_SYSTEM 1 > #endif >=20 > -#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 >=20 > -#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 >=20 > +#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=3D-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=3D-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. > */ >=20 > -#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 = ------------------------------------------------------ */ >=20 > /* Error message strings. */ > @@ -183,7 +195,125 @@ static void *err_unwind(lua_State *L, void = *stopcf, int errcode) >=20 > /* -- External frame unwinding = -------------------------------------------- */ >=20 > -#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=3D99 */ > +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) <=3D 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 =3D (char *)f - CFRAME_OFS_SEH; > +#else > + void *cf =3D f; > +#endif > + lua_State *L =3D cframe_L(cf); > + int errcode =3D 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 =3D err_unwind(L, cf, 0); > + if (cf2) { /* We catch it, so start unwinding the upper frames. = */ > + if (rec->ExceptionCode =3D=3D LJ_MSVC_EXCODE || > + rec->ExceptionCode =3D=3D 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 !=3D 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 =3D cf, result =3D errcode and jump to the = specified target. > + */ > + RtlUnwindEx(cf, (void *)((cframe_unwind_ff(cf2) && errcode !=3D = 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__)) >=20 > /* > ** 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 !=3D 1) > return _URC_FATAL_PHASE1_ERROR; > - UNUSED(uexclass); > cf =3D (void *)_Unwind_GetCFA(ctx); > L =3D 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 =3D LJ_UEXCLASS_MAKE(errcode); > - static_uex.excleanup =3D NULL; > - _Unwind_RaiseException(&static_uex); > -} > #endif >=20 > #else /* LJ_TARGET_ARM */ > @@ -373,132 +497,22 @@ LJ_FUNCA int lj_err_unwind_arm(int state, = _Unwind_Control_Block *ucb, >=20 > #if LJ_UNWIND_EXT > static __thread _Unwind_Control_Block static_uex; > +#endif > +#endif /* LJ_TARGET_ARM */ >=20 > -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 =3D LJ_UEXCLASS_MAKE(errcode); > _Unwind_RaiseException(&static_uex); > } > #endif >=20 > -#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=3D99 */ > -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) <=3D 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 =3D f; > -#else > - void *cf =3D (char *)f - CFRAME_OFS_SEH; > -#endif > - lua_State *L =3D cframe_L(cf); > - int errcode =3D 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 =3D err_unwind(L, cf, 0); > - if (cf2) { /* We catch it, so start unwinding the upper frames. = */ > - if (rec->ExceptionCode =3D=3D LJ_MSVC_EXCODE || > - rec->ExceptionCode =3D=3D 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 =3D cf, rax =3D errcode and jump to the specified = target. > - */ > - RtlUnwindEx(cf, (void *)((cframe_unwind_ff(cf2) && errcode !=3D = 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 !=3D 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 >=20 > /* -- Error handling = ------------------------------------------------------ */ > @@ -508,22 +522,23 @@ LJ_NOINLINE void LJ_FASTCALL = lj_err_throw(lua_State *L, int errcode) > { > global_State *g =3D G(L); > lj_trace_abort(g); > - setmref(g->jit_base, NULL); > L->status =3D 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 =3D err_unwind(L, NULL, errcode); > if (cframe_unwind_ff(cf)) > --=20 > 2.37.0 (Apple Git-136) >=20 --Apple-Mail=_E22EC3AA-2BFB-4158-95FE-A4E25BB6057C Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=us-ascii
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 = <max.kokryashkin@gmail.com> 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 =             &n= bsp;       |   3 +
= cmake/SetTargetFlags.cmake =         |  22 +-
= doc/extensions.html =             &n= bsp;  |  22 +-
src/Makefile.original =             &n= bsp;|  11 +-
src/lj_arch.h =             &n= bsp;        |  27 ++-
= src/lj_err.c =             &n= bsp;         | 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
=             CM= AKEFLAGS: -DCMAKE_BUILD_TYPE=3DDebug -DLUA_USE_ASSERT=3DON = -DLUA_USE_APICHECK=3DON
@@ -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 <mmap> 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:
<td = class=3D"excinterop">Interoperability</td>
</tr>
= <tr class=3D"odd separate">
-<td = class=3D"excplatform">POSIX/x64, DWARF2 = unwinding</td>
-<td class=3D"exccompiler">GCC 4.3+, = Clang</td>
+<td class=3D"excplatform">External frame = unwinding</td>
+<td class=3D"exccompiler">GCC, Clang, = MSVC</td>
<td class=3D"excinterop"><b style=3D"color: = #00a000;">Full</b></td>
</tr>
<tr = class=3D"even">
-<td class=3D"excplatform">ARM = <tt>-DLUAJIT_UNWIND_EXTERNAL</tt></td>
-<td = class=3D"exccompiler">GCC, Clang</td>
-<td = class=3D"excinterop"><b style=3D"color: = #00a000;">Full</b></td>
-</tr>
-<tr = class=3D"odd">
-<td class=3D"excplatform">Other platforms, = DWARF2 unwinding</td>
+<td class=3D"excplatform">Internal = frame unwinding + DWARF2</td>
<td = class=3D"exccompiler">GCC, Clang</td>
<td = class=3D"excinterop"><b style=3D"color: = #c06000;">Limited</b></td>
</tr>
-<tr = class=3D"even">
-<td = class=3D"excplatform">Windows/x64</td>
-<td = class=3D"exccompiler">MSVC or WinSDK</td>
-<td = class=3D"excinterop"><b style=3D"color: = #00a000;">Full</b></td>
-</tr>
<tr = class=3D"odd">
-<td = class=3D"excplatform">Windows/x86</td>
-<td = class=3D"exccompiler">Any</td>
-<td = class=3D"excinterop"><b style=3D"color: = #00a000;">Full</b></td>
+<td = class=3D"excplatform">Windows 64 bit</td>
+<td = class=3D"exccompiler">non-MSVC</td>
+<td = class=3D"excinterop"><b style=3D"color: = #c06000;">Limited</b></td>
</tr>
<tr = class=3D"even">
<td class=3D"excplatform">Other = platforms</td>
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+=3D -fno-stack-protector
endif
+ifeq = (,$(findstring LJ_NO_UNWIND 1,$(TARGET_TESTARCH)))
+  # Find out = whether the target toolchain always generates unwind tables.
+ =  TARGET_TESTUNWIND=3D$(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+=3D = -DLUAJIT_UNWIND_EXTERNAL
+  endif
+endif
ifeq = (Darwin,$(TARGET_SYS))
  ifeq = (,$(MACOSX_DEPLOYMENT_TARGET))
    export = MACOSX_DEPLOYMENT_TARGET=3D10.4
@@ -328,10 +335,6 @@ ifeq = (Darwin,$(TARGET_SYS))
  TARGET_XSHLDFLAGS=3D -dynamiclib = -single_module -undefined dynamic_lookup -fPIC
=   TARGET_DYNXLDOPTS=3D
  TARGET_XSHLDFLAGS+=3D = -install_name $(TARGET_DYLIBPATH) -compatibility_version = $(MAJVER).$(MINVER) -current_version $(MAJVER).$(MINVER).$(RELVER)
- =  ifeq (x64,$(TARGET_LJARCH))
- =    TARGET_XLDFLAGS+=3D -pagezero_size 10000 -image_base = 100000000
-    TARGET_XSHLDFLAGS+=3D -image_base = 7fff04c4a000
-  endif
else
ifeq (iOS,$(TARGET_SYS))
=   TARGET_STRIP+=3D -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 =3D=3D = 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=3D-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=3D-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 = <windows.h>
+
+#if LJ_TARGET_X86
+typedef void = *UndocumentedDispatcherContext;  /* Unused on x86. = */
+#else
+/* Taken from: http://www.nynaeve.net/?p=3D99 = */
+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) <=3D 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 =3D (char *)f - = CFRAME_OFS_SEH;
+#else
+  void *cf =3D f;
+#endif
+ =  lua_State *L =3D cframe_L(cf);
+  int errcode =3D = 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 =3D err_unwind(L, cf, = 0);
+    if (cf2) {  /* We catch it, so start = unwinding the upper frames. */
+      if = (rec->ExceptionCode =3D=3D LJ_MSVC_EXCODE ||
+ =  rec->ExceptionCode =3D=3D 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 !=3D 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 =3D cf, result =3D errcode and jump to the specified = target.
+      */
+ =      RtlUnwindEx(cf, (void = *)((cframe_unwind_ff(cf2) && errcode !=3D 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 !=3D 1)
    return = _URC_FATAL_PHASE1_ERROR;
-  UNUSED(uexclass);
  cf = =3D (void *)_Unwind_GetCFA(ctx);
  L =3D 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 =3D LJ_UEXCLASS_MAKE(errcode);
- =  static_uex.excleanup =3D 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 =3D = 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 = <windows.h>
-
-#if LJ_TARGET_X64
-/* Taken from: = http://www.nynaeve.net/?p=3D99 */
-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) <=3D 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 =3D f;
-#else
-  void *cf =3D= (char *)f - CFRAME_OFS_SEH;
-#endif
-  lua_State *L =3D = cframe_L(cf);
-  int errcode =3D = 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 =3D err_unwind(L, cf, = 0);
-    if (cf2) {  /* We catch it, so start = unwinding the upper frames. */
-      if = (rec->ExceptionCode =3D=3D LJ_MSVC_EXCODE ||
- =  rec->ExceptionCode =3D=3D 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 =3D = cf, rax =3D errcode and jump to the specified target.
- =      */
- =      RtlUnwindEx(cf, (void = *)((cframe_unwind_ff(cf2) && errcode !=3D 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 !=3D 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 =3D G(L);
=   lj_trace_abort(g);
-  setmref(g->jit_base, = NULL);
  L->status =3D 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 =3D err_unwind(L, = NULL, errcode);
    if = (cframe_unwind_ff(cf))
--
2.37.0 (Apple = Git-136)


= --Apple-Mail=_E22EC3AA-2BFB-4158-95FE-A4E25BB6057C--