1 /*
2 ** $Id: ldo.c,v 1.2 2002/07/12 07:49:04 jcatki Exp $
3 ** Stack and Call structure of Lua
4 ** See Copyright Notice in lua.h
5 */
6 
7 
8 #include <setjmp.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 
13 #include "lua.h"
14 
15 #include "ldebug.h"
16 #include "ldo.h"
17 #include "lgc.h"
18 #include "lmem.h"
19 #include "lobject.h"
20 #include "lparser.h"
21 #include "lstate.h"
22 #include "lstring.h"
23 #include "ltable.h"
24 #include "ltm.h"
25 #include "lundump.h"
26 #include "lvm.h"
27 #include "lzio.h"
28 
29 
30 /* space to handle stack overflow errors */
31 #define EXTRA_STACK	(2*LUA_MINSTACK)
32 
33 
luaD_init(lua_State * L,int stacksize)34 void luaD_init (lua_State *L, int stacksize) {
35   L->stack = luaM_newvector(L, stacksize+EXTRA_STACK, TObject);
36   L->nblocks += stacksize*sizeof(TObject);
37   L->stack_last = L->stack+(stacksize-1);
38   L->stacksize = stacksize;
39   L->Cbase = L->top = L->stack;
40 }
41 
42 
luaD_checkstack(lua_State * L,int n)43 void luaD_checkstack (lua_State *L, int n) {
44   if (L->stack_last - L->top <= n) {  /* stack overflow? */
45     if (L->stack_last-L->stack > (L->stacksize-1)) {
46       /* overflow while handling overflow */
47       luaD_breakrun(L, LUA_ERRERR);  /* break run without error message */
48     }
49     else {
50       L->stack_last += EXTRA_STACK;  /* to be used by error message */
51       lua_error(L, "stack overflow");
52     }
53   }
54 }
55 
56 
restore_stack_limit(lua_State * L)57 static void restore_stack_limit (lua_State *L) {
58   if (L->top - L->stack < L->stacksize - 1)
59     L->stack_last = L->stack + (L->stacksize-1);
60 }
61 
62 
63 /*
64 ** Adjust stack. Set top to base+extra, pushing NILs if needed.
65 ** (we cannot add base+extra unless we are sure it fits in the stack;
66 **  otherwise the result of such operation on pointers is undefined)
67 */
luaD_adjusttop(lua_State * L,StkId base,int extra)68 void luaD_adjusttop (lua_State *L, StkId base, int extra) {
69   int diff = extra-(L->top-base);
70   if (diff <= 0)
71     L->top = base+extra;
72   else {
73     luaD_checkstack(L, diff);
74     while (diff--)
75       ttype(L->top++) = LUA_TNIL;
76   }
77 }
78 
79 
80 /*
81 ** Open a hole inside the stack at `pos'
82 */
luaD_openstack(lua_State * L,StkId pos)83 static void luaD_openstack (lua_State *L, StkId pos) {
84   int i = L->top-pos;
85   while (i--) pos[i+1] = pos[i];
86   incr_top;
87 }
88 
89 
dohook(lua_State * L,lua_Debug * ar,lua_Hook hook)90 static void dohook (lua_State *L, lua_Debug *ar, lua_Hook hook) {
91   StkId old_Cbase = L->Cbase;
92   StkId old_top = L->Cbase = L->top;
93   luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */
94   L->allowhooks = 0;  /* cannot call hooks inside a hook */
95   (*hook)(L, ar);
96   LUA_ASSERT(L->allowhooks == 0, "invalid allow");
97   L->allowhooks = 1;
98   L->top = old_top;
99   L->Cbase = old_Cbase;
100 }
101 
102 
luaD_lineHook(lua_State * L,StkId func,int line,lua_Hook linehook)103 void luaD_lineHook (lua_State *L, StkId func, int line, lua_Hook linehook) {
104   if (L->allowhooks) {
105     lua_Debug ar;
106     ar._func = func;
107     ar.event = "line";
108     ar.currentline = line;
109     dohook(L, &ar, linehook);
110   }
111 }
112 
113 
luaD_callHook(lua_State * L,StkId func,lua_Hook callhook,const char * event)114 static void luaD_callHook (lua_State *L, StkId func, lua_Hook callhook,
115                     const char *event) {
116   if (L->allowhooks) {
117     lua_Debug ar;
118     ar._func = func;
119     ar.event = event;
120     infovalue(func)->pc = NULL;  /* function is not active */
121     dohook(L, &ar, callhook);
122   }
123 }
124 
125 
callCclosure(lua_State * L,const struct Closure * cl,StkId base)126 static StkId callCclosure (lua_State *L, const struct Closure *cl, StkId base) {
127   int nup = cl->nupvalues;  /* number of upvalues */
128   StkId old_Cbase = L->Cbase;
129   int n;
130   L->Cbase = base;       /* new base for C function */
131   luaD_checkstack(L, nup+LUA_MINSTACK);  /* ensure minimum stack size */
132   for (n=0; n<nup; n++)  /* copy upvalues as extra arguments */
133     *(L->top++) = cl->upvalue[n];
134   n = (*cl->f.c)(L);  /* do the actual call */
135   L->Cbase = old_Cbase;  /* restore old C base */
136   return L->top - n;  /* return index of first result */
137 }
138 
139 
luaD_callTM(lua_State * L,Closure * f,int nParams,int nResults)140 void luaD_callTM (lua_State *L, Closure *f, int nParams, int nResults) {
141   StkId base = L->top - nParams;
142   luaD_openstack(L, base);
143   clvalue(base) = f;
144   ttype(base) = LUA_TFUNCTION;
145   luaD_call(L, base, nResults);
146 }
147 
148 
149 /*
150 ** Call a function (C or Lua). The function to be called is at *func.
151 ** The arguments are on the stack, right after the function.
152 ** When returns, the results are on the stack, starting at the original
153 ** function position.
154 ** The number of results is nResults, unless nResults=LUA_MULTRET.
155 */
luaD_call(lua_State * L,StkId func,int nResults)156 void luaD_call (lua_State *L, StkId func, int nResults) {
157   lua_Hook callhook;
158   StkId firstResult;
159   CallInfo ci;
160   Closure *cl;
161   if (ttype(func) != LUA_TFUNCTION) {
162     /* `func' is not a function; check the `function' tag method */
163     Closure *tm = luaT_gettmbyObj(L, func, TM_FUNCTION);
164     if (tm == NULL)
165       luaG_typeerror(L, func, "call");
166     luaD_openstack(L, func);
167     clvalue(func) = tm;  /* tag method is the new function to be called */
168     ttype(func) = LUA_TFUNCTION;
169   }
170   cl = clvalue(func);
171   ci.func = cl;
172   infovalue(func) = &ci;
173   ttype(func) = LUA_TMARK;
174   callhook = L->callhook;
175   if (callhook)
176     luaD_callHook(L, func, callhook, "call");
177   firstResult = (cl->isC ? callCclosure(L, cl, func+1) :
178                            luaV_execute(L, cl, func+1));
179   if (callhook)  /* same hook that was active at entry */
180     luaD_callHook(L, func, callhook, "return");
181   LUA_ASSERT(ttype(func) == LUA_TMARK, "invalid tag");
182   /* move results to `func' (to erase parameters and function) */
183   if (nResults == LUA_MULTRET) {
184     while (firstResult < L->top)  /* copy all results */
185       *func++ = *firstResult++;
186     L->top = func;
187   }
188   else {  /* copy at most `nResults' */
189     for (; nResults > 0 && firstResult < L->top; nResults--)
190       *func++ = *firstResult++;
191     L->top = func;
192     for (; nResults > 0; nResults--) {  /* if there are not enough results */
193       ttype(L->top) = LUA_TNIL;  /* adjust the stack */
194       incr_top;  /* must check stack space */
195     }
196   }
197   luaC_checkGC(L);
198 }
199 
200 
201 /*
202 ** Execute a protected call.
203 */
204 struct CallS {  /* data to `f_call' */
205   StkId func;
206   int nresults;
207 };
208 
f_call(lua_State * L,void * ud)209 static void f_call (lua_State *L, void *ud) {
210   struct CallS *c = (struct CallS *)ud;
211   luaD_call(L, c->func, c->nresults);
212 }
213 
214 
lua_call(lua_State * L,int nargs,int nresults)215 LUA_API int lua_call (lua_State *L, int nargs, int nresults) {
216   StkId func = L->top - (nargs+1);  /* function to be called */
217   struct CallS c;
218   int status;
219   c.func = func; c.nresults = nresults;
220   status = luaD_runprotected(L, f_call, &c);
221   if (status != 0)  /* an error occurred? */
222     L->top = func;  /* remove parameters from the stack */
223   return status;
224 }
225 
226 
227 /*
228 ** Execute a protected parser.
229 */
230 struct ParserS {  /* data to `f_parser' */
231   ZIO *z;
232   int bin;
233 };
234 
f_parser(lua_State * L,void * ud)235 static void f_parser (lua_State *L, void *ud) {
236   struct ParserS *p = (struct ParserS *)ud;
237   Proto *tf = p->bin ? luaU_undump(L, p->z) : luaY_parser(L, p->z);
238   luaV_Lclosure(L, tf, 0);
239 }
240 
241 
protectedparser(lua_State * L,ZIO * z,int bin)242 static int protectedparser (lua_State *L, ZIO *z, int bin) {
243   struct ParserS p;
244   unsigned long old_blocks;
245   int status;
246   p.z = z; p.bin = bin;
247   /* before parsing, give a (good) chance to GC */
248   if (L->nblocks/8 >= L->GCthreshold/10)
249     luaC_collectgarbage(L);
250   old_blocks = L->nblocks;
251   status = luaD_runprotected(L, f_parser, &p);
252   if (status == 0) {
253     /* add new memory to threshold (as it probably will stay) */
254     L->GCthreshold += (L->nblocks - old_blocks);
255   }
256   else if (status == LUA_ERRRUN)  /* an error occurred: correct error code */
257     status = LUA_ERRSYNTAX;
258   return status;
259 }
260 
261 
parse_file(lua_State * L,const char * filename)262 static int parse_file (lua_State *L, const char *filename) {
263   ZIO z;
264   int status;
265   int bin;  /* flag for file mode */
266   int c;    /* look ahead char */
267   FILE *f = (filename == NULL) ? stdin : fopen(filename, "r");
268   if (f == NULL) return LUA_ERRFILE;  /* unable to open file */
269   c = fgetc(f);
270   ungetc(c, f);
271   bin = (c == ID_CHUNK);
272   if (bin && f != stdin) {
273     f = freopen(filename, "rb", f);  /* set binary mode */
274     if (f == NULL) return LUA_ERRFILE;  /* unable to reopen file */
275   }
276   lua_pushstring(L, "@");
277   lua_pushstring(L, (filename == NULL) ? "(stdin)" : filename);
278   lua_concat(L, 2);
279   c = lua_gettop(L);
280   filename = lua_tostring(L, c);  /* filename = '@'..filename */
281   luaZ_Fopen(&z, f, filename);
282   status = protectedparser(L, &z, bin);
283   lua_remove(L, c);  /* remove `filename' from the stack */
284   if (f != stdin)
285     fclose(f);
286   return status;
287 }
288 
289 
lua_dofile(lua_State * L,const char * filename)290 LUA_API int lua_dofile (lua_State *L, const char *filename) {
291   int status = parse_file(L, filename);
292   if (status == 0)  /* parse OK? */
293     status = lua_call(L, 0, LUA_MULTRET);  /* call main */
294   return status;
295 }
296 
297 
parse_buffer(lua_State * L,const char * buff,size_t size,const char * name)298 static int parse_buffer (lua_State *L, const char *buff, size_t size,
299                          const char *name) {
300   ZIO z;
301   if (!name) name = "?";
302   luaZ_mopen(&z, buff, size, name);
303   return protectedparser(L, &z, buff[0]==ID_CHUNK);
304 }
305 
306 
lua_dobuffer(lua_State * L,const char * buff,size_t size,const char * name)307 LUA_API int lua_dobuffer (lua_State *L, const char *buff, size_t size, const char *name) {
308   int status = parse_buffer(L, buff, size, name);
309   if (status == 0)  /* parse OK? */
310     status = lua_call(L, 0, LUA_MULTRET);  /* call main */
311   return status;
312 }
313 
314 
lua_dostring(lua_State * L,const char * str)315 LUA_API int lua_dostring (lua_State *L, const char *str) {
316   return lua_dobuffer(L, str, strlen(str), str);
317 }
318 
319 
320 /*
321 ** {======================================================
322 ** Error-recover functions (based on long jumps)
323 ** =======================================================
324 */
325 
326 /* chain list of long jump buffers */
327 struct lua_longjmp {
328   jmp_buf b;
329   struct lua_longjmp *previous;
330   volatile int status;  /* error code */
331 };
332 
333 
message(lua_State * L,const char * s)334 static void message (lua_State *L, const char *s) {
335   const TObject *em = luaH_getglobal(L, LUA_ERRORMESSAGE);
336   if (ttype(em) == LUA_TFUNCTION) {
337     *L->top = *em;
338     incr_top;
339     lua_pushstring(L, s);
340     luaD_call(L, L->top-2, 0);
341   }
342 }
343 
344 
345 /*
346 ** Reports an error, and jumps up to the available recovery label
347 */
lua_error(lua_State * L,const char * s)348 LUA_API void lua_error (lua_State *L, const char *s) {
349   if (s) message(L, s);
350   luaD_breakrun(L, LUA_ERRRUN);
351 }
352 
353 
luaD_breakrun(lua_State * L,int errcode)354 void luaD_breakrun (lua_State *L, int errcode) {
355   if (L->errorJmp) {
356     L->errorJmp->status = errcode;
357     longjmp(L->errorJmp->b, 1);
358   }
359   else {
360     if (errcode != LUA_ERRMEM)
361       message(L, "unable to recover; exiting\n");
362     exit(EXIT_FAILURE);
363   }
364 }
365 
366 
luaD_runprotected(lua_State * L,void (* f)(lua_State *,void *),void * ud)367 int luaD_runprotected (lua_State *L, void (*f)(lua_State *, void *), void *ud) {
368   StkId oldCbase = L->Cbase;
369   StkId oldtop = L->top;
370   struct lua_longjmp lj;
371   int allowhooks = L->allowhooks;
372   lj.status = 0;
373   lj.previous = L->errorJmp;  /* chain new error handler */
374   L->errorJmp = &lj;
375   if (setjmp(lj.b) == 0)
376     (*f)(L, ud);
377   else {  /* an error occurred: restore the state */
378     L->allowhooks = allowhooks;
379     L->Cbase = oldCbase;
380     L->top = oldtop;
381     restore_stack_limit(L);
382   }
383   L->errorJmp = lj.previous;  /* restore old error handler */
384   return lj.status;
385 }
386 
387 /* }====================================================== */
388 
389