mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-19 00:15:30 +00:00
c1f029c6dc
an engine feature
385 lines
11 KiB
C++
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
|