Browse Source

Major rewrite of error handling to allow external/internal unwinding.

Make external unwinding the default on x64.
It's mandatory on WIN64 due to the abundance of callee-saved regs.
Allow piecewise internal frame unwinding and optional cleanup.
Store ERRMEM, ERRERR and ERRCPP early and copy down later.
Use FRAME_CP for lj_vm_resume.
Add lj_vm_unwind_*_eh variants as landing pads for external unwinder.
Use fastcall for lj_vm_unwind_*.
Can drop r12/r13 saves in POSIX/x64 interpreter now.
Mike Pall 15 years ago
parent
commit
93ee10642e
6 changed files with 851 additions and 705 deletions
  1. 11 19
      src/buildvm_x86.dasc
  2. 561 557
      src/buildvm_x86.h
  3. 273 126
      src/lj_err.c
  4. 1 0
      src/lj_err.h
  5. 1 1
      src/lj_frame.h
  6. 4 2
      src/lj_vm.h

+ 11 - 19
src/buildvm_x86.dasc

@@ -213,18 +213,16 @@
 |
 |.define CFRAME_SPACE,	aword*5			// Delta for rsp (see <--).
 |.macro saveregs
-|  push rbp; push rbx; push r15; push r14; push r13; push r12
+|  push rbp; push rbx; push r15; push r14
 |  sub rsp, CFRAME_SPACE
 |.endmacro
 |.macro restoreregs
 |  add rsp, CFRAME_SPACE
-|  pop r12; pop r13; pop r14; pop r15; pop rbx; pop rbp
+|  pop r14; pop r15; pop rbx; pop rbp
 |.endmacro
 |
 |//----- 16 byte aligned,
-|.define SAVE_RET,	aword [rsp+aword*11]	//<-- rsp entering interpreter.
-|.define SAVE_R6,	aword [rsp+aword*10]
-|.define SAVE_R5,	aword [rsp+aword*9]
+|.define SAVE_RET,	aword [rsp+aword*9]	//<-- rsp entering interpreter.
 |.define SAVE_R4,	aword [rsp+aword*8]
 |.define SAVE_R3,	aword [rsp+aword*7]
 |.define SAVE_R2,	aword [rsp+aword*6]
@@ -621,10 +619,10 @@ static void build_subroutines(BuildCtx *ctx, int cmov, int sse)
   |  mov eax, CARG2d			// Error return status for vm_pcall.
   |  mov rsp, CARG1
   |.else
-  |  mov ecx, [esp+4]
-  |  mov eax, [esp+8]			// Error return status for vm_pcall.
-  |  mov esp, ecx
+  |  mov eax, FCARG2			// Error return status for vm_pcall.
+  |  mov esp, FCARG1
   |.endif
+  |->vm_unwind_c_eh:			// Landing pad for external unwinder.
   |  mov L:RB, SAVE_L
   |  mov GL:RB, L:RB->glref
   |  mov dword GL:RB->vmstate, ~LJ_VMST_C
@@ -636,10 +634,10 @@ static void build_subroutines(BuildCtx *ctx, int cmov, int sse)
   |  and CARG1, CFRAME_RAWMASK
   |  mov rsp, CARG1
   |.else
-  |  mov ecx, [esp+4]
-  |  and ecx, CFRAME_RAWMASK
-  |  mov esp, ecx
+  |  and FCARG1, CFRAME_RAWMASK
+  |  mov esp, FCARG1
   |.endif
+  |->vm_unwind_ff_eh:			// Landing pad for external unwinder.
   |  mov L:RB, SAVE_L
   |  mov RAa, -8			// Results start at BASE+RA = BASE-8.
   |  mov RD, 1+1			// Really 1+2 results, incr. later.
@@ -718,7 +716,7 @@ static void build_subroutines(BuildCtx *ctx, int cmov, int sse)
   |  mov L:RB, SAVE_L
   |  mov RA, INARG_BASE			// Caveat: overlaps SAVE_CFRAME!
   |.endif
-  |  mov PC, FRAME_C
+  |  mov PC, FRAME_CP
   |  xor RD, RD
   |  lea KBASEa, [esp+CFRAME_RESUME]
   |  mov DISPATCH, L:RB->glref		// Setup pointer to dispatch table.
@@ -4689,7 +4687,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop, int cmov, int sse)
 	|  movsd FOR_IDX, xmm0
 	|  test RB, RB; js >3
       } else {
-        |  jl >3
+	|  jl >3
       }
       |  ucomisd xmm1, xmm0
       |1:
@@ -4876,8 +4874,6 @@ static void emit_asm_debug(BuildCtx *ctx)
 	"\t.byte 0x83\n\t.uleb128 0x3\n"	/* offset rbx */
 	"\t.byte 0x8f\n\t.uleb128 0x4\n"	/* offset r15 */
 	"\t.byte 0x8e\n\t.uleb128 0x5\n"	/* offset r14 */
-	"\t.byte 0x8d\n\t.uleb128 0x6\n"	/* offset r13 */
-	"\t.byte 0x8c\n\t.uleb128 0x7\n"	/* offset r12 */
 #else
 	"\t.byte 0x85\n\t.uleb128 0x2\n"	/* offset ebp */
 	"\t.byte 0x87\n\t.uleb128 0x3\n"	/* offset edi */
@@ -4919,8 +4915,6 @@ static void emit_asm_debug(BuildCtx *ctx)
 	"\t.byte 0x83\n\t.uleb128 0x3\n"	/* offset rbx */
 	"\t.byte 0x8f\n\t.uleb128 0x4\n"	/* offset r15 */
 	"\t.byte 0x8e\n\t.uleb128 0x5\n"	/* offset r14 */
-	"\t.byte 0x8d\n\t.uleb128 0x6\n"	/* offset r13 */
-	"\t.byte 0x8c\n\t.uleb128 0x7\n"	/* offset r12 */
 #else
 	"\t.byte 0x85\n\t.uleb128 0x2\n"	/* offset ebp */
 	"\t.byte 0x87\n\t.uleb128 0x3\n"	/* offset edi */
@@ -4971,8 +4965,6 @@ static void emit_asm_debug(BuildCtx *ctx)
 	"\t.byte 0x83\n\t.uleb128 0x3\n"	/* offset rbx */
 	"\t.byte 0x8f\n\t.uleb128 0x4\n"	/* offset r15 */
 	"\t.byte 0x8e\n\t.uleb128 0x5\n"	/* offset r14 */
-	"\t.byte 0x8d\n\t.uleb128 0x6\n"	/* offset r13 */
-	"\t.byte 0x8c\n\t.uleb128 0x7\n"	/* offset r12 */
 #else
 	"\t.byte 0x84\n\t.byte 0x2\n"		/* offset ebp (4 for MACH-O)*/
 	"\t.byte 0x87\n\t.byte 0x3\n"		/* offset edi */

File diff suppressed because it is too large
+ 561 - 557
src/buildvm_x86.h


+ 273 - 126
src/lj_err.c

@@ -20,6 +20,63 @@
 #include "lj_trace.h"
 #include "lj_vm.h"
 
+/*
+** LuaJIT can either use internal or external frame unwinding:
+**
+** - Internal frame unwinding (INT) is free-standing and doesn't require
+**   any OS or library support.
+**
+** - External frame unwinding (EXT) uses the system-provided unwind handler.
+**
+** 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 for non-C++ code.
+**
+** - INT is faster when actually throwing errors (but this happens rarely).
+**   Setting up error handlers is zero-cost in any case.
+**
+** - 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
+**   are converted to the string "C++ exception". Lua errors can be caught
+**   with catch (...) in C++.
+**
+** - INT has only limited support for automatically catching C++ exceptions
+**   on POSIX systems using DWARF2 stack unwinding. Other systems may use
+**   the wrapper function feature. Lua errors thrown through C++ frames
+**   cannot be caught by C++ code and C++ destructors are not run.
+**
+** INT is the default on x86 systems, EXT is the default on x64 systems.
+**
+** EXT can only be manually enabled on POSIX/x86 systems using 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.
+**
+** EXT cannot be enabled on WIN32 since system exceptions use code-driven SEH.
+** EXT is mandatory on WIN64 since the calling convention has an abundance
+** of callee-saved registers (rbx, rbp, rsi, rdi, r12-r15, xmm6-xmm15).
+** EXT is mandatory on POSIX/x64 since the interpreter doesn't save r12/r13.
+*/
+
+#if defined(__ELF__) || defined(__MACH__)
+#if LJ_TARGET_X86
+#ifdef LUAJIT_UNWIND_EXTERNAL
+#define LJ_UNWIND_EXT	1
+#endif
+#elif LJ_TARGET_X64
+#define LJ_UNWIND_EXT	1
+#endif
+#elif defined(LUA_USE_WIN)
+#if LJ_TARGET_X64
+#define LJ_UNWIND_EXT	1
+#endif
+#endif
+
 /* -- Error messages ------------------------------------------------------ */
 
 /* Error message strings. */
@@ -374,117 +431,249 @@ LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar)
   }
 }
 
-/* -- Error handling ------------------------------------------------------ */
-
-/* Return string object for error message. */
-LJ_NOINLINE GCstr *lj_err_str(lua_State *L, ErrMsg em)
-{
-  return lj_str_newz(L, err2msg(em));
-}
+/* -- Internal frame unwinding -------------------------------------------- */
 
-/* Unwind Lua stack and add error message on top. */
-LJ_NOINLINE static void unwindstack(lua_State *L, TValue *top, int errcode)
+/* Unwind Lua stack and move error message to new top. */
+LJ_NOINLINE static void unwindstack(lua_State *L, TValue *top)
 {
   lj_func_closeuv(L, top);
-  switch (errcode) {
-  case LUA_ERRMEM:
-    setstrV(L, top, lj_err_str(L, LJ_ERR_ERRMEM));
-    break;
-  case LUA_ERRERR:
-    setstrV(L, top, lj_err_str(L, LJ_ERR_ERRERR));
-    break;
-  case LUA_ERRSYNTAX:
-  case LUA_ERRRUN:
-    copyTV(L, top, L->top - 1);
-    break;
-  default:
-    lua_assert(0);
-    break;
+  if (top < L->top-1) {
+    copyTV(L, top, L->top-1);
+    L->top = top+1;
   }
-  L->top = top+1;
   lj_state_relimitstack(L);
 }
 
-/* Throw error. Find catch frame, unwind stack and continue. */
-LJ_NOINLINE void lj_err_throw(lua_State *L, int errcode)
+/* Unwind until stop frame. Optionally cleanup frames. */
+static void *err_unwind(lua_State *L, void *stopcf, int errcode)
 {
   TValue *frame = L->base-1;
   void *cf = L->cframe;
-  global_State *g = G(L);
-  if (L->status == LUA_ERRERR+1) {  /* Don't touch the stack during lua_open. */
-    lj_vm_unwind_c(cf, errcode);
-    goto uncaught;  /* unreachable */
-  }
-  lj_trace_abort(g);
-  setgcrefnull(g->jit_L);
-  L->status = 0;
   while (cf) {
-    if (cframe_nres(cframe_raw(cf)) < 0) {  /* cframe without frame? */
-      TValue *top = restorestack(L, -cframe_nres(cf));
-      if (frame < top) {
-	L->cframe = cframe_prev(cf);
-	L->base = frame+1;
-	unwindstack(L, top, errcode);
-	lj_vm_unwind_c(cf, errcode);
-	goto uncaught;  /* unreachable */
+    int32_t nres = cframe_nres(cframe_raw(cf));
+    if (nres < 0) {  /* C frame without Lua frame? */
+      TValue *top = restorestack(L, -nres);
+      if (frame < top) {  /* Frame reached? */
+	if (errcode) {
+	  L->cframe = cframe_prev(cf);
+	  L->base = frame+1;
+	  unwindstack(L, top);
+	}
+	return cf;
       }
     }
     if (frame <= L->stack)
       break;
     switch (frame_typep(frame)) {
-    case FRAME_LUA:
+    case FRAME_LUA:  /* Lua frame. */
     case FRAME_LUAP:
       frame = frame_prevl(frame);
       break;
-    case FRAME_C:
-      if (cframe_canyield(cf)) goto uncaught;
+    case FRAME_C:  /* C frame. */
+#if LJ_UNWIND_EXT
+      if (errcode) {
+	L->cframe = cframe_prev(cf);
+	L->base = frame_prevd(frame) + 1;
+	unwindstack(L, frame);
+      } else if (cf != stopcf) {
+	cf = cframe_prev(cf);
+	frame = frame_prevd(frame);
+	break;
+      }
+      return NULL;  /* Continue unwinding. */
+#else
+      UNUSED(stopcf);
       cf = cframe_prev(cf);
-      /* fallthrough */
-    case FRAME_CONT:
-    case FRAME_VARG:
       frame = frame_prevd(frame);
       break;
-    case FRAME_CP:
-      L->cframe = cframe_prev(cf);
-      L->base = frame_prevd(frame) + 1;
-      unwindstack(L, frame, errcode);
-      lj_vm_unwind_c(cf, errcode);
-      goto uncaught;  /* unreachable */
-    case FRAME_PCALL:
-      hook_leave(g);
+#endif
+    case FRAME_CP:  /* Protected C frame. */
+      if (cframe_canyield(cf)) {  /* Resume? */
+	if (errcode) {
+	  L->cframe = NULL;
+	  L->status = cast_byte(errcode);
+	}
+	return cframe_raw(cf);
+      }
+      if (errcode) {
+	L->cframe = cframe_prev(cf);
+	L->base = frame_prevd(frame) + 1;
+	unwindstack(L, frame);
+      }
+      return cf;
+    case FRAME_CONT:  /* Continuation frame. */
+    case FRAME_VARG:  /* Vararg frame. */
+      frame = frame_prevd(frame);
+      break;
+    case FRAME_PCALL:  /* FF pcall() frame. */
+      if (errcode)
+	hook_leave(G(L));
       /* fallthrough */
-    case FRAME_PCALLH:
-      L->cframe = cf;
-      L->base = frame_prevd(frame) + 1;
-      unwindstack(L, L->base, errcode);
-      lj_vm_unwind_ff(cf);
-      goto uncaught;  /* unreachable */
-    default:
-      lua_assert(0);
-      goto uncaught;
+    case FRAME_PCALLH:  /* FF pcall() frame inside hook. */
+      if (errcode) {
+	L->cframe = cf;
+	L->base = frame_prevd(frame) + 1;
+	unwindstack(L, L->base);
+	return NULL;  /* Call special handler. */
+      }
+      return cf;
     }
   }
-  /* No catch frame found. Must be a resume or an unprotected error. */
-uncaught:
-  L->status = cast_byte(errcode);
-  L->cframe = NULL;
-  if (cframe_canyield(cf)) {  /* Resume? */
-    unwindstack(L, L->top, errcode);
-    lj_vm_unwind_c(cframe_raw(cf), errcode);
+  /* No C frame. */
+  if (errcode) {
+    L->cframe = NULL;
+    L->base = L->stack+1;
+    unwindstack(L, L->base);
+    if (G(L)->panic)
+      G(L)->panic(L);
+    exit(EXIT_FAILURE);
   }
-  /* Better rethrow on main thread than panic. */
-  {
-    if (L != mainthread(g))
-      lj_err_throw(mainthread(g), errcode);
-    if (g->panic) {
-      L->base = L->stack+1;
-      unwindstack(L, L->base, errcode);
-      g->panic(L);
+  return L;  /* Anything not-NULL will do. */
+}
+
+/* -- External frame unwinding -------------------------------------------- */
+
+#if defined(__ELF__) || defined(__MACH__)
+
+#include <unwind.h>
+
+#define LJ_UEXCLASS		0x4c55414a49543200ULL	/* LUAJIT2\0 */
+#define LJ_UEXCLASS_MAKE(c)	(LJ_UEXCLASS | (_Unwind_Exception_Class)(c))
+#define LJ_UEXCLASS_CHECK(cl)	(((cl) ^ LJ_UEXCLASS) <= 0xff)
+#define LJ_UEXCLASS_ERRCODE(cl)	(cast_int((cl) & 0xff))
+
+/* DWARF2 personality handler referenced from interpreter .eh_frame. */
+LJ_FUNCA int lj_err_unwind_dwarf(int version, _Unwind_Action actions,
+  _Unwind_Exception_Class uexclass, struct _Unwind_Exception *uex,
+  struct _Unwind_Context *ctx)
+{
+  void *cf;
+  lua_State *L;
+  if (version != 1)
+    return _URC_FATAL_PHASE1_ERROR;
+  UNUSED(uexclass);
+  cf = (void *)_Unwind_GetCFA(ctx);
+  L = cframe_L(cf);
+  if ((actions & _UA_SEARCH_PHASE)) {
+#if LJ_UNWIND_EXT
+    if (err_unwind(L, cf, 0) == NULL)
+      return _URC_CONTINUE_UNWIND;
+#endif
+    if (!LJ_UEXCLASS_CHECK(uexclass)) {
+      setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP));
+    }
+    return _URC_HANDLER_FOUND;
+  }
+  if ((actions & _UA_CLEANUP_PHASE)) {
+    int errcode;
+    if (LJ_UEXCLASS_CHECK(uexclass)) {
+      errcode = LJ_UEXCLASS_ERRCODE(uexclass);
+    } else {
+      if ((actions & _UA_HANDLER_FRAME))
+	_Unwind_DeleteException(uex);
+      errcode = LUA_ERRRUN;
+    }
+#if LJ_UNWIND_EXT
+    if (err_unwind(L, cf, errcode)) {
+      _Unwind_SetGR(ctx, 0, errcode);
+      _Unwind_SetIP(ctx, (_Unwind_Ptr)lj_vm_unwind_c_eh);
+      return _URC_INSTALL_CONTEXT;
+    } else if ((actions & _UA_HANDLER_FRAME)) {
+      _Unwind_SetIP(ctx, (_Unwind_Ptr)lj_vm_unwind_ff_eh);
+      return _URC_INSTALL_CONTEXT;
     }
+#else
+    /* This is not the proper way to escape from the unwinder. We get away
+    ** with it on x86 because the interpreter restores all callee-saved regs.
+    */
+    lj_err_throw(L, errcode);
+#endif
+  }
+  return _URC_CONTINUE_UNWIND;
+}
+
+#if LJ_UNWIND_EXT
+/* NYI: this is not thread-safe. */
+static struct _Unwind_Exception static_uex;
+
+/* Raise DWARF2 exception. */
+static void err_raise_ext(int errcode)
+{
+  static_uex.exception_class = LJ_UEXCLASS_MAKE(errcode);
+  static_uex.exception_cleanup = NULL;
+  _Unwind_RaiseException(&static_uex);
+}
+#endif
+
+#elif defined(_WIN64)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#define LJ_EXCODE		((DWORD)0x024c4a00)
+#define LJ_EXCODE_MAKE(c)	(LJ_EXCODE | (DWORD)(c))
+#define LJ_EXCODE_CHECK(cl)	(((cl) ^ LJ_EXCODE) <= 0xff)
+#define LJ_EXCODE_ERRCODE(cl)	(cast_int((cl) & 0xff))
+
+/* NYI: Win64 exception handler for interpreter frame. */
+
+/* Raise Windows exception. */
+static void err_raise_ext(int errcode)
+{
+  RaiseException(LJ_EXCODE_MAKE(errcode), 0, 0, NULL);
+}
+
+#endif
+
+/* -- Error handling ------------------------------------------------------ */
+
+/* Throw error. Find catch frame, unwind stack and continue. */
+LJ_NOINLINE void lj_err_throw(lua_State *L, int errcode)
+{
+  global_State *g = G(L);
+  lj_trace_abort(g);
+  setgcrefnull(g->jit_L);
+  L->status = 0;
+#if LJ_UNWIND_EXT
+  err_raise_ext(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 on x86 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
+  {
+    void *cf = err_unwind(L, NULL, errcode);
+    if (cf)
+      lj_vm_unwind_c(cf, errcode);
+    else
+      lj_vm_unwind_ff(cframe_raw(L->cframe));
   }
+#endif
   exit(EXIT_FAILURE);
 }
 
+/* Return string object for error message. */
+LJ_NOINLINE GCstr *lj_err_str(lua_State *L, ErrMsg em)
+{
+  return lj_str_newz(L, err2msg(em));
+}
+
+/* Out-of-memory error. */
+LJ_NOINLINE void lj_err_mem(lua_State *L)
+{
+  if (L->status == LUA_ERRERR+1)  /* Don't touch the stack during lua_open. */
+    lj_vm_unwind_c(L->cframe, LUA_ERRMEM);
+  setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRMEM));
+  lj_err_throw(L, LUA_ERRMEM);
+}
+
 /* Find error function for runtime errors. Requires an extra stack traversal. */
 static ptrdiff_t finderrfunc(lua_State *L)
 {
@@ -507,7 +696,6 @@ static ptrdiff_t finderrfunc(lua_State *L)
       frame = frame_prevl(frame);
       break;
     case FRAME_C:
-      if (cframe_canyield(cf)) return 0;
       cf = cframe_prev(cf);
       /* fallthrough */
     case FRAME_CONT:
@@ -515,6 +703,7 @@ static ptrdiff_t finderrfunc(lua_State *L)
       frame = frame_prevd(frame);
       break;
     case FRAME_CP:
+      if (cframe_canyield(cf)) return 0;
       if (cframe_errfunc(cf) >= 0)
 	return cframe_errfunc(cf);
       frame = frame_prevd(frame);
@@ -540,8 +729,10 @@ LJ_NOINLINE void lj_err_run(lua_State *L)
     TValue *errfunc = restorestack(L, ef);
     TValue *top = L->top;
     lj_trace_abort(G(L));
-    if (!tvisfunc(errfunc) || L->status == LUA_ERRERR)
+    if (!tvisfunc(errfunc) || L->status == LUA_ERRERR) {
+      setstrV(L, top-1, lj_err_str(L, LJ_ERR_ERRERR));
       lj_err_throw(L, LUA_ERRERR);
+    }
     L->status = LUA_ERRERR;
     copyTV(L, top, top-1);
     copyTV(L, top-1, errfunc);
@@ -763,47 +954,3 @@ LUALIB_API int luaL_error(lua_State *L, const char *fmt, ...)
   return 0;  /* unreachable */
 }
 
-/* -- C++ exception support ----------------------------------------------- */
-
-#if defined(__ELF__) || defined(__MACH__)
-typedef enum
-{
-  _URC_NO_REASON,
-  _URC_FOREIGN_EXCEPTION_CAUGHT,
-  _URC_FATAL_PHASE2_ERROR,
-  _URC_FATAL_PHASE1_ERROR,
-  _URC_NORMAL_STOP,
-  _URC_END_OF_STACK,
-  _URC_HANDLER_FOUND,
-  _URC_INSTALL_CONTEXT,
-  _URC_CONTINUE_UNWIND
-} _Unwind_Reason_Code;
-
-#define _UA_SEARCH_PHASE	1
-#define _UA_CLEANUP_PHASE	2
-#define _UA_HANDLER_FRAME	4
-#define _UA_FORCE_UNWIND	8
-#define _UA_END_OF_STACK	16
-
-extern void *_Unwind_GetCFA(void *ctx);
-extern void _Unwind_DeleteException(void *uex);
-
-/* DWARF2 personality handler referenced from .eh_frame. */
-LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions, uint64_t uexclass,
-				 void *uex, void *ctx)
-{
-  if (version != 1)
-    return _URC_FATAL_PHASE1_ERROR;
-  UNUSED(uexclass);
-  if ((actions & _UA_SEARCH_PHASE))
-    return _URC_HANDLER_FOUND;
-  if ((actions & _UA_HANDLER_FRAME)) {
-    void *cf = _Unwind_GetCFA(ctx);
-    lua_State *L = cframe_L(cf);
-    _Unwind_DeleteException(uex);
-    lj_err_msg(L, LJ_ERR_ERRCPP);
-  }
-  return _URC_CONTINUE_UNWIND;
-}
-#endif
-

+ 1 - 0
src/lj_err.h

@@ -19,6 +19,7 @@ typedef enum {
 
 LJ_FUNC GCstr *lj_err_str(lua_State *L, ErrMsg em);
 LJ_FUNC_NORET void lj_err_throw(lua_State *L, int errcode);
+LJ_FUNC_NORET void lj_err_mem(lua_State *L);
 LJ_FUNC_NORET void lj_err_run(lua_State *L);
 LJ_FUNC_NORET void lj_err_msg(lua_State *L, ErrMsg em);
 LJ_FUNC_NORET void lj_err_lex(lua_State *L, const char *src, const char *tok,

+ 1 - 1
src/lj_frame.h

@@ -81,7 +81,7 @@ enum {
 #define CFRAME_OFS_ERRF		(3*4)
 #define CFRAME_OFS_NRES		(2*4)
 #define CFRAME_OFS_MULTRES	(1*4)
-#define CFRAME_SIZE		(12*8)
+#define CFRAME_SIZE		(10*8)
 #endif
 #else
 #error "Missing CFRAME_* definitions for this architecture"

+ 4 - 2
src/lj_vm.h

@@ -15,8 +15,10 @@ typedef TValue *(*lua_CPFunction)(lua_State *L, lua_CFunction func, void *ud);
 LJ_ASMF int lj_vm_cpcall(lua_State *L, lua_CFunction func, void *ud,
 			 lua_CPFunction cp);
 LJ_ASMF int lj_vm_resume(lua_State *L, TValue *base, int nres1, ptrdiff_t ef);
-LJ_ASMF_NORET void lj_vm_unwind_c(void *cframe, int errcode);
-LJ_ASMF_NORET void lj_vm_unwind_ff(void *cframe);
+LJ_ASMF_NORET void LJ_FASTCALL lj_vm_unwind_c(void *cframe, int errcode);
+LJ_ASMF_NORET void LJ_FASTCALL lj_vm_unwind_ff(void *cframe);
+LJ_ASMF void lj_vm_unwind_c_eh(void);
+LJ_ASMF void lj_vm_unwind_ff_eh(void);
 
 /* Miscellaneous functions. */
 #if LJ_TARGET_X86ORX64

Some files were not shown because too many files changed in this diff