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