xref: /illumos-gate/usr/src/uts/common/fs/zfs/lua/ldo.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
1 /*
2 ** $Id: ldo.c,v 2.108.1.3 2013/11/08 18:22:50 roberto Exp $
3 ** Stack and Call structure of Lua
4 ** See Copyright Notice in lua.h
5 */
6 
7 
8 #include <sys/zfs_context.h>
9 
10 #define ldo_c
11 #define LUA_CORE
12 
13 #include "lua.h"
14 
15 #include "lapi.h"
16 #include "ldebug.h"
17 #include "ldo.h"
18 #include "lfunc.h"
19 #include "lgc.h"
20 #include "lmem.h"
21 #include "lobject.h"
22 #include "lopcodes.h"
23 #include "lparser.h"
24 #include "lstate.h"
25 #include "lstring.h"
26 #include "ltable.h"
27 #include "ltm.h"
28 #include "lundump.h"
29 #include "lvm.h"
30 #include "lzio.h"
31 
32 
33 
34 
35 /*
36 ** {======================================================
37 ** Error-recovery functions
38 ** =======================================================
39 */
40 
41 /*
42 ** LUAI_THROW/LUAI_TRY define how Lua does exception handling. By
43 ** default, Lua handles errors with exceptions when compiling as
44 ** C++ code, with _longjmp/_setjmp when asked to use them, and with
45 ** longjmp/setjmp otherwise.
46 */
47 #if !defined(LUAI_THROW)
48 
49 #ifdef _KERNEL
50 #define LUAI_THROW(L,c)		longjmp(&(c)->b)
51 #define LUAI_TRY(L,c,a)		if (setjmp(&(c)->b) == 0) { a }
52 #define luai_jmpbuf		label_t
53 #else
54 #if defined(__cplusplus) && !defined(LUA_USE_LONGJMP)
55 /* C++ exceptions */
56 #define LUAI_THROW(L,c)		throw(c)
57 #define LUAI_TRY(L,c,a) \
58 	try { a } catch(...) { if ((c)->status == 0) (c)->status = -1; }
59 #define luai_jmpbuf		int  /* dummy variable */
60 
61 #elif defined(LUA_USE_ULONGJMP)
62 /* in Unix, try _longjmp/_setjmp (more efficient) */
63 #define LUAI_THROW(L,c)		_longjmp((c)->b, 1)
64 #define LUAI_TRY(L,c,a)		if (_setjmp((c)->b) == 0) { a }
65 #define luai_jmpbuf		jmp_buf
66 
67 #else
68 /* default handling with long jumps */
69 #define LUAI_THROW(L,c)		longjmp((c)->b, 1)
70 #define LUAI_TRY(L,c,a)		if (setjmp((c)->b) == 0) { a }
71 #define luai_jmpbuf		jmp_buf
72 
73 #endif
74 
75 #endif
76 
77 #endif
78 
79 
80 /* chain list of long jump buffers */
81 struct lua_longjmp {
82   struct lua_longjmp *previous;
83   luai_jmpbuf b;
84   volatile int status;  /* error code */
85 };
86 
87 
88 static void seterrorobj (lua_State *L, int errcode, StkId oldtop) {
89   switch (errcode) {
90     case LUA_ERRMEM: {  /* memory error? */
91       setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */
92       break;
93     }
94     case LUA_ERRERR: {
95       setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling"));
96       break;
97     }
98     default: {
99       setobjs2s(L, oldtop, L->top - 1);  /* error message on current top */
100       break;
101     }
102   }
103   L->top = oldtop + 1;
104 }
105 
106 
107 l_noret luaD_throw (lua_State *L, int errcode) {
108   if (L->errorJmp) {  /* thread has an error handler? */
109     L->errorJmp->status = errcode;  /* set status */
110     LUAI_THROW(L, L->errorJmp);  /* jump to it */
111   }
112   else {  /* thread has no error handler */
113     L->status = cast_byte(errcode);  /* mark it as dead */
114     if (G(L)->mainthread->errorJmp) {  /* main thread has a handler? */
115       setobjs2s(L, G(L)->mainthread->top++, L->top - 1);  /* copy error obj. */
116       luaD_throw(G(L)->mainthread, errcode);  /* re-throw in main thread */
117     }
118     else {  /* no handler at all; abort */
119       if (G(L)->panic) {  /* panic function? */
120         lua_unlock(L);
121         G(L)->panic(L);  /* call it (last chance to jump out) */
122       }
123       panic("no error handler");
124     }
125   }
126 }
127 
128 
129 int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
130   unsigned short oldnCcalls = L->nCcalls;
131   struct lua_longjmp lj;
132   lj.status = LUA_OK;
133   lj.previous = L->errorJmp;  /* chain new error handler */
134   L->errorJmp = &lj;
135   LUAI_TRY(L, &lj,
136     (*f)(L, ud);
137   );
138   L->errorJmp = lj.previous;  /* restore old error handler */
139   L->nCcalls = oldnCcalls;
140   return lj.status;
141 }
142 
143 /* }====================================================== */
144 
145 
146 static void correctstack (lua_State *L, TValue *oldstack) {
147   CallInfo *ci;
148   GCObject *up;
149   L->top = (L->top - oldstack) + L->stack;
150   for (up = L->openupval; up != NULL; up = up->gch.next)
151     gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack;
152   for (ci = L->ci; ci != NULL; ci = ci->previous) {
153     ci->top = (ci->top - oldstack) + L->stack;
154     ci->func = (ci->func - oldstack) + L->stack;
155     if (isLua(ci))
156       ci->u.l.base = (ci->u.l.base - oldstack) + L->stack;
157   }
158 }
159 
160 
161 /* some space for error handling */
162 #define ERRORSTACKSIZE	(LUAI_MAXSTACK + 200)
163 
164 
165 void luaD_reallocstack (lua_State *L, int newsize) {
166   TValue *oldstack = L->stack;
167   int lim = L->stacksize;
168   lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
169   lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK);
170   luaM_reallocvector(L, L->stack, L->stacksize, newsize, TValue);
171   for (; lim < newsize; lim++)
172     setnilvalue(L->stack + lim); /* erase new segment */
173   L->stacksize = newsize;
174   L->stack_last = L->stack + newsize - EXTRA_STACK;
175   correctstack(L, oldstack);
176 }
177 
178 
179 void luaD_growstack (lua_State *L, int n) {
180   int size = L->stacksize;
181   if (size > LUAI_MAXSTACK)  /* error after extra size? */
182     luaD_throw(L, LUA_ERRERR);
183   else {
184     int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK;
185     int newsize = 2 * size;
186     if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK;
187     if (newsize < needed) newsize = needed;
188     if (newsize > LUAI_MAXSTACK) {  /* stack overflow? */
189       luaD_reallocstack(L, ERRORSTACKSIZE);
190       luaG_runerror(L, "stack overflow");
191     }
192     else
193       luaD_reallocstack(L, newsize);
194   }
195 }
196 
197 
198 static int stackinuse (lua_State *L) {
199   CallInfo *ci;
200   StkId lim = L->top;
201   for (ci = L->ci; ci != NULL; ci = ci->previous) {
202     lua_assert(ci->top <= L->stack_last);
203     if (lim < ci->top) lim = ci->top;
204   }
205   return cast_int(lim - L->stack) + 1;  /* part of stack in use */
206 }
207 
208 
209 void luaD_shrinkstack (lua_State *L) {
210   int inuse = stackinuse(L);
211   int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;
212   if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK;
213   if (inuse > LUAI_MAXSTACK ||  /* handling stack overflow? */
214       goodsize >= L->stacksize)  /* would grow instead of shrink? */
215     condmovestack(L);  /* don't change stack (change only for debugging) */
216   else
217     luaD_reallocstack(L, goodsize);  /* shrink it */
218 }
219 
220 
221 void luaD_hook (lua_State *L, int event, int line) {
222   lua_Hook hook = L->hook;
223   if (hook && L->allowhook) {
224     CallInfo *ci = L->ci;
225     ptrdiff_t top = savestack(L, L->top);
226     ptrdiff_t ci_top = savestack(L, ci->top);
227     lua_Debug ar;
228     ar.event = event;
229     ar.currentline = line;
230     ar.i_ci = ci;
231     luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */
232     ci->top = L->top + LUA_MINSTACK;
233     lua_assert(ci->top <= L->stack_last);
234     L->allowhook = 0;  /* cannot call hooks inside a hook */
235     ci->callstatus |= CIST_HOOKED;
236     lua_unlock(L);
237     (*hook)(L, &ar);
238     lua_lock(L);
239     lua_assert(!L->allowhook);
240     L->allowhook = 1;
241     ci->top = restorestack(L, ci_top);
242     L->top = restorestack(L, top);
243     ci->callstatus &= ~CIST_HOOKED;
244   }
245 }
246 
247 
248 static void callhook (lua_State *L, CallInfo *ci) {
249   int hook = LUA_HOOKCALL;
250   ci->u.l.savedpc++;  /* hooks assume 'pc' is already incremented */
251   if (isLua(ci->previous) &&
252       GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) {
253     ci->callstatus |= CIST_TAIL;
254     hook = LUA_HOOKTAILCALL;
255   }
256   luaD_hook(L, hook, -1);
257   ci->u.l.savedpc--;  /* correct 'pc' */
258 }
259 
260 
261 static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
262   int i;
263   int nfixargs = p->numparams;
264   StkId base, fixed;
265   lua_assert(actual >= nfixargs);
266   /* move fixed parameters to final position */
267   luaD_checkstack(L, p->maxstacksize);  /* check again for new 'base' */
268   fixed = L->top - actual;  /* first fixed argument */
269   base = L->top;  /* final position of first argument */
270   for (i=0; i<nfixargs; i++) {
271     setobjs2s(L, L->top++, fixed + i);
272     setnilvalue(fixed + i);
273   }
274   return base;
275 }
276 
277 
278 static StkId tryfuncTM (lua_State *L, StkId func) {
279   const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL);
280   StkId p;
281   ptrdiff_t funcr = savestack(L, func);
282   if (!ttisfunction(tm))
283     luaG_typeerror(L, func, "call");
284   /* Open a hole inside the stack at `func' */
285   for (p = L->top; p > func; p--) setobjs2s(L, p, p-1);
286   incr_top(L);
287   func = restorestack(L, funcr);  /* previous call may change stack */
288   setobj2s(L, func, tm);  /* tag method is the new function to be called */
289   return func;
290 }
291 
292 
293 
294 #define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L)))
295 
296 
297 /*
298 ** returns true if function has been executed (C function)
299 */
300 int luaD_precall (lua_State *L, StkId func, int nresults) {
301   lua_CFunction f;
302   CallInfo *ci;
303   int n;  /* number of arguments (Lua) or returns (C) */
304   ptrdiff_t funcr = savestack(L, func);
305   switch (ttype(func)) {
306     case LUA_TLCF:  /* light C function */
307       f = fvalue(func);
308       goto Cfunc;
309     case LUA_TCCL: {  /* C closure */
310       f = clCvalue(func)->f;
311      Cfunc:
312       luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */
313       ci = next_ci(L);  /* now 'enter' new function */
314       ci->nresults = nresults;
315       ci->func = restorestack(L, funcr);
316       ci->top = L->top + LUA_MINSTACK;
317       lua_assert(ci->top <= L->stack_last);
318       ci->callstatus = 0;
319       luaC_checkGC(L);  /* stack grow uses memory */
320       if (L->hookmask & LUA_MASKCALL)
321         luaD_hook(L, LUA_HOOKCALL, -1);
322       lua_unlock(L);
323       n = (*f)(L);  /* do the actual call */
324       lua_lock(L);
325       api_checknelems(L, n);
326       luaD_poscall(L, L->top - n);
327       return 1;
328     }
329     case LUA_TLCL: {  /* Lua function: prepare its call */
330       StkId base;
331       Proto *p = clLvalue(func)->p;
332       n = cast_int(L->top - func) - 1;  /* number of real arguments */
333       luaD_checkstack(L, p->maxstacksize);
334       for (; n < p->numparams; n++)
335         setnilvalue(L->top++);  /* complete missing arguments */
336       if (!p->is_vararg) {
337         func = restorestack(L, funcr);
338         base = func + 1;
339       }
340       else {
341         base = adjust_varargs(L, p, n);
342         func = restorestack(L, funcr);  /* previous call can change stack */
343       }
344       ci = next_ci(L);  /* now 'enter' new function */
345       ci->nresults = nresults;
346       ci->func = func;
347       ci->u.l.base = base;
348       ci->top = base + p->maxstacksize;
349       lua_assert(ci->top <= L->stack_last);
350       ci->u.l.savedpc = p->code;  /* starting point */
351       ci->callstatus = CIST_LUA;
352       L->top = ci->top;
353       luaC_checkGC(L);  /* stack grow uses memory */
354       if (L->hookmask & LUA_MASKCALL)
355         callhook(L, ci);
356       return 0;
357     }
358     default: {  /* not a function */
359       func = tryfuncTM(L, func);  /* retry with 'function' tag method */
360       return luaD_precall(L, func, nresults);  /* now it must be a function */
361     }
362   }
363 }
364 
365 
366 int luaD_poscall (lua_State *L, StkId firstResult) {
367   StkId res;
368   int wanted, i;
369   CallInfo *ci = L->ci;
370   if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
371     if (L->hookmask & LUA_MASKRET) {
372       ptrdiff_t fr = savestack(L, firstResult);  /* hook may change stack */
373       luaD_hook(L, LUA_HOOKRET, -1);
374       firstResult = restorestack(L, fr);
375     }
376     L->oldpc = ci->previous->u.l.savedpc;  /* 'oldpc' for caller function */
377   }
378   res = ci->func;  /* res == final position of 1st result */
379   wanted = ci->nresults;
380   L->ci = ci = ci->previous;  /* back to caller */
381   /* move results to correct place */
382   for (i = wanted; i != 0 && firstResult < L->top; i--)
383     setobjs2s(L, res++, firstResult++);
384   while (i-- > 0)
385     setnilvalue(res++);
386   L->top = res;
387   return (wanted - LUA_MULTRET);  /* 0 iff wanted == LUA_MULTRET */
388 }
389 
390 
391 /*
392 ** Call a function (C or Lua). The function to be called is at *func.
393 ** The arguments are on the stack, right after the function.
394 ** When returns, all the results are on the stack, starting at the original
395 ** function position.
396 */
397 void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) {
398   if (++L->nCcalls >= LUAI_MAXCCALLS) {
399     if (L->nCcalls == LUAI_MAXCCALLS)
400       luaG_runerror(L, "C stack overflow");
401     else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))
402       luaD_throw(L, LUA_ERRERR);  /* error while handing stack error */
403   }
404   if (!allowyield) L->nny++;
405   if (!luaD_precall(L, func, nResults))  /* is a Lua function? */
406     luaV_execute(L);  /* call it */
407   if (!allowyield) L->nny--;
408   L->nCcalls--;
409 }
410 
411 
412 static void finishCcall (lua_State *L) {
413   CallInfo *ci = L->ci;
414   int n;
415   lua_assert(ci->u.c.k != NULL);  /* must have a continuation */
416   lua_assert(L->nny == 0);
417   if (ci->callstatus & CIST_YPCALL) {  /* was inside a pcall? */
418     ci->callstatus &= ~CIST_YPCALL;  /* finish 'lua_pcall' */
419     L->errfunc = ci->u.c.old_errfunc;
420   }
421   /* finish 'lua_callk'/'lua_pcall' */
422   adjustresults(L, ci->nresults);
423   /* call continuation function */
424   if (!(ci->callstatus & CIST_STAT))  /* no call status? */
425     ci->u.c.status = LUA_YIELD;  /* 'default' status */
426   lua_assert(ci->u.c.status != LUA_OK);
427   ci->callstatus = (ci->callstatus & ~(CIST_YPCALL | CIST_STAT)) | CIST_YIELDED;
428   lua_unlock(L);
429   n = (*ci->u.c.k)(L);
430   lua_lock(L);
431   api_checknelems(L, n);
432   /* finish 'luaD_precall' */
433   luaD_poscall(L, L->top - n);
434 }
435 
436 
437 static void unroll (lua_State *L, void *ud) {
438   UNUSED(ud);
439   for (;;) {
440     if (L->ci == &L->base_ci)  /* stack is empty? */
441       return;  /* coroutine finished normally */
442     if (!isLua(L->ci))  /* C function? */
443       finishCcall(L);
444     else {  /* Lua function */
445       luaV_finishOp(L);  /* finish interrupted instruction */
446       luaV_execute(L);  /* execute down to higher C 'boundary' */
447     }
448   }
449 }
450 
451 
452 /*
453 ** check whether thread has a suspended protected call
454 */
455 static CallInfo *findpcall (lua_State *L) {
456   CallInfo *ci;
457   for (ci = L->ci; ci != NULL; ci = ci->previous) {  /* search for a pcall */
458     if (ci->callstatus & CIST_YPCALL)
459       return ci;
460   }
461   return NULL;  /* no pending pcall */
462 }
463 
464 
465 static int recover (lua_State *L, int status) {
466   StkId oldtop;
467   CallInfo *ci = findpcall(L);
468   if (ci == NULL) return 0;  /* no recovery point */
469   /* "finish" luaD_pcall */
470   oldtop = restorestack(L, ci->extra);
471   luaF_close(L, oldtop);
472   seterrorobj(L, status, oldtop);
473   L->ci = ci;
474   L->allowhook = ci->u.c.old_allowhook;
475   L->nny = 0;  /* should be zero to be yieldable */
476   luaD_shrinkstack(L);
477   L->errfunc = ci->u.c.old_errfunc;
478   ci->callstatus |= CIST_STAT;  /* call has error status */
479   ci->u.c.status = status;  /* (here it is) */
480   return 1;  /* continue running the coroutine */
481 }
482 
483 
484 /*
485 ** signal an error in the call to 'resume', not in the execution of the
486 ** coroutine itself. (Such errors should not be handled by any coroutine
487 ** error handler and should not kill the coroutine.)
488 */
489 static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
490   L->top = firstArg;  /* remove args from the stack */
491   setsvalue2s(L, L->top, luaS_new(L, msg));  /* push error message */
492   api_incr_top(L);
493   luaD_throw(L, -1);  /* jump back to 'lua_resume' */
494 }
495 
496 
497 /*
498 ** do the work for 'lua_resume' in protected mode
499 */
500 static void resume_cb (lua_State *L, void *ud) {
501   int nCcalls = L->nCcalls;
502   StkId firstArg = cast(StkId, ud);
503   CallInfo *ci = L->ci;
504   if (nCcalls >= LUAI_MAXCCALLS)
505     resume_error(L, "C stack overflow", firstArg);
506   if (L->status == LUA_OK) {  /* may be starting a coroutine */
507     if (ci != &L->base_ci)  /* not in base level? */
508       resume_error(L, "cannot resume non-suspended coroutine", firstArg);
509     /* coroutine is in base level; start running it */
510     if (!luaD_precall(L, firstArg - 1, LUA_MULTRET))  /* Lua function? */
511       luaV_execute(L);  /* call it */
512   }
513   else if (L->status != LUA_YIELD)
514     resume_error(L, "cannot resume dead coroutine", firstArg);
515   else {  /* resuming from previous yield */
516     L->status = LUA_OK;
517     ci->func = restorestack(L, ci->extra);
518     if (isLua(ci))  /* yielded inside a hook? */
519       luaV_execute(L);  /* just continue running Lua code */
520     else {  /* 'common' yield */
521       if (ci->u.c.k != NULL) {  /* does it have a continuation? */
522         int n;
523         ci->u.c.status = LUA_YIELD;  /* 'default' status */
524         ci->callstatus |= CIST_YIELDED;
525         lua_unlock(L);
526         n = (*ci->u.c.k)(L);  /* call continuation */
527         lua_lock(L);
528         api_checknelems(L, n);
529         firstArg = L->top - n;  /* yield results come from continuation */
530       }
531       luaD_poscall(L, firstArg);  /* finish 'luaD_precall' */
532     }
533     unroll(L, NULL);
534   }
535   lua_assert(nCcalls == L->nCcalls);
536 }
537 
538 
539 LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
540   int status;
541   int oldnny = L->nny;  /* save 'nny' */
542   lua_lock(L);
543   luai_userstateresume(L, nargs);
544   L->nCcalls = (from) ? from->nCcalls + 1 : 1;
545   L->nny = 0;  /* allow yields */
546   api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
547   status = luaD_rawrunprotected(L, resume_cb, L->top - nargs);
548   if (status == -1)  /* error calling 'lua_resume'? */
549     status = LUA_ERRRUN;
550   else {  /* yield or regular error */
551     while (status != LUA_OK && status != LUA_YIELD) {  /* error? */
552       if (recover(L, status))  /* recover point? */
553         status = luaD_rawrunprotected(L, unroll, NULL);  /* run continuation */
554       else {  /* unrecoverable error */
555         L->status = cast_byte(status);  /* mark thread as `dead' */
556         seterrorobj(L, status, L->top);
557         L->ci->top = L->top;
558         break;
559       }
560     }
561     lua_assert(status == L->status);
562   }
563   L->nny = oldnny;  /* restore 'nny' */
564   L->nCcalls--;
565   lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0));
566   lua_unlock(L);
567   return status;
568 }
569 
570 
571 LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) {
572   CallInfo *ci = L->ci;
573   luai_userstateyield(L, nresults);
574   lua_lock(L);
575   api_checknelems(L, nresults);
576   if (L->nny > 0) {
577     if (L != G(L)->mainthread)
578       luaG_runerror(L, "attempt to yield across a C-call boundary");
579     else
580       luaG_runerror(L, "attempt to yield from outside a coroutine");
581   }
582   L->status = LUA_YIELD;
583   ci->extra = savestack(L, ci->func);  /* save current 'func' */
584   if (isLua(ci)) {  /* inside a hook? */
585     api_check(L, k == NULL, "hooks cannot continue after yielding");
586   }
587   else {
588     if ((ci->u.c.k = k) != NULL)  /* is there a continuation? */
589       ci->u.c.ctx = ctx;  /* save context */
590     ci->func = L->top - nresults - 1;  /* protect stack below results */
591     luaD_throw(L, LUA_YIELD);
592   }
593   lua_assert(ci->callstatus & CIST_HOOKED);  /* must be inside a hook */
594   lua_unlock(L);
595   return 0;  /* return to 'luaD_hook' */
596 }
597 
598 
599 int luaD_pcall (lua_State *L, Pfunc func, void *u,
600                 ptrdiff_t old_top, ptrdiff_t ef) {
601   int status;
602   CallInfo *old_ci = L->ci;
603   lu_byte old_allowhooks = L->allowhook;
604   unsigned short old_nny = L->nny;
605   ptrdiff_t old_errfunc = L->errfunc;
606   L->errfunc = ef;
607   status = luaD_rawrunprotected(L, func, u);
608   if (status != LUA_OK) {  /* an error occurred? */
609     StkId oldtop = restorestack(L, old_top);
610     luaF_close(L, oldtop);  /* close possible pending closures */
611     seterrorobj(L, status, oldtop);
612     L->ci = old_ci;
613     L->allowhook = old_allowhooks;
614     L->nny = old_nny;
615     luaD_shrinkstack(L);
616   }
617   L->errfunc = old_errfunc;
618   return status;
619 }
620 
621 
622 
623 /*
624 ** Execute a protected parser.
625 */
626 struct SParser {  /* data to `f_parser' */
627   ZIO *z;
628   Mbuffer buff;  /* dynamic structure used by the scanner */
629   Dyndata dyd;  /* dynamic structures used by the parser */
630   const char *mode;
631   const char *name;
632 };
633 
634 
635 static void checkmode (lua_State *L, const char *mode, const char *x) {
636   if (mode && strchr(mode, x[0]) == NULL) {
637     luaO_pushfstring(L,
638        "attempt to load a %s chunk (mode is " LUA_QS ")", x, mode);
639     luaD_throw(L, LUA_ERRSYNTAX);
640   }
641 }
642 
643 
644 static void f_parser (lua_State *L, void *ud) {
645   int i;
646   Closure *cl;
647   struct SParser *p = cast(struct SParser *, ud);
648   int c = zgetc(p->z);  /* read first character */
649   if (c == LUA_SIGNATURE[0]) {
650     checkmode(L, p->mode, "binary");
651     cl = luaU_undump(L, p->z, &p->buff, p->name);
652   }
653   else {
654     checkmode(L, p->mode, "text");
655     cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
656   }
657   lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues);
658   for (i = 0; i < cl->l.nupvalues; i++) {  /* initialize upvalues */
659     UpVal *up = luaF_newupval(L);
660     cl->l.upvals[i] = up;
661     luaC_objbarrier(L, cl, up);
662   }
663 }
664 
665 
666 int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
667                                         const char *mode) {
668   struct SParser p;
669   int status;
670   L->nny++;  /* cannot yield during parsing */
671   p.z = z; p.name = name; p.mode = mode;
672   p.dyd.actvar.arr = NULL; p.dyd.actvar.size = 0;
673   p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;
674   p.dyd.label.arr = NULL; p.dyd.label.size = 0;
675   luaZ_initbuffer(L, &p.buff);
676   status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);
677   luaZ_freebuffer(L, &p.buff);
678   luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);
679   luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);
680   luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size);
681   L->nny--;
682   return status;
683 }
684 
685 
686