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