diff options
Diffstat (limited to 'engines/sword25/util/pluto')
-rw-r--r-- | engines/sword25/util/pluto/CHANGELOG | 37 | ||||
-rw-r--r-- | engines/sword25/util/pluto/FILEFORMAT | 168 | ||||
-rw-r--r-- | engines/sword25/util/pluto/README | 133 | ||||
-rw-r--r-- | engines/sword25/util/pluto/THANKS | 9 | ||||
-rw-r--r-- | engines/sword25/util/pluto/pdep.cpp | 112 | ||||
-rw-r--r-- | engines/sword25/util/pluto/pdep/README | 5 | ||||
-rw-r--r-- | engines/sword25/util/pluto/pdep/lzio.h | 65 | ||||
-rw-r--r-- | engines/sword25/util/pluto/pdep/pdep.h | 42 | ||||
-rw-r--r-- | engines/sword25/util/pluto/pluto.cpp | 2083 | ||||
-rw-r--r-- | engines/sword25/util/pluto/pluto.h | 25 | ||||
-rw-r--r-- | engines/sword25/util/pluto/plzio.cpp | 74 |
11 files changed, 0 insertions, 2753 deletions
diff --git a/engines/sword25/util/pluto/CHANGELOG b/engines/sword25/util/pluto/CHANGELOG deleted file mode 100644 index 1be321f898..0000000000 --- a/engines/sword25/util/pluto/CHANGELOG +++ /dev/null @@ -1,37 +0,0 @@ -$Id$ - --- 2.4 -- -* Changed upval unboxing to allow upvals which contain func-housed cycles -* Added stack checking to all stack-growing functions -* Serialized debug information for functions - --- 2.3 -- -* Added LUALIB_API declaration for luaopen_pluto - --- 2.2 -- -* Rolled all internal Lua dependencies into the Pluto distribution -* Made the unit tests depend on dynamically loading Pluto - --- 2.1 -- -* Various fixes to make the GC happy -* stack size always expanded where necessary -* fixed some memory leaks -* GC disabled during unpersist -* callstack initialized for traversal - -This changelog is maintained as of version 2.0alpha1. -Earlier versions are changelogged on the LuaForge site. - --- 2.0 -- -* Fixed a few format changes to 5.1.3 -* Fixed myriad warnings -* GCC compliance: not incrementing cast results -* Fix for self-referring upvals -* Renamed loading function to work with Lua module system -* Loading tables with __newindex works -* unpersist makes buffer copy - --- 2.0alpha1 -- -* Fixed all outstanding 5.0->5.1 conversion issues -* Made heavier use of size_t in preference to int -* Fixed GC/Upval issue (thanks to Eric Jacobs) diff --git a/engines/sword25/util/pluto/FILEFORMAT b/engines/sword25/util/pluto/FILEFORMAT deleted file mode 100644 index e7716675c7..0000000000 --- a/engines/sword25/util/pluto/FILEFORMAT +++ /dev/null @@ -1,168 +0,0 @@ -$Id$ - -pluto_persist() produces a "hunk" of objects. Here's the file format adhered -to by the function, and expected by pluto_unpersist(). - -As a developer, I feel that where file format information is given it is of -utmost importance that that information precisely and accurately reflects the -actual operation of the application. Therefore, if you find any discrepancy -between this and actual operation, please lambast me thoroughly over email. - -Pseudo-C is used to express the file format. Padding is assumed to be -nonexistent. The keyword "one_of" is used to express a concept similar to -"union", except that its size is the size of the actual datatype chosen. Thus, -objects which contain, directly or indirectly, a one_of, may vary in size. - - -struct Object { - int firstTime; /* Whether this is the first time the object - is being referenced */ - one_of { - RealObject o; /* if firstTime == 1 */ - Reference r; /* if firstTime == 0 */ - }; -}; - -struct Reference { - int ref; /* The index the object was registered with */ -}; - -struct RealObject { - int type; /* The type of the object */ - one_of { - Boolean b; /* If type == LUA_TBOOLEAN */ - LightUserData l; /* If type == LUA_TLIGHTUSERDATA */ - Number n; /* If type == LUA_TNUMBER */ - String s; /* If type == LUA_TSTRING */ - Table t; /* If type == LUA_TTABLE */ - Function f; /* If type == LUA_TFUNCTION */ - Userdata u; /* If type == LUA_TUSERDATA */ - Thread th; /* If type == LUA_TTHREAD */ - Proto p; /* If type == LUA_TPROTO (from lobject.h) */ - Upval uv; /* If type == LUA_TUPVAL (from lobject.h) */ - }; /* The actual object */ -}; - -struct Boolean { - int32 bvalue; /* 0 for false, 1 for true */ -}; - -struct LightUserData { - void* luvalue; /* The actual, literal pointer */ -}; - -struct Number { - lua_Number nvalue; /* The actual number */ -}; - -struct String { - int length; /* The length of the string */ - char str[length]; /* The actual string (not null terminated) */ -}; - -struct Table { - int isspecial; /* 1 if SP is used; 0 otherwise */ - one_of { - Closure c; /* if isspecial == 1; closure to refill the table */ - LiteralTable t; /* if isspecial == 0; literal table info */ - }; -}; - -struct LiteralTable { - Object metatable; /* nil for default metatable */ - Pair p[]; /* key/value pairs */ - Object nil = nil; /* Nil reference to terminate */ -}; - -struct Pair { - Object key; - Object value; -}; - -struct Function { /* Actually a closure */ - lu_byte nups; /* Number of upvalues the function uses */ - Object proto; /* The proto this function uses */ - Object upvals[nups]; /* All upvalues */ - Object fenv; /* The FEnv (nil for the global table) -}; - -struct Upval { - Object obj; /* The object this upval refers to */ -} - -struct Userdata { - int isSpecial; /* 1 for special persistence, 0 for literal - one_of { - LiteralUserdata lu; /* if is_special is 0 */ - SpecialUserdata su; /* if is_special is 1 */ - }; -}; - -struct LiteralUserdata { - Object metatable; /* The metatable (nil for default) */ - int length; /* Size of the data */ - char data[length]; /* The actual data */ -}; - -struct SpecialUserdata { - int length; /* The size of the data */ - Object func; /* The closure used to fill the userdata */ -}; - -struct Thread { - int stacksize; /* The size of the stack filled with objects, - * including the "nil" that is hidden below - * the bottom of the stack visible to C */ - Object stack[stacksize];/* Indices of all stack values, bottom up */ - int callinfosize; /* Number of elements in the CallInfo stack */ - CallInfo callinfostack[callinfosize]; /* The CallInfo stack */ - int base; /* base = L->base - L->stack; */ - int top; /* top = L->top - L->stack; */ - OpenUpval openupvals[]; /* Upvalues to open */ - Object nil = nil; /* To terminate the open upvalues list */ -}; - -struct OpenUpval { - Object upval; /* The upvalue */ - int stackpos; /* The stack position to "reopen" it to */ - -}; - -struct CallInfo { - int base; /* base = ci->base - L->stack; */ - int top; /* top = ci->top - L->stack; */ - int pc; /* pc = ci->pc - proto->code; */ - int state; /* flags used by the CallInfo */ -}; - -struct Proto { - int sizek; /* Number of constants referenced */ - Object k[sizek]; /* Constants referenced */ - int sizep; /* Number of inner Protos referenced */ - Object p[sizep]; /* Inner Protos referenced */ - int sizecode; /* Number of instructions in code */ - Instruction code[sizecode]; /* The proto's code */ - ProtoDebug debuginfo; /* Debug information for the proto */ - lu_byte nups; /* Number of upvalues used */ - lu_byte numparams; /* Number of parameters taken */ - lu_byte is_vararg; /* 1 if function accepts varargs, 0 otherwise */ - lu_byte maxstacksize; /* Size of stack reserved for the function */ -}; - -struct ProtoDebug { - int sizeupvals; /* Number of upvalue names */ - Object upvals; /* Upvalue names */ - int sizelocvars; /* Number of local variable names */ - LocVar[sizelocvars]; /* Local variable names */ - Object source; /* The source code */ - int sizelineinfo; /* Number of opcode-line mappings */ - int lineinfo[sizelineinfo]; /* opcode-line mappings */ - int linedefined; /* Start of line range */ - int lastlinedefined; /* End of line range */ -}; - -struct LocVar { - Object name; /* Name of the local variable */ - int startpc; /* Point where variable is active */ - int endpc; /* Point where variable is dead */ -}; diff --git a/engines/sword25/util/pluto/README b/engines/sword25/util/pluto/README deleted file mode 100644 index 838fce498b..0000000000 --- a/engines/sword25/util/pluto/README +++ /dev/null @@ -1,133 +0,0 @@ -$Id$ - -PLUTO - Heavy duty persistence for Lua - -Pluto is a library which allows users to write arbitrarily large portions -of the "Lua universe" into a flat file, and later read them back into the -same or a different Lua universe. Object references are appropriately -handled, such that the file contains everything needed to recreate the -objects in question. - -Pluto has the following major features: -* Can persist any Lua function -* Can persist threads -* Works with any Lua chunkreader/chunkwriter -* Support for "invariant" permanent objects, of all datatypes -* Can invoke metafunctions for custom persistence of tables and userdata - -Pluto 2.2 requires Lua 5.1.3. If you need to use Pluto with Lua -5.0, please use version 1.2 of Pluto. - -Starting with version 2.2, Pluto no longer depends on the Lua sources. -Instead, it subsumes the required headers into its own codebase. -As a result, it may not work properly with Lua version 5.1.4 or later. - -Pluto may have bugs. Users are advised to define lua_assert in -luaconf.h to something useful when compiling in debug mode, to catch -assertions by Pluto and Lua. - -The Pluto library consists of two public functions. - -int pluto_persist(lua_State *L, lua_Chunkwriter writer, void *ud) - -This function recursively persists the Lua object in stack position 2 -and all other objects which are directly or indirectly referenced by -it, except those referenced in the permanent object table. The data -is written using the chunk-writer given, and that writer is passed -the arbitrary pointer value ud. - -The Lua stack must contain exactly and only these two items, in order: - -1. A table of permanent objects, that should not be persisted. For each -permanent object, the object itself should be the key, and a unique -object of any type should be the value. Likely candidates for this table -include Lua functions (including those in the Lua libraries) that are -loaded at load-time. It must include all non-persistable objects that -are referenced by the object to be persisted. The table is not modified -by the function. Objects in this table are considered "opaque" and are -not examined or descended into. Objects should not appear in the table -multiple times; the result of doing this is undefined (though probably -harmless). NOTE: If you are planning to persist threads, keep in mind -that all yielded threads have coroutine.yield on the tops of their -stacks. Since it's a C function, it should be put here. For complex -permanents, it may be a good idea to use the __index meta-function of -the permanents table to "search" for permanents. - -2. The single object to be persisted. In many cases, this will be the -global table. For more flexibility, however, it may be something like a -table built for the occasion, with various values to keep track of. The -object may not be nil. - - -int pluto_unpersist(lua_State *L, lua_Chunkreader reader, void *ud) - -This function loads in a Lua object and places it on top of the stack. All -objects directly or indirectly referenced by it are also loaded. - -The Lua stack must contain, as its top value, a table of permanent -objects. This table should be like the permanent object table used when -persisting, but with the key and value of each pair reversed. These -objects are used as substitutes for those referenced in their positions -when persisting, and under most circumstances should be identical objects -to those referenced in the permanents table used for persisting. It's -okay for multiple keys to refer to the same object. - - -RUNNING PLUTO FROM LUA: -It is also possible to invoke pluto from a Lua script. The C function -pluto_open() will register pluto.persist and pluto.unpersist, lua functions -which operate on strings. The first takes a permanents table and a root -object, and returns a string; the second takes a permanents table and a -string, and returns the root object. - -An error will be raised if pluto.persist is called from a thread which is -itself referenced by the root object. - -SPECIAL PERSISTENCE: -Tables and userdata have special persistence semantics. These semantics are -keyed to the value of the object's metatable's __persist member, if any. This -member may be any of the following four values: -1. Boolean "true": The table or userdata is persisted literally; tables are -persisted member-by-member, and userdata are written out as literal data. -2. Boolean "false": An error is returned, indicating that the object cannot -be persisted. -3. A function: This function should take one argument, the object in question, -and return one result, a closure. This "fixup closure", in turn, will be -persisted, and during unpersistence will be called. The closure will be -responsible for recreating the object with the appropriate data, based on -its upvalues. -4. Nil, or no metatable. In the case of tables, the table is literally -persisted. In the case of userdata, an error is returned. - -Here's an example of special persistence for a simple 3d vector object: - -vec = { x = 2, y = 1, z = 4 } -setmetatable(vec, { __persist = function(oldtbl) - local x = oldtbl.x - local y = oldtbl.y - local z = oldtbl.z - local mt = getmetatable(oldtbl) - return function() - newtbl = {} - newtbl.x = x - newtbl.y = y - newtbl.z = z - setmetatable(newtbl, mt) - return newtbl - end -end }) - -Note how x, y, z, and the mt are explicitly pulled out of the table. It is -important that the fixup closure returned not reference the original table -directly, as that table would again be persisted as an upvalue, leading to an -infinite loop. Also note that the object's metatable is NOT automatically -persisted; it is necessary for the fixup closure to reset it, if it wants. - -LIMITATIONS/TODO: -* Light userdata are persisted literally, as their pointer values. This -may or may not be what you want. -* Closures of C functions may not be persisted. Once it becomes possible -to specify a C function "proto" as a permanent object, this restriction -will be relaxed. - -BUGS: None known. Emphasis on the 'known'. diff --git a/engines/sword25/util/pluto/THANKS b/engines/sword25/util/pluto/THANKS deleted file mode 100644 index 443713fa61..0000000000 --- a/engines/sword25/util/pluto/THANKS +++ /dev/null @@ -1,9 +0,0 @@ -Pluto is surprisingly robust and useful. This would not be the case without -the hard work and helpfulness of the following people, mentioned in no -particular order: - -Ivko Stanilov -Goran Adrinek -Eric Jacobs -Anolan Milanes -Malte Thiesen diff --git a/engines/sword25/util/pluto/pdep.cpp b/engines/sword25/util/pluto/pdep.cpp deleted file mode 100644 index a32c43b42d..0000000000 --- a/engines/sword25/util/pluto/pdep.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* This file is derived from the Lua source code. Please see lua.h for -the copyright statement. -*/ - -#include "pdep/pdep.h" - -#define api_incr_top(L) {api_check(L, L->top < L->ci->top); L->top++;} - -void pdep_pushobject (lua_State *L, const TValue *o) { - setobj2s(L, L->top, o); - api_incr_top(L); -} - -void *pdep_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { - global_State *g = G(L); - lua_assert((osize == 0) == (block == NULL)); - block = (*g->frealloc)(g->ud, block, osize, nsize); - lua_assert((nsize == 0) == (block == NULL)); - g->totalbytes = (g->totalbytes - osize) + nsize; - return block; -} - -void pdep_link (lua_State *L, GCObject *o, lu_byte tt) { - global_State *g = G(L); - o->gch.next = g->rootgc; - g->rootgc = o; - o->gch.marked = luaC_white(g); - o->gch.tt = tt; -} - -Proto *pdep_newproto (lua_State *L) { - Proto *f = pdep_new(L, Proto); - pdep_link(L, obj2gco(f), LUA_TPROTO); - f->k = NULL; - f->sizek = 0; - f->p = NULL; - f->sizep = 0; - f->code = NULL; - f->sizecode = 0; - f->sizelineinfo = 0; - f->sizeupvalues = 0; - f->nups = 0; - f->upvalues = NULL; - f->numparams = 0; - f->is_vararg = 0; - f->maxstacksize = 0; - f->lineinfo = NULL; - f->sizelocvars = 0; - f->locvars = NULL; - f->linedefined = 0; - f->lastlinedefined = 0; - f->source = NULL; - return f; -} - -Closure *pdep_newLclosure (lua_State *L, int nelems, Table *e) { - Closure *c = cast(Closure *, pdep_malloc(L, sizeLclosure(nelems))); - pdep_link(L, obj2gco(c), LUA_TFUNCTION); - c->l.isC = 0; - c->l.env = e; - c->l.nupvalues = cast_byte(nelems); - while (nelems--) c->l.upvals[nelems] = NULL; - return c; -} - -static void correctstack (lua_State *L, TValue *oldstack) { - CallInfo *ci; - GCObject *up; - L->top = (L->top - oldstack) + L->stack; - for (up = L->openupval; up != NULL; up = up->gch.next) - gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack; - for (ci = L->base_ci; ci <= L->ci; ci++) { - ci->top = (ci->top - oldstack) + L->stack; - ci->base = (ci->base - oldstack) + L->stack; - ci->func = (ci->func - oldstack) + L->stack; - } - L->base = (L->base - oldstack) + L->stack; -} - - -void pdep_reallocstack (lua_State *L, int newsize) { - TValue *oldstack = L->stack; - int realsize = newsize + 1 + EXTRA_STACK; - lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); - pdep_reallocvector(L, L->stack, L->stacksize, realsize, TValue); - L->stacksize = realsize; - L->stack_last = L->stack+newsize; - correctstack(L, oldstack); -} - -void pdep_growstack (lua_State *L, int n) { - if (n <= L->stacksize) /* double size is enough? */ - pdep_reallocstack(L, 2*L->stacksize); - else - pdep_reallocstack(L, L->stacksize + n); -} - -void pdep_reallocCI (lua_State *L, int newsize) { - CallInfo *oldci = L->base_ci; - pdep_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo); - L->size_ci = newsize; - L->ci = (L->ci - oldci) + L->base_ci; - L->end_ci = L->base_ci + L->size_ci - 1; -} - -TString *pdep_newlstr (lua_State *L, const char *str, size_t l) { - TString *res; - lua_pushlstring(L, str, l); - res = rawtsvalue(L->top-1); - lua_pop(L, 1); - return res; -} diff --git a/engines/sword25/util/pluto/pdep/README b/engines/sword25/util/pluto/pdep/README deleted file mode 100644 index 3592754da0..0000000000 --- a/engines/sword25/util/pluto/pdep/README +++ /dev/null @@ -1,5 +0,0 @@ -These files are directly copied from the Lua distribution, with the -exception of lzio.h, which is s/lua{ZM}/pdep/g and has an include removed. - -As such, unlike the rest of Pluto, they are released under the -same terms as Lua. See "lua.h" for the copyright notice. diff --git a/engines/sword25/util/pluto/pdep/lzio.h b/engines/sword25/util/pluto/pdep/lzio.h deleted file mode 100644 index 2e37f8d202..0000000000 --- a/engines/sword25/util/pluto/pdep/lzio.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -** $Id$ -** Buffered streams -** See Copyright Notice in lua.h -*/ - - -#ifndef lzio_h -#define lzio_h - -#include "sword25/util/lua/lua.h" - - -#define EOZ (-1) /* end of stream */ - -typedef struct Zio ZIO; - -#define char2int(c) cast(int, cast(unsigned char, (c))) - -#define zgetc(z) (((z)->n--)>0 ? char2int(*(z)->p++) : pdep_fill(z)) - -typedef struct Mbuffer { - char *buffer; - size_t n; - size_t buffsize; -} Mbuffer; - -#define pdep_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) - -#define pdep_buffer(buff) ((buff)->buffer) -#define pdep_sizebuffer(buff) ((buff)->buffsize) -#define pdep_bufflen(buff) ((buff)->n) - -#define pdep_resetbuffer(buff) ((buff)->n = 0) - - -#define pdep_resizebuffer(L, buff, size) \ - (pdep_reallocvector(L, (buff)->buffer, (buff)->buffsize, size, char), \ - (buff)->buffsize = size) - -#define pdep_freebuffer(L, buff) pdep_resizebuffer(L, buff, 0) - - -LUAI_FUNC char *pdep_openspace (lua_State *L, Mbuffer *buff, size_t n); -LUAI_FUNC void pdep_init (lua_State *L, ZIO *z, lua_Reader reader, - void *data); -LUAI_FUNC size_t pdep_read (ZIO* z, void* b, size_t n); /* read next n bytes */ -LUAI_FUNC int pdep_lookahead (ZIO *z); - - - -/* --------- Private Part ------------------ */ - -struct Zio { - size_t n; /* bytes still unread */ - const char *p; /* current position in buffer */ - lua_Reader reader; - void* data; /* additional data */ - lua_State *L; /* Lua state (for reader) */ -}; - - -LUAI_FUNC int pdep_fill (ZIO *z); - -#endif diff --git a/engines/sword25/util/pluto/pdep/pdep.h b/engines/sword25/util/pluto/pdep/pdep.h deleted file mode 100644 index 664fc812b5..0000000000 --- a/engines/sword25/util/pluto/pdep/pdep.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef PDEP_H -#define PDEP_H - -#include "sword25/util/lua/lua.h" -#include "sword25/util/pluto/pdep/lzio.h" -#include "sword25/util/lua/ldo.h" -#include "sword25/util/lua/lfunc.h" -#include "sword25/util/lua/lgc.h" -#include "sword25/util/lua/llimits.h" -#include "sword25/util/lua/lobject.h" -#include "sword25/util/lua/lopcodes.h" -#include "sword25/util/lua/lstate.h" -#include "sword25/util/lua/lstring.h" -#include "sword25/util/lua/lauxlib.h" - - -#define pdep_reallocv(L,b,on,n,e) \ - pdep_realloc_(L, (b), (on)*(e), (n)*(e)) -#define pdep_reallocvector(L, v,oldn,n,t) \ - ((v)=cast(t *, pdep_reallocv(L, v, oldn, n, sizeof(t)))) -#define pdep_freearray(L, b, n, t) pdep_reallocv(L, (b), n, 0, sizeof(t)) -#define pdep_newvector(L,n,t) \ - cast(t *, pdep_reallocv(L, NULL, 0, n, sizeof(t))) -#define pdep_new(L,t) cast(t *, pdep_malloc(L, sizeof(t))) -#define pdep_malloc(L,t) pdep_realloc_(L, NULL, 0, (t)) -#define pdep_checkstack(L,n) \ - if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TValue)) \ - pdep_growstack(L, n); \ - else pdep_reallocstack(L, L->stacksize - EXTRA_STACK - 1); - - -void pdep_pushobject (lua_State *L, const TValue *o); -void *pdep_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize); -void pdep_link (lua_State *L, GCObject *o, lu_byte tt); -Proto *pdep_newproto (lua_State *L); -Closure *pdep_newLclosure (lua_State *L, int nelems, Table *e); -void pdep_reallocstack (lua_State *L, int newsize); -void pdep_growstack (lua_State *L, int n); -void pdep_reallocCI (lua_State *L, int newsize); -TString *pdep_newlstr (lua_State *L, const char *str, size_t l); - -#endif diff --git a/engines/sword25/util/pluto/pluto.cpp b/engines/sword25/util/pluto/pluto.cpp deleted file mode 100644 index cbe16b0d5b..0000000000 --- a/engines/sword25/util/pluto/pluto.cpp +++ /dev/null @@ -1,2083 +0,0 @@ -/* $Id$ */ - -/* Tamed Pluto - Heavy-duty persistence for Lua - * Copyright (C) 2004 by Ben Sunshine-Hill, and released into the public - * domain. People making use of this software as part of an application - * are politely requested to email the author at sneftel@gmail.com - * with a brief description of the application, primarily to satisfy his - * curiosity. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Instrumented by Stefan Reich (info@luaos.net) - * for Mobile Lua (http://luaos.net/pages/mobile-lua.php) - */ - -#include "sword25/util/lua/lua.h" -#include "pluto.h" - -#undef TOTEXT - -#define USE_PDEP - -#ifdef USE_PDEP -#include "pdep/pdep.h" -#define LIF(prefix, name) pdep ## _ ## name -#else -#include "lapi.h" -#include "ldo.h" -#include "lfunc.h" -#include "lgc.h" -#include "llimits.h" -#include "lmem.h" -#include "lobject.h" -#include "lopcodes.h" -#include "lstate.h" -#include "lstring.h" -#include "lauxlib.h" -#define LIF(prefix, name) lua ## prefix ## _ ## name -#endif - -#include <string.h> - - -/* Define this if you want size_t values to be written in 64-bit - (even on 32-bit systems). Should eliminate at least one source of - 32/64 bit incompatibility. */ -#define SIZES64 - - -/* #define PLUTO_DEBUG */ - - -#ifdef SIZES64 -#define VERSION "Tamed Pluto 1.0 with SIZES64 flag" -#else -#define VERSION "Tamed Pluto 1.0" -#endif - - -#ifdef PLUTO_DEBUG -#include <stdio.h> -#endif - -#define PLUTO_TPERMANENT 101 - -#define verify(x) { int v = (int)((x)); v=v; lua_assert(v); } - -#define NUMTYPES 9 -static const char* typenames[] = { - "nil", - "boolean", - "lightuserdata", - "number", - "string", - "table", - "function", - "userdata", - "thread" -}; - -static int humanReadable = 0; -#define hrBufSize 200 -static char hrBuf[hrBufSize]; - -typedef struct PersistInfo_t { - lua_State *L; - int counter; - lua_Chunkwriter writer; - void *ud; -#ifdef PLUTO_DEBUG - int level; -#endif -} PersistInfo; - -#ifdef PLUTO_DEBUG -void printindent(int indent) -{ - int il; - for(il=0; il<indent; il++) { - printf(" "); - } -} -#endif - -/* lua_Chunkwriter signature: (lua_State *L, const void *p, size_t sz, void *ud). - ud is a pointer to the WriterInfo struct (holds the buffer pointer) -*/ - -static void pi_write(PersistInfo *pi, const void *p, size_t size, void *ud) { - if (humanReadable) { - uint i; - snprintf(hrBuf, hrBufSize, " pi_write %d ", (int) size); - pi->writer(pi->L, hrBuf, strlen(hrBuf), ud); - for (i = 0; i < size; i++) { - char b = ((char *)p)[i]; - snprintf(hrBuf, hrBufSize, "%X%X", (b >> 4) & 0xF, b & 0xF); - pi->writer(pi->L, hrBuf, strlen(hrBuf), ud); - } - snprintf(hrBuf, hrBufSize, "\n"); - pi->writer(pi->L, hrBuf, strlen(hrBuf), ud); - } else { - pi->writer(pi->L, p, size, ud); - } -#ifdef TOTEXT - int i; - printf(" pi_write %d ", (int) size); - for (i = 0; i < size; i++) { - char b = ((char *)p)[i]; - printf("%X%X", (b >> 4) & 0xF, b & 0xF); - } - printf("\n"); -#endif -} - -static void hrOut(PersistInfo *pi) { - pi->writer(pi->L, hrBuf, strlen(hrBuf), pi->ud); -} - -static void write_size(PersistInfo *pi, size_t *val) -{ -#ifdef SIZES64 - int64 longval; /* yeah, you really need long long to get 8 bytes on win32... duh. */ - longval = *val; - pi_write(pi, &longval, 8, pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "write_size64 %ld\n", longval); - hrOut(pi); - } -#ifdef TOTEXT - printf("write_size64 %ld\n", longval); -#endif -#else - pi_write(pi, val, sizeof(size_t), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "write_size %ld\n", *((size_t *)val)); - hrOut(pi); - } -#ifdef TOTEXT - printf("write_size %ld\n", *val); -#endif -#endif -} - -static void read_size(ZIO *zio, size_t *val) -{ -#ifdef SIZES64 - int64 longval; - verify(LIF(Z,read)(zio, &longval, 8) == 0); - *val = longval; -#else - verify(LIF(Z,read)(zio, val, sizeof(size_t)) == 0); -#endif -} - - -/* Mutual recursion requires prototype */ -static void persist(PersistInfo *pi); - -/* A simple reimplementation of the unfortunately static function luaA_index. - * Does not support the global table, registry, or upvalues. */ -static StkId getobject(lua_State *L, int stackpos) -{ - if(stackpos > 0) { - lua_assert(L->base+stackpos-1 < L->top); - return L->base+stackpos-1; - } else { - lua_assert(L->top-stackpos >= L->base); - return L->top+stackpos; - } -} - -/* Choose whether to do a regular or special persistence based on an object's - * metatable. "default" is whether the object, if it doesn't have a __persist - * entry, is literally persistable or not. - * Pushes the unpersist closure and returns true if special persistence is - * used. */ -static int persistspecialobject(PersistInfo *pi, int defaction) -{ - /* perms reftbl ... obj */ - lua_checkstack(pi->L, 4); - /* Check whether we should persist literally, or via the __persist - * metafunction */ - if(!lua_getmetatable(pi->L, -1)) { - if(defaction) { - { - int zero = 0; - pi_write(pi, &zero, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistspecialobject_write_zero\n"); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistspecialobject_write_zero\n"); -#endif - } - return 0; - } else { - lua_pushstring(pi->L, "Type not literally persistable by default"); - lua_error(pi->L); - } - } - /* perms reftbl sptbl ... obj mt */ - lua_pushstring(pi->L, "__persist"); - /* perms reftbl sptbl ... obj mt "__persist" */ - lua_rawget(pi->L, -2); - /* perms reftbl sptbl ... obj mt __persist? */ - if(lua_isnil(pi->L, -1)) { - /* perms reftbl sptbl ... obj mt nil */ - lua_pop(pi->L, 2); - /* perms reftbl sptbl ... obj */ - if(defaction) { - { - int zero = 0; - pi_write(pi, &zero, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistspecialobject_write_zero2\n"); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistspecialobject_write_zero2\n"); -#endif - } - return 0; - } else { - lua_pushstring(pi->L, "Type not literally persistable by default"); - lua_error(pi->L); - return 0; /* not reached */ - } - } else if(lua_isboolean(pi->L, -1)) { - /* perms reftbl sptbl ... obj mt bool */ - if(lua_toboolean(pi->L, -1)) { - /* perms reftbl sptbl ... obj mt true */ - lua_pop(pi->L, 2); - /* perms reftbl sptbl ... obj */ - { - int zero = 0; - pi_write(pi, &zero, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistspecialobject_write_zero3\n"); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistspecialobject_write_zero3\n"); -#endif - } - return 0; - } else { - lua_pushstring(pi->L, "Metatable forbade persistence"); - lua_error(pi->L); - return 0; /* not reached */ - } - } else if(!lua_isfunction(pi->L, -1)) { - lua_pushstring(pi->L, "__persist not nil, boolean, or function"); - lua_error(pi->L); - } - /* perms reftbl ... obj mt __persist */ - lua_pushvalue(pi->L, -3); - /* perms reftbl ... obj mt __persist obj */ -#ifdef PLUTO_PASS_USERDATA_TO_PERSIST - lua_pushlightuserdata(pi->L, (void *)pi->writer); - lua_pushlightuserdata(pi->L, pi->ud); - /* perms reftbl ... obj mt __persist obj ud */ - lua_call(pi->L, 3, 1); - /* perms reftbl ... obj mt func? */ -#else - lua_call(pi->L, 1, 1); - /* perms reftbl ... obj mt func? */ -#endif - /* perms reftbl ... obj mt func? */ - if(!lua_isfunction(pi->L, -1)) { - lua_pushstring(pi->L, "__persist function did not return a function"); - lua_error(pi->L); - } - /* perms reftbl ... obj mt func */ - { - int one = 1; - pi_write(pi, &one, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistspecialobject_write_one\n"); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistspecialobject_write_one\n"); -#endif - } - persist(pi); - /* perms reftbl ... obj mt func */ - lua_pop(pi->L, 2); - /* perms reftbl ... obj */ - return 1; -} - -static void persisttable(PersistInfo *pi) -{ - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persisttable\n"); - hrOut(pi); - } -#ifdef TOTEXT - printf("persisttable\n"); -#endif - - /* perms reftbl ... tbl */ - lua_checkstack(pi->L, 3); - if(persistspecialobject(pi, 1)) { - /* perms reftbl ... tbl */ - return; - } - /* perms reftbl ... tbl */ - /* First, persist the metatable (if any) */ - if(!lua_getmetatable(pi->L, -1)) { - lua_pushnil(pi->L); - } - /* perms reftbl ... tbl mt/nil */ - persist(pi); - lua_pop(pi->L, 1); - /* perms reftbl ... tbl */ - - /* Now, persist all k/v pairs */ - lua_pushnil(pi->L); - /* perms reftbl ... tbl nil */ - while(lua_next(pi->L, -2)) { - /* perms reftbl ... tbl k v */ - lua_pushvalue(pi->L, -2); - /* perms reftbl ... tbl k v k */ - persist(pi); - lua_pop(pi->L, 1); - /* perms reftbl ... tbl k v */ - persist(pi); - lua_pop(pi->L, 1); - /* perms reftbl ... tbl k */ - } - /* perms reftbl ... tbl */ - /* Terminate list */ - lua_pushnil(pi->L); - /* perms reftbl ... tbl nil */ - persist(pi); - lua_pop(pi->L, 1); - /* perms reftbl ... tbl */ -} - -static void persistuserdata(PersistInfo *pi) { - /* perms reftbl ... udata */ - lua_checkstack(pi->L, 2); - if(persistspecialobject(pi, 0)) { - /* perms reftbl ... udata */ - return; - } else { - /* Use literal persistence */ - size_t length = uvalue(getobject(pi->L, -1))->len; - write_size(pi, &length); - pi_write(pi, lua_touserdata(pi->L, -1), length, pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistuserdata %ld\n", (long) length); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistuserdata %ld\n", (long) length); -#endif - if(!lua_getmetatable(pi->L, -1)) { - /* perms reftbl ... udata */ - lua_pushnil(pi->L); - /* perms reftbl ... udata mt/nil */ - } - persist(pi); - lua_pop(pi->L, 1); - /* perms reftbl ... udata */ - } -} - - -static Proto *toproto(lua_State *L, int stackpos) -{ - return gco2p(getobject(L, stackpos)->value.gc); -} - -static UpVal *toupval(lua_State *L, int stackpos) -{ - lua_assert(ttype(getobject(L, stackpos)) == LUA_TUPVAL); - return gco2uv(getobject(L, stackpos)->value.gc); -} - -static void pushproto(lua_State *L, Proto *proto) -{ - TValue o; - setptvalue(L, &o, proto); - LIF(A,pushobject)(L, &o); -} - -#define setuvvalue(L,obj,x) \ - { TValue *i_o=(obj); \ - i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUPVAL; \ - checkliveness(G(L),i_o); } - -static void pushupval(lua_State *L, UpVal *upval) -{ - TValue o; - setuvvalue(L, &o, upval); - LIF(A,pushobject)(L, &o); -} - -static void pushclosure(lua_State *L, Closure *closure) -{ - TValue o; - setclvalue(L, &o, closure); - LIF(A,pushobject)(L, &o); -} - -static void pushstring(lua_State *L, TString *s) -{ - TValue o; - setsvalue(L, &o, s); - LIF(A,pushobject)(L, &o); -} - -static void persistfunction(PersistInfo *pi) -{ - /* perms reftbl ... func */ - Closure *cl = clvalue(getobject(pi->L, -1)); - lua_checkstack(pi->L, 2); - if(cl->c.isC) { - /* It's a C function. For now, we aren't going to allow - * persistence of C closures, even if the "C proto" is - * already in the permanents table. */ - lua_pushstring(pi->L, "Attempt to persist a C function"); - lua_error(pi->L); - } else { - /* It's a Lua closure. */ - { - /* We don't really _NEED_ the number of upvals, - * but it'll simplify things a bit */ - pi_write(pi, &cl->l.p->nups, sizeof(lu_byte), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistfunction_number_upvalues %d\n", (int) cl->l.p->nups); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistfunction_number_upvalues %d\n", (int) cl->l.p->nups); -#endif - } - /* Persist prototype */ - { - pushproto(pi->L, cl->l.p); - /* perms reftbl ... func proto */ - persist(pi); - lua_pop(pi->L, 1); - /* perms reftbl ... func */ - } - /* Persist upvalue values (not the upvalue objects - * themselves) */ - { - int i; - for(i=0; i<cl->l.p->nups; i++) { - /* perms reftbl ... func */ - pushupval(pi->L, cl->l.upvals[i]); - /* perms reftbl ... func upval */ - persist(pi); - lua_pop(pi->L, 1); - /* perms reftbl ... func */ - } - /* perms reftbl ... func */ - } - /* Persist function environment */ - { - lua_getfenv(pi->L, -1); - /* perms reftbl ... func fenv */ - if(lua_equal(pi->L, -1, LUA_GLOBALSINDEX)) { - /* Function has the default fenv */ - /* perms reftbl ... func _G */ - lua_pop(pi->L, 1); - /* perms reftbl ... func */ - lua_pushnil(pi->L); - /* perms reftbl ... func nil */ - } - /* perms reftbl ... func fenv/nil */ - persist(pi); - lua_pop(pi->L, 1); - /* perms reftbl ... func */ - } - } -} - - -/* Upvalues are tricky. Here's why. - * - * A particular upvalue may be either "open", in which case its member v - * points into a thread's stack, or "closed" in which case it points to the - * upvalue itself. An upvalue is closed under any of the following conditions: - * -- The function that initially declared the variable "local" returns - * -- The thread in which the closure was created is garbage collected - * - * To make things wackier, just because a thread is reachable by Lua doesn't - * mean it's in our root set. We need to be able to treat an open upvalue - * from an unreachable thread as a closed upvalue. - * - * The solution: - * (a) For the purposes of persisting, don't indicate whether an upvalue is - * closed or not. - * (b) When unpersisting, pretend that all upvalues are closed. - * (c) When persisting, persist all open upvalues referenced by a thread - * that is persisted, and tag each one with the corresponding stack position - * (d) When unpersisting, "reopen" each of these upvalues as the thread is - * unpersisted - */ -static void persistupval(PersistInfo *pi) -{ - /* perms reftbl ... upval */ - UpVal *uv = toupval(pi->L, -1); - lua_checkstack(pi->L, 1); - - /* We can't permit the upval to linger around on the stack, as Lua - * will bail if its GC finds it. */ - - lua_pop(pi->L, 1); - /* perms reftbl ... */ - LIF(A,pushobject)(pi->L, uv->v); - /* perms reftbl ... obj */ - persist(pi); - /* perms reftbl ... obj */ -} - -static void persistproto(PersistInfo *pi) -{ - /* perms reftbl ... proto */ - Proto *p = toproto(pi->L, -1); - lua_checkstack(pi->L, 2); - - /* Persist constant refs */ - { - int i; - pi_write(pi, &p->sizek, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistproto_sizek %d\n", p->sizek); - hrOut(pi); - } - #ifdef TOTEXT - printf("persistproto_sizek %d\n", p->sizek); - #endif - for(i=0; i<p->sizek; i++) { - LIF(A,pushobject)(pi->L, &p->k[i]); - /* perms reftbl ... proto const */ - persist(pi); - lua_pop(pi->L, 1); - /* perms reftbl ... proto */ - } - } - /* perms reftbl ... proto */ - - /* serialize inner Proto refs */ - { - int i; - pi_write(pi, &p->sizep, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistproto_sizep %d\n", p->sizep); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistproto_sizep %d\n", p->sizep); -#endif - for(i=0; i<p->sizep; i++) - { - pushproto(pi->L, p->p[i]); - /* perms reftbl ... proto subproto */ - persist(pi); - lua_pop(pi->L, 1); - /* perms reftbl ... proto */ - } - } - /* perms reftbl ... proto */ - - /* Serialize code */ - { - int len; - pi_write(pi, &p->sizecode, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistproto_sizecode %d\n", p->sizecode); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistproto_sizecode %d\n", p->sizecode); -#endif - len = sizeof(Instruction) * p->sizecode; - pi_write(pi, p->code, len, pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistproto_code %d\n", len); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistproto_code %d\n", len); -#endif - } - - /* Serialize upvalue names */ - { - int i; - pi_write(pi, &p->sizeupvalues, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistproto_upvalues %d\n", p->sizeupvalues); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistproto_upvalues %d\n", p->sizeupvalues); -#endif - for(i=0; i<p->sizeupvalues; i++) - { - pushstring(pi->L, p->upvalues[i]); - persist(pi); - lua_pop(pi->L, 1); - } - } - /* Serialize local variable infos */ - { - int i; - pi_write(pi, &p->sizelocvars, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistproto_sizelocvars %d\n", p->sizelocvars); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistproto_sizelocvars %d\n", p->sizelocvars); -#endif - for(i=0; i<p->sizelocvars; i++) - { - pushstring(pi->L, p->locvars[i].varname); - persist(pi); - lua_pop(pi->L, 1); - - pi_write(pi, &p->locvars[i].startpc, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistproto_startpc %d\n", p->locvars[i].startpc); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistproto_startpc %d\n", p->locvars[i].startpc); -#endif - pi_write(pi, &p->locvars[i].endpc, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistproto_endpc %d\n", p->locvars[i].endpc); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistproto_endpc %d\n", p->locvars[i].endpc); -#endif - } - } - - /* Serialize source string */ - pushstring(pi->L, p->source); - persist(pi); - lua_pop(pi->L, 1); - - /* Serialize line numbers */ - { - pi_write(pi, &p->sizelineinfo, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistproto_sizelineinfo %d\n", p->sizelineinfo); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistproto_sizelineinfo %d\n", p->sizelineinfo); -#endif - if (p->sizelineinfo) - { - int len; - len = sizeof(int) * p->sizelineinfo; - pi_write(pi, p->lineinfo, len, pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistproto_lineinfo %d\n", len); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistproto_lineinfo %d\n", len); -#endif - } - } - - /* Serialize linedefined and lastlinedefined */ - pi_write(pi, &p->linedefined, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistproto_linedefined %d\n", p->linedefined); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistproto_linedefined %d\n", p->linedefined); -#endif - pi_write(pi, &p->lastlinedefined, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistproto_lastlinedefined %d\n", p->lastlinedefined); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistproto_lastlinedefined %d\n", p->lastlinedefined); -#endif - - /* Serialize misc values */ - { - pi_write(pi, &p->nups, sizeof(lu_byte), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistproto_nups %d\n", (int) p->nups); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistproto_nups %d\n", (int) p->nups); -#endif - pi_write(pi, &p->numparams, sizeof(lu_byte), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistproto_numparams %d\n", (int) p->numparams); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistproto_numparams %d\n", (int) p->numparams); -#endif - pi_write(pi, &p->is_vararg, sizeof(lu_byte), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistproto_is_vararg %d\n", (int) p->is_vararg); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistproto_is_vararg %d\n", (int) p->is_vararg); -#endif - pi_write(pi, &p->maxstacksize, sizeof(lu_byte), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistproto_maxstacksize %d\n", (int) p->maxstacksize); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistproto_maxstacksize %d\n", (int) p->maxstacksize); -#endif - } - /* We do not currently persist upvalue names, local variable names, - * variable lifetimes, line info, or source code. */ -} - -/* Copies a stack, but the stack is reversed in the process - */ -static size_t revappendstack(lua_State *from, lua_State *to) -{ - StkId o; - for(o=from->top-1; o>=from->stack; o--) { - setobj2s(to, to->top, o); - to->top++; - } - return from->top - from->stack; -} - -/* Persist all stack members - */ -static void persistthread(PersistInfo *pi) -{ - size_t posremaining; - lua_State *L2; - /* perms reftbl ... thr */ - L2 = lua_tothread(pi->L, -1); - lua_checkstack(pi->L, L2->top - L2->stack + 1); - if(pi->L == L2) { - lua_pushstring(pi->L, "Can't persist currently running thread"); - lua_error(pi->L); - return; /* not reached */ - } - - /* Persist the stack */ - posremaining = revappendstack(L2, pi->L); - /* perms reftbl ... thr (rev'ed contents of L2) */ - write_size(pi, &posremaining); - for(; posremaining > 0; posremaining--) { - persist(pi); - lua_pop(pi->L, 1); - } - /* perms reftbl ... thr */ - /* Now, persist the CallInfo stack. */ - { - size_t i, numframes = (L2->ci - L2->base_ci) + 1; - write_size(pi, &numframes); - for(i=0; i<numframes; i++) { - CallInfo *ci = L2->base_ci + i; - size_t stackbase = ci->base - L2->stack; - size_t stackfunc = ci->func - L2->stack; - size_t stacktop = ci->top - L2->stack; - size_t savedpc = (ci != L2->base_ci) ? - ci->savedpc - ci_func(ci)->l.p->code : - 0; - write_size(pi, &stackbase); - write_size(pi, &stackfunc); - write_size(pi, &stacktop); - pi_write(pi, &ci->nresults, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistthread %d\n", ci->nresults); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistthread %d\n", ci->nresults); -#endif - write_size(pi, &savedpc); - } - } - - /* Serialize the state's other parameters, with the exception of upval stuff */ - { - size_t stackbase = L2->base - L2->stack; - size_t stacktop = L2->top - L2->stack; - lua_assert(L2->nCcalls <= 1); - pi_write(pi, &L2->status, sizeof(lu_byte), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistthread_status %d\n", (int) L2->status); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistthread_status %d\n", (int) L2->status); -#endif - write_size(pi, &stackbase); - write_size(pi, &stacktop); - - // ptrdiff_t changes sizes based on 32/64 bit - // Hard cast to 64 bit size if SIZE64 is defined -#ifdef SIZES64 - uint64 ptrIndex = static_cast<uint64>(L2->errfunc); - pi_write(pi, &ptrIndex, sizeof(uint64), pi->ud); -#else - pi_write(pi, &L2->errfunc, sizeof(ptrdiff_t), pi->ud); -#endif - //write_size(pi, (size_t *)&L2->errfunc); - } - - /* Finally, record upvalues which need to be reopened */ - /* See the comment above persistupval() for why we do this */ - { - GCObject *gco; - UpVal *uv; - /* perms reftbl ... thr */ - for(gco = L2->openupval; gco != NULL; gco = uv->next) { - size_t stackpos; - uv = gco2uv(gco); - - /* Make sure upvalue is really open */ - lua_assert(uv->v != &uv->u.value); - pushupval(pi->L, uv); - /* perms reftbl ... thr uv */ - persist(pi); - lua_pop(pi->L, 1); - /* perms reftbl ... thr */ - stackpos = uv->v - L2->stack; - write_size(pi, &stackpos); - } - /* perms reftbl ... thr */ - lua_pushnil(pi->L); - /* perms reftbl ... thr nil */ - persist(pi); - lua_pop(pi->L, 1); - /* perms reftbl ... thr */ - } - /* perms reftbl ... thr */ -} - -static void persistboolean(PersistInfo *pi) -{ - int b = lua_toboolean(pi->L, -1); - pi_write(pi, &b, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistboolean %d\n", b); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistboolean %d\n", b); -#endif -} - -static void persistlightuserdata(PersistInfo *pi) -{ - void *p = lua_touserdata(pi->L, -1); - pi_write(pi, &p, sizeof(void *), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistlightuserdata %p\n", p); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistlightuserdata %d\n", (int) p); -#endif -} - -static void persistnumber(PersistInfo *pi) -{ - lua_Number n = lua_tonumber(pi->L, -1); - pi_write(pi, &n, sizeof(lua_Number), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persistnumber %d (%d)\n", (int) n, (int) sizeof(lua_Number)); - hrOut(pi); - } -#ifdef TOTEXT - printf("persistnumber %d (%d)\n", (int) n, (int) sizeof(lua_Number)); -#endif -} - -static void persiststring(PersistInfo *pi) -{ - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persiststring\n"); - hrOut(pi); - } -#ifdef TOTEXT - printf("persiststring\n"); -#endif - size_t length = lua_strlen(pi->L, -1); - write_size(pi, &length); - const char* s = lua_tostring(pi->L, -1); - pi_write(pi, s, length, pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persiststring %d \"%s\"\n", (int)length, s); - hrOut(pi); - } -#ifdef TOTEXT - printf("persiststring %d \"%s\"\n", length, s); -#endif -} - -/* Top-level delegating persist function - */ -static void persist(PersistInfo *pi) -{ - /* perms reftbl ... obj */ - lua_checkstack(pi->L, 2); - /* If the object has already been written, write a reference to it */ - lua_pushvalue(pi->L, -1); - /* perms reftbl ... obj obj */ - lua_rawget(pi->L, 2); - /* perms reftbl ... obj ref? */ - if(!lua_isnil(pi->L, -1)) { - /* perms reftbl ... obj ref */ - int zero = 0; - pi_write(pi, &zero, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persist_seenobject\n"); - hrOut(pi); - } -#ifdef TOTEXT - printf("persist_seenobject\n"); -#endif - int *ref = (int *)lua_touserdata(pi->L, -1); - pi_write(pi, ref, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persist_touserdata_ref %d\n", ref); - hrOut(pi); - } -#ifdef TOTEXT - printf("persist_touserdata_ref %d\n", ref); -#endif - lua_pop(pi->L, 1); - /* perms reftbl ... obj ref */ -#ifdef PLUTO_DEBUG - printindent(pi->level); - printf("0 %d\n", ref); -#endif - return; - } - /* perms reftbl ... obj nil */ - lua_pop(pi->L, 1); - /* perms reftbl ... obj */ - /* If the object is nil, write the pseudoreference 0 */ - if(lua_isnil(pi->L, -1)) { - int zero = 0; - /* firsttime */ - pi_write(pi, &zero, sizeof(int), pi->ud); - /* ref */ - pi_write(pi, &zero, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persist_nil (last 2 lines)\n"); - hrOut(pi); - } -#ifdef TOTEXT - printf("persist_nil (last 2 lines)\n"); -#endif -#ifdef PLUTO_DEBUG - printindent(pi->level); - printf("0 0\n"); -#endif - return; - } - { - /* indicate that it's the first time */ - int one = 1; - pi_write(pi, &one, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persist_newobject\n"); - hrOut(pi); - } -#ifdef TOTEXT - printf("persist_newobject\n"); -#endif - } - lua_pushvalue(pi->L, -1); - /* perms reftbl ... obj obj */ - int *ref = (int *)lua_newuserdata(pi->L, sizeof(int)); - *ref = ++(pi->counter); - /* perms reftbl ... obj obj ref */ - lua_rawset(pi->L, 2); - /* perms reftbl ... obj */ - - pi_write(pi, &pi->counter, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persist_counter %d\n", pi->counter); - hrOut(pi); - } -#ifdef TOTEXT - printf("persist_counter %d\n", pi->counter); -#endif - - - /* At this point, we'll give the permanents table a chance to play. */ - { - lua_pushvalue(pi->L, -1); - /* perms reftbl ... obj obj */ - lua_gettable(pi->L, 1); - /* perms reftbl ... obj permkey? */ - if(!lua_isnil(pi->L, -1)) { - /* perms reftbl ... obj permkey */ - int type = PLUTO_TPERMANENT; -#ifdef PLUTO_DEBUG - printindent(pi->level); - printf("1 %d PERM\n", pi->counter); - pi->level++; -#endif - pi_write(pi, &type, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persist_permtype %d\n", type); - hrOut(pi); - } -#ifdef TOTEXT - printf("persist_permtype %d\n", type); -#endif - persist(pi); - lua_pop(pi->L, 1); - /* perms reftbl ... obj */ -#ifdef PLUTO_DEBUG - pi->level--; -#endif - return; - } else { - /* perms reftbl ... obj nil */ - lua_pop(pi->L, 1); - /* perms reftbl ... obj */ - } - /* perms reftbl ... obj */ - } - { - int type = lua_type(pi->L, -1); - pi_write(pi, &type, sizeof(int), pi->ud); - if (humanReadable) { - snprintf(hrBuf, hrBufSize, "persist %s\n", type >= 0 && type < NUMTYPES ? typenames[type] : "?"); - hrOut(pi); - } -#ifdef TOTEXT - printf("persist %s\n", type >= 0 && type < NUMTYPES ? typenames[type] : "?"); -#endif - -#ifdef PLUTO_DEBUG - printindent(pi->level); - printf("1 %d %d\n", pi->counter, type); - pi->level++; -#endif - } - - switch(lua_type(pi->L, -1)) { - case LUA_TBOOLEAN: - persistboolean(pi); - break; - case LUA_TLIGHTUSERDATA: - persistlightuserdata(pi); - break; - case LUA_TNUMBER: - persistnumber(pi); - break; - case LUA_TSTRING: - persiststring(pi); - break; - case LUA_TTABLE: - persisttable(pi); - break; - case LUA_TFUNCTION: - persistfunction(pi); - break; - case LUA_TTHREAD: - persistthread(pi); - break; - case LUA_TPROTO: - persistproto(pi); - break; - case LUA_TUPVAL: - persistupval(pi); - break; - case LUA_TUSERDATA: - persistuserdata(pi); - break; - default: - lua_assert(0); - } -#ifdef PLUTO_DEBUG - pi->level--; -#endif -} - -void pluto_persist(lua_State *L, lua_Chunkwriter writer, void *ud) -{ - PersistInfo pi; - - pi.counter = 0; - pi.L = L; - pi.writer = writer; - pi.ud = ud; -#ifdef PLUTO_DEBUG - pi.level = 0; -#endif - - lua_checkstack(L, 4); - /* perms? rootobj? ...? */ - lua_assert(lua_gettop(L) == 2); - /* perms rootobj */ - lua_assert(!lua_isnil(L, 2)); - /* perms rootobj */ - lua_newtable(L); - /* perms rootobj reftbl */ - - /* Now we're going to make the table weakly keyed. This prevents the - * GC from visiting it and trying to mark things it doesn't want to - * mark in tables, e.g. upvalues. All objects in the table are - * a priori reachable, so it doesn't matter that we do this. */ - lua_newtable(L); - /* perms rootobj reftbl mt */ - lua_pushstring(L, "__mode"); - /* perms rootobj reftbl mt "__mode" */ - lua_pushstring(L, "k"); - /* perms rootobj reftbl mt "__mode" "k" */ - lua_settable(L, 4); - /* perms rootobj reftbl mt */ - lua_setmetatable(L, 3); - /* perms rootobj reftbl */ - lua_insert(L, 2); - /* perms reftbl rootobj */ - persist(&pi); - /* perms reftbl rootobj */ - lua_remove(L, 2); - /* perms rootobj */ -} - -typedef struct WriterInfo_t { - char* buf; - size_t buflen; -} WriterInfo; - -static int bufwriter (lua_State *L, const void *p, size_t sz, void *ud) { - const char *cp = (const char *)p; - WriterInfo *wi = (WriterInfo *)ud; - - LIF(M,reallocvector)(L, wi->buf, wi->buflen, wi->buflen+sz, char); - while(sz) - { - /* how dearly I love ugly C pointer twiddling */ - wi->buf[wi->buflen++] = *cp++; - sz--; - } - return 0; -} - -int persist_l(lua_State *L) -{ - /* perms? rootobj? ...? */ - WriterInfo wi; - - wi.buf = NULL; - wi.buflen = 0; - - lua_settop(L, 2); - /* perms? rootobj? */ - luaL_checktype(L, 1, LUA_TTABLE); - /* perms rootobj? */ - luaL_checktype(L, 1, LUA_TTABLE); - /* perms rootobj */ - - pluto_persist(L, bufwriter, &wi); - - lua_settop(L, 0); - /* (empty) */ - lua_pushlstring(L, wi.buf, wi.buflen); - /* str */ - pdep_freearray(L, wi.buf, wi.buflen, char); - return 1; -} - -typedef struct UnpersistInfo_t { - lua_State *L; - ZIO zio; -#ifdef PLUTO_DEBUG - int level; -#endif -} UnpersistInfo; - -static void unpersist(UnpersistInfo *upi); - -/* The object is left on the stack. This is primarily used by unpersist, but - * may be used by GCed objects that may incur cycles in order to preregister - * the object. */ -static void registerobject(int ref, UnpersistInfo *upi) -{ - /* perms reftbl ... obj */ - lua_checkstack(upi->L, 2); - lua_pushlightuserdata(upi->L, (void *)ref); - /* perms reftbl ... obj ref */ - lua_pushvalue(upi->L, -2); - /* perms reftbl ... obj ref obj */ - lua_settable(upi->L, 2); - /* perms reftbl ... obj */ -} - -static void unpersistboolean(UnpersistInfo *upi) -{ - /* perms reftbl ... */ - int b; - lua_checkstack(upi->L, 1); - verify(LIF(Z,read)(&upi->zio, &b, sizeof(int)) == 0); - lua_pushboolean(upi->L, b); - /* perms reftbl ... bool */ -} - -static void unpersistlightuserdata(UnpersistInfo *upi) -{ - /* perms reftbl ... */ - void *p; - lua_checkstack(upi->L, 1); - verify(LIF(Z,read)(&upi->zio, &p, sizeof(void *)) == 0); - lua_pushlightuserdata(upi->L, p); - /* perms reftbl ... ludata */ -} - -static void unpersistnumber(UnpersistInfo *upi) -{ - /* perms reftbl ... */ - lua_Number n; - lua_checkstack(upi->L, 1); - verify(LIF(Z,read)(&upi->zio, &n, sizeof(lua_Number)) == 0); - lua_pushnumber(upi->L, n); - /* perms reftbl ... num */ -} - -static void unpersiststring(UnpersistInfo *upi) -{ - /* perms reftbl sptbl ref */ - /*int length;*/ - size_t length; - char* string; - lua_checkstack(upi->L, 1); - /*verify(LIF(Z,read)(&upi->zio, &length, sizeof(int)) == 0);*/ - /*verify(LIF(Z,read)(&upi->zio, &length, sizeof(size_t)) == 0);*/ - read_size(&upi->zio, &length); - string = pdep_newvector(upi->L, length, char); - verify(LIF(Z,read)(&upi->zio, string, length) == 0); - lua_pushlstring(upi->L, string, length); - /* perms reftbl sptbl ref str */ - pdep_freearray(upi->L, string, length, char); -} - -static void unpersistspecialtable(int ref, UnpersistInfo *upi) -{ - /* perms reftbl ... */ - lua_checkstack(upi->L, 1); - unpersist(upi); - /* perms reftbl ... spfunc? */ - lua_assert(lua_isfunction(upi->L, -1)); - /* perms reftbl ... spfunc */ - lua_call(upi->L, 0, 1); - /* perms reftbl ... tbl? */ - lua_assert(lua_istable(upi->L, -1)); - /* perms reftbl ... tbl */ -} - -static void unpersistliteraltable(int ref, UnpersistInfo *upi) -{ - /* perms reftbl ... */ - lua_checkstack(upi->L, 3); - /* Preregister table for handling of cycles */ - lua_newtable(upi->L); - /* perms reftbl ... tbl */ - registerobject(ref, upi); - /* perms reftbl ... tbl */ - /* Unpersist metatable */ - { - unpersist(upi); - /* perms reftbl ... tbl mt/nil? */ - if(lua_istable(upi->L, -1)) { - /* perms reftbl ... tbl mt */ - lua_setmetatable(upi->L, -2); - /* perms reftbl ... tbl */ - } else { - /* perms reftbl ... tbl nil? */ - lua_assert(lua_isnil(upi->L, -1)); - /* perms reftbl ... tbl nil */ - lua_pop(upi->L, 1); - /* perms reftbl ... tbl */ - } - /* perms reftbl ... tbl */ - } - - while(1) - { - /* perms reftbl ... tbl */ - unpersist(upi); - /* perms reftbl ... tbl key/nil */ - if(lua_isnil(upi->L, -1)) { - /* perms reftbl ... tbl nil */ - lua_pop(upi->L, 1); - /* perms reftbl ... tbl */ - break; - } - /* perms reftbl ... tbl key */ - unpersist(upi); - /* perms reftbl ... tbl key value? */ - lua_assert(!lua_isnil(upi->L, -1)); - /* perms reftbl ... tbl key value */ - lua_rawset(upi->L, -3); - /* perms reftbl ... tbl */ - } -} - -static void unpersisttable(int ref, UnpersistInfo *upi) -{ - /* perms reftbl ... */ - lua_checkstack(upi->L, 1); - { - int isspecial; - verify(LIF(Z,read)(&upi->zio, &isspecial, sizeof(int)) == 0); - if(isspecial) { - unpersistspecialtable(ref, upi); - /* perms reftbl ... tbl */ - } else { - unpersistliteraltable(ref, upi); - /* perms reftbl ... tbl */ - } - /* perms reftbl ... tbl */ - } -} - -static UpVal *makeupval(lua_State *L, int stackpos) -{ - UpVal *uv = pdep_new(L, UpVal); - pdep_link(L, (GCObject *)uv, LUA_TUPVAL); - uv->tt = LUA_TUPVAL; - uv->v = &uv->u.value; - uv->u.l.prev = NULL; - uv->u.l.next = NULL; - setobj(L, uv->v, getobject(L, stackpos)); - return uv; -} - -static Proto *makefakeproto(lua_State *L, lu_byte nups) -{ - Proto *p = pdep_newproto(L); - p->sizelineinfo = 1; - p->lineinfo = pdep_newvector(L, 1, int); - p->lineinfo[0] = 1; - p->sizecode = 1; - p->code = pdep_newvector(L, 1, Instruction); - p->code[0] = CREATE_ABC(OP_RETURN, 0, 1, 0); - p->source = pdep_newlstr(L, "", 0); - p->maxstacksize = 2; - p->nups = nups; - p->sizek = 0; - p->sizep = 0; - - return p; -} - -/* The GC is not fond of finding upvalues in tables. We get around this - * during persistence using a weakly keyed table, so that the GC doesn't - * bother to mark them. This won't work in unpersisting, however, since - * if we make the values weak they'll be collected (since nothing else - * references them). Our solution, during unpersisting, is to represent - * upvalues as dummy functions, each with one upvalue. */ -static void boxupval_start(lua_State *L) -{ - LClosure *lcl; - lcl = (LClosure *)pdep_newLclosure(L, 1, hvalue(&L->l_gt)); - pushclosure(L, (Closure *)lcl); - /* ... func */ - lcl->p = makefakeproto(L, 1); - - /* Temporarily initialize the upvalue to nil */ - - lua_pushnil(L); - lcl->upvals[0] = makeupval(L, -1); - lua_pop(L, 1); -} - -static void boxupval_finish(lua_State *L) -{ - /* ... func obj */ - LClosure *lcl = (LClosure *) clvalue(getobject(L, -2)); - - lcl->upvals[0]->u.value = *getobject(L, -1); - lua_pop(L, 1); -} - - -static void unboxupval(lua_State *L) -{ - /* ... func */ - LClosure *lcl; - UpVal *uv; - - lcl = (LClosure *)clvalue(getobject(L, -1)); - uv = lcl->upvals[0]; - lua_pop(L, 1); - /* ... */ - pushupval(L, uv); - /* ... upval */ -} - -static void unpersistfunction(int ref, UnpersistInfo *upi) -{ - /* perms reftbl ... */ - LClosure *lcl; - int i; - lu_byte nupvalues; - lua_checkstack(upi->L, 2); - - verify(LIF(Z,read)(&upi->zio, &nupvalues, sizeof(lu_byte)) == 0); - - lcl = (LClosure *)pdep_newLclosure(upi->L, nupvalues, hvalue(&upi->L->l_gt)); - pushclosure(upi->L, (Closure *)lcl); - - /* perms reftbl ... func */ - /* Put *some* proto in the closure, before the GC can find it */ - lcl->p = makefakeproto(upi->L, nupvalues); - - /* Also, we need to temporarily fill the upvalues */ - lua_pushnil(upi->L); - /* perms reftbl ... func nil */ - for(i=0; i<nupvalues; i++) { - lcl->upvals[i] = makeupval(upi->L, -1); - } - lua_pop(upi->L, 1); - /* perms reftbl ... func */ - - /* I can't see offhand how a function would ever get to be self- - * referential, but just in case let's register it early */ - registerobject(ref, upi); - - /* Now that it's safe, we can get the real proto */ - unpersist(upi); - /* perms reftbl ... func proto? */ - lua_assert(lua_type(upi->L, -1) == LUA_TPROTO); - /* perms reftbl ... func proto */ - lcl->p = toproto(upi->L, -1); - lua_pop(upi->L, 1); - /* perms reftbl ... func */ - - for(i=0; i<nupvalues; i++) { - /* perms reftbl ... func */ - unpersist(upi); - /* perms reftbl ... func func2 */ - unboxupval(upi->L); - /* perms reftbl ... func upval */ - lcl->upvals[i] = toupval(upi->L, -1); - lua_pop(upi->L, 1); - /* perms reftbl ... func */ - } - /* perms reftbl ... func */ - - /* Finally, the fenv */ - unpersist(upi); - /* perms reftbl ... func fenv/nil? */ - lua_assert(lua_type(upi->L, -1) == LUA_TNIL || - lua_type(upi->L, -1) == LUA_TTABLE); - /* perms reftbl ... func fenv/nil */ - if(!lua_isnil(upi->L, -1)) { - /* perms reftbl ... func fenv */ - lua_setfenv(upi->L, -2); - /* perms reftbl ... func */ - } else { - /* perms reftbl ... func nil */ - lua_pop(upi->L, 1); - /* perms reftbl ... func */ - } - /* perms reftbl ... func */ -} - -static void unpersistupval(int ref, UnpersistInfo *upi) -{ - /* perms reftbl ... */ - lua_checkstack(upi->L, 2); - - boxupval_start(upi->L); - /* perms reftbl ... func */ - registerobject(ref, upi); - - unpersist(upi); - /* perms reftbl ... func obj */ - boxupval_finish(upi->L); - /* perms reftbl ... func */ -} - -static void unpersistproto(int ref, UnpersistInfo *upi) -{ - /* perms reftbl ... */ - Proto *p; - int i; - int sizep, sizek; - - /* We have to be careful. The GC expects a lot out of protos. In - * particular, we need to give the function a valid string for its - * source, and valid code, even before we actually read in the real - * code. */ - TString *source = pdep_newlstr(upi->L, "", 0); - p = pdep_newproto(upi->L); - p->source = source; - p->sizecode=1; - p->code = pdep_newvector(upi->L, 1, Instruction); - p->code[0] = CREATE_ABC(OP_RETURN, 0, 1, 0); - p->maxstacksize = 2; - p->sizek = 0; - p->sizep = 0; - - lua_checkstack(upi->L, 2); - - pushproto(upi->L, p); - /* perms reftbl ... proto */ - /* We don't need to register early, since protos can never ever be - * involved in cyclic references */ - - /* Read in constant references */ - { - verify(LIF(Z,read)(&upi->zio, &sizek, sizeof(int)) == 0); - LIF(M,reallocvector)(upi->L, p->k, 0, sizek, TValue); - for(i=0; i<sizek; i++) { - /* perms reftbl ... proto */ - unpersist(upi); - /* perms reftbl ... proto k */ - setobj2s(upi->L, &p->k[i], getobject(upi->L, -1)); - p->sizek++; - lua_pop(upi->L, 1); - /* perms reftbl ... proto */ - } - /* perms reftbl ... proto */ - } - /* Read in sub-proto references */ - { - verify(LIF(Z,read)(&upi->zio, &sizep, sizeof(int)) == 0); - LIF(M,reallocvector)(upi->L, p->p, 0, sizep, Proto*); - for(i=0; i<sizep; i++) { - /* perms reftbl ... proto */ - unpersist(upi); - /* perms reftbl ... proto subproto */ - p->p[i] = toproto(upi->L, -1); - p->sizep++; - lua_pop(upi->L, 1); - /* perms reftbl ... proto */ - } - /* perms reftbl ... proto */ - } - - /* Read in code */ - { - verify(LIF(Z,read)(&upi->zio, &p->sizecode, sizeof(int)) == 0); - LIF(M,reallocvector)(upi->L, p->code, 1, p->sizecode, Instruction); - verify(LIF(Z,read)(&upi->zio, p->code, - sizeof(Instruction) * p->sizecode) == 0); - } - - /* Read in upvalue names */ - { - verify(LIF(Z,read)(&upi->zio, &p->sizeupvalues, sizeof(int)) == 0); - if (p->sizeupvalues) - { - LIF(M,reallocvector)(upi->L, p->upvalues, 0, p->sizeupvalues, TString *); - for(i=0; i<p->sizeupvalues; i++) - { - unpersist(upi); - p->upvalues[i] = pdep_newlstr(upi->L, lua_tostring(upi->L, -1), strlen(lua_tostring(upi->L, -1))); - lua_pop(upi->L, 1); - } - } - } - - /* Read in local variable infos */ - { - verify(LIF(Z,read)(&upi->zio, &p->sizelocvars, sizeof(int)) == 0); - if (p->sizelocvars) - { - LIF(M,reallocvector)(upi->L, p->locvars, 0, p->sizelocvars, LocVar); - for(i=0; i<p->sizelocvars; i++) - { - unpersist(upi); - p->locvars[i].varname = pdep_newlstr(upi->L, lua_tostring(upi->L, -1), strlen(lua_tostring(upi->L, -1))); - lua_pop(upi->L, 1); - - verify(LIF(Z,read)(&upi->zio, &p->locvars[i].startpc, sizeof(int)) == 0); - verify(LIF(Z,read)(&upi->zio, &p->locvars[i].endpc, sizeof(int)) == 0); - } - } - } - - /* Read in source string*/ - unpersist(upi); - p->source = pdep_newlstr(upi->L, lua_tostring(upi->L, -1), strlen(lua_tostring(upi->L, -1))); - lua_pop(upi->L, 1); - - /* Read in line numbers */ - { - verify(LIF(Z,read)(&upi->zio, &p->sizelineinfo, sizeof(int)) == 0); - if (p->sizelineinfo) - { - LIF(M,reallocvector)(upi->L, p->lineinfo, 0, p->sizelineinfo, int); - verify(LIF(Z,read)(&upi->zio, p->lineinfo, - sizeof(int) * p->sizelineinfo) == 0); - } - } - - /* Read in linedefined and lastlinedefined */ - verify(LIF(Z,read)(&upi->zio, &p->linedefined, sizeof(int)) == 0); - verify(LIF(Z,read)(&upi->zio, &p->lastlinedefined, sizeof(int)) == 0); - - /* Read in misc values */ - { - verify(LIF(Z,read)(&upi->zio, &p->nups, sizeof(lu_byte)) == 0); - verify(LIF(Z,read)(&upi->zio, &p->numparams, sizeof(lu_byte)) == 0); - verify(LIF(Z,read)(&upi->zio, &p->is_vararg, sizeof(lu_byte)) == 0); - verify(LIF(Z,read)(&upi->zio, &p->maxstacksize, sizeof(lu_byte)) == 0); - } -} - - -/* Does basically the opposite of luaC_link(). - * Right now this function is rather inefficient; it requires traversing the - * entire root GC set in order to find one object. If the GC list were doubly - * linked this would be much easier, but there's no reason for Lua to have - * that. */ -static void gcunlink(lua_State *L, GCObject *gco) -{ - GCObject *prevslot; - if(G(L)->rootgc == gco) { - G(L)->rootgc = G(L)->rootgc->gch.next; - return; - } - - prevslot = G(L)->rootgc; - while(prevslot->gch.next != gco) { - lua_assert(prevslot->gch.next != NULL); - prevslot = prevslot->gch.next; - } - - prevslot->gch.next = prevslot->gch.next->gch.next; -} - -/* FIXME __ALL__ field ordering */ -static void unpersistthread(int ref, UnpersistInfo *upi) -{ - /* perms reftbl ... */ - lua_State *L2; - size_t stacklimit = 0; - L2 = lua_newthread(upi->L); - lua_checkstack(upi->L, 3); - /* L1: perms reftbl ... thr */ - /* L2: (empty) */ - registerobject(ref, upi); - - /* First, deserialize the object stack. */ - { - size_t i, stacksize; - read_size(&upi->zio, &stacksize); - LIF(D,growstack)(L2, (int)stacksize); - /* Make sure that the first stack element (a nil, representing - * the imaginary top-level C function) is written to the very, - * very bottom of the stack */ - L2->top--; - for(i=0; i<stacksize; i++) { - unpersist(upi); - /* L1: perms reftbl ... thr obj* */ - } - lua_xmove(upi->L, L2, stacksize); - /* L1: perms reftbl ... thr */ - /* L2: obj* */ - } - /* (hereafter, stacks refer to L1) */ - - /* Now, deserialize the CallInfo stack. */ - { - size_t i, numframes; - read_size(&upi->zio, &numframes); - LIF(D,reallocCI)(L2,numframes*2); - for(i=0; i<numframes; i++) { - CallInfo *ci = L2->base_ci + i; - size_t stackbase, stackfunc, stacktop, savedpc; - read_size(&upi->zio, &stackbase); - read_size(&upi->zio, &stackfunc); - read_size(&upi->zio, &stacktop); - verify(LIF(Z,read)(&upi->zio, &ci->nresults, sizeof(int)) == 0); - read_size(&upi->zio, &savedpc); - - if(stacklimit < stacktop) - stacklimit = stacktop; - - ci->base = L2->stack+stackbase; - ci->func = L2->stack+stackfunc; - ci->top = L2->stack+stacktop; - ci->savedpc = (ci != L2->base_ci) ? - ci_func(ci)->l.p->code+savedpc : - 0; - ci->tailcalls = 0; - /* Update the pointer each time, to keep the GC - * happy*/ - L2->ci = ci; - } - } - /* perms reftbl ... thr */ - /* Deserialize the state's other parameters, with the exception of upval stuff */ - { - size_t stackbase, stacktop; - L2->savedpc = L2->ci->savedpc; - verify(LIF(Z,read)(&upi->zio, &L2->status, sizeof(lu_byte)) == 0); - read_size(&upi->zio, &stackbase); - read_size(&upi->zio, &stacktop); - -#ifdef SIZES64 - uint64 value; - verify(LIF(Z,read)(&upi->zio, &value, sizeof(uint64)) == 0); - - L2->errfunc = static_cast<ptrdiff_t>(value); -#else - verify(LIF(Z,read)(&upi->zio, &L2->errfunc, sizeof(ptrdiff_t)) == 0); -#endif - - //read_size(&upi->zio, (size_t *)&L2->errfunc); - L2->base = L2->stack + stackbase; - L2->top = L2->stack + stacktop; - } - /* Finally, "reopen" upvalues (see persistupval() for why) */ - { - UpVal* uv; - GCObject **nextslot = &L2->openupval; - global_State *g = G(L2); - while(1) { - size_t stackpos; - unpersist(upi); - /* perms reftbl ... thr uv/nil */ - if(lua_isnil(upi->L, -1)) { - /* perms reftbl ... thr nil */ - lua_pop(upi->L, 1); - /* perms reftbl ... thr */ - break; - } - /* perms reftbl ... thr boxeduv */ - unboxupval(upi->L); - /* perms reftbl ... thr uv */ - uv = toupval(upi->L, -1); - lua_pop(upi->L, 1); - /* perms reftbl ... thr */ - - read_size(&upi->zio, &stackpos); - uv->v = L2->stack + stackpos; - gcunlink(upi->L, (GCObject *)uv); - uv->marked = luaC_white(g); - *nextslot = (GCObject *)uv; - nextslot = &uv->next; - uv->u.l.prev = &G(L2)->uvhead; - uv->u.l.next = G(L2)->uvhead.u.l.next; - uv->u.l.next->u.l.prev = uv; - G(L2)->uvhead.u.l.next = uv; - lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); - } - *nextslot = NULL; - } - - /* The stack must be valid at least to the highest value among the CallInfos */ - /* 'top' and the values up to there must be filled with 'nil' */ - { - StkId o; - LIF(D,checkstack)(L2, (int)stacklimit); - for (o = L2->top; o <= L2->top + stacklimit; o++) - setnilvalue(o); - } -} - -static void unpersistuserdata(int ref, UnpersistInfo *upi) -{ - /* perms reftbl ... */ - int isspecial; - lua_checkstack(upi->L, 2); - verify(LIF(Z,read)(&upi->zio, &isspecial, sizeof(int)) == 0); - if(isspecial) { - unpersist(upi); - /* perms reftbl ... spfunc? */ - lua_assert(lua_isfunction(upi->L, -1)); - /* perms reftbl ... spfunc */ -#ifdef PLUTO_PASS_USERDATA_TO_PERSIST - lua_pushlightuserdata(upi->L, &upi->zio); - lua_call(upi->L, 1, 1); -#else - lua_call(upi->L, 0, 1); -#endif - /* perms reftbl ... udata? */ -/* This assertion might not be necessary; it's conceivable, for - * example, that the SP function might decide to return a table - * with equivalent functionality. For the time being, we'll - * ignore this possibility in favor of stricter and more testable - * requirements. */ - lua_assert(lua_isuserdata(upi->L, -1)); - /* perms reftbl ... udata */ - } else { - size_t length; - read_size(&upi->zio, &length); - - lua_newuserdata(upi->L, length); - /* perms reftbl ... udata */ - registerobject(ref, upi); - verify(LIF(Z,read)(&upi->zio, lua_touserdata(upi->L, -1), length) == 0); - - unpersist(upi); - /* perms reftbl ... udata mt/nil? */ - lua_assert(lua_istable(upi->L, -1) || lua_isnil(upi->L, -1)); - /* perms reftbl ... udata mt/nil */ - lua_setmetatable(upi->L, -2); - /* perms reftbl ... udata */ - } - /* perms reftbl ... udata */ -} - -static void unpersistpermanent(int ref, UnpersistInfo *upi) -{ - /* perms reftbl ... */ - lua_checkstack(upi->L, 2); - unpersist(upi); - /* perms reftbl permkey */ - lua_gettable(upi->L, 1); - /* perms reftbl perm? */ - /* We assume currently that the substituted permanent value - * shouldn't be nil. This may be a bad assumption. Real-life - * experience is needed to evaluate this. */ - lua_assert(!lua_isnil(upi->L, -1)); - /* perms reftbl perm */ -} - -#if 0 -/* For debugging only; not called when lua_assert is empty */ -static int inreftable(lua_State *L, int ref) -{ - int res; - lua_checkstack(L, 1); - /* perms reftbl ... */ - lua_pushlightuserdata(L, (void *)ref); - /* perms reftbl ... ref */ - lua_gettable(L, 2); - /* perms reftbl ... obj? */ - res = !lua_isnil(L, -1); - lua_pop(L, 1); - /* perms reftbl ... */ - return res; -} -#endif - -static void unpersist(UnpersistInfo *upi) -{ - /* perms reftbl ... */ - int firstTime; - int stacksize = lua_gettop(upi->L); stacksize = stacksize; /* DEBUG */ - lua_checkstack(upi->L, 2); - LIF(Z,read)(&upi->zio, &firstTime, sizeof(int)); - if(firstTime) { - int ref; - int type; - LIF(Z,read)(&upi->zio, &ref, sizeof(int)); - lua_assert(!inreftable(upi->L, ref)); - LIF(Z,read)(&upi->zio, &type, sizeof(int)); -#ifdef PLUTO_DEBUG - printindent(upi->level); - printf("1 %d %d\n", ref, type); - upi->level++; -#endif - switch(type) { - case LUA_TBOOLEAN: - unpersistboolean(upi); - break; - case LUA_TLIGHTUSERDATA: - unpersistlightuserdata(upi); - break; - case LUA_TNUMBER: - unpersistnumber(upi); - break; - case LUA_TSTRING: - unpersiststring(upi); - break; - case LUA_TTABLE: - unpersisttable(ref, upi); - break; - case LUA_TFUNCTION: - unpersistfunction(ref, upi); - break; - case LUA_TTHREAD: - unpersistthread(ref, upi); - break; - case LUA_TPROTO: - unpersistproto(ref, upi); - break; - case LUA_TUPVAL: - unpersistupval(ref, upi); - break; - case LUA_TUSERDATA: - unpersistuserdata(ref, upi); - break; - case PLUTO_TPERMANENT: - unpersistpermanent(ref, upi); - break; - default: - lua_assert(0); - } - /* perms reftbl ... obj */ - lua_assert(lua_type(upi->L, -1) == type || - type == PLUTO_TPERMANENT || - /* Remember, upvalues get a special dispensation, as - * described in boxupval */ - (lua_type(upi->L, -1) == LUA_TFUNCTION && - type == LUA_TUPVAL)); - registerobject(ref, upi); - /* perms reftbl ... obj */ -#ifdef PLUTO_DEBUG - upi->level--; -#endif - } else { - int ref; - LIF(Z,read)(&upi->zio, &ref, sizeof(int)); -#ifdef PLUTO_DEBUG - printindent(upi->level); - printf("0 %d\n", ref); -#endif - if(ref == 0) { - lua_pushnil(upi->L); - /* perms reftbl ... nil */ - } else { - lua_pushlightuserdata(upi->L, (void *)ref); - /* perms reftbl ... ref */ - lua_gettable(upi->L, 2); - /* perms reftbl ... obj? */ - lua_assert(!lua_isnil(upi->L, -1)); - } - /* perms reftbl ... obj/nil */ - } - /* perms reftbl ... obj/nil */ - lua_assert(lua_gettop(upi->L) == stacksize + 1); -} - -void pluto_unpersist(lua_State *L, lua_Chunkreader reader, void *ud) -{ - /* We use the graciously provided ZIO (what the heck does the Z stand - * for?) library so that we don't have to deal with the reader directly. - * Letting the reader function decide how much data to return can be - * very unpleasant. - */ - UnpersistInfo upi; - upi.L = L; -#ifdef PLUTO_DEBUG - upi.level = 0; -#endif - - lua_checkstack(L, 3); - LIF(Z,init)(L, &upi.zio, reader, ud); - - /* perms */ - lua_newtable(L); - /* perms reftbl */ - lua_gc(L, LUA_GCSTOP, 0); - unpersist(&upi); - lua_gc(L, LUA_GCRESTART, 0); - /* perms reftbl rootobj */ - lua_replace(L, 2); - /* perms rootobj */ -} - -typedef struct LoadInfo_t { - char *buf; - size_t size; -} LoadInfo; - - -static const char *bufreader(lua_State *L, void *ud, size_t *sz) { - LoadInfo *li = (LoadInfo *)ud; - if(li->size == 0) { - return NULL; - } - *sz = li->size; - li->size = 0; - return li->buf; -} - -int unpersist_l(lua_State *L) -{ - LoadInfo li; - char const *origbuf; - char *tempbuf; - size_t bufsize; - /* perms? str? ...? */ - lua_settop(L, 2); - /* perms? str? */ - origbuf = luaL_checklstring(L, 2, &bufsize); - tempbuf = LIF(M,newvector)(L, bufsize, char); - memcpy(tempbuf, origbuf, bufsize); - - li.buf = tempbuf; - li.size = bufsize; - - /* perms? str */ - lua_pop(L, 1); - /* perms? */ - luaL_checktype(L, 1, LUA_TTABLE); - /* perms */ - pluto_unpersist(L, bufreader, &li); - /* perms rootobj */ - LIF(M,freearray)(L, tempbuf, bufsize, char); - return 1; -} - -/* Stefan's first C function for Lua! :) - Returns a string describing the Pluto version you're using. */ - -int version_l(lua_State *L) -{ - const char *version = VERSION; - - lua_settop(L, 0); - /* (empty) */ - lua_pushlstring(L, version, strlen(version)); - /* str */ - return 1; -} - -/* Set human-readable output on or off. */ -int human_l(lua_State *L) -{ - /* flag? ...? */ - lua_settop(L, 1); - /* flag? */ - /*luaL_checktype(L, 1, LUA_TBOOLEAN);*/ - /* flag */ - - humanReadable = lua_toboolean(L, 1); - - lua_settop(L, 0); - /* (empty) */ - return 0; -} - -static luaL_reg pluto_reg[] = { - { "persist", persist_l }, - { "unpersist", unpersist_l }, - { "version", version_l }, - { "human", human_l }, - { NULL, NULL } -}; - -LUALIB_API int luaopen_pluto(lua_State *L) { - luaL_openlib(L, "pluto", pluto_reg, 0); - return 1; -} diff --git a/engines/sword25/util/pluto/pluto.h b/engines/sword25/util/pluto/pluto.h deleted file mode 100644 index 3674842d44..0000000000 --- a/engines/sword25/util/pluto/pluto.h +++ /dev/null @@ -1,25 +0,0 @@ -/* $Id$ */ - -/* Pluto - Heavy-duty persistence for Lua - * Copyright (C) 2004 by Ben Sunshine-Hill, and released into the public - * domain. People making use of this software as part of an application - * are politely requested to email the author at sneftel@gmail.com - * with a brief description of the application, primarily to satisfy his - * curiosity. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* lua.h must be included before this file */ - -void pluto_persist(lua_State *L, lua_Chunkwriter writer, void *ud); - -void pluto_unpersist(lua_State *L, lua_Chunkreader reader, void *ud); - -LUALIB_API int luaopen_pluto(lua_State *L); diff --git a/engines/sword25/util/pluto/plzio.cpp b/engines/sword25/util/pluto/plzio.cpp deleted file mode 100644 index 21f69a9e8d..0000000000 --- a/engines/sword25/util/pluto/plzio.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* -** $Id$ -** a generic input stream interface -** See Copyright Notice in lua.h -*/ - - -#include <string.h> - -#define lzio_c -#define LUA_CORE - -#include "pdep/pdep.h" - -int pdep_fill (ZIO *z) { - size_t size; - lua_State *L = z->L; - const char *buff; - lua_unlock(L); - buff = z->reader(L, z->data, &size); - lua_lock(L); - if (buff == NULL || size == 0) return EOZ; - z->n = size - 1; - z->p = buff; - return char2int(*(z->p++)); -} - - -int pdep_lookahead (ZIO *z) { - if (z->n == 0) { - if (pdep_fill(z) == EOZ) - return EOZ; - else { - z->n++; /* pdep_fill removed first byte; put back it */ - z->p--; - } - } - return char2int(*z->p); -} - - -void pdep_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { - z->L = L; - z->reader = reader; - z->data = data; - z->n = 0; - z->p = NULL; -} - - -/* --------------------------------------------------------------- read --- */ -size_t pdep_read (ZIO *z, void *b, size_t n) { - while (n) { - size_t m; - if (pdep_lookahead(z) == EOZ) - return n; /* return number of missing bytes */ - m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ - memcpy(b, z->p, m); - z->n -= m; - z->p += m; - b = (char *)b + m; - n -= m; - } - return 0; -} - -/* ------------------------------------------------------------------------ */ -char *pdep_openspace (lua_State *L, Mbuffer *buff, size_t n) { - if (n > buff->buffsize) { - if (n < LUA_MINBUFFER) n = LUA_MINBUFFER; - pdep_resizebuffer(L, buff, n); - } - return buff->buffer; -} |