Path: blob/main/sys/contrib/openzfs/module/lua/ldo.c
48383 views
// SPDX-License-Identifier: MIT1/*2** $Id: ldo.c,v 2.108.1.3 2013/11/08 18:22:50 roberto Exp $3** Stack and Call structure of Lua4** See Copyright Notice in lua.h5*/678#define ldo_c9#define LUA_CORE1011#include <sys/lua/lua.h>12#include <sys/asm_linkage.h>1314#include "lapi.h"15#include "ldebug.h"16#include "ldo.h"17#include "lfunc.h"18#include "lgc.h"19#include "lmem.h"20#include "lobject.h"21#include "lopcodes.h"22#include "lparser.h"23#include "lstate.h"24#include "lstring.h"25#include "ltable.h"26#include "ltm.h"27#include "lvm.h"28#include "lzio.h"293031/* Return the number of bytes available on the stack. */32#if defined (_KERNEL) && defined(__linux__)33#include <asm/current.h>34static intptr_t stack_remaining(void) {35intptr_t local;36local = (intptr_t)&local - (intptr_t)current->stack;37return local;38}39#elif defined (_KERNEL) && defined(__FreeBSD__)40#include <sys/pcpu.h>41static intptr_t stack_remaining(void) {42intptr_t local;43local = (intptr_t)&local - (intptr_t)curthread->td_kstack;44return local;45}46#else47static intptr_t stack_remaining(void) {48return INTPTR_MAX;49}50#endif5152/*53** {======================================================54** Error-recovery functions55** =======================================================56*/5758/*59** LUAI_THROW/LUAI_TRY define how Lua does exception handling. By60** default, Lua handles errors with exceptions when compiling as61** C++ code, with _longjmp/_setjmp when asked to use them, and with62** longjmp/setjmp otherwise.63*/64#if !defined(LUAI_THROW)6566#ifdef _KERNEL6768#ifdef __linux__69#if defined(__i386__)70#define JMP_BUF_CNT 671#elif defined(__x86_64__)72#define JMP_BUF_CNT 873#elif defined(__sparc__) && defined(__arch64__)74#define JMP_BUF_CNT 675#elif defined(__powerpc__)76#define JMP_BUF_CNT 2677#elif defined(__aarch64__)78#define JMP_BUF_CNT 6479#elif defined(__arm__)80#define JMP_BUF_CNT 6581#elif defined(__mips__)82#define JMP_BUF_CNT 1283#elif defined(__s390x__)84#define JMP_BUF_CNT 1885#elif defined(__riscv)86#define JMP_BUF_CNT 6487#elif defined(__loongarch_lp64)88#define JMP_BUF_CNT 6489#else90#define JMP_BUF_CNT 191#endif9293typedef struct _label_t { long long unsigned val[JMP_BUF_CNT]; } label_t;9495int ASMABI setjmp(label_t *) __attribute__ ((__nothrow__));96extern __attribute__((noreturn)) void ASMABI longjmp(label_t *);9798#define LUAI_THROW(L,c) longjmp(&(c)->b)99#define LUAI_TRY(L,c,a) if (setjmp(&(c)->b) == 0) { a }100#define luai_jmpbuf label_t101102/* unsupported arches will build but not be able to run lua programs */103#if JMP_BUF_CNT == 1104int setjmp (label_t *buf) {105return 1;106}107108void longjmp (label_t * buf) {109for (;;);110}111#endif112#else113#define LUAI_THROW(L,c) longjmp((c)->b, 1)114#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a }115#define luai_jmpbuf jmp_buf116#endif117118#else /* _KERNEL */119120#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP)121/* C++ exceptions */122#define LUAI_THROW(L,c) throw(c)123#define LUAI_TRY(L,c,a) \124try { a } catch(...) { if ((c)->status == 0) (c)->status = -1; }125#define luai_jmpbuf int /* dummy variable */126127#elif defined(LUA_USE_ULONGJMP)128/* in Unix, try _longjmp/_setjmp (more efficient) */129#define LUAI_THROW(L,c) _longjmp((c)->b, 1)130#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a }131#define luai_jmpbuf jmp_buf132133#else134/* default handling with long jumps */135#define LUAI_THROW(L,c) longjmp((c)->b, 1)136#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a }137#define luai_jmpbuf jmp_buf138139#endif140141#endif /* _KERNEL */142143#endif /* LUAI_THROW */144145146/* chain list of long jump buffers */147struct lua_longjmp {148struct lua_longjmp *previous;149luai_jmpbuf b;150volatile int status; /* error code */151};152153154static void seterrorobj (lua_State *L, int errcode, StkId oldtop) {155switch (errcode) {156case LUA_ERRMEM: { /* memory error? */157setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */158break;159}160case LUA_ERRERR: {161setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling"));162break;163}164default: {165setobjs2s(L, oldtop, L->top - 1); /* error message on current top */166break;167}168}169L->top = oldtop + 1;170}171172/*173* Silence infinite recursion warning which was added to -Wall in gcc 12.1174*/175#if defined(__GNUC__) && !defined(__clang__) && \176defined(HAVE_KERNEL_INFINITE_RECURSION)177#pragma GCC diagnostic push178#pragma GCC diagnostic ignored "-Winfinite-recursion"179#endif180181l_noret luaD_throw (lua_State *L, int errcode) {182if (L->errorJmp) { /* thread has an error handler? */183L->errorJmp->status = errcode; /* set status */184LUAI_THROW(L, L->errorJmp); /* jump to it */185}186else { /* thread has no error handler */187L->status = cast_byte(errcode); /* mark it as dead */188if (G(L)->mainthread->errorJmp) { /* main thread has a handler? */189setobjs2s(L, G(L)->mainthread->top++, L->top - 1); /* copy error obj. */190luaD_throw(G(L)->mainthread, errcode); /* re-throw in main thread */191}192else { /* no handler at all; abort */193if (G(L)->panic) { /* panic function? */194lua_unlock(L);195G(L)->panic(L); /* call it (last chance to jump out) */196}197panic("no error handler");198}199}200}201202#if defined(__GNUC__) && !defined(__clang__) && \203defined(HAVE_INFINITE_RECURSION)204#pragma GCC diagnostic pop205#endif206207208int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {209unsigned short oldnCcalls = L->nCcalls;210struct lua_longjmp lj;211lj.status = LUA_OK;212lj.previous = L->errorJmp; /* chain new error handler */213L->errorJmp = &lj;214LUAI_TRY(L, &lj,215(*f)(L, ud);216);217L->errorJmp = lj.previous; /* restore old error handler */218L->nCcalls = oldnCcalls;219return lj.status;220}221222/* }====================================================== */223224225static void correctstack (lua_State *L, TValue *oldstack) {226CallInfo *ci;227GCObject *up;228L->top = (L->top - oldstack) + L->stack;229for (up = L->openupval; up != NULL; up = up->gch.next)230gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack;231for (ci = L->ci; ci != NULL; ci = ci->previous) {232ci->top = (ci->top - oldstack) + L->stack;233ci->func = (ci->func - oldstack) + L->stack;234if (isLua(ci))235ci->u.l.base = (ci->u.l.base - oldstack) + L->stack;236}237}238239240/* some space for error handling */241#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)242243244void luaD_reallocstack (lua_State *L, int newsize) {245TValue *oldstack = L->stack;246int lim = L->stacksize;247lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);248lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK);249luaM_reallocvector(L, L->stack, L->stacksize, newsize, TValue);250for (; lim < newsize; lim++)251setnilvalue(L->stack + lim); /* erase new segment */252L->stacksize = newsize;253L->stack_last = L->stack + newsize - EXTRA_STACK;254correctstack(L, oldstack);255}256257258void luaD_growstack (lua_State *L, int n) {259int size = L->stacksize;260if (size > LUAI_MAXSTACK) /* error after extra size? */261luaD_throw(L, LUA_ERRERR);262else {263int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK;264int newsize = 2 * size;265if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK;266if (newsize < needed) newsize = needed;267if (newsize > LUAI_MAXSTACK) { /* stack overflow? */268luaD_reallocstack(L, ERRORSTACKSIZE);269luaG_runerror(L, "stack overflow");270}271else272luaD_reallocstack(L, newsize);273}274}275276277static int stackinuse (lua_State *L) {278CallInfo *ci;279StkId lim = L->top;280for (ci = L->ci; ci != NULL; ci = ci->previous) {281lua_assert(ci->top <= L->stack_last);282if (lim < ci->top) lim = ci->top;283}284return cast_int(lim - L->stack) + 1; /* part of stack in use */285}286287288void luaD_shrinkstack (lua_State *L) {289int inuse = stackinuse(L);290int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;291if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK;292if (inuse > LUAI_MAXSTACK || /* handling stack overflow? */293goodsize >= L->stacksize) /* would grow instead of shrink? */294condmovestack(L); /* don't change stack (change only for debugging) */295else296luaD_reallocstack(L, goodsize); /* shrink it */297}298299300void luaD_hook (lua_State *L, int event, int line) {301lua_Hook hook = L->hook;302if (hook && L->allowhook) {303CallInfo *ci = L->ci;304ptrdiff_t top = savestack(L, L->top);305ptrdiff_t ci_top = savestack(L, ci->top);306lua_Debug ar;307ar.event = event;308ar.currentline = line;309ar.i_ci = ci;310luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */311ci->top = L->top + LUA_MINSTACK;312lua_assert(ci->top <= L->stack_last);313L->allowhook = 0; /* cannot call hooks inside a hook */314ci->callstatus |= CIST_HOOKED;315lua_unlock(L);316(*hook)(L, &ar);317lua_lock(L);318lua_assert(!L->allowhook);319L->allowhook = 1;320ci->top = restorestack(L, ci_top);321L->top = restorestack(L, top);322ci->callstatus &= ~CIST_HOOKED;323}324}325326327static void callhook (lua_State *L, CallInfo *ci) {328int hook = LUA_HOOKCALL;329ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */330if (isLua(ci->previous) &&331GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) {332ci->callstatus |= CIST_TAIL;333hook = LUA_HOOKTAILCALL;334}335luaD_hook(L, hook, -1);336ci->u.l.savedpc--; /* correct 'pc' */337}338339340static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {341int i;342int nfixargs = p->numparams;343StkId base, fixed;344lua_assert(actual >= nfixargs);345/* move fixed parameters to final position */346luaD_checkstack(L, p->maxstacksize); /* check again for new 'base' */347fixed = L->top - actual; /* first fixed argument */348base = L->top; /* final position of first argument */349for (i=0; i<nfixargs; i++) {350setobjs2s(L, L->top++, fixed + i);351setnilvalue(fixed + i);352}353return base;354}355356357static StkId tryfuncTM (lua_State *L, StkId func) {358const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL);359StkId p;360ptrdiff_t funcr = savestack(L, func);361if (!ttisfunction(tm))362luaG_typeerror(L, func, "call");363/* Open a hole inside the stack at `func' */364for (p = L->top; p > func; p--) setobjs2s(L, p, p-1);365incr_top(L);366func = restorestack(L, funcr); /* previous call may change stack */367setobj2s(L, func, tm); /* tag method is the new function to be called */368return func;369}370371372373#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L)))374375376/*377** returns true if function has been executed (C function)378*/379int luaD_precall (lua_State *L, StkId func, int nresults) {380lua_CFunction f;381CallInfo *ci;382int n; /* number of arguments (Lua) or returns (C) */383ptrdiff_t funcr = savestack(L, func);384switch (ttype(func)) {385case LUA_TLCF: /* light C function */386f = fvalue(func);387goto Cfunc;388case LUA_TCCL: { /* C closure */389f = clCvalue(func)->f;390Cfunc:391luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */392ci = next_ci(L); /* now 'enter' new function */393ci->nresults = nresults;394ci->func = restorestack(L, funcr);395ci->top = L->top + LUA_MINSTACK;396lua_assert(ci->top <= L->stack_last);397ci->callstatus = 0;398luaC_checkGC(L); /* stack grow uses memory */399if (L->hookmask & LUA_MASKCALL)400luaD_hook(L, LUA_HOOKCALL, -1);401lua_unlock(L);402n = (*f)(L); /* do the actual call */403lua_lock(L);404api_checknelems(L, n);405luaD_poscall(L, L->top - n);406return 1;407}408case LUA_TLCL: { /* Lua function: prepare its call */409StkId base;410Proto *p = clLvalue(func)->p;411n = cast_int(L->top - func) - 1; /* number of real arguments */412luaD_checkstack(L, p->maxstacksize + p->numparams);413for (; n < p->numparams; n++)414setnilvalue(L->top++); /* complete missing arguments */415if (!p->is_vararg) {416func = restorestack(L, funcr);417base = func + 1;418}419else {420base = adjust_varargs(L, p, n);421func = restorestack(L, funcr); /* previous call can change stack */422}423ci = next_ci(L); /* now 'enter' new function */424ci->nresults = nresults;425ci->func = func;426ci->u.l.base = base;427ci->top = base + p->maxstacksize;428lua_assert(ci->top <= L->stack_last);429ci->u.l.savedpc = p->code; /* starting point */430ci->callstatus = CIST_LUA;431L->top = ci->top;432luaC_checkGC(L); /* stack grow uses memory */433if (L->hookmask & LUA_MASKCALL)434callhook(L, ci);435return 0;436}437default: { /* not a function */438func = tryfuncTM(L, func); /* retry with 'function' tag method */439return luaD_precall(L, func, nresults); /* now it must be a function */440}441}442}443444445int luaD_poscall (lua_State *L, StkId firstResult) {446StkId res;447int wanted, i;448CallInfo *ci = L->ci;449if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {450if (L->hookmask & LUA_MASKRET) {451ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */452luaD_hook(L, LUA_HOOKRET, -1);453firstResult = restorestack(L, fr);454}455L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */456}457res = ci->func; /* res == final position of 1st result */458wanted = ci->nresults;459L->ci = ci->previous; /* back to caller */460/* move results to correct place */461for (i = wanted; i != 0 && firstResult < L->top; i--)462setobjs2s(L, res++, firstResult++);463while (i-- > 0)464setnilvalue(res++);465L->top = res;466return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */467}468469470/*471** Call a function (C or Lua). The function to be called is at *func.472** The arguments are on the stack, right after the function.473** When returns, all the results are on the stack, starting at the original474** function position.475*/476void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) {477if (++L->nCcalls >= LUAI_MAXCCALLS) {478if (L->nCcalls == LUAI_MAXCCALLS)479luaG_runerror(L, "C stack overflow");480else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))481luaD_throw(L, LUA_ERRERR); /* error while handling stack error */482}483intptr_t remaining = stack_remaining();484if (L->runerror == 0 && remaining < LUAI_MINCSTACK)485luaG_runerror(L, "C stack overflow");486if (L->runerror != 0 && remaining < LUAI_MINCSTACK / 2)487luaD_throw(L, LUA_ERRERR); /* error while handling stack error */488if (!allowyield) L->nny++;489if (!luaD_precall(L, func, nResults)) /* is a Lua function? */490luaV_execute(L); /* call it */491if (!allowyield) L->nny--;492L->nCcalls--;493}494495496static void finishCcall (lua_State *L) {497CallInfo *ci = L->ci;498int n;499lua_assert(ci->u.c.k != NULL); /* must have a continuation */500lua_assert(L->nny == 0);501if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */502ci->callstatus &= ~CIST_YPCALL; /* finish 'lua_pcall' */503L->errfunc = ci->u.c.old_errfunc;504}505/* finish 'lua_callk'/'lua_pcall' */506adjustresults(L, ci->nresults);507/* call continuation function */508if (!(ci->callstatus & CIST_STAT)) /* no call status? */509ci->u.c.status = LUA_YIELD; /* 'default' status */510lua_assert(ci->u.c.status != LUA_OK);511ci->callstatus = (ci->callstatus & ~(CIST_YPCALL | CIST_STAT)) | CIST_YIELDED;512lua_unlock(L);513n = (*ci->u.c.k)(L);514lua_lock(L);515api_checknelems(L, n);516/* finish 'luaD_precall' */517luaD_poscall(L, L->top - n);518}519520521static void unroll (lua_State *L, void *ud) {522UNUSED(ud);523for (;;) {524if (L->ci == &L->base_ci) /* stack is empty? */525return; /* coroutine finished normally */526if (!isLua(L->ci)) /* C function? */527finishCcall(L);528else { /* Lua function */529luaV_finishOp(L); /* finish interrupted instruction */530luaV_execute(L); /* execute down to higher C 'boundary' */531}532}533}534535536/*537** check whether thread has a suspended protected call538*/539static CallInfo *findpcall (lua_State *L) {540CallInfo *ci;541for (ci = L->ci; ci != NULL; ci = ci->previous) { /* search for a pcall */542if (ci->callstatus & CIST_YPCALL)543return ci;544}545return NULL; /* no pending pcall */546}547548549static int recover (lua_State *L, int status) {550StkId oldtop;551CallInfo *ci = findpcall(L);552if (ci == NULL) return 0; /* no recovery point */553/* "finish" luaD_pcall */554oldtop = restorestack(L, ci->extra);555luaF_close(L, oldtop);556seterrorobj(L, status, oldtop);557L->ci = ci;558L->allowhook = ci->u.c.old_allowhook;559L->nny = 0; /* should be zero to be yieldable */560luaD_shrinkstack(L);561L->errfunc = ci->u.c.old_errfunc;562ci->callstatus |= CIST_STAT; /* call has error status */563ci->u.c.status = status; /* (here it is) */564return 1; /* continue running the coroutine */565}566567568/*569** signal an error in the call to 'resume', not in the execution of the570** coroutine itself. (Such errors should not be handled by any coroutine571** error handler and should not kill the coroutine.)572*/573static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {574L->top = firstArg; /* remove args from the stack */575setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */576api_incr_top(L);577luaD_throw(L, -1); /* jump back to 'lua_resume' */578}579580581/*582** do the work for 'lua_resume' in protected mode583*/584static void resume_cb (lua_State *L, void *ud) {585int nCcalls = L->nCcalls;586StkId firstArg = cast(StkId, ud);587CallInfo *ci = L->ci;588if (nCcalls >= LUAI_MAXCCALLS)589resume_error(L, "C stack overflow", firstArg);590if (L->status == LUA_OK) { /* may be starting a coroutine */591if (ci != &L->base_ci) /* not in base level? */592resume_error(L, "cannot resume non-suspended coroutine", firstArg);593/* coroutine is in base level; start running it */594if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */595luaV_execute(L); /* call it */596}597else if (L->status != LUA_YIELD)598resume_error(L, "cannot resume dead coroutine", firstArg);599else { /* resuming from previous yield */600L->status = LUA_OK;601ci->func = restorestack(L, ci->extra);602if (isLua(ci)) /* yielded inside a hook? */603luaV_execute(L); /* just continue running Lua code */604else { /* 'common' yield */605if (ci->u.c.k != NULL) { /* does it have a continuation? */606int n;607ci->u.c.status = LUA_YIELD; /* 'default' status */608ci->callstatus |= CIST_YIELDED;609lua_unlock(L);610n = (*ci->u.c.k)(L); /* call continuation */611lua_lock(L);612api_checknelems(L, n);613firstArg = L->top - n; /* yield results come from continuation */614}615luaD_poscall(L, firstArg); /* finish 'luaD_precall' */616}617unroll(L, NULL);618}619lua_assert(nCcalls == L->nCcalls);620}621622623LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {624int status;625int oldnny = L->nny; /* save 'nny' */626lua_lock(L);627luai_userstateresume(L, nargs);628L->nCcalls = (from) ? from->nCcalls + 1 : 1;629L->nny = 0; /* allow yields */630api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);631status = luaD_rawrunprotected(L, resume_cb, L->top - nargs);632if (status == -1) /* error calling 'lua_resume'? */633status = LUA_ERRRUN;634else { /* yield or regular error */635while (status != LUA_OK && status != LUA_YIELD) { /* error? */636if (recover(L, status)) /* recover point? */637status = luaD_rawrunprotected(L, unroll, NULL); /* run continuation */638else { /* unrecoverable error */639L->status = cast_byte(status); /* mark thread as `dead' */640seterrorobj(L, status, L->top);641L->ci->top = L->top;642break;643}644}645lua_assert(status == L->status);646}647L->nny = oldnny; /* restore 'nny' */648L->nCcalls--;649lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0));650lua_unlock(L);651return status;652}653654655LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) {656CallInfo *ci = L->ci;657luai_userstateyield(L, nresults);658lua_lock(L);659api_checknelems(L, nresults);660if (L->nny > 0) {661if (L != G(L)->mainthread)662luaG_runerror(L, "attempt to yield across a C-call boundary");663else664luaG_runerror(L, "attempt to yield from outside a coroutine");665}666L->status = LUA_YIELD;667ci->extra = savestack(L, ci->func); /* save current 'func' */668if (isLua(ci)) { /* inside a hook? */669api_check(L, k == NULL, "hooks cannot continue after yielding");670}671else {672if ((ci->u.c.k = k) != NULL) /* is there a continuation? */673ci->u.c.ctx = ctx; /* save context */674ci->func = L->top - nresults - 1; /* protect stack below results */675luaD_throw(L, LUA_YIELD);676}677lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */678lua_unlock(L);679return 0; /* return to 'luaD_hook' */680}681682683int luaD_pcall (lua_State *L, Pfunc func, void *u,684ptrdiff_t old_top, ptrdiff_t ef) {685int status;686CallInfo *old_ci = L->ci;687lu_byte old_allowhooks = L->allowhook;688unsigned short old_nny = L->nny;689ptrdiff_t old_errfunc = L->errfunc;690L->errfunc = ef;691status = luaD_rawrunprotected(L, func, u);692if (status != LUA_OK) { /* an error occurred? */693StkId oldtop = restorestack(L, old_top);694luaF_close(L, oldtop); /* close possible pending closures */695seterrorobj(L, status, oldtop);696L->ci = old_ci;697L->allowhook = old_allowhooks;698L->nny = old_nny;699luaD_shrinkstack(L);700}701L->errfunc = old_errfunc;702return status;703}704705706707/*708** Execute a protected parser.709*/710struct SParser { /* data to `f_parser' */711ZIO *z;712Mbuffer buff; /* dynamic structure used by the scanner */713Dyndata dyd; /* dynamic structures used by the parser */714const char *mode;715const char *name;716};717718719static void checkmode (lua_State *L, const char *mode, const char *x) {720if (mode && strchr(mode, x[0]) == NULL) {721luaO_pushfstring(L,722"attempt to load a %s chunk (mode is " LUA_QS ")", x, mode);723luaD_throw(L, LUA_ERRSYNTAX);724}725}726727728static void f_parser (lua_State *L, void *ud) {729int i;730Closure *cl;731struct SParser *p = cast(struct SParser *, ud);732int c = zgetc(p->z); /* read first character */733lua_assert(c != LUA_SIGNATURE[0]); /* binary not supported */734checkmode(L, p->mode, "text");735cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);736lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues);737for (i = 0; i < cl->l.nupvalues; i++) { /* initialize upvalues */738UpVal *up = luaF_newupval(L);739cl->l.upvals[i] = up;740luaC_objbarrier(L, cl, up);741}742}743744745int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,746const char *mode) {747struct SParser p;748int status;749L->nny++; /* cannot yield during parsing */750p.z = z; p.name = name; p.mode = mode;751p.dyd.actvar.arr = NULL; p.dyd.actvar.size = 0;752p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;753p.dyd.label.arr = NULL; p.dyd.label.size = 0;754luaZ_initbuffer(L, &p.buff);755status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);756luaZ_freebuffer(L, &p.buff);757luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);758luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);759luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size);760L->nny--;761return status;762}763764765