Update to SQUIRREL 3.0.4
[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         else {\r
355                 _roottable = friendvm->_roottable;\r
356                 _errorhandler = friendvm->_errorhandler;\r
357                 _debughook = friendvm->_debughook;\r
358                 _debughook_native = friendvm->_debughook_native;\r
359                 _debughook_closure = friendvm->_debughook_closure;\r
360         }\r
361         \r
362         sq_base_register(this);\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                 Call(_class(target)->_metamethods[MT_INHERITED],nparams,_top - nparams, ret, false);\r
623                 Pop(nparams);\r
624         }\r
625         _class(target)->_attributes = attrs;\r
626         return true;\r
627 }\r
628 \r
629 bool SQVM::IsEqual(const SQObjectPtr &o1,const SQObjectPtr &o2,bool &res)\r
630 {\r
631         if(type(o1) == type(o2)) {\r
632                 res = (_rawval(o1) == _rawval(o2));\r
633         }\r
634         else {\r
635                 if(sq_isnumeric(o1) && sq_isnumeric(o2)) {\r
636                         res = (tofloat(o1) == tofloat(o2));\r
637                 }\r
638                 else {\r
639                         res = false;\r
640                 }\r
641         }\r
642         return true;\r
643 }\r
644 \r
645 bool SQVM::IsFalse(SQObjectPtr &o)\r
646 {\r
647         if(((type(o) & SQOBJECT_CANBEFALSE) \r
648                 && ( ((type(o) == OT_FLOAT) && (_float(o) == SQFloat(0.0))) ))\r
649 #if !defined(SQUSEDOUBLE) || (defined(SQUSEDOUBLE) && defined(_SQ64))\r
650                 || (_integer(o) == 0) )  //OT_NULL|OT_INTEGER|OT_BOOL\r
651 #else\r
652                 || (((type(o) != OT_FLOAT) && (_integer(o) == 0))) )  //OT_NULL|OT_INTEGER|OT_BOOL\r
653 #endif\r
654         {\r
655                 return true;\r
656         }\r
657         return false;\r
658 }\r
659 \r
660 bool SQVM::Execute(SQObjectPtr &closure, SQInteger nargs, SQInteger stackbase,SQObjectPtr &outres, SQBool raiseerror,ExecutionType et)\r
661 {\r
662         if ((_nnativecalls + 1) > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; }\r
663         _nnativecalls++;\r
664         AutoDec ad(&_nnativecalls);\r
665         SQInteger traps = 0;\r
666         CallInfo *prevci = ci;\r
667                 \r
668         switch(et) {\r
669                 case ET_CALL: {\r
670                         temp_reg = closure;\r
671                         if(!StartCall(_closure(temp_reg), _top - nargs, nargs, stackbase, false)) { \r
672                                 //call the handler if there are no calls in the stack, if not relies on the previous node\r
673                                 if(ci == NULL) CallErrorHandler(_lasterror);\r
674                                 return false;\r
675                         }\r
676                         if(ci == prevci) {\r
677                                 outres = STK(_top-nargs);\r
678                                 return true;\r
679                         }\r
680                         ci->_root = SQTrue;\r
681                                           }\r
682                         break;\r
683                 case ET_RESUME_GENERATOR: _generator(closure)->Resume(this, outres); ci->_root = SQTrue; traps += ci->_etraps; break;\r
684                 case ET_RESUME_VM:\r
685                 case ET_RESUME_THROW_VM:\r
686                         traps = _suspended_traps;\r
687                         ci->_root = _suspended_root;\r
688                         _suspended = SQFalse;\r
689                         if(et  == ET_RESUME_THROW_VM) { SQ_THROW(); }\r
690                         break;\r
691         }\r
692         \r
693 exception_restore:\r
694         //\r
695         {\r
696                 for(;;)\r
697                 {\r
698                         const SQInstruction &_i_ = *ci->_ip++;\r
699                         //dumpstack(_stackbase);\r
700                         //scprintf("\n[%d] %s %d %d %d %d\n",ci->_ip-ci->_iv->_vals,g_InstrDesc[_i_.op].name,arg0,arg1,arg2,arg3);\r
701                         switch(_i_.op)\r
702                         {\r
703                         case _OP_LINE: if (_debughook) CallDebugHook(_SC('l'),arg1); continue;\r
704                         case _OP_LOAD: TARGET = ci->_literals[arg1]; continue;\r
705                         case _OP_LOADINT: \r
706 #ifndef _SQ64\r
707                                 TARGET = (SQInteger)arg1; continue;\r
708 #else\r
709                                 TARGET = (SQInteger)((SQUnsignedInteger32)arg1); continue;\r
710 #endif\r
711                         case _OP_LOADFLOAT: TARGET = *((SQFloat *)&arg1); continue;\r
712                         case _OP_DLOAD: TARGET = ci->_literals[arg1]; STK(arg2) = ci->_literals[arg3];continue;\r
713                         case _OP_TAILCALL:{\r
714                                 SQObjectPtr &t = STK(arg1);\r
715                                 if (type(t) == OT_CLOSURE \r
716                                         && (!_closure(t)->_function->_bgenerator)){\r
717                                         SQObjectPtr clo = t;\r
718                                         if(_openouters) CloseOuters(&(_stack._vals[_stackbase]));\r
719                                         for (SQInteger i = 0; i < arg3; i++) STK(i) = STK(arg2 + i);\r
720                                         _GUARD(StartCall(_closure(clo), ci->_target, arg3, _stackbase, true));\r
721                                         continue;\r
722                                 }\r
723                                                           }\r
724                         case _OP_CALL: {\r
725                                         SQObjectPtr clo = STK(arg1);\r
726                                         switch (type(clo)) {\r
727                                         case OT_CLOSURE:\r
728                                                 _GUARD(StartCall(_closure(clo), sarg0, arg3, _stackbase+arg2, false));\r
729                                                 continue;\r
730                                         case OT_NATIVECLOSURE: {\r
731                                                 bool suspend;\r
732                                                 _GUARD(CallNative(_nativeclosure(clo), arg3, _stackbase+arg2, clo,suspend));\r
733                                                 if(suspend){\r
734                                                         _suspended = SQTrue;\r
735                                                         _suspended_target = sarg0;\r
736                                                         _suspended_root = ci->_root;\r
737                                                         _suspended_traps = traps;\r
738                                                         outres = clo;\r
739                                                         return true;\r
740                                                 }\r
741                                                 if(sarg0 != -1) {\r
742                                                         STK(arg0) = clo;\r
743                                                 }\r
744                                                                                    }\r
745                                                 continue;\r
746                                         case OT_CLASS:{\r
747                                                 SQObjectPtr inst;\r
748                                                 _GUARD(CreateClassInstance(_class(clo),inst,clo));\r
749                                                 if(sarg0 != -1) {\r
750                                                         STK(arg0) = inst;\r
751                                                 }\r
752                                                 SQInteger stkbase;\r
753                                                 switch(type(clo)) {\r
754                                                         case OT_CLOSURE:\r
755                                                                 stkbase = _stackbase+arg2;\r
756                                                                 _stack._vals[stkbase] = inst;\r
757                                                                 _GUARD(StartCall(_closure(clo), -1, arg3, stkbase, false));\r
758                                                                 break;\r
759                                                         case OT_NATIVECLOSURE:\r
760                                                                 bool suspend;\r
761                                                                 stkbase = _stackbase+arg2;\r
762                                                                 _stack._vals[stkbase] = inst;\r
763                                                                 _GUARD(CallNative(_nativeclosure(clo), arg3, stkbase, clo,suspend));\r
764                                                                 break;\r
765                                                         default: break; //shutup GCC 4.x\r
766                                                 }\r
767                                                 }\r
768                                                 break;\r
769                                         case OT_TABLE:\r
770                                         case OT_USERDATA:\r
771                                         case OT_INSTANCE:{\r
772                                                 SQObjectPtr closure;\r
773                                                 if(_delegable(clo)->_delegate && _delegable(clo)->GetMetaMethod(this,MT_CALL,closure)) {\r
774                                                         Push(clo);\r
775                                                         for (SQInteger i = 0; i < arg3; i++) Push(STK(arg2 + i));\r
776                                                         if(!CallMetaMethod(closure, MT_CALL, arg3+1, clo)) SQ_THROW();\r
777                                                         if(sarg0 != -1) {\r
778                                                                 STK(arg0) = clo;\r
779                                                         }\r
780                                                         break;\r
781                                                 }\r
782                                                                          \r
783                                                 //Raise_Error(_SC("attempt to call '%s'"), GetTypeName(clo));\r
784                                                 //SQ_THROW();\r
785                                           }\r
786                                         default:\r
787                                                 Raise_Error(_SC("attempt to call '%s'"), GetTypeName(clo));\r
788                                                 SQ_THROW();\r
789                                         }\r
790                                 }\r
791                                   continue;\r
792                         case _OP_PREPCALL:\r
793                         case _OP_PREPCALLK:     {\r
794                                         SQObjectPtr &key = _i_.op == _OP_PREPCALLK?(ci->_literals)[arg1]:STK(arg1);\r
795                                         SQObjectPtr &o = STK(arg2);\r
796                                         if (!Get(o, key, temp_reg,false,arg2)) {\r
797                                                 SQ_THROW();\r
798                                         }\r
799                                         STK(arg3) = o;\r
800                                         _Swap(TARGET,temp_reg);//TARGET = temp_reg;\r
801                                 }\r
802                                 continue;\r
803                         case _OP_GETK:\r
804                                 if (!Get(STK(arg2), ci->_literals[arg1], temp_reg, false,arg2)) { SQ_THROW();}\r
805                                 _Swap(TARGET,temp_reg);//TARGET = temp_reg;\r
806                                 continue;\r
807                         case _OP_MOVE: TARGET = STK(arg1); continue;\r
808                         case _OP_NEWSLOT:\r
809                                 _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),false));\r
810                                 if(arg0 != 0xFF) TARGET = STK(arg3);\r
811                                 continue;\r
812                         case _OP_DELETE: _GUARD(DeleteSlot(STK(arg1), STK(arg2), TARGET)); continue;\r
813                         case _OP_SET:\r
814                                 if (!Set(STK(arg1), STK(arg2), STK(arg3),arg1)) { SQ_THROW(); }\r
815                                 if (arg0 != 0xFF) TARGET = STK(arg3);\r
816                                 continue;\r
817                         case _OP_GET:\r
818                                 if (!Get(STK(arg1), STK(arg2), temp_reg, false,arg1)) { SQ_THROW(); }\r
819                                 _Swap(TARGET,temp_reg);//TARGET = temp_reg;\r
820                                 continue;\r
821                         case _OP_EQ:{\r
822                                 bool res;\r
823                                 if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); }\r
824                                 TARGET = res?true:false;\r
825                                 }continue;\r
826                         case _OP_NE:{ \r
827                                 bool res;\r
828                                 if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); }\r
829                                 TARGET = (!res)?true:false;\r
830                                 } continue;\r
831                         case _OP_ADD: _ARITH_(+,TARGET,STK(arg2),STK(arg1)); continue;\r
832                         case _OP_SUB: _ARITH_(-,TARGET,STK(arg2),STK(arg1)); continue;\r
833                         case _OP_MUL: _ARITH_(*,TARGET,STK(arg2),STK(arg1)); continue;\r
834                         case _OP_DIV: _ARITH_NOZERO(/,TARGET,STK(arg2),STK(arg1),_SC("division by zero")); continue;\r
835                         case _OP_MOD: ARITH_OP('%',TARGET,STK(arg2),STK(arg1)); continue;\r
836                         case _OP_BITW:  _GUARD(BW_OP( arg3,TARGET,STK(arg2),STK(arg1))); continue;\r
837                         case _OP_RETURN:\r
838                                 if((ci)->_generator) {\r
839                                         (ci)->_generator->Kill();\r
840                                 }\r
841                                 if(Return(arg0, arg1, temp_reg)){\r
842                                         assert(traps==0);\r
843                                         //outres = temp_reg;\r
844                                         _Swap(outres,temp_reg);\r
845                                         return true;\r
846                                 }\r
847                                 continue;\r
848                         case _OP_LOADNULLS:{ for(SQInt32 n=0; n < arg1; n++) STK(arg0+n).Null(); }continue;\r
849                         case _OP_LOADROOT:      TARGET = _roottable; continue;\r
850                         case _OP_LOADBOOL: TARGET = arg1?true:false; continue;\r
851                         case _OP_DMOVE: STK(arg0) = STK(arg1); STK(arg2) = STK(arg3); continue;\r
852                         case _OP_JMP: ci->_ip += (sarg1); continue;\r
853                         //case _OP_JNZ: if(!IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue;\r
854                         case _OP_JCMP: \r
855                                 _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg0),temp_reg));\r
856                                 if(IsFalse(temp_reg)) ci->_ip+=(sarg1);\r
857                                 continue;\r
858                         case _OP_JZ: if(IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue;\r
859                         case _OP_GETOUTER: {\r
860                                 SQClosure *cur_cls = _closure(ci->_closure);\r
861                                 SQOuter *otr = _outer(cur_cls->_outervalues[arg1]);\r
862                                 TARGET = *(otr->_valptr);\r
863                                 }\r
864                         continue;\r
865                         case _OP_SETOUTER: {\r
866                                 SQClosure *cur_cls = _closure(ci->_closure);\r
867                                 SQOuter   *otr = _outer(cur_cls->_outervalues[arg1]);\r
868                                 *(otr->_valptr) = STK(arg2);\r
869                                 if(arg0 != 0xFF) {\r
870                                         TARGET = STK(arg2);\r
871                                 }\r
872                                 }\r
873                         continue;\r
874                         case _OP_NEWOBJ: \r
875                                 switch(arg3) {\r
876                                         case NOT_TABLE: TARGET = SQTable::Create(_ss(this), arg1); continue;\r
877                                         case NOT_ARRAY: TARGET = SQArray::Create(_ss(this), 0); _array(TARGET)->Reserve(arg1); continue;\r
878                                         case NOT_CLASS: _GUARD(CLASS_OP(TARGET,arg1,arg2)); continue;\r
879                                         default: assert(0); continue;\r
880                                 }\r
881                         case _OP_APPENDARRAY: \r
882                                 {\r
883                                         SQObject val;\r
884                                         val._unVal.raw = 0;\r
885                                 switch(arg2) {\r
886                                 case AAT_STACK:\r
887                                         val = STK(arg1); break;\r
888                                 case AAT_LITERAL:\r
889                                         val = ci->_literals[arg1]; break;\r
890                                 case AAT_INT:\r
891                                         val._type = OT_INTEGER;\r
892 #ifndef _SQ64\r
893                                         val._unVal.nInteger = (SQInteger)arg1; \r
894 #else\r
895                                         val._unVal.nInteger = (SQInteger)((SQUnsignedInteger32)arg1);\r
896 #endif\r
897                                         break;\r
898                                 case AAT_FLOAT:\r
899                                         val._type = OT_FLOAT;\r
900                                         val._unVal.fFloat = *((SQFloat *)&arg1);\r
901                                         break;\r
902                                 case AAT_BOOL:\r
903                                         val._type = OT_BOOL;\r
904                                         val._unVal.nInteger = arg1;\r
905                                         break;\r
906                                 default: assert(0); break;\r
907 \r
908                                 }\r
909                                 _array(STK(arg0))->Append(val); continue;\r
910                                 }\r
911                         case _OP_COMPARITH: {\r
912                                 SQInteger selfidx = (((SQUnsignedInteger)arg1&0xFFFF0000)>>16);\r
913                                 _GUARD(DerefInc(arg3, TARGET, STK(selfidx), STK(arg2), STK(arg1&0x0000FFFF), false, selfidx)); \r
914                                                                 }\r
915                                 continue;\r
916                         case _OP_INC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, false, arg1));} continue;\r
917                         case _OP_INCL: {\r
918                                 SQObjectPtr &a = STK(arg1);\r
919                                 if(type(a) == OT_INTEGER) {\r
920                                         a._unVal.nInteger = _integer(a) + sarg3;\r
921                                 }\r
922                                 else {\r
923                                         SQObjectPtr o(sarg3); //_GUARD(LOCAL_INC('+',TARGET, STK(arg1), o));\r
924                                         _ARITH_(+,a,a,o);\r
925                                 }\r
926                                                    } continue;\r
927                         case _OP_PINC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, true, arg1));} continue;\r
928                         case _OP_PINCL: {\r
929                                 SQObjectPtr &a = STK(arg1);\r
930                                 if(type(a) == OT_INTEGER) {\r
931                                         TARGET = a;\r
932                                         a._unVal.nInteger = _integer(a) + sarg3;\r
933                                 }\r
934                                 else {\r
935                                         SQObjectPtr o(sarg3); _GUARD(PLOCAL_INC('+',TARGET, STK(arg1), o));\r
936                                 }\r
937                                 \r
938                                                 } continue;\r
939                         case _OP_CMP:   _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg1),TARGET))  continue;\r
940                         case _OP_EXISTS: TARGET = Get(STK(arg1), STK(arg2), temp_reg, true,DONT_FALL_BACK)?true:false;continue;\r
941                         case _OP_INSTANCEOF: \r
942                                 if(type(STK(arg1)) != OT_CLASS)\r
943                                 {Raise_Error(_SC("cannot apply instanceof between a %s and a %s"),GetTypeName(STK(arg1)),GetTypeName(STK(arg2))); SQ_THROW();}\r
944                                 TARGET = (type(STK(arg2)) == OT_INSTANCE) ? (_instance(STK(arg2))->InstanceOf(_class(STK(arg1)))?true:false) : false;\r
945                                 continue;\r
946                         case _OP_AND: \r
947                                 if(IsFalse(STK(arg2))) {\r
948                                         TARGET = STK(arg2);\r
949                                         ci->_ip += (sarg1);\r
950                                 }\r
951                                 continue;\r
952                         case _OP_OR:\r
953                                 if(!IsFalse(STK(arg2))) {\r
954                                         TARGET = STK(arg2);\r
955                                         ci->_ip += (sarg1);\r
956                                 }\r
957                                 continue;\r
958                         case _OP_NEG: _GUARD(NEG_OP(TARGET,STK(arg1))); continue;\r
959                         case _OP_NOT: TARGET = IsFalse(STK(arg1)); continue;\r
960                         case _OP_BWNOT:\r
961                                 if(type(STK(arg1)) == OT_INTEGER) {\r
962                                         SQInteger t = _integer(STK(arg1));\r
963                                         TARGET = SQInteger(~t);\r
964                                         continue;\r
965                                 }\r
966                                 Raise_Error(_SC("attempt to perform a bitwise op on a %s"), GetTypeName(STK(arg1)));\r
967                                 SQ_THROW();\r
968                         case _OP_CLOSURE: {\r
969                                 SQClosure *c = ci->_closure._unVal.pClosure;\r
970                                 SQFunctionProto *fp = c->_function;\r
971                                 if(!CLOSURE_OP(TARGET,fp->_functions[arg1]._unVal.pFunctionProto)) { SQ_THROW(); }\r
972                                 continue;\r
973                         }\r
974                         case _OP_YIELD:{\r
975                                 if(ci->_generator) {\r
976                                         if(sarg1 != MAX_FUNC_STACKSIZE) temp_reg = STK(arg1);\r
977                                         _GUARD(ci->_generator->Yield(this,arg2));\r
978                                         traps -= ci->_etraps;\r
979                                         if(sarg1 != MAX_FUNC_STACKSIZE) _Swap(STK(arg1),temp_reg);//STK(arg1) = temp_reg;\r
980                                 }\r
981                                 else { Raise_Error(_SC("trying to yield a '%s',only genenerator can be yielded"), GetTypeName(ci->_generator)); SQ_THROW();}\r
982                                 if(Return(arg0, arg1, temp_reg)){\r
983                                         assert(traps == 0);\r
984                                         outres = temp_reg;\r
985                                         return true;\r
986                                 }\r
987                                         \r
988                                 }\r
989                                 continue;\r
990                         case _OP_RESUME:\r
991                                 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
992                                 _GUARD(_generator(STK(arg1))->Resume(this, TARGET));\r
993                                 traps += ci->_etraps;\r
994                 continue;\r
995                         case _OP_FOREACH:{ int tojump;\r
996                                 _GUARD(FOREACH_OP(STK(arg0),STK(arg2),STK(arg2+1),STK(arg2+2),arg2,sarg1,tojump));\r
997                                 ci->_ip += tojump; }\r
998                                 continue;\r
999                         case _OP_POSTFOREACH:\r
1000                                 assert(type(STK(arg0)) == OT_GENERATOR);\r
1001                                 if(_generator(STK(arg0))->_state == SQGenerator::eDead) \r
1002                                         ci->_ip += (sarg1 - 1);\r
1003                                 continue;\r
1004                         case _OP_CLONE: _GUARD(Clone(STK(arg1), TARGET)); continue;\r
1005                         case _OP_TYPEOF: _GUARD(TypeOf(STK(arg1), TARGET)) continue;\r
1006                         case _OP_PUSHTRAP:{\r
1007                                 SQInstruction *_iv = _closure(ci->_closure)->_function->_instructions;\r
1008                                 _etraps.push_back(SQExceptionTrap(_top,_stackbase, &_iv[(ci->_ip-_iv)+arg1], arg0)); traps++;\r
1009                                 ci->_etraps++;\r
1010                                                           }\r
1011                                 continue;\r
1012                         case _OP_POPTRAP: {\r
1013                                 for(SQInteger i = 0; i < arg0; i++) {\r
1014                                         _etraps.pop_back(); traps--;\r
1015                                         ci->_etraps--;\r
1016                                 }\r
1017                                                           }\r
1018                                 continue;\r
1019                         case _OP_THROW: Raise_Error(TARGET); SQ_THROW(); continue;\r
1020                         case _OP_NEWSLOTA:\r
1021                                 _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
1022                                 continue;\r
1023                         case _OP_GETBASE:{\r
1024                                 SQClosure *clo = _closure(ci->_closure);\r
1025                                 if(clo->_base) {\r
1026                                         TARGET = clo->_base;\r
1027                                 }\r
1028                                 else {\r
1029                                         TARGET.Null();\r
1030                                 }\r
1031                                 continue;\r
1032                         }\r
1033                         case _OP_CLOSE:\r
1034                                 if(_openouters) CloseOuters(&(STK(arg1)));\r
1035                                 continue;\r
1036                         }\r
1037                         \r
1038                 }\r
1039         }\r
1040 exception_trap:\r
1041         {\r
1042                 SQObjectPtr currerror = _lasterror;\r
1043 //              dumpstack(_stackbase);\r
1044 //              SQInteger n = 0;\r
1045                 SQInteger last_top = _top;\r
1046                 \r
1047                 if(_ss(this)->_notifyallexceptions || (!traps && raiseerror)) CallErrorHandler(currerror);\r
1048 \r
1049                 while( ci ) {\r
1050                         if(ci->_etraps > 0) {\r
1051                                 SQExceptionTrap &et = _etraps.top();\r
1052                                 ci->_ip = et._ip;\r
1053                                 _top = et._stacksize;\r
1054                                 _stackbase = et._stackbase;\r
1055                                 _stack._vals[_stackbase + et._extarget] = currerror;\r
1056                                 _etraps.pop_back(); traps--; ci->_etraps--;\r
1057                                 while(last_top >= _top) _stack._vals[last_top--].Null();\r
1058                                 goto exception_restore;\r
1059                         }\r
1060                         else if (_debughook) { \r
1061                                         //notify debugger of a "return"\r
1062                                         //even if it really an exception unwinding the stack\r
1063                                         for(SQInteger i = 0; i < ci->_ncalls; i++) {\r
1064                                                 CallDebugHook(_SC('r'));\r
1065                                         }\r
1066                         }\r
1067                         if(ci->_generator) ci->_generator->Kill();\r
1068                         bool mustbreak = ci && ci->_root;\r
1069                         LeaveFrame();\r
1070                         if(mustbreak) break;\r
1071                 }\r
1072                                                 \r
1073                 _lasterror = currerror;\r
1074                 return false;\r
1075         }\r
1076         assert(0);\r
1077 }\r
1078 \r
1079 bool SQVM::CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor)\r
1080 {\r
1081         inst = theclass->CreateInstance();\r
1082         if(!theclass->GetConstructor(constructor)) {\r
1083                 constructor.Null();\r
1084         }\r
1085         return true;\r
1086 }\r
1087 \r
1088 void SQVM::CallErrorHandler(SQObjectPtr &error)\r
1089 {\r
1090         if(type(_errorhandler) != OT_NULL) {\r
1091                 SQObjectPtr out;\r
1092                 Push(_roottable); Push(error);\r
1093                 Call(_errorhandler, 2, _top-2, out,SQFalse);\r
1094                 Pop(2);\r
1095         }\r
1096 }\r
1097 \r
1098 \r
1099 void SQVM::CallDebugHook(SQInteger type,SQInteger forcedline)\r
1100 {\r
1101         _debughook = false;\r
1102         SQFunctionProto *func=_closure(ci->_closure)->_function;\r
1103         if(_debughook_native) {\r
1104                 const SQChar *src = type(func->_sourcename) == OT_STRING?_stringval(func->_sourcename):NULL;\r
1105                 const SQChar *fname = type(func->_name) == OT_STRING?_stringval(func->_name):NULL;\r
1106                 SQInteger line = forcedline?forcedline:func->GetLine(ci->_ip);\r
1107                 _debughook_native(this,type,src,line,fname);\r
1108         }\r
1109         else {\r
1110                 SQObjectPtr temp_reg;\r
1111                 SQInteger nparams=5;\r
1112                 Push(_roottable); Push(type); Push(func->_sourcename); Push(forcedline?forcedline:func->GetLine(ci->_ip)); Push(func->_name);\r
1113                 Call(_debughook_closure,nparams,_top-nparams,temp_reg,SQFalse);\r
1114                 Pop(nparams);\r
1115         }\r
1116         _debughook = true;\r
1117 }\r
1118 \r
1119 bool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval, bool &suspend)\r
1120 {\r
1121         SQInteger nparamscheck = nclosure->_nparamscheck;\r
1122         SQInteger newtop = newbase + nargs + nclosure->_noutervalues;\r
1123         \r
1124         if (_nnativecalls + 1 > MAX_NATIVE_CALLS) {\r
1125                 Raise_Error(_SC("Native stack overflow"));\r
1126                 return false;\r
1127         }\r
1128 \r
1129         if(nparamscheck && (((nparamscheck > 0) && (nparamscheck != nargs)) ||\r
1130                 ((nparamscheck < 0) && (nargs < (-nparamscheck)))))\r
1131         {\r
1132                 Raise_Error(_SC("wrong number of parameters"));\r
1133                 return false;\r
1134         }\r
1135 \r
1136         SQInteger tcs;\r
1137         SQIntVec &tc = nclosure->_typecheck;\r
1138         if((tcs = tc.size())) {\r
1139                 for(SQInteger i = 0; i < nargs && i < tcs; i++) {\r
1140                         if((tc._vals[i] != -1) && !(type(_stack._vals[newbase+i]) & tc._vals[i])) {\r
1141                                 Raise_ParamTypeError(i,tc._vals[i],type(_stack._vals[newbase+i]));\r
1142                                 return false;\r
1143                         }\r
1144                 }\r
1145         }\r
1146 \r
1147         if(!EnterFrame(newbase, newtop, false)) return false;\r
1148         ci->_closure  = nclosure;\r
1149 \r
1150         SQInteger outers = nclosure->_noutervalues;\r
1151         for (SQInteger i = 0; i < outers; i++) {\r
1152                 _stack._vals[newbase+nargs+i] = nclosure->_outervalues[i];\r
1153         }\r
1154         if(nclosure->_env) {\r
1155                 _stack._vals[newbase] = nclosure->_env->_obj;\r
1156         }\r
1157 \r
1158         _nnativecalls++;\r
1159         SQInteger ret = (nclosure->_function)(this);\r
1160         _nnativecalls--;\r
1161 \r
1162         suspend = false;\r
1163         if (ret == SQ_SUSPEND_FLAG) {\r
1164                 suspend = true;\r
1165         }\r
1166         else if (ret < 0) {\r
1167                 LeaveFrame();\r
1168                 Raise_Error(_lasterror);\r
1169                 return false;\r
1170         }\r
1171         if(ret) {\r
1172                 retval = _stack._vals[_top-1];\r
1173         }\r
1174         else {\r
1175                 retval.Null();\r
1176         }\r
1177         //retval = ret ? _stack._vals[_top-1] : _null_;\r
1178         LeaveFrame();\r
1179         return true;\r
1180 }\r
1181 \r
1182 #define FALLBACK_OK                     0\r
1183 #define FALLBACK_NO_MATCH       1\r
1184 #define FALLBACK_ERROR          2\r
1185 \r
1186 bool SQVM::Get(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw, SQInteger selfidx)\r
1187 {\r
1188         switch(type(self)){\r
1189         case OT_TABLE:\r
1190                 if(_table(self)->Get(key,dest))return true;\r
1191                 break;\r
1192         case OT_ARRAY:\r
1193                 if(sq_isnumeric(key)) { if(_array(self)->Get(tointeger(key),dest)) { return true; } Raise_IdxError(key); return false; }\r
1194                 break;\r
1195         case OT_INSTANCE:\r
1196                 if(_instance(self)->Get(key,dest)) return true;\r
1197                 break;\r
1198         case OT_CLASS: \r
1199                 if(_class(self)->Get(key,dest)) return true;\r
1200                 break;\r
1201         case OT_STRING:\r
1202                 if(sq_isnumeric(key)){\r
1203                         SQInteger n = tointeger(key);\r
1204                         if(abs((int)n) < _string(self)->_len) {\r
1205                                 if(n < 0) n = _string(self)->_len - n;\r
1206                                 dest = SQInteger(_stringval(self)[n]);\r
1207                                 return true;\r
1208                         }\r
1209                         Raise_IdxError(key);\r
1210                         return false;\r
1211                 }\r
1212                 break;\r
1213         default:break; //shut up compiler\r
1214         }\r
1215         if(!raw) {\r
1216                 switch(FallBackGet(self,key,dest)) {\r
1217                         case FALLBACK_OK: return true; //okie\r
1218                         case FALLBACK_NO_MATCH: break; //keep falling back\r
1219                         case FALLBACK_ERROR: return false; // the metamethod failed\r
1220                 }\r
1221                 if(InvokeDefaultDelegate(self,key,dest)) {\r
1222                         return true;\r
1223                 }\r
1224         }\r
1225 //#ifdef ROOT_FALLBACK\r
1226         if(selfidx == 0) {\r
1227                 if(_table(_roottable)->Get(key,dest)) return true;\r
1228         }\r
1229 //#endif\r
1230         Raise_IdxError(key);\r
1231         return false;\r
1232 }\r
1233 \r
1234 bool SQVM::InvokeDefaultDelegate(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest)\r
1235 {\r
1236         SQTable *ddel = NULL;\r
1237         switch(type(self)) {\r
1238                 case OT_CLASS: ddel = _class_ddel; break;\r
1239                 case OT_TABLE: ddel = _table_ddel; break;\r
1240                 case OT_ARRAY: ddel = _array_ddel; break;\r
1241                 case OT_STRING: ddel = _string_ddel; break;\r
1242                 case OT_INSTANCE: ddel = _instance_ddel; break;\r
1243                 case OT_INTEGER:case OT_FLOAT:case OT_BOOL: ddel = _number_ddel; break;\r
1244                 case OT_GENERATOR: ddel = _generator_ddel; break;\r
1245                 case OT_CLOSURE: case OT_NATIVECLOSURE: ddel = _closure_ddel; break;\r
1246                 case OT_THREAD: ddel = _thread_ddel; break;\r
1247                 case OT_WEAKREF: ddel = _weakref_ddel; break;\r
1248                 default: return false;\r
1249         }\r
1250         return  ddel->Get(key,dest);\r
1251 }\r
1252 \r
1253 \r
1254 SQInteger SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest)\r
1255 {\r
1256         switch(type(self)){\r
1257         case OT_TABLE:\r
1258         case OT_USERDATA:\r
1259         //delegation\r
1260                 if(_delegable(self)->_delegate) {\r
1261                         if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest,false,DONT_FALL_BACK)) return FALLBACK_OK;     \r
1262                 }\r
1263                 else {\r
1264                         return FALLBACK_NO_MATCH;\r
1265                 }\r
1266                 //go through\r
1267         case OT_INSTANCE: {\r
1268                 SQObjectPtr closure;\r
1269                 if(_delegable(self)->GetMetaMethod(this, MT_GET, closure)) {\r
1270                         Push(self);Push(key);\r
1271                         _nmetamethodscall++;\r
1272                         AutoDec ad(&_nmetamethodscall);\r
1273                         if(Call(closure, 2, _top - 2, dest, SQFalse)) {\r
1274                                 Pop(2);\r
1275                                 return FALLBACK_OK;\r
1276                         }\r
1277                         else {\r
1278                                 Pop(2);\r
1279                                 if(type(_lasterror) != OT_NULL) { //NULL means "clean failure" (not found)\r
1280                                         return FALLBACK_ERROR;\r
1281                                 }\r
1282                         }\r
1283                 }\r
1284                                           }\r
1285                 break;\r
1286         default: break;//shutup GCC 4.x\r
1287         }\r
1288         // no metamethod or no fallback type\r
1289         return FALLBACK_NO_MATCH;\r
1290 }\r
1291 \r
1292 bool SQVM::Set(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,SQInteger selfidx)\r
1293 {\r
1294         switch(type(self)){\r
1295         case OT_TABLE:\r
1296                 if(_table(self)->Set(key,val)) return true;\r
1297                 break;\r
1298         case OT_INSTANCE:\r
1299                 if(_instance(self)->Set(key,val)) return true;\r
1300                 break;\r
1301         case OT_ARRAY:\r
1302                 if(!sq_isnumeric(key)) { Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key)); return false; }\r
1303                 if(!_array(self)->Set(tointeger(key),val)) {\r
1304                         Raise_IdxError(key);\r
1305                         return false;\r
1306                 }\r
1307                 return true;\r
1308         default:\r
1309                 Raise_Error(_SC("trying to set '%s'"),GetTypeName(self));\r
1310                 return false;\r
1311         }\r
1312 \r
1313         switch(FallBackSet(self,key,val)) {\r
1314                 case FALLBACK_OK: return true; //okie\r
1315                 case FALLBACK_NO_MATCH: break; //keep falling back\r
1316                 case FALLBACK_ERROR: return false; // the metamethod failed\r
1317         }\r
1318         if(selfidx == 0) {\r
1319                 if(_table(_roottable)->Set(key,val))\r
1320                         return true;\r
1321         }\r
1322         Raise_IdxError(key);\r
1323         return false;\r
1324 }\r
1325 \r
1326 SQInteger SQVM::FallBackSet(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val)\r
1327 {\r
1328         switch(type(self)) {\r
1329         case OT_TABLE:\r
1330                 if(_table(self)->_delegate) {\r
1331                         if(Set(_table(self)->_delegate,key,val,DONT_FALL_BACK)) return FALLBACK_OK;\r
1332                 }\r
1333                 //keps on going\r
1334         case OT_INSTANCE:\r
1335         case OT_USERDATA:{\r
1336                 SQObjectPtr closure;\r
1337                 SQObjectPtr t;\r
1338                 if(_delegable(self)->GetMetaMethod(this, MT_SET, closure)) {\r
1339                         Push(self);Push(key);Push(val);\r
1340                         _nmetamethodscall++;\r
1341                         AutoDec ad(&_nmetamethodscall);\r
1342                         if(Call(closure, 3, _top - 3, t, SQFalse)) {\r
1343                                 Pop(3);\r
1344                                 return FALLBACK_OK;\r
1345                         }\r
1346                         else {\r
1347                                 if(type(_lasterror) != OT_NULL) { //NULL means "clean failure" (not found)\r
1348                                         //error\r
1349                                         Pop(3);\r
1350                                         return FALLBACK_ERROR;\r
1351                                 }\r
1352                         }\r
1353                 }\r
1354                                          }\r
1355                 break;\r
1356                 default: break;//shutup GCC 4.x\r
1357         }\r
1358         // no metamethod or no fallback type\r
1359         return FALLBACK_NO_MATCH;\r
1360 }\r
1361 \r
1362 bool SQVM::Clone(const SQObjectPtr &self,SQObjectPtr &target)\r
1363 {\r
1364         SQObjectPtr temp_reg;\r
1365         SQObjectPtr newobj;\r
1366         switch(type(self)){\r
1367         case OT_TABLE:\r
1368                 newobj = _table(self)->Clone();\r
1369                 goto cloned_mt;\r
1370         case OT_INSTANCE: {\r
1371                 newobj = _instance(self)->Clone(_ss(this));\r
1372 cloned_mt:\r
1373                 SQObjectPtr closure;\r
1374                 if(_delegable(newobj)->_delegate && _delegable(newobj)->GetMetaMethod(this,MT_CLONED,closure)) {\r
1375                         Push(newobj);\r
1376                         Push(self);\r
1377                         if(!CallMetaMethod(closure,MT_CLONED,2,temp_reg))\r
1378                                 return false;\r
1379                 }\r
1380                 }\r
1381                 target = newobj;\r
1382                 return true;\r
1383         case OT_ARRAY: \r
1384                 target = _array(self)->Clone();\r
1385                 return true;\r
1386         default: \r
1387                 Raise_Error(_SC("cloning a %s"), GetTypeName(self));\r
1388                 return false;\r
1389         }\r
1390 }\r
1391 \r
1392 bool SQVM::NewSlotA(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,const SQObjectPtr &attrs,bool bstatic,bool raw)\r
1393 {\r
1394         if(type(self) != OT_CLASS) {\r
1395                 Raise_Error(_SC("object must be a class"));\r
1396                 return false;\r
1397         }\r
1398         SQClass *c = _class(self);\r
1399         if(!raw) {\r
1400                 SQObjectPtr &mm = c->_metamethods[MT_NEWMEMBER];\r
1401                 if(type(mm) != OT_NULL ) {\r
1402                         Push(self); Push(key); Push(val);\r
1403                         Push(attrs);\r
1404                         Push(bstatic);\r
1405                         return CallMetaMethod(mm,MT_NEWMEMBER,5,temp_reg);\r
1406                 }\r
1407         }\r
1408         if(!NewSlot(self, key, val,bstatic))\r
1409                 return false;\r
1410         if(type(attrs) != OT_NULL) {\r
1411                 c->SetAttributes(key,attrs);\r
1412         }\r
1413         return true;\r
1414 }\r
1415 \r
1416 bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic)\r
1417 {\r
1418         if(type(key) == OT_NULL) { Raise_Error(_SC("null cannot be used as index")); return false; }\r
1419         switch(type(self)) {\r
1420         case OT_TABLE: {\r
1421                 bool rawcall = true;\r
1422                 if(_table(self)->_delegate) {\r
1423                         SQObjectPtr res;\r
1424                         if(!_table(self)->Get(key,res)) {\r
1425                                 SQObjectPtr closure;\r
1426                                 if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_NEWSLOT,closure)) {\r
1427                                         Push(self);Push(key);Push(val);\r
1428                                         if(!CallMetaMethod(closure,MT_NEWSLOT,3,res)) {\r
1429                                                 return false;\r
1430                                         }\r
1431                                         rawcall = false;\r
1432                                 }\r
1433                                 else {\r
1434                                         rawcall = true;\r
1435                                 }\r
1436                         }\r
1437                 }\r
1438                 if(rawcall) _table(self)->NewSlot(key,val); //cannot fail\r
1439                 \r
1440                 break;}\r
1441         case OT_INSTANCE: {\r
1442                 SQObjectPtr res;\r
1443                 SQObjectPtr closure;\r
1444                 if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_NEWSLOT,closure)) {\r
1445                         Push(self);Push(key);Push(val);\r
1446                         if(!CallMetaMethod(closure,MT_NEWSLOT,3,res)) {\r
1447                                 return false;\r
1448                         }\r
1449                         break;\r
1450                 }\r
1451                 Raise_Error(_SC("class instances do not support the new slot operator"));\r
1452                 return false;\r
1453                 break;}\r
1454         case OT_CLASS: \r
1455                 if(!_class(self)->NewSlot(_ss(this),key,val,bstatic)) {\r
1456                         if(_class(self)->_locked) {\r
1457                                 Raise_Error(_SC("trying to modify a class that has already been instantiated"));\r
1458                                 return false;\r
1459                         }\r
1460                         else {\r
1461                                 SQObjectPtr oval = PrintObjVal(key);\r
1462                                 Raise_Error(_SC("the property '%s' already exists"),_stringval(oval));\r
1463                                 return false;\r
1464                         }\r
1465                 }\r
1466                 break;\r
1467         default:\r
1468                 Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key));\r
1469                 return false;\r
1470                 break;\r
1471         }\r
1472         return true;\r
1473 }\r
1474 \r
1475 \r
1476 \r
1477 bool SQVM::DeleteSlot(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &res)\r
1478 {\r
1479         switch(type(self)) {\r
1480         case OT_TABLE:\r
1481         case OT_INSTANCE:\r
1482         case OT_USERDATA: {\r
1483                 SQObjectPtr t;\r
1484                 //bool handled = false;\r
1485                 SQObjectPtr closure;\r
1486                 if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_DELSLOT,closure)) {\r
1487                         Push(self);Push(key);\r
1488                         return CallMetaMethod(closure,MT_DELSLOT,2,res);\r
1489                 }\r
1490                 else {\r
1491                         if(type(self) == OT_TABLE) {\r
1492                                 if(_table(self)->Get(key,t)) {\r
1493                                         _table(self)->Remove(key);\r
1494                                 }\r
1495                                 else {\r
1496                                         Raise_IdxError((SQObject &)key);\r
1497                                         return false;\r
1498                                 }\r
1499                         }\r
1500                         else {\r
1501                                 Raise_Error(_SC("cannot delete a slot from %s"),GetTypeName(self));\r
1502                                 return false;\r
1503                         }\r
1504                 }\r
1505                 res = t;\r
1506                                 }\r
1507                 break;\r
1508         default:\r
1509                 Raise_Error(_SC("attempt to delete a slot from a %s"),GetTypeName(self));\r
1510                 return false;\r
1511         }\r
1512         return true;\r
1513 }\r
1514 \r
1515 bool SQVM::Call(SQObjectPtr &closure,SQInteger nparams,SQInteger stackbase,SQObjectPtr &outres,SQBool raiseerror)\r
1516 {\r
1517 #ifdef _DEBUG\r
1518 SQInteger prevstackbase = _stackbase;\r
1519 #endif\r
1520         switch(type(closure)) {\r
1521         case OT_CLOSURE:\r
1522                 return Execute(closure, nparams, stackbase, outres, raiseerror);\r
1523                 break;\r
1524         case OT_NATIVECLOSURE:{\r
1525                 bool suspend;\r
1526                 return CallNative(_nativeclosure(closure), nparams, stackbase, outres,suspend);\r
1527                 \r
1528                                                   }\r
1529                 break;\r
1530         case OT_CLASS: {\r
1531                 SQObjectPtr constr;\r
1532                 SQObjectPtr temp;\r
1533                 CreateClassInstance(_class(closure),outres,constr);\r
1534                 if(type(constr) != OT_NULL) {\r
1535                         _stack[stackbase] = outres;\r
1536                         return Call(constr,nparams,stackbase,temp,raiseerror);\r
1537                 }\r
1538                 return true;\r
1539                                    }\r
1540                 break;\r
1541         default:\r
1542                 return false;\r
1543         }\r
1544 #ifdef _DEBUG\r
1545         if(!_suspended) {\r
1546                 assert(_stackbase == prevstackbase);\r
1547         }\r
1548 #endif\r
1549         return true;\r
1550 }\r
1551 \r
1552 bool SQVM::CallMetaMethod(SQObjectPtr &closure,SQMetaMethod mm,SQInteger nparams,SQObjectPtr &outres)\r
1553 {\r
1554         //SQObjectPtr closure;\r
1555         \r
1556         _nmetamethodscall++;\r
1557         if(Call(closure, nparams, _top - nparams, outres, SQFalse)) {\r
1558                 _nmetamethodscall--;\r
1559                 Pop(nparams);\r
1560                 return true;\r
1561         }\r
1562         _nmetamethodscall--;\r
1563         //}\r
1564         Pop(nparams);\r
1565         return false;\r
1566 }\r
1567 \r
1568 void SQVM::FindOuter(SQObjectPtr &target, SQObjectPtr *stackindex)\r
1569 {\r
1570         SQOuter **pp = &_openouters;\r
1571         SQOuter *p;\r
1572         SQOuter *otr;\r
1573 \r
1574         while ((p = *pp) != NULL && p->_valptr >= stackindex) {\r
1575                 if (p->_valptr == stackindex) {\r
1576                         target = SQObjectPtr(p);\r
1577                         return;\r
1578                 }\r
1579                 pp = &p->_next;\r
1580         }\r
1581         otr = SQOuter::Create(_ss(this), stackindex);\r
1582         otr->_next = *pp;\r
1583         otr->_idx  = (stackindex - _stack._vals);\r
1584         __ObjAddRef(otr);\r
1585         *pp = otr;\r
1586         target = SQObjectPtr(otr);\r
1587 }\r
1588 \r
1589 bool SQVM::EnterFrame(SQInteger newbase, SQInteger newtop, bool tailcall)\r
1590 {\r
1591         if( !tailcall ) {\r
1592                 if( _callsstacksize == _alloccallsstacksize ) {\r
1593                         GrowCallStack();\r
1594                 }\r
1595                 ci = &_callsstack[_callsstacksize++];\r
1596                 ci->_prevstkbase = (SQInt32)(newbase - _stackbase);\r
1597                 ci->_prevtop = (SQInt32)(_top - _stackbase);\r
1598                 ci->_etraps = 0;\r
1599                 ci->_ncalls = 1;\r
1600                 ci->_generator = NULL;\r
1601                 ci->_root = SQFalse;\r
1602         }\r
1603         else {\r
1604                 ci->_ncalls++;\r
1605         }\r
1606 \r
1607         _stackbase = newbase;\r
1608         _top = newtop;\r
1609         if(newtop + MIN_STACK_OVERHEAD > (SQInteger)_stack.size()) {\r
1610                 if(_nmetamethodscall) {\r
1611                         Raise_Error(_SC("stack overflow, cannot resize stack while in  a metamethod"));\r
1612                         return false;\r
1613                 }\r
1614                 _stack.resize(_stack.size() + (MIN_STACK_OVERHEAD << 2));\r
1615                 RelocateOuters();\r
1616         }\r
1617         return true;\r
1618 }\r
1619 \r
1620 void SQVM::LeaveFrame() {\r
1621         SQInteger last_top = _top;\r
1622         SQInteger last_stackbase = _stackbase;\r
1623         SQInteger css = --_callsstacksize;\r
1624 \r
1625         /* First clean out the call stack frame */\r
1626         ci->_closure.Null();\r
1627         _stackbase -= ci->_prevstkbase;\r
1628         _top = _stackbase + ci->_prevtop;\r
1629         ci = (css) ? &_callsstack[css-1] : NULL;\r
1630 \r
1631         if(_openouters) CloseOuters(&(_stack._vals[last_stackbase]));\r
1632         while (last_top >= _top) {\r
1633                 _stack._vals[last_top--].Null();\r
1634         }\r
1635 }\r
1636 \r
1637 void SQVM::RelocateOuters()\r
1638 {\r
1639         SQOuter *p = _openouters;\r
1640         while (p) {\r
1641                 p->_valptr = _stack._vals + p->_idx;\r
1642                 p = p->_next;\r
1643         }\r
1644 }\r
1645 \r
1646 void SQVM::CloseOuters(SQObjectPtr *stackindex) {\r
1647   SQOuter *p;\r
1648   while ((p = _openouters) != NULL && p->_valptr >= stackindex) {\r
1649     p->_value = *(p->_valptr);\r
1650     p->_valptr = &p->_value;\r
1651     _openouters = p->_next;\r
1652         __ObjRelease(p);\r
1653   }\r
1654 }\r
1655 \r
1656 void SQVM::Remove(SQInteger n) {\r
1657         n = (n >= 0)?n + _stackbase - 1:_top + n;\r
1658         for(SQInteger i = n; i < _top; i++){\r
1659                 _stack[i] = _stack[i+1];\r
1660         }\r
1661         _stack[_top].Null();\r
1662         _top--;\r
1663 }\r
1664 \r
1665 void SQVM::Pop() {\r
1666         _stack[--_top].Null();\r
1667 }\r
1668 \r
1669 void SQVM::Pop(SQInteger n) {\r
1670         for(SQInteger i = 0; i < n; i++){\r
1671                 _stack[--_top].Null();\r
1672         }\r
1673 }\r
1674 \r
1675 void SQVM::PushNull() { _stack[_top++].Null(); }\r
1676 void SQVM::Push(const SQObjectPtr &o) { _stack[_top++] = o; }\r
1677 SQObjectPtr &SQVM::Top() { return _stack[_top-1]; }\r
1678 SQObjectPtr &SQVM::PopGet() { return _stack[--_top]; }\r
1679 SQObjectPtr &SQVM::GetUp(SQInteger n) { return _stack[_top+n]; }\r
1680 SQObjectPtr &SQVM::GetAt(SQInteger n) { return _stack[n]; }\r
1681 \r
1682 #ifdef _DEBUG_DUMP\r
1683 void SQVM::dumpstack(SQInteger stackbase,bool dumpall)\r
1684 {\r
1685         SQInteger size=dumpall?_stack.size():_top;\r
1686         SQInteger n=0;\r
1687         scprintf(_SC("\n>>>>stack dump<<<<\n"));\r
1688         CallInfo &ci=_callsstack[_callsstacksize-1];\r
1689         scprintf(_SC("IP: %p\n"),ci._ip);\r
1690         scprintf(_SC("prev stack base: %d\n"),ci._prevstkbase);\r
1691         scprintf(_SC("prev top: %d\n"),ci._prevtop);\r
1692         for(SQInteger i=0;i<size;i++){\r
1693                 SQObjectPtr &obj=_stack[i];     \r
1694                 if(stackbase==i)scprintf(_SC(">"));else scprintf(_SC(" "));\r
1695                 scprintf(_SC("[%d]:"),n);\r
1696                 switch(type(obj)){\r
1697                 case OT_FLOAT:                  scprintf(_SC("FLOAT %.3f"),_float(obj));break;\r
1698                 case OT_INTEGER:                scprintf(_SC("INTEGER %d"),_integer(obj));break;\r
1699                 case OT_BOOL:                   scprintf(_SC("BOOL %s"),_integer(obj)?"true":"false");break;\r
1700                 case OT_STRING:                 scprintf(_SC("STRING %s"),_stringval(obj));break;\r
1701                 case OT_NULL:                   scprintf(_SC("NULL"));  break;\r
1702                 case OT_TABLE:                  scprintf(_SC("TABLE %p[%p]"),_table(obj),_table(obj)->_delegate);break;\r
1703                 case OT_ARRAY:                  scprintf(_SC("ARRAY %p"),_array(obj));break;\r
1704                 case OT_CLOSURE:                scprintf(_SC("CLOSURE [%p]"),_closure(obj));break;\r
1705                 case OT_NATIVECLOSURE:  scprintf(_SC("NATIVECLOSURE"));break;\r
1706                 case OT_USERDATA:               scprintf(_SC("USERDATA %p[%p]"),_userdataval(obj),_userdata(obj)->_delegate);break;\r
1707                 case OT_GENERATOR:              scprintf(_SC("GENERATOR %p"),_generator(obj));break;\r
1708                 case OT_THREAD:                 scprintf(_SC("THREAD [%p]"),_thread(obj));break;\r
1709                 case OT_USERPOINTER:    scprintf(_SC("USERPOINTER %p"),_userpointer(obj));break;\r
1710                 case OT_CLASS:                  scprintf(_SC("CLASS %p"),_class(obj));break;\r
1711                 case OT_INSTANCE:               scprintf(_SC("INSTANCE %p"),_instance(obj));break;\r
1712                 case OT_WEAKREF:                scprintf(_SC("WEAKERF %p"),_weakref(obj));break;\r
1713                 default:\r
1714                         assert(0);\r
1715                         break;\r
1716                 };\r
1717                 scprintf(_SC("\n"));\r
1718                 ++n;\r
1719         }\r
1720 }\r
1721 \r
1722 \r
1723 \r
1724 #endif\r