Updated addon repository URL and improved debug output on download
[supertux.git] / external / squirrel / squirrel / sqvm.cpp
1 /*\r
2         see copyright notice in squirrel.h\r
3 */\r
4 #include "sqpcheader.h"\r
5 #include <math.h>\r
6 #include <stdlib.h>\r
7 #include "sqopcodes.h"\r
8 #include "sqvm.h"\r
9 #include "sqfuncproto.h"\r
10 #include "sqclosure.h"\r
11 #include "sqstring.h"\r
12 #include "sqtable.h"\r
13 #include "squserdata.h"\r
14 #include "sqarray.h"\r
15 #include "sqclass.h"\r
16 \r
17 #define TOP() (_stack._vals[_top-1])\r
18 \r
19 bool SQVM::BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2)\r
20 {\r
21         SQInteger res;\r
22         if((type(o1)|type(o2)) == OT_INTEGER)\r
23         {\r
24                 SQInteger i1 = _integer(o1), i2 = _integer(o2);\r
25                 switch(op) {\r
26                         case BW_AND:    res = i1 & i2; break;\r
27                         case BW_OR:             res = i1 | i2; break;\r
28                         case BW_XOR:    res = i1 ^ i2; break;\r
29                         case BW_SHIFTL: res = i1 << i2; break;\r
30                         case BW_SHIFTR: res = i1 >> i2; break;\r
31                         case BW_USHIFTR:res = (SQInteger)(*((SQUnsignedInteger*)&i1) >> i2); break;\r
32                         default: { Raise_Error(_SC("internal vm error bitwise op failed")); return false; }\r
33                 }\r
34         } \r
35         else { Raise_Error(_SC("bitwise op between '%s' and '%s'"),GetTypeName(o1),GetTypeName(o2)); return false;}\r
36         trg = res;\r
37         return true;\r
38 }\r
39 \r
40 #define _ARITH_(op,trg,o1,o2) \\r
41 { \\r
42         SQInteger tmask = type(o1)|type(o2); \\r
43         switch(tmask) { \\r
44                 case OT_INTEGER: trg = _integer(o1) op _integer(o2);break; \\r
45                 case (OT_FLOAT|OT_INTEGER): \\r
46                 case (OT_FLOAT): trg = tofloat(o1) op tofloat(o2); break;\\r
47                 default: _GUARD(ARITH_OP((#op)[0],trg,o1,o2)); break;\\r
48         } \\r
49 }\r
50 \r
51 #define _ARITH_NOZERO(op,trg,o1,o2,err) \\r
52 { \\r
53         SQInteger tmask = type(o1)|type(o2); \\r
54         switch(tmask) { \\r
55                 case OT_INTEGER: { SQInteger i2 = _integer(o2); if(i2 == 0) { Raise_Error(err); SQ_THROW(); } trg = _integer(o1) op i2; } break;\\r
56                 case (OT_FLOAT|OT_INTEGER): \\r
57                 case (OT_FLOAT): trg = tofloat(o1) op tofloat(o2); break;\\r
58                 default: _GUARD(ARITH_OP((#op)[0],trg,o1,o2)); break;\\r
59         } \\r
60 }\r
61 \r
62 bool SQVM::ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2)\r
63 {\r
64         SQInteger tmask = type(o1)|type(o2);\r
65         switch(tmask) {\r
66                 case OT_INTEGER:{\r
67                         SQInteger res, i1 = _integer(o1), i2 = _integer(o2);\r
68                         switch(op) {\r
69                         case '+': res = i1 + i2; break;\r
70                         case '-': res = i1 - i2; break;\r
71                         case '/': if(i2 == 0) { Raise_Error(_SC("division by zero")); return false; }\r
72                                         res = i1 / i2; \r
73                                         break;\r
74                         case '*': res = i1 * i2; break;\r
75                         case '%': if(i2 == 0) { Raise_Error(_SC("modulo by zero")); return false; }\r
76                                         res = i1 % i2; \r
77                                         break;\r
78                         default: res = 0xDEADBEEF;\r
79                         }\r
80                         trg = res; }\r
81                         break;\r
82                 case (OT_FLOAT|OT_INTEGER):\r
83                 case (OT_FLOAT):{\r
84                         SQFloat res, f1 = tofloat(o1), f2 = tofloat(o2);\r
85                         switch(op) {\r
86                         case '+': res = f1 + f2; break;\r
87                         case '-': res = f1 - f2; break;\r
88                         case '/': res = f1 / f2; break;\r
89                         case '*': res = f1 * f2; break;\r
90                         case '%': res = SQFloat(fmod((double)f1,(double)f2)); break;\r
91                         default: res = 0x0f;\r
92                         }\r
93                         trg = res; }\r
94                         break;\r
95                 default:\r
96                         if(op == '+' && (tmask & _RT_STRING)){\r
97                                 if(!StringCat(o1, o2, trg)) return false;\r
98                         }\r
99                         else if(!ArithMetaMethod(op,o1,o2,trg)) { \r
100                                 return false; \r
101                         }\r
102         }\r
103         return true;\r
104 }\r
105 \r
106 SQVM::SQVM(SQSharedState *ss)\r
107 {\r
108         _sharedstate=ss;\r
109         _suspended = SQFalse;\r
110         _suspended_target = -1;\r
111         _suspended_root = SQFalse;\r
112         _suspended_traps = -1;\r
113         _foreignptr = NULL;\r
114         _nnativecalls = 0;\r
115         _nmetamethodscall = 0;\r
116         _lasterror.Null();\r
117         _errorhandler.Null();\r
118         _debughook = false;\r
119         _debughook_native = NULL;\r
120         _debughook_closure.Null();\r
121         _openouters = NULL;\r
122         ci = NULL;\r
123         INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);\r
124 }\r
125 \r
126 void SQVM::Finalize()\r
127 {\r
128         if(_openouters) CloseOuters(&_stack._vals[0]);\r
129         _roottable.Null();\r
130         _lasterror.Null();\r
131         _errorhandler.Null();\r
132         _debughook = false;\r
133         _debughook_native = NULL;\r
134         _debughook_closure.Null();\r
135         temp_reg.Null();\r
136         _callstackdata.resize(0);\r
137         SQInteger size=_stack.size();\r
138         for(SQInteger i=0;i<size;i++)\r
139                 _stack[i].Null();\r
140 }\r
141 \r
142 SQVM::~SQVM()\r
143 {\r
144         Finalize();\r
145         REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);\r
146 }\r
147 \r
148 bool SQVM::ArithMetaMethod(SQInteger op,const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &dest)\r
149 {\r
150         SQMetaMethod mm;\r
151         switch(op){\r
152                 case _SC('+'): mm=MT_ADD; break;\r
153                 case _SC('-'): mm=MT_SUB; break;\r
154                 case _SC('/'): mm=MT_DIV; break;\r
155                 case _SC('*'): mm=MT_MUL; break;\r
156                 case _SC('%'): mm=MT_MODULO; break;\r
157                 default: mm = MT_ADD; assert(0); break; //shutup compiler\r
158         }\r
159         if(is_delegable(o1) && _delegable(o1)->_delegate) {\r
160                 \r
161                 SQObjectPtr closure;\r
162                 if(_delegable(o1)->GetMetaMethod(this, mm, closure)) {\r
163                         Push(o1);Push(o2);\r
164                         return CallMetaMethod(closure,mm,2,dest);\r
165                 }\r
166         }\r
167         Raise_Error(_SC("arith op %c on between '%s' and '%s'"),op,GetTypeName(o1),GetTypeName(o2)); \r
168         return false;\r
169 }\r
170 \r
171 bool SQVM::NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o)\r
172 {\r
173         \r
174         switch(type(o)) {\r
175         case OT_INTEGER:\r
176                 trg = -_integer(o);\r
177                 return true;\r
178         case OT_FLOAT:\r
179                 trg = -_float(o);\r
180                 return true;\r
181         case OT_TABLE:\r
182         case OT_USERDATA:\r
183         case OT_INSTANCE:\r
184                 if(_delegable(o)->_delegate) {\r
185                         SQObjectPtr closure;\r
186                         if(_delegable(o)->GetMetaMethod(this, MT_UNM, closure)) {\r
187                                 Push(o);\r
188                                 if(!CallMetaMethod(closure, MT_UNM, 1, temp_reg)) return false;\r
189                                 _Swap(trg,temp_reg);\r
190                                 return true;\r
191 \r
192                         }\r
193                 }\r
194         default:break; //shutup compiler\r
195         }\r
196         Raise_Error(_SC("attempt to negate a %s"), GetTypeName(o));\r
197         return false;\r
198 }\r
199 \r
200 #define _RET_SUCCEED(exp) { result = (exp); return true; } \r
201 bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result)\r
202 {\r
203         SQObjectType t1 = type(o1), t2 = type(o2);\r
204         if(t1 == t2) {\r
205                 if(_rawval(o1) == _rawval(o2))_RET_SUCCEED(0);\r
206                 SQObjectPtr res;\r
207                 switch(t1){\r
208                 case OT_STRING:\r
209                         _RET_SUCCEED(scstrcmp(_stringval(o1),_stringval(o2)));\r
210                 case OT_INTEGER:\r
211                         _RET_SUCCEED((_integer(o1)<_integer(o2))?-1:1);\r
212                 case OT_FLOAT:\r
213                         _RET_SUCCEED((_float(o1)<_float(o2))?-1:1);\r
214                 case OT_TABLE:\r
215                 case OT_USERDATA:\r
216                 case OT_INSTANCE:\r
217                         if(_delegable(o1)->_delegate) {\r
218                                 SQObjectPtr closure;\r
219                                 if(_delegable(o1)->GetMetaMethod(this, MT_CMP, closure)) {\r
220                                         Push(o1);Push(o2);\r
221                                         if(CallMetaMethod(closure,MT_CMP,2,res)) {\r
222                                                 if(type(res) != OT_INTEGER) {\r
223                                                         Raise_Error(_SC("_cmp must return an integer"));\r
224                                                         return false;\r
225                                                 }\r
226                                                 _RET_SUCCEED(_integer(res))\r
227                                         }\r
228                                         return false;\r
229                                 }\r
230                         }\r
231                         //continues through (no break needed)\r
232                 default: \r
233                         _RET_SUCCEED( _userpointer(o1) < _userpointer(o2)?-1:1 );\r
234                 }\r
235                 assert(0);\r
236                 //if(type(res)!=OT_INTEGER) { Raise_CompareError(o1,o2); return false; }\r
237                 //      _RET_SUCCEED(_integer(res));\r
238                 \r
239         }\r
240         else{\r
241                 if(sq_isnumeric(o1) && sq_isnumeric(o2)){\r
242                         if((t1==OT_INTEGER) && (t2==OT_FLOAT)) { \r
243                                 if( _integer(o1)==_float(o2) ) { _RET_SUCCEED(0); }\r
244                                 else if( _integer(o1)<_float(o2) ) { _RET_SUCCEED(-1); }\r
245                                 _RET_SUCCEED(1);\r
246                         }\r
247                         else{\r
248                                 if( _float(o1)==_integer(o2) ) { _RET_SUCCEED(0); }\r
249                                 else if( _float(o1)<_integer(o2) ) { _RET_SUCCEED(-1); }\r
250                                 _RET_SUCCEED(1);\r
251                         }\r
252                 }\r
253                 else if(t1==OT_NULL) {_RET_SUCCEED(-1);}\r
254                 else if(t2==OT_NULL) {_RET_SUCCEED(1);}\r
255                 else { Raise_CompareError(o1,o2); return false; }\r
256                 \r
257         }\r
258         assert(0);\r
259         _RET_SUCCEED(0); //cannot happen\r
260 }\r
261 \r
262 bool SQVM::CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res)\r
263 {\r
264         SQInteger r;\r
265         if(ObjCmp(o1,o2,r)) {\r
266                 switch(op) {\r
267                         case CMP_G: res = (r > 0); return true;\r
268                         case CMP_GE: res = (r >= 0); return true;\r
269                         case CMP_L: res = (r < 0); return true;\r
270                         case CMP_LE: res = (r <= 0); return true;\r
271                         case CMP_3W: res = r; return true;\r
272                 }\r
273                 assert(0);\r
274         }\r
275         return false;\r
276 }\r
277 \r
278 bool SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res)\r
279 {\r
280         switch(type(o)) {\r
281         case OT_STRING:\r
282                 res = o;\r
283                 return true;\r
284         case OT_FLOAT:\r
285                 scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)),_SC("%g"),_float(o));\r
286                 break;\r
287         case OT_INTEGER:\r
288                 scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)),_PRINT_INT_FMT,_integer(o));\r
289                 break;\r
290         case OT_BOOL:\r
291                 scsprintf(_sp(rsl(6)),_integer(o)?_SC("true"):_SC("false"));\r
292                 break;\r
293         case OT_TABLE:\r
294         case OT_USERDATA:\r
295         case OT_INSTANCE:\r
296                 if(_delegable(o)->_delegate) {\r
297                         SQObjectPtr closure;\r
298                         if(_delegable(o)->GetMetaMethod(this, MT_TOSTRING, closure)) {\r
299                                 Push(o);\r
300                                 if(CallMetaMethod(closure,MT_TOSTRING,1,res)) {;\r
301                                         if(type(res) == OT_STRING)\r
302                                                 return true;\r
303                                 } \r
304                                 else {\r
305                                         return false;\r
306                                 }\r
307                         }\r
308                 }\r
309         default:\r
310                 scsprintf(_sp(rsl(sizeof(void*)+20)),_SC("(%s : 0x%p)"),GetTypeName(o),(void*)_rawval(o));\r
311         }\r
312         res = SQString::Create(_ss(this),_spval);\r
313         return true;\r
314 }\r
315 \r
316 \r
317 bool SQVM::StringCat(const SQObjectPtr &str,const SQObjectPtr &obj,SQObjectPtr &dest)\r
318 {\r
319         SQObjectPtr a, b;\r
320         if(!ToString(str, a)) return false;\r
321         if(!ToString(obj, b)) return false;\r
322         SQInteger l = _string(a)->_len , ol = _string(b)->_len;\r
323         SQChar *s = _sp(rsl(l + ol + 1));\r
324         memcpy(s, _stringval(a), rsl(l)); \r
325         memcpy(s + l, _stringval(b), rsl(ol));\r
326         dest = SQString::Create(_ss(this), _spval, l + ol);\r
327         return true;\r
328 }\r
329 \r
330 bool SQVM::TypeOf(const SQObjectPtr &obj1,SQObjectPtr &dest)\r
331 {\r
332         if(is_delegable(obj1) && _delegable(obj1)->_delegate) {\r
333                 SQObjectPtr closure;\r
334                 if(_delegable(obj1)->GetMetaMethod(this, MT_TYPEOF, closure)) {\r
335                         Push(obj1);\r
336                         return CallMetaMethod(closure,MT_TYPEOF,1,dest);\r
337                 }\r
338         }\r
339         dest = SQString::Create(_ss(this),GetTypeName(obj1));\r
340         return true;\r
341 }\r
342 \r
343 bool SQVM::Init(SQVM *friendvm, SQInteger stacksize)\r
344 {\r
345         _stack.resize(stacksize);\r
346         _alloccallsstacksize = 4;\r
347         _callstackdata.resize(_alloccallsstacksize);\r
348         _callsstacksize = 0;\r
349         _callsstack = &_callstackdata[0];\r
350         _stackbase = 0;\r
351         _top = 0;\r
352         if(!friendvm) {\r
353                 _roottable = SQTable::Create(_ss(this), 0);\r
354                 sq_base_register(this);\r
355         }\r
356         else {\r
357                 _roottable = friendvm->_roottable;\r
358                 _errorhandler = friendvm->_errorhandler;\r
359                 _debughook = friendvm->_debughook;\r
360                 _debughook_native = friendvm->_debughook_native;\r
361                 _debughook_closure = friendvm->_debughook_closure;\r
362         }\r
363         return true;\r
364 }\r
365 \r
366 \r
367 bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger args,SQInteger stackbase,bool tailcall)\r
368 {\r
369         SQFunctionProto *func = closure->_function;\r
370 \r
371         SQInteger paramssize = func->_nparameters;\r
372         const SQInteger newtop = stackbase + func->_stacksize;\r
373         SQInteger nargs = args;\r
374         if(func->_varparams)\r
375         {\r
376                 paramssize--;\r
377                 if (nargs < paramssize) {\r
378                         Raise_Error(_SC("wrong number of parameters"));\r
379                         return false;\r
380                 }\r
381 \r
382                 //dumpstack(stackbase);\r
383                 SQInteger nvargs = nargs - paramssize;\r
384                 SQArray *arr = SQArray::Create(_ss(this),nvargs);\r
385                 SQInteger pbase = stackbase+paramssize;\r
386                 for(SQInteger n = 0; n < nvargs; n++) {\r
387                         arr->_values[n] = _stack._vals[pbase];\r
388                         _stack._vals[pbase].Null();\r
389                         pbase++;\r
390 \r
391                 }\r
392                 _stack._vals[stackbase+paramssize] = arr;\r
393                 //dumpstack(stackbase);\r
394         }\r
395         else if (paramssize != nargs) {\r
396                 SQInteger ndef = func->_ndefaultparams;\r
397                 SQInteger diff;\r
398                 if(ndef && nargs < paramssize && (diff = paramssize - nargs) <= ndef) {\r
399                         for(SQInteger n = ndef - diff; n < ndef; n++) {\r
400                                 _stack._vals[stackbase + (nargs++)] = closure->_defaultparams[n];\r
401                         }\r
402                 }\r
403                 else {\r
404                         Raise_Error(_SC("wrong number of parameters"));\r
405                         return false;\r
406                 }\r
407         }\r
408 \r
409         if(closure->_env) {\r
410                 _stack._vals[stackbase] = closure->_env->_obj;\r
411         }\r
412 \r
413         if(!EnterFrame(stackbase, newtop, tailcall)) return false;\r
414 \r
415         ci->_closure  = closure;\r
416         ci->_literals = func->_literals;\r
417         ci->_ip       = func->_instructions;\r
418         ci->_target   = (SQInt32)target;\r
419 \r
420         if (_debughook) {\r
421                 CallDebugHook(_SC('c'));\r
422         }\r
423 \r
424         if (closure->_function->_bgenerator) {\r
425                 SQFunctionProto *f = closure->_function;\r
426                 SQGenerator *gen = SQGenerator::Create(_ss(this), closure);\r
427                 if(!gen->Yield(this,f->_stacksize))\r
428                         return false;\r
429                 SQObjectPtr temp;\r
430                 Return(1, target, temp);\r
431                 STK(target) = gen;\r
432         }\r
433 \r
434 \r
435         return true;\r
436 }\r
437 \r
438 bool SQVM::Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval)\r
439 {\r
440         SQBool    _isroot      = ci->_root;\r
441         SQInteger callerbase   = _stackbase - ci->_prevstkbase;\r
442 \r
443         if (_debughook) {\r
444                 for(SQInteger i=0; i<ci->_ncalls; i++) {\r
445                         CallDebugHook(_SC('r'));\r
446                 }\r
447         }\r
448 \r
449         SQObjectPtr *dest;\r
450         if (_isroot) {\r
451                 dest = &(retval);\r
452         } else if (ci->_target == -1) {\r
453                 dest = NULL;\r
454         } else {\r
455                 dest = &_stack._vals[callerbase + ci->_target];\r
456         }\r
457         if (dest) {\r
458                 if(_arg0 != 0xFF) {\r
459                         *dest = _stack._vals[_stackbase+_arg1];\r
460                 }\r
461                 else {\r
462                         dest->Null();\r
463                 }\r
464                 //*dest = (_arg0 != 0xFF) ? _stack._vals[_stackbase+_arg1] : _null_;\r
465         }\r
466         LeaveFrame();\r
467         return _isroot ? true : false;\r
468 }\r
469 \r
470 #define _RET_ON_FAIL(exp) { if(!exp) return false; }\r
471 \r
472 bool SQVM::PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr)\r
473 {\r
474         SQObjectPtr trg;\r
475         _RET_ON_FAIL(ARITH_OP( op , trg, a, incr));\r
476         target = a;\r
477         a = trg;\r
478         return true;\r
479 }\r
480 \r
481 bool SQVM::DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix,SQInteger selfidx)\r
482 {\r
483         SQObjectPtr tmp, tself = self, tkey = key;\r
484         if (!Get(tself, tkey, tmp, false, selfidx)) { return false; }\r
485         _RET_ON_FAIL(ARITH_OP( op , target, tmp, incr))\r
486         if (!Set(tself, tkey, target,selfidx)) { return false; }\r
487         if (postfix) target = tmp;\r
488         return true;\r
489 }\r
490 \r
491 #define arg0 (_i_._arg0)\r
492 #define sarg0 ((SQInteger)*((signed char *)&_i_._arg0))\r
493 #define arg1 (_i_._arg1)\r
494 #define sarg1 (*((SQInt32 *)&_i_._arg1))\r
495 #define arg2 (_i_._arg2)\r
496 #define arg3 (_i_._arg3)\r
497 #define sarg3 ((SQInteger)*((signed char *)&_i_._arg3))\r
498 \r
499 SQRESULT SQVM::Suspend()\r
500 {\r
501         if (_suspended)\r
502                 return sq_throwerror(this, _SC("cannot suspend an already suspended vm"));\r
503         if (_nnativecalls!=2)\r
504                 return sq_throwerror(this, _SC("cannot suspend through native calls/metamethods"));\r
505         return SQ_SUSPEND_FLAG;\r
506 }\r
507 \r
508 \r
509 #define _FINISH(howmuchtojump) {jump = howmuchtojump; return true; }\r
510 bool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr \r
511 &o3,SQObjectPtr &o4,SQInteger arg_2,int exitpos,int &jump)\r
512 {\r
513         SQInteger nrefidx;\r
514         switch(type(o1)) {\r
515         case OT_TABLE:\r
516                 if((nrefidx = _table(o1)->Next(false,o4, o2, o3)) == -1) _FINISH(exitpos);\r
517                 o4 = (SQInteger)nrefidx; _FINISH(1);\r
518         case OT_ARRAY:\r
519                 if((nrefidx = _array(o1)->Next(o4, o2, o3)) == -1) _FINISH(exitpos);\r
520                 o4 = (SQInteger) nrefidx; _FINISH(1);\r
521         case OT_STRING:\r
522                 if((nrefidx = _string(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos);\r
523                 o4 = (SQInteger)nrefidx; _FINISH(1);\r
524         case OT_CLASS:\r
525                 if((nrefidx = _class(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos);\r
526                 o4 = (SQInteger)nrefidx; _FINISH(1);\r
527         case OT_USERDATA:\r
528         case OT_INSTANCE:\r
529                 if(_delegable(o1)->_delegate) {\r
530                         SQObjectPtr itr;\r
531                         SQObjectPtr closure;\r
532                         if(_delegable(o1)->GetMetaMethod(this, MT_NEXTI, closure)) {\r
533                                 Push(o1);\r
534                                 Push(o4);\r
535                                 if(CallMetaMethod(closure, MT_NEXTI, 2, itr)) {\r
536                                         o4 = o2 = itr;\r
537                                         if(type(itr) == OT_NULL) _FINISH(exitpos);\r
538                                         if(!Get(o1, itr, o3, false, DONT_FALL_BACK)) {\r
539                                                 Raise_Error(_SC("_nexti returned an invalid idx")); // cloud be changed\r
540                                                 return false;\r
541                                         }\r
542                                         _FINISH(1);\r
543                                 }\r
544                                 else {\r
545                                         return false;\r
546                                 }\r
547                         }\r
548                         Raise_Error(_SC("_nexti failed"));\r
549                         return false;\r
550                 }\r
551                 break;\r
552         case OT_GENERATOR:\r
553                 if(_generator(o1)->_state == SQGenerator::eDead) _FINISH(exitpos);\r
554                 if(_generator(o1)->_state == SQGenerator::eSuspended) {\r
555                         SQInteger idx = 0;\r
556                         if(type(o4) == OT_INTEGER) {\r
557                                 idx = _integer(o4) + 1;\r
558                         }\r
559                         o2 = idx;\r
560                         o4 = idx;\r
561                         _generator(o1)->Resume(this, o3);\r
562                         _FINISH(0);\r
563                 }\r
564         default: \r
565                 Raise_Error(_SC("cannot iterate %s"), GetTypeName(o1));\r
566         }\r
567         return false; //cannot be hit(just to avoid warnings)\r
568 }\r
569 \r
570 #define COND_LITERAL (arg3!=0?ci->_literals[arg1]:STK(arg1))\r
571 \r
572 #define SQ_THROW() { goto exception_trap; }\r
573 \r
574 #define _GUARD(exp) { if(!exp) { SQ_THROW();} }\r
575 \r
576 bool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func)\r
577 {\r
578         SQInteger nouters;\r
579         SQClosure *closure = SQClosure::Create(_ss(this), func);\r
580         if((nouters = func->_noutervalues)) {\r
581                 for(SQInteger i = 0; i<nouters; i++) {\r
582                         SQOuterVar &v = func->_outervalues[i];\r
583                         switch(v._type){\r
584                         case otLOCAL:\r
585                                 FindOuter(closure->_outervalues[i], &STK(_integer(v._src)));\r
586                                 break;\r
587                         case otOUTER:\r
588                                 closure->_outervalues[i] = _closure(ci->_closure)->_outervalues[_integer(v._src)];\r
589                                 break;\r
590                         }\r
591                 }\r
592         }\r
593         SQInteger ndefparams;\r
594         if((ndefparams = func->_ndefaultparams)) {\r
595                 for(SQInteger i = 0; i < ndefparams; i++) {\r
596                         SQInteger spos = func->_defaultparams[i];\r
597                         closure->_defaultparams[i] = _stack._vals[_stackbase + spos];\r
598                 }\r
599         }\r
600         target = closure;\r
601         return true;\r
602 \r
603 }\r
604 \r
605 \r
606 bool SQVM::CLASS_OP(SQObjectPtr &target,SQInteger baseclass,SQInteger attributes)\r
607 {\r
608         SQClass *base = NULL;\r
609         SQObjectPtr attrs;\r
610         if(baseclass != -1) {\r
611                 if(type(_stack._vals[_stackbase+baseclass]) != OT_CLASS) { Raise_Error(_SC("trying to inherit from a %s"),GetTypeName(_stack._vals[_stackbase+baseclass])); return false; }\r
612                 base = _class(_stack._vals[_stackbase + baseclass]);\r
613         }\r
614         if(attributes != MAX_FUNC_STACKSIZE) {\r
615                 attrs = _stack._vals[_stackbase+attributes];\r
616         }\r
617         target = SQClass::Create(_ss(this),base);\r
618         if(type(_class(target)->_metamethods[MT_INHERITED]) != OT_NULL) {\r
619                 int nparams = 2;\r
620                 SQObjectPtr ret;\r
621                 Push(target); Push(attrs);\r
622                 if(!Call(_class(target)->_metamethods[MT_INHERITED],nparams,_top - nparams, ret, false)) {\r
623                         Pop(nparams);\r
624                         return false;\r
625                 }\r
626                 Pop(nparams);\r
627         }\r
628         _class(target)->_attributes = attrs;\r
629         return true;\r
630 }\r
631 \r
632 bool SQVM::IsEqual(const SQObjectPtr &o1,const SQObjectPtr &o2,bool &res)\r
633 {\r
634         if(type(o1) == type(o2)) {\r
635                 res = (_rawval(o1) == _rawval(o2));\r
636         }\r
637         else {\r
638                 if(sq_isnumeric(o1) && sq_isnumeric(o2)) {\r
639                         res = (tofloat(o1) == tofloat(o2));\r
640                 }\r
641                 else {\r
642                         res = false;\r
643                 }\r
644         }\r
645         return true;\r
646 }\r
647 \r
648 bool SQVM::IsFalse(SQObjectPtr &o)\r
649 {\r
650         if(((type(o) & SQOBJECT_CANBEFALSE) \r
651                 && ( ((type(o) == OT_FLOAT) && (_float(o) == SQFloat(0.0))) ))\r
652 #if !defined(SQUSEDOUBLE) || (defined(SQUSEDOUBLE) && defined(_SQ64))\r
653                 || (_integer(o) == 0) )  //OT_NULL|OT_INTEGER|OT_BOOL\r
654 #else\r
655                 || (((type(o) != OT_FLOAT) && (_integer(o) == 0))) )  //OT_NULL|OT_INTEGER|OT_BOOL\r
656 #endif\r
657         {\r
658                 return true;\r
659         }\r
660         return false;\r
661 }\r
662 \r
663 bool SQVM::Execute(SQObjectPtr &closure, SQInteger nargs, SQInteger stackbase,SQObjectPtr &outres, SQBool raiseerror,ExecutionType et)\r
664 {\r
665         if ((_nnativecalls + 1) > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; }\r
666         _nnativecalls++;\r
667         AutoDec ad(&_nnativecalls);\r
668         SQInteger traps = 0;\r
669         CallInfo *prevci = ci;\r
670                 \r
671         switch(et) {\r
672                 case ET_CALL: {\r
673                         temp_reg = closure;\r
674                         if(!StartCall(_closure(temp_reg), _top - nargs, nargs, stackbase, false)) { \r
675                                 //call the handler if there are no calls in the stack, if not relies on the previous node\r
676                                 if(ci == NULL) CallErrorHandler(_lasterror);\r
677                                 return false;\r
678                         }\r
679                         if(ci == prevci) {\r
680                                 outres = STK(_top-nargs);\r
681                                 return true;\r
682                         }\r
683                         ci->_root = SQTrue;\r
684                                           }\r
685                         break;\r
686                 case ET_RESUME_GENERATOR: _generator(closure)->Resume(this, outres); ci->_root = SQTrue; traps += ci->_etraps; break;\r
687                 case ET_RESUME_VM:\r
688                 case ET_RESUME_THROW_VM:\r
689                         traps = _suspended_traps;\r
690                         ci->_root = _suspended_root;\r
691                         _suspended = SQFalse;\r
692                         if(et  == ET_RESUME_THROW_VM) { SQ_THROW(); }\r
693                         break;\r
694         }\r
695         \r
696 exception_restore:\r
697         //\r
698         {\r
699                 for(;;)\r
700                 {\r
701                         const SQInstruction &_i_ = *ci->_ip++;\r
702                         //dumpstack(_stackbase);\r
703                         //scprintf("\n[%d] %s %d %d %d %d\n",ci->_ip-ci->_iv->_vals,g_InstrDesc[_i_.op].name,arg0,arg1,arg2,arg3);\r
704                         switch(_i_.op)\r
705                         {\r
706                         case _OP_LINE: if (_debughook) CallDebugHook(_SC('l'),arg1); continue;\r
707                         case _OP_LOAD: TARGET = ci->_literals[arg1]; continue;\r
708                         case _OP_LOADINT: \r
709 #ifndef _SQ64\r
710                                 TARGET = (SQInteger)arg1; continue;\r
711 #else\r
712                                 TARGET = (SQInteger)((SQUnsignedInteger32)arg1); continue;\r
713 #endif\r
714                         case _OP_LOADFLOAT: TARGET = *((SQFloat *)&arg1); continue;\r
715                         case _OP_DLOAD: TARGET = ci->_literals[arg1]; STK(arg2) = ci->_literals[arg3];continue;\r
716                         case _OP_TAILCALL:{\r
717                                 SQObjectPtr &t = STK(arg1);\r
718                                 if (type(t) == OT_CLOSURE \r
719                                         && (!_closure(t)->_function->_bgenerator)){\r
720                                         SQObjectPtr clo = t;\r
721                                         if(_openouters) CloseOuters(&(_stack._vals[_stackbase]));\r
722                                         for (SQInteger i = 0; i < arg3; i++) STK(i) = STK(arg2 + i);\r
723                                         _GUARD(StartCall(_closure(clo), ci->_target, arg3, _stackbase, true));\r
724                                         continue;\r
725                                 }\r
726                                                           }\r
727                         case _OP_CALL: {\r
728                                         SQObjectPtr clo = STK(arg1);\r
729                                         switch (type(clo)) {\r
730                                         case OT_CLOSURE:\r
731                                                 _GUARD(StartCall(_closure(clo), sarg0, arg3, _stackbase+arg2, false));\r
732                                                 continue;\r
733                                         case OT_NATIVECLOSURE: {\r
734                                                 bool suspend;\r
735                                                 _GUARD(CallNative(_nativeclosure(clo), arg3, _stackbase+arg2, clo,suspend));\r
736                                                 if(suspend){\r
737                                                         _suspended = SQTrue;\r
738                                                         _suspended_target = sarg0;\r
739                                                         _suspended_root = ci->_root;\r
740                                                         _suspended_traps = traps;\r
741                                                         outres = clo;\r
742                                                         return true;\r
743                                                 }\r
744                                                 if(sarg0 != -1) {\r
745                                                         STK(arg0) = clo;\r
746                                                 }\r
747                                                                                    }\r
748                                                 continue;\r
749                                         case OT_CLASS:{\r
750                                                 SQObjectPtr inst;\r
751                                                 _GUARD(CreateClassInstance(_class(clo),inst,clo));\r
752                                                 if(sarg0 != -1) {\r
753                                                         STK(arg0) = inst;\r
754                                                 }\r
755                                                 SQInteger stkbase;\r
756                                                 switch(type(clo)) {\r
757                                                         case OT_CLOSURE:\r
758                                                                 stkbase = _stackbase+arg2;\r
759                                                                 _stack._vals[stkbase] = inst;\r
760                                                                 _GUARD(StartCall(_closure(clo), -1, arg3, stkbase, false));\r
761                                                                 break;\r
762                                                         case OT_NATIVECLOSURE:\r
763                                                                 bool suspend;\r
764                                                                 stkbase = _stackbase+arg2;\r
765                                                                 _stack._vals[stkbase] = inst;\r
766                                                                 _GUARD(CallNative(_nativeclosure(clo), arg3, stkbase, clo,suspend));\r
767                                                                 break;\r
768                                                         default: break; //shutup GCC 4.x\r
769                                                 }\r
770                                                 }\r
771                                                 break;\r
772                                         case OT_TABLE:\r
773                                         case OT_USERDATA:\r
774                                         case OT_INSTANCE:{\r
775                                                 SQObjectPtr closure;\r
776                                                 if(_delegable(clo)->_delegate && _delegable(clo)->GetMetaMethod(this,MT_CALL,closure)) {\r
777                                                         Push(clo);\r
778                                                         for (SQInteger i = 0; i < arg3; i++) Push(STK(arg2 + i));\r
779                                                         if(!CallMetaMethod(closure, MT_CALL, arg3+1, clo)) SQ_THROW();\r
780                                                         if(sarg0 != -1) {\r
781                                                                 STK(arg0) = clo;\r
782                                                         }\r
783                                                         break;\r
784                                                 }\r
785                                                                          \r
786                                                 //Raise_Error(_SC("attempt to call '%s'"), GetTypeName(clo));\r
787                                                 //SQ_THROW();\r
788                                           }\r
789                                         default:\r
790                                                 Raise_Error(_SC("attempt to call '%s'"), GetTypeName(clo));\r
791                                                 SQ_THROW();\r
792                                         }\r
793                                 }\r
794                                   continue;\r
795                         case _OP_PREPCALL:\r
796                         case _OP_PREPCALLK:     {\r
797                                         SQObjectPtr &key = _i_.op == _OP_PREPCALLK?(ci->_literals)[arg1]:STK(arg1);\r
798                                         SQObjectPtr &o = STK(arg2);\r
799                                         if (!Get(o, key, temp_reg,false,arg2)) {\r
800                                                 SQ_THROW();\r
801                                         }\r
802                                         STK(arg3) = o;\r
803                                         _Swap(TARGET,temp_reg);//TARGET = temp_reg;\r
804                                 }\r
805                                 continue;\r
806                         case _OP_GETK:\r
807                                 if (!Get(STK(arg2), ci->_literals[arg1], temp_reg, false,arg2)) { SQ_THROW();}\r
808                                 _Swap(TARGET,temp_reg);//TARGET = temp_reg;\r
809                                 continue;\r
810                         case _OP_MOVE: TARGET = STK(arg1); continue;\r
811                         case _OP_NEWSLOT:\r
812                                 _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),false));\r
813                                 if(arg0 != 0xFF) TARGET = STK(arg3);\r
814                                 continue;\r
815                         case _OP_DELETE: _GUARD(DeleteSlot(STK(arg1), STK(arg2), TARGET)); continue;\r
816                         case _OP_SET:\r
817                                 if (!Set(STK(arg1), STK(arg2), STK(arg3),arg1)) { SQ_THROW(); }\r
818                                 if (arg0 != 0xFF) TARGET = STK(arg3);\r
819                                 continue;\r
820                         case _OP_GET:\r
821                                 if (!Get(STK(arg1), STK(arg2), temp_reg, false,arg1)) { SQ_THROW(); }\r
822                                 _Swap(TARGET,temp_reg);//TARGET = temp_reg;\r
823                                 continue;\r
824                         case _OP_EQ:{\r
825                                 bool res;\r
826                                 if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); }\r
827                                 TARGET = res?true:false;\r
828                                 }continue;\r
829                         case _OP_NE:{ \r
830                                 bool res;\r
831                                 if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); }\r
832                                 TARGET = (!res)?true:false;\r
833                                 } continue;\r
834                         case _OP_ADD: _ARITH_(+,TARGET,STK(arg2),STK(arg1)); continue;\r
835                         case _OP_SUB: _ARITH_(-,TARGET,STK(arg2),STK(arg1)); continue;\r
836                         case _OP_MUL: _ARITH_(*,TARGET,STK(arg2),STK(arg1)); continue;\r
837                         case _OP_DIV: _ARITH_NOZERO(/,TARGET,STK(arg2),STK(arg1),_SC("division by zero")); continue;\r
838                         case _OP_MOD: ARITH_OP('%',TARGET,STK(arg2),STK(arg1)); continue;\r
839                         case _OP_BITW:  _GUARD(BW_OP( arg3,TARGET,STK(arg2),STK(arg1))); continue;\r
840                         case _OP_RETURN:\r
841                                 if((ci)->_generator) {\r
842                                         (ci)->_generator->Kill();\r
843                                 }\r
844                                 if(Return(arg0, arg1, temp_reg)){\r
845                                         assert(traps==0);\r
846                                         //outres = temp_reg;\r
847                                         _Swap(outres,temp_reg);\r
848                                         return true;\r
849                                 }\r
850                                 continue;\r
851                         case _OP_LOADNULLS:{ for(SQInt32 n=0; n < arg1; n++) STK(arg0+n).Null(); }continue;\r
852                         case _OP_LOADROOT:      TARGET = _roottable; continue;\r
853                         case _OP_LOADBOOL: TARGET = arg1?true:false; continue;\r
854                         case _OP_DMOVE: STK(arg0) = STK(arg1); STK(arg2) = STK(arg3); continue;\r
855                         case _OP_JMP: ci->_ip += (sarg1); continue;\r
856                         //case _OP_JNZ: if(!IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue;\r
857                         case _OP_JCMP: \r
858                                 _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg0),temp_reg));\r
859                                 if(IsFalse(temp_reg)) ci->_ip+=(sarg1);\r
860                                 continue;\r
861                         case _OP_JZ: if(IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue;\r
862                         case _OP_GETOUTER: {\r
863                                 SQClosure *cur_cls = _closure(ci->_closure);\r
864                                 SQOuter *otr = _outer(cur_cls->_outervalues[arg1]);\r
865                                 TARGET = *(otr->_valptr);\r
866                                 }\r
867                         continue;\r
868                         case _OP_SETOUTER: {\r
869                                 SQClosure *cur_cls = _closure(ci->_closure);\r
870                                 SQOuter   *otr = _outer(cur_cls->_outervalues[arg1]);\r
871                                 *(otr->_valptr) = STK(arg2);\r
872                                 if(arg0 != 0xFF) {\r
873                                         TARGET = STK(arg2);\r
874                                 }\r
875                                 }\r
876                         continue;\r
877                         case _OP_NEWOBJ: \r
878                                 switch(arg3) {\r
879                                         case NOT_TABLE: TARGET = SQTable::Create(_ss(this), arg1); continue;\r
880                                         case NOT_ARRAY: TARGET = SQArray::Create(_ss(this), 0); _array(TARGET)->Reserve(arg1); continue;\r
881                                         case NOT_CLASS: _GUARD(CLASS_OP(TARGET,arg1,arg2)); continue;\r
882                                         default: assert(0); continue;\r
883                                 }\r
884                         case _OP_APPENDARRAY: \r
885                                 {\r
886                                         SQObject val;\r
887                                         val._unVal.raw = 0;\r
888                                 switch(arg2) {\r
889                                 case AAT_STACK:\r
890                                         val = STK(arg1); break;\r
891                                 case AAT_LITERAL:\r
892                                         val = ci->_literals[arg1]; break;\r
893                                 case AAT_INT:\r
894                                         val._type = OT_INTEGER;\r
895 #ifndef _SQ64\r
896                                         val._unVal.nInteger = (SQInteger)arg1; \r
897 #else\r
898                                         val._unVal.nInteger = (SQInteger)((SQUnsignedInteger32)arg1);\r
899 #endif\r
900                                         break;\r
901                                 case AAT_FLOAT:\r
902                                         val._type = OT_FLOAT;\r
903                                         val._unVal.fFloat = *((SQFloat *)&arg1);\r
904                                         break;\r
905                                 case AAT_BOOL:\r
906                                         val._type = OT_BOOL;\r
907                                         val._unVal.nInteger = arg1;\r
908                                         break;\r
909                                 default: assert(0); break;\r
910 \r
911                                 }\r
912                                 _array(STK(arg0))->Append(val); continue;\r
913                                 }\r
914                         case _OP_COMPARITH: {\r
915                                 SQInteger selfidx = (((SQUnsignedInteger)arg1&0xFFFF0000)>>16);\r
916                                 _GUARD(DerefInc(arg3, TARGET, STK(selfidx), STK(arg2), STK(arg1&0x0000FFFF), false, selfidx)); \r
917                                                                 }\r
918                                 continue;\r
919                         case _OP_INC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, false, arg1));} continue;\r
920                         case _OP_INCL: {\r
921                                 SQObjectPtr &a = STK(arg1);\r
922                                 if(type(a) == OT_INTEGER) {\r
923                                         a._unVal.nInteger = _integer(a) + sarg3;\r
924                                 }\r
925                                 else {\r
926                                         SQObjectPtr o(sarg3); //_GUARD(LOCAL_INC('+',TARGET, STK(arg1), o));\r
927                                         _ARITH_(+,a,a,o);\r
928                                 }\r
929                                                    } continue;\r
930                         case _OP_PINC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, true, arg1));} continue;\r
931                         case _OP_PINCL: {\r
932                                 SQObjectPtr &a = STK(arg1);\r
933                                 if(type(a) == OT_INTEGER) {\r
934                                         TARGET = a;\r
935                                         a._unVal.nInteger = _integer(a) + sarg3;\r
936                                 }\r
937                                 else {\r
938                                         SQObjectPtr o(sarg3); _GUARD(PLOCAL_INC('+',TARGET, STK(arg1), o));\r
939                                 }\r
940                                 \r
941                                                 } continue;\r
942                         case _OP_CMP:   _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg1),TARGET))  continue;\r
943                         case _OP_EXISTS: TARGET = Get(STK(arg1), STK(arg2), temp_reg, true,DONT_FALL_BACK)?true:false;continue;\r
944                         case _OP_INSTANCEOF: \r
945                                 if(type(STK(arg1)) != OT_CLASS)\r
946                                 {Raise_Error(_SC("cannot apply instanceof between a %s and a %s"),GetTypeName(STK(arg1)),GetTypeName(STK(arg2))); SQ_THROW();}\r
947                                 TARGET = (type(STK(arg2)) == OT_INSTANCE) ? (_instance(STK(arg2))->InstanceOf(_class(STK(arg1)))?true:false) : false;\r
948                                 continue;\r
949                         case _OP_AND: \r
950                                 if(IsFalse(STK(arg2))) {\r
951                                         TARGET = STK(arg2);\r
952                                         ci->_ip += (sarg1);\r
953                                 }\r
954                                 continue;\r
955                         case _OP_OR:\r
956                                 if(!IsFalse(STK(arg2))) {\r
957                                         TARGET = STK(arg2);\r
958                                         ci->_ip += (sarg1);\r
959                                 }\r
960                                 continue;\r
961                         case _OP_NEG: _GUARD(NEG_OP(TARGET,STK(arg1))); continue;\r
962                         case _OP_NOT: TARGET = IsFalse(STK(arg1)); continue;\r
963                         case _OP_BWNOT:\r
964                                 if(type(STK(arg1)) == OT_INTEGER) {\r
965                                         SQInteger t = _integer(STK(arg1));\r
966                                         TARGET = SQInteger(~t);\r
967                                         continue;\r
968                                 }\r
969                                 Raise_Error(_SC("attempt to perform a bitwise op on a %s"), GetTypeName(STK(arg1)));\r
970                                 SQ_THROW();\r
971                         case _OP_CLOSURE: {\r
972                                 SQClosure *c = ci->_closure._unVal.pClosure;\r
973                                 SQFunctionProto *fp = c->_function;\r
974                                 if(!CLOSURE_OP(TARGET,fp->_functions[arg1]._unVal.pFunctionProto)) { SQ_THROW(); }\r
975                                 continue;\r
976                         }\r
977                         case _OP_YIELD:{\r
978                                 if(ci->_generator) {\r
979                                         if(sarg1 != MAX_FUNC_STACKSIZE) temp_reg = STK(arg1);\r
980                                         _GUARD(ci->_generator->Yield(this,arg2));\r
981                                         traps -= ci->_etraps;\r
982                                         if(sarg1 != MAX_FUNC_STACKSIZE) _Swap(STK(arg1),temp_reg);//STK(arg1) = temp_reg;\r
983                                 }\r
984                                 else { Raise_Error(_SC("trying to yield a '%s',only genenerator can be yielded"), GetTypeName(ci->_generator)); SQ_THROW();}\r
985                                 if(Return(arg0, arg1, temp_reg)){\r
986                                         assert(traps == 0);\r
987                                         outres = temp_reg;\r
988                                         return true;\r
989                                 }\r
990                                         \r
991                                 }\r
992                                 continue;\r
993                         case _OP_RESUME:\r
994                                 if(type(STK(arg1)) != OT_GENERATOR){ Raise_Error(_SC("trying to resume a '%s',only genenerator can be resumed"), GetTypeName(STK(arg1))); SQ_THROW();}\r
995                                 _GUARD(_generator(STK(arg1))->Resume(this, TARGET));\r
996                                 traps += ci->_etraps;\r
997                 continue;\r
998                         case _OP_FOREACH:{ int tojump;\r
999                                 _GUARD(FOREACH_OP(STK(arg0),STK(arg2),STK(arg2+1),STK(arg2+2),arg2,sarg1,tojump));\r
1000                                 ci->_ip += tojump; }\r
1001                                 continue;\r
1002                         case _OP_POSTFOREACH:\r
1003                                 assert(type(STK(arg0)) == OT_GENERATOR);\r
1004                                 if(_generator(STK(arg0))->_state == SQGenerator::eDead) \r
1005                                         ci->_ip += (sarg1 - 1);\r
1006                                 continue;\r
1007                         case _OP_CLONE: _GUARD(Clone(STK(arg1), TARGET)); continue;\r
1008                         case _OP_TYPEOF: _GUARD(TypeOf(STK(arg1), TARGET)) continue;\r
1009                         case _OP_PUSHTRAP:{\r
1010                                 SQInstruction *_iv = _closure(ci->_closure)->_function->_instructions;\r
1011                                 _etraps.push_back(SQExceptionTrap(_top,_stackbase, &_iv[(ci->_ip-_iv)+arg1], arg0)); traps++;\r
1012                                 ci->_etraps++;\r
1013                                                           }\r
1014                                 continue;\r
1015                         case _OP_POPTRAP: {\r
1016                                 for(SQInteger i = 0; i < arg0; i++) {\r
1017                                         _etraps.pop_back(); traps--;\r
1018                                         ci->_etraps--;\r
1019                                 }\r
1020                                                           }\r
1021                                 continue;\r
1022                         case _OP_THROW: Raise_Error(TARGET); SQ_THROW(); continue;\r
1023                         case _OP_NEWSLOTA:\r
1024                                 _GUARD(NewSlotA(STK(arg1),STK(arg2),STK(arg3),(arg0&NEW_SLOT_ATTRIBUTES_FLAG) ? STK(arg2-1) : SQObjectPtr(),(arg0&NEW_SLOT_STATIC_FLAG)?true:false,false));\r
1025                                 continue;\r
1026                         case _OP_GETBASE:{\r
1027                                 SQClosure *clo = _closure(ci->_closure);\r
1028                                 if(clo->_base) {\r
1029                                         TARGET = clo->_base;\r
1030                                 }\r
1031                                 else {\r
1032                                         TARGET.Null();\r
1033                                 }\r
1034                                 continue;\r
1035                         }\r
1036                         case _OP_CLOSE:\r
1037                                 if(_openouters) CloseOuters(&(STK(arg1)));\r
1038                                 continue;\r
1039                         }\r
1040                         \r
1041                 }\r
1042         }\r
1043 exception_trap:\r
1044         {\r
1045                 SQObjectPtr currerror = _lasterror;\r
1046 //              dumpstack(_stackbase);\r
1047 //              SQInteger n = 0;\r
1048                 SQInteger last_top = _top;\r
1049                 \r
1050                 if(_ss(this)->_notifyallexceptions || (!traps && raiseerror)) CallErrorHandler(currerror);\r
1051 \r
1052                 while( ci ) {\r
1053                         if(ci->_etraps > 0) {\r
1054                                 SQExceptionTrap &et = _etraps.top();\r
1055                                 ci->_ip = et._ip;\r
1056                                 _top = et._stacksize;\r
1057                                 _stackbase = et._stackbase;\r
1058                                 _stack._vals[_stackbase + et._extarget] = currerror;\r
1059                                 _etraps.pop_back(); traps--; ci->_etraps--;\r
1060                                 while(last_top >= _top) _stack._vals[last_top--].Null();\r
1061                                 goto exception_restore;\r
1062                         }\r
1063                         else if (_debughook) { \r
1064                                         //notify debugger of a "return"\r
1065                                         //even if it really an exception unwinding the stack\r
1066                                         for(SQInteger i = 0; i < ci->_ncalls; i++) {\r
1067                                                 CallDebugHook(_SC('r'));\r
1068                                         }\r
1069                         }\r
1070                         if(ci->_generator) ci->_generator->Kill();\r
1071                         bool mustbreak = ci && ci->_root;\r
1072                         LeaveFrame();\r
1073                         if(mustbreak) break;\r
1074                 }\r
1075                                                 \r
1076                 _lasterror = currerror;\r
1077                 return false;\r
1078         }\r
1079         assert(0);\r
1080 }\r
1081 \r
1082 bool SQVM::CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor)\r
1083 {\r
1084         inst = theclass->CreateInstance();\r
1085         if(!theclass->GetConstructor(constructor)) {\r
1086                 constructor.Null();\r
1087         }\r
1088         return true;\r
1089 }\r
1090 \r
1091 void SQVM::CallErrorHandler(SQObjectPtr &error)\r
1092 {\r
1093         if(type(_errorhandler) != OT_NULL) {\r
1094                 SQObjectPtr out;\r
1095                 Push(_roottable); Push(error);\r
1096                 Call(_errorhandler, 2, _top-2, out,SQFalse);\r
1097                 Pop(2);\r
1098         }\r
1099 }\r
1100 \r
1101 \r
1102 void SQVM::CallDebugHook(SQInteger type,SQInteger forcedline)\r
1103 {\r
1104         _debughook = false;\r
1105         SQFunctionProto *func=_closure(ci->_closure)->_function;\r
1106         if(_debughook_native) {\r
1107                 const SQChar *src = type(func->_sourcename) == OT_STRING?_stringval(func->_sourcename):NULL;\r
1108                 const SQChar *fname = type(func->_name) == OT_STRING?_stringval(func->_name):NULL;\r
1109                 SQInteger line = forcedline?forcedline:func->GetLine(ci->_ip);\r
1110                 _debughook_native(this,type,src,line,fname);\r
1111         }\r
1112         else {\r
1113                 SQObjectPtr temp_reg;\r
1114                 SQInteger nparams=5;\r
1115                 Push(_roottable); Push(type); Push(func->_sourcename); Push(forcedline?forcedline:func->GetLine(ci->_ip)); Push(func->_name);\r
1116                 Call(_debughook_closure,nparams,_top-nparams,temp_reg,SQFalse);\r
1117                 Pop(nparams);\r
1118         }\r
1119         _debughook = true;\r
1120 }\r
1121 \r
1122 bool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval, bool &suspend)\r
1123 {\r
1124         SQInteger nparamscheck = nclosure->_nparamscheck;\r
1125         SQInteger newtop = newbase + nargs + nclosure->_noutervalues;\r
1126         \r
1127         if (_nnativecalls + 1 > MAX_NATIVE_CALLS) {\r
1128                 Raise_Error(_SC("Native stack overflow"));\r
1129                 return false;\r
1130         }\r
1131 \r
1132         if(nparamscheck && (((nparamscheck > 0) && (nparamscheck != nargs)) ||\r
1133                 ((nparamscheck < 0) && (nargs < (-nparamscheck)))))\r
1134         {\r
1135                 Raise_Error(_SC("wrong number of parameters"));\r
1136                 return false;\r
1137         }\r
1138 \r
1139         SQInteger tcs;\r
1140         SQIntVec &tc = nclosure->_typecheck;\r
1141         if((tcs = tc.size())) {\r
1142                 for(SQInteger i = 0; i < nargs && i < tcs; i++) {\r
1143                         if((tc._vals[i] != -1) && !(type(_stack._vals[newbase+i]) & tc._vals[i])) {\r
1144                                 Raise_ParamTypeError(i,tc._vals[i],type(_stack._vals[newbase+i]));\r
1145                                 return false;\r
1146                         }\r
1147                 }\r
1148         }\r
1149 \r
1150         if(!EnterFrame(newbase, newtop, false)) return false;\r
1151         ci->_closure  = nclosure;\r
1152 \r
1153         SQInteger outers = nclosure->_noutervalues;\r
1154         for (SQInteger i = 0; i < outers; i++) {\r
1155                 _stack._vals[newbase+nargs+i] = nclosure->_outervalues[i];\r
1156         }\r
1157         if(nclosure->_env) {\r
1158                 _stack._vals[newbase] = nclosure->_env->_obj;\r
1159         }\r
1160 \r
1161         _nnativecalls++;\r
1162         SQInteger ret = (nclosure->_function)(this);\r
1163         _nnativecalls--;\r
1164 \r
1165         suspend = false;\r
1166         if (ret == SQ_SUSPEND_FLAG) {\r
1167                 suspend = true;\r
1168         }\r
1169         else if (ret < 0) {\r
1170                 LeaveFrame();\r
1171                 Raise_Error(_lasterror);\r
1172                 return false;\r
1173         }\r
1174         if(ret) {\r
1175                 retval = _stack._vals[_top-1];\r
1176         }\r
1177         else {\r
1178                 retval.Null();\r
1179         }\r
1180         //retval = ret ? _stack._vals[_top-1] : _null_;\r
1181         LeaveFrame();\r
1182         return true;\r
1183 }\r
1184 \r
1185 #define FALLBACK_OK                     0\r
1186 #define FALLBACK_NO_MATCH       1\r
1187 #define FALLBACK_ERROR          2\r
1188 \r
1189 bool SQVM::Get(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw, SQInteger selfidx)\r
1190 {\r
1191         switch(type(self)){\r
1192         case OT_TABLE:\r
1193                 if(_table(self)->Get(key,dest))return true;\r
1194                 break;\r
1195         case OT_ARRAY:\r
1196                 if(sq_isnumeric(key)) { if(_array(self)->Get(tointeger(key),dest)) { return true; } if(selfidx != EXISTS_FALL_BACK) Raise_IdxError(key); return false; }\r
1197                 break;\r
1198         case OT_INSTANCE:\r
1199                 if(_instance(self)->Get(key,dest)) return true;\r
1200                 break;\r
1201         case OT_CLASS: \r
1202                 if(_class(self)->Get(key,dest)) return true;\r
1203                 break;\r
1204         case OT_STRING:\r
1205                 if(sq_isnumeric(key)){\r
1206                         SQInteger n = tointeger(key);\r
1207                         if(abs((int)n) < _string(self)->_len) {\r
1208                                 if(n < 0) n = _string(self)->_len - n;\r
1209                                 dest = SQInteger(_stringval(self)[n]);\r
1210                                 return true;\r
1211                         }\r
1212                         if(selfidx != EXISTS_FALL_BACK) Raise_IdxError(key);\r
1213                         return false;\r
1214                 }\r
1215                 break;\r
1216         default:break; //shut up compiler\r
1217         }\r
1218         if(!raw) {\r
1219                 switch(FallBackGet(self,key,dest)) {\r
1220                         case FALLBACK_OK: return true; //okie\r
1221                         case FALLBACK_NO_MATCH: break; //keep falling back\r
1222                         case FALLBACK_ERROR: return false; // the metamethod failed\r
1223                 }\r
1224                 if(InvokeDefaultDelegate(self,key,dest)) {\r
1225                         return true;\r
1226                 }\r
1227         }\r
1228 //#ifdef ROOT_FALLBACK\r
1229         if(selfidx == 0) {\r
1230                 if(_table(_roottable)->Get(key,dest)) return true;\r
1231         }\r
1232 //#endif\r
1233         if(selfidx != EXISTS_FALL_BACK) Raise_IdxError(key);\r
1234         return false;\r
1235 }\r
1236 \r
1237 bool SQVM::InvokeDefaultDelegate(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest)\r
1238 {\r
1239         SQTable *ddel = NULL;\r
1240         switch(type(self)) {\r
1241                 case OT_CLASS: ddel = _class_ddel; break;\r
1242                 case OT_TABLE: ddel = _table_ddel; break;\r
1243                 case OT_ARRAY: ddel = _array_ddel; break;\r
1244                 case OT_STRING: ddel = _string_ddel; break;\r
1245                 case OT_INSTANCE: ddel = _instance_ddel; break;\r
1246                 case OT_INTEGER:case OT_FLOAT:case OT_BOOL: ddel = _number_ddel; break;\r
1247                 case OT_GENERATOR: ddel = _generator_ddel; break;\r
1248                 case OT_CLOSURE: case OT_NATIVECLOSURE: ddel = _closure_ddel; break;\r
1249                 case OT_THREAD: ddel = _thread_ddel; break;\r
1250                 case OT_WEAKREF: ddel = _weakref_ddel; break;\r
1251                 default: return false;\r
1252         }\r
1253         return  ddel->Get(key,dest);\r
1254 }\r
1255 \r
1256 \r
1257 SQInteger SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest)\r
1258 {\r
1259         switch(type(self)){\r
1260         case OT_TABLE:\r
1261         case OT_USERDATA:\r
1262         //delegation\r
1263                 if(_delegable(self)->_delegate) {\r
1264                         if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest,false,DONT_FALL_BACK)) return FALLBACK_OK;     \r
1265                 }\r
1266                 else {\r
1267                         return FALLBACK_NO_MATCH;\r
1268                 }\r
1269                 //go through\r
1270         case OT_INSTANCE: {\r
1271                 SQObjectPtr closure;\r
1272                 if(_delegable(self)->GetMetaMethod(this, MT_GET, closure)) {\r
1273                         Push(self);Push(key);\r
1274                         _nmetamethodscall++;\r
1275                         AutoDec ad(&_nmetamethodscall);\r
1276                         if(Call(closure, 2, _top - 2, dest, SQFalse)) {\r
1277                                 Pop(2);\r
1278                                 return FALLBACK_OK;\r
1279                         }\r
1280                         else {\r
1281                                 Pop(2);\r
1282                                 if(type(_lasterror) != OT_NULL) { //NULL means "clean failure" (not found)\r
1283                                         return FALLBACK_ERROR;\r
1284                                 }\r
1285                         }\r
1286                 }\r
1287                                           }\r
1288                 break;\r
1289         default: break;//shutup GCC 4.x\r
1290         }\r
1291         // no metamethod or no fallback type\r
1292         return FALLBACK_NO_MATCH;\r
1293 }\r
1294 \r
1295 bool SQVM::Set(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,SQInteger selfidx)\r
1296 {\r
1297         switch(type(self)){\r
1298         case OT_TABLE:\r
1299                 if(_table(self)->Set(key,val)) return true;\r
1300                 break;\r
1301         case OT_INSTANCE:\r
1302                 if(_instance(self)->Set(key,val)) return true;\r
1303                 break;\r
1304         case OT_ARRAY:\r
1305                 if(!sq_isnumeric(key)) { Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key)); return false; }\r
1306                 if(!_array(self)->Set(tointeger(key),val)) {\r
1307                         Raise_IdxError(key);\r
1308                         return false;\r
1309                 }\r
1310                 return true;\r
1311         default:\r
1312                 Raise_Error(_SC("trying to set '%s'"),GetTypeName(self));\r
1313                 return false;\r
1314         }\r
1315 \r
1316         switch(FallBackSet(self,key,val)) {\r
1317                 case FALLBACK_OK: return true; //okie\r
1318                 case FALLBACK_NO_MATCH: break; //keep falling back\r
1319                 case FALLBACK_ERROR: return false; // the metamethod failed\r
1320         }\r
1321         if(selfidx == 0) {\r
1322                 if(_table(_roottable)->Set(key,val))\r
1323                         return true;\r
1324         }\r
1325         Raise_IdxError(key);\r
1326         return false;\r
1327 }\r
1328 \r
1329 SQInteger SQVM::FallBackSet(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val)\r
1330 {\r
1331         switch(type(self)) {\r
1332         case OT_TABLE:\r
1333                 if(_table(self)->_delegate) {\r
1334                         if(Set(_table(self)->_delegate,key,val,DONT_FALL_BACK)) return FALLBACK_OK;\r
1335                 }\r
1336                 //keps on going\r
1337         case OT_INSTANCE:\r
1338         case OT_USERDATA:{\r
1339                 SQObjectPtr closure;\r
1340                 SQObjectPtr t;\r
1341                 if(_delegable(self)->GetMetaMethod(this, MT_SET, closure)) {\r
1342                         Push(self);Push(key);Push(val);\r
1343                         _nmetamethodscall++;\r
1344                         AutoDec ad(&_nmetamethodscall);\r
1345                         if(Call(closure, 3, _top - 3, t, SQFalse)) {\r
1346                                 Pop(3);\r
1347                                 return FALLBACK_OK;\r
1348                         }\r
1349                         else {\r
1350                                 if(type(_lasterror) != OT_NULL) { //NULL means "clean failure" (not found)\r
1351                                         //error\r
1352                                         Pop(3);\r
1353                                         return FALLBACK_ERROR;\r
1354                                 }\r
1355                         }\r
1356                 }\r
1357                                          }\r
1358                 break;\r
1359                 default: break;//shutup GCC 4.x\r
1360         }\r
1361         // no metamethod or no fallback type\r
1362         return FALLBACK_NO_MATCH;\r
1363 }\r
1364 \r
1365 bool SQVM::Clone(const SQObjectPtr &self,SQObjectPtr &target)\r
1366 {\r
1367         SQObjectPtr temp_reg;\r
1368         SQObjectPtr newobj;\r
1369         switch(type(self)){\r
1370         case OT_TABLE:\r
1371                 newobj = _table(self)->Clone();\r
1372                 goto cloned_mt;\r
1373         case OT_INSTANCE: {\r
1374                 newobj = _instance(self)->Clone(_ss(this));\r
1375 cloned_mt:\r
1376                 SQObjectPtr closure;\r
1377                 if(_delegable(newobj)->_delegate && _delegable(newobj)->GetMetaMethod(this,MT_CLONED,closure)) {\r
1378                         Push(newobj);\r
1379                         Push(self);\r
1380                         if(!CallMetaMethod(closure,MT_CLONED,2,temp_reg))\r
1381                                 return false;\r
1382                 }\r
1383                 }\r
1384                 target = newobj;\r
1385                 return true;\r
1386         case OT_ARRAY: \r
1387                 target = _array(self)->Clone();\r
1388                 return true;\r
1389         default: \r
1390                 Raise_Error(_SC("cloning a %s"), GetTypeName(self));\r
1391                 return false;\r
1392         }\r
1393 }\r
1394 \r
1395 bool SQVM::NewSlotA(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,const SQObjectPtr &attrs,bool bstatic,bool raw)\r
1396 {\r
1397         if(type(self) != OT_CLASS) {\r
1398                 Raise_Error(_SC("object must be a class"));\r
1399                 return false;\r
1400         }\r
1401         SQClass *c = _class(self);\r
1402         if(!raw) {\r
1403                 SQObjectPtr &mm = c->_metamethods[MT_NEWMEMBER];\r
1404                 if(type(mm) != OT_NULL ) {\r
1405                         Push(self); Push(key); Push(val);\r
1406                         Push(attrs);\r
1407                         Push(bstatic);\r
1408                         return CallMetaMethod(mm,MT_NEWMEMBER,5,temp_reg);\r
1409                 }\r
1410         }\r
1411         if(!NewSlot(self, key, val,bstatic))\r
1412                 return false;\r
1413         if(type(attrs) != OT_NULL) {\r
1414                 c->SetAttributes(key,attrs);\r
1415         }\r
1416         return true;\r
1417 }\r
1418 \r
1419 bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic)\r
1420 {\r
1421         if(type(key) == OT_NULL) { Raise_Error(_SC("null cannot be used as index")); return false; }\r
1422         switch(type(self)) {\r
1423         case OT_TABLE: {\r
1424                 bool rawcall = true;\r
1425                 if(_table(self)->_delegate) {\r
1426                         SQObjectPtr res;\r
1427                         if(!_table(self)->Get(key,res)) {\r
1428                                 SQObjectPtr closure;\r
1429                                 if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_NEWSLOT,closure)) {\r
1430                                         Push(self);Push(key);Push(val);\r
1431                                         if(!CallMetaMethod(closure,MT_NEWSLOT,3,res)) {\r
1432                                                 return false;\r
1433                                         }\r
1434                                         rawcall = false;\r
1435                                 }\r
1436                                 else {\r
1437                                         rawcall = true;\r
1438                                 }\r
1439                         }\r
1440                 }\r
1441                 if(rawcall) _table(self)->NewSlot(key,val); //cannot fail\r
1442                 \r
1443                 break;}\r
1444         case OT_INSTANCE: {\r
1445                 SQObjectPtr res;\r
1446                 SQObjectPtr closure;\r
1447                 if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_NEWSLOT,closure)) {\r
1448                         Push(self);Push(key);Push(val);\r
1449                         if(!CallMetaMethod(closure,MT_NEWSLOT,3,res)) {\r
1450                                 return false;\r
1451                         }\r
1452                         break;\r
1453                 }\r
1454                 Raise_Error(_SC("class instances do not support the new slot operator"));\r
1455                 return false;\r
1456                 break;}\r
1457         case OT_CLASS: \r
1458                 if(!_class(self)->NewSlot(_ss(this),key,val,bstatic)) {\r
1459                         if(_class(self)->_locked) {\r
1460                                 Raise_Error(_SC("trying to modify a class that has already been instantiated"));\r
1461                                 return false;\r
1462                         }\r
1463                         else {\r
1464                                 SQObjectPtr oval = PrintObjVal(key);\r
1465                                 Raise_Error(_SC("the property '%s' already exists"),_stringval(oval));\r
1466                                 return false;\r
1467                         }\r
1468                 }\r
1469                 break;\r
1470         default:\r
1471                 Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key));\r
1472                 return false;\r
1473                 break;\r
1474         }\r
1475         return true;\r
1476 }\r
1477 \r
1478 \r
1479 \r
1480 bool SQVM::DeleteSlot(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &res)\r
1481 {\r
1482         switch(type(self)) {\r
1483         case OT_TABLE:\r
1484         case OT_INSTANCE:\r
1485         case OT_USERDATA: {\r
1486                 SQObjectPtr t;\r
1487                 //bool handled = false;\r
1488                 SQObjectPtr closure;\r
1489                 if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_DELSLOT,closure)) {\r
1490                         Push(self);Push(key);\r
1491                         return CallMetaMethod(closure,MT_DELSLOT,2,res);\r
1492                 }\r
1493                 else {\r
1494                         if(type(self) == OT_TABLE) {\r
1495                                 if(_table(self)->Get(key,t)) {\r
1496                                         _table(self)->Remove(key);\r
1497                                 }\r
1498                                 else {\r
1499                                         Raise_IdxError((SQObject &)key);\r
1500                                         return false;\r
1501                                 }\r
1502                         }\r
1503                         else {\r
1504                                 Raise_Error(_SC("cannot delete a slot from %s"),GetTypeName(self));\r
1505                                 return false;\r
1506                         }\r
1507                 }\r
1508                 res = t;\r
1509                                 }\r
1510                 break;\r
1511         default:\r
1512                 Raise_Error(_SC("attempt to delete a slot from a %s"),GetTypeName(self));\r
1513                 return false;\r
1514         }\r
1515         return true;\r
1516 }\r
1517 \r
1518 bool SQVM::Call(SQObjectPtr &closure,SQInteger nparams,SQInteger stackbase,SQObjectPtr &outres,SQBool raiseerror)\r
1519 {\r
1520 #ifdef _DEBUG\r
1521 SQInteger prevstackbase = _stackbase;\r
1522 #endif\r
1523         switch(type(closure)) {\r
1524         case OT_CLOSURE:\r
1525                 return Execute(closure, nparams, stackbase, outres, raiseerror);\r
1526                 break;\r
1527         case OT_NATIVECLOSURE:{\r
1528                 bool suspend;\r
1529                 return CallNative(_nativeclosure(closure), nparams, stackbase, outres,suspend);\r
1530                 \r
1531                                                   }\r
1532                 break;\r
1533         case OT_CLASS: {\r
1534                 SQObjectPtr constr;\r
1535                 SQObjectPtr temp;\r
1536                 CreateClassInstance(_class(closure),outres,constr);\r
1537                 if(type(constr) != OT_NULL) {\r
1538                         _stack[stackbase] = outres;\r
1539                         return Call(constr,nparams,stackbase,temp,raiseerror);\r
1540                 }\r
1541                 return true;\r
1542                                    }\r
1543                 break;\r
1544         default:\r
1545                 return false;\r
1546         }\r
1547 #ifdef _DEBUG\r
1548         if(!_suspended) {\r
1549                 assert(_stackbase == prevstackbase);\r
1550         }\r
1551 #endif\r
1552         return true;\r
1553 }\r
1554 \r
1555 bool SQVM::CallMetaMethod(SQObjectPtr &closure,SQMetaMethod mm,SQInteger nparams,SQObjectPtr &outres)\r
1556 {\r
1557         //SQObjectPtr closure;\r
1558         \r
1559         _nmetamethodscall++;\r
1560         if(Call(closure, nparams, _top - nparams, outres, SQFalse)) {\r
1561                 _nmetamethodscall--;\r
1562                 Pop(nparams);\r
1563                 return true;\r
1564         }\r
1565         _nmetamethodscall--;\r
1566         //}\r
1567         Pop(nparams);\r
1568         return false;\r
1569 }\r
1570 \r
1571 void SQVM::FindOuter(SQObjectPtr &target, SQObjectPtr *stackindex)\r
1572 {\r
1573         SQOuter **pp = &_openouters;\r
1574         SQOuter *p;\r
1575         SQOuter *otr;\r
1576 \r
1577         while ((p = *pp) != NULL && p->_valptr >= stackindex) {\r
1578                 if (p->_valptr == stackindex) {\r
1579                         target = SQObjectPtr(p);\r
1580                         return;\r
1581                 }\r
1582                 pp = &p->_next;\r
1583         }\r
1584         otr = SQOuter::Create(_ss(this), stackindex);\r
1585         otr->_next = *pp;\r
1586         otr->_idx  = (stackindex - _stack._vals);\r
1587         __ObjAddRef(otr);\r
1588         *pp = otr;\r
1589         target = SQObjectPtr(otr);\r
1590 }\r
1591 \r
1592 bool SQVM::EnterFrame(SQInteger newbase, SQInteger newtop, bool tailcall)\r
1593 {\r
1594         if( !tailcall ) {\r
1595                 if( _callsstacksize == _alloccallsstacksize ) {\r
1596                         GrowCallStack();\r
1597                 }\r
1598                 ci = &_callsstack[_callsstacksize++];\r
1599                 ci->_prevstkbase = (SQInt32)(newbase - _stackbase);\r
1600                 ci->_prevtop = (SQInt32)(_top - _stackbase);\r
1601                 ci->_etraps = 0;\r
1602                 ci->_ncalls = 1;\r
1603                 ci->_generator = NULL;\r
1604                 ci->_root = SQFalse;\r
1605         }\r
1606         else {\r
1607                 ci->_ncalls++;\r
1608         }\r
1609 \r
1610         _stackbase = newbase;\r
1611         _top = newtop;\r
1612         if(newtop + MIN_STACK_OVERHEAD > (SQInteger)_stack.size()) {\r
1613                 if(_nmetamethodscall) {\r
1614                         Raise_Error(_SC("stack overflow, cannot resize stack while in  a metamethod"));\r
1615                         return false;\r
1616                 }\r
1617                 _stack.resize(_stack.size() + (MIN_STACK_OVERHEAD << 2));\r
1618                 RelocateOuters();\r
1619         }\r
1620         return true;\r
1621 }\r
1622 \r
1623 void SQVM::LeaveFrame() {\r
1624         SQInteger last_top = _top;\r
1625         SQInteger last_stackbase = _stackbase;\r
1626         SQInteger css = --_callsstacksize;\r
1627 \r
1628         /* First clean out the call stack frame */\r
1629         ci->_closure.Null();\r
1630         _stackbase -= ci->_prevstkbase;\r
1631         _top = _stackbase + ci->_prevtop;\r
1632         ci = (css) ? &_callsstack[css-1] : NULL;\r
1633 \r
1634         if(_openouters) CloseOuters(&(_stack._vals[last_stackbase]));\r
1635         while (last_top >= _top) {\r
1636                 _stack._vals[last_top--].Null();\r
1637         }\r
1638 }\r
1639 \r
1640 void SQVM::RelocateOuters()\r
1641 {\r
1642         SQOuter *p = _openouters;\r
1643         while (p) {\r
1644                 p->_valptr = _stack._vals + p->_idx;\r
1645                 p = p->_next;\r
1646         }\r
1647 }\r
1648 \r
1649 void SQVM::CloseOuters(SQObjectPtr *stackindex) {\r
1650   SQOuter *p;\r
1651   while ((p = _openouters) != NULL && p->_valptr >= stackindex) {\r
1652     p->_value = *(p->_valptr);\r
1653     p->_valptr = &p->_value;\r
1654     _openouters = p->_next;\r
1655         __ObjRelease(p);\r
1656   }\r
1657 }\r
1658 \r
1659 void SQVM::Remove(SQInteger n) {\r
1660         n = (n >= 0)?n + _stackbase - 1:_top + n;\r
1661         for(SQInteger i = n; i < _top; i++){\r
1662                 _stack[i] = _stack[i+1];\r
1663         }\r
1664         _stack[_top].Null();\r
1665         _top--;\r
1666 }\r
1667 \r
1668 void SQVM::Pop() {\r
1669         _stack[--_top].Null();\r
1670 }\r
1671 \r
1672 void SQVM::Pop(SQInteger n) {\r
1673         for(SQInteger i = 0; i < n; i++){\r
1674                 _stack[--_top].Null();\r
1675         }\r
1676 }\r
1677 \r
1678 void SQVM::PushNull() { _stack[_top++].Null(); }\r
1679 void SQVM::Push(const SQObjectPtr &o) { _stack[_top++] = o; }\r
1680 SQObjectPtr &SQVM::Top() { return _stack[_top-1]; }\r
1681 SQObjectPtr &SQVM::PopGet() { return _stack[--_top]; }\r
1682 SQObjectPtr &SQVM::GetUp(SQInteger n) { return _stack[_top+n]; }\r
1683 SQObjectPtr &SQVM::GetAt(SQInteger n) { return _stack[n]; }\r
1684 \r
1685 #ifdef _DEBUG_DUMP\r
1686 void SQVM::dumpstack(SQInteger stackbase,bool dumpall)\r
1687 {\r
1688         SQInteger size=dumpall?_stack.size():_top;\r
1689         SQInteger n=0;\r
1690         scprintf(_SC("\n>>>>stack dump<<<<\n"));\r
1691         CallInfo &ci=_callsstack[_callsstacksize-1];\r
1692         scprintf(_SC("IP: %p\n"),ci._ip);\r
1693         scprintf(_SC("prev stack base: %d\n"),ci._prevstkbase);\r
1694         scprintf(_SC("prev top: %d\n"),ci._prevtop);\r
1695         for(SQInteger i=0;i<size;i++){\r
1696                 SQObjectPtr &obj=_stack[i];     \r
1697                 if(stackbase==i)scprintf(_SC(">"));else scprintf(_SC(" "));\r
1698                 scprintf(_SC("[%d]:"),n);\r
1699                 switch(type(obj)){\r
1700                 case OT_FLOAT:                  scprintf(_SC("FLOAT %.3f"),_float(obj));break;\r
1701                 case OT_INTEGER:                scprintf(_SC("INTEGER %d"),_integer(obj));break;\r
1702                 case OT_BOOL:                   scprintf(_SC("BOOL %s"),_integer(obj)?"true":"false");break;\r
1703                 case OT_STRING:                 scprintf(_SC("STRING %s"),_stringval(obj));break;\r
1704                 case OT_NULL:                   scprintf(_SC("NULL"));  break;\r
1705                 case OT_TABLE:                  scprintf(_SC("TABLE %p[%p]"),_table(obj),_table(obj)->_delegate);break;\r
1706                 case OT_ARRAY:                  scprintf(_SC("ARRAY %p"),_array(obj));break;\r
1707                 case OT_CLOSURE:                scprintf(_SC("CLOSURE [%p]"),_closure(obj));break;\r
1708                 case OT_NATIVECLOSURE:  scprintf(_SC("NATIVECLOSURE"));break;\r
1709                 case OT_USERDATA:               scprintf(_SC("USERDATA %p[%p]"),_userdataval(obj),_userdata(obj)->_delegate);break;\r
1710                 case OT_GENERATOR:              scprintf(_SC("GENERATOR %p"),_generator(obj));break;\r
1711                 case OT_THREAD:                 scprintf(_SC("THREAD [%p]"),_thread(obj));break;\r
1712                 case OT_USERPOINTER:    scprintf(_SC("USERPOINTER %p"),_userpointer(obj));break;\r
1713                 case OT_CLASS:                  scprintf(_SC("CLASS %p"),_class(obj));break;\r
1714                 case OT_INSTANCE:               scprintf(_SC("INSTANCE %p"),_instance(obj));break;\r
1715                 case OT_WEAKREF:                scprintf(_SC("WEAKERF %p"),_weakref(obj));break;\r
1716                 default:\r
1717                         assert(0);\r
1718                         break;\r
1719                 };\r
1720                 scprintf(_SC("\n"));\r
1721                 ++n;\r
1722         }\r
1723 }\r
1724 \r
1725 \r
1726 \r
1727 #endif\r