scummvm/common/lua/lua_persistence_util.cpp
2019-08-13 10:18:02 +02:00

385 lines
11 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distri8buted in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
/**
* This code is heavily based on the pluto code base. Copyright below
*/
/* 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)
*/
/**
* This code is heavily based on the Pluto code base. Copyright below
*/
/* 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 "lua_persistence_util.h"
#include "common/scummsys.h"
#include "lobject.h"
#include "lstate.h"
#include "lgc.h"
#include "lopcodes.h"
namespace Lua {
void *lua_realloc(lua_State *luaState, void *block, size_t osize, size_t nsize) {
global_State *globalState = G(luaState);
block = (*globalState->frealloc)(globalState->ud, block, osize, nsize);
globalState->totalbytes = (globalState->totalbytes - osize) + nsize;
return block;
}
void pushObject(lua_State *luaState, TValue *obj) {
setobj2s(luaState, luaState->top, obj);
api_check(luaState, luaState->top < luaState->ci->top);
luaState->top++;
}
void pushProto(lua_State *luaState, Proto *proto) {
TValue obj;
setptvalue(luaState, &obj, proto);
pushObject(luaState, &obj);
}
void pushUpValue(lua_State *luaState, UpVal *upval) {
TValue obj;
obj.value.gc = cast(GCObject *, upval);
obj.tt = LUA_TUPVAL;
checkliveness(G(L), obj);
pushObject(luaState, &obj);
}
void pushString(lua_State *luaState, TString *str) {
TValue o;
setsvalue(luaState, &o, str);
pushObject(luaState, &o);
}
/* A simple reimplementation of the unfortunately static function luaA_index.
* Does not support the global table, registry, or upvalues. */
StkId getObject(lua_State *luaState, int stackpos) {
if (stackpos > 0) {
lua_assert(luaState->base + stackpos - 1 < luaState->top);
return luaState->base + stackpos - 1;
} else {
lua_assert(L->top - stackpos >= L->base);
return luaState->top + stackpos;
}
}
void lua_linkObjToGC(lua_State *luaState, GCObject *obj, lu_byte type) {
global_State *globalState = G(luaState);
obj->gch.next = globalState->rootgc;
globalState->rootgc = obj;
obj->gch.marked = luaC_white(globalState);
obj->gch.tt = type;
}
Closure *lua_newLclosure(lua_State *luaState, int numElements, Table *elementTable) {
Closure *c = (Closure *)lua_malloc(luaState, sizeLclosure(numElements));
lua_linkObjToGC(luaState, obj2gco(c), LUA_TFUNCTION);
c->l.isC = 0;
c->l.env = elementTable;
c->l.nupvalues = cast_byte(numElements);
while (numElements--) {
c->l.upvals[numElements] = NULL;
}
return c;
}
void pushClosure(lua_State *luaState, Closure *closure) {
TValue obj;
setclvalue(luaState, &obj, closure);
pushObject(luaState, &obj);
}
Proto *createProto(lua_State *luaState) {
Proto *newProto = (Proto *)lua_malloc(luaState, sizeof(Proto));
lua_linkObjToGC(luaState, obj2gco(newProto), LUA_TPROTO);
newProto->k = NULL;
newProto->sizek = 0;
newProto->p = NULL;
newProto->sizep = 0;
newProto->code = NULL;
newProto->sizecode = 0;
newProto->sizelineinfo = 0;
newProto->sizeupvalues = 0;
newProto->nups = 0;
newProto->upvalues = NULL;
newProto->numparams = 0;
newProto->is_vararg = 0;
newProto->maxstacksize = 0;
newProto->lineinfo = NULL;
newProto->sizelocvars = 0;
newProto->locvars = NULL;
newProto->linedefined = 0;
newProto->lastlinedefined = 0;
newProto->source = NULL;
return newProto;
}
TString *createString(lua_State *luaState, const char *str, size_t len) {
TString *res;
lua_pushlstring(luaState, str, len);
res = rawtsvalue(luaState->top - 1);
lua_pop(luaState, 1);
return res;
}
Proto *makeFakeProto(lua_State *L, lu_byte nups) {
Proto *p = createProto(L);
p->sizelineinfo = 1;
p->lineinfo = lua_newVector(L, 1, int);
p->lineinfo[0] = 1;
p->sizecode = 1;
p->code = lua_newVector(L, 1, Instruction);
p->code[0] = CREATE_ABC(OP_RETURN, 0, 1, 0);
p->source = createString(L, "", 0);
p->maxstacksize = 2;
p->nups = nups;
p->sizek = 0;
p->sizep = 0;
return p;
}
UpVal *createUpValue(lua_State *luaState, int stackpos) {
UpVal *upValue = (UpVal *)lua_malloc(luaState, sizeof(UpVal));
lua_linkObjToGC(luaState, (GCObject *)upValue, LUA_TUPVAL);
upValue->tt = LUA_TUPVAL;
upValue->v = &upValue->u.value;
upValue->u.l.prev = NULL;
upValue->u.l.next = NULL;
const TValue *o2 = (TValue *)getObject(luaState, stackpos);
upValue->v->value = o2->value;
upValue->v->tt = o2->tt;
checkliveness(G(L), upValue->v);
return upValue;
}
void unboxUpValue(lua_State *luaState) {
// >>>>> ...... func
LClosure *lcl;
UpVal *uv;
lcl = (LClosure *)clvalue(getObject(luaState, -1));
uv = lcl->upvals[0];
lua_pop(luaState, 1);
// >>>>> ......
pushUpValue(luaState, uv);
// >>>>> ...... upValue
}
size_t appendStackToStack_reverse(lua_State *from, lua_State *to) {
for (StkId id = from->top - 1; id >= from->stack; --id) {
setobj2s(to, to->top, id);
to->top++;
}
return from->top - from->stack;
}
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 lua_reallocstack(lua_State *L, int newsize) {
TValue *oldstack = L->stack;
int realsize = newsize + 1 + EXTRA_STACK;
lua_reallocvector(L, L->stack, L->stacksize, realsize, TValue);
L->stacksize = realsize;
L->stack_last = L->stack + newsize;
correctStack(L, oldstack);
}
void lua_reallocCallInfo(lua_State *lauState, int newsize) {
CallInfo *oldci = lauState->base_ci;
lua_reallocvector(lauState, lauState->base_ci, lauState->size_ci, newsize, CallInfo);
lauState->size_ci = newsize;
lauState->ci = (lauState->ci - oldci) + lauState->base_ci;
lauState->end_ci = lauState->base_ci + lauState->size_ci - 1;
}
void GCUnlink(lua_State *luaState, GCObject *gco) {
GCObject *prevslot;
if (G(luaState)->rootgc == gco) {
G(luaState)->rootgc = G(luaState)->rootgc->gch.next;
return;
}
prevslot = G(luaState)->rootgc;
while (prevslot->gch.next != gco) {
prevslot = prevslot->gch.next;
}
prevslot->gch.next = prevslot->gch.next->gch.next;
}
TString *lua_newlstr(lua_State *luaState, const char *str, size_t len) {
lua_pushlstring(luaState, str, len);
TString *luaStr = &(luaState->top - 1)->value.gc->ts;
lua_pop(luaState, 1);
return luaStr;
}
void lua_link(lua_State *luaState, GCObject *o, lu_byte tt) {
global_State *g = G(luaState);
o->gch.next = g->rootgc;
g->rootgc = o;
o->gch.marked = luaC_white(g);
o->gch.tt = tt;
}
Proto *lua_newproto(lua_State *luaState) {
Proto *f = (Proto *)lua_malloc(luaState, sizeof(Proto));
lua_link(luaState, 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;
}
UpVal *makeUpValue(lua_State *luaState, int stackPos) {
UpVal *uv = lua_new(luaState, UpVal);
lua_link(luaState, (GCObject *)uv, LUA_TUPVAL);
uv->tt = LUA_TUPVAL;
uv->v = &uv->u.value;
uv->u.l.prev = NULL;
uv->u.l.next = NULL;
setobj(luaState, uv->v, getObject(luaState, stackPos));
return uv;
}
void boxUpValue_start(lua_State *luaState) {
LClosure *closure;
closure = (LClosure *)lua_newLclosure(luaState, 1, hvalue(&luaState->l_gt));
pushClosure(luaState, (Closure *)closure);
// >>>>> ...... func
closure->p = makeFakeProto(luaState, 1);
// Temporarily initialize the upvalue to nil
lua_pushnil(luaState);
closure->upvals[0] = makeUpValue(luaState, -1);
lua_pop(luaState, 1);
}
void boxUpValue_finish(lua_State *luaState) {
// >>>>> ...... func obj
LClosure *lcl = (LClosure *)clvalue(getObject(luaState, -2));
lcl->upvals[0]->u.value = *getObject(luaState, -1);
lua_pop(luaState, 1);
// >>>>> ...... func
}
} // End of namespace Lua