aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMike Pall <mike>2010-01-05 22:39:46 +0100
committerMike Pall <mike>2010-01-05 22:39:46 +0100
commitc31ac26fb9803d4b09c27668b7c2d9a01385c9ba (patch)
tree620bc1af468b94d4676f5b6e335b5983e9f1ef8b /src
parentb3e3bad0ffffe9e1a23c658b99810c687905005d (diff)
downloadluajit-c31ac26fb9803d4b09c27668b7c2d9a01385c9ba.tar.gz
luajit-c31ac26fb9803d4b09c27668b7c2d9a01385c9ba.tar.bz2
luajit-c31ac26fb9803d4b09c27668b7c2d9a01385c9ba.zip
Add support for WIN64 exception handling to external unwinder.
Modify unwinding to always return _ff or _c unwind type. Generate PE object .pdata/.xdata sections for x64 interpreter. Can drop r12-r15 saves in Windows/x64 interpreter now.
Diffstat (limited to 'src')
-rw-r--r--src/buildvm_peobj.c70
-rw-r--r--src/buildvm_x86.dasc30
-rw-r--r--src/buildvm_x86.h2
-rw-r--r--src/lj_err.c98
-rw-r--r--src/lj_frame.h21
5 files changed, 177 insertions, 44 deletions
diff --git a/src/buildvm_peobj.c b/src/buildvm_peobj.c
index d45f3c97..68af79c7 100644
--- a/src/buildvm_peobj.c
+++ b/src/buildvm_peobj.c
@@ -90,6 +90,7 @@ typedef struct PEsymaux {
90#define PEOBJ_ARCH_TARGET 0x8664 90#define PEOBJ_ARCH_TARGET 0x8664
91#define PEOBJ_RELOC_REL32 0x04 /* MS: REL32, GNU: DISP32. */ 91#define PEOBJ_RELOC_REL32 0x04 /* MS: REL32, GNU: DISP32. */
92#define PEOBJ_RELOC_DIR32 0x02 92#define PEOBJ_RELOC_DIR32 0x02
93#define PEOBJ_RELOC_ADDR32NB 0x03
93#define PEOBJ_SYM_PREFIX "" 94#define PEOBJ_SYM_PREFIX ""
94#endif 95#endif
95 96
@@ -98,7 +99,10 @@ enum {
98 PEOBJ_SECT_ABS = -2, 99 PEOBJ_SECT_ABS = -2,
99 PEOBJ_SECT_UNDEF = -1, 100 PEOBJ_SECT_UNDEF = -1,
100 PEOBJ_SECT_TEXT, 101 PEOBJ_SECT_TEXT,
101 /* TODO: add .pdata/.xdata for x64. */ 102#if LJ_TARGET_X64
103 PEOBJ_SECT_PDATA,
104 PEOBJ_SECT_XDATA,
105#endif
102 PEOBJ_SECT_RDATA, 106 PEOBJ_SECT_RDATA,
103 PEOBJ_SECT_RDATA_Z, 107 PEOBJ_SECT_RDATA_Z,
104 PEOBJ_NSECTIONS 108 PEOBJ_NSECTIONS
@@ -196,6 +200,24 @@ void emit_peobj(BuildCtx *ctx)
196 /* Flags: 60 = read+execute, 50 = align16, 20 = code. */ 200 /* Flags: 60 = read+execute, 50 = align16, 20 = code. */
197 pesect[PEOBJ_SECT_TEXT].flags = 0x60500020; 201 pesect[PEOBJ_SECT_TEXT].flags = 0x60500020;
198 202
203#if LJ_TARGET_X64
204 memcpy(pesect[PEOBJ_SECT_PDATA].name, ".pdata", sizeof(".pdata")-1);
205 pesect[PEOBJ_SECT_PDATA].ofs = sofs;
206 sofs += (pesect[PEOBJ_SECT_PDATA].size = 3*4);
207 pesect[PEOBJ_SECT_PDATA].relocofs = sofs;
208 sofs += (pesect[PEOBJ_SECT_PDATA].nreloc = 3) * PEOBJ_RELOC_SIZE;
209 /* Flags: 40 = read, 30 = align4, 40 = initialized data. */
210 pesect[PEOBJ_SECT_PDATA].flags = 0x40300040;
211
212 memcpy(pesect[PEOBJ_SECT_XDATA].name, ".xdata", sizeof(".xdata")-1);
213 pesect[PEOBJ_SECT_XDATA].ofs = sofs;
214 sofs += (pesect[PEOBJ_SECT_XDATA].size = 8*2+4); /* See below. */
215 pesect[PEOBJ_SECT_XDATA].relocofs = sofs;
216 sofs += (pesect[PEOBJ_SECT_XDATA].nreloc = 1) * PEOBJ_RELOC_SIZE;
217 /* Flags: 40 = read, 30 = align4, 40 = initialized data. */
218 pesect[PEOBJ_SECT_XDATA].flags = 0x40300040;
219#endif
220
199 memcpy(pesect[PEOBJ_SECT_RDATA].name, ".rdata", sizeof(".rdata")-1); 221 memcpy(pesect[PEOBJ_SECT_RDATA].name, ".rdata", sizeof(".rdata")-1);
200 pesect[PEOBJ_SECT_RDATA].ofs = sofs; 222 pesect[PEOBJ_SECT_RDATA].ofs = sofs;
201 sofs += (pesect[PEOBJ_SECT_RDATA].size = ctx->npc*sizeof(uint16_t)); 223 sofs += (pesect[PEOBJ_SECT_RDATA].size = ctx->npc*sizeof(uint16_t));
@@ -228,6 +250,9 @@ void emit_peobj(BuildCtx *ctx)
228#if !LJ_HASJIT 250#if !LJ_HASJIT
229 pehdr.nsyms -= 7; 251 pehdr.nsyms -= 7;
230#endif 252#endif
253#if LJ_TARGET_X64
254 pehdr.nsyms += 1; /* Symbol for lj_err_unwind_win64. */
255#endif
231 256
232 /* Write PE object header and all sections. */ 257 /* Write PE object header and all sections. */
233 owrite(ctx, &pehdr, sizeof(PEheader)); 258 owrite(ctx, &pehdr, sizeof(PEheader));
@@ -243,6 +268,41 @@ void emit_peobj(BuildCtx *ctx)
243 owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); 268 owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
244 } 269 }
245 270
271#if LJ_TARGET_X64
272 { /* Write .pdata section. */
273 uint32_t pdata[3]; /* Start of .text, end of .text and .xdata. */
274 PEreloc reloc;
275 pdata[0] = 0; pdata[1] = (uint32_t)ctx->codesz; pdata[2] = 0;
276 owrite(ctx, &pdata, sizeof(pdata));
277 reloc.vaddr = 0; reloc.symidx = 1+2+relocsyms+2+2+1;
278 reloc.type = PEOBJ_RELOC_ADDR32NB;
279 owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
280 reloc.vaddr = 4; reloc.symidx = 1+2+relocsyms+2+2+1;
281 reloc.type = PEOBJ_RELOC_ADDR32NB;
282 owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
283 reloc.vaddr = 8; reloc.symidx = 1+2+relocsyms+2;
284 reloc.type = PEOBJ_RELOC_ADDR32NB;
285 owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
286 }
287 { /* Write .xdata section. */
288 uint16_t xdata[8+2];
289 PEreloc reloc;
290 xdata[0] = 0x01|0x08|0x10; /* Ver. 1, uhander/ehandler, prolog size 0. */
291 xdata[1] = 5; /* Number of unwind codes, no frame pointer. */
292 xdata[2] = 0x4200; /* Stack offset 4*8+8 = aword*5. */
293 xdata[3] = 0x3000; /* Push rbx. */
294 xdata[4] = 0x6000; /* Push rsi. */
295 xdata[5] = 0x7000; /* Push rdi. */
296 xdata[6] = 0x5000; /* Push rbp. */
297 xdata[7] = 0; /* Alignment. */
298 xdata[8] = xdata[9] = 0; /* Relocated address of exception handler. */
299 owrite(ctx, &xdata, sizeof(xdata));
300 reloc.vaddr = sizeof(xdata)-4; reloc.symidx = 1+2+relocsyms+2+2;
301 reloc.type = PEOBJ_RELOC_ADDR32NB;
302 owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
303 }
304#endif
305
246 /* Write .rdata section. */ 306 /* Write .rdata section. */
247 for (i = 0; i < ctx->npc; i++) { 307 for (i = 0; i < ctx->npc; i++) {
248 uint16_t pcofs = (uint16_t)ctx->sym_ofs[i]; 308 uint16_t pcofs = (uint16_t)ctx->sym_ofs[i];
@@ -279,6 +339,14 @@ void emit_peobj(BuildCtx *ctx)
279 emit_peobj_sym(ctx, name, 0, 339 emit_peobj_sym(ctx, name, 0,
280 PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN); 340 PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
281 } 341 }
342
343#if LJ_TARGET_X64
344 emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_PDATA);
345 emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_XDATA);
346 emit_peobj_sym(ctx, PEOBJ_SYM_PREFIX "lj_err_unwind_win64", 0,
347 PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
348#endif
349
282 emit_peobj_sym(ctx, PEOBJ_SYM_PREFIX LABEL_ASM_BEGIN, 0, 350 emit_peobj_sym(ctx, PEOBJ_SYM_PREFIX LABEL_ASM_BEGIN, 0,
283 PEOBJ_SECT_TEXT, PEOBJ_TYPE_NULL, PEOBJ_SCL_EXTERN); 351 PEOBJ_SECT_TEXT, PEOBJ_TYPE_NULL, PEOBJ_SCL_EXTERN);
284 for (i = nzsym; i < ctx->nsym; i++) { 352 for (i = nzsym; i < ctx->nsym; i++) {
diff --git a/src/buildvm_x86.dasc b/src/buildvm_x86.dasc
index be2ee71e..e40ca6d7 100644
--- a/src/buildvm_x86.dasc
+++ b/src/buildvm_x86.dasc
@@ -168,28 +168,22 @@
168|.define CFRAME_SPACE, aword*5 // Delta for rsp (see <--). 168|.define CFRAME_SPACE, aword*5 // Delta for rsp (see <--).
169|.macro saveregs 169|.macro saveregs
170| push rbp; push rdi; push rsi; push rbx 170| push rbp; push rdi; push rsi; push rbx
171| push r15; push r14; push r13; push r12
172| sub rsp, CFRAME_SPACE 171| sub rsp, CFRAME_SPACE
173|.endmacro 172|.endmacro
174|.macro restoreregs 173|.macro restoreregs
175| add rsp, CFRAME_SPACE 174| add rsp, CFRAME_SPACE
176| pop r12; pop r13; pop r14; pop r15
177| pop rbx; pop rsi; pop rdi; pop rbp 175| pop rbx; pop rsi; pop rdi; pop rbp
178|.endmacro 176|.endmacro
179| 177|
180|.define SAVE_CFRAME, aword [rsp+aword*17] 178|.define SAVE_CFRAME, aword [rsp+aword*13]
181|.define SAVE_PC, dword [rsp+dword*33] 179|.define SAVE_PC, dword [rsp+dword*25]
182|.define SAVE_L, dword [rsp+dword*32] 180|.define SAVE_L, dword [rsp+dword*24]
183|.define SAVE_ERRF, dword [rsp+dword*31] 181|.define SAVE_ERRF, dword [rsp+dword*23]
184|.define SAVE_NRES, dword [rsp+dword*30] 182|.define SAVE_NRES, dword [rsp+dword*22]
185|.define TMP2, dword [rsp+dword*29] 183|.define TMP2, dword [rsp+dword*21]
186|.define TMP1, dword [rsp+dword*28] 184|.define TMP1, dword [rsp+dword*20]
187|//----- 16 byte aligned, ^^^ 32 byte register save area, owned by interpreter 185|//----- 16 byte aligned, ^^^ 32 byte register save area, owned by interpreter
188|.define SAVE_RET, aword [rsp+aword*13] //<-- rsp entering interpreter. 186|.define SAVE_RET, aword [rsp+aword*9] //<-- rsp entering interpreter.
189|.define SAVE_R8, aword [rsp+aword*12]
190|.define SAVE_R7, aword [rsp+aword*11]
191|.define SAVE_R6, aword [rsp+aword*10]
192|.define SAVE_R5, aword [rsp+aword*9]
193|.define SAVE_R4, aword [rsp+aword*8] 187|.define SAVE_R4, aword [rsp+aword*8]
194|.define SAVE_R3, aword [rsp+aword*7] 188|.define SAVE_R3, aword [rsp+aword*7]
195|.define SAVE_R2, aword [rsp+aword*6] 189|.define SAVE_R2, aword [rsp+aword*6]
@@ -202,7 +196,7 @@
202|//----- 16 byte aligned, ^^^ 32 byte register save area, owned by callee 196|//----- 16 byte aligned, ^^^ 32 byte register save area, owned by callee
203| 197|
204|// TMPQ overlaps TMP1/TMP2. MULTRES overlaps TMP2 (and TMPQ). 198|// TMPQ overlaps TMP1/TMP2. MULTRES overlaps TMP2 (and TMPQ).
205|.define TMPQ, qword [rsp+aword*14] 199|.define TMPQ, qword [rsp+aword*10]
206|.define MULTRES, TMP2 200|.define MULTRES, TMP2
207|.define TMPa, ARG5 201|.define TMPa, ARG5
208|.define ARG5d, dword [rsp+aword*4] 202|.define ARG5d, dword [rsp+aword*4]
@@ -861,10 +855,12 @@ static void build_subroutines(BuildCtx *ctx, int cmov, int sse)
861 | mov dword [RA+RD*8-4], LJ_TNIL // Ensure one valid arg. 855 | mov dword [RA+RD*8-4], LJ_TNIL // Ensure one valid arg.
862 | mov RC, RA // ... in [RC] 856 | mov RC, RA // ... in [RC]
863 | mov PC, [RB-12] // Restore PC from [cont|PC]. 857 | mov PC, [RB-12] // Restore PC from [cont|PC].
864 | mov RA, dword [RB-16]
865 |.if X64 858 |.if X64
859 | movsxd RAa, dword [RB-16] // May be negative on WIN64 with debug.
866 | lea KBASEa, qword [=>0] 860 | lea KBASEa, qword [=>0]
867 | add RAa, KBASEa 861 | add RAa, KBASEa
862 |.else
863 | mov RA, dword [RB-16]
868 |.endif 864 |.endif
869 | mov LFUNC:KBASE, [BASE-8] 865 | mov LFUNC:KBASE, [BASE-8]
870 | mov PROTO:KBASE, LFUNC:KBASE->pt 866 | mov PROTO:KBASE, LFUNC:KBASE->pt
@@ -1854,7 +1850,7 @@ static void build_subroutines(BuildCtx *ctx, int cmov, int sse)
1854 |.ffunc coroutine_yield 1850 |.ffunc coroutine_yield
1855 | mov L:RB, SAVE_L 1851 | mov L:RB, SAVE_L
1856 | mov [RA-4], PC 1852 | mov [RA-4], PC
1857 | test aword L:RB->cframe, CFRAME_CANYIELD 1853 | test aword L:RB->cframe, CFRAME_RESUME
1858 | jz ->fff_fallback 1854 | jz ->fff_fallback
1859 | mov L:RB->base, RA 1855 | mov L:RB->base, RA
1860 | lea RC, [RA+NARGS:RC*8-8] 1856 | lea RC, [RA+NARGS:RC*8-8]
diff --git a/src/buildvm_x86.h b/src/buildvm_x86.h
index 030ac179..68f27f93 100644
--- a/src/buildvm_x86.h
+++ b/src/buildvm_x86.h
@@ -1177,7 +1177,7 @@ static void build_subroutines(BuildCtx *ctx, int cmov, int sse)
1177 dasm_put(Dst, 3443, Dt1(->top), Dt1(->base), Dt8(->upvalue[0].gcr), Dt1(->cframe), Dt1(->status), LUA_YIELD, Dt1(->top), Dt1(->base)); 1177 dasm_put(Dst, 3443, Dt1(->top), Dt1(->base), Dt8(->upvalue[0].gcr), Dt1(->cframe), Dt1(->status), LUA_YIELD, Dt1(->top), Dt1(->base));
1178 dasm_put(Dst, 3523, Dt1(->maxstack), Dt1(->top), Dt1(->base), Dt1(->top), DISPATCH_GL(vmstate), ~LJ_VMST_INTERP, Dt1(->base)); 1178 dasm_put(Dst, 3523, Dt1(->maxstack), Dt1(->top), Dt1(->base), Dt1(->top), DISPATCH_GL(vmstate), ~LJ_VMST_INTERP, Dt1(->base));
1179 dasm_put(Dst, 3631, LUA_YIELD, Dt1(->base), Dt1(->top), Dt1(->top), Dt1(->maxstack), FRAME_TYPE); 1179 dasm_put(Dst, 3631, LUA_YIELD, Dt1(->base), Dt1(->top), Dt1(->top), Dt1(->maxstack), FRAME_TYPE);
1180 dasm_put(Dst, 3727, Dt1(->top), Dt1(->base), Dt1(->cframe), CFRAME_CANYIELD, Dt1(->base), Dt1(->top), Dt1(->cframe), LUA_YIELD, Dt1(->status)); 1180 dasm_put(Dst, 3727, Dt1(->top), Dt1(->base), Dt1(->cframe), CFRAME_RESUME, Dt1(->base), Dt1(->top), Dt1(->cframe), LUA_YIELD, Dt1(->status));
1181 if (sse) { 1181 if (sse) {
1182 dasm_put(Dst, 3813, 1+1, LJ_TISNUM); 1182 dasm_put(Dst, 3813, 1+1, LJ_TISNUM);
1183 } else { 1183 } else {
diff --git a/src/lj_err.c b/src/lj_err.c
index b2e7f5f8..b8070250 100644
--- a/src/lj_err.c
+++ b/src/lj_err.c
@@ -493,7 +493,7 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode)
493 L->cframe = NULL; 493 L->cframe = NULL;
494 L->status = cast_byte(errcode); 494 L->status = cast_byte(errcode);
495 } 495 }
496 return cframe_raw(cf); 496 return cf;
497 } 497 }
498 if (errcode) { 498 if (errcode) {
499 L->cframe = cframe_prev(cf); 499 L->cframe = cframe_prev(cf);
@@ -514,9 +514,8 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode)
514 L->cframe = cf; 514 L->cframe = cf;
515 L->base = frame_prevd(frame) + 1; 515 L->base = frame_prevd(frame) + 1;
516 unwindstack(L, L->base); 516 unwindstack(L, L->base);
517 return NULL; /* Call special handler. */
518 } 517 }
519 return cf; 518 return (void *)((intptr_t)cf | CFRAME_UNWIND_FF);
520 } 519 }
521 } 520 }
522 /* No C frame. */ 521 /* No C frame. */
@@ -528,7 +527,7 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode)
528 G(L)->panic(L); 527 G(L)->panic(L);
529 exit(EXIT_FAILURE); 528 exit(EXIT_FAILURE);
530 } 529 }
531 return L; /* Anything not-NULL will do. */ 530 return L; /* Anything non-NULL will do. */
532} 531}
533 532
534/* -- External frame unwinding -------------------------------------------- */ 533/* -- External frame unwinding -------------------------------------------- */
@@ -574,12 +573,12 @@ LJ_FUNCA int lj_err_unwind_dwarf(int version, _Unwind_Action actions,
574 errcode = LUA_ERRRUN; 573 errcode = LUA_ERRRUN;
575 } 574 }
576#if LJ_UNWIND_EXT 575#if LJ_UNWIND_EXT
577 if (err_unwind(L, cf, errcode)) { 576 cf = err_unwind(L, cf, errcode);
577 if (cf) {
578 _Unwind_SetGR(ctx, 0, errcode); 578 _Unwind_SetGR(ctx, 0, errcode);
579 _Unwind_SetIP(ctx, (_Unwind_Ptr)lj_vm_unwind_c_eh); 579 _Unwind_SetIP(ctx, (_Unwind_Ptr)(cframe_unwind_ff(cf) ?
580 return _URC_INSTALL_CONTEXT; 580 lj_vm_unwind_ff_eh :
581 } else if ((actions & _UA_HANDLER_FRAME)) { 581 lj_vm_unwind_c_eh));
582 _Unwind_SetIP(ctx, (_Unwind_Ptr)lj_vm_unwind_ff_eh);
583 return _URC_INSTALL_CONTEXT; 582 return _URC_INSTALL_CONTEXT;
584 } 583 }
585#else 584#else
@@ -607,20 +606,89 @@ static void err_raise_ext(int errcode)
607 606
608#elif defined(_WIN64) 607#elif defined(_WIN64)
609 608
609/*
610** Someone in Redmond owes me several days of my life. A lot of this is
611** undocumented or just plain wrong on MSDN. Some of it can be gathered
612** from 3rd party docs or must be found by trial-and-error. They really
613** don't want you to write your own language-specific exception handler
614** or to interact gracefully with MSVC. :-(
615**
616** Apparently MSVC doesn't call C++ destructors for foreign exceptions
617** unless you compile your C++ code with /EHa. Unfortunately this means
618** catch (...) also catches things like access violations. The use of
619** _set_se_translator doesn't really help, because it requires /EHa, too.
620*/
621
610#define WIN32_LEAN_AND_MEAN 622#define WIN32_LEAN_AND_MEAN
611#include <windows.h> 623#include <windows.h>
612 624
613#define LJ_EXCODE ((DWORD)0x024c4a00) 625/* Taken from: http://www.nynaeve.net/?p=99 */
626typedef struct UndocumentedDispatcherContext {
627 ULONG64 ControlPc;
628 ULONG64 ImageBase;
629 PRUNTIME_FUNCTION FunctionEntry;
630 ULONG64 EstablisherFrame;
631 ULONG64 TargetIp;
632 PCONTEXT ContextRecord;
633 PEXCEPTION_ROUTINE LanguageHandler;
634 PVOID HandlerData;
635 PUNWIND_HISTORY_TABLE HistoryTable;
636 ULONG ScopeIndex;
637 ULONG Fill0;
638} UndocumentedDispatcherContext;
639
640#ifdef _MSC_VER
641/* Another wild guess. */
642extern __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow);
643#endif
644
645#define LJ_MSVC_EXCODE ((DWORD)0xe06d7363)
646
647#define LJ_EXCODE ((DWORD)0xe24c4a00)
614#define LJ_EXCODE_MAKE(c) (LJ_EXCODE | (DWORD)(c)) 648#define LJ_EXCODE_MAKE(c) (LJ_EXCODE | (DWORD)(c))
615#define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff) 649#define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff)
616#define LJ_EXCODE_ERRCODE(cl) (cast_int((cl) & 0xff)) 650#define LJ_EXCODE_ERRCODE(cl) (cast_int((cl) & 0xff))
617 651
618/* NYI: Win64 exception handler for interpreter frame. */ 652/* Win64 exception handler for interpreter frame. */
653LJ_FUNCA EXCEPTION_DISPOSITION lj_err_unwind_win64(EXCEPTION_RECORD *rec,
654 void *cf, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch)
655{
656 lua_State *L = cframe_L(cf);
657 if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */
658 err_unwind(L, cf, 1); /* Unwind internal frames. */
659 } else {
660 void *cf2 = err_unwind(L, cf, 0);
661 if (cf2) { /* We catch it, so start unwinding the upper frames. */
662 int errcode;
663 if (LJ_EXCODE_CHECK(rec->ExceptionCode)) {
664 errcode = LJ_EXCODE_ERRCODE(rec->ExceptionCode);
665 } else if (rec->ExceptionCode == LJ_MSVC_EXCODE) {
666#ifdef _MSC_VER
667 __DestructExceptionObject(rec, 1);
668#endif
669 setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP));
670 errcode = LUA_ERRRUN;
671 } else { /* Don't catch access violations etc. */
672 return ExceptionContinueSearch;
673 }
674 /* Unwind the stack and call all handlers for all lower C frames
675 ** (including ourselves) again with EH_UNWINDING set. Then set
676 ** rsp = cf, rax = errcode and jump to the specified target.
677 */
678 RtlUnwindEx(cf, (void *)(cframe_unwind_ff(cf2) ?
679 lj_vm_unwind_ff_eh :
680 lj_vm_unwind_c_eh),
681 rec, (void *)errcode, ctx, dispatch->HistoryTable);
682 /* RtlUnwindEx should never return. */
683 }
684 }
685 return ExceptionContinueSearch;
686}
619 687
620/* Raise Windows exception. */ 688/* Raise Windows exception. */
621static void err_raise_ext(int errcode) 689static void err_raise_ext(int errcode)
622{ 690{
623 RaiseException(LJ_EXCODE_MAKE(errcode), 0, 0, NULL); 691 RaiseException(LJ_EXCODE_MAKE(errcode), 1 /* EH_NONCONTINUABLE */, 0, NULL);
624} 692}
625 693
626#endif 694#endif
@@ -650,10 +718,10 @@ LJ_NOINLINE void lj_err_throw(lua_State *L, int errcode)
650#else 718#else
651 { 719 {
652 void *cf = err_unwind(L, NULL, errcode); 720 void *cf = err_unwind(L, NULL, errcode);
653 if (cf) 721 if (cframe_unwind_ff(cf))
654 lj_vm_unwind_c(cf, errcode); 722 lj_vm_unwind_ff(cframe_raw(cf));
655 else 723 else
656 lj_vm_unwind_ff(cframe_raw(L->cframe)); 724 lj_vm_unwind_c(cframe_raw(cf), errcode);
657 } 725 }
658#endif 726#endif
659 exit(EXIT_FAILURE); 727 exit(EXIT_FAILURE);
diff --git a/src/lj_frame.h b/src/lj_frame.h
index 0bfcb005..c86818e0 100644
--- a/src/lj_frame.h
+++ b/src/lj_frame.h
@@ -67,13 +67,13 @@ enum {
67#define CFRAME_SIZE (12*4) 67#define CFRAME_SIZE (12*4)
68#elif LJ_TARGET_X64 68#elif LJ_TARGET_X64
69#if _WIN64 69#if _WIN64
70#define CFRAME_OFS_PREV (17*8) 70#define CFRAME_OFS_PREV (13*8)
71#define CFRAME_OFS_PC (33*4) 71#define CFRAME_OFS_PC (25*4)
72#define CFRAME_OFS_L (32*4) 72#define CFRAME_OFS_L (24*4)
73#define CFRAME_OFS_ERRF (31*4) 73#define CFRAME_OFS_ERRF (23*4)
74#define CFRAME_OFS_NRES (30*4) 74#define CFRAME_OFS_NRES (22*4)
75#define CFRAME_OFS_MULTRES (29*4) 75#define CFRAME_OFS_MULTRES (21*4)
76#define CFRAME_SIZE (14*8) 76#define CFRAME_SIZE (10*8)
77#else 77#else
78#define CFRAME_OFS_PREV (4*8) 78#define CFRAME_OFS_PREV (4*8)
79#define CFRAME_OFS_PC (5*4) 79#define CFRAME_OFS_PC (5*4)
@@ -88,8 +88,8 @@ enum {
88#endif 88#endif
89 89
90#define CFRAME_RESUME 1 90#define CFRAME_RESUME 1
91#define CFRAME_CANYIELD ((intptr_t)(CFRAME_RESUME)) 91#define CFRAME_UNWIND_FF 2 /* Only used in unwinder. */
92#define CFRAME_RAWMASK (~CFRAME_CANYIELD) 92#define CFRAME_RAWMASK (~(intptr_t)(CFRAME_RESUME|CFRAME_UNWIND_FF))
93 93
94#define cframe_errfunc(cf) (*(int32_t *)(((char *)(cf))+CFRAME_OFS_ERRF)) 94#define cframe_errfunc(cf) (*(int32_t *)(((char *)(cf))+CFRAME_OFS_ERRF))
95#define cframe_nres(cf) (*(int32_t *)(((char *)(cf))+CFRAME_OFS_NRES)) 95#define cframe_nres(cf) (*(int32_t *)(((char *)(cf))+CFRAME_OFS_NRES))
@@ -101,7 +101,8 @@ enum {
101 (mref(*(MRef *)(((char *)(cf))+CFRAME_OFS_PC), const BCIns)) 101 (mref(*(MRef *)(((char *)(cf))+CFRAME_OFS_PC), const BCIns))
102#define setcframe_pc(cf, pc) \ 102#define setcframe_pc(cf, pc) \
103 (setmref(*(MRef *)(((char *)(cf))+CFRAME_OFS_PC), (pc))) 103 (setmref(*(MRef *)(((char *)(cf))+CFRAME_OFS_PC), (pc)))
104#define cframe_canyield(cf) ((intptr_t)(cf) & CFRAME_CANYIELD) 104#define cframe_canyield(cf) ((intptr_t)(cf) & CFRAME_RESUME)
105#define cframe_unwind_ff(cf) ((intptr_t)(cf) & CFRAME_UNWIND_FF)
105#define cframe_raw(cf) ((void *)((intptr_t)(cf) & CFRAME_RAWMASK)) 106#define cframe_raw(cf) ((void *)((intptr_t)(cf) & CFRAME_RAWMASK))
106#define cframe_Lpc(L) cframe_pc(cframe_raw(L->cframe)) 107#define cframe_Lpc(L) cframe_pc(cframe_raw(L->cframe))
107 108