bdcbfa6ed8b8813015f138881fc958e58e8b9d57
[supertux.git] / external / squirrel / squirrel / sqobject.cpp
1 /*\r
2         see copyright notice in squirrel.h\r
3 */\r
4 #include "sqpcheader.h"\r
5 #include "sqvm.h"\r
6 #include "sqstring.h"\r
7 #include "sqarray.h"\r
8 #include "sqtable.h"\r
9 #include "squserdata.h"\r
10 #include "sqfuncproto.h"\r
11 #include "sqclass.h"\r
12 #include "sqclosure.h"\r
13 \r
14 \r
15 const SQChar *IdType2Name(SQObjectType type)\r
16 {\r
17         switch(_RAW_TYPE(type))\r
18         {\r
19         case _RT_NULL:return _SC("null");\r
20         case _RT_INTEGER:return _SC("integer");\r
21         case _RT_FLOAT:return _SC("float");\r
22         case _RT_BOOL:return _SC("bool");\r
23         case _RT_STRING:return _SC("string");\r
24         case _RT_TABLE:return _SC("table");\r
25         case _RT_ARRAY:return _SC("array");\r
26         case _RT_GENERATOR:return _SC("generator");\r
27         case _RT_CLOSURE:\r
28         case _RT_NATIVECLOSURE:\r
29                 return _SC("function");\r
30         case _RT_USERDATA:\r
31         case _RT_USERPOINTER:\r
32                 return _SC("userdata");\r
33         case _RT_THREAD: return _SC("thread");\r
34         case _RT_FUNCPROTO: return _SC("function");\r
35         case _RT_CLASS: return _SC("class");\r
36         case _RT_INSTANCE: return _SC("instance");\r
37         case _RT_WEAKREF: return _SC("weakref");\r
38         case _RT_OUTER: return _SC("outer");\r
39         default:\r
40                 return NULL;\r
41         }\r
42 }\r
43 \r
44 const SQChar *GetTypeName(const SQObjectPtr &obj1)\r
45 {\r
46         return IdType2Name(type(obj1)); \r
47 }\r
48 \r
49 SQString *SQString::Create(SQSharedState *ss,const SQChar *s,SQInteger len)\r
50 {\r
51         SQString *str=ADD_STRING(ss,s,len);\r
52         return str;\r
53 }\r
54 \r
55 void SQString::Release()\r
56 {\r
57         REMOVE_STRING(_sharedstate,this);\r
58 }\r
59 \r
60 SQInteger SQString::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)\r
61 {\r
62         SQInteger idx = (SQInteger)TranslateIndex(refpos);\r
63         while(idx < _len){\r
64                 outkey = (SQInteger)idx;\r
65                 outval = (SQInteger)((SQUnsignedInteger)_val[idx]);\r
66                 //return idx for the next iteration\r
67                 return ++idx;\r
68         }\r
69         //nothing to iterate anymore\r
70         return -1;\r
71 }\r
72 \r
73 SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx)\r
74 {\r
75         switch(type(idx)){\r
76                 case OT_NULL:\r
77                         return 0;\r
78                 case OT_INTEGER:\r
79                         return (SQUnsignedInteger)_integer(idx);\r
80                 default: assert(0); break;\r
81         }\r
82         return 0;\r
83 }\r
84 \r
85 SQWeakRef *SQRefCounted::GetWeakRef(SQObjectType type)\r
86 {\r
87         if(!_weakref) {\r
88                 sq_new(_weakref,SQWeakRef);\r
89                 _weakref->_obj._type = type;\r
90                 _weakref->_obj._unVal.pRefCounted = this;\r
91         }\r
92         return _weakref;\r
93 }\r
94 \r
95 SQRefCounted::~SQRefCounted()\r
96 {\r
97         if(_weakref) {\r
98                 _weakref->_obj._type = OT_NULL;\r
99                 _weakref->_obj._unVal.pRefCounted = NULL;\r
100         }\r
101 }\r
102 \r
103 void SQWeakRef::Release() { \r
104         if(ISREFCOUNTED(_obj._type)) { \r
105                 _obj._unVal.pRefCounted->_weakref = NULL;\r
106         } \r
107         sq_delete(this,SQWeakRef);\r
108 }\r
109 \r
110 bool SQDelegable::GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res) {\r
111         if(_delegate) {\r
112                 return _delegate->Get((*_ss(v)->_metamethods)[mm],res);\r
113         }\r
114         return false;\r
115 }\r
116 \r
117 bool SQDelegable::SetDelegate(SQTable *mt)\r
118 {\r
119         SQTable *temp = mt;\r
120         if(temp == this) return false;\r
121         while (temp) {\r
122                 if (temp->_delegate == this) return false; //cycle detected\r
123                 temp = temp->_delegate;\r
124         }\r
125         if (mt) __ObjAddRef(mt);\r
126         __ObjRelease(_delegate);\r
127         _delegate = mt;\r
128         return true;\r
129 }\r
130 \r
131 bool SQGenerator::Yield(SQVM *v,SQInteger target)\r
132 {\r
133         if(_state==eSuspended) { v->Raise_Error(_SC("internal vm error, yielding dead generator"));  return false;}\r
134         if(_state==eDead) { v->Raise_Error(_SC("internal vm error, yielding a dead generator")); return false; }\r
135         SQInteger size = v->_top-v->_stackbase;\r
136         \r
137         _stack.resize(size);\r
138         SQObject _this = v->_stack[v->_stackbase];\r
139         _stack._vals[0] = ISREFCOUNTED(type(_this)) ? SQObjectPtr(_refcounted(_this)->GetWeakRef(type(_this))) : _this;\r
140         for(SQInteger n =1; n<target; n++) {\r
141                 _stack._vals[n] = v->_stack[v->_stackbase+n];\r
142         }\r
143         for(SQInteger j =0; j < size; j++)\r
144         {\r
145                 v->_stack[v->_stackbase+j].Null();\r
146         }\r
147 \r
148         _ci = *v->ci;\r
149         _ci._generator=NULL;\r
150         for(SQInteger i=0;i<_ci._etraps;i++) {\r
151                 _etraps.push_back(v->_etraps.top());\r
152                 v->_etraps.pop_back();\r
153         }\r
154         _state=eSuspended;\r
155         return true;\r
156 }\r
157 \r
158 bool SQGenerator::Resume(SQVM *v,SQObjectPtr &dest)\r
159 {\r
160         if(_state==eDead){ v->Raise_Error(_SC("resuming dead generator")); return false; }\r
161         if(_state==eRunning){ v->Raise_Error(_SC("resuming active generator")); return false; }\r
162         SQInteger size = _stack.size();\r
163         SQInteger target = &dest - &(v->_stack._vals[v->_stackbase]);\r
164         assert(target>=0 && target<=255);\r
165         if(!v->EnterFrame(v->_top, v->_top + size, false)) \r
166                 return false;\r
167         v->ci->_generator   = this;\r
168         v->ci->_target      = (SQInt32)target;\r
169         v->ci->_closure     = _ci._closure;\r
170         v->ci->_ip          = _ci._ip;\r
171         v->ci->_literals    = _ci._literals;\r
172         v->ci->_ncalls      = _ci._ncalls;\r
173         v->ci->_etraps      = _ci._etraps;\r
174         v->ci->_root        = _ci._root;\r
175 \r
176 \r
177         for(SQInteger i=0;i<_ci._etraps;i++) {\r
178                 v->_etraps.push_back(_etraps.top());\r
179                 _etraps.pop_back();\r
180         }\r
181         SQObject _this = _stack._vals[0];\r
182         v->_stack[v->_stackbase] = type(_this) == OT_WEAKREF ? _weakref(_this)->_obj : _this;\r
183 \r
184         for(SQInteger n = 1; n<size; n++) {\r
185                 v->_stack[v->_stackbase+n] = _stack._vals[n];\r
186                 _stack._vals[n].Null();\r
187         }\r
188 \r
189         _state=eRunning;\r
190         if (v->_debughook)\r
191                 v->CallDebugHook(_SC('c'));\r
192 \r
193         return true;\r
194 }\r
195 \r
196 void SQArray::Extend(const SQArray *a){\r
197         SQInteger xlen;\r
198         if((xlen=a->Size()))\r
199                 for(SQInteger i=0;i<xlen;i++)\r
200                         Append(a->_values[i]);\r
201 }\r
202 \r
203 const SQChar* SQFunctionProto::GetLocal(SQVM *vm,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop)\r
204 {\r
205         SQUnsignedInteger nvars=_nlocalvarinfos;\r
206         const SQChar *res=NULL; \r
207         if(nvars>=nseq){\r
208                 for(SQUnsignedInteger i=0;i<nvars;i++){\r
209                         if(_localvarinfos[i]._start_op<=nop && _localvarinfos[i]._end_op>=nop)\r
210                         {\r
211                                 if(nseq==0){\r
212                                         vm->Push(vm->_stack[stackbase+_localvarinfos[i]._pos]);\r
213                                         res=_stringval(_localvarinfos[i]._name);\r
214                                         break;\r
215                                 }\r
216                                 nseq--;\r
217                         }\r
218                 }\r
219         }\r
220         return res;\r
221 }\r
222 \r
223 \r
224 SQInteger SQFunctionProto::GetLine(SQInstruction *curr)\r
225 {\r
226         SQInteger op = (SQInteger)(curr-_instructions);\r
227         SQInteger line=_lineinfos[0]._line;\r
228         SQInteger low = 0;\r
229         SQInteger high = _nlineinfos - 1;\r
230         SQInteger mid = 0;\r
231         while(low <= high)\r
232         {\r
233                 mid = low + ((high - low) >> 1);\r
234                 SQInteger curop = _lineinfos[mid]._op;\r
235                 if(curop > op)\r
236                 {\r
237                         high = mid - 1;\r
238                 }\r
239                 else if(curop < op) {\r
240                         if(mid < (_nlineinfos - 1) \r
241                                 && _lineinfos[mid + 1]._op >= op) {\r
242                                 break;\r
243                         }\r
244                         low = mid + 1;\r
245                 }\r
246                 else { //equal\r
247                         break;\r
248                 }\r
249         }\r
250 \r
251         line = _lineinfos[mid]._line;\r
252         return line;\r
253 }\r
254 \r
255 SQClosure::~SQClosure()\r
256 {\r
257         __ObjRelease(_env);\r
258         __ObjRelease(_base);\r
259         REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);\r
260 }\r
261 \r
262 #define _CHECK_IO(exp)  { if(!exp)return false; }\r
263 bool SafeWrite(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQUserPointer dest,SQInteger size)\r
264 {\r
265         if(write(up,dest,size) != size) {\r
266                 v->Raise_Error(_SC("io error (write function failure)"));\r
267                 return false;\r
268         }\r
269         return true;\r
270 }\r
271 \r
272 bool SafeRead(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,SQUserPointer dest,SQInteger size)\r
273 {\r
274         if(size && read(up,dest,size) != size) {\r
275                 v->Raise_Error(_SC("io error, read function failure, the origin stream could be corrupted/trucated"));\r
276                 return false;\r
277         }\r
278         return true;\r
279 }\r
280 \r
281 bool WriteTag(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQUnsignedInteger32 tag)\r
282 {\r
283         return SafeWrite(v,write,up,&tag,sizeof(tag));\r
284 }\r
285 \r
286 bool CheckTag(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,SQUnsignedInteger32 tag)\r
287 {\r
288         SQUnsignedInteger32 t;\r
289         _CHECK_IO(SafeRead(v,read,up,&t,sizeof(t)));\r
290         if(t != tag){\r
291                 v->Raise_Error(_SC("invalid or corrupted closure stream"));\r
292                 return false;\r
293         }\r
294         return true;\r
295 }\r
296 \r
297 bool WriteObject(HSQUIRRELVM v,SQUserPointer up,SQWRITEFUNC write,SQObjectPtr &o)\r
298 {\r
299         SQUnsignedInteger32 _type = (SQUnsignedInteger32)type(o);\r
300         _CHECK_IO(SafeWrite(v,write,up,&_type,sizeof(_type)));\r
301         switch(type(o)){\r
302         case OT_STRING:\r
303                 _CHECK_IO(SafeWrite(v,write,up,&_string(o)->_len,sizeof(SQInteger)));\r
304                 _CHECK_IO(SafeWrite(v,write,up,_stringval(o),rsl(_string(o)->_len)));\r
305                 break;\r
306         case OT_INTEGER:\r
307                 _CHECK_IO(SafeWrite(v,write,up,&_integer(o),sizeof(SQInteger)));break;\r
308         case OT_FLOAT:\r
309                 _CHECK_IO(SafeWrite(v,write,up,&_float(o),sizeof(SQFloat)));break;\r
310         case OT_NULL:\r
311                 break;\r
312         default:\r
313                 v->Raise_Error(_SC("cannot serialize a %s"),GetTypeName(o));\r
314                 return false;\r
315         }\r
316         return true;\r
317 }\r
318 \r
319 bool ReadObject(HSQUIRRELVM v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &o)\r
320 {\r
321         SQUnsignedInteger32 _type;\r
322         _CHECK_IO(SafeRead(v,read,up,&_type,sizeof(_type)));\r
323         SQObjectType t = (SQObjectType)_type;\r
324         switch(t){\r
325         case OT_STRING:{\r
326                 SQInteger len;\r
327                 _CHECK_IO(SafeRead(v,read,up,&len,sizeof(SQInteger)));\r
328                 _CHECK_IO(SafeRead(v,read,up,_ss(v)->GetScratchPad(rsl(len)),rsl(len)));\r
329                 o=SQString::Create(_ss(v),_ss(v)->GetScratchPad(-1),len);\r
330                                    }\r
331                 break;\r
332         case OT_INTEGER:{\r
333                 SQInteger i;\r
334                 _CHECK_IO(SafeRead(v,read,up,&i,sizeof(SQInteger))); o = i; break;\r
335                                         }\r
336         case OT_FLOAT:{\r
337                 SQFloat f;\r
338                 _CHECK_IO(SafeRead(v,read,up,&f,sizeof(SQFloat))); o = f; break;\r
339                                   }\r
340         case OT_NULL:\r
341                 o.Null();\r
342                 break;\r
343         default:\r
344                 v->Raise_Error(_SC("cannot serialize a %s"),IdType2Name(t));\r
345                 return false;\r
346         }\r
347         return true;\r
348 }\r
349 \r
350 bool SQClosure::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write)\r
351 {\r
352         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_HEAD));\r
353         _CHECK_IO(WriteTag(v,write,up,sizeof(SQChar)));\r
354         _CHECK_IO(WriteTag(v,write,up,sizeof(SQInteger)));\r
355         _CHECK_IO(WriteTag(v,write,up,sizeof(SQFloat)));\r
356         _CHECK_IO(_function->Save(v,up,write));\r
357         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_TAIL));\r
358         return true;\r
359 }\r
360 \r
361 bool SQClosure::Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret)\r
362 {\r
363         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_HEAD));\r
364         _CHECK_IO(CheckTag(v,read,up,sizeof(SQChar)));\r
365         _CHECK_IO(CheckTag(v,read,up,sizeof(SQInteger)));\r
366         _CHECK_IO(CheckTag(v,read,up,sizeof(SQFloat)));\r
367         SQObjectPtr func;\r
368         _CHECK_IO(SQFunctionProto::Load(v,up,read,func));\r
369         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_TAIL));\r
370         ret = SQClosure::Create(_ss(v),_funcproto(func));\r
371         return true;\r
372 }\r
373 \r
374 SQFunctionProto::SQFunctionProto(SQSharedState *ss)\r
375 {\r
376         _stacksize=0;\r
377         _bgenerator=false;\r
378         INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);\r
379 }\r
380 \r
381 SQFunctionProto::~SQFunctionProto()\r
382 {\r
383         REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);\r
384 }\r
385 \r
386 bool SQFunctionProto::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write)\r
387 {\r
388         SQInteger i,nliterals = _nliterals,nparameters = _nparameters;\r
389         SQInteger noutervalues = _noutervalues,nlocalvarinfos = _nlocalvarinfos;\r
390         SQInteger nlineinfos=_nlineinfos,ninstructions = _ninstructions,nfunctions=_nfunctions;\r
391         SQInteger ndefaultparams = _ndefaultparams;\r
392         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\r
393         _CHECK_IO(WriteObject(v,up,write,_sourcename));\r
394         _CHECK_IO(WriteObject(v,up,write,_name));\r
395         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\r
396         _CHECK_IO(SafeWrite(v,write,up,&nliterals,sizeof(nliterals)));\r
397         _CHECK_IO(SafeWrite(v,write,up,&nparameters,sizeof(nparameters)));\r
398         _CHECK_IO(SafeWrite(v,write,up,&noutervalues,sizeof(noutervalues)));\r
399         _CHECK_IO(SafeWrite(v,write,up,&nlocalvarinfos,sizeof(nlocalvarinfos)));\r
400         _CHECK_IO(SafeWrite(v,write,up,&nlineinfos,sizeof(nlineinfos)));\r
401         _CHECK_IO(SafeWrite(v,write,up,&ndefaultparams,sizeof(ndefaultparams)));\r
402         _CHECK_IO(SafeWrite(v,write,up,&ninstructions,sizeof(ninstructions)));\r
403         _CHECK_IO(SafeWrite(v,write,up,&nfunctions,sizeof(nfunctions)));\r
404         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\r
405         for(i=0;i<nliterals;i++){\r
406                 _CHECK_IO(WriteObject(v,up,write,_literals[i]));\r
407         }\r
408 \r
409         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\r
410         for(i=0;i<nparameters;i++){\r
411                 _CHECK_IO(WriteObject(v,up,write,_parameters[i]));\r
412         }\r
413 \r
414         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\r
415         for(i=0;i<noutervalues;i++){\r
416                 _CHECK_IO(SafeWrite(v,write,up,&_outervalues[i]._type,sizeof(SQUnsignedInteger)));\r
417                 _CHECK_IO(WriteObject(v,up,write,_outervalues[i]._src));\r
418                 _CHECK_IO(WriteObject(v,up,write,_outervalues[i]._name));\r
419         }\r
420 \r
421         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\r
422         for(i=0;i<nlocalvarinfos;i++){\r
423                 SQLocalVarInfo &lvi=_localvarinfos[i];\r
424                 _CHECK_IO(WriteObject(v,up,write,lvi._name));\r
425                 _CHECK_IO(SafeWrite(v,write,up,&lvi._pos,sizeof(SQUnsignedInteger)));\r
426                 _CHECK_IO(SafeWrite(v,write,up,&lvi._start_op,sizeof(SQUnsignedInteger)));\r
427                 _CHECK_IO(SafeWrite(v,write,up,&lvi._end_op,sizeof(SQUnsignedInteger)));\r
428         }\r
429 \r
430         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\r
431         _CHECK_IO(SafeWrite(v,write,up,_lineinfos,sizeof(SQLineInfo)*nlineinfos));\r
432 \r
433         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\r
434         _CHECK_IO(SafeWrite(v,write,up,_defaultparams,sizeof(SQInteger)*ndefaultparams));\r
435 \r
436         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\r
437         _CHECK_IO(SafeWrite(v,write,up,_instructions,sizeof(SQInstruction)*ninstructions));\r
438 \r
439         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\r
440         for(i=0;i<nfunctions;i++){\r
441                 _CHECK_IO(_funcproto(_functions[i])->Save(v,up,write));\r
442         }\r
443         _CHECK_IO(SafeWrite(v,write,up,&_stacksize,sizeof(_stacksize)));\r
444         _CHECK_IO(SafeWrite(v,write,up,&_bgenerator,sizeof(_bgenerator)));\r
445         _CHECK_IO(SafeWrite(v,write,up,&_varparams,sizeof(_varparams)));\r
446         return true;\r
447 }\r
448 \r
449 bool SQFunctionProto::Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret)\r
450 {\r
451         SQInteger i, nliterals,nparameters;\r
452         SQInteger noutervalues ,nlocalvarinfos ;\r
453         SQInteger nlineinfos,ninstructions ,nfunctions,ndefaultparams ;\r
454         SQObjectPtr sourcename, name;\r
455         SQObjectPtr o;\r
456         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\r
457         _CHECK_IO(ReadObject(v, up, read, sourcename));\r
458         _CHECK_IO(ReadObject(v, up, read, name));\r
459         \r
460         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\r
461         _CHECK_IO(SafeRead(v,read,up, &nliterals, sizeof(nliterals)));\r
462         _CHECK_IO(SafeRead(v,read,up, &nparameters, sizeof(nparameters)));\r
463         _CHECK_IO(SafeRead(v,read,up, &noutervalues, sizeof(noutervalues)));\r
464         _CHECK_IO(SafeRead(v,read,up, &nlocalvarinfos, sizeof(nlocalvarinfos)));\r
465         _CHECK_IO(SafeRead(v,read,up, &nlineinfos, sizeof(nlineinfos)));\r
466         _CHECK_IO(SafeRead(v,read,up, &ndefaultparams, sizeof(ndefaultparams)));\r
467         _CHECK_IO(SafeRead(v,read,up, &ninstructions, sizeof(ninstructions)));\r
468         _CHECK_IO(SafeRead(v,read,up, &nfunctions, sizeof(nfunctions)));\r
469         \r
470 \r
471         SQFunctionProto *f = SQFunctionProto::Create(_opt_ss(v),ninstructions,nliterals,nparameters,\r
472                         nfunctions,noutervalues,nlineinfos,nlocalvarinfos,ndefaultparams);\r
473         SQObjectPtr proto = f; //gets a ref in case of failure\r
474         f->_sourcename = sourcename;\r
475         f->_name = name;\r
476 \r
477         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\r
478 \r
479         for(i = 0;i < nliterals; i++){\r
480                 _CHECK_IO(ReadObject(v, up, read, o));\r
481                 f->_literals[i] = o;\r
482         }\r
483         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\r
484 \r
485         for(i = 0; i < nparameters; i++){\r
486                 _CHECK_IO(ReadObject(v, up, read, o));\r
487                 f->_parameters[i] = o;\r
488         }\r
489         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\r
490 \r
491         for(i = 0; i < noutervalues; i++){\r
492                 SQUnsignedInteger type;\r
493                 SQObjectPtr name;\r
494                 _CHECK_IO(SafeRead(v,read,up, &type, sizeof(SQUnsignedInteger)));\r
495                 _CHECK_IO(ReadObject(v, up, read, o));\r
496                 _CHECK_IO(ReadObject(v, up, read, name));\r
497                 f->_outervalues[i] = SQOuterVar(name,o, (SQOuterType)type);\r
498         }\r
499         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\r
500 \r
501         for(i = 0; i < nlocalvarinfos; i++){\r
502                 SQLocalVarInfo lvi;\r
503                 _CHECK_IO(ReadObject(v, up, read, lvi._name));\r
504                 _CHECK_IO(SafeRead(v,read,up, &lvi._pos, sizeof(SQUnsignedInteger)));\r
505                 _CHECK_IO(SafeRead(v,read,up, &lvi._start_op, sizeof(SQUnsignedInteger)));\r
506                 _CHECK_IO(SafeRead(v,read,up, &lvi._end_op, sizeof(SQUnsignedInteger)));\r
507                 f->_localvarinfos[i] = lvi;\r
508         }\r
509         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\r
510         _CHECK_IO(SafeRead(v,read,up, f->_lineinfos, sizeof(SQLineInfo)*nlineinfos));\r
511 \r
512         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\r
513         _CHECK_IO(SafeRead(v,read,up, f->_defaultparams, sizeof(SQInteger)*ndefaultparams));\r
514 \r
515         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\r
516         _CHECK_IO(SafeRead(v,read,up, f->_instructions, sizeof(SQInstruction)*ninstructions));\r
517 \r
518         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\r
519         for(i = 0; i < nfunctions; i++){\r
520                 _CHECK_IO(_funcproto(o)->Load(v, up, read, o));\r
521                 f->_functions[i] = o;\r
522         }\r
523         _CHECK_IO(SafeRead(v,read,up, &f->_stacksize, sizeof(f->_stacksize)));\r
524         _CHECK_IO(SafeRead(v,read,up, &f->_bgenerator, sizeof(f->_bgenerator)));\r
525         _CHECK_IO(SafeRead(v,read,up, &f->_varparams, sizeof(f->_varparams)));\r
526         \r
527         ret = f;\r
528         return true;\r
529 }\r
530 \r
531 #ifndef NO_GARBAGE_COLLECTOR\r
532 \r
533 #define START_MARK()    if(!(_uiRef&MARK_FLAG)){ \\r
534                 _uiRef|=MARK_FLAG;\r
535 \r
536 #define END_MARK() RemoveFromChain(&_sharedstate->_gc_chain, this); \\r
537                 AddToChain(chain, this); }\r
538 \r
539 void SQVM::Mark(SQCollectable **chain)\r
540 {\r
541         START_MARK()\r
542                 SQSharedState::MarkObject(_lasterror,chain);\r
543                 SQSharedState::MarkObject(_errorhandler,chain);\r
544                 SQSharedState::MarkObject(_debughook_closure,chain);\r
545                 SQSharedState::MarkObject(_roottable, chain);\r
546                 SQSharedState::MarkObject(temp_reg, chain);\r
547                 for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain);\r
548                 for(SQInteger k = 0; k < _callsstacksize; k++) SQSharedState::MarkObject(_callsstack[k]._closure, chain);\r
549         END_MARK()\r
550 }\r
551 \r
552 void SQArray::Mark(SQCollectable **chain)\r
553 {\r
554         START_MARK()\r
555                 SQInteger len = _values.size();\r
556                 for(SQInteger i = 0;i < len; i++) SQSharedState::MarkObject(_values[i], chain);\r
557         END_MARK()\r
558 }\r
559 void SQTable::Mark(SQCollectable **chain)\r
560 {\r
561         START_MARK()\r
562                 if(_delegate) _delegate->Mark(chain);\r
563                 SQInteger len = _numofnodes;\r
564                 for(SQInteger i = 0; i < len; i++){\r
565                         SQSharedState::MarkObject(_nodes[i].key, chain);\r
566                         SQSharedState::MarkObject(_nodes[i].val, chain);\r
567                 }\r
568         END_MARK()\r
569 }\r
570 \r
571 void SQClass::Mark(SQCollectable **chain)\r
572 {\r
573         START_MARK()\r
574                 _members->Mark(chain);\r
575                 if(_base) _base->Mark(chain);\r
576                 SQSharedState::MarkObject(_attributes, chain);\r
577                 for(SQUnsignedInteger i =0; i< _defaultvalues.size(); i++) {\r
578                         SQSharedState::MarkObject(_defaultvalues[i].val, chain);\r
579                         SQSharedState::MarkObject(_defaultvalues[i].attrs, chain);\r
580                 }\r
581                 for(SQUnsignedInteger j =0; j< _methods.size(); j++) {\r
582                         SQSharedState::MarkObject(_methods[j].val, chain);\r
583                         SQSharedState::MarkObject(_methods[j].attrs, chain);\r
584                 }\r
585                 for(SQUnsignedInteger k =0; k< MT_LAST; k++) {\r
586                         SQSharedState::MarkObject(_metamethods[k], chain);\r
587                 }\r
588         END_MARK()\r
589 }\r
590 \r
591 void SQInstance::Mark(SQCollectable **chain)\r
592 {\r
593         START_MARK()\r
594                 _class->Mark(chain);\r
595                 SQUnsignedInteger nvalues = _class->_defaultvalues.size();\r
596                 for(SQUnsignedInteger i =0; i< nvalues; i++) {\r
597                         SQSharedState::MarkObject(_values[i], chain);\r
598                 }\r
599         END_MARK()\r
600 }\r
601 \r
602 void SQGenerator::Mark(SQCollectable **chain)\r
603 {\r
604         START_MARK()\r
605                 for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain);\r
606                 SQSharedState::MarkObject(_closure, chain);\r
607         END_MARK()\r
608 }\r
609 \r
610 void SQFunctionProto::Mark(SQCollectable **chain)\r
611 {\r
612         START_MARK()\r
613                 for(SQInteger i = 0; i < _nliterals; i++) SQSharedState::MarkObject(_literals[i], chain);\r
614                 for(SQInteger k = 0; k < _nfunctions; k++) SQSharedState::MarkObject(_functions[k], chain);\r
615         END_MARK()\r
616 }\r
617 \r
618 void SQClosure::Mark(SQCollectable **chain)\r
619 {\r
620         START_MARK()\r
621                 if(_base) _base->Mark(chain);\r
622                 SQFunctionProto *fp = _function;\r
623                 fp->Mark(chain);\r
624                 for(SQInteger i = 0; i < fp->_noutervalues; i++) SQSharedState::MarkObject(_outervalues[i], chain);\r
625                 for(SQInteger k = 0; k < fp->_ndefaultparams; k++) SQSharedState::MarkObject(_defaultparams[k], chain);\r
626         END_MARK()\r
627 }\r
628 \r
629 void SQNativeClosure::Mark(SQCollectable **chain)\r
630 {\r
631         START_MARK()\r
632                 for(SQUnsignedInteger i = 0; i < _noutervalues; i++) SQSharedState::MarkObject(_outervalues[i], chain);\r
633         END_MARK()\r
634 }\r
635 \r
636 void SQOuter::Mark(SQCollectable **chain)\r
637 {\r
638         START_MARK()\r
639     /* If the valptr points to a closed value, that value is alive */\r
640     if(_valptr == &_value) {\r
641       SQSharedState::MarkObject(_value, chain);\r
642     }\r
643         END_MARK()\r
644 }\r
645 \r
646 void SQUserData::Mark(SQCollectable **chain){\r
647         START_MARK()\r
648                 if(_delegate) _delegate->Mark(chain);\r
649         END_MARK()\r
650 }\r
651 \r
652 void SQCollectable::UnMark() { _uiRef&=~MARK_FLAG; }\r
653 \r
654 #endif\r
655 \r