diff options
| -rw-r--r-- | doc/extensions.html | 25 | ||||
| -rw-r--r-- | src/host/buildvm.c | 2 | ||||
| -rw-r--r-- | src/host/buildvm_peobj.c | 28 | ||||
| -rw-r--r-- | src/lj_err.c | 38 | ||||
| -rw-r--r-- | src/lj_frame.h | 12 | ||||
| -rw-r--r-- | src/lj_vm.h | 4 | ||||
| -rw-r--r-- | src/vm_x86.dasc | 77 |
7 files changed, 158 insertions, 28 deletions
diff --git a/doc/extensions.html b/doc/extensions.html index 7f712a62..368b527c 100644 --- a/doc/extensions.html +++ b/doc/extensions.html | |||
| @@ -365,25 +365,30 @@ the toolchain used to compile LuaJIT: | |||
| 365 | </tr> | 365 | </tr> |
| 366 | <tr class="odd separate"> | 366 | <tr class="odd separate"> |
| 367 | <td class="excplatform">POSIX/x64, DWARF2 unwinding</td> | 367 | <td class="excplatform">POSIX/x64, DWARF2 unwinding</td> |
| 368 | <td class="exccompiler">GCC 4.3+</td> | 368 | <td class="exccompiler">GCC 4.3+, Clang</td> |
| 369 | <td class="excinterop"><b style="color: #00a000;">Full</b></td> | 369 | <td class="excinterop"><b style="color: #00a000;">Full</b></td> |
| 370 | </tr> | 370 | </tr> |
| 371 | <tr class="even"> | 371 | <tr class="even"> |
| 372 | <td class="excplatform">ARM <tt>-DLUAJIT_UNWIND_EXTERNAL</tt></td> | ||
| 373 | <td class="exccompiler">GCC, Clang</td> | ||
| 374 | <td class="excinterop"><b style="color: #00a000;">Full</b></td> | ||
| 375 | </tr> | ||
| 376 | <tr class="odd"> | ||
| 372 | <td class="excplatform">Other platforms, DWARF2 unwinding</td> | 377 | <td class="excplatform">Other platforms, DWARF2 unwinding</td> |
| 373 | <td class="exccompiler">GCC</td> | 378 | <td class="exccompiler">GCC, Clang</td> |
| 374 | <td class="excinterop"><b style="color: #c06000;">Limited</b></td> | 379 | <td class="excinterop"><b style="color: #c06000;">Limited</b></td> |
| 375 | </tr> | 380 | </tr> |
| 376 | <tr class="odd"> | 381 | <tr class="even"> |
| 377 | <td class="excplatform">Windows/x64</td> | 382 | <td class="excplatform">Windows/x64</td> |
| 378 | <td class="exccompiler">MSVC or WinSDK</td> | 383 | <td class="exccompiler">MSVC or WinSDK</td> |
| 379 | <td class="excinterop"><b style="color: #00a000;">Full</b></td> | 384 | <td class="excinterop"><b style="color: #00a000;">Full</b></td> |
| 380 | </tr> | 385 | </tr> |
| 381 | <tr class="even"> | 386 | <tr class="odd"> |
| 382 | <td class="excplatform">Windows/x86</td> | 387 | <td class="excplatform">Windows/x86</td> |
| 383 | <td class="exccompiler">Any</td> | 388 | <td class="exccompiler">Any</td> |
| 384 | <td class="excinterop"><b style="color: #a00000;">No</b></td> | 389 | <td class="excinterop"><b style="color: #00a000;">Full</b></td> |
| 385 | </tr> | 390 | </tr> |
| 386 | <tr class="odd"> | 391 | <tr class="even"> |
| 387 | <td class="excplatform">Other platforms</td> | 392 | <td class="excplatform">Other platforms</td> |
| 388 | <td class="exccompiler">Other compilers</td> | 393 | <td class="exccompiler">Other compilers</td> |
| 389 | <td class="excinterop"><b style="color: #a00000;">No</b></td> | 394 | <td class="excinterop"><b style="color: #a00000;">No</b></td> |
| @@ -432,14 +437,6 @@ C++ destructors.</li> | |||
| 432 | <li>Lua errors <b>cannot</b> be caught on the C++ side.</li> | 437 | <li>Lua errors <b>cannot</b> be caught on the C++ side.</li> |
| 433 | <li>Throwing Lua errors across C++ frames will <b>not</b> call | 438 | <li>Throwing Lua errors across C++ frames will <b>not</b> call |
| 434 | C++ destructors.</li> | 439 | C++ destructors.</li> |
| 435 | <li>Additionally, on Windows/x86 with SEH-based C++ exceptions: | ||
| 436 | it's <b>not</b> safe to throw a Lua error across any frames containing | ||
| 437 | a C++ function with any try/catch construct or using variables with | ||
| 438 | (implicit) destructors. This also applies to any functions which may be | ||
| 439 | inlined in such a function. It doesn't matter whether <tt>lua_error()</tt> | ||
| 440 | is called inside or outside of a try/catch or whether any object actually | ||
| 441 | needs to be destroyed: the SEH chain is corrupted and this will eventually | ||
| 442 | lead to the termination of the process.</li> | ||
| 443 | </ul> | 440 | </ul> |
| 444 | <br class="flush"> | 441 | <br class="flush"> |
| 445 | </div> | 442 | </div> |
diff --git a/src/host/buildvm.c b/src/host/buildvm.c index 6d9e09e1..57b4dc97 100644 --- a/src/host/buildvm.c +++ b/src/host/buildvm.c | |||
| @@ -110,7 +110,7 @@ static const char *sym_decorate(BuildCtx *ctx, | |||
| 110 | if (p) { | 110 | if (p) { |
| 111 | #if LJ_TARGET_X86ORX64 | 111 | #if LJ_TARGET_X86ORX64 |
| 112 | if (!LJ_64 && (ctx->mode == BUILD_coffasm || ctx->mode == BUILD_peobj)) | 112 | if (!LJ_64 && (ctx->mode == BUILD_coffasm || ctx->mode == BUILD_peobj)) |
| 113 | name[0] = '@'; | 113 | name[0] = name[1] == 'R' ? '_' : '@'; /* Just for _RtlUnwind@16. */ |
| 114 | else | 114 | else |
| 115 | *p = '\0'; | 115 | *p = '\0'; |
| 116 | #elif LJ_TARGET_PPC && !LJ_TARGET_CONSOLE | 116 | #elif LJ_TARGET_PPC && !LJ_TARGET_CONSOLE |
diff --git a/src/host/buildvm_peobj.c b/src/host/buildvm_peobj.c index e8c927d8..42f6ac84 100644 --- a/src/host/buildvm_peobj.c +++ b/src/host/buildvm_peobj.c | |||
| @@ -109,6 +109,8 @@ enum { | |||
| 109 | #if LJ_TARGET_X64 | 109 | #if LJ_TARGET_X64 |
| 110 | PEOBJ_SECT_PDATA, | 110 | PEOBJ_SECT_PDATA, |
| 111 | PEOBJ_SECT_XDATA, | 111 | PEOBJ_SECT_XDATA, |
| 112 | #elif LJ_TARGET_X86 | ||
| 113 | PEOBJ_SECT_SXDATA, | ||
| 112 | #endif | 114 | #endif |
| 113 | PEOBJ_SECT_RDATA_Z, | 115 | PEOBJ_SECT_RDATA_Z, |
| 114 | PEOBJ_NSECTIONS | 116 | PEOBJ_NSECTIONS |
| @@ -208,6 +210,13 @@ void emit_peobj(BuildCtx *ctx) | |||
| 208 | sofs += (pesect[PEOBJ_SECT_XDATA].nreloc = 1) * PEOBJ_RELOC_SIZE; | 210 | sofs += (pesect[PEOBJ_SECT_XDATA].nreloc = 1) * PEOBJ_RELOC_SIZE; |
| 209 | /* Flags: 40 = read, 30 = align4, 40 = initialized data. */ | 211 | /* Flags: 40 = read, 30 = align4, 40 = initialized data. */ |
| 210 | pesect[PEOBJ_SECT_XDATA].flags = 0x40300040; | 212 | pesect[PEOBJ_SECT_XDATA].flags = 0x40300040; |
| 213 | #elif LJ_TARGET_X86 | ||
| 214 | memcpy(pesect[PEOBJ_SECT_SXDATA].name, ".sxdata", sizeof(".sxdata")-1); | ||
| 215 | pesect[PEOBJ_SECT_SXDATA].ofs = sofs; | ||
| 216 | sofs += (pesect[PEOBJ_SECT_SXDATA].size = 4); | ||
| 217 | pesect[PEOBJ_SECT_SXDATA].relocofs = sofs; | ||
| 218 | /* Flags: 40 = read, 30 = align4, 02 = lnk_info, 40 = initialized data. */ | ||
| 219 | pesect[PEOBJ_SECT_SXDATA].flags = 0x40300240; | ||
| 211 | #endif | 220 | #endif |
| 212 | 221 | ||
| 213 | memcpy(pesect[PEOBJ_SECT_RDATA_Z].name, ".rdata$Z", sizeof(".rdata$Z")-1); | 222 | memcpy(pesect[PEOBJ_SECT_RDATA_Z].name, ".rdata$Z", sizeof(".rdata$Z")-1); |
| @@ -232,7 +241,7 @@ void emit_peobj(BuildCtx *ctx) | |||
| 232 | nrsym = ctx->nrelocsym; | 241 | nrsym = ctx->nrelocsym; |
| 233 | pehdr.nsyms = 1+PEOBJ_NSECTIONS*2 + 1+ctx->nsym + nrsym; | 242 | pehdr.nsyms = 1+PEOBJ_NSECTIONS*2 + 1+ctx->nsym + nrsym; |
| 234 | #if LJ_TARGET_X64 | 243 | #if LJ_TARGET_X64 |
| 235 | pehdr.nsyms += 1; /* Symbol for lj_err_unwind_win64. */ | 244 | pehdr.nsyms += 1; /* Symbol for lj_err_unwind_win. */ |
| 236 | #endif | 245 | #endif |
| 237 | 246 | ||
| 238 | /* Write PE object header and all sections. */ | 247 | /* Write PE object header and all sections. */ |
| @@ -312,6 +321,19 @@ void emit_peobj(BuildCtx *ctx) | |||
| 312 | reloc.type = PEOBJ_RELOC_ADDR32NB; | 321 | reloc.type = PEOBJ_RELOC_ADDR32NB; |
| 313 | owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); | 322 | owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); |
| 314 | } | 323 | } |
| 324 | #elif LJ_TARGET_X86 | ||
| 325 | /* Write .sxdata section. */ | ||
| 326 | for (i = 0; i < nrsym; i++) { | ||
| 327 | if (!strcmp(ctx->relocsym[i], "_lj_err_unwind_win")) { | ||
| 328 | uint32_t symidx = 1+2+i; | ||
| 329 | owrite(ctx, &symidx, 4); | ||
| 330 | break; | ||
| 331 | } | ||
| 332 | } | ||
| 333 | if (i == nrsym) { | ||
| 334 | fprintf(stderr, "Error: extern lj_err_unwind_win not used\n"); | ||
| 335 | exit(1); | ||
| 336 | } | ||
| 315 | #endif | 337 | #endif |
| 316 | 338 | ||
| 317 | /* Write .rdata$Z section. */ | 339 | /* Write .rdata$Z section. */ |
| @@ -333,8 +355,10 @@ void emit_peobj(BuildCtx *ctx) | |||
| 333 | #if LJ_TARGET_X64 | 355 | #if LJ_TARGET_X64 |
| 334 | emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_PDATA); | 356 | emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_PDATA); |
| 335 | emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_XDATA); | 357 | emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_XDATA); |
| 336 | emit_peobj_sym(ctx, "lj_err_unwind_win64", 0, | 358 | emit_peobj_sym(ctx, "lj_err_unwind_win", 0, |
| 337 | PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN); | 359 | PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN); |
| 360 | #elif LJ_TARGET_X86 | ||
| 361 | emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_SXDATA); | ||
| 338 | #endif | 362 | #endif |
| 339 | 363 | ||
| 340 | emit_peobj_sym(ctx, ctx->beginsym, 0, | 364 | emit_peobj_sym(ctx, ctx->beginsym, 0, |
diff --git a/src/lj_err.c b/src/lj_err.c index a847ca07..1314c8db 100644 --- a/src/lj_err.c +++ b/src/lj_err.c | |||
| @@ -46,7 +46,8 @@ | |||
| 46 | ** the wrapper function feature. Lua errors thrown through C++ frames | 46 | ** the wrapper function feature. Lua errors thrown through C++ frames |
| 47 | ** cannot be caught by C++ code and C++ destructors are not run. | 47 | ** cannot be caught by C++ code and C++ destructors are not run. |
| 48 | ** | 48 | ** |
| 49 | ** EXT is the default on x64 systems, INT is the default on all other systems. | 49 | ** EXT is the default on x64 systems and on Windows, INT is the default on all |
| 50 | ** other systems. | ||
| 50 | ** | 51 | ** |
| 51 | ** EXT can be manually enabled on POSIX systems using GCC and DWARF2 stack | 52 | ** EXT can be manually enabled on POSIX systems using GCC and DWARF2 stack |
| 52 | ** unwinding with -DLUAJIT_UNWIND_EXTERNAL. *All* C code must be compiled | 53 | ** unwinding with -DLUAJIT_UNWIND_EXTERNAL. *All* C code must be compiled |
| @@ -55,7 +56,6 @@ | |||
| 55 | ** and all C libraries that have callbacks which may be used to call back | 56 | ** and all C libraries that have callbacks which may be used to call back |
| 56 | ** into Lua. C++ code must *not* be compiled with -fno-exceptions. | 57 | ** into Lua. C++ code must *not* be compiled with -fno-exceptions. |
| 57 | ** | 58 | ** |
| 58 | ** EXT cannot be enabled on WIN32 since system exceptions use code-driven SEH. | ||
| 59 | ** EXT is mandatory on WIN64 since the calling convention has an abundance | 59 | ** EXT is mandatory on WIN64 since the calling convention has an abundance |
| 60 | ** of callee-saved registers (rbx, rbp, rsi, rdi, r12-r15, xmm6-xmm15). | 60 | ** of callee-saved registers (rbx, rbp, rsi, rdi, r12-r15, xmm6-xmm15). |
| 61 | ** The POSIX/x64 interpreter only saves r12/r13 for INT (e.g. PS4). | 61 | ** The POSIX/x64 interpreter only saves r12/r13 for INT (e.g. PS4). |
| @@ -63,7 +63,7 @@ | |||
| 63 | 63 | ||
| 64 | #if defined(__GNUC__) && (LJ_TARGET_X64 || defined(LUAJIT_UNWIND_EXTERNAL)) && !LJ_NO_UNWIND | 64 | #if defined(__GNUC__) && (LJ_TARGET_X64 || defined(LUAJIT_UNWIND_EXTERNAL)) && !LJ_NO_UNWIND |
| 65 | #define LJ_UNWIND_EXT 1 | 65 | #define LJ_UNWIND_EXT 1 |
| 66 | #elif LJ_TARGET_X64 && LJ_TARGET_WINDOWS | 66 | #elif LJ_TARGET_WINDOWS |
| 67 | #define LJ_UNWIND_EXT 1 | 67 | #define LJ_UNWIND_EXT 1 |
| 68 | #endif | 68 | #endif |
| 69 | 69 | ||
| @@ -384,7 +384,7 @@ static void err_raise_ext(int errcode) | |||
| 384 | 384 | ||
| 385 | #endif /* LJ_TARGET_ARM */ | 385 | #endif /* LJ_TARGET_ARM */ |
| 386 | 386 | ||
| 387 | #elif LJ_TARGET_X64 && LJ_ABI_WIN | 387 | #elif LJ_ABI_WIN |
| 388 | 388 | ||
| 389 | /* | 389 | /* |
| 390 | ** Someone in Redmond owes me several days of my life. A lot of this is | 390 | ** Someone in Redmond owes me several days of my life. A lot of this is |
| @@ -402,6 +402,7 @@ static void err_raise_ext(int errcode) | |||
| 402 | #define WIN32_LEAN_AND_MEAN | 402 | #define WIN32_LEAN_AND_MEAN |
| 403 | #include <windows.h> | 403 | #include <windows.h> |
| 404 | 404 | ||
| 405 | #if LJ_TARGET_X64 | ||
| 405 | /* Taken from: http://www.nynaeve.net/?p=99 */ | 406 | /* Taken from: http://www.nynaeve.net/?p=99 */ |
| 406 | typedef struct UndocumentedDispatcherContext { | 407 | typedef struct UndocumentedDispatcherContext { |
| 407 | ULONG64 ControlPc; | 408 | ULONG64 ControlPc; |
| @@ -416,11 +417,14 @@ typedef struct UndocumentedDispatcherContext { | |||
| 416 | ULONG ScopeIndex; | 417 | ULONG ScopeIndex; |
| 417 | ULONG Fill0; | 418 | ULONG Fill0; |
| 418 | } UndocumentedDispatcherContext; | 419 | } UndocumentedDispatcherContext; |
| 420 | #else | ||
| 421 | typedef void *UndocumentedDispatcherContext; | ||
| 422 | #endif | ||
| 419 | 423 | ||
| 420 | /* Another wild guess. */ | 424 | /* Another wild guess. */ |
| 421 | extern void __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow); | 425 | extern void __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow); |
| 422 | 426 | ||
| 423 | #ifdef MINGW_SDK_INIT | 427 | #if LJ_TARGET_X64 && defined(MINGW_SDK_INIT) |
| 424 | /* Workaround for broken MinGW64 declaration. */ | 428 | /* Workaround for broken MinGW64 declaration. */ |
| 425 | VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx"); | 429 | VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx"); |
| 426 | #define RtlUnwindEx RtlUnwindEx_FIXED | 430 | #define RtlUnwindEx RtlUnwindEx_FIXED |
| @@ -434,10 +438,15 @@ VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx"); | |||
| 434 | #define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff) | 438 | #define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff) |
| 435 | #define LJ_EXCODE_ERRCODE(cl) ((int)((cl) & 0xff)) | 439 | #define LJ_EXCODE_ERRCODE(cl) ((int)((cl) & 0xff)) |
| 436 | 440 | ||
| 437 | /* Win64 exception handler for interpreter frame. */ | 441 | /* Windows exception handler for interpreter frame. */ |
| 438 | LJ_FUNCA EXCEPTION_DISPOSITION lj_err_unwind_win64(EXCEPTION_RECORD *rec, | 442 | LJ_FUNCA EXCEPTION_DISPOSITION lj_err_unwind_win(EXCEPTION_RECORD *rec, |
| 439 | void *cf, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch) | 443 | void *f, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch) |
| 440 | { | 444 | { |
| 445 | #if LJ_TARGET_X64 | ||
| 446 | void *cf = f; | ||
| 447 | #else | ||
| 448 | void *cf = (char *)f - CFRAME_OFS_SEH; | ||
| 449 | #endif | ||
| 441 | lua_State *L = cframe_L(cf); | 450 | lua_State *L = cframe_L(cf); |
| 442 | int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ? | 451 | int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ? |
| 443 | LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN; | 452 | LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN; |
| @@ -457,6 +466,7 @@ LJ_FUNCA EXCEPTION_DISPOSITION lj_err_unwind_win64(EXCEPTION_RECORD *rec, | |||
| 457 | /* Don't catch access violations etc. */ | 466 | /* Don't catch access violations etc. */ |
| 458 | return ExceptionContinueSearch; | 467 | return ExceptionContinueSearch; |
| 459 | } | 468 | } |
| 469 | #if LJ_TARGET_X64 | ||
| 460 | /* Unwind the stack and call all handlers for all lower C frames | 470 | /* Unwind the stack and call all handlers for all lower C frames |
| 461 | ** (including ourselves) again with EH_UNWINDING set. Then set | 471 | ** (including ourselves) again with EH_UNWINDING set. Then set |
| 462 | ** rsp = cf, rax = errcode and jump to the specified target. | 472 | ** rsp = cf, rax = errcode and jump to the specified target. |
| @@ -466,6 +476,18 @@ LJ_FUNCA EXCEPTION_DISPOSITION lj_err_unwind_win64(EXCEPTION_RECORD *rec, | |||
| 466 | lj_vm_unwind_c_eh), | 476 | lj_vm_unwind_c_eh), |
| 467 | rec, (void *)(uintptr_t)errcode, ctx, dispatch->HistoryTable); | 477 | rec, (void *)(uintptr_t)errcode, ctx, dispatch->HistoryTable); |
| 468 | /* RtlUnwindEx should never return. */ | 478 | /* RtlUnwindEx should never return. */ |
| 479 | #else | ||
| 480 | UNUSED(ctx); | ||
| 481 | UNUSED(dispatch); | ||
| 482 | /* Call all handlers for all lower C frames (including ourselves) again | ||
| 483 | ** with EH_UNWINDING set. Then call the specified function, passing cf | ||
| 484 | ** and errcode. | ||
| 485 | */ | ||
| 486 | lj_vm_rtlunwind(cf, (void *)rec, | ||
| 487 | (cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? | ||
| 488 | (void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode); | ||
| 489 | /* lj_vm_rtlunwind does not return. */ | ||
| 490 | #endif | ||
| 469 | } | 491 | } |
| 470 | } | 492 | } |
| 471 | return ExceptionContinueSearch; | 493 | return ExceptionContinueSearch; |
diff --git a/src/lj_frame.h b/src/lj_frame.h index fc0e281c..db2e4da1 100644 --- a/src/lj_frame.h +++ b/src/lj_frame.h | |||
| @@ -116,6 +116,17 @@ enum { LJ_CONT_TAILCALL, LJ_CONT_FFI_CALLBACK }; /* Special continuations. */ | |||
| 116 | 116 | ||
| 117 | /* These definitions must match with the arch-specific *.dasc files. */ | 117 | /* These definitions must match with the arch-specific *.dasc files. */ |
| 118 | #if LJ_TARGET_X86 | 118 | #if LJ_TARGET_X86 |
| 119 | #if LJ_ABI_WIN | ||
| 120 | #define CFRAME_OFS_ERRF (19*4) | ||
| 121 | #define CFRAME_OFS_NRES (18*4) | ||
| 122 | #define CFRAME_OFS_PREV (17*4) | ||
| 123 | #define CFRAME_OFS_L (16*4) | ||
| 124 | #define CFRAME_OFS_SEH (9*4) | ||
| 125 | #define CFRAME_OFS_PC (6*4) | ||
| 126 | #define CFRAME_OFS_MULTRES (5*4) | ||
| 127 | #define CFRAME_SIZE (16*4) | ||
| 128 | #define CFRAME_SHIFT_MULTRES 0 | ||
| 129 | #else | ||
| 119 | #define CFRAME_OFS_ERRF (15*4) | 130 | #define CFRAME_OFS_ERRF (15*4) |
| 120 | #define CFRAME_OFS_NRES (14*4) | 131 | #define CFRAME_OFS_NRES (14*4) |
| 121 | #define CFRAME_OFS_PREV (13*4) | 132 | #define CFRAME_OFS_PREV (13*4) |
| @@ -124,6 +135,7 @@ enum { LJ_CONT_TAILCALL, LJ_CONT_FFI_CALLBACK }; /* Special continuations. */ | |||
| 124 | #define CFRAME_OFS_MULTRES (5*4) | 135 | #define CFRAME_OFS_MULTRES (5*4) |
| 125 | #define CFRAME_SIZE (12*4) | 136 | #define CFRAME_SIZE (12*4) |
| 126 | #define CFRAME_SHIFT_MULTRES 0 | 137 | #define CFRAME_SHIFT_MULTRES 0 |
| 138 | #endif | ||
| 127 | #elif LJ_TARGET_X64 | 139 | #elif LJ_TARGET_X64 |
| 128 | #if LJ_ABI_WIN | 140 | #if LJ_ABI_WIN |
| 129 | #define CFRAME_OFS_PREV (13*8) | 141 | #define CFRAME_OFS_PREV (13*8) |
diff --git a/src/lj_vm.h b/src/lj_vm.h index be35295d..d605b143 100644 --- a/src/lj_vm.h +++ b/src/lj_vm.h | |||
| @@ -17,6 +17,10 @@ LJ_ASMF int lj_vm_cpcall(lua_State *L, lua_CFunction func, void *ud, | |||
| 17 | LJ_ASMF int lj_vm_resume(lua_State *L, TValue *base, int nres1, ptrdiff_t ef); | 17 | LJ_ASMF int lj_vm_resume(lua_State *L, TValue *base, int nres1, ptrdiff_t ef); |
| 18 | LJ_ASMF_NORET void LJ_FASTCALL lj_vm_unwind_c(void *cframe, int errcode); | 18 | LJ_ASMF_NORET void LJ_FASTCALL lj_vm_unwind_c(void *cframe, int errcode); |
| 19 | LJ_ASMF_NORET void LJ_FASTCALL lj_vm_unwind_ff(void *cframe); | 19 | LJ_ASMF_NORET void LJ_FASTCALL lj_vm_unwind_ff(void *cframe); |
| 20 | #if LJ_ABI_WIN && LJ_TARGET_X86 | ||
| 21 | LJ_ASMF_NORET void LJ_FASTCALL lj_vm_rtlunwind(void *cframe, void *excptrec, | ||
| 22 | void *unwinder, int errcode); | ||
| 23 | #endif | ||
| 20 | LJ_ASMF void lj_vm_unwind_c_eh(void); | 24 | LJ_ASMF void lj_vm_unwind_c_eh(void); |
| 21 | LJ_ASMF void lj_vm_unwind_ff_eh(void); | 25 | LJ_ASMF void lj_vm_unwind_ff_eh(void); |
| 22 | #if LJ_TARGET_X86ORX64 | 26 | #if LJ_TARGET_X86ORX64 |
diff --git a/src/vm_x86.dasc b/src/vm_x86.dasc index f108c0b5..39ccaa2e 100644 --- a/src/vm_x86.dasc +++ b/src/vm_x86.dasc | |||
| @@ -121,19 +121,68 @@ | |||
| 121 | |//----------------------------------------------------------------------- | 121 | |//----------------------------------------------------------------------- |
| 122 | |.if not X64 // x86 stack layout. | 122 | |.if not X64 // x86 stack layout. |
| 123 | | | 123 | | |
| 124 | |.define CFRAME_SPACE, aword*7 // Delta for esp (see <--). | 124 | |.if WIN |
| 125 | | | ||
| 126 | |.define CFRAME_SPACE, aword*9 // Delta for esp (see <--). | ||
| 125 | |.macro saveregs_ | 127 | |.macro saveregs_ |
| 126 | | push edi; push esi; push ebx | 128 | | push edi; push esi; push ebx |
| 129 | | push extern lj_err_unwind_win | ||
| 130 | | fs; push dword [0] | ||
| 131 | | fs; mov [0], esp | ||
| 127 | | sub esp, CFRAME_SPACE | 132 | | sub esp, CFRAME_SPACE |
| 128 | |.endmacro | 133 | |.endmacro |
| 129 | |.macro saveregs | 134 | |.macro restoreregs |
| 130 | | push ebp; saveregs_ | 135 | | add esp, CFRAME_SPACE |
| 136 | | fs; pop dword [0] | ||
| 137 | | pop edi // Short for esp += 4. | ||
| 138 | | pop ebx; pop esi; pop edi; pop ebp | ||
| 139 | |.endmacro | ||
| 140 | | | ||
| 141 | |.else | ||
| 142 | | | ||
| 143 | |.define CFRAME_SPACE, aword*7 // Delta for esp (see <--). | ||
| 144 | |.macro saveregs_ | ||
| 145 | | push edi; push esi; push ebx | ||
| 146 | | sub esp, CFRAME_SPACE | ||
| 131 | |.endmacro | 147 | |.endmacro |
| 132 | |.macro restoreregs | 148 | |.macro restoreregs |
| 133 | | add esp, CFRAME_SPACE | 149 | | add esp, CFRAME_SPACE |
| 134 | | pop ebx; pop esi; pop edi; pop ebp | 150 | | pop ebx; pop esi; pop edi; pop ebp |
| 135 | |.endmacro | 151 | |.endmacro |
| 136 | | | 152 | | |
| 153 | |.endif | ||
| 154 | | | ||
| 155 | |.macro saveregs | ||
| 156 | | push ebp; saveregs_ | ||
| 157 | |.endmacro | ||
| 158 | | | ||
| 159 | |.if WIN | ||
| 160 | |.define SAVE_ERRF, aword [esp+aword*19] // vm_pcall/vm_cpcall only. | ||
| 161 | |.define SAVE_NRES, aword [esp+aword*18] | ||
| 162 | |.define SAVE_CFRAME, aword [esp+aword*17] | ||
| 163 | |.define SAVE_L, aword [esp+aword*16] | ||
| 164 | |//----- 16 byte aligned, ^^^ arguments from C caller | ||
| 165 | |.define SAVE_RET, aword [esp+aword*15] //<-- esp entering interpreter. | ||
| 166 | |.define SAVE_R4, aword [esp+aword*14] | ||
| 167 | |.define SAVE_R3, aword [esp+aword*13] | ||
| 168 | |.define SAVE_R2, aword [esp+aword*12] | ||
| 169 | |//----- 16 byte aligned | ||
| 170 | |.define SAVE_R1, aword [esp+aword*11] | ||
| 171 | |.define SEH_FUNC, aword [esp+aword*10] | ||
| 172 | |.define SEH_NEXT, aword [esp+aword*9] //<-- esp after register saves. | ||
| 173 | |.define UNUSED2, aword [esp+aword*8] | ||
| 174 | |//----- 16 byte aligned | ||
| 175 | |.define UNUSED1, aword [esp+aword*7] | ||
| 176 | |.define SAVE_PC, aword [esp+aword*6] | ||
| 177 | |.define TMP2, aword [esp+aword*5] | ||
| 178 | |.define TMP1, aword [esp+aword*4] | ||
| 179 | |//----- 16 byte aligned | ||
| 180 | |.define ARG4, aword [esp+aword*3] | ||
| 181 | |.define ARG3, aword [esp+aword*2] | ||
| 182 | |.define ARG2, aword [esp+aword*1] | ||
| 183 | |.define ARG1, aword [esp] //<-- esp while in interpreter. | ||
| 184 | |//----- 16 byte aligned, ^^^ arguments for C callee | ||
| 185 | |.else | ||
| 137 | |.define SAVE_ERRF, aword [esp+aword*15] // vm_pcall/vm_cpcall only. | 186 | |.define SAVE_ERRF, aword [esp+aword*15] // vm_pcall/vm_cpcall only. |
| 138 | |.define SAVE_NRES, aword [esp+aword*14] | 187 | |.define SAVE_NRES, aword [esp+aword*14] |
| 139 | |.define SAVE_CFRAME, aword [esp+aword*13] | 188 | |.define SAVE_CFRAME, aword [esp+aword*13] |
| @@ -154,6 +203,7 @@ | |||
| 154 | |.define ARG2, aword [esp+aword*1] | 203 | |.define ARG2, aword [esp+aword*1] |
| 155 | |.define ARG1, aword [esp] //<-- esp while in interpreter. | 204 | |.define ARG1, aword [esp] //<-- esp while in interpreter. |
| 156 | |//----- 16 byte aligned, ^^^ arguments for C callee | 205 | |//----- 16 byte aligned, ^^^ arguments for C callee |
| 206 | |.endif | ||
| 157 | | | 207 | | |
| 158 | |// FPARGx overlaps ARGx and ARG(x+1) on x86. | 208 | |// FPARGx overlaps ARGx and ARG(x+1) on x86. |
| 159 | |.define FPARG3, qword [esp+qword*1] | 209 | |.define FPARG3, qword [esp+qword*1] |
| @@ -554,6 +604,10 @@ static void build_subroutines(BuildCtx *ctx) | |||
| 554 | |.else | 604 | |.else |
| 555 | | mov eax, FCARG2 // Error return status for vm_pcall. | 605 | | mov eax, FCARG2 // Error return status for vm_pcall. |
| 556 | | mov esp, FCARG1 | 606 | | mov esp, FCARG1 |
| 607 | |.if WIN | ||
| 608 | | lea FCARG1, SEH_NEXT | ||
| 609 | | fs; mov [0], FCARG1 | ||
| 610 | |.endif | ||
| 557 | |.endif | 611 | |.endif |
| 558 | |->vm_unwind_c_eh: // Landing pad for external unwinder. | 612 | |->vm_unwind_c_eh: // Landing pad for external unwinder. |
| 559 | | mov L:RB, SAVE_L | 613 | | mov L:RB, SAVE_L |
| @@ -577,6 +631,10 @@ static void build_subroutines(BuildCtx *ctx) | |||
| 577 | |.else | 631 | |.else |
| 578 | | and FCARG1, CFRAME_RAWMASK | 632 | | and FCARG1, CFRAME_RAWMASK |
| 579 | | mov esp, FCARG1 | 633 | | mov esp, FCARG1 |
| 634 | |.if WIN | ||
| 635 | | lea FCARG1, SEH_NEXT | ||
| 636 | | fs; mov [0], FCARG1 | ||
| 637 | |.endif | ||
| 580 | |.endif | 638 | |.endif |
| 581 | |->vm_unwind_ff_eh: // Landing pad for external unwinder. | 639 | |->vm_unwind_ff_eh: // Landing pad for external unwinder. |
| 582 | | mov L:RB, SAVE_L | 640 | | mov L:RB, SAVE_L |
| @@ -590,6 +648,19 @@ static void build_subroutines(BuildCtx *ctx) | |||
| 590 | | set_vmstate INTERP | 648 | | set_vmstate INTERP |
| 591 | | jmp ->vm_returnc // Increments RD/MULTRES and returns. | 649 | | jmp ->vm_returnc // Increments RD/MULTRES and returns. |
| 592 | | | 650 | | |
| 651 | |.if WIN and not X64 | ||
| 652 | |->vm_rtlunwind@16: // Thin layer around RtlUnwind. | ||
| 653 | | // (void *cframe, void *excptrec, void *unwinder, int errcode) | ||
| 654 | | mov [esp], FCARG1 // Return value for RtlUnwind. | ||
| 655 | | push FCARG2 // Exception record for RtlUnwind. | ||
| 656 | | push 0 // Ignored by RtlUnwind. | ||
| 657 | | push dword [FCARG1+CFRAME_OFS_SEH] | ||
| 658 | | call extern RtlUnwind@16 // Violates ABI (clobbers too much). | ||
| 659 | | mov FCARG1, eax | ||
| 660 | | mov FCARG2, [esp+4] // errcode (for vm_unwind_c). | ||
| 661 | | ret // Jump to unwinder. | ||
| 662 | |.endif | ||
| 663 | | | ||
| 593 | |//----------------------------------------------------------------------- | 664 | |//----------------------------------------------------------------------- |
| 594 | |//-- Grow stack for calls ----------------------------------------------- | 665 | |//-- Grow stack for calls ----------------------------------------------- |
| 595 | |//----------------------------------------------------------------------- | 666 | |//----------------------------------------------------------------------- |
