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; |
