Johan Wikman / SQUIRREL3

Dependents:   Squirrel

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sqvm.cpp Source File

sqvm.cpp

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