1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distri8buted in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 /**
24  * This code is heavily based on the pluto code base. Copyright below
25  */
26 
27 /* Tamed Pluto - Heavy-duty persistence for Lua
28  * Copyright (C) 2004 by Ben Sunshine-Hill, and released into the public
29  * domain. People making use of this software as part of an application
30  * are politely requested to email the author at sneftel@gmail.com
31  * with a brief description of the application, primarily to satisfy his
32  * curiosity.
33  *
34  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
35  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
36  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
37  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
38  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
39  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
40  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
41  *
42  * Instrumented by Stefan Reich (info@luaos.net)
43  * for Mobile Lua (http://luaos.net/pages/mobile-lua.php)
44  */
45 
46 /**
47  * This code is heavily based on the Pluto code base. Copyright below
48  */
49 
50 /* Tamed Pluto - Heavy-duty persistence for Lua
51  * Copyright (C) 2004 by Ben Sunshine-Hill, and released into the public
52  * domain. People making use of this software as part of an application
53  * are politely requested to email the author at sneftel@gmail.com
54  * with a brief description of the application, primarily to satisfy his
55  * curiosity.
56  *
57  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
58  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
59  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
60  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
61  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
62  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
63  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64  *
65  * Instrumented by Stefan Reich (info@luaos.net)
66  * for Mobile Lua (http://luaos.net/pages/mobile-lua.php)
67  */
68 
69 
70 #include "lua_persistence_util.h"
71 
72 #include "common/scummsys.h"
73 
74 #include "lobject.h"
75 #include "lstate.h"
76 #include "lgc.h"
77 #include "lopcodes.h"
78 
79 
80 namespace Lua {
81 
lua_realloc(lua_State * luaState,void * block,size_t osize,size_t nsize)82 void *lua_realloc(lua_State *luaState, void *block, size_t osize, size_t nsize) {
83 	global_State *globalState = G(luaState);
84 
85 	block = (*globalState->frealloc)(globalState->ud, block, osize, nsize);
86 	globalState->totalbytes = (globalState->totalbytes - osize) + nsize;
87 
88 	return block;
89 }
90 
pushObject(lua_State * luaState,TValue * obj)91 void pushObject(lua_State *luaState, TValue *obj) {
92 	setobj2s(luaState, luaState->top, obj);
93 
94 	api_check(luaState, luaState->top < luaState->ci->top);
95 	luaState->top++;
96 }
97 
pushProto(lua_State * luaState,Proto * proto)98 void pushProto(lua_State *luaState, Proto *proto) {
99 	TValue obj;
100 	setptvalue(luaState, &obj, proto);
101 
102 	pushObject(luaState, &obj);
103 }
104 
pushUpValue(lua_State * luaState,UpVal * upval)105 void pushUpValue(lua_State *luaState, UpVal *upval) {
106 	TValue obj;
107 
108 	obj.value.gc = cast(GCObject *, upval);
109 	obj.tt = LUA_TUPVAL;
110 	checkliveness(G(L), obj);
111 
112 	pushObject(luaState, &obj);
113 }
114 
pushString(lua_State * luaState,TString * str)115 void pushString(lua_State *luaState, TString *str) {
116 	TValue o;
117 	setsvalue(luaState, &o, str);
118 
119 	pushObject(luaState, &o);
120 }
121 
122 /* A simple reimplementation of the unfortunately static function luaA_index.
123  * Does not support the global table, registry, or upvalues. */
getObject(lua_State * luaState,int stackpos)124 StkId getObject(lua_State *luaState, int stackpos) {
125 	if (stackpos > 0) {
126 		lua_assert(luaState->base + stackpos - 1 < luaState->top);
127 		return luaState->base + stackpos - 1;
128 	} else {
129 		lua_assert(L->top - stackpos >= L->base);
130 		return luaState->top + stackpos;
131 	}
132 }
133 
lua_linkObjToGC(lua_State * luaState,GCObject * obj,lu_byte type)134 void lua_linkObjToGC(lua_State *luaState, GCObject *obj, lu_byte type) {
135 	global_State *globalState = G(luaState);
136 
137 	obj->gch.next = globalState->rootgc;
138 	globalState->rootgc = obj;
139 	obj->gch.marked = luaC_white(globalState);
140 	obj->gch.tt = type;
141 }
142 
lua_newLclosure(lua_State * luaState,int numElements,Table * elementTable)143 Closure *lua_newLclosure(lua_State *luaState, int numElements, Table *elementTable) {
144 	Closure *c = (Closure *)lua_malloc(luaState, sizeLclosure(numElements));
145 	lua_linkObjToGC(luaState, obj2gco(c), LUA_TFUNCTION);
146 
147 	c->l.isC = 0;
148 	c->l.env = elementTable;
149 	c->l.nupvalues = cast_byte(numElements);
150 
151 	while (numElements--) {
152 		c->l.upvals[numElements] = NULL;
153 	}
154 
155 	return c;
156 }
157 
pushClosure(lua_State * luaState,Closure * closure)158 void pushClosure(lua_State *luaState, Closure *closure) {
159 	TValue obj;
160 	setclvalue(luaState, &obj, closure);
161 	pushObject(luaState, &obj);
162 }
163 
createProto(lua_State * luaState)164 Proto *createProto(lua_State *luaState) {
165 	Proto *newProto = (Proto *)lua_malloc(luaState, sizeof(Proto));
166 	lua_linkObjToGC(luaState, obj2gco(newProto), LUA_TPROTO);
167 
168 	newProto->k = NULL;
169 	newProto->sizek = 0;
170 	newProto->p = NULL;
171 	newProto->sizep = 0;
172 	newProto->code = NULL;
173 	newProto->sizecode = 0;
174 	newProto->sizelineinfo = 0;
175 	newProto->sizeupvalues = 0;
176 	newProto->nups = 0;
177 	newProto->upvalues = NULL;
178 	newProto->numparams = 0;
179 	newProto->is_vararg = 0;
180 	newProto->maxstacksize = 0;
181 	newProto->lineinfo = NULL;
182 	newProto->sizelocvars = 0;
183 	newProto->locvars = NULL;
184 	newProto->linedefined = 0;
185 	newProto->lastlinedefined = 0;
186 	newProto->source = NULL;
187 
188 	return newProto;
189 }
190 
createString(lua_State * luaState,const char * str,size_t len)191 TString *createString(lua_State *luaState, const char *str, size_t len) {
192 	TString *res;
193 	lua_pushlstring(luaState, str, len);
194 
195 	res = rawtsvalue(luaState->top - 1);
196 	lua_pop(luaState, 1);
197 
198 	return res;
199 }
200 
makeFakeProto(lua_State * L,lu_byte nups)201 Proto *makeFakeProto(lua_State *L, lu_byte nups) {
202 	Proto *p = createProto(L);
203 
204 	p->sizelineinfo = 1;
205 	p->lineinfo = lua_newVector(L, 1, int);
206 	p->lineinfo[0] = 1;
207 	p->sizecode = 1;
208 	p->code = lua_newVector(L, 1, Instruction);
209 	p->code[0] = CREATE_ABC(OP_RETURN, 0, 1, 0);
210 	p->source = createString(L, "", 0);
211 	p->maxstacksize = 2;
212 	p->nups = nups;
213 	p->sizek = 0;
214 	p->sizep = 0;
215 
216 	return p;
217 }
218 
createUpValue(lua_State * luaState,int stackpos)219 UpVal *createUpValue(lua_State *luaState, int stackpos) {
220 	UpVal *upValue = (UpVal *)lua_malloc(luaState, sizeof(UpVal));
221 	lua_linkObjToGC(luaState, (GCObject *)upValue, LUA_TUPVAL);
222 	upValue->tt = LUA_TUPVAL;
223 	upValue->v = &upValue->u.value;
224 	upValue->u.l.prev = NULL;
225 	upValue->u.l.next = NULL;
226 
227 	const TValue *o2 = (TValue *)getObject(luaState, stackpos);
228 	upValue->v->value = o2->value;
229 	upValue->v->tt = o2->tt;
230 	checkliveness(G(L), upValue->v);
231 
232 	return upValue;
233 }
234 
unboxUpValue(lua_State * luaState)235 void unboxUpValue(lua_State *luaState) {
236 	// >>>>> ...... func
237 	LClosure *lcl;
238 	UpVal *uv;
239 
240 	lcl = (LClosure *)clvalue(getObject(luaState, -1));
241 	uv = lcl->upvals[0];
242 
243 	lua_pop(luaState, 1);
244 	// >>>>> ......
245 
246 	pushUpValue(luaState, uv);
247 	// >>>>> ...... upValue
248 }
249 
appendStackToStack_reverse(lua_State * from,lua_State * to)250 size_t appendStackToStack_reverse(lua_State *from, lua_State *to) {
251 	for (StkId id = from->top - 1; id >= from->stack; --id) {
252 		setobj2s(to, to->top, id);
253 		to->top++;
254 	}
255 
256 	return from->top - from->stack;
257 }
258 
correctStack(lua_State * L,TValue * oldstack)259 void correctStack(lua_State *L, TValue *oldstack) {
260 	CallInfo *ci;
261 	GCObject *up;
262 	L->top = (L->top - oldstack) + L->stack;
263 	for (up = L->openupval; up != NULL; up = up->gch.next)
264 		gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack;
265 	for (ci = L->base_ci; ci <= L->ci; ci++) {
266 		ci->top = (ci->top - oldstack) + L->stack;
267 		ci->base = (ci->base - oldstack) + L->stack;
268 		ci->func = (ci->func - oldstack) + L->stack;
269 	}
270 	L->base = (L->base - oldstack) + L->stack;
271 }
272 
lua_reallocstack(lua_State * L,int newsize)273 void lua_reallocstack(lua_State *L, int newsize) {
274 	TValue *oldstack = L->stack;
275 	int realsize = newsize + 1 + EXTRA_STACK;
276 
277 	lua_reallocvector(L, L->stack, L->stacksize, realsize, TValue);
278 	L->stacksize = realsize;
279 	L->stack_last = L->stack + newsize;
280 	correctStack(L, oldstack);
281 }
282 
lua_reallocCallInfo(lua_State * lauState,int newsize)283 void lua_reallocCallInfo(lua_State *lauState, int newsize) {
284 	CallInfo *oldci = lauState->base_ci;
285 	lua_reallocvector(lauState, lauState->base_ci, lauState->size_ci, newsize, CallInfo);
286 
287 	lauState->size_ci = newsize;
288 	lauState->ci = (lauState->ci - oldci) + lauState->base_ci;
289 	lauState->end_ci = lauState->base_ci + lauState->size_ci - 1;
290 }
291 
GCUnlink(lua_State * luaState,GCObject * gco)292 void GCUnlink(lua_State *luaState, GCObject *gco) {
293 	GCObject *prevslot;
294 	if (G(luaState)->rootgc == gco) {
295 		G(luaState)->rootgc = G(luaState)->rootgc->gch.next;
296 		return;
297 	}
298 
299 	prevslot = G(luaState)->rootgc;
300 	while (prevslot->gch.next != gco) {
301 		prevslot = prevslot->gch.next;
302 	}
303 
304 	prevslot->gch.next = prevslot->gch.next->gch.next;
305 }
306 
lua_newlstr(lua_State * luaState,const char * str,size_t len)307 TString *lua_newlstr(lua_State *luaState, const char *str, size_t len) {
308 	lua_pushlstring(luaState, str, len);
309 	TString *luaStr = &(luaState->top - 1)->value.gc->ts;
310 
311 	lua_pop(luaState, 1);
312 
313 	return luaStr;
314 }
315 
lua_link(lua_State * luaState,GCObject * o,lu_byte tt)316 void lua_link(lua_State *luaState, GCObject *o, lu_byte tt) {
317 	global_State *g = G(luaState);
318 	o->gch.next = g->rootgc;
319 	g->rootgc = o;
320 	o->gch.marked = luaC_white(g);
321 	o->gch.tt = tt;
322 }
323 
lua_newproto(lua_State * luaState)324 Proto *lua_newproto(lua_State *luaState) {
325 	Proto *f = (Proto *)lua_malloc(luaState, sizeof(Proto));
326 	lua_link(luaState, obj2gco(f), LUA_TPROTO);
327 	f->k = NULL;
328 	f->sizek = 0;
329 	f->p = NULL;
330 	f->sizep = 0;
331 	f->code = NULL;
332 	f->sizecode = 0;
333 	f->sizelineinfo = 0;
334 	f->sizeupvalues = 0;
335 	f->nups = 0;
336 	f->upvalues = NULL;
337 	f->numparams = 0;
338 	f->is_vararg = 0;
339 	f->maxstacksize = 0;
340 	f->lineinfo = NULL;
341 	f->sizelocvars = 0;
342 	f->locvars = NULL;
343 	f->linedefined = 0;
344 	f->lastlinedefined = 0;
345 	f->source = NULL;
346 	return f;
347 }
348 
makeUpValue(lua_State * luaState,int stackPos)349 UpVal *makeUpValue(lua_State *luaState, int stackPos) {
350 	UpVal *uv = lua_new(luaState, UpVal);
351 	lua_link(luaState, (GCObject *)uv, LUA_TUPVAL);
352 	uv->tt = LUA_TUPVAL;
353 	uv->v = &uv->u.value;
354 	uv->u.l.prev = NULL;
355 	uv->u.l.next = NULL;
356 
357 	setobj(luaState, uv->v, getObject(luaState, stackPos));
358 
359 	return uv;
360 }
361 
boxUpValue_start(lua_State * luaState)362 void boxUpValue_start(lua_State *luaState) {
363 	LClosure *closure;
364 	closure = (LClosure *)lua_newLclosure(luaState, 1, hvalue(&luaState->l_gt));
365 	pushClosure(luaState, (Closure *)closure);
366 	// >>>>> ...... func
367 	closure->p = makeFakeProto(luaState, 1);
368 
369 	// Temporarily initialize the upvalue to nil
370 	lua_pushnil(luaState);
371 	closure->upvals[0] = makeUpValue(luaState, -1);
372 	lua_pop(luaState, 1);
373 }
374 
boxUpValue_finish(lua_State * luaState)375 void boxUpValue_finish(lua_State *luaState) {
376 	// >>>>> ...... func obj
377 	LClosure *lcl = (LClosure *)clvalue(getObject(luaState, -2));
378 
379 	lcl->upvals[0]->u.value = *getObject(luaState, -1);
380 	lua_pop(luaState, 1);
381 	// >>>>> ...... func
382 }
383 
384 } // End of namespace Lua
385