aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pall <mike>2021-03-23 00:22:34 +0100
committerMike Pall <mike>2021-03-23 00:22:34 +0100
commite131936133c58de4426c595db2341caf5a1665b5 (patch)
treee8659c1bbc626acde7bbcb998eac5ad93349d113
parentce9faf2e0d627aa043b84f290aebc4ef87c5a3b4 (diff)
downloadluajit-e131936133c58de4426c595db2341caf5a1665b5.tar.gz
luajit-e131936133c58de4426c595db2341caf5a1665b5.tar.bz2
luajit-e131936133c58de4426c595db2341caf5a1665b5.zip
Cleanup and enable external unwinding for more platforms.
-rw-r--r--doc/extensions.html22
-rw-r--r--src/Makefile11
-rw-r--r--src/lj_arch.h33
-rw-r--r--src/lj_err.c321
4 files changed, 197 insertions, 190 deletions
diff --git a/doc/extensions.html b/doc/extensions.html
index d0c3ca7a..be7e66d8 100644
--- a/doc/extensions.html
+++ b/doc/extensions.html
@@ -392,29 +392,19 @@ the toolchain used to compile LuaJIT:
392<td class="excinterop">Interoperability</td> 392<td class="excinterop">Interoperability</td>
393</tr> 393</tr>
394<tr class="odd separate"> 394<tr class="odd separate">
395<td class="excplatform">POSIX/x64, DWARF2 unwinding</td> 395<td class="excplatform">External frame unwinding</td>
396<td class="exccompiler">GCC 4.3+, Clang</td> 396<td class="exccompiler">GCC, Clang, MSVC</td>
397<td class="excinterop"><b style="color: #00a000;">Full</b></td> 397<td class="excinterop"><b style="color: #00a000;">Full</b></td>
398</tr> 398</tr>
399<tr class="even"> 399<tr class="even">
400<td class="excplatform">ARM <tt>-DLUAJIT_UNWIND_EXTERNAL</tt></td> 400<td class="excplatform">Internal frame unwinding + DWARF2</td>
401<td class="exccompiler">GCC, Clang</td>
402<td class="excinterop"><b style="color: #00a000;">Full</b></td>
403</tr>
404<tr class="odd">
405<td class="excplatform">Other platforms, DWARF2 unwinding</td>
406<td class="exccompiler">GCC, Clang</td> 401<td class="exccompiler">GCC, Clang</td>
407<td class="excinterop"><b style="color: #c06000;">Limited</b></td> 402<td class="excinterop"><b style="color: #c06000;">Limited</b></td>
408</tr> 403</tr>
409<tr class="even">
410<td class="excplatform">Windows/x64</td>
411<td class="exccompiler">MSVC</td>
412<td class="excinterop"><b style="color: #00a000;">Full</b></td>
413</tr>
414<tr class="odd"> 404<tr class="odd">
415<td class="excplatform">Windows/x86</td> 405<td class="excplatform">Windows 64 bit</td>
416<td class="exccompiler">Any</td> 406<td class="exccompiler">non-MSVC</td>
417<td class="excinterop"><b style="color: #00a000;">Full</b></td> 407<td class="excinterop"><b style="color: #c06000;">Limited</b></td>
418</tr> 408</tr>
419<tr class="even"> 409<tr class="even">
420<td class="excplatform">Other platforms</td> 410<td class="excplatform">Other platforms</td>
diff --git a/src/Makefile b/src/Makefile
index 2e1a2888..6f17bafd 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -314,6 +314,13 @@ else
314ifeq (,$(shell $(TARGET_CC) -o /dev/null -c -x c /dev/null -fno-stack-protector 2>/dev/null || echo 1)) 314ifeq (,$(shell $(TARGET_CC) -o /dev/null -c -x c /dev/null -fno-stack-protector 2>/dev/null || echo 1))
315 TARGET_XCFLAGS+= -fno-stack-protector 315 TARGET_XCFLAGS+= -fno-stack-protector
316endif 316endif
317ifeq (,$(findstring LJ_NO_UNWIND 1,$(TARGET_TESTARCH)))
318 # Find out whether the target toolchain always generates unwind tables.
319 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)
320 ifneq (,$(findstring E,$(TARGET_TESTUNWIND)))
321 TARGET_XCFLAGS+= -DLUAJIT_UNWIND_EXTERNAL
322 endif
323endif
317ifeq (Darwin,$(TARGET_SYS)) 324ifeq (Darwin,$(TARGET_SYS))
318 ifeq (,$(MACOSX_DEPLOYMENT_TARGET)) 325 ifeq (,$(MACOSX_DEPLOYMENT_TARGET))
319 $(error missing: export MACOSX_DEPLOYMENT_TARGET=XX.YY) 326 $(error missing: export MACOSX_DEPLOYMENT_TARGET=XX.YY)
@@ -322,10 +329,6 @@ ifeq (Darwin,$(TARGET_SYS))
322 TARGET_XSHLDFLAGS= -dynamiclib -single_module -undefined dynamic_lookup -fPIC 329 TARGET_XSHLDFLAGS= -dynamiclib -single_module -undefined dynamic_lookup -fPIC
323 TARGET_DYNXLDOPTS= 330 TARGET_DYNXLDOPTS=
324 TARGET_XSHLDFLAGS+= -install_name $(TARGET_DYLIBPATH) -compatibility_version $(MAJVER).$(MINVER) -current_version $(MAJVER).$(MINVER).$(RELVER) 331 TARGET_XSHLDFLAGS+= -install_name $(TARGET_DYLIBPATH) -compatibility_version $(MAJVER).$(MINVER) -current_version $(MAJVER).$(MINVER).$(RELVER)
325 ifeq (x64,$(TARGET_LJARCH))
326 TARGET_XLDFLAGS+= -pagezero_size 10000 -image_base 100000000
327 TARGET_XSHLDFLAGS+= -image_base 7fff04c4a000
328 endif
329else 332else
330ifeq (iOS,$(TARGET_SYS)) 333ifeq (iOS,$(TARGET_SYS))
331 TARGET_STRIP+= -x 334 TARGET_STRIP+= -x
diff --git a/src/lj_arch.h b/src/lj_arch.h
index d4fd9c9d..ac3e3753 100644
--- a/src/lj_arch.h
+++ b/src/lj_arch.h
@@ -170,11 +170,6 @@
170#define LJ_ARCH_NAME "x86" 170#define LJ_ARCH_NAME "x86"
171#define LJ_ARCH_BITS 32 171#define LJ_ARCH_BITS 32
172#define LJ_ARCH_ENDIAN LUAJIT_LE 172#define LJ_ARCH_ENDIAN LUAJIT_LE
173#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN
174#define LJ_ABI_WIN 1
175#else
176#define LJ_ABI_WIN 0
177#endif
178#define LJ_TARGET_X86 1 173#define LJ_TARGET_X86 1
179#define LJ_TARGET_X86ORX64 1 174#define LJ_TARGET_X86ORX64 1
180#define LJ_TARGET_EHRETREG 0 175#define LJ_TARGET_EHRETREG 0
@@ -188,11 +183,6 @@
188#define LJ_ARCH_NAME "x64" 183#define LJ_ARCH_NAME "x64"
189#define LJ_ARCH_BITS 64 184#define LJ_ARCH_BITS 64
190#define LJ_ARCH_ENDIAN LUAJIT_LE 185#define LJ_ARCH_ENDIAN LUAJIT_LE
191#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN
192#define LJ_ABI_WIN 1
193#else
194#define LJ_ABI_WIN 0
195#endif
196#define LJ_TARGET_X64 1 186#define LJ_TARGET_X64 1
197#define LJ_TARGET_X86ORX64 1 187#define LJ_TARGET_X86ORX64 1
198#define LJ_TARGET_EHRETREG 0 188#define LJ_TARGET_EHRETREG 0
@@ -203,6 +193,8 @@
203#define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE_DUAL 193#define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE_DUAL
204#ifndef LUAJIT_DISABLE_GC64 194#ifndef LUAJIT_DISABLE_GC64
205#define LJ_TARGET_GC64 1 195#define LJ_TARGET_GC64 1
196#elif LJ_TARGET_OSX
197#error "macOS requires GC64 -- don't disable it"
206#endif 198#endif
207 199
208#elif LUAJIT_TARGET == LUAJIT_ARCH_ARM 200#elif LUAJIT_TARGET == LUAJIT_ARCH_ARM
@@ -611,13 +603,10 @@
611#define LJ_NO_SYSTEM 1 603#define LJ_NO_SYSTEM 1
612#endif 604#endif
613 605
614#if !defined(LUAJIT_NO_UNWIND) && __GNU_COMPACT_EH__ 606#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN
615/* NYI: no support for compact unwind specification, yet. */ 607#define LJ_ABI_WIN 1
616#define LUAJIT_NO_UNWIND 1 608#else
617#endif 609#define LJ_ABI_WIN 0
618
619#if defined(LUAJIT_NO_UNWIND) || defined(__symbian__) || LJ_TARGET_IOS || LJ_TARGET_PS3 || LJ_TARGET_PS4
620#define LJ_NO_UNWIND 1
621#endif 610#endif
622 611
623#if LJ_TARGET_WINDOWS 612#if LJ_TARGET_WINDOWS
@@ -632,6 +621,16 @@ extern void *LJ_WIN_LOADLIBA(const char *path);
632#endif 621#endif
633#endif 622#endif
634 623
624#if defined(LUAJIT_NO_UNWIND) || __GNU_COMPACT_EH__ || defined(__symbian__) || LJ_TARGET_IOS || LJ_TARGET_PS3 || LJ_TARGET_PS4
625#define LJ_NO_UNWIND 1
626#endif
627
628#if !LJ_NO_UNWIND && !defined(LUAJIT_UNWIND_INTERNAL) && (LJ_ABI_WIN || (defined(LUAJIT_UNWIND_EXTERNAL) && (defined(__GNUC__) || defined(__clang__))))
629#define LJ_UNWIND_EXT 1
630#else
631#define LJ_UNWIND_EXT 0
632#endif
633
635/* Compatibility with Lua 5.1 vs. 5.2. */ 634/* Compatibility with Lua 5.1 vs. 5.2. */
636#ifdef LUAJIT_ENABLE_LUA52COMPAT 635#ifdef LUAJIT_ENABLE_LUA52COMPAT
637#define LJ_52 1 636#define LJ_52 1
diff --git a/src/lj_err.c b/src/lj_err.c
index c0bf38c2..ba0fac0a 100644
--- a/src/lj_err.c
+++ b/src/lj_err.c
@@ -29,12 +29,18 @@
29** Pros and Cons: 29** Pros and Cons:
30** 30**
31** - EXT requires unwind tables for *all* functions on the C stack between 31** - EXT requires unwind tables for *all* functions on the C stack between
32** the pcall/catch and the error/throw. This is the default on x64, 32** the pcall/catch and the error/throw. C modules used by Lua code can
33** but needs to be manually enabled on x86/PPC for non-C++ code. 33** throw errors, so these need to have unwind tables, too. Transitively
34** this applies to all system libraries used by C modules -- at least
35** when they have callbacks which may throw an error.
34** 36**
35** - INT is faster when actually throwing errors (but this happens rarely). 37** - INT is faster when actually throwing errors, but this happens rarely.
36** Setting up error handlers is zero-cost in any case. 38** Setting up error handlers is zero-cost in any case.
37** 39**
40** - INT needs to save *all* callee-saved registers when entering the
41** interpreter. EXT only needs to save those actually used inside the
42** interpreter. JIT-compiled code may need to save some more.
43**
38** - EXT provides full interoperability with C++ exceptions. You can throw 44** - EXT provides full interoperability with C++ exceptions. You can throw
39** Lua errors or C++ exceptions through a mix of Lua frames and C++ frames. 45** Lua errors or C++ exceptions through a mix of Lua frames and C++ frames.
40** C++ destructors are called as needed. C++ exceptions caught by pcall 46** C++ destructors are called as needed. C++ exceptions caught by pcall
@@ -46,27 +52,33 @@
46** the wrapper function feature. Lua errors thrown through C++ frames 52** the wrapper function feature. Lua errors thrown through C++ frames
47** cannot be caught by C++ code and C++ destructors are not run. 53** cannot be caught by C++ code and C++ destructors are not run.
48** 54**
49** EXT is the default on x64 systems and on Windows, INT is the default on all 55** EXT is the default on all systems where the toolchain produces unwind
50** other systems. 56** tables by default (*). This is hard-coded and/or detected in src/Makefile.
57** You can thwart the detection with: TARGET_XCFLAGS=-DLUAJIT_UNWIND_INTERNAL
58**
59** INT is the default on all other systems.
60**
61** EXT can be manually enabled for toolchains that are able to produce
62** conforming unwind tables:
63** "TARGET_XCFLAGS=-funwind-tables -DLUAJIT_UNWIND_EXTERNAL"
64** As explained above, *all* C code used directly or indirectly by LuaJIT
65** must be compiled with -funwind-tables (or -fexceptions). C++ code must
66** *not* be compiled with -fno-exceptions.
67**
68** If you're unsure whether error handling inside the VM works correctly,
69** try running this and check whether it prints "OK":
51** 70**
52** EXT can be manually enabled on POSIX systems using GCC and DWARF2 stack 71** luajit -e "print(select(2, load('OK')):match('OK'))"
53** unwinding with -DLUAJIT_UNWIND_EXTERNAL. *All* C code must be compiled
54** with -funwind-tables (or -fexceptions). This includes LuaJIT itself (set
55** TARGET_CFLAGS), all of your C/Lua binding code, all loadable C modules
56** and all C libraries that have callbacks which may be used to call back
57** into Lua. C++ code must *not* be compiled with -fno-exceptions.
58** 72**
59** EXT is mandatory on WIN64 since the calling convention has an abundance 73** (*) Originally, toolchains only generated unwind tables for C++ code. For
60** of callee-saved registers (rbx, rbp, rsi, rdi, r12-r15, xmm6-xmm15). 74** interoperability reasons, this can be manually enabled for plain C code,
61** The POSIX/x64 interpreter only saves r12/r13 for INT (e.g. PS4). 75** too (with -funwind-tables). With the introduction of the x64 architecture,
76** the corresponding POSIX and Windows ABIs mandated unwind tables for all
77** code. Over the following years most desktop and server platforms have
78** enabled unwind tables by default on all architectures. OTOH mobile and
79** embedded platforms do not consistently mandate unwind tables.
62*/ 80*/
63 81
64#if (defined(__GNUC__) || defined(__clang__)) && (LJ_TARGET_X64 || defined(LUAJIT_UNWIND_EXTERNAL)) && !LJ_NO_UNWIND
65#define LJ_UNWIND_EXT 1
66#elif LJ_TARGET_WINDOWS
67#define LJ_UNWIND_EXT 1
68#endif
69
70/* -- Error messages ------------------------------------------------------ */ 82/* -- Error messages ------------------------------------------------------ */
71 83
72/* Error message strings. */ 84/* Error message strings. */
@@ -184,7 +196,125 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode)
184 196
185/* -- External frame unwinding -------------------------------------------- */ 197/* -- External frame unwinding -------------------------------------------- */
186 198
187#if (defined(__GNUC__) || defined(__clang__)) && !LJ_NO_UNWIND && !LJ_ABI_WIN 199#if LJ_ABI_WIN
200
201/*
202** Someone in Redmond owes me several days of my life. A lot of this is
203** undocumented or just plain wrong on MSDN. Some of it can be gathered
204** from 3rd party docs or must be found by trial-and-error. They really
205** don't want you to write your own language-specific exception handler
206** or to interact gracefully with MSVC. :-(
207**
208** Apparently MSVC doesn't call C++ destructors for foreign exceptions
209** unless you compile your C++ code with /EHa. Unfortunately this means
210** catch (...) also catches things like access violations. The use of
211** _set_se_translator doesn't really help, because it requires /EHa, too.
212*/
213
214#define WIN32_LEAN_AND_MEAN
215#include <windows.h>
216
217#if LJ_TARGET_X86
218typedef void *UndocumentedDispatcherContext; /* Unused on x86. */
219#else
220/* Taken from: http://www.nynaeve.net/?p=99 */
221typedef struct UndocumentedDispatcherContext {
222 ULONG64 ControlPc;
223 ULONG64 ImageBase;
224 PRUNTIME_FUNCTION FunctionEntry;
225 ULONG64 EstablisherFrame;
226 ULONG64 TargetIp;
227 PCONTEXT ContextRecord;
228 void (*LanguageHandler)(void);
229 PVOID HandlerData;
230 PUNWIND_HISTORY_TABLE HistoryTable;
231 ULONG ScopeIndex;
232 ULONG Fill0;
233} UndocumentedDispatcherContext;
234#endif
235
236/* Another wild guess. */
237extern void __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow);
238
239#if LJ_TARGET_X64 && defined(MINGW_SDK_INIT)
240/* Workaround for broken MinGW64 declaration. */
241VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx");
242#define RtlUnwindEx RtlUnwindEx_FIXED
243#endif
244
245#define LJ_MSVC_EXCODE ((DWORD)0xe06d7363)
246#define LJ_GCC_EXCODE ((DWORD)0x20474343)
247
248#define LJ_EXCODE ((DWORD)0xe24c4a00)
249#define LJ_EXCODE_MAKE(c) (LJ_EXCODE | (DWORD)(c))
250#define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff)
251#define LJ_EXCODE_ERRCODE(cl) ((int)((cl) & 0xff))
252
253/* Windows exception handler for interpreter frame. */
254LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec,
255 void *f, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch)
256{
257#if LJ_TARGET_X86
258 void *cf = (char *)f - CFRAME_OFS_SEH;
259#else
260 void *cf = f;
261#endif
262 lua_State *L = cframe_L(cf);
263 int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ?
264 LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN;
265 if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */
266 /* Unwind internal frames. */
267 err_unwind(L, cf, errcode);
268 } else {
269 void *cf2 = err_unwind(L, cf, 0);
270 if (cf2) { /* We catch it, so start unwinding the upper frames. */
271 if (rec->ExceptionCode == LJ_MSVC_EXCODE ||
272 rec->ExceptionCode == LJ_GCC_EXCODE) {
273#if !LJ_TARGET_CYGWIN
274 __DestructExceptionObject(rec, 1);
275#endif
276 setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP));
277 } else if (!LJ_EXCODE_CHECK(rec->ExceptionCode)) {
278 /* Don't catch access violations etc. */
279 return 1; /* ExceptionContinueSearch */
280 }
281#if LJ_TARGET_X86
282 UNUSED(ctx);
283 UNUSED(dispatch);
284 /* Call all handlers for all lower C frames (including ourselves) again
285 ** with EH_UNWINDING set. Then call the specified function, passing cf
286 ** and errcode.
287 */
288 lj_vm_rtlunwind(cf, (void *)rec,
289 (cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ?
290 (void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode);
291 /* lj_vm_rtlunwind does not return. */
292#else
293 /* Unwind the stack and call all handlers for all lower C frames
294 ** (including ourselves) again with EH_UNWINDING set. Then set
295 ** stack pointer = cf, result = errcode and jump to the specified target.
296 */
297 RtlUnwindEx(cf, (void *)((cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ?
298 lj_vm_unwind_ff_eh :
299 lj_vm_unwind_c_eh),
300 rec, (void *)(uintptr_t)errcode, ctx, dispatch->HistoryTable);
301 /* RtlUnwindEx should never return. */
302#endif
303 }
304 }
305 return 1; /* ExceptionContinueSearch */
306}
307
308/* Raise Windows exception. */
309static void err_raise_ext(global_State *g, int errcode)
310{
311#if LJ_HASJIT
312 setmref(g->jit_base, NULL);
313#endif
314 RaiseException(LJ_EXCODE_MAKE(errcode), 1 /* EH_NONCONTINUABLE */, 0, NULL);
315}
316
317#elif !LJ_NO_UNWIND && (defined(__GNUC__) || defined(__clang__))
188 318
189/* 319/*
190** We have to use our own definitions instead of the mandatory (!) unwind.h, 320** We have to use our own definitions instead of the mandatory (!) unwind.h,
@@ -233,7 +363,6 @@ LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions,
233 lua_State *L; 363 lua_State *L;
234 if (version != 1) 364 if (version != 1)
235 return _URC_FATAL_PHASE1_ERROR; 365 return _URC_FATAL_PHASE1_ERROR;
236 UNUSED(uexclass);
237 cf = (void *)_Unwind_GetCFA(ctx); 366 cf = (void *)_Unwind_GetCFA(ctx);
238 L = cframe_L(cf); 367 L = cframe_L(cf);
239 if ((actions & _UA_SEARCH_PHASE)) { 368 if ((actions & _UA_SEARCH_PHASE)) {
@@ -281,6 +410,9 @@ LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions,
281 ** it on non-x64 because the interpreter restores all callee-saved regs. 410 ** it on non-x64 because the interpreter restores all callee-saved regs.
282 */ 411 */
283 lj_err_throw(L, errcode); 412 lj_err_throw(L, errcode);
413#if LJ_TARGET_X64
414#error "Broken build system -- only use the provided Makefiles!"
415#endif
284#endif 416#endif
285 } 417 }
286 return _URC_CONTINUE_UNWIND; 418 return _URC_CONTINUE_UNWIND;
@@ -288,14 +420,6 @@ LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions,
288 420
289#if LJ_UNWIND_EXT 421#if LJ_UNWIND_EXT
290static __thread _Unwind_Exception static_uex; 422static __thread _Unwind_Exception static_uex;
291
292/* Raise DWARF2 exception. */
293static void err_raise_ext(int errcode)
294{
295 static_uex.exclass = LJ_UEXCLASS_MAKE(errcode);
296 static_uex.excleanup = NULL;
297 _Unwind_RaiseException(&static_uex);
298}
299#endif 423#endif
300 424
301#else /* LJ_TARGET_ARM */ 425#else /* LJ_TARGET_ARM */
@@ -369,132 +493,22 @@ LJ_FUNCA int lj_err_unwind_arm(int state, _Unwind_Control_Block *ucb,
369 493
370#if LJ_UNWIND_EXT 494#if LJ_UNWIND_EXT
371static __thread _Unwind_Control_Block static_uex; 495static __thread _Unwind_Control_Block static_uex;
496#endif
497#endif /* LJ_TARGET_ARM */
372 498
373static void err_raise_ext(int errcode) 499#if LJ_UNWIND_EXT
500/* Raise external exception. */
501static void err_raise_ext(global_State *g, int errcode)
374{ 502{
503#if LJ_HASJIT
504 setmref(g->jit_base, NULL);
505#endif
375 memset(&static_uex, 0, sizeof(static_uex)); 506 memset(&static_uex, 0, sizeof(static_uex));
376 static_uex.exclass = LJ_UEXCLASS_MAKE(errcode); 507 static_uex.exclass = LJ_UEXCLASS_MAKE(errcode);
377 _Unwind_RaiseException(&static_uex); 508 _Unwind_RaiseException(&static_uex);
378} 509}
379#endif 510#endif
380 511
381#endif /* LJ_TARGET_ARM */
382
383#elif LJ_ABI_WIN
384
385/*
386** Someone in Redmond owes me several days of my life. A lot of this is
387** undocumented or just plain wrong on MSDN. Some of it can be gathered
388** from 3rd party docs or must be found by trial-and-error. They really
389** don't want you to write your own language-specific exception handler
390** or to interact gracefully with MSVC. :-(
391**
392** Apparently MSVC doesn't call C++ destructors for foreign exceptions
393** unless you compile your C++ code with /EHa. Unfortunately this means
394** catch (...) also catches things like access violations. The use of
395** _set_se_translator doesn't really help, because it requires /EHa, too.
396*/
397
398#define WIN32_LEAN_AND_MEAN
399#include <windows.h>
400
401#if LJ_TARGET_X64
402/* Taken from: http://www.nynaeve.net/?p=99 */
403typedef struct UndocumentedDispatcherContext {
404 ULONG64 ControlPc;
405 ULONG64 ImageBase;
406 PRUNTIME_FUNCTION FunctionEntry;
407 ULONG64 EstablisherFrame;
408 ULONG64 TargetIp;
409 PCONTEXT ContextRecord;
410 void (*LanguageHandler)(void);
411 PVOID HandlerData;
412 PUNWIND_HISTORY_TABLE HistoryTable;
413 ULONG ScopeIndex;
414 ULONG Fill0;
415} UndocumentedDispatcherContext;
416#else
417typedef void *UndocumentedDispatcherContext;
418#endif
419
420/* Another wild guess. */
421extern void __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow);
422
423#if LJ_TARGET_X64 && defined(MINGW_SDK_INIT)
424/* Workaround for broken MinGW64 declaration. */
425VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx");
426#define RtlUnwindEx RtlUnwindEx_FIXED
427#endif
428
429#define LJ_MSVC_EXCODE ((DWORD)0xe06d7363)
430#define LJ_GCC_EXCODE ((DWORD)0x20474343)
431
432#define LJ_EXCODE ((DWORD)0xe24c4a00)
433#define LJ_EXCODE_MAKE(c) (LJ_EXCODE | (DWORD)(c))
434#define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff)
435#define LJ_EXCODE_ERRCODE(cl) ((int)((cl) & 0xff))
436
437/* Windows exception handler for interpreter frame. */
438LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec,
439 void *f, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch)
440{
441#if LJ_TARGET_X64
442 void *cf = f;
443#else
444 void *cf = (char *)f - CFRAME_OFS_SEH;
445#endif
446 lua_State *L = cframe_L(cf);
447 int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ?
448 LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN;
449 if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */
450 /* Unwind internal frames. */
451 err_unwind(L, cf, errcode);
452 } else {
453 void *cf2 = err_unwind(L, cf, 0);
454 if (cf2) { /* We catch it, so start unwinding the upper frames. */
455 if (rec->ExceptionCode == LJ_MSVC_EXCODE ||
456 rec->ExceptionCode == LJ_GCC_EXCODE) {
457#if LJ_TARGET_WINDOWS
458 __DestructExceptionObject(rec, 1);
459#endif
460 setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP));
461 } else if (!LJ_EXCODE_CHECK(rec->ExceptionCode)) {
462 /* Don't catch access violations etc. */
463 return 1; /* ExceptionContinueSearch */
464 }
465#if LJ_TARGET_X64
466 /* Unwind the stack and call all handlers for all lower C frames
467 ** (including ourselves) again with EH_UNWINDING set. Then set
468 ** rsp = cf, rax = errcode and jump to the specified target.
469 */
470 RtlUnwindEx(cf, (void *)((cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ?
471 lj_vm_unwind_ff_eh :
472 lj_vm_unwind_c_eh),
473 rec, (void *)(uintptr_t)errcode, ctx, dispatch->HistoryTable);
474 /* RtlUnwindEx should never return. */
475#else
476 UNUSED(ctx);
477 UNUSED(dispatch);
478 /* Call all handlers for all lower C frames (including ourselves) again
479 ** with EH_UNWINDING set. Then call the specified function, passing cf
480 ** and errcode.
481 */
482 lj_vm_rtlunwind(cf, (void *)rec,
483 (cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ?
484 (void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode);
485 /* lj_vm_rtlunwind does not return. */
486#endif
487 }
488 }
489 return 1; /* ExceptionContinueSearch */
490}
491
492/* Raise Windows exception. */
493static void err_raise_ext(int errcode)
494{
495 RaiseException(LJ_EXCODE_MAKE(errcode), 1 /* EH_NONCONTINUABLE */, 0, NULL);
496}
497
498#endif 512#endif
499 513
500/* -- Error handling ------------------------------------------------------ */ 514/* -- Error handling ------------------------------------------------------ */
@@ -504,22 +518,23 @@ LJ_NOINLINE void LJ_FASTCALL lj_err_throw(lua_State *L, int errcode)
504{ 518{
505 global_State *g = G(L); 519 global_State *g = G(L);
506 lj_trace_abort(g); 520 lj_trace_abort(g);
507 setmref(g->jit_base, NULL);
508 L->status = LUA_OK; 521 L->status = LUA_OK;
509#if LJ_UNWIND_EXT 522#if LJ_UNWIND_EXT
510 err_raise_ext(errcode); 523 err_raise_ext(g, errcode);
511 /* 524 /*
512 ** A return from this function signals a corrupt C stack that cannot be 525 ** A return from this function signals a corrupt C stack that cannot be
513 ** unwound. We have no choice but to call the panic function and exit. 526 ** unwound. We have no choice but to call the panic function and exit.
514 ** 527 **
515 ** Usually this is caused by a C function without unwind information. 528 ** Usually this is caused by a C function without unwind information.
516 ** This should never happen on x64, but may happen if you've manually 529 ** This may happen if you've manually enabled LUAJIT_UNWIND_EXTERNAL
517 ** enabled LUAJIT_UNWIND_EXTERNAL and forgot to recompile *every* 530 ** and forgot to recompile *every* non-C++ file with -funwind-tables.
518 ** non-C++ file with -funwind-tables.
519 */ 531 */
520 if (G(L)->panic) 532 if (G(L)->panic)
521 G(L)->panic(L); 533 G(L)->panic(L);
522#else 534#else
535#if LJ_HASJIT
536 setmref(g->jit_base, NULL);
537#endif
523 { 538 {
524 void *cf = err_unwind(L, NULL, errcode); 539 void *cf = err_unwind(L, NULL, errcode);
525 if (cframe_unwind_ff(cf)) 540 if (cframe_unwind_ff(cf))