diff options
Diffstat (limited to 'src/lua/ldo.c')
-rw-r--r-- | src/lua/ldo.c | 125 |
1 files changed, 91 insertions, 34 deletions
diff --git a/src/lua/ldo.c b/src/lua/ldo.c index 4b55c31..aa159cf 100644 --- a/src/lua/ldo.c +++ b/src/lua/ldo.c | |||
@@ -98,11 +98,12 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { | |||
98 | setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); | 98 | setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); |
99 | break; | 99 | break; |
100 | } | 100 | } |
101 | case CLOSEPROTECT: { | 101 | case LUA_OK: { /* special case only for closing upvalues */ |
102 | setnilvalue(s2v(oldtop)); /* no error message */ | 102 | setnilvalue(s2v(oldtop)); /* no error message */ |
103 | break; | 103 | break; |
104 | } | 104 | } |
105 | default: { | 105 | default: { |
106 | lua_assert(errorstatus(errcode)); /* real error */ | ||
106 | setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ | 107 | setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ |
107 | break; | 108 | break; |
108 | } | 109 | } |
@@ -118,17 +119,13 @@ l_noret luaD_throw (lua_State *L, int errcode) { | |||
118 | } | 119 | } |
119 | else { /* thread has no error handler */ | 120 | else { /* thread has no error handler */ |
120 | global_State *g = G(L); | 121 | global_State *g = G(L); |
121 | errcode = luaF_close(L, L->stack, errcode); /* close all upvalues */ | 122 | errcode = luaE_resetthread(L, errcode); /* close all upvalues */ |
122 | L->status = cast_byte(errcode); /* mark it as dead */ | ||
123 | if (g->mainthread->errorJmp) { /* main thread has a handler? */ | 123 | if (g->mainthread->errorJmp) { /* main thread has a handler? */ |
124 | setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ | 124 | setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ |
125 | luaD_throw(g->mainthread, errcode); /* re-throw in main thread */ | 125 | luaD_throw(g->mainthread, errcode); /* re-throw in main thread */ |
126 | } | 126 | } |
127 | else { /* no handler at all; abort */ | 127 | else { /* no handler at all; abort */ |
128 | if (g->panic) { /* panic function? */ | 128 | if (g->panic) { /* panic function? */ |
129 | luaD_seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */ | ||
130 | if (L->ci->top < L->top) | ||
131 | L->ci->top = L->top; /* pushing msg. can break this invariant */ | ||
132 | lua_unlock(L); | 129 | lua_unlock(L); |
133 | g->panic(L); /* call panic function (last chance to jump out) */ | 130 | g->panic(L); /* call panic function (last chance to jump out) */ |
134 | } | 131 | } |
@@ -375,7 +372,7 @@ void luaD_tryfuncTM (lua_State *L, StkId func) { | |||
375 | const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); | 372 | const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); |
376 | StkId p; | 373 | StkId p; |
377 | if (unlikely(ttisnil(tm))) | 374 | if (unlikely(ttisnil(tm))) |
378 | luaG_typeerror(L, s2v(func), "call"); /* nothing to call */ | 375 | luaG_callerror(L, s2v(func)); /* nothing to call */ |
379 | for (p = L->top; p > func; p--) /* open space for metamethod */ | 376 | for (p = L->top; p > func; p--) /* open space for metamethod */ |
380 | setobjs2s(L, p, p-1); | 377 | setobjs2s(L, p, p-1); |
381 | L->top++; /* stack space pre-allocated by the caller */ | 378 | L->top++; /* stack space pre-allocated by the caller */ |
@@ -409,7 +406,7 @@ static void moveresults (lua_State *L, StkId res, int nres, int wanted) { | |||
409 | default: /* multiple results (or to-be-closed variables) */ | 406 | default: /* multiple results (or to-be-closed variables) */ |
410 | if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */ | 407 | if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */ |
411 | ptrdiff_t savedres = savestack(L, res); | 408 | ptrdiff_t savedres = savestack(L, res); |
412 | luaF_close(L, res, LUA_OK); /* may change the stack */ | 409 | luaF_close(L, res, CLOSEKTOP, 0); /* may change the stack */ |
413 | res = restorestack(L, savedres); | 410 | res = restorestack(L, savedres); |
414 | wanted = codeNresults(wanted); /* correct value */ | 411 | wanted = codeNresults(wanted); /* correct value */ |
415 | if (wanted == LUA_MULTRET) | 412 | if (wanted == LUA_MULTRET) |
@@ -596,15 +593,11 @@ static void finishCcall (lua_State *L, int status) { | |||
596 | /* | 593 | /* |
597 | ** Executes "full continuation" (everything in the stack) of a | 594 | ** Executes "full continuation" (everything in the stack) of a |
598 | ** previously interrupted coroutine until the stack is empty (or another | 595 | ** previously interrupted coroutine until the stack is empty (or another |
599 | ** interruption long-jumps out of the loop). If the coroutine is | 596 | ** interruption long-jumps out of the loop). |
600 | ** recovering from an error, 'ud' points to the error status, which must | ||
601 | ** be passed to the first continuation function (otherwise the default | ||
602 | ** status is LUA_YIELD). | ||
603 | */ | 597 | */ |
604 | static void unroll (lua_State *L, void *ud) { | 598 | static void unroll (lua_State *L, void *ud) { |
605 | CallInfo *ci; | 599 | CallInfo *ci; |
606 | if (ud != NULL) /* error status? */ | 600 | UNUSED(ud); |
607 | finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */ | ||
608 | while ((ci = L->ci) != &L->base_ci) { /* something in the stack */ | 601 | while ((ci = L->ci) != &L->base_ci) { /* something in the stack */ |
609 | if (!isLua(ci)) /* C function? */ | 602 | if (!isLua(ci)) /* C function? */ |
610 | finishCcall(L, LUA_YIELD); /* complete its execution */ | 603 | finishCcall(L, LUA_YIELD); /* complete its execution */ |
@@ -631,24 +624,36 @@ static CallInfo *findpcall (lua_State *L) { | |||
631 | 624 | ||
632 | 625 | ||
633 | /* | 626 | /* |
634 | ** Recovers from an error in a coroutine. Finds a recover point (if | 627 | ** Auxiliary structure to call 'recover' in protected mode. |
635 | ** there is one) and completes the execution of the interrupted | ||
636 | ** 'luaD_pcall'. If there is no recover point, returns zero. | ||
637 | */ | 628 | */ |
638 | static int recover (lua_State *L, int status) { | 629 | struct RecoverS { |
639 | StkId oldtop; | 630 | int status; |
640 | CallInfo *ci = findpcall(L); | 631 | CallInfo *ci; |
641 | if (ci == NULL) return 0; /* no recovery point */ | 632 | }; |
633 | |||
634 | |||
635 | /* | ||
636 | ** Recovers from an error in a coroutine: completes the execution of the | ||
637 | ** interrupted 'luaD_pcall', completes the interrupted C function which | ||
638 | ** called 'lua_pcallk', and continues running the coroutine. If there is | ||
639 | ** an error in 'luaF_close', this function will be called again and the | ||
640 | ** coroutine will continue from where it left. | ||
641 | */ | ||
642 | static void recover (lua_State *L, void *ud) { | ||
643 | struct RecoverS *r = cast(struct RecoverS *, ud); | ||
644 | int status = r->status; | ||
645 | CallInfo *ci = r->ci; /* recover point */ | ||
646 | StkId func = restorestack(L, ci->u2.funcidx); | ||
642 | /* "finish" luaD_pcall */ | 647 | /* "finish" luaD_pcall */ |
643 | oldtop = restorestack(L, ci->u2.funcidx); | ||
644 | L->ci = ci; | 648 | L->ci = ci; |
645 | L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ | 649 | L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ |
646 | status = luaF_close(L, oldtop, status); /* may change the stack */ | 650 | luaF_close(L, func, status, 0); /* may change the stack */ |
647 | oldtop = restorestack(L, ci->u2.funcidx); | 651 | func = restorestack(L, ci->u2.funcidx); |
648 | luaD_seterrorobj(L, status, oldtop); | 652 | luaD_seterrorobj(L, status, func); |
649 | luaD_shrinkstack(L); /* restore stack size in case of overflow */ | 653 | luaD_shrinkstack(L); /* restore stack size in case of overflow */ |
650 | L->errfunc = ci->u.c.old_errfunc; | 654 | L->errfunc = ci->u.c.old_errfunc; |
651 | return 1; /* continue running the coroutine */ | 655 | finishCcall(L, status); /* finish 'lua_pcallk' callee */ |
656 | unroll(L, NULL); /* continue running the coroutine */ | ||
652 | } | 657 | } |
653 | 658 | ||
654 | 659 | ||
@@ -698,6 +703,24 @@ static void resume (lua_State *L, void *ud) { | |||
698 | } | 703 | } |
699 | } | 704 | } |
700 | 705 | ||
706 | |||
707 | /* | ||
708 | ** Calls 'recover' in protected mode, repeating while there are | ||
709 | ** recoverable errors, that is, errors inside a protected call. (Any | ||
710 | ** error interrupts 'recover', and this loop protects it again so it | ||
711 | ** can continue.) Stops with a normal end (status == LUA_OK), an yield | ||
712 | ** (status == LUA_YIELD), or an unprotected error ('findpcall' doesn't | ||
713 | ** find a recover point). | ||
714 | */ | ||
715 | static int p_recover (lua_State *L, int status) { | ||
716 | struct RecoverS r; | ||
717 | r.status = status; | ||
718 | while (errorstatus(status) && (r.ci = findpcall(L)) != NULL) | ||
719 | r.status = luaD_rawrunprotected(L, recover, &r); | ||
720 | return r.status; | ||
721 | } | ||
722 | |||
723 | |||
701 | LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, | 724 | LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, |
702 | int *nresults) { | 725 | int *nresults) { |
703 | int status; | 726 | int status; |
@@ -715,10 +738,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, | |||
715 | api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); | 738 | api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); |
716 | status = luaD_rawrunprotected(L, resume, &nargs); | 739 | status = luaD_rawrunprotected(L, resume, &nargs); |
717 | /* continue running after recoverable errors */ | 740 | /* continue running after recoverable errors */ |
718 | while (errorstatus(status) && recover(L, status)) { | 741 | status = p_recover(L, status); |
719 | /* unroll continuation */ | ||
720 | status = luaD_rawrunprotected(L, unroll, &status); | ||
721 | } | ||
722 | if (likely(!errorstatus(status))) | 742 | if (likely(!errorstatus(status))) |
723 | lua_assert(status == L->status); /* normal end or yield */ | 743 | lua_assert(status == L->status); /* normal end or yield */ |
724 | else { /* unrecoverable error */ | 744 | else { /* unrecoverable error */ |
@@ -770,6 +790,45 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, | |||
770 | 790 | ||
771 | 791 | ||
772 | /* | 792 | /* |
793 | ** Auxiliary structure to call 'luaF_close' in protected mode. | ||
794 | */ | ||
795 | struct CloseP { | ||
796 | StkId level; | ||
797 | int status; | ||
798 | }; | ||
799 | |||
800 | |||
801 | /* | ||
802 | ** Auxiliary function to call 'luaF_close' in protected mode. | ||
803 | */ | ||
804 | static void closepaux (lua_State *L, void *ud) { | ||
805 | struct CloseP *pcl = cast(struct CloseP *, ud); | ||
806 | luaF_close(L, pcl->level, pcl->status, 0); | ||
807 | } | ||
808 | |||
809 | |||
810 | /* | ||
811 | ** Calls 'luaF_close' in protected mode. Return the original status | ||
812 | ** or, in case of errors, the new status. | ||
813 | */ | ||
814 | int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status) { | ||
815 | CallInfo *old_ci = L->ci; | ||
816 | lu_byte old_allowhooks = L->allowhook; | ||
817 | for (;;) { /* keep closing upvalues until no more errors */ | ||
818 | struct CloseP pcl; | ||
819 | pcl.level = restorestack(L, level); pcl.status = status; | ||
820 | status = luaD_rawrunprotected(L, &closepaux, &pcl); | ||
821 | if (likely(status == LUA_OK)) /* no more errors? */ | ||
822 | return pcl.status; | ||
823 | else { /* an error occurred; restore saved state and repeat */ | ||
824 | L->ci = old_ci; | ||
825 | L->allowhook = old_allowhooks; | ||
826 | } | ||
827 | } | ||
828 | } | ||
829 | |||
830 | |||
831 | /* | ||
773 | ** Call the C function 'func' in protected mode, restoring basic | 832 | ** Call the C function 'func' in protected mode, restoring basic |
774 | ** thread information ('allowhook', etc.) and in particular | 833 | ** thread information ('allowhook', etc.) and in particular |
775 | ** its stack level in case of errors. | 834 | ** its stack level in case of errors. |
@@ -783,12 +842,10 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, | |||
783 | L->errfunc = ef; | 842 | L->errfunc = ef; |
784 | status = luaD_rawrunprotected(L, func, u); | 843 | status = luaD_rawrunprotected(L, func, u); |
785 | if (unlikely(status != LUA_OK)) { /* an error occurred? */ | 844 | if (unlikely(status != LUA_OK)) { /* an error occurred? */ |
786 | StkId oldtop = restorestack(L, old_top); | ||
787 | L->ci = old_ci; | 845 | L->ci = old_ci; |
788 | L->allowhook = old_allowhooks; | 846 | L->allowhook = old_allowhooks; |
789 | status = luaF_close(L, oldtop, status); | 847 | status = luaD_closeprotected(L, old_top, status); |
790 | oldtop = restorestack(L, old_top); /* previous call may change stack */ | 848 | luaD_seterrorobj(L, status, restorestack(L, old_top)); |
791 | luaD_seterrorobj(L, status, oldtop); | ||
792 | luaD_shrinkstack(L); /* restore stack size in case of overflow */ | 849 | luaD_shrinkstack(L); /* restore stack size in case of overflow */ |
793 | } | 850 | } |
794 | L->errfunc = old_errfunc; | 851 | L->errfunc = old_errfunc; |