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 distributed 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 #include "lua_persistence.h"
48 
49 #include "double_serialization.h"
50 #include "lua_persistence_util.h"
51 
52 #include "common/stream.h"
53 
54 #include "lobject.h"
55 #include "lstate.h"
56 #include "lgc.h"
57 #include "lopcodes.h"
58 
59 
60 namespace Lua {
61 
62 struct UnSerializationInfo {
63 	lua_State *luaState;
64 	Common::ReadStream *readStream;
65 };
66 
67 static void unpersist(UnSerializationInfo *info);
68 
69 static void unpersistBoolean(UnSerializationInfo *info);
70 static void unpersistNumber(UnSerializationInfo *info);
71 static void unpersistString(UnSerializationInfo *info);
72 static void unpersistTable(UnSerializationInfo *info, int index);
73 static void unpersistFunction(UnSerializationInfo *info, int index);
74 static void unpersistThread(UnSerializationInfo *info, int index);
75 static void unpersistProto(UnSerializationInfo *info, int index);
76 static void unpersistUpValue(UnSerializationInfo *info, int index);
77 static void unpersistUserData(UnSerializationInfo *info, int index);
78 static void unpersistPermanent(UnSerializationInfo *info, int index);
79 
80 
unpersistLua(lua_State * luaState,Common::ReadStream * readStream)81 void unpersistLua(lua_State *luaState, Common::ReadStream *readStream) {
82 	UnSerializationInfo info;
83 	info.luaState = luaState;
84 	info.readStream = readStream;
85 
86 	// The process starts with the lua stack as follows:
87 	// >>>>> permTbl
88 	// That's the table of permanents
89 
90 	// Make sure there is enough room on the stack
91 	lua_checkstack(luaState, 3);
92 
93 	// Create a table to hold indexes of everything thats already been read
94 	lua_newtable(luaState);
95 	// >>>>> permTbl indexTbl
96 
97 	// Prevent garbage collection while we unserialize
98 	lua_gc(luaState, LUA_GCSTOP, 0);
99 
100 	// Unserialize the root object
101 	unpersist(&info);
102 	// >>>>> permTbl indexTbl rootObj
103 
104 	// Re-start garbage collection
105 	lua_gc(luaState, LUA_GCRESTART, 0);
106 
107 	// Remove the indexTbl
108 	lua_replace(luaState, 2);
109 	// >>>>> permTbl rootObj
110 }
111 
112 /* The object is left on the stack. This is primarily used by unserialize, but
113  * may be used by GCed objects that may incur cycles in order to preregister
114  * the object. */
registerObjectInIndexTable(UnSerializationInfo * info,int index)115 static void registerObjectInIndexTable(UnSerializationInfo *info, int index) {
116 	// >>>>> permTbl indexTbl ...... obj
117 
118 	// Make sure there is enough room on the stack
119 	lua_checkstack(info->luaState, 1);
120 
121 	lua_pushvalue(info->luaState, -1);
122 	// >>>>> permTbl indexTbl ...... obj obj
123 
124 	// Push the k/v pair into the indexTbl
125 	lua_rawseti(info->luaState, 2, index);
126 	// >>>>> permTbl indexTbl ...... obj
127 }
128 
unpersist(UnSerializationInfo * info)129 static void unpersist(UnSerializationInfo *info) {
130 	// >>>>> permTbl indexTbl ......
131 
132 	// Make sure there is enough room on the stack
133 	lua_checkstack(info->luaState, 2);
134 
135 	byte isARealValue = info->readStream->readByte();
136 	if (isARealValue) {
137 		int index = info->readStream->readSint32LE();
138 		int type = info->readStream->readSint32LE();
139 
140 		switch (type) {
141 		case LUA_TBOOLEAN:
142 			unpersistBoolean(info);
143 			break;
144 		case LUA_TLIGHTUSERDATA:
145 			// You can't serialize a pointer
146 			// It would be meaningless on the next run
147 			assert(0);
148 			break;
149 		case LUA_TNUMBER:
150 			unpersistNumber(info);
151 			break;
152 		case LUA_TSTRING:
153 			unpersistString(info);
154 			break;
155 		case LUA_TTABLE:
156 			unpersistTable(info, index);
157 			break;
158 		case LUA_TFUNCTION:
159 			unpersistFunction(info, index);
160 			break;
161 		case LUA_TTHREAD:
162 			unpersistThread(info, index);
163 			break;
164 		case LUA_TPROTO:
165 			unpersistProto(info, index);
166 			break;
167 		case LUA_TUPVAL:
168 			unpersistUpValue(info, index);
169 			break;
170 		case LUA_TUSERDATA:
171 			unpersistUserData(info, index);
172 			break;
173 		case PERMANENT_TYPE:
174 			unpersistPermanent(info, index);
175 			break;
176 		default:
177 			assert(0);
178 		}
179 
180 
181 		// >>>>> permTbl indexTbl ...... obj
182 		assert(lua_type(info->luaState, -1) == type ||
183 		       type == PERMANENT_TYPE ||
184 		       // Remember, upvalues get a special dispensation, as described in boxUpValue
185 		       (lua_type(info->luaState, -1) == LUA_TFUNCTION && type == LUA_TUPVAL));
186 
187 		registerObjectInIndexTable(info, index);
188 		// >>>>> permTbl indexTbl ...... obj
189 	} else {
190 		int index = info->readStream->readSint32LE();
191 
192 		if (index == 0) {
193 			lua_pushnil(info->luaState);
194 			// >>>>> permTbl indexTbl ...... nil
195 		} else {
196 			// Fetch the object from the indexTbl
197 
198 			lua_rawgeti(info->luaState, 2, index);
199 			// >>>>> permTbl indexTbl ...... ?obj?
200 
201 			assert(!lua_isnil(info->luaState, -1));
202 		}
203 		// >>>>> permTbl indexTbl ...... obj/nil
204 	}
205 
206 	// >>>>> permTbl indexTbl ...... obj/nil
207 }
208 
unpersistBoolean(UnSerializationInfo * info)209 static void unpersistBoolean(UnSerializationInfo *info) {
210 	// >>>>> permTbl indexTbl ......
211 
212 	// Make sure there is enough room on the stack
213 	lua_checkstack(info->luaState, 1);
214 
215 	int value = info->readStream->readSint32LE();
216 
217 	lua_pushboolean(info->luaState, value);
218 	// >>>>> permTbl indexTbl ...... bool
219 }
220 
unpersistNumber(UnSerializationInfo * info)221 static void unpersistNumber(UnSerializationInfo *info) {
222 	// >>>>> permTbl indexTbl ......
223 
224 	// Make sure there is enough room on the stack
225 	lua_checkstack(info->luaState, 1);
226 
227 	// Read the serialized double
228 	Util::SerializedDouble serializedValue;
229 	serializedValue.significandOne = info->readStream->readUint32LE();
230 	serializedValue.signAndSignificandTwo = info->readStream->readUint32LE();
231 	serializedValue.exponent = info->readStream->readSint16LE();
232 
233 	lua_Number value = Util::decodeDouble(serializedValue);
234 
235 	lua_pushnumber(info->luaState, value);
236 	// >>>>> permTbl indexTbl ...... num
237 }
238 
unpersistString(UnSerializationInfo * info)239 static void unpersistString(UnSerializationInfo *info) {
240 	// >>>>> permTbl indexTbl ......
241 
242 	// Make sure there is enough room on the stack
243 	lua_checkstack(info->luaState, 1);
244 
245 	uint32 length = info->readStream->readUint32LE();
246 	char *string = new char[length];
247 
248 	info->readStream->read(string, length);
249 	lua_pushlstring(info->luaState, string, length);
250 
251 	// >>>>> permTbl indexTbl ...... string
252 
253 	delete[] string;
254 }
255 
unserializeSpecialTable(UnSerializationInfo * info,int index)256 static void unserializeSpecialTable(UnSerializationInfo *info, int index) {
257 	// >>>>> permTbl indexTbl ......
258 
259 	// Make sure there is enough room on the stack
260 	lua_checkstack(info->luaState, 1);
261 
262 	unpersist(info);
263 
264 	// >>>>> permTbl indexTbl ...... spfunc
265 	lua_call(info->luaState, 0, 1);
266 	// >>>>> permTbl indexTbl ...... tbl
267 }
268 
unserializeLiteralTable(UnSerializationInfo * info,int index)269 static void unserializeLiteralTable(UnSerializationInfo *info, int index) {
270 	// >>>>> permTbl indexTbl ......
271 
272 	// Make sure there is enough room on the stack
273 	lua_checkstack(info->luaState, 3);
274 
275 	// Preregister table for handling of cycles
276 	lua_newtable(info->luaState);
277 
278 	// >>>>> permTbl indexTbl ...... tbl
279 	registerObjectInIndexTable(info, index);
280 	// >>>>> permTbl indexTbl ...... tbl
281 
282 	// Unserialize metatable
283 	unpersist(info);
284 	// >>>>> permTbl indexTbl ...... tbl ?metaTbl/nil?
285 
286 	if (lua_istable(info->luaState, -1)) {
287 		// >>>>> permTbl indexTbl ...... tbl metaTbl
288 		lua_setmetatable(info->luaState, -2);
289 		// >>>>> permTbl indexTbl ...... tbl
290 	} else {
291 		// >>>>> permTbl indexTbl ...... tbl nil
292 		lua_pop(info->luaState, 1);
293 		// >>>>> permTbl indexTbl ...... tbl
294 	}
295 	// >>>>> permTbl indexTbl ...... tbl
296 
297 
298 	while (1) {
299 		// >>>>> permTbl indexTbl ...... tbl
300 		unpersist(info);
301 		// >>>>> permTbl indexTbl ...... tbl key/nil
302 
303 		// The table serialization is nil terminated
304 		if (lua_isnil(info->luaState, -1)) {
305 			// >>>>> permTbl indexTbl ...... tbl nil
306 			lua_pop(info->luaState, 1);
307 			// >>>>> permTbl indexTbl ...... tbl
308 
309 			break;
310 		}
311 
312 		// >>>>> permTbl indexTbl ...... tbl key
313 		unpersist(info);
314 		// >>>>> permTbl indexTbl ...... tbl value
315 
316 		lua_rawset(info->luaState, -3);
317 		// >>>>> permTbl indexTbl ...... tbl
318 	}
319 }
320 
unpersistTable(UnSerializationInfo * info,int index)321 void unpersistTable(UnSerializationInfo *info, int index) {
322 	// >>>>> permTbl indexTbl ......
323 
324 	// Make sure there is enough room on the stack
325 	lua_checkstack(info->luaState, 1);
326 
327 	int isSpecial = info->readStream->readSint32LE();
328 
329 	if (isSpecial) {
330 		unserializeSpecialTable(info, index);
331 		// >>>>> permTbl indexTbl ...... tbl
332 	} else {
333 		unserializeLiteralTable(info, index);
334 		// >>>>> permTbl indexTbl ...... tbl
335 	}
336 }
337 
unpersistFunction(UnSerializationInfo * info,int index)338 void unpersistFunction(UnSerializationInfo *info, int index) {
339 	// >>>>> permTbl indexTbl ......
340 
341 	// Make sure there is enough room on the stack
342 	lua_checkstack(info->luaState, 2);
343 
344 	byte numUpValues = info->readStream->readByte();
345 
346 	LClosure *lclosure = (LClosure *)lua_newLclosure(info->luaState, numUpValues, hvalue(&info->luaState->l_gt));
347 	pushClosure(info->luaState, (Closure *)lclosure);
348 	// >>>>> permTbl indexTbl ...... func
349 
350 	// Put *some* proto in the closure, before the GC can find it
351 	lclosure->p = makeFakeProto(info->luaState, numUpValues);
352 
353 	//Also, we need to temporarily fill the upvalues
354 	lua_pushnil(info->luaState);
355 	// >>>>> permTbl indexTbl ...... func nil
356 
357 	for (byte i = 0; i < numUpValues; ++i) {
358 		lclosure->upvals[i] = createUpValue(info->luaState, -1);
359 	}
360 
361 	lua_pop(info->luaState, 1);
362 	// >>>>> permTbl indexTbl ...... func
363 
364 	// I can't see offhand how a function would ever get to be self-
365 	// referential, but just in case let's register it early
366 	registerObjectInIndexTable(info, index);
367 
368 	// Now that it's safe, we can get the real proto
369 	unpersist(info);
370 	// >>>>> permTbl indexTbl ...... func proto
371 
372 	lclosure->p = gco2p(getObject(info->luaState, -1)->value.gc);
373 
374 	lua_pop(info->luaState, 1);
375 	// >>>>> permTbl indexTbl ...... func
376 
377 	for (byte i = 0; i < numUpValues; ++i) {
378 		// >>>>> permTbl indexTbl ...... func
379 		unpersist(info);
380 		// >>>>> permTbl indexTbl ...... func func2
381 
382 		unboxUpValue(info->luaState);
383 		// >>>>> permTbl indexTbl ...... func upValue
384 		lclosure->upvals[i] = gco2uv(getObject(info->luaState, -1)->value.gc);
385 
386 		lua_pop(info->luaState, 1);
387 		// >>>>> permTbl indexTbl ...... func
388 	}
389 
390 	// Finally, the fenv
391 	unpersist(info);
392 
393 	// >>>>> permTbl indexTbl ...... func ?fenv/nil?
394 	if (!lua_isnil(info->luaState, -1)) {
395 		// >>>>> permTbl indexTbl ...... func fenv
396 		lua_setfenv(info->luaState, -2);
397 		// >>>>> permTbl indexTbl ...... func
398 	} else {
399 		// >>>>> permTbl indexTbl ...... func nil
400 		lua_pop(info->luaState, 1);
401 		// >>>>> permTbl indexTbl ...... func
402 	}
403 
404 	// >>>>> permTbl indexTbl ...... func
405 }
406 
unpersistThread(UnSerializationInfo * info,int index)407 void unpersistThread(UnSerializationInfo *info, int index) {
408 	// >>>>> permTbl indexTbl ......
409 
410 	lua_State *L2;
411 	uint32 stacklimit = 0;
412 
413 	L2 = lua_newthread(info->luaState);
414 	lua_checkstack(info->luaState, 3);
415 
416 	// L1: permTbl indexTbl ...... thread
417 	// L2: (empty)
418 	registerObjectInIndexTable(info, index);
419 
420 	// First, deserialize the object stack
421 	uint32 stackSize = info->readStream->readUint32LE();
422 	lua_checkstack(info->luaState, (int)stackSize);
423 
424 	// Make sure that the first stack element (a nil, representing
425 	// the imaginary top-level C function) is written to the very,
426 	// very bottom of the stack
427 	L2->top--;
428 	for (uint32 i = 0; i < stackSize; ++i) {
429 		unpersist(info);
430 		// L1: permTbl indexTbl ...... thread obj*
431 	}
432 
433 	lua_xmove(info->luaState, L2, stackSize);
434 	// L1: permTbl indexTbl ...... thread
435 	// L2: obj*
436 
437 	// Hereafter, stacks refer to L1
438 
439 
440 	// Now, deserialize the CallInfo stack
441 
442 	uint32 numFrames = info->readStream->readUint32LE();
443 
444 	lua_reallocCallInfo(L2, numFrames * 2);
445 	for (uint32 i = 0; i < numFrames; ++i) {
446 		CallInfo *ci = L2->base_ci + i;
447 		uint32 stackbase = info->readStream->readUint32LE();
448 		uint32 stackfunc = info->readStream->readUint32LE();
449 		uint32 stacktop = info->readStream->readUint32LE();
450 
451 		ci->nresults = info->readStream->readSint32LE();
452 
453 		uint32 savedpc = info->readStream->readUint32LE();
454 
455 		if (stacklimit < stacktop) {
456 			stacklimit = stacktop;
457 		}
458 
459 		ci->base = L2->stack + stackbase;
460 		ci->func = L2->stack + stackfunc;
461 		ci->top = L2->stack + stacktop;
462 		ci->savedpc = (ci != L2->base_ci) ? ci_func(ci)->l.p->code + savedpc : 0;
463 		ci->tailcalls = 0;
464 
465 		// Update the pointer each time, to keep the GC happy
466 		L2->ci = ci;
467 	}
468 
469 	// >>>>> permTbl indexTbl ...... thread
470 	// Deserialize the state's other parameters, with the exception of upval stuff
471 
472 	L2->savedpc = L2->ci->savedpc;
473 	L2->status = info->readStream->readByte();
474 	uint32 stackbase = info->readStream->readUint32LE();
475 	uint32 stacktop = info->readStream->readUint32LE();
476 
477 
478 	L2->errfunc = info->readStream->readUint32LE();
479 
480 	L2->base = L2->stack + stackbase;
481 	L2->top = L2->stack + stacktop;
482 
483 	// Finally, "reopen" upvalues. See serializeUpVal() for why we do this
484 	UpVal *uv;
485 	GCObject **nextslot = &L2->openupval;
486 	global_State *g = G(L2);
487 
488 	while (true) {
489 		unpersist(info);
490 		// >>>>> permTbl indexTbl ...... thread upVal/nil
491 
492 		// The list is terminated by a nil
493 		if (lua_isnil(info->luaState, -1)) {
494 			// >>>>> permTbl indexTbl ...... thread nil
495 			lua_pop(info->luaState, 1);
496 			// >>>>> permTbl indexTbl ...... thread
497 			break;
498 		}
499 
500 		// >>>>> permTbl indexTbl ...... thread boxedUpVal
501 		unboxUpValue(info->luaState);
502 		// >>>>> permTbl indexTbl ...... thread boxedUpVal
503 
504 		uv = &(getObject(info->luaState, -1)->value.gc->uv);
505 		lua_pop(info->luaState, 1);
506 		// >>>>> permTbl indexTbl ...... thread
507 
508 		uint32 stackpos = info->readStream->readUint32LE();
509 		uv->v = L2->stack + stackpos;
510 
511 		GCUnlink(info->luaState, (GCObject *)uv);
512 
513 		uv->marked = luaC_white(g);
514 		*nextslot = (GCObject *)uv;
515 		nextslot = &uv->next;
516 		uv->u.l.prev = &G(L2)->uvhead;
517 		uv->u.l.next = G(L2)->uvhead.u.l.next;
518 		uv->u.l.next->u.l.prev = uv;
519 		G(L2)->uvhead.u.l.next = uv;
520 		lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
521 	}
522 	*nextslot = NULL;
523 
524 	// The stack must be valid at least to the highest value among the CallInfos
525 	// 'top' and the values up to there must be filled with 'nil'
526 	lua_checkstack(L2, (int)stacklimit);
527 	for (StkId o = L2->top; o <= L2->top + stacklimit; ++o) {
528 		setnilvalue(o);
529 	}
530 }
531 
unpersistProto(UnSerializationInfo * info,int index)532 void unpersistProto(UnSerializationInfo *info, int index) {
533 	// >>>>> permTbl indexTbl ......
534 
535 	// We have to be careful. The GC expects a lot out of protos. In particular, we need
536 	// to give the function a valid string for its source, and valid code, even before we
537 	// actually read in the real code.
538 	TString *source = lua_newlstr(info->luaState, "", 0);
539 	Proto *p = lua_newproto(info->luaState);
540 	p->source = source;
541 	p->sizecode = 1;
542 	p->code = (Instruction *)lua_reallocv(info->luaState, NULL, 0, 1, sizeof(Instruction));
543 	p->code[0] = CREATE_ABC(OP_RETURN, 0, 1, 0);
544 	p->maxstacksize = 2;
545 	p->sizek = 0;
546 	p->sizep = 0;
547 
548 	lua_checkstack(info->luaState, 2);
549 
550 	pushProto(info->luaState, p);
551 	// >>>>> permTbl indexTbl ...... proto
552 
553 	// We don't need to register early, since protos can never ever be
554 	// involved in cyclic references
555 
556 	// Read in constant references
557 	int sizek = info->readStream->readSint32LE();
558 	lua_reallocvector(info->luaState, p->k, 0, sizek, TValue);
559 	for (int i = 0; i < sizek; ++i) {
560 		// >>>>> permTbl indexTbl ...... proto
561 		unpersist(info);
562 		// >>>>> permTbl indexTbl ...... proto  k
563 
564 		setobj2s(info->luaState, &p->k[i], getObject(info->luaState, -1));
565 		p->sizek++;
566 
567 		lua_pop(info->luaState, 1);
568 		// >>>>> permTbl indexTbl ...... proto
569 	}
570 	// >>>>> permTbl indexTbl ...... proto
571 
572 	// Read in sub-proto references
573 
574 	int sizep = info->readStream->readSint32LE();
575 	lua_reallocvector(info->luaState, p->p, 0, sizep, Proto *);
576 	for (int i = 0; i < sizep; ++i) {
577 		// >>>>> permTbl indexTbl ...... proto
578 		unpersist(info);
579 		// >>>>> permTbl indexTbl ...... proto  subproto
580 
581 		p->p[i] = (Proto *)getObject(info->luaState, -1)->value.gc;
582 		p->sizep++;
583 
584 		lua_pop(info->luaState, 1);
585 		// >>>>> permTbl indexTbl ...... proto
586 	}
587 	// >>>>> permTbl indexTbl ...... proto
588 
589 
590 	// Read in code
591 	p->sizecode = info->readStream->readSint32LE();
592 	lua_reallocvector(info->luaState, p->code, 1, p->sizecode, Instruction);
593 	info->readStream->read(p->code, sizeof(Instruction) * p->sizecode);
594 
595 
596 	/* Read in upvalue names */
597 	p->sizeupvalues = info->readStream->readSint32LE();
598 	if (p->sizeupvalues) {
599 		lua_reallocvector(info->luaState, p->upvalues, 0, p->sizeupvalues, TString *);
600 		for (int i = 0; i < p->sizeupvalues; ++i) {
601 			// >>>>> permTbl indexTbl ...... proto
602 			unpersist(info);
603 			// >>>>> permTbl indexTbl ...... proto str
604 
605 			p->upvalues[i] = lua_newlstr(info->luaState, lua_tostring(info->luaState, -1), strlen(lua_tostring(info->luaState, -1)));
606 			lua_pop(info->luaState, 1);
607 			// >>>>> permTbl indexTbl ...... proto
608 		}
609 	}
610 	// >>>>> permTbl indexTbl ...... proto
611 
612 	// Read in local variable infos
613 	p->sizelocvars = info->readStream->readSint32LE();
614 	if (p->sizelocvars) {
615 		lua_reallocvector(info->luaState, p->locvars, 0, p->sizelocvars, LocVar);
616 		for (int i = 0; i < p->sizelocvars; ++i) {
617 			// >>>>> permTbl indexTbl ...... proto
618 			unpersist(info);
619 			// >>>>> permTbl indexTbl ...... proto str
620 
621 			p->locvars[i].varname = lua_newlstr(info->luaState, lua_tostring(info->luaState, -1), strlen(lua_tostring(info->luaState, -1)));
622 			lua_pop(info->luaState, 1);
623 			// >>>>> permTbl indexTbl ...... proto
624 
625 			p->locvars[i].startpc = info->readStream->readSint32LE();
626 			p->locvars[i].endpc = info->readStream->readSint32LE();
627 		}
628 	}
629 	// >>>>> permTbl indexTbl ...... proto
630 
631 	// Read in source string
632 	unpersist(info);
633 	// >>>>> permTbl indexTbl ...... proto sourceStr
634 
635 	p->source = lua_newlstr(info->luaState, lua_tostring(info->luaState, -1), strlen(lua_tostring(info->luaState, -1)));
636 	lua_pop(info->luaState, 1);
637 	// >>>>> permTbl indexTbl ...... proto
638 
639 	// Read in line numbers
640 	p->sizelineinfo = info->readStream->readSint32LE();
641 	if (p->sizelineinfo) {
642 		lua_reallocvector(info->luaState, p->lineinfo, 0, p->sizelineinfo, int);
643 		info->readStream->read(p->lineinfo, sizeof(int) * p->sizelineinfo);
644 	}
645 
646 
647 	/* Read in linedefined and lastlinedefined */
648 	p->linedefined = info->readStream->readSint32LE();
649 	p->lastlinedefined = info->readStream->readSint32LE();
650 
651 	// Read in misc values
652 	p->nups = info->readStream->readByte();
653 	p->numparams = info->readStream->readByte();
654 	p->is_vararg = info->readStream->readByte();
655 	p->maxstacksize = info->readStream->readByte();
656 }
657 
unpersistUpValue(UnSerializationInfo * info,int index)658 void unpersistUpValue(UnSerializationInfo *info, int index) {
659 	// >>>>> permTbl indexTbl ......
660 	lua_checkstack(info->luaState, 2);
661 
662 	boxUpValue_start(info->luaState);
663 	// >>>>> permTbl indexTbl ...... func
664 	registerObjectInIndexTable(info, index);
665 
666 	unpersist(info);
667 	// >>>>> permTbl indexTbl ...... func obj
668 
669 	boxUpValue_finish(info->luaState);
670 	// >>>>> permTbl indexTbl ...... func
671 }
672 
unpersistUserData(UnSerializationInfo * info,int index)673 void unpersistUserData(UnSerializationInfo *info, int index) {
674 	// >>>>> permTbl indexTbl ......
675 
676 	// Make sure there is enough room on the stack
677 	lua_checkstack(info->luaState, 2);
678 
679 	int isspecial = info->readStream->readSint32LE();
680 	if (isspecial) {
681 		unpersist(info);
682 		// >>>>> permTbl indexTbl ...... specialFunc
683 
684 		lua_call(info->luaState, 0, 1);
685 		// >>>>> permTbl indexTbl ...... udata
686 	} else {
687 		uint32 length = info->readStream->readUint32LE();
688 		lua_newuserdata(info->luaState, length);
689 		// >>>>> permTbl indexTbl ...... udata
690 		registerObjectInIndexTable(info, index);
691 
692 		info->readStream->read(lua_touserdata(info->luaState, -1), length);
693 
694 		unpersist(info);
695 		// >>>>> permTbl indexTbl ...... udata metaTable/nil
696 
697 		lua_setmetatable(info->luaState, -2);
698 		// >>>>> permTbl indexTbl ...... udata
699 	}
700 	// >>>>> permTbl indexTbl ...... udata
701 }
702 
unpersistPermanent(UnSerializationInfo * info,int index)703 void unpersistPermanent(UnSerializationInfo *info, int index) {
704 	// >>>>> permTbl indexTbl ......
705 
706 	// Make sure there is enough room on the stack
707 	lua_checkstack(info->luaState, 2);
708 
709 	unpersist(info);
710 	// >>>>> permTbl indexTbl ...... permKey
711 
712 	lua_gettable(info->luaState, 1);
713 	// >>>>> permTbl indexTbl ...... perm
714 }
715 
716 } // End of namespace Lua
717