00001
00002
00003
00004 #include <squirrel.h>
00005 #include "sqpcheader.h"
00006 #include <math.h>
00007 #include <stdlib.h>
00008 #include "sqopcodes.h"
00009 #include "sqfuncproto.h"
00010 #include "sqvm.h"
00011 #include "sqclosure.h"
00012 #include "sqstring.h"
00013 #include "sqtable.h"
00014 #include "squserdata.h"
00015 #include "sqarray.h"
00016 #include "sqclass.h"
00017
00018 #define TOP() (_stack._vals[_top-1])
00019
00020 bool SQVM::BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2)
00021 {
00022 SQInteger res;
00023 SQInteger i1 = _integer(o1), i2 = _integer(o2);
00024 if((type(o1)==OT_INTEGER) && (type(o2)==OT_INTEGER))
00025 {
00026 switch(op) {
00027 case BW_AND: res = i1 & i2; break;
00028 case BW_OR: res = i1 | i2; break;
00029 case BW_XOR: res = i1 ^ i2; break;
00030 case BW_SHIFTL: res = i1 << i2; break;
00031 case BW_SHIFTR: res = i1 >> i2; break;
00032 case BW_USHIFTR:res = (SQInteger)(*((SQUnsignedInteger*)&i1) >> i2); break;
00033 default: { Raise_Error(_SC("internal vm error bitwise op failed")); return false; }
00034 }
00035 }
00036 else { Raise_Error(_SC("bitwise op between '%s' and '%s'"),GetTypeName(o1),GetTypeName(o2)); return false;}
00037 trg = res;
00038 return true;
00039 }
00040
00041 bool SQVM::ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2)
00042 {
00043 if(sq_isnumeric(o1) && sq_isnumeric(o2)) {
00044 if((type(o1)==OT_INTEGER) && (type(o2)==OT_INTEGER)) {
00045 SQInteger res, i1 = _integer(o1), i2 = _integer(o2);
00046 switch(op) {
00047 case '+': res = i1 + i2; break;
00048 case '-': res = i1 - i2; break;
00049 case '/': if(i2 == 0) { Raise_Error(_SC("division by zero")); return false; }
00050 res = i1 / i2;
00051 break;
00052 case '*': res = i1 * i2; break;
00053 case '%': if(i2 == 0) { Raise_Error(_SC("modulo by zero")); return false; }
00054 res = i1 % i2;
00055 break;
00056 default: res = 0xDEADBEEF;
00057 }
00058 trg = res;
00059 }else{
00060 SQFloat res, f1 = tofloat(o1), f2 = tofloat(o2);
00061 switch(op) {
00062 case '+': res = f1 + f2; break;
00063 case '-': res = f1 - f2; break;
00064 case '/': res = f1 / f2; break;
00065 case '*': res = f1 * f2; break;
00066 case '%': res = SQFloat(fmod((double)f1,(double)f2)); break;
00067 default: res = 0x0f;
00068 }
00069 trg = res;
00070 }
00071 } else {
00072 if(op == '+' && (type(o1) == OT_STRING || type(o2) == OT_STRING)){
00073 if(!StringCat(o1, o2, trg)) return false;
00074 }
00075 else if(!ArithMetaMethod(op,o1,o2,trg)) {
00076 Raise_Error(_SC("arith op %c on between '%s' and '%s'"),op,GetTypeName(o1),GetTypeName(o2)); return false;
00077 }
00078 }
00079 return true;
00080 }
00081
00082 SQVM::SQVM(SQSharedState *ss)
00083 {
00084 _sharedstate=ss;
00085 _suspended = SQFalse;
00086 _suspended_target=-1;
00087 _suspended_root = SQFalse;
00088 _suspended_traps=0;
00089 _foreignptr=NULL;
00090 _nnativecalls=0;
00091 _lasterror = _null_;
00092 _errorhandler = _null_;
00093 _debughook = _null_;
00094 _can_suspend = false;
00095 _ops_till_suspend = 0;
00096 ci = NULL;
00097 INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);
00098 }
00099
00100 void SQVM::Finalize()
00101 {
00102 _roottable = _null_;
00103 _lasterror = _null_;
00104 _errorhandler = _null_;
00105 _debughook = _null_;
00106 temp_reg = _null_;
00107 _callstackdata.resize(0);
00108 SQInteger size=_stack.size();
00109 for(SQInteger i=size - 1;i>=0;i--)
00110 _stack[i]=_null_;
00111 }
00112
00113 SQVM::~SQVM()
00114 {
00115 Finalize();
00116
00117 REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);
00118 }
00119
00120 bool SQVM::ArithMetaMethod(SQInteger op,const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &dest)
00121 {
00122 SQMetaMethod mm;
00123 switch(op){
00124 case _SC('+'): mm=MT_ADD; break;
00125 case _SC('-'): mm=MT_SUB; break;
00126 case _SC('/'): mm=MT_DIV; break;
00127 case _SC('*'): mm=MT_MUL; break;
00128 case _SC('%'): mm=MT_MODULO; break;
00129 default: mm = MT_ADD; assert(0); break;
00130 }
00131 if(is_delegable(o1) && _delegable(o1)->_delegate) {
00132 Push(o1);Push(o2);
00133 return CallMetaMethod(_delegable(o1),mm,2,dest);
00134 }
00135 return false;
00136 }
00137
00138 bool SQVM::NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o)
00139 {
00140
00141 switch(type(o)) {
00142 case OT_INTEGER:
00143 trg = -_integer(o);
00144 return true;
00145 case OT_FLOAT:
00146 trg = -_float(o);
00147 return true;
00148 case OT_TABLE:
00149 case OT_USERDATA:
00150 case OT_INSTANCE:
00151 if(_delegable(o)->_delegate) {
00152 Push(o);
00153 if(CallMetaMethod(_delegable(o), MT_UNM, 1, temp_reg)) {
00154 trg = temp_reg;
00155 return true;
00156 }
00157 }
00158 default:break;
00159 }
00160 Raise_Error(_SC("attempt to negate a %s"), GetTypeName(o));
00161 return false;
00162 }
00163
00164 #define _RET_SUCCEED(exp) { result = (exp); return true; }
00165 bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result)
00166 {
00167 if(type(o1)==type(o2)){
00168 if(_userpointer(o1)==_userpointer(o2))_RET_SUCCEED(0);
00169 SQObjectPtr res;
00170 switch(type(o1)){
00171 case OT_STRING:
00172 _RET_SUCCEED(scstrcmp(_stringval(o1),_stringval(o2)));
00173 case OT_INTEGER:
00174 _RET_SUCCEED(_integer(o1)-_integer(o2));
00175 case OT_FLOAT:
00176 _RET_SUCCEED((_float(o1)<_float(o2))?-1:1);
00177 case OT_TABLE:
00178 case OT_USERDATA:
00179 case OT_INSTANCE:
00180 if(_delegable(o1)->_delegate) {
00181 Push(o1);Push(o2);
00182 if(CallMetaMethod(_delegable(o1),MT_CMP,2,res)) break;
00183 }
00184
00185 default:
00186 _RET_SUCCEED( _userpointer(o1) < _userpointer(o2)?-1:1 );
00187 }
00188 if(type(res)!=OT_INTEGER) { Raise_CompareError(o1,o2); return false; }
00189 _RET_SUCCEED(_integer(res));
00190
00191 }
00192 else{
00193 if(sq_isnumeric(o1) && sq_isnumeric(o2)){
00194 if((type(o1)==OT_INTEGER) && (type(o2)==OT_FLOAT)) {
00195 if( _integer(o1)==_float(o2) ) { _RET_SUCCEED(0); }
00196 else if( _integer(o1)<_float(o2) ) { _RET_SUCCEED(-1); }
00197 _RET_SUCCEED(1);
00198 }
00199 else{
00200 if( _float(o1)==_integer(o2) ) { _RET_SUCCEED(0); }
00201 else if( _float(o1)<_integer(o2) ) { _RET_SUCCEED(-1); }
00202 _RET_SUCCEED(1);
00203 }
00204 }
00205 else if(type(o1)==OT_NULL) {_RET_SUCCEED(-1);}
00206 else if(type(o2)==OT_NULL) {_RET_SUCCEED(1);}
00207 else { Raise_CompareError(o1,o2); return false; }
00208
00209 }
00210 assert(0);
00211 _RET_SUCCEED(0);
00212 }
00213
00214 bool SQVM::CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res)
00215 {
00216 SQInteger r;
00217 if(ObjCmp(o1,o2,r)) {
00218 switch(op) {
00219 case CMP_G: res = (r > 0)?_true_:_false_; return true;
00220 case CMP_GE: res = (r >= 0)?_true_:_false_; return true;
00221 case CMP_L: res = (r < 0)?_true_:_false_; return true;
00222 case CMP_LE: res = (r <= 0)?_true_:_false_; return true;
00223
00224 }
00225 assert(0);
00226 }
00227 return false;
00228 }
00229
00230 void SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res)
00231 {
00232 switch(type(o)) {
00233 case OT_STRING:
00234 res = o;
00235 return;
00236 case OT_FLOAT:
00237 scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)),_SC("%g"),_float(o));
00238 break;
00239 case OT_INTEGER:
00240 #if defined(_SQ64)
00241 scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)),_SC("%ld"),_integer(o));
00242 #else
00243 scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)),_SC("%d"),_integer(o));
00244 #endif
00245 break;
00246 case OT_BOOL:
00247 scsprintf(_sp(rsl(6)),_integer(o)?_SC("true"):_SC("false"));
00248 break;
00249 case OT_TABLE:
00250 case OT_USERDATA:
00251 case OT_INSTANCE:
00252 if(_delegable(o)->_delegate) {
00253 Push(o);
00254 if(CallMetaMethod(_delegable(o),MT_TOSTRING,1,res)) {
00255 if(type(res) == OT_STRING)
00256 return;
00257
00258 }
00259 }
00260 default:
00261 scsprintf(_sp(rsl(sizeof(void*)+20)),_SC("(%s : 0x%p)"),GetTypeName(o),(void*)_rawval(o));
00262 }
00263 res = SQString::Create(_ss(this),_spval);
00264 }
00265
00266
00267 bool SQVM::StringCat(const SQObjectPtr &str,const SQObjectPtr &obj,SQObjectPtr &dest)
00268 {
00269 SQObjectPtr a, b;
00270 ToString(str, a);
00271 ToString(obj, b);
00272 SQInteger l = _string(a)->_len , ol = _string(b)->_len;
00273 SQChar *s = _sp(rsl(l + ol + 1));
00274 memcpy(s, _stringval(a), rsl(l));
00275 memcpy(s + l, _stringval(b), rsl(ol));
00276 dest = SQString::Create(_ss(this), _spval, l + ol);
00277 return true;
00278 }
00279
00280 void SQVM::TypeOf(const SQObjectPtr &obj1,SQObjectPtr &dest)
00281 {
00282 if(is_delegable(obj1) && _delegable(obj1)->_delegate) {
00283 Push(obj1);
00284 if(CallMetaMethod(_delegable(obj1),MT_TYPEOF,1,dest))
00285 return;
00286 }
00287 dest = SQString::Create(_ss(this),GetTypeName(obj1));
00288 }
00289
00290 bool SQVM::Init(SQVM *friendvm, SQInteger stacksize)
00291 {
00292 _stack.resize(stacksize);
00293
00294 _alloccallsstacksize = 4;
00295 _callstackdata.resize(_alloccallsstacksize);
00296 _callsstacksize = 0;
00297 _callsstack = &_callstackdata[0];
00298
00299 _stackbase = 0;
00300 _top = 0;
00301 if(!friendvm)
00302 _roottable = SQTable::Create(_ss(this), 0);
00303 else {
00304 _roottable = friendvm->_roottable;
00305 _errorhandler = friendvm->_errorhandler;
00306 _debughook = friendvm->_debughook;
00307 }
00308
00309 sq_base_register(this);
00310 return true;
00311 }
00312
00313 extern SQInstructionDesc g_InstrDesc[];
00314
00315 bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger args,SQInteger stackbase,bool tailcall)
00316 {
00317 SQFunctionProto *func = _funcproto(closure->_function);
00318
00319 const SQInteger paramssize = func->_nparameters;
00320 const SQInteger newtop = stackbase + func->_stacksize;
00321 SQInteger nargs = args;
00322 if (paramssize != nargs) {
00323 SQInteger ndef = func->_ndefaultparams;
00324 if(ndef && nargs < paramssize) {
00325 SQInteger diff = paramssize - nargs;
00326 if (diff > ndef) {
00327 Raise_Error(_SC("wrong number of parameters"));
00328 return false;
00329 }
00330 for(SQInteger n = ndef - diff; n < ndef; n++) {
00331 _stack._vals[stackbase + (nargs++)] = closure->_defaultparams[n];
00332 }
00333 }
00334 else if(func->_varparams)
00335 {
00336 if (nargs < paramssize) {
00337 Raise_Error(_SC("wrong number of parameters"));
00338 return false;
00339 }
00340 for(SQInteger n = 0; n < nargs - paramssize; n++) {
00341 _vargsstack.push_back(_stack._vals[stackbase+paramssize+n]);
00342 _stack._vals[stackbase+paramssize+n] = _null_;
00343 }
00344 }
00345 else {
00346 Raise_Error(_SC("wrong number of parameters"));
00347 return false;
00348 }
00349 }
00350
00351 if(type(closure->_env) == OT_WEAKREF) {
00352 _stack._vals[stackbase] = _weakref(closure->_env)->_obj;
00353 }
00354
00355 if (!tailcall) {
00356 CallInfo lc;
00357 memset(&lc, 0, sizeof(lc));
00358 lc._generator = NULL;
00359 lc._etraps = 0;
00360 lc._prevstkbase = (SQInt32) ( stackbase - _stackbase );
00361 lc._target = (SQInt32) target;
00362 lc._prevtop = (SQInt32) (_top - _stackbase);
00363 lc._ncalls = 1;
00364 lc._root = SQFalse;
00365 PUSH_CALLINFO(this, lc);
00366 }
00367 else {
00368 ci->_ncalls++;
00369 }
00370 ci->_vargs.size = (SQInt32)(nargs - paramssize);
00371 ci->_vargs.base = (SQInt32)(_vargsstack.size()-(ci->_vargs.size));
00372 ci->_closure = closure;
00373 ci->_literals = func->_literals;
00374 ci->_ip = func->_instructions;
00375
00376 if (((SQUnsignedInteger)newtop + (func->_stacksize<<1)) > _stack.size()) {
00377 _stack.resize(_stack.size() + (func->_stacksize<<1));
00378 }
00379
00380 _top = newtop;
00381 _stackbase = stackbase;
00382 if (type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure))
00383 CallDebugHook(_SC('c'));
00384 return true;
00385 }
00386
00387 bool SQVM::Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval)
00388 {
00389 if (type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure))
00390 for(SQInteger i=0;i<ci->_ncalls;i++)
00391 CallDebugHook(_SC('r'));
00392
00393 SQBool broot = ci->_root;
00394 SQInteger last_top = _top;
00395 SQInteger target = ci->_target;
00396 SQInteger oldstackbase = _stackbase;
00397 _stackbase -= ci->_prevstkbase;
00398 _top = _stackbase + ci->_prevtop;
00399 if(ci->_vargs.size) PopVarArgs(ci->_vargs);
00400 POP_CALLINFO(this);
00401 if (broot) {
00402 if (_arg0 != MAX_FUNC_STACKSIZE) retval = _stack._vals[oldstackbase+_arg1];
00403 else retval = _null_;
00404 }
00405 else {
00406 if(target != -1) {
00407 if (_arg0 != MAX_FUNC_STACKSIZE)
00408 STK(target) = _stack._vals[oldstackbase+_arg1];
00409 else
00410 STK(target) = _null_;
00411 }
00412 }
00413
00414 while (last_top > oldstackbase) _stack._vals[last_top--].Null();
00415 assert(oldstackbase >= _stackbase);
00416 return broot?true:false;
00417 }
00418
00419 #define _RET_ON_FAIL(exp) { if(!exp) return false; }
00420
00421 bool SQVM::LOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr)
00422 {
00423 _RET_ON_FAIL(ARITH_OP( op , target, a, incr));
00424 a = target;
00425 return true;
00426 }
00427
00428 bool SQVM::PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr)
00429 {
00430 SQObjectPtr trg;
00431 _RET_ON_FAIL(ARITH_OP( op , trg, a, incr));
00432 target = a;
00433 a = trg;
00434 return true;
00435 }
00436
00437 bool SQVM::DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix)
00438 {
00439 SQObjectPtr tmp, tself = self, tkey = key;
00440 if (!Get(tself, tkey, tmp, false, true)) { Raise_IdxError(tkey); return false; }
00441 _RET_ON_FAIL(ARITH_OP( op , target, tmp, incr))
00442 Set(tself, tkey, target,true);
00443 if (postfix) target = tmp;
00444 return true;
00445 }
00446
00447 #define arg0 (_i_._arg0)
00448 #define arg1 (_i_._arg1)
00449 #define sarg1 (*((SQInt32 *)&_i_._arg1))
00450 #define arg2 (_i_._arg2)
00451 #define arg3 (_i_._arg3)
00452 #define sarg3 ((SQInteger)*((signed char *)&_i_._arg3))
00453
00454 SQRESULT SQVM::Suspend()
00455 {
00456 if (_suspended)
00457 return sq_throwerror(this, _SC("cannot suspend an already suspended vm"));
00458 if (_nnativecalls!=2)
00459 return sq_throwerror(this, _SC("cannot suspend through native calls/metamethods"));
00460 return SQ_SUSPEND_FLAG;
00461 }
00462
00463 void SQVM::PopVarArgs(VarArgs &vargs)
00464 {
00465 for(SQInteger n = 0; n< vargs.size; n++)
00466 _vargsstack.pop_back();
00467 }
00468
00469 #define _FINISH(howmuchtojump) {jump = howmuchtojump; return true; }
00470 bool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr
00471 &o3,SQObjectPtr &o4,SQInteger arg_2,int exitpos,int &jump)
00472 {
00473 SQInteger nrefidx;
00474 switch(type(o1)) {
00475 case OT_TABLE:
00476 if((nrefidx = _table(o1)->Next(false,o4, o2, o3)) == -1) _FINISH(exitpos);
00477 o4 = (SQInteger)nrefidx; _FINISH(1);
00478 case OT_ARRAY:
00479 if((nrefidx = _array(o1)->Next(o4, o2, o3)) == -1) _FINISH(exitpos);
00480 o4 = (SQInteger) nrefidx; _FINISH(1);
00481 case OT_STRING:
00482 if((nrefidx = _string(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos);
00483 o4 = (SQInteger)nrefidx; _FINISH(1);
00484 case OT_CLASS:
00485 if((nrefidx = _class(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos);
00486 o4 = (SQInteger)nrefidx; _FINISH(1);
00487 case OT_USERDATA:
00488 case OT_INSTANCE:
00489 if(_delegable(o1)->_delegate) {
00490 SQObjectPtr itr;
00491 Push(o1);
00492 Push(o4);
00493 if(CallMetaMethod(_delegable(o1), MT_NEXTI, 2, itr)){
00494 o4 = o2 = itr;
00495 if(type(itr) == OT_NULL) _FINISH(exitpos);
00496 if(!Get(o1, itr, o3, false,false)) {
00497 Raise_Error(_SC("_nexti returned an invalid idx"));
00498 return false;
00499 }
00500 _FINISH(1);
00501 }
00502 Raise_Error(_SC("_nexti failed"));
00503 return false;
00504 }
00505 break;
00506 case OT_GENERATOR:
00507 if(_generator(o1)->_state == SQGenerator::eDead) _FINISH(exitpos);
00508 if(_generator(o1)->_state == SQGenerator::eSuspended) {
00509 SQInteger idx = 0;
00510 if(type(o4) == OT_INTEGER) {
00511 idx = _integer(o4) + 1;
00512 }
00513 o2 = idx;
00514 o4 = idx;
00515 _generator(o1)->Resume(this, arg_2+1);
00516 _FINISH(0);
00517 }
00518 default:
00519 Raise_Error(_SC("cannot iterate %s"), GetTypeName(o1));
00520 }
00521 return false;
00522 }
00523
00524 bool SQVM::DELEGATE_OP(SQObjectPtr &trg,SQObjectPtr &o1,SQObjectPtr &o2)
00525 {
00526 if(type(o1) != OT_TABLE) { Raise_Error(_SC("delegating a '%s'"), GetTypeName(o1)); return false; }
00527 switch(type(o2)) {
00528 case OT_TABLE:
00529 if(!_table(o1)->SetDelegate(_table(o2))){
00530 Raise_Error(_SC("delegate cycle detected"));
00531 return false;
00532 }
00533 break;
00534 case OT_NULL:
00535 _table(o1)->SetDelegate(NULL);
00536 break;
00537 default:
00538 Raise_Error(_SC("using '%s' as delegate"), GetTypeName(o2));
00539 return false;
00540 break;
00541 }
00542 trg = o1;
00543 return true;
00544 }
00545 #define COND_LITERAL (arg3!=0?ci->_literals[arg1]:STK(arg1))
00546
00547 #define _GUARD(exp) { if(!exp) { Raise_Error(_lasterror); SQ_THROW();} }
00548
00549 #define SQ_THROW() { goto exception_trap; }
00550
00551 bool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func)
00552 {
00553 SQInteger nouters;
00554 SQClosure *closure = SQClosure::Create(_ss(this), func);
00555 if((nouters = func->_noutervalues)) {
00556 closure->_outervalues.reserve(nouters);
00557 for(SQInteger i = 0; i<nouters; i++) {
00558 SQOuterVar &v = func->_outervalues[i];
00559 switch(v._type){
00560 case otSYMBOL:
00561 closure->_outervalues.push_back(_null_);
00562 if(!Get(_stack._vals[_stackbase], v._src, closure->_outervalues.top(), false,true))
00563 {Raise_IdxError(v._src); return false; }
00564 break;
00565 case otLOCAL:
00566 closure->_outervalues.push_back(_stack._vals[_stackbase+_integer(v._src)]);
00567 break;
00568 case otOUTER:
00569 closure->_outervalues.push_back(_closure(ci->_closure)->_outervalues[_integer(v._src)]);
00570 break;
00571 }
00572 }
00573 }
00574 SQInteger ndefparams;
00575 if((ndefparams = func->_ndefaultparams)) {
00576 closure->_defaultparams.reserve(ndefparams);
00577 for(SQInteger i = 0; i < ndefparams; i++) {
00578 SQInteger spos = func->_defaultparams[i];
00579 closure->_defaultparams.push_back(_stack._vals[_stackbase + spos]);
00580 }
00581 }
00582 target = closure;
00583 return true;
00584
00585 }
00586
00587 bool SQVM::GETVARGV_OP(SQObjectPtr &target,SQObjectPtr &index,CallInfo *ci)
00588 {
00589 if(ci->_vargs.size == 0) {
00590 Raise_Error(_SC("the function doesn't have var args"));
00591 return false;
00592 }
00593 if(!sq_isnumeric(index)){
00594 Raise_Error(_SC("indexing 'vargv' with %s"),GetTypeName(index));
00595 return false;
00596 }
00597 SQInteger idx = tointeger(index);
00598 if(idx < 0 || idx >= ci->_vargs.size){ Raise_Error(_SC("vargv index out of range")); return false; }
00599 target = _vargsstack[ci->_vargs.base+idx];
00600 return true;
00601 }
00602
00603 bool SQVM::CLASS_OP(SQObjectPtr &target,SQInteger baseclass,SQInteger attributes)
00604 {
00605 SQClass *base = NULL;
00606 SQObjectPtr attrs;
00607 if(baseclass != -1) {
00608 if(type(_stack._vals[_stackbase+baseclass]) != OT_CLASS) { Raise_Error(_SC("trying to inherit from a %s"),GetTypeName(_stack._vals[_stackbase+baseclass])); return false; }
00609 base = _class(_stack._vals[_stackbase + baseclass]);
00610 }
00611 if(attributes != MAX_FUNC_STACKSIZE) {
00612 attrs = _stack._vals[_stackbase+attributes];
00613 }
00614 target = SQClass::Create(_ss(this),base);
00615 if(type(_class(target)->_metamethods[MT_INHERITED]) != OT_NULL) {
00616 int nparams = 2;
00617 SQObjectPtr ret;
00618 Push(target); Push(attrs);
00619 Call(_class(target)->_metamethods[MT_INHERITED],nparams,_top - nparams, ret, false, false);
00620 Pop(nparams);
00621 }
00622 _class(target)->_attributes = attrs;
00623 return true;
00624 }
00625
00626
00627
00628 bool SQVM::IsEqual(SQObjectPtr &o1,SQObjectPtr &o2,bool &res)
00629 {
00630 if(type(o1) == type(o2)) {
00631 res = ((_userpointer(o1) == _userpointer(o2)?true:false));
00632 }
00633 else {
00634 if(sq_isnumeric(o1) && sq_isnumeric(o2)) {
00635 SQInteger cmpres;
00636 if(!ObjCmp(o1, o2,cmpres)) return false;
00637 res = (cmpres == 0);
00638 }
00639 else {
00640 res = false;
00641 }
00642 }
00643 return true;
00644 }
00645
00646 bool SQVM::IsFalse(SQObjectPtr &o)
00647 {
00648 if(((type(o) & SQOBJECT_CANBEFALSE) && ( (type(o) == OT_FLOAT) && (_float(o) == SQFloat(0.0)) ))
00649 || (_integer(o) == 0) ) {
00650 return true;
00651 }
00652 return false;
00653 }
00654
00655 bool SQVM::GETPARENT_OP(SQObjectPtr &o,SQObjectPtr &target)
00656 {
00657 switch(type(o)) {
00658 case OT_TABLE: target = _table(o)->_delegate?SQObjectPtr(_table(o)->_delegate):_null_;
00659 break;
00660 case OT_CLASS: target = _class(o)->_base?_class(o)->_base:_null_;
00661 break;
00662 default:
00663 Raise_Error(_SC("the %s type doesn't have a parent slot"), GetTypeName(o));
00664 return false;
00665 }
00666 return true;
00667 }
00668
00669 bool SQVM::Execute(SQObjectPtr &closure, SQInteger target, SQInteger nargs, SQInteger stackbase,SQObjectPtr &outres, SQBool raiseerror,ExecutionType et)
00670 {
00671 if ((_nnativecalls + 1) > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; }
00672 _nnativecalls++;
00673 AutoDec ad(&_nnativecalls);
00674 SQInteger traps = 0;
00675
00676 SQInteger ct_target;
00677 SQInteger ct_stackbase;
00678 bool ct_tailcall;
00679
00680 switch(et) {
00681 case ET_CALL:
00682 if(!StartCall(_closure(closure), _top - nargs, nargs, stackbase, false)) {
00683
00684 if(ci == NULL) CallErrorHandler(_lasterror);
00685 return false;
00686 }
00687 ci->_root = SQTrue;
00688 break;
00689 case ET_RESUME_GENERATOR: _generator(closure)->Resume(this, target); ci->_root = SQTrue; traps += ci->_etraps; break;
00690 case ET_RESUME_VM:
00691 case ET_RESUME_THROW_VM:
00692 traps = _suspended_traps;
00693 ci->_root = _suspended_root;
00694 ci->_vargs = _suspend_varargs;
00695 _suspended = SQFalse;
00696 if(et == ET_RESUME_THROW_VM) { SQ_THROW(); }
00697 break;
00698 case ET_RESUME_OPENTTD:
00699 traps = _suspended_traps;
00700 _suspended = SQFalse;
00701 break;
00702 }
00703
00704 exception_restore:
00705
00706 {
00707 for(;;)
00708 {
00709 DecreaseOps(1);
00710 if (ShouldSuspend()) { _suspended = SQTrue; _suspended_traps = traps; return true; }
00711
00712 const SQInstruction &_i_ = *ci->_ip++;
00713
00714
00715 switch(_i_.op)
00716 {
00717 case _OP_LINE:
00718 if(type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure))
00719 CallDebugHook(_SC('l'),arg1);
00720 continue;
00721 case _OP_LOAD: TARGET = ci->_literals[arg1]; continue;
00722 case _OP_LOADINT: TARGET = (SQInteger)arg1; continue;
00723 case _OP_LOADFLOAT: TARGET = *((SQFloat *)&arg1); continue;
00724 case _OP_DLOAD: TARGET = ci->_literals[arg1]; STK(arg2) = ci->_literals[arg3];continue;
00725 case _OP_TAILCALL:
00726 temp_reg = STK(arg1);
00727 if (type(temp_reg) == OT_CLOSURE){
00728 ct_tailcall = true;
00729 if(ci->_vargs.size) PopVarArgs(ci->_vargs);
00730 for (SQInteger i = 0; i < arg3; i++) STK(i) = STK(arg2 + i);
00731 ct_target = ci->_target;
00732 ct_stackbase = _stackbase;
00733 goto common_call;
00734 }
00735 case _OP_CALL: {
00736 ct_tailcall = false;
00737 ct_target = arg0;
00738 temp_reg = STK(arg1);
00739 ct_stackbase = _stackbase+arg2;
00740
00741 common_call:
00742 SQObjectPtr clo = temp_reg;
00743 SQInteger last_top = _top;
00744 switch (type(clo)) {
00745 case OT_CLOSURE:{
00746 _GUARD(StartCall(_closure(clo), ct_target, arg3, ct_stackbase, ct_tailcall));
00747 if (_funcproto(_closure(clo)->_function)->_bgenerator) {
00748 SQGenerator *gen = SQGenerator::Create(_ss(this), _closure(clo));
00749 _GUARD(gen->Yield(this));
00750 Return(1, ct_target, clo);
00751 STK(ct_target) = gen;
00752 }
00753 while (last_top >= _top) _stack._vals[last_top--].Null();
00754 }
00755 continue;
00756 case OT_NATIVECLOSURE: {
00757 bool suspend;
00758 _suspended_target = ct_target;
00759 try {
00760 _GUARD(CallNative(_nativeclosure(clo), arg3, ct_stackbase, clo,suspend));
00761 } catch (...) {
00762 _suspended = SQTrue;
00763 _suspended_target = ct_target;
00764 _suspended_root = ci->_root;
00765 _suspended_traps = traps;
00766 _suspend_varargs = ci->_vargs;
00767 throw;
00768 }
00769 if(suspend){
00770 _suspended = SQTrue;
00771 _suspended_target = ct_target;
00772 _suspended_root = ci->_root;
00773 _suspended_traps = traps;
00774 _suspend_varargs = ci->_vargs;
00775 outres = clo;
00776 return true;
00777 }
00778 if(ct_target != -1) {
00779 STK(ct_target) = clo;
00780 }
00781 }
00782 continue;
00783 case OT_CLASS:{
00784 SQObjectPtr inst;
00785 _GUARD(CreateClassInstance(_class(clo),inst,temp_reg));
00786 STK(ct_target) = inst;
00787 ct_target = -1;
00788 if(type(temp_reg) != OT_NULL) {
00789 _stack._vals[ct_stackbase] = inst;
00790 goto common_call;
00791 }
00792 }
00793 break;
00794 case OT_TABLE:
00795 case OT_USERDATA:
00796 case OT_INSTANCE:
00797 {
00798 Push(clo);
00799 for (SQInteger i = 0; i < arg3; i++) Push(STK(arg2 + i));
00800 if (_delegable(clo) && CallMetaMethod(_delegable(clo), MT_CALL, arg3+1, clo)){
00801 STK(ct_target) = clo;
00802 break;
00803 }
00804 Raise_Error(_SC("attempt to call '%s'"), GetTypeName(clo));
00805 SQ_THROW();
00806 }
00807 default:
00808 Raise_Error(_SC("attempt to call '%s'"), GetTypeName(clo));
00809 SQ_THROW();
00810 }
00811 }
00812 continue;
00813 case _OP_PREPCALL:
00814 case _OP_PREPCALLK:
00815 {
00816 SQObjectPtr &key = _i_.op == _OP_PREPCALLK?(ci->_literals)[arg1]:STK(arg1);
00817 SQObjectPtr &o = STK(arg2);
00818 if (!Get(o, key, temp_reg,false,true)) {
00819 if(type(o) == OT_CLASS) {
00820 if(_class_ddel->Get(key,temp_reg)) {
00821 STK(arg3) = o;
00822 TARGET = temp_reg;
00823 continue;
00824 }
00825 }
00826 { Raise_IdxError(key); SQ_THROW();}
00827 }
00828
00829 STK(arg3) = type(o) == OT_CLASS?STK(0):o;
00830 TARGET = temp_reg;
00831 }
00832 continue;
00833 case _OP_SCOPE_END:
00834 {
00835 SQInteger from = arg0;
00836 SQInteger count = arg1 - arg0 + 2;
00837
00838
00839
00840 if (_stackbase + count + from <= _top) {
00841 while (--count >= 0) _stack._vals[_stackbase + count + from].Null();
00842 }
00843 } continue;
00844 case _OP_GETK:
00845 if (!Get(STK(arg2), ci->_literals[arg1], temp_reg, false,true)) { Raise_IdxError(ci->_literals[arg1]); SQ_THROW();}
00846 TARGET = temp_reg;
00847 continue;
00848 case _OP_MOVE: TARGET = STK(arg1); continue;
00849 case _OP_NEWSLOT:
00850 _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),false));
00851 if(arg0 != arg3) TARGET = STK(arg3);
00852 continue;
00853 case _OP_DELETE: _GUARD(DeleteSlot(STK(arg1), STK(arg2), TARGET)); continue;
00854 case _OP_SET:
00855 if (!Set(STK(arg1), STK(arg2), STK(arg3),true)) { Raise_IdxError(STK(arg2)); SQ_THROW(); }
00856 if (arg0 != arg3) TARGET = STK(arg3);
00857 continue;
00858 case _OP_GET:
00859 if (!Get(STK(arg1), STK(arg2), temp_reg, false,true)) { Raise_IdxError(STK(arg2)); SQ_THROW(); }
00860 TARGET = temp_reg;
00861 continue;
00862 case _OP_EQ:{
00863 bool res;
00864 if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); }
00865 TARGET = res?_true_:_false_;
00866 }continue;
00867 case _OP_NE:{
00868 bool res;
00869 if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); }
00870 TARGET = (!res)?_true_:_false_;
00871 } continue;
00872 case _OP_ARITH: _GUARD(ARITH_OP( arg3 , temp_reg, STK(arg2), STK(arg1))); TARGET = temp_reg; continue;
00873 case _OP_BITW: _GUARD(BW_OP( arg3,TARGET,STK(arg2),STK(arg1))); continue;
00874 case _OP_RETURN:
00875 if(ci->_generator) {
00876 ci->_generator->Kill();
00877 }
00878 if(Return(arg0, arg1, temp_reg)){
00879 assert(traps==0);
00880 outres = temp_reg;
00881 return true;
00882 }
00883 continue;
00884 case _OP_LOADNULLS:{ for(SQInt32 n=0; n < arg1; n++) STK(arg0+n) = _null_; }continue;
00885 case _OP_LOADROOTTABLE: TARGET = _roottable; continue;
00886 case _OP_LOADBOOL: TARGET = arg1?_true_:_false_; continue;
00887 case _OP_DMOVE: STK(arg0) = STK(arg1); STK(arg2) = STK(arg3); continue;
00888 case _OP_JMP: ci->_ip += (sarg1); continue;
00889 case _OP_JNZ: if(!IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue;
00890 case _OP_JZ: if(IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue;
00891 case _OP_LOADFREEVAR: TARGET = _closure(ci->_closure)->_outervalues[arg1]; continue;
00892 case _OP_VARGC: TARGET = SQInteger(ci->_vargs.size); continue;
00893 case _OP_GETVARGV:
00894 if(!GETVARGV_OP(TARGET,STK(arg1),ci)) { SQ_THROW(); }
00895 continue;
00896 case _OP_NEWTABLE: TARGET = SQTable::Create(_ss(this), arg1); continue;
00897 case _OP_NEWARRAY: TARGET = SQArray::Create(_ss(this), 0); _array(TARGET)->Reserve(arg1); continue;
00898 case _OP_APPENDARRAY: _array(STK(arg0))->Append(COND_LITERAL); continue;
00899 case _OP_GETPARENT: _GUARD(GETPARENT_OP(STK(arg1),TARGET)); continue;
00900 case _OP_COMPARITH: _GUARD(DerefInc(arg3, TARGET, STK((((SQUnsignedInteger)arg1&0xFFFF0000)>>16)), STK(arg2), STK(arg1&0x0000FFFF), false)); continue;
00901 case _OP_COMPARITHL: _GUARD(LOCAL_INC(arg3, TARGET, STK(arg1), STK(arg2))); continue;
00902 case _OP_INC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, false));} continue;
00903 case _OP_INCL: {SQObjectPtr o(sarg3); _GUARD(LOCAL_INC('+',TARGET, STK(arg1), o));} continue;
00904 case _OP_PINC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, true));} continue;
00905 case _OP_PINCL: {SQObjectPtr o(sarg3); _GUARD(PLOCAL_INC('+',TARGET, STK(arg1), o));} continue;
00906 case _OP_CMP: _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg1),TARGET)) continue;
00907 case _OP_EXISTS: TARGET = Get(STK(arg1), STK(arg2), temp_reg, true,false)?_true_:_false_;continue;
00908 case _OP_INSTANCEOF:
00909 if(type(STK(arg1)) != OT_CLASS || type(STK(arg2)) != OT_INSTANCE)
00910 {Raise_Error(_SC("cannot apply instanceof between a %s and a %s"),GetTypeName(STK(arg1)),GetTypeName(STK(arg2))); SQ_THROW();}
00911 TARGET = _instance(STK(arg2))->InstanceOf(_class(STK(arg1)))?_true_:_false_;
00912 continue;
00913 case _OP_AND:
00914 if(IsFalse(STK(arg2))) {
00915 TARGET = STK(arg2);
00916 ci->_ip += (sarg1);
00917 }
00918 continue;
00919 case _OP_OR:
00920 if(!IsFalse(STK(arg2))) {
00921 TARGET = STK(arg2);
00922 ci->_ip += (sarg1);
00923 }
00924 continue;
00925 case _OP_NEG: _GUARD(NEG_OP(TARGET,STK(arg1))); continue;
00926 case _OP_NOT: TARGET = (IsFalse(STK(arg1))?_true_:_false_); continue;
00927 case _OP_BWNOT:
00928 if(type(STK(arg1)) == OT_INTEGER) {
00929 SQInteger t = _integer(STK(arg1));
00930 TARGET = SQInteger(~t);
00931 continue;
00932 }
00933 Raise_Error(_SC("attempt to perform a bitwise op on a %s"), GetTypeName(STK(arg1)));
00934 SQ_THROW();
00935 case _OP_CLOSURE: {
00936 SQClosure *c = ci->_closure._unVal.pClosure;
00937 SQFunctionProto *fp = c->_function._unVal.pFunctionProto;
00938 if(!CLOSURE_OP(TARGET,fp->_functions[arg1]._unVal.pFunctionProto)) { SQ_THROW(); }
00939 continue;
00940 }
00941 case _OP_YIELD:{
00942 if(ci->_generator) {
00943 if(sarg1 != MAX_FUNC_STACKSIZE) temp_reg = STK(arg1);
00944 _GUARD(ci->_generator->Yield(this));
00945 traps -= ci->_etraps;
00946 if(sarg1 != MAX_FUNC_STACKSIZE) STK(arg1) = temp_reg;
00947 }
00948 else { Raise_Error(_SC("trying to yield a '%s',only genenerator can be yielded"), GetTypeName(ci->_closure)); SQ_THROW();}
00949 if(Return(arg0, arg1, temp_reg)){
00950 assert(traps == 0);
00951 outres = temp_reg;
00952 return true;
00953 }
00954
00955 }
00956 continue;
00957 case _OP_RESUME:
00958 if(type(STK(arg1)) != OT_GENERATOR){ Raise_Error(_SC("trying to resume a '%s',only genenerator can be resumed"), GetTypeName(STK(arg1))); SQ_THROW();}
00959 _GUARD(_generator(STK(arg1))->Resume(this, arg0));
00960 traps += ci->_etraps;
00961 continue;
00962 case _OP_FOREACH:{ int tojump;
00963 _GUARD(FOREACH_OP(STK(arg0),STK(arg2),STK(arg2+1),STK(arg2+2),arg2,sarg1,tojump));
00964 ci->_ip += tojump; }
00965 continue;
00966 case _OP_POSTFOREACH:
00967 assert(type(STK(arg0)) == OT_GENERATOR);
00968 if(_generator(STK(arg0))->_state == SQGenerator::eDead)
00969 ci->_ip += (sarg1 - 1);
00970 continue;
00971 case _OP_DELEGATE: _GUARD(DELEGATE_OP(TARGET,STK(arg1),STK(arg2))); continue;
00972 case _OP_CLONE:
00973 if(!Clone(STK(arg1), TARGET))
00974 { Raise_Error(_SC("cloning a %s"), GetTypeName(STK(arg1))); SQ_THROW();}
00975 continue;
00976 case _OP_TYPEOF: TypeOf(STK(arg1), TARGET); continue;
00977 case _OP_PUSHTRAP:{
00978 SQInstruction *_iv = _funcproto(_closure(ci->_closure)->_function)->_instructions;
00979 _etraps.push_back(SQExceptionTrap(_top,_stackbase, &_iv[(ci->_ip-_iv)+arg1], arg0)); traps++;
00980 ci->_etraps++;
00981 }
00982 continue;
00983 case _OP_POPTRAP: {
00984 for(SQInteger i = 0; i < arg0; i++) {
00985 _etraps.pop_back(); traps--;
00986 ci->_etraps--;
00987 }
00988 }
00989 continue;
00990 case _OP_THROW: Raise_Error(TARGET); SQ_THROW(); continue;
00991 case _OP_CLASS: _GUARD(CLASS_OP(TARGET,arg1,arg2)); continue;
00992 case _OP_NEWSLOTA:
00993 bool bstatic = (arg0&NEW_SLOT_STATIC_FLAG)?true:false;
00994 if(type(STK(arg1)) == OT_CLASS) {
00995 if(type(_class(STK(arg1))->_metamethods[MT_NEWMEMBER]) != OT_NULL ) {
00996 Push(STK(arg1)); Push(STK(arg2)); Push(STK(arg3));
00997 Push((arg0&NEW_SLOT_ATTRIBUTES_FLAG) ? STK(arg2-1) : _null_);
00998 int nparams = 4;
00999 if(Call(_class(STK(arg1))->_metamethods[MT_NEWMEMBER], nparams, _top - nparams, temp_reg,SQFalse,SQFalse)) {
01000 Pop(nparams);
01001 continue;
01002 }
01003 }
01004 }
01005 _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),bstatic));
01006 if((arg0&NEW_SLOT_ATTRIBUTES_FLAG)) {
01007 _class(STK(arg1))->SetAttributes(STK(arg2),STK(arg2-1));
01008 }
01009 continue;
01010 }
01011
01012 }
01013 }
01014 exception_trap:
01015 {
01016 SQObjectPtr currerror = _lasterror;
01017
01018 SQInteger n = 0;
01019 SQInteger last_top = _top;
01020 if(ci) {
01021 if(_ss(this)->_notifyallexceptions) CallErrorHandler(currerror);
01022
01023 if(traps) {
01024 do {
01025 if(ci->_etraps > 0) {
01026 SQExceptionTrap &et = _etraps.top();
01027 ci->_ip = et._ip;
01028 _top = et._stacksize;
01029 _stackbase = et._stackbase;
01030 _stack._vals[_stackbase+et._extarget] = currerror;
01031 _etraps.pop_back(); traps--; ci->_etraps--;
01032 while(last_top >= _top) _stack._vals[last_top--].Null();
01033 goto exception_restore;
01034 }
01035
01036 if(type(ci->_closure) != OT_CLOSURE && n)
01037 break;
01038 if(ci->_generator) ci->_generator->Kill();
01039 PopVarArgs(ci->_vargs);
01040 POP_CALLINFO(this);
01041 n++;
01042 } while(_callsstacksize);
01043 }
01044 else {
01045
01046 if(raiseerror && !_ss(this)->_notifyallexceptions)
01047 CallErrorHandler(currerror);
01048 }
01049
01050 if(ci) do {
01051 SQBool exitafterthisone = ci->_root;
01052 if(ci->_generator) ci->_generator->Kill();
01053 _stackbase -= ci->_prevstkbase;
01054 _top = _stackbase + ci->_prevtop;
01055 PopVarArgs(ci->_vargs);
01056 POP_CALLINFO(this);
01057 if( (ci && type(ci->_closure) != OT_CLOSURE) || exitafterthisone) break;
01058 } while(_callsstacksize);
01059
01060 while(last_top >= _top) _stack._vals[last_top--].Null();
01061 }
01062 _lasterror = currerror;
01063 return false;
01064 }
01065 assert(0);
01066 }
01067
01068 bool SQVM::CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor)
01069 {
01070 inst = theclass->CreateInstance();
01071 if(!theclass->Get(_ss(this)->_constructoridx,constructor)) {
01072
01073
01074 constructor = _null_;
01075 }
01076 return true;
01077 }
01078
01079 void SQVM::CallErrorHandler(SQObjectPtr &error)
01080 {
01081 if(type(_errorhandler) != OT_NULL) {
01082 SQObjectPtr out;
01083 Push(_roottable); Push(error);
01084 Call(_errorhandler, 2, _top-2, out,SQFalse,SQFalse);
01085 Pop(2);
01086 }
01087 }
01088
01089 void SQVM::CallDebugHook(SQInteger type,SQInteger forcedline)
01090 {
01091 SQObjectPtr temp_reg;
01092 SQInteger nparams=5;
01093 SQFunctionProto *func=_funcproto(_closure(ci->_closure)->_function);
01094 Push(_roottable); Push(type); Push(func->_sourcename); Push(forcedline?forcedline:func->GetLine(ci->_ip)); Push(func->_name);
01095 Call(_debughook,nparams,_top-nparams,temp_reg,SQFalse,SQFalse);
01096 Pop(nparams);
01097 }
01098
01099 bool SQVM::CallNative(SQNativeClosure *nclosure,SQInteger nargs,SQInteger stackbase,SQObjectPtr &retval,bool &suspend)
01100 {
01101 if (_nnativecalls + 1 > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; }
01102 SQInteger nparamscheck = nclosure->_nparamscheck;
01103 if(((nparamscheck > 0) && (nparamscheck != nargs))
01104 || ((nparamscheck < 0) && (nargs < (-nparamscheck)))) {
01105 Raise_Error(_SC("wrong number of parameters"));
01106 return false;
01107 }
01108
01109 SQInteger tcs;
01110 if((tcs = nclosure->_typecheck.size())) {
01111 for(SQInteger i = 0; i < nargs && i < tcs; i++)
01112 if((nclosure->_typecheck._vals[i] != -1) && !(type(_stack._vals[stackbase+i]) & nclosure->_typecheck[i])) {
01113 Raise_ParamTypeError(i,nclosure->_typecheck._vals[i],type(_stack._vals[stackbase+i]));
01114 return false;
01115 }
01116 }
01117 _nnativecalls++;
01118 if ((_top + MIN_STACK_OVERHEAD) > (SQInteger)_stack.size()) {
01119 _stack.resize(_stack.size() + (MIN_STACK_OVERHEAD<<1));
01120 }
01121 SQInteger oldtop = _top;
01122 SQInteger oldstackbase = _stackbase;
01123 _top = stackbase + nargs;
01124 CallInfo lci;
01125 memset(&lci, 0, sizeof(lci));
01126 lci._closure = nclosure;
01127 lci._generator = NULL;
01128 lci._etraps = 0;
01129 lci._prevstkbase = (SQInt32) (stackbase - _stackbase);
01130 lci._ncalls = 1;
01131 lci._prevtop = (SQInt32) (oldtop - oldstackbase);
01132 PUSH_CALLINFO(this, lci);
01133 _stackbase = stackbase;
01134
01135 SQInteger outers = nclosure->_outervalues.size();
01136 for (SQInteger i = 0; i < outers; i++) {
01137 Push(nclosure->_outervalues[i]);
01138 }
01139
01140 if(type(nclosure->_env) == OT_WEAKREF) {
01141 _stack[stackbase] = _weakref(nclosure->_env)->_obj;
01142 }
01143
01144
01145
01146 SQInteger cstksize = _callsstacksize;
01147 SQInteger ret;
01148 try {
01149 SQBool can_suspend = this->_can_suspend;
01150 this->_can_suspend = false;
01151 ret = (nclosure->_function)(this);
01152 this->_can_suspend = can_suspend;
01153 } catch (...) {
01154 _nnativecalls--;
01155 suspend = false;
01156
01157 _callsstacksize = cstksize;
01158 _stackbase = oldstackbase;
01159 _top = oldtop;
01160
01161 POP_CALLINFO(this);
01162
01163 while(oldtop > _stackbase + stackbase) _stack._vals[oldtop--].Null();
01164 throw;
01165 }
01166
01167 assert(cstksize == _callsstacksize);
01168
01169 _nnativecalls--;
01170 suspend = false;
01171 if( ret == SQ_SUSPEND_FLAG) suspend = true;
01172 else if (ret < 0) {
01173 _stackbase = oldstackbase;
01174 _top = oldtop;
01175 POP_CALLINFO(this);
01176 while(oldtop > _stackbase + stackbase) _stack._vals[oldtop--].Null();
01177 Raise_Error(_lasterror);
01178 return false;
01179 }
01180
01181 if (ret != 0){ retval = TOP(); TOP().Null(); }
01182 else { retval = _null_; }
01183 _stackbase = oldstackbase;
01184 _top = oldtop;
01185 POP_CALLINFO(this);
01186 while(oldtop > _stackbase + stackbase) _stack._vals[oldtop--].Null();
01187 return true;
01188 }
01189
01190 bool SQVM::Get(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw, bool fetchroot)
01191 {
01192 switch(type(self)){
01193 case OT_TABLE:
01194 if(_table(self)->Get(key,dest))return true;
01195 break;
01196 case OT_ARRAY:
01197 if(sq_isnumeric(key)){
01198 return _array(self)->Get(tointeger(key),dest);
01199 }
01200 break;
01201 case OT_INSTANCE:
01202 if(_instance(self)->Get(key,dest)) return true;
01203 break;
01204 default:break;
01205 }
01206 if(FallBackGet(self,key,dest,raw)) return true;
01207
01208 if(fetchroot) {
01209 if(_rawval(STK(0)) == _rawval(self) &&
01210 type(STK(0)) == type(self)) {
01211 return _table(_roottable)->Get(key,dest);
01212 }
01213 }
01214 return false;
01215 }
01216
01217 bool SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw)
01218 {
01219 switch(type(self)){
01220 case OT_CLASS:
01221 return _class(self)->Get(key,dest);
01222 break;
01223 case OT_TABLE:
01224 case OT_USERDATA:
01225
01226 if(_delegable(self)->_delegate) {
01227 if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest,raw,false))
01228 return true;
01229 if(raw)return false;
01230 Push(self);Push(key);
01231 if(CallMetaMethod(_delegable(self),MT_GET,2,dest))
01232 return true;
01233 }
01234 if(type(self) == OT_TABLE) {
01235 if(raw) return false;
01236 return _table_ddel->Get(key,dest);
01237 }
01238 return false;
01239 break;
01240 case OT_ARRAY:
01241 if(raw)return false;
01242 return _array_ddel->Get(key,dest);
01243 case OT_STRING:
01244 if(sq_isnumeric(key)){
01245 SQInteger n=tointeger(key);
01246 if(abs((int)n)<_string(self)->_len){
01247 if(n<0)n=_string(self)->_len-n;
01248 dest=SQInteger(_stringval(self)[n]);
01249 return true;
01250 }
01251 return false;
01252 }
01253 else {
01254 if(raw)return false;
01255 return _string_ddel->Get(key,dest);
01256 }
01257 break;
01258 case OT_INSTANCE:
01259 if(raw)return false;
01260 Push(self);Push(key);
01261 if(!CallMetaMethod(_delegable(self),MT_GET,2,dest)) {
01262 return _instance_ddel->Get(key,dest);
01263 }
01264 return true;
01265 case OT_INTEGER:case OT_FLOAT:case OT_BOOL:
01266 if(raw)return false;
01267 return _number_ddel->Get(key,dest);
01268 case OT_GENERATOR:
01269 if(raw)return false;
01270 return _generator_ddel->Get(key,dest);
01271 case OT_CLOSURE: case OT_NATIVECLOSURE:
01272 if(raw)return false;
01273 return _closure_ddel->Get(key,dest);
01274 case OT_THREAD:
01275 if(raw)return false;
01276 return _thread_ddel->Get(key,dest);
01277 case OT_WEAKREF:
01278 if(raw)return false;
01279 return _weakref_ddel->Get(key,dest);
01280 default:return false;
01281 }
01282 return false;
01283 }
01284
01285 bool SQVM::Set(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool fetchroot)
01286 {
01287 switch(type(self)){
01288 case OT_TABLE:
01289 if(_table(self)->Set(key,val))
01290 return true;
01291 if(_table(self)->_delegate) {
01292 if(Set(_table(self)->_delegate,key,val,false)) {
01293 return true;
01294 }
01295 }
01296
01297 case OT_USERDATA:
01298 if(_delegable(self)->_delegate) {
01299 SQObjectPtr t;
01300 Push(self);Push(key);Push(val);
01301 if(CallMetaMethod(_delegable(self),MT_SET,3,t)) return true;
01302 }
01303 break;
01304 case OT_INSTANCE:{
01305 if(_instance(self)->Set(key,val))
01306 return true;
01307 SQObjectPtr t;
01308 Push(self);Push(key);Push(val);
01309 if(CallMetaMethod(_delegable(self),MT_SET,3,t)) return true;
01310 }
01311 break;
01312 case OT_ARRAY:
01313 if(!sq_isnumeric(key)) {Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key)); return false; }
01314 return _array(self)->Set(tointeger(key),val);
01315 default:
01316 Raise_Error(_SC("trying to set '%s'"),GetTypeName(self));
01317 return false;
01318 }
01319 if(fetchroot) {
01320 if(_rawval(STK(0)) == _rawval(self) &&
01321 type(STK(0)) == type(self)) {
01322 return _table(_roottable)->Set(key,val);
01323 }
01324 }
01325 return false;
01326 }
01327
01328 bool SQVM::Clone(const SQObjectPtr &self,SQObjectPtr &target)
01329 {
01330 SQObjectPtr temp_reg;
01331 SQObjectPtr newobj;
01332 switch(type(self)){
01333 case OT_TABLE:
01334 newobj = _table(self)->Clone();
01335 goto cloned_mt;
01336 case OT_INSTANCE:
01337 newobj = _instance(self)->Clone(_ss(this));
01338 cloned_mt:
01339 if(_delegable(newobj)->_delegate){
01340 Push(newobj);
01341 Push(self);
01342 CallMetaMethod(_delegable(newobj),MT_CLONED,2,temp_reg);
01343 }
01344 target = newobj;
01345 return true;
01346 case OT_ARRAY:
01347 target = _array(self)->Clone();
01348 return true;
01349 default: return false;
01350 }
01351 }
01352
01353 bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic)
01354 {
01355 if(type(key) == OT_NULL) { Raise_Error(_SC("null cannot be used as index")); return false; }
01356 switch(type(self)) {
01357 case OT_TABLE: {
01358 bool rawcall = true;
01359 if(_table(self)->_delegate) {
01360 SQObjectPtr res;
01361 if(!_table(self)->Get(key,res)) {
01362 Push(self);Push(key);Push(val);
01363 rawcall = !CallMetaMethod(_table(self),MT_NEWSLOT,3,res);
01364 }
01365 }
01366 if(rawcall) _table(self)->NewSlot(key,val);
01367
01368 break;}
01369 case OT_INSTANCE: {
01370 SQObjectPtr res;
01371 Push(self);Push(key);Push(val);
01372 if(!CallMetaMethod(_instance(self),MT_NEWSLOT,3,res)) {
01373 Raise_Error(_SC("class instances do not support the new slot operator"));
01374 return false;
01375 }
01376 break;}
01377 case OT_CLASS:
01378 if(!_class(self)->NewSlot(_ss(this),key,val,bstatic)) {
01379 if(_class(self)->_locked) {
01380 Raise_Error(_SC("trying to modify a class that has already been instantiated"));
01381 return false;
01382 }
01383 else {
01384 SQObjectPtr oval = PrintObjVal(key);
01385 Raise_Error(_SC("the property '%s' already exists"),_stringval(oval));
01386 return false;
01387 }
01388 }
01389 break;
01390 default:
01391 Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key));
01392 return false;
01393 break;
01394 }
01395 return true;
01396 }
01397
01398 bool SQVM::DeleteSlot(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &res)
01399 {
01400 switch(type(self)) {
01401 case OT_TABLE:
01402 case OT_INSTANCE:
01403 case OT_USERDATA: {
01404 SQObjectPtr t;
01405 bool handled = false;
01406 if(_delegable(self)->_delegate) {
01407 Push(self);Push(key);
01408 handled = CallMetaMethod(_delegable(self),MT_DELSLOT,2,t);
01409 }
01410
01411 if(!handled) {
01412 if(type(self) == OT_TABLE) {
01413 if(_table(self)->Get(key,t)) {
01414 _table(self)->Remove(key);
01415 }
01416 else {
01417 Raise_IdxError((SQObject &)key);
01418 return false;
01419 }
01420 }
01421 else {
01422 Raise_Error(_SC("cannot delete a slot from %s"),GetTypeName(self));
01423 return false;
01424 }
01425 }
01426 res = t;
01427 }
01428 break;
01429 default:
01430 Raise_Error(_SC("attempt to delete a slot from a %s"),GetTypeName(self));
01431 return false;
01432 }
01433 return true;
01434 }
01435
01436 bool SQVM::Call(SQObjectPtr &closure,SQInteger nparams,SQInteger stackbase,SQObjectPtr &outres,SQBool raiseerror,SQBool can_suspend)
01437 {
01438 #ifdef _DEBUG
01439 SQInteger prevstackbase = _stackbase;
01440 #endif
01441 switch(type(closure)) {
01442 case OT_CLOSURE: {
01443 assert(!can_suspend || this->_can_suspend);
01444 SQBool backup_suspend = this->_can_suspend;
01445 this->_can_suspend = can_suspend;
01446 bool ret = Execute(closure, _top - nparams, nparams, stackbase,outres,raiseerror);
01447 this->_can_suspend = backup_suspend;
01448 return ret;
01449 }
01450 break;
01451 case OT_NATIVECLOSURE:{
01452 bool suspend;
01453 return CallNative(_nativeclosure(closure), nparams, stackbase, outres,suspend);
01454
01455 }
01456 break;
01457 case OT_CLASS: {
01458 SQObjectPtr constr;
01459 SQObjectPtr temp;
01460 CreateClassInstance(_class(closure),outres,constr);
01461 if(type(constr) != OT_NULL) {
01462 _stack[stackbase] = outres;
01463 return Call(constr,nparams,stackbase,temp,raiseerror,false);
01464 }
01465 return true;
01466 }
01467 break;
01468 default:
01469 return false;
01470 }
01471 #ifdef _DEBUG
01472 if(!_suspended) {
01473 assert(_stackbase == prevstackbase);
01474 }
01475 #endif
01476 return true;
01477 }
01478
01479 bool SQVM::CallMetaMethod(SQDelegable *del,SQMetaMethod mm,SQInteger nparams,SQObjectPtr &outres)
01480 {
01481 SQObjectPtr closure;
01482 if(del->GetMetaMethod(this, mm, closure)) {
01483 if(Call(closure, nparams, _top - nparams, outres, SQFalse, SQFalse)) {
01484 Pop(nparams);
01485 return true;
01486 }
01487 }
01488 Pop(nparams);
01489 return false;
01490 }
01491
01492 void SQVM::Remove(SQInteger n) {
01493 n = (n >= 0)?n + _stackbase - 1:_top + n;
01494 for(SQInteger i = n; i < _top; i++){
01495 _stack[i] = _stack[i+1];
01496 }
01497 _stack[_top] = _null_;
01498 _top--;
01499 }
01500
01501 void SQVM::Pop() {
01502 _stack[--_top] = _null_;
01503 }
01504
01505 void SQVM::Pop(SQInteger n) {
01506 for(SQInteger i = 0; i < n; i++){
01507 _stack[--_top] = _null_;
01508 }
01509 }
01510
01511 void SQVM::Push(const SQObjectPtr &o) {
01512
01513
01514
01515
01516
01517 #ifdef NDEBUG
01518 if (_top >= (int)_stack.capacity()) _stack.resize(2 * _stack.capacity());
01519 #else
01520 assert(_top < (int)_stack.capacity());
01521 #endif
01522 _stack[_top++] = o;
01523 }
01524 SQObjectPtr &SQVM::Top() { return _stack[_top-1]; }
01525 SQObjectPtr &SQVM::PopGet() { return _stack[--_top]; }
01526 SQObjectPtr &SQVM::GetUp(SQInteger n) { return _stack[_top+n]; }
01527 SQObjectPtr &SQVM::GetAt(SQInteger n) { return _stack[n]; }
01528
01529 #ifdef _DEBUG_DUMP
01530 void SQVM::dumpstack(SQInteger stackbase,bool dumpall)
01531 {
01532 SQInteger size=dumpall?_stack.size():_top;
01533 SQInteger n=0;
01534 scprintf(_SC("\n>>>>stack dump<<<<\n"));
01535 CallInfo &ci=_callsstack[_callsstacksize-1];
01536 scprintf(_SC("IP: %p\n"),ci._ip);
01537 scprintf(_SC("prev stack base: %d\n"),ci._prevstkbase);
01538 scprintf(_SC("prev top: %d\n"),ci._prevtop);
01539 for(SQInteger i=0;i<size;i++){
01540 SQObjectPtr &obj=_stack[i];
01541 if(stackbase==i)scprintf(_SC(">"));else scprintf(_SC(" "));
01542 scprintf(_SC("[%d]:"),n);
01543 switch(type(obj)){
01544 case OT_FLOAT: scprintf(_SC("FLOAT %.3f"),_float(obj));break;
01545 case OT_INTEGER: scprintf(_SC("INTEGER %d"),_integer(obj));break;
01546 case OT_BOOL: scprintf(_SC("BOOL %s"),_integer(obj)?"true":"false");break;
01547 case OT_STRING: scprintf(_SC("STRING %s"),_stringval(obj));break;
01548 case OT_NULL: scprintf(_SC("NULL")); break;
01549 case OT_TABLE: scprintf(_SC("TABLE %p[%p]"),_table(obj),_table(obj)->_delegate);break;
01550 case OT_ARRAY: scprintf(_SC("ARRAY %p"),_array(obj));break;
01551 case OT_CLOSURE: scprintf(_SC("CLOSURE [%p]"),_closure(obj));break;
01552 case OT_NATIVECLOSURE: scprintf(_SC("NATIVECLOSURE"));break;
01553 case OT_USERDATA: scprintf(_SC("USERDATA %p[%p]"),_userdataval(obj),_userdata(obj)->_delegate);break;
01554 case OT_GENERATOR: scprintf(_SC("GENERATOR %p"),_generator(obj));break;
01555 case OT_THREAD: scprintf(_SC("THREAD [%p]"),_thread(obj));break;
01556 case OT_USERPOINTER: scprintf(_SC("USERPOINTER %p"),_userpointer(obj));break;
01557 case OT_CLASS: scprintf(_SC("CLASS %p"),_class(obj));break;
01558 case OT_INSTANCE: scprintf(_SC("INSTANCE %p"),_instance(obj));break;
01559 case OT_WEAKREF: scprintf(_SC("WEAKERF %p"),_weakref(obj));break;
01560 default:
01561 assert(0);
01562 break;
01563 };
01564 scprintf(_SC("\n"));
01565 ++n;
01566 }
01567 }
01568
01569
01570
01571 #endif