ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

ldo.cpp

Go to the documentation of this file.
00001 /*
00002 ** Stack and Call structure of Lua
00003 ** See Copyright Notice in lua.h
00004 */
00005 
00006 #define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
00007 #define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
00008 #define FORBIDDEN_SYMBOL_EXCEPTION_fprintf
00009 #define FORBIDDEN_SYMBOL_EXCEPTION_stderr
00010 #define FORBIDDEN_SYMBOL_EXCEPTION_exit
00011 
00012 #ifdef _MSC_VER
00013 #pragma warning(disable:4611)
00014 #endif
00015 
00016 #include "engines/grim/lua/ldo.h"
00017 #include "engines/grim/lua/lfunc.h"
00018 #include "engines/grim/lua/lgc.h"
00019 #include "engines/grim/lua/lmem.h"
00020 #include "engines/grim/lua/lobject.h"
00021 #include "engines/grim/lua/lopcodes.h"
00022 #include "engines/grim/lua/lparser.h"
00023 #include "engines/grim/lua/lstate.h"
00024 #include "engines/grim/lua/ltask.h"
00025 #include "engines/grim/lua/ltm.h"
00026 #include "engines/grim/lua/lua.h"
00027 #include "engines/grim/lua/luadebug.h"
00028 #include "engines/grim/lua/lundump.h"
00029 #include "engines/grim/lua/lvm.h"
00030 #include "engines/grim/lua/lzio.h"
00031 
00032 #include "common/file.h"
00033 #include "common/textconsole.h"
00034 
00035 namespace Grim {
00036 
00037 #ifndef STACK_LIMIT
00038 #define STACK_LIMIT     6000
00039 #endif
00040 
00041 // Extra stack size to run a function: LUA_T_LINE(1), TM calls(2), ...
00042 #define EXTRA_STACK 5
00043 
00044 /*
00045 ** Error messages
00046 */
00047 
00048 void stderrorim() {
00049     fprintf(stderr, "lua error: %s\n", lua_getstring(lua_getparam(1)));
00050 }
00051 
00052 #define STACK_UNIT  256
00053 
00054 // Initial size for CallInfo array
00055 #define BASIC_CI_SIZE   8
00056 
00057 void luaD_init() {
00058     ttype(&errorim) = LUA_T_CPROTO;
00059     fvalue(&errorim) = stderrorim;
00060 }
00061 
00062 void luaD_checkstack(int32 n) {
00063     struct Stack *S = &lua_state->stack;
00064     if (S->last-S->top <= n) {
00065         StkId top = S->top-S->stack;
00066         int32 stacksize = (S->last-S->stack) + 1 + STACK_UNIT + n;
00067         S->stack = luaM_reallocvector(S->stack, stacksize, TObject);
00068         S->last = S->stack + (stacksize - 1);
00069         S->top = S->stack + top;
00070         if (stacksize >= STACK_LIMIT) {  // stack overflow?
00071             if (lua_stackedfunction(100) == LUA_NOOBJECT)  // 100 funcs on stack?
00072                 lua_error("Lua2C - C2Lua overflow"); // doesn't look like a rec. loop
00073             else
00074                 lua_error("stack size overflow");
00075         }
00076     }
00077 }
00078 
00079 /*
00080 ** Adjust stack. Set top to the given value, pushing NILs if needed.
00081 */
00082 void luaD_adjusttop(StkId newtop) {
00083     int32 diff = newtop-(lua_state->stack.top-lua_state->stack.stack);
00084     if (diff <= 0)
00085         lua_state->stack.top += diff;
00086     else {
00087         luaD_checkstack(diff);
00088         while (diff--)
00089             ttype(lua_state->stack.top++) = LUA_T_NIL;
00090     }
00091 }
00092 
00093 /*
00094 ** Open a hole below "nelems" from the lua_state->stack.top.
00095 */
00096 void luaD_openstack(int32 nelems) {
00097     luaO_memup(lua_state->stack.top - nelems + 1, lua_state->stack.top - nelems, nelems * sizeof(TObject));
00098     incr_top;
00099 }
00100 
00101 void luaD_lineHook(int32 line) {
00102     struct C_Lua_Stack oldCLS = lua_state->Cstack;
00103     StkId old_top = lua_state->Cstack.lua2C = lua_state->Cstack.base = lua_state->stack.top-lua_state->stack.stack;
00104     lua_state->Cstack.num = 0;
00105     (*lua_linehook)(line);
00106     lua_state->stack.top = lua_state->stack.stack + old_top;
00107     lua_state->Cstack = oldCLS;
00108 }
00109 
00110 void luaD_callHook(StkId base, TProtoFunc *tf, int32 isreturn) {
00111     struct C_Lua_Stack oldCLS = lua_state->Cstack;
00112     StkId old_top = lua_state->Cstack.lua2C = lua_state->Cstack.base = lua_state->stack.top - lua_state->stack.stack;
00113     lua_state->Cstack.num = 0;
00114     if (isreturn)
00115         (*lua_callhook)(LUA_NOOBJECT, "(return)", 0);
00116     else {
00117         TObject *f = lua_state->stack.stack + base - 1;
00118         if (tf)
00119             (*lua_callhook)(Ref(f), tf->fileName->str, tf->lineDefined);
00120         else
00121             (*lua_callhook)(Ref(f), "(C)", -1);
00122     }
00123     lua_state->stack.top = lua_state->stack.stack + old_top;
00124     lua_state->Cstack = oldCLS;
00125 }
00126 
00127 /*
00128 ** Call a C function.
00129 ** Cstack.num is the number of arguments; Cstack.lua2C points to the
00130 ** first argument. Returns an index to the first result from C.
00131 */
00132 static StkId callC(lua_CFunction f, StkId base) {
00133     struct C_Lua_Stack *CS = &lua_state->Cstack;
00134     struct C_Lua_Stack oldCLS = *CS;
00135     StkId firstResult;
00136     int32 numarg = (lua_state->stack.top - lua_state->stack.stack) - base;
00137     CS->num = numarg;
00138     CS->lua2C = base;
00139     CS->base = base + numarg;  // == top - stack
00140     if (lua_callhook) {
00141         TObject *r = lua_state->stack.stack + base - 1;
00142         (*lua_callhook)(Ref(r), "(C)", -1);
00143     }
00144     lua_state->state_counter2++;
00145     (*f)();  // do the actual call
00146     lua_state->state_counter2--;
00147 //  if (lua_callhook)  // func may have changed lua_callhook
00148 //      (*lua_callhook)(LUA_NOOBJECT, "(return)", 0);
00149     firstResult = CS->base;
00150     *CS = oldCLS;
00151     return firstResult;
00152 }
00153 
00154 static StkId callCclosure(struct Closure *cl, lua_CFunction f, StkId base) {
00155     TObject *pbase;
00156     int32 nup = cl->nelems;  // number of upvalues
00157     luaD_checkstack(nup);
00158     pbase = lua_state->stack.stack + base;  // care: previous call may change this
00159     // open space for upvalues as extra arguments
00160     luaO_memup(pbase+nup, pbase, (lua_state->stack.top - pbase) * sizeof(TObject));
00161     // copy upvalues into stack
00162     memcpy(pbase, cl->consts + 1, nup * sizeof(TObject));
00163     lua_state->stack.top += nup;
00164     return callC(f, base);
00165 }
00166 
00167 void luaD_callTM(TObject *f, int32 nParams, int32 nResults) {
00168     luaD_openstack(nParams);
00169     *(lua_state->stack.top - nParams - 1) = *f;
00170     lua_state->state_counter1++;
00171     lua_state->state_counter2++;
00172     luaD_call((lua_state->stack.top - lua_state->stack.stack) - nParams, nResults);
00173     lua_state->state_counter2--;
00174     lua_state->state_counter1--;
00175 }
00176 
00177 int32 luaD_call(StkId base, int32 nResults) {
00178     lua_Task *tmpTask = lua_state->task;
00179     if (!lua_state->task || lua_state->state_counter2) {
00180         lua_Task *t = luaM_new(lua_Task);
00181         lua_taskinit(t, lua_state->task, base, nResults);
00182         lua_state->task = t;
00183     } else {
00184         tmpTask = lua_state->some_task;
00185     }
00186 
00187     while (1) {
00188         lua_CFunction function = nullptr;
00189         StkId firstResult = 0;
00190         TObject *funcObj = lua_state->stack.stack + base - 1;
00191         if (ttype(funcObj) == LUA_T_CLOSURE) {
00192             Closure *c = clvalue(funcObj);
00193             TObject *proto = &(c->consts[0]);
00194             ttype(funcObj) = LUA_T_CLMARK;
00195             if (ttype(proto) == LUA_T_CPROTO) {
00196                 function = fvalue(funcObj);
00197                 firstResult = callCclosure(c, fvalue(proto), base);
00198             } else {
00199                 lua_taskresume(lua_state->task, c, tfvalue(proto), base);
00200                 firstResult = luaV_execute(lua_state->task);
00201             }
00202         } else if (ttype(funcObj) == LUA_T_PMARK) {
00203             if (!lua_state->task->some_flag) {
00204                 TObject *im = luaT_getimbyObj(funcObj, IM_FUNCTION);
00205                 if (ttype(im) == LUA_T_NIL)
00206                     lua_error("call expression not a function");
00207                 luaD_callTM(im, (lua_state->stack.top - lua_state->stack.stack) - (base - 1), nResults);
00208                 continue;
00209             }
00210             firstResult = luaV_execute(lua_state->task);
00211         } else if (ttype(funcObj) == LUA_T_CMARK) {
00212             if (!lua_state->task->some_flag) {
00213                 TObject *im = luaT_getimbyObj(funcObj, IM_FUNCTION);
00214                 if (ttype(im) == LUA_T_NIL)
00215                     lua_error("call expression not a function");
00216                 luaD_callTM(im, (lua_state->stack.top - lua_state->stack.stack) - (base - 1), nResults);
00217                 continue;
00218             }
00219         } else if (ttype(funcObj) == LUA_T_CLMARK) {
00220             Closure *c = clvalue(funcObj);
00221             TObject *proto = &(c->consts[0]);
00222             if (!lua_state->task->some_flag) {
00223                 TObject *im = luaT_getimbyObj(funcObj, IM_FUNCTION);
00224                 if (ttype(im) == LUA_T_NIL)
00225                     lua_error("call expression not a function");
00226                 luaD_callTM(im, (lua_state->stack.top - lua_state->stack.stack) - (base - 1), nResults);
00227                 continue;
00228             }
00229             if (ttype(proto) != LUA_T_CPROTO)
00230                 firstResult = luaV_execute(lua_state->task);
00231         } else if (ttype(funcObj) == LUA_T_PROTO) {
00232             ttype(funcObj) = LUA_T_PMARK;
00233             lua_taskresume(lua_state->task, nullptr, tfvalue(funcObj), base);
00234             firstResult = luaV_execute(lua_state->task);
00235         } else if (ttype(funcObj) == LUA_T_CPROTO) {
00236             ttype(funcObj) = LUA_T_CMARK;
00237             function = fvalue(funcObj);
00238             firstResult = callC(fvalue(funcObj), base);
00239         } else {
00240             TObject *im = luaT_getimbyObj(funcObj, IM_FUNCTION);
00241             if (ttype(im) == LUA_T_NIL) {
00242                 // NOTE: Originally this throwed the lua_error. Anyway it is commented here because
00243                 // when in year 4 bi.exit() calls bi.book.act:free(). But bi.book.act is nil,
00244                 // hence it enters this branch and the error blocks the game.
00245                 // Now we try instead to survive and go on with the function.
00246                 lua_Task *t = lua_state->task;
00247                 lua_state->task = t->next;
00248                 lua_state->some_task = tmpTask;
00249                 luaM_free(t);
00250 
00251                 warning("Lua: call expression not a function");
00252                 return 1;
00253 //              lua_error("call expression not a function");
00254             }
00255             luaD_callTM(im, (lua_state->stack.top - lua_state->stack.stack) - (base - 1), nResults);
00256             continue;
00257         }
00258 
00259         if (firstResult <= 0) {
00260             nResults = lua_state->task->aux;
00261             base = -firstResult;
00262             lua_Task *t = luaM_new(lua_Task);
00263             lua_taskinit(t, lua_state->task, base, nResults);
00264             lua_state->task = t;
00265         } else {
00266             nResults = lua_state->task->some_results;
00267             base = lua_state->task->some_base;
00268             if (nResults != 255)
00269                 luaD_adjusttop(firstResult + nResults);
00270             base--;
00271             nResults = lua_state->stack.top - (lua_state->stack.stack + firstResult);
00272             for (int32 i = 0; i < nResults; i++)
00273                 *(lua_state->stack.stack + base + i) = *(lua_state->stack.stack + firstResult + i);
00274             lua_state->stack.top -= firstResult - base;
00275 
00276             lua_Task *tmp = lua_state->task;
00277             lua_state->task = lua_state->task->next;
00278             luaM_free(tmp);
00279             if (lua_state->task) {
00280                 nResults = lua_state->task->some_results;
00281                 base = lua_state->task->some_base;
00282             }
00283 
00284             if (function == break_here || function == sleep_for) {
00285                 if (!lua_state->state_counter1)  {
00286                     lua_state->some_task = tmpTask;
00287                     return 1;
00288                 }
00289             }
00290         }
00291 
00292         if (lua_state->task == tmpTask)
00293             break;
00294     }
00295 
00296     return 0;
00297 }
00298 
00299 static void travstack(struct Stack *S, int32 (*fn)(TObject *)) {
00300     StkId i;
00301     for (i = (S->top - 1) - S->stack; i >= 0; i--)
00302         fn(S->stack + i);
00303 }
00304 
00305 /*
00306 ** Traverse all objects on lua_state->stack.stack, and all other active stacks
00307 */
00308 void luaD_travstack(int32(*fn)(TObject *)) {
00309     LState *t;
00310     for (t = lua_rootState; t != nullptr; t = t->next) {
00311         travstack(&t->stack, fn);
00312     }
00313 }
00314 
00315 static void message(const char *s) {
00316     TObject im = errorim;
00317     if (ttype(&im) != LUA_T_NIL) {
00318         lua_pushstring(s);
00319         luaD_callTM(&im, 1, 0);
00320     }
00321 }
00322 
00323 /*
00324 ** Reports an error, and jumps up to the available recover label
00325 */
00326 void lua_error(const char *s) {
00327     if (s)
00328         message(s);
00329     if (lua_state->errorJmp) {
00330         longjmp(*((jmp_buf *)lua_state->errorJmp), 1);
00331     } else {
00332         fprintf(stderr, "lua: exit(1). Unable to recover\n");
00333         exit(1);
00334     }
00335 }
00336 
00337 /*
00338 ** Call the function at lua_state->Cstack.base, and incorporate results on
00339 ** the Lua2C structure.
00340 */
00341 static void do_callinc(int32 nResults) {
00342     StkId base = lua_state->Cstack.base;
00343     luaD_call(base + 1, nResults);
00344     lua_state->Cstack.lua2C = base;  // position of the luaM_new results
00345     lua_state->Cstack.num = (lua_state->stack.top - lua_state->stack.stack) - base;  // number of results
00346     lua_state->Cstack.base = base + lua_state->Cstack.num;  // incorporate results on lua_state->stack.stack/
00347 }
00348 
00349 /*
00350 ** Execute a protected call. Assumes that function is at lua_state->Cstack.base and
00351 ** parameters are on top of it. Leave nResults on the stack.
00352 */
00353 int32 luaD_protectedrun(int32 nResults) {
00354     jmp_buf myErrorJmp;
00355     int32 status;
00356     struct C_Lua_Stack oldCLS = lua_state->Cstack;
00357     jmp_buf *oldErr = lua_state->errorJmp;
00358     lua_state->errorJmp = &myErrorJmp;
00359     lua_state->state_counter1++;
00360     lua_Task *tmpTask = lua_state->task;
00361     if (setjmp(myErrorJmp) == 0) {
00362         do_callinc(nResults);
00363         status = 0;
00364     } else { // an error occurred: restore lua_state->Cstack and lua_state->stack.top
00365         lua_state->Cstack = oldCLS;
00366         lua_state->stack.top = lua_state->stack.stack + lua_state->Cstack.base;
00367         while (tmpTask != lua_state->task) {
00368             lua_Task *t = lua_state->task;
00369             lua_state->task = lua_state->task->next;
00370             luaM_free(t);
00371         }
00372         status = 1;
00373     }
00374     lua_state->state_counter1--;
00375     lua_state->errorJmp = oldErr;
00376     return status;
00377 }
00378 
00379 /*
00380 ** returns 0 = chunk loaded; 1 = error; 2 = no more chunks to load
00381 */
00382 static int32 protectedparser(ZIO *z, int32 bin) {
00383     int32 status;
00384     TProtoFunc *tf;
00385     jmp_buf myErrorJmp;
00386     jmp_buf *oldErr = lua_state->errorJmp;
00387     lua_state->errorJmp = &myErrorJmp;
00388     if (setjmp(myErrorJmp) == 0) {
00389         tf = bin ? luaU_undump1(z) : luaY_parser(z);
00390         status = 0;
00391     } else {
00392         tf = nullptr;
00393         status = 1;
00394     }
00395     lua_state->errorJmp = oldErr;
00396     if (status)
00397         return 1;  // error code
00398     if (tf == nullptr)
00399         return 2;  // 'natural' end
00400     luaD_adjusttop(lua_state->Cstack.base + 1);  // one slot for the pseudo-function
00401     lua_state->stack.stack[lua_state->Cstack.base].ttype = LUA_T_PROTO;
00402     lua_state->stack.stack[lua_state->Cstack.base].value.tf = tf;
00403     luaV_closure(0);
00404     return 0;
00405 }
00406 
00407 static int32 do_main(ZIO *z, int32 bin) {
00408     int32 status;
00409     do {
00410         int32 old_blocks = (luaC_checkGC(), nblocks);
00411         status = protectedparser(z, bin);
00412         if (status == 1)
00413             return 1;  // error
00414         else if (status == 2)
00415             return 0;  // 'natural' end
00416         else {
00417             int32 newelems2 = 2 * (nblocks - old_blocks);
00418             GCthreshold += newelems2;
00419             status = luaD_protectedrun(MULT_RET);
00420             GCthreshold -= newelems2;
00421         }
00422     } while (bin && status == 0);
00423     return status;
00424 }
00425 
00426 void luaD_gcIM(TObject *o) {
00427     TObject *im = luaT_getimbyObj(o, IM_GC);
00428     if (ttype(im) != LUA_T_NIL) {
00429         *lua_state->stack.top = *o;
00430         incr_top;
00431         luaD_callTM(im, 1, 0);
00432     }
00433 }
00434 
00435 #define SIZE_PREF 20  // size of string prefix to appear in error messages
00436 #define SSIZE_PREF "20"
00437 
00438 static void build_name (const char *str, char *name) {
00439     if (str == nullptr || *str == ID_CHUNK)
00440         strcpy(name, "(buffer)");
00441     else {
00442         char *temp;
00443         sprintf(name, "(dostring) >> \"%." SSIZE_PREF "s\"", str);
00444         temp = strchr(name, '\n');
00445         if (temp) {  // end string after first line
00446             *temp = '"';
00447             *(temp + 1) = 0;
00448         }
00449     }
00450 }
00451 
00452 int32 lua_dostring(const char *str) {
00453     return lua_dobuffer(str, strlen(str), nullptr);
00454 }
00455 
00456 int32 lua_dobuffer(const char *buff, int32 size, const char *name) {
00457     char newname[SIZE_PREF + 25];
00458     ZIO z;
00459     int32 status;
00460 
00461     if (!name) {
00462         build_name(buff, newname);
00463         name = newname;
00464     }
00465     luaZ_mopen(&z, buff, size, name);
00466     status = do_main(&z, buff[0] == ID_CHUNK);
00467     return status;
00468 }
00469 
00470 } // end of namespace Grim


Generated on Sat Feb 16 2019 05:00:55 for ResidualVM by doxygen 1.7.1
curved edge   curved edge