Back to home page

Enduro/X

 
 

    


0001 /*

0002     see copyright notice in pscript.h

0003 */
0004 #include <math.h>
0005 #include "pspcheader.h"
0006 #include <stdlib.h>
0007 #include "psopcodes.h"
0008 #include "psvm.h"
0009 #include "psfuncproto.h"
0010 #include "psclosure.h"
0011 #include "psstring.h"
0012 #include "pstable.h"
0013 #include "psuserdata.h"
0014 #include "psarray.h"
0015 #include "psclass.h"
0016 
0017 #define TOP() (_stack._vals[_top-1])
0018 
0019 bool PSVM::BW_OP(PSUnsignedInteger op,PSObjectPtr &trg,const PSObjectPtr &o1,const PSObjectPtr &o2)
0020 {
0021     PSInteger res;
0022     if((type(o1)|type(o2)) == OT_INTEGER)
0023     {
0024         PSInteger i1 = _integer(o1), i2 = _integer(o2);
0025         switch(op) {
0026             case BW_AND:    res = i1 & i2; break;
0027             case BW_OR:     res = i1 | i2; break;
0028             case BW_XOR:    res = i1 ^ i2; break;
0029             case BW_SHIFTL: res = i1 << i2; break;
0030             case BW_SHIFTR: res = i1 >> i2; break;
0031             case BW_USHIFTR:res = (PSInteger)(*((PSUnsignedInteger*)&i1) >> i2); break;
0032             default: { Raise_Error(_SC("internal vm error bitwise op failed")); return false; }
0033         }
0034     }
0035     else { Raise_Error(_SC("bitwise op between '%s' and '%s'"),GetTypeName(o1),GetTypeName(o2)); return false;}
0036     trg = res;
0037     return true;
0038 }
0039 
0040 #define _ARITH_(op,trg,o1,o2) \
0041 { \
0042     PSInteger tmask = type(o1)|type(o2); \
0043     switch(tmask) { \
0044         case OT_INTEGER: trg = _integer(o1) op _integer(o2);break; \
0045         case (OT_FLOAT|OT_INTEGER): \
0046         case (OT_FLOAT): trg = tofloat(o1) op tofloat(o2); break;\
0047         default: _GUARD(ARITH_OP((#op)[0],trg,o1,o2)); break;\
0048     } \
0049 }
0050 
0051 #define _ARITH_NOZERO(op,trg,o1,o2,err) \
0052 { \
0053     PSInteger tmask = type(o1)|type(o2); \
0054     switch(tmask) { \
0055         case OT_INTEGER: { PSInteger i2 = _integer(o2); if(i2 == 0) { Raise_Error(err); PS_THROW(); } trg = _integer(o1) op i2; } break;\
0056         case (OT_FLOAT|OT_INTEGER): \
0057         case (OT_FLOAT): trg = tofloat(o1) op tofloat(o2); break;\
0058         default: _GUARD(ARITH_OP((#op)[0],trg,o1,o2)); break;\
0059     } \
0060 }
0061 
0062 bool PSVM::ARITH_OP(PSUnsignedInteger op,PSObjectPtr &trg,const PSObjectPtr &o1,const PSObjectPtr &o2)
0063 {
0064     PSInteger tmask = type(o1)|type(o2);
0065     switch(tmask) {
0066         case OT_INTEGER:{
0067             PSInteger res, i1 = _integer(o1), i2 = _integer(o2);
0068             switch(op) {
0069             case '+': res = i1 + i2; break;
0070             case '-': res = i1 - i2; break;
0071             case '/': if (i2 == 0) { Raise_Error(_SC("division by zero")); return false; }
0072                     else if (i2 == -1 && i1 == INT_MIN) { Raise_Error(_SC("integer overflow")); return false; }
0073                     res = i1 / i2;
0074                     break;
0075             case '*': res = i1 * i2; break;
0076             case '%': if (i2 == 0) { Raise_Error(_SC("modulo by zero")); return false; }
0077                     else if (i2 == -1 && i1 == INT_MIN) { res = 0; break; }
0078                     res = i1 % i2;
0079                     break;
0080             default: res = 0xDEADBEEF;
0081             }
0082             trg = res; }
0083             break;
0084         case (OT_FLOAT|OT_INTEGER):
0085         case (OT_FLOAT):{
0086             PSFloat res, f1 = tofloat(o1), f2 = tofloat(o2);
0087             switch(op) {
0088             case '+': res = f1 + f2; break;
0089             case '-': res = f1 - f2; break;
0090             case '/': res = f1 / f2; break;
0091             case '*': res = f1 * f2; break;
0092             case '%': res = PSFloat(fmod((double)f1,(double)f2)); break;
0093             default: res = 0x0f;
0094             }
0095             trg = res; }
0096             break;
0097         default:
0098             if(op == '+' && (tmask & _RT_STRING)){
0099                 if(!StringCat(o1, o2, trg)) return false;
0100             }
0101             else if(!ArithMetaMethod(op,o1,o2,trg)) {
0102                 return false;
0103             }
0104     }
0105     return true;
0106 }
0107 
0108 PSVM::PSVM(PSSharedState *ss)
0109 {
0110     _sharedstate=ss;
0111     _suspended = PSFalse;
0112     _suspended_target = -1;
0113     _suspended_root = PSFalse;
0114     _suspended_traps = -1;
0115     _foreignptr = NULL;
0116     _nnativecalls = 0;
0117     _nmetamethodscall = 0;
0118     _lasterror.Null();
0119     _errorhandler.Null();
0120     _debughook = false;
0121     _debughook_native = NULL;
0122     _debughook_closure.Null();
0123     _openouters = NULL;
0124     ci = NULL;
0125     _releasehook = NULL;
0126     INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);
0127 }
0128 
0129 void PSVM::Finalize()
0130 {
0131     if(_releasehook) { _releasehook(_foreignptr,0); _releasehook = NULL; }
0132     if(_openouters) CloseOuters(&_stack._vals[0]);
0133     _roottable.Null();
0134     _lasterror.Null();
0135     _errorhandler.Null();
0136     _debughook = false;
0137     _debughook_native = NULL;
0138     _debughook_closure.Null();
0139     temp_reg.Null();
0140     _callstackdata.resize(0);
0141     PSInteger size=_stack.size();
0142     for(PSInteger i=0;i<size;i++)
0143         _stack[i].Null();
0144 }
0145 
0146 PSVM::~PSVM()
0147 {
0148     Finalize();
0149     REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);
0150 }
0151 
0152 bool PSVM::ArithMetaMethod(PSInteger op,const PSObjectPtr &o1,const PSObjectPtr &o2,PSObjectPtr &dest)
0153 {
0154     PSMetaMethod mm;
0155     switch(op){
0156         case _SC('+'): mm=MT_ADD; break;
0157         case _SC('-'): mm=MT_SUB; break;
0158         case _SC('/'): mm=MT_DIV; break;
0159         case _SC('*'): mm=MT_MUL; break;
0160         case _SC('%'): mm=MT_MODULO; break;
0161         default: mm = MT_ADD; assert(0); break; //shutup compiler

0162     }
0163     if(is_delegable(o1) && _delegable(o1)->_delegate) {
0164 
0165         PSObjectPtr closure;
0166         if(_delegable(o1)->GetMetaMethod(this, mm, closure)) {
0167             Push(o1);Push(o2);
0168             return CallMetaMethod(closure,mm,2,dest);
0169         }
0170     }
0171     Raise_Error(_SC("arith op %c on between '%s' and '%s'"),op,GetTypeName(o1),GetTypeName(o2));
0172     return false;
0173 }
0174 
0175 bool PSVM::NEG_OP(PSObjectPtr &trg,const PSObjectPtr &o)
0176 {
0177 
0178     switch(type(o)) {
0179     case OT_INTEGER:
0180         trg = -_integer(o);
0181         return true;
0182     case OT_FLOAT:
0183         trg = -_float(o);
0184         return true;
0185     case OT_TABLE:
0186     case OT_USERDATA:
0187     case OT_INSTANCE:
0188         if(_delegable(o)->_delegate) {
0189             PSObjectPtr closure;
0190             if(_delegable(o)->GetMetaMethod(this, MT_UNM, closure)) {
0191                 Push(o);
0192                 if(!CallMetaMethod(closure, MT_UNM, 1, temp_reg)) return false;
0193                 _Swap(trg,temp_reg);
0194                 return true;
0195 
0196             }
0197         }
0198     default:break; //shutup compiler

0199     }
0200     Raise_Error(_SC("attempt to negate a %s"), GetTypeName(o));
0201     return false;
0202 }
0203 
0204 #define _RET_SUCCEED(exp) { result = (exp); return true; }
0205 bool PSVM::ObjCmp(const PSObjectPtr &o1,const PSObjectPtr &o2,PSInteger &result)
0206 {
0207     PSObjectType t1 = type(o1), t2 = type(o2);
0208     if(t1 == t2) {
0209         if(_rawval(o1) == _rawval(o2))_RET_SUCCEED(0);
0210         PSObjectPtr res;
0211         switch(t1){
0212         case OT_STRING:
0213             _RET_SUCCEED(scstrcmp(_stringval(o1),_stringval(o2)));
0214         case OT_INTEGER:
0215             _RET_SUCCEED((_integer(o1)<_integer(o2))?-1:1);
0216         case OT_FLOAT:
0217             _RET_SUCCEED((_float(o1)<_float(o2))?-1:1);
0218         case OT_TABLE:
0219         case OT_USERDATA:
0220         case OT_INSTANCE:
0221             if(_delegable(o1)->_delegate) {
0222                 PSObjectPtr closure;
0223                 if(_delegable(o1)->GetMetaMethod(this, MT_CMP, closure)) {
0224                     Push(o1);Push(o2);
0225                     if(CallMetaMethod(closure,MT_CMP,2,res)) {
0226                         if(type(res) != OT_INTEGER) {
0227                             Raise_Error(_SC("_cmp must return an integer"));
0228                             return false;
0229                         }
0230                         _RET_SUCCEED(_integer(res))
0231                     }
0232                     return false;
0233                 }
0234             }
0235             //continues through (no break needed)

0236         default:
0237             _RET_SUCCEED( _userpointer(o1) < _userpointer(o2)?-1:1 );
0238         }
0239         assert(0);
0240         //if(type(res)!=OT_INTEGER) { Raise_CompareError(o1,o2); return false; }

0241         //  _RET_SUCCEED(_integer(res));

0242 
0243     }
0244     else{
0245         if(ps_isnumeric(o1) && ps_isnumeric(o2)){
0246             if((t1==OT_INTEGER) && (t2==OT_FLOAT)) {
0247                 if( _integer(o1)==_float(o2) ) { _RET_SUCCEED(0); }
0248                 else if( _integer(o1)<_float(o2) ) { _RET_SUCCEED(-1); }
0249                 _RET_SUCCEED(1);
0250             }
0251             else{
0252                 if( _float(o1)==_integer(o2) ) { _RET_SUCCEED(0); }
0253                 else if( _float(o1)<_integer(o2) ) { _RET_SUCCEED(-1); }
0254                 _RET_SUCCEED(1);
0255             }
0256         }
0257         else if(t1==OT_NULL) {_RET_SUCCEED(-1);}
0258         else if(t2==OT_NULL) {_RET_SUCCEED(1);}
0259         else { Raise_CompareError(o1,o2); return false; }
0260 
0261     }
0262     assert(0);
0263     _RET_SUCCEED(0); //cannot happen

0264 }
0265 
0266 bool PSVM::CMP_OP(CmpOP op, const PSObjectPtr &o1,const PSObjectPtr &o2,PSObjectPtr &res)
0267 {
0268     PSInteger r;
0269     if(ObjCmp(o1,o2,r)) {
0270         switch(op) {
0271             case CMP_G: res = (r > 0); return true;
0272             case CMP_GE: res = (r >= 0); return true;
0273             case CMP_L: res = (r < 0); return true;
0274             case CMP_LE: res = (r <= 0); return true;
0275             case CMP_3W: res = r; return true;
0276         }
0277         assert(0);
0278     }
0279     return false;
0280 }
0281 
0282 bool PSVM::ToString(const PSObjectPtr &o,PSObjectPtr &res)
0283 {
0284     switch(type(o)) {
0285     case OT_STRING:
0286         res = o;
0287         return true;
0288     case OT_FLOAT:
0289         scsprintf(_sp(ps_rsl(NUMBER_MAX_CHAR+1)),ps_rsl(NUMBER_MAX_CHAR),_SC("%g"),_float(o));
0290         break;
0291     case OT_INTEGER:
0292         scsprintf(_sp(ps_rsl(NUMBER_MAX_CHAR+1)),ps_rsl(NUMBER_MAX_CHAR),_PRINT_INT_FMT,_integer(o));
0293         break;
0294     case OT_BOOL:
0295         scsprintf(_sp(ps_rsl(6)),ps_rsl(6),_integer(o)?_SC("true"):_SC("false"));
0296         break;
0297     case OT_TABLE:
0298     case OT_USERDATA:
0299     case OT_INSTANCE:
0300         if(_delegable(o)->_delegate) {
0301             PSObjectPtr closure;
0302             if(_delegable(o)->GetMetaMethod(this, MT_TOSTRING, closure)) {
0303                 Push(o);
0304                 if(CallMetaMethod(closure,MT_TOSTRING,1,res)) {;
0305                     if(type(res) == OT_STRING)
0306                         return true;
0307                 }
0308                 else {
0309                     return false;
0310                 }
0311             }
0312         }
0313     default:
0314         scsprintf(_sp(ps_rsl((sizeof(void*)*2)+NUMBER_MAX_CHAR)),ps_rsl((sizeof(void*)*2)+NUMBER_MAX_CHAR),_SC("(%s : 0x%p)"),GetTypeName(o),(void*)_rawval(o));
0315     }
0316     res = PSString::Create(_ss(this),_spval);
0317     return true;
0318 }
0319 
0320 
0321 bool PSVM::StringCat(const PSObjectPtr &str,const PSObjectPtr &obj,PSObjectPtr &dest)
0322 {
0323     PSObjectPtr a, b;
0324     if(!ToString(str, a)) return false;
0325     if(!ToString(obj, b)) return false;
0326     PSInteger l = _string(a)->_len , ol = _string(b)->_len;
0327     PSChar *s = _sp(ps_rsl(l + ol + 1));
0328     memcpy(s, _stringval(a), ps_rsl(l));
0329     memcpy(s + l, _stringval(b), ps_rsl(ol));
0330     dest = PSString::Create(_ss(this), _spval, l + ol);
0331     return true;
0332 }
0333 
0334 bool PSVM::TypeOf(const PSObjectPtr &obj1,PSObjectPtr &dest)
0335 {
0336     if(is_delegable(obj1) && _delegable(obj1)->_delegate) {
0337         PSObjectPtr closure;
0338         if(_delegable(obj1)->GetMetaMethod(this, MT_TYPEOF, closure)) {
0339             Push(obj1);
0340             return CallMetaMethod(closure,MT_TYPEOF,1,dest);
0341         }
0342     }
0343     dest = PSString::Create(_ss(this),GetTypeName(obj1));
0344     return true;
0345 }
0346 
0347 bool PSVM::Init(PSVM *friendvm, PSInteger stacksize)
0348 {
0349     _stack.resize(stacksize);
0350     _alloccallsstacksize = 4;
0351     _callstackdata.resize(_alloccallsstacksize);
0352     _callsstacksize = 0;
0353     _callsstack = &_callstackdata[0];
0354     _stackbase = 0;
0355     _top = 0;
0356     if(!friendvm) {
0357         _roottable = PSTable::Create(_ss(this), 0);
0358         ps_base_register(this);
0359     }
0360     else {
0361         _roottable = friendvm->_roottable;
0362         _errorhandler = friendvm->_errorhandler;
0363         _debughook = friendvm->_debughook;
0364         _debughook_native = friendvm->_debughook_native;
0365         _debughook_closure = friendvm->_debughook_closure;
0366     }
0367 
0368 
0369     return true;
0370 }
0371 
0372 
0373 bool PSVM::StartCall(PSClosure *closure,PSInteger target,PSInteger args,PSInteger stackbase,bool tailcall)
0374 {
0375     PSFunctionProto *func = closure->_function;
0376 
0377     PSInteger paramssize = func->_nparameters;
0378     const PSInteger newtop = stackbase + func->_stacksize;
0379     PSInteger nargs = args;
0380     if(func->_varparams)
0381     {
0382         paramssize--;
0383         if (nargs < paramssize) {
0384             Raise_Error(_SC("wrong number of parameters"));
0385             return false;
0386         }
0387 
0388         //dumpstack(stackbase);

0389         PSInteger nvargs = nargs - paramssize;
0390         PSArray *arr = PSArray::Create(_ss(this),nvargs);
0391         PSInteger pbase = stackbase+paramssize;
0392         for(PSInteger n = 0; n < nvargs; n++) {
0393             arr->_values[n] = _stack._vals[pbase];
0394             _stack._vals[pbase].Null();
0395             pbase++;
0396 
0397         }
0398         _stack._vals[stackbase+paramssize] = arr;
0399         //dumpstack(stackbase);

0400     }
0401     else if (paramssize != nargs) {
0402         PSInteger ndef = func->_ndefaultparams;
0403         PSInteger diff;
0404         if(ndef && nargs < paramssize && (diff = paramssize - nargs) <= ndef) {
0405             for(PSInteger n = ndef - diff; n < ndef; n++) {
0406                 _stack._vals[stackbase + (nargs++)] = closure->_defaultparams[n];
0407             }
0408         }
0409         else {
0410             Raise_Error(_SC("wrong number of parameters"));
0411             return false;
0412         }
0413     }
0414 
0415     if(closure->_env) {
0416         _stack._vals[stackbase] = closure->_env->_obj;
0417     }
0418 
0419     if(!EnterFrame(stackbase, newtop, tailcall)) return false;
0420 
0421     ci->_closure  = closure;
0422     ci->_literals = func->_literals;
0423     ci->_ip       = func->_instructions;
0424     ci->_target   = (PSInt32)target;
0425 
0426     if (_debughook) {
0427         CallDebugHook(_SC('c'));
0428     }
0429 
0430     if (closure->_function->_bgenerator) {
0431         PSFunctionProto *f = closure->_function;
0432         PSGenerator *gen = PSGenerator::Create(_ss(this), closure);
0433         if(!gen->Yield(this,f->_stacksize))
0434             return false;
0435         PSObjectPtr temp;
0436         Return(1, target, temp);
0437         STK(target) = gen;
0438     }
0439 
0440 
0441     return true;
0442 }
0443 
0444 bool PSVM::Return(PSInteger _arg0, PSInteger _arg1, PSObjectPtr &retval)
0445 {
0446     PSBool    _isroot      = ci->_root;
0447     PSInteger callerbase   = _stackbase - ci->_prevstkbase;
0448 
0449     if (_debughook) {
0450         for(PSInteger i=0; i<ci->_ncalls; i++) {
0451             CallDebugHook(_SC('r'));
0452         }
0453     }
0454 
0455     PSObjectPtr *dest;
0456     if (_isroot) {
0457         dest = &(retval);
0458     } else if (ci->_target == -1) {
0459         dest = NULL;
0460     } else {
0461         dest = &_stack._vals[callerbase + ci->_target];
0462     }
0463     if (dest) {
0464         if(_arg0 != 0xFF) {
0465             *dest = _stack._vals[_stackbase+_arg1];
0466         }
0467         else {
0468             dest->Null();
0469         }
0470         //*dest = (_arg0 != 0xFF) ? _stack._vals[_stackbase+_arg1] : _null_;

0471     }
0472     LeaveFrame();
0473     return _isroot ? true : false;
0474 }
0475 
0476 #define _RET_ON_FAIL(exp) { if(!exp) return false; }
0477 
0478 bool PSVM::PLOCAL_INC(PSInteger op,PSObjectPtr &target, PSObjectPtr &a, PSObjectPtr &incr)
0479 {
0480     PSObjectPtr trg;
0481     _RET_ON_FAIL(ARITH_OP( op , trg, a, incr));
0482     target = a;
0483     a = trg;
0484     return true;
0485 }
0486 
0487 bool PSVM::DerefInc(PSInteger op,PSObjectPtr &target, PSObjectPtr &self, PSObjectPtr &key, PSObjectPtr &incr, bool postfix,PSInteger selfidx)
0488 {
0489     PSObjectPtr tmp, tself = self, tkey = key;
0490     if (!Get(tself, tkey, tmp, 0, selfidx)) { return false; }
0491     _RET_ON_FAIL(ARITH_OP( op , target, tmp, incr))
0492     if (!Set(tself, tkey, target,selfidx)) { return false; }
0493     if (postfix) target = tmp;
0494     return true;
0495 }
0496 
0497 #define arg0 (_i_._arg0)
0498 #define sarg0 ((PSInteger)*((const signed char *)&_i_._arg0))
0499 #define arg1 (_i_._arg1)
0500 #define sarg1 (*((const PSInt32 *)&_i_._arg1))
0501 #define arg2 (_i_._arg2)
0502 #define arg3 (_i_._arg3)
0503 #define sarg3 ((PSInteger)*((const signed char *)&_i_._arg3))
0504 
0505 PSRESULT PSVM::Suspend()
0506 {
0507     if (_suspended)
0508         return ps_throwerror(this, _SC("cannot suspend an already suspended vm"));
0509     if (_nnativecalls!=2)
0510         return ps_throwerror(this, _SC("cannot suspend through native calls/metamethods"));
0511     return PS_SUSPEND_FLAG;
0512 }
0513 
0514 
0515 #define _FINISH(howmuchtojump) {jump = howmuchtojump; return true; }
0516 bool PSVM::FOREACH_OP(PSObjectPtr &o1,PSObjectPtr &o2,PSObjectPtr
0517 &o3,PSObjectPtr &o4,PSInteger PS_UNUSED_ARG(arg_2),int exitpos,int &jump)
0518 {
0519     PSInteger nrefidx;
0520     switch(type(o1)) {
0521     case OT_TABLE:
0522         if((nrefidx = _table(o1)->Next(false,o4, o2, o3)) == -1) _FINISH(exitpos);
0523         o4 = (PSInteger)nrefidx; _FINISH(1);
0524     case OT_ARRAY:
0525         if((nrefidx = _array(o1)->Next(o4, o2, o3)) == -1) _FINISH(exitpos);
0526         o4 = (PSInteger) nrefidx; _FINISH(1);
0527     case OT_STRING:
0528         if((nrefidx = _string(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos);
0529         o4 = (PSInteger)nrefidx; _FINISH(1);
0530     case OT_CLASS:
0531         if((nrefidx = _class(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos);
0532         o4 = (PSInteger)nrefidx; _FINISH(1);
0533     case OT_USERDATA:
0534     case OT_INSTANCE:
0535         if(_delegable(o1)->_delegate) {
0536             PSObjectPtr itr;
0537             PSObjectPtr closure;
0538             if(_delegable(o1)->GetMetaMethod(this, MT_NEXTI, closure)) {
0539                 Push(o1);
0540                 Push(o4);
0541                 if(CallMetaMethod(closure, MT_NEXTI, 2, itr)) {
0542                     o4 = o2 = itr;
0543                     if(type(itr) == OT_NULL) _FINISH(exitpos);
0544                     if(!Get(o1, itr, o3, 0, DONT_FALL_BACK)) {
0545                         Raise_Error(_SC("_nexti returned an invalid idx")); // cloud be changed

0546                         return false;
0547                     }
0548                     _FINISH(1);
0549                 }
0550                 else {
0551                     return false;
0552                 }
0553             }
0554             Raise_Error(_SC("_nexti failed"));
0555             return false;
0556         }
0557         break;
0558     case OT_GENERATOR:
0559         if(_generator(o1)->_state == PSGenerator::eDead) _FINISH(exitpos);
0560         if(_generator(o1)->_state == PSGenerator::eSuspended) {
0561             PSInteger idx = 0;
0562             if(type(o4) == OT_INTEGER) {
0563                 idx = _integer(o4) + 1;
0564             }
0565             o2 = idx;
0566             o4 = idx;
0567             _generator(o1)->Resume(this, o3);
0568             _FINISH(0);
0569         }
0570     default:
0571         Raise_Error(_SC("cannot iterate %s"), GetTypeName(o1));
0572     }
0573     return false; //cannot be hit(just to avoid warnings)

0574 }
0575 
0576 #define COND_LITERAL (arg3!=0?ci->_literals[arg1]:STK(arg1))
0577 
0578 #define PS_THROW() { goto exception_trap; }
0579 
0580 #define _GUARD(exp) { if(!exp) { PS_THROW();} }
0581 
0582 bool PSVM::CLOSURE_OP(PSObjectPtr &target, PSFunctionProto *func)
0583 {
0584     PSInteger nouters;
0585     PSClosure *closure = PSClosure::Create(_ss(this), func,_table(_roottable)->GetWeakRef(OT_TABLE));
0586     if((nouters = func->_noutervalues)) {
0587         for(PSInteger i = 0; i<nouters; i++) {
0588             PSOuterVar &v = func->_outervalues[i];
0589             switch(v._type){
0590             case otLOCAL:
0591                 FindOuter(closure->_outervalues[i], &STK(_integer(v._src)));
0592                 break;
0593             case otOUTER:
0594                 closure->_outervalues[i] = _closure(ci->_closure)->_outervalues[_integer(v._src)];
0595                 break;
0596             }
0597         }
0598     }
0599     PSInteger ndefparams;
0600     if((ndefparams = func->_ndefaultparams)) {
0601         for(PSInteger i = 0; i < ndefparams; i++) {
0602             PSInteger spos = func->_defaultparams[i];
0603             closure->_defaultparams[i] = _stack._vals[_stackbase + spos];
0604         }
0605     }
0606     target = closure;
0607     return true;
0608 
0609 }
0610 
0611 
0612 bool PSVM::CLASS_OP(PSObjectPtr &target,PSInteger baseclass,PSInteger attributes)
0613 {
0614     PSClass *base = NULL;
0615     PSObjectPtr attrs;
0616     if(baseclass != -1) {
0617         if(type(_stack._vals[_stackbase+baseclass]) != OT_CLASS) { Raise_Error(_SC("trying to inherit from a %s"),GetTypeName(_stack._vals[_stackbase+baseclass])); return false; }
0618         base = _class(_stack._vals[_stackbase + baseclass]);
0619     }
0620     if(attributes != MAX_FUNC_STACKSIZE) {
0621         attrs = _stack._vals[_stackbase+attributes];
0622     }
0623     target = PSClass::Create(_ss(this),base);
0624     if(type(_class(target)->_metamethods[MT_INHERITED]) != OT_NULL) {
0625         int nparams = 2;
0626         PSObjectPtr ret;
0627         Push(target); Push(attrs);
0628         if(!Call(_class(target)->_metamethods[MT_INHERITED],nparams,_top - nparams, ret, false)) {
0629             Pop(nparams);
0630             return false;
0631         }
0632         Pop(nparams);
0633     }
0634     _class(target)->_attributes = attrs;
0635     return true;
0636 }
0637 
0638 bool PSVM::IsEqual(const PSObjectPtr &o1,const PSObjectPtr &o2,bool &res)
0639 {
0640     if(type(o1) == type(o2)) {
0641         res = (_rawval(o1) == _rawval(o2));
0642     }
0643     else {
0644         if(ps_isnumeric(o1) && ps_isnumeric(o2)) {
0645             res = (tofloat(o1) == tofloat(o2));
0646         }
0647         else {
0648             res = false;
0649         }
0650     }
0651     return true;
0652 }
0653 
0654 bool PSVM::IsFalse(PSObjectPtr &o)
0655 {
0656     if(((type(o) & PSOBJECT_CANBEFALSE)
0657         && ( ((type(o) == OT_FLOAT) && (_float(o) == PSFloat(0.0))) ))
0658 #if !defined(PSUSEDOUBLE) || (defined(PSUSEDOUBLE) && defined(_PS64))
0659         || (_integer(o) == 0) )  //OT_NULL|OT_INTEGER|OT_BOOL

0660 #else
0661         || (((type(o) != OT_FLOAT) && (_integer(o) == 0))) )  //OT_NULL|OT_INTEGER|OT_BOOL

0662 #endif
0663     {
0664         return true;
0665     }
0666     return false;
0667 }
0668 extern PSInstructionDesc g_InstrDesc[];
0669 bool PSVM::Execute(PSObjectPtr &closure, PSInteger nargs, PSInteger stackbase,PSObjectPtr &outres, PSBool raiseerror,ExecutionType et)
0670 {
0671     if ((_nnativecalls + 1) > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; }
0672     _nnativecalls++;
0673     AutoDec ad(&_nnativecalls);
0674     PSInteger traps = 0;
0675     CallInfo *prevci = ci;
0676 
0677     switch(et) {
0678         case ET_CALL: {
0679             temp_reg = closure;
0680             if(!StartCall(_closure(temp_reg), _top - nargs, nargs, stackbase, false)) {
0681                 //call the handler if there are no calls in the stack, if not relies on the previous node

0682                 if(ci == NULL) CallErrorHandler(_lasterror);
0683                 return false;
0684             }
0685             if(ci == prevci) {
0686                 outres = STK(_top-nargs);
0687                 return true;
0688             }
0689             ci->_root = PSTrue;
0690                       }
0691             break;
0692         case ET_RESUME_GENERATOR: _generator(closure)->Resume(this, outres); ci->_root = PSTrue; traps += ci->_etraps; break;
0693         case ET_RESUME_VM:
0694         case ET_RESUME_THROW_VM:
0695             traps = _suspended_traps;
0696             ci->_root = _suspended_root;
0697             _suspended = PSFalse;
0698             if(et  == ET_RESUME_THROW_VM) { PS_THROW(); }
0699             break;
0700     }
0701 
0702 exception_restore:
0703     //

0704     {
0705         for(;;)
0706         {
0707             const PSInstruction &_i_ = *ci->_ip++;
0708             //dumpstack(_stackbase);

0709             //scprintf("\n[%d] %s %d %d %d %d\n",ci->_ip-_closure(ci->_closure)->_function->_instructions,g_InstrDesc[_i_.op].name,arg0,arg1,arg2,arg3);

0710             switch(_i_.op)
0711             {
0712             case _OP_LINE: if (_debughook) CallDebugHook(_SC('l'),arg1); continue;
0713             case _OP_LOAD: TARGET = ci->_literals[arg1]; continue;
0714             case _OP_LOADINT:
0715 #ifndef _PS64
0716                 TARGET = (PSInteger)arg1; continue;
0717 #else
0718                 TARGET = (PSInteger)((PSInt32)arg1); continue;
0719 #endif
0720             case _OP_LOADFLOAT: TARGET = *((const PSFloat *)&arg1); continue;
0721             case _OP_DLOAD: TARGET = ci->_literals[arg1]; STK(arg2) = ci->_literals[arg3];continue;
0722             case _OP_TAILCALL:{
0723                 PSObjectPtr &t = STK(arg1);
0724                 if (type(t) == OT_CLOSURE
0725                     && (!_closure(t)->_function->_bgenerator)){
0726                     PSObjectPtr clo = t;
0727                     if(_openouters) CloseOuters(&(_stack._vals[_stackbase]));
0728                     for (PSInteger i = 0; i < arg3; i++) STK(i) = STK(arg2 + i);
0729                     _GUARD(StartCall(_closure(clo), ci->_target, arg3, _stackbase, true));
0730                     continue;
0731                 }
0732                               }
0733             case _OP_CALL: {
0734                     PSObjectPtr clo = STK(arg1);
0735                     switch (type(clo)) {
0736                     case OT_CLOSURE:
0737                         _GUARD(StartCall(_closure(clo), sarg0, arg3, _stackbase+arg2, false));
0738                         continue;
0739                     case OT_NATIVECLOSURE: {
0740                         bool suspend;
0741                         _GUARD(CallNative(_nativeclosure(clo), arg3, _stackbase+arg2, clo,suspend));
0742                         if(suspend){
0743                             _suspended = PSTrue;
0744                             _suspended_target = sarg0;
0745                             _suspended_root = ci->_root;
0746                             _suspended_traps = traps;
0747                             outres = clo;
0748                             return true;
0749                         }
0750                         if(sarg0 != -1) {
0751                             STK(arg0) = clo;
0752                         }
0753                                            }
0754                         continue;
0755                     case OT_CLASS:{
0756                         PSObjectPtr inst;
0757                         _GUARD(CreateClassInstance(_class(clo),inst,clo));
0758                         if(sarg0 != -1) {
0759                             STK(arg0) = inst;
0760                         }
0761                         PSInteger stkbase;
0762                         switch(type(clo)) {
0763                             case OT_CLOSURE:
0764                                 stkbase = _stackbase+arg2;
0765                                 _stack._vals[stkbase] = inst;
0766                                 _GUARD(StartCall(_closure(clo), -1, arg3, stkbase, false));
0767                                 break;
0768                             case OT_NATIVECLOSURE:
0769                                 bool suspend;
0770                                 stkbase = _stackbase+arg2;
0771                                 _stack._vals[stkbase] = inst;
0772                                 _GUARD(CallNative(_nativeclosure(clo), arg3, stkbase, clo,suspend));
0773                                 break;
0774                             default: break; //shutup GCC 4.x

0775                         }
0776                         }
0777                         break;
0778                     case OT_TABLE:
0779                     case OT_USERDATA:
0780                     case OT_INSTANCE:{
0781                         PSObjectPtr closure;
0782                         if(_delegable(clo)->_delegate && _delegable(clo)->GetMetaMethod(this,MT_CALL,closure)) {
0783                             Push(clo);
0784                             for (PSInteger i = 0; i < arg3; i++) Push(STK(arg2 + i));
0785                             if(!CallMetaMethod(closure, MT_CALL, arg3+1, clo)) PS_THROW();
0786                             if(sarg0 != -1) {
0787                                 STK(arg0) = clo;
0788                             }
0789                             break;
0790                         }
0791 
0792                         //Raise_Error(_SC("attempt to call '%s'"), GetTypeName(clo));

0793                         //PS_THROW();

0794                       }
0795                     default:
0796                         Raise_Error(_SC("attempt to call '%s'"), GetTypeName(clo));
0797                         PS_THROW();
0798                     }
0799                 }
0800                   continue;
0801             case _OP_PREPCALL:
0802             case _OP_PREPCALLK: {
0803                     PSObjectPtr &key = _i_.op == _OP_PREPCALLK?(ci->_literals)[arg1]:STK(arg1);
0804                     PSObjectPtr &o = STK(arg2);
0805                     if (!Get(o, key, temp_reg,0,arg2)) {
0806                         PS_THROW();
0807                     }
0808                     STK(arg3) = o;
0809                     _Swap(TARGET,temp_reg);//TARGET = temp_reg;

0810                 }
0811                 continue;
0812             case _OP_GETK:
0813                 if (!Get(STK(arg2), ci->_literals[arg1], temp_reg, 0,arg2)) { PS_THROW();}
0814                 _Swap(TARGET,temp_reg);//TARGET = temp_reg;

0815                 continue;
0816             case _OP_MOVE: TARGET = STK(arg1); continue;
0817             case _OP_NEWSLOT:
0818                 _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),false));
0819                 if(arg0 != 0xFF) TARGET = STK(arg3);
0820                 continue;
0821             case _OP_DELETE: _GUARD(DeleteSlot(STK(arg1), STK(arg2), TARGET)); continue;
0822             case _OP_SET:
0823                 if (!Set(STK(arg1), STK(arg2), STK(arg3),arg1)) { PS_THROW(); }
0824                 if (arg0 != 0xFF) TARGET = STK(arg3);
0825                 continue;
0826             case _OP_GET:
0827                 if (!Get(STK(arg1), STK(arg2), temp_reg, 0,arg1)) { PS_THROW(); }
0828                 _Swap(TARGET,temp_reg);//TARGET = temp_reg;

0829                 continue;
0830             case _OP_EQ:{
0831                 bool res;
0832                 if(!IsEqual(STK(arg2),COND_LITERAL,res)) { PS_THROW(); }
0833                 TARGET = res?true:false;
0834                 }continue;
0835             case _OP_NE:{
0836                 bool res;
0837                 if(!IsEqual(STK(arg2),COND_LITERAL,res)) { PS_THROW(); }
0838                 TARGET = (!res)?true:false;
0839                 } continue;
0840             case _OP_ADD: _ARITH_(+,TARGET,STK(arg2),STK(arg1)); continue;
0841             case _OP_SUB: _ARITH_(-,TARGET,STK(arg2),STK(arg1)); continue;
0842             case _OP_MUL: _ARITH_(*,TARGET,STK(arg2),STK(arg1)); continue;
0843             case _OP_DIV: _ARITH_NOZERO(/,TARGET,STK(arg2),STK(arg1),_SC("division by zero")); continue;
0844             case _OP_MOD: ARITH_OP('%',TARGET,STK(arg2),STK(arg1)); continue;
0845             case _OP_BITW:  _GUARD(BW_OP( arg3,TARGET,STK(arg2),STK(arg1))); continue;
0846             case _OP_RETURN:
0847                 if((ci)->_generator) {
0848                     (ci)->_generator->Kill();
0849                 }
0850                 if(Return(arg0, arg1, temp_reg)){
0851                     assert(traps==0);
0852                     //outres = temp_reg;

0853                     _Swap(outres,temp_reg);
0854                     return true;
0855                 }
0856                 continue;
0857             case _OP_LOADNULLS:{ for(PSInt32 n=0; n < arg1; n++) STK(arg0+n).Null(); }continue;
0858             case _OP_LOADROOT:  {
0859                 PSWeakRef *w = _closure(ci->_closure)->_root;
0860                 if(type(w->_obj) != OT_NULL) {
0861                     TARGET = w->_obj;
0862                 } else {
0863                     TARGET = _roottable; //shoud this be like this? or null

0864                 }
0865                                 }
0866                 continue;
0867             case _OP_LOADBOOL: TARGET = arg1?true:false; continue;
0868             case _OP_DMOVE: STK(arg0) = STK(arg1); STK(arg2) = STK(arg3); continue;
0869             case _OP_JMP: ci->_ip += (sarg1); continue;
0870             //case _OP_JNZ: if(!IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue;

0871             case _OP_JCMP:
0872                 _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg0),temp_reg));
0873                 if(IsFalse(temp_reg)) ci->_ip+=(sarg1);
0874                 continue;
0875             case _OP_JZ: if(IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue;
0876             case _OP_GETOUTER: {
0877                 PSClosure *cur_cls = _closure(ci->_closure);
0878                 PSOuter *otr = _outer(cur_cls->_outervalues[arg1]);
0879                 TARGET = *(otr->_valptr);
0880                 }
0881             continue;
0882             case _OP_SETOUTER: {
0883                 PSClosure *cur_cls = _closure(ci->_closure);
0884                 PSOuter   *otr = _outer(cur_cls->_outervalues[arg1]);
0885                 *(otr->_valptr) = STK(arg2);
0886                 if(arg0 != 0xFF) {
0887                     TARGET = STK(arg2);
0888                 }
0889                 }
0890             continue;
0891             case _OP_NEWOBJ:
0892                 switch(arg3) {
0893                     case NOT_TABLE: TARGET = PSTable::Create(_ss(this), arg1); continue;
0894                     case NOT_ARRAY: TARGET = PSArray::Create(_ss(this), 0); _array(TARGET)->Reserve(arg1); continue;
0895                     case NOT_CLASS: _GUARD(CLASS_OP(TARGET,arg1,arg2)); continue;
0896                     default: assert(0); continue;
0897                 }
0898             case _OP_APPENDARRAY:
0899                 {
0900                     PSObject val;
0901                     val._unVal.raw = 0;
0902                 switch(arg2) {
0903                 case AAT_STACK:
0904                     val = STK(arg1); break;
0905                 case AAT_LITERAL:
0906                     val = ci->_literals[arg1]; break;
0907                 case AAT_INT:
0908                     val._type = OT_INTEGER;
0909 #ifndef _PS64
0910                     val._unVal.nInteger = (PSInteger)arg1;
0911 #else
0912                     val._unVal.nInteger = (PSInteger)((PSInt32)arg1);
0913 #endif
0914                     break;
0915                 case AAT_FLOAT:
0916                     val._type = OT_FLOAT;
0917                     val._unVal.fFloat = *((const PSFloat *)&arg1);
0918                     break;
0919                 case AAT_BOOL:
0920                     val._type = OT_BOOL;
0921                     val._unVal.nInteger = arg1;
0922                     break;
0923                 default: val._type = OT_INTEGER; assert(0); break;
0924 
0925                 }
0926                 _array(STK(arg0))->Append(val); continue;
0927                 }
0928             case _OP_COMPARITH: {
0929                 PSInteger selfidx = (((PSUnsignedInteger)arg1&0xFFFF0000)>>16);
0930                 _GUARD(DerefInc(arg3, TARGET, STK(selfidx), STK(arg2), STK(arg1&0x0000FFFF), false, selfidx));
0931                                 }
0932                 continue;
0933             case _OP_INC: {PSObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, false, arg1));} continue;
0934             case _OP_INCL: {
0935                 PSObjectPtr &a = STK(arg1);
0936                 if(type(a) == OT_INTEGER) {
0937                     a._unVal.nInteger = _integer(a) + sarg3;
0938                 }
0939                 else {
0940                     PSObjectPtr o(sarg3); //_GUARD(LOCAL_INC('+',TARGET, STK(arg1), o));

0941                     _ARITH_(+,a,a,o);
0942                 }
0943                            } continue;
0944             case _OP_PINC: {PSObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, true, arg1));} continue;
0945             case _OP_PINCL: {
0946                 PSObjectPtr &a = STK(arg1);
0947                 if(type(a) == OT_INTEGER) {
0948                     TARGET = a;
0949                     a._unVal.nInteger = _integer(a) + sarg3;
0950                 }
0951                 else {
0952                     PSObjectPtr o(sarg3); _GUARD(PLOCAL_INC('+',TARGET, STK(arg1), o));
0953                 }
0954 
0955                         } continue;
0956             case _OP_CMP:   _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg1),TARGET))  continue;
0957             case _OP_EXISTS: TARGET = Get(STK(arg1), STK(arg2), temp_reg, GET_FLAG_DO_NOT_RAISE_ERROR | GET_FLAG_RAW, DONT_FALL_BACK) ? true : false; continue;
0958             case _OP_INSTANCEOF:
0959                 if(type(STK(arg1)) != OT_CLASS)
0960                 {Raise_Error(_SC("cannot apply instanceof between a %s and a %s"),GetTypeName(STK(arg1)),GetTypeName(STK(arg2))); PS_THROW();}
0961                 TARGET = (type(STK(arg2)) == OT_INSTANCE) ? (_instance(STK(arg2))->InstanceOf(_class(STK(arg1)))?true:false) : false;
0962                 continue;
0963             case _OP_AND:
0964                 if(IsFalse(STK(arg2))) {
0965                     TARGET = STK(arg2);
0966                     ci->_ip += (sarg1);
0967                 }
0968                 continue;
0969             case _OP_OR:
0970                 if(!IsFalse(STK(arg2))) {
0971                     TARGET = STK(arg2);
0972                     ci->_ip += (sarg1);
0973                 }
0974                 continue;
0975             case _OP_NEG: _GUARD(NEG_OP(TARGET,STK(arg1))); continue;
0976             case _OP_NOT: TARGET = IsFalse(STK(arg1)); continue;
0977             case _OP_BWNOT:
0978                 if(type(STK(arg1)) == OT_INTEGER) {
0979                     PSInteger t = _integer(STK(arg1));
0980                     TARGET = PSInteger(~t);
0981                     continue;
0982                 }
0983                 Raise_Error(_SC("attempt to perform a bitwise op on a %s"), GetTypeName(STK(arg1)));
0984                 PS_THROW();
0985             case _OP_CLOSURE: {
0986                 PSClosure *c = ci->_closure._unVal.pClosure;
0987                 PSFunctionProto *fp = c->_function;
0988                 if(!CLOSURE_OP(TARGET,fp->_functions[arg1]._unVal.pFunctionProto)) { PS_THROW(); }
0989                 continue;
0990             }
0991             case _OP_YIELD:{
0992                 if(ci->_generator) {
0993                     if(sarg1 != MAX_FUNC_STACKSIZE) temp_reg = STK(arg1);
0994                     _GUARD(ci->_generator->Yield(this,arg2));
0995                     traps -= ci->_etraps;
0996                     if(sarg1 != MAX_FUNC_STACKSIZE) _Swap(STK(arg1),temp_reg);//STK(arg1) = temp_reg;

0997                 }
0998                 else { Raise_Error(_SC("trying to yield a '%s',only genenerator can be yielded"), GetTypeName(ci->_generator)); PS_THROW();}
0999                 if(Return(arg0, arg1, temp_reg)){
1000                     assert(traps == 0);
1001                     outres = temp_reg;
1002                     return true;
1003                 }
1004 
1005                 }
1006                 continue;
1007             case _OP_RESUME:
1008                 if(type(STK(arg1)) != OT_GENERATOR){ Raise_Error(_SC("trying to resume a '%s',only genenerator can be resumed"), GetTypeName(STK(arg1))); PS_THROW();}
1009                 _GUARD(_generator(STK(arg1))->Resume(this, TARGET));
1010                 traps += ci->_etraps;
1011                 continue;
1012             case _OP_FOREACH:{ int tojump;
1013                 _GUARD(FOREACH_OP(STK(arg0),STK(arg2),STK(arg2+1),STK(arg2+2),arg2,sarg1,tojump));
1014                 ci->_ip += tojump; }
1015                 continue;
1016             case _OP_POSTFOREACH:
1017                 assert(type(STK(arg0)) == OT_GENERATOR);
1018                 if(_generator(STK(arg0))->_state == PSGenerator::eDead)
1019                     ci->_ip += (sarg1 - 1);
1020                 continue;
1021             case _OP_CLONE: _GUARD(Clone(STK(arg1), TARGET)); continue;
1022             case _OP_TYPEOF: _GUARD(TypeOf(STK(arg1), TARGET)) continue;
1023             case _OP_PUSHTRAP:{
1024                 PSInstruction *_iv = _closure(ci->_closure)->_function->_instructions;
1025                 _etraps.push_back(PSExceptionTrap(_top,_stackbase, &_iv[(ci->_ip-_iv)+arg1], arg0)); traps++;
1026                 ci->_etraps++;
1027                               }
1028                 continue;
1029             case _OP_POPTRAP: {
1030                 for(PSInteger i = 0; i < arg0; i++) {
1031                     _etraps.pop_back(); traps--;
1032                     ci->_etraps--;
1033                 }
1034                               }
1035                 continue;
1036             case _OP_THROW: Raise_Error(TARGET); PS_THROW(); continue;
1037             case _OP_NEWSLOTA:
1038                 _GUARD(NewSlotA(STK(arg1),STK(arg2),STK(arg3),(arg0&NEW_SLOT_ATTRIBUTES_FLAG) ? STK(arg2-1) : PSObjectPtr(),(arg0&NEW_SLOT_STATIC_FLAG)?true:false,false));
1039                 continue;
1040             case _OP_GETBASE:{
1041                 PSClosure *clo = _closure(ci->_closure);
1042                 if(clo->_base) {
1043                     TARGET = clo->_base;
1044                 }
1045                 else {
1046                     TARGET.Null();
1047                 }
1048                 continue;
1049             }
1050             case _OP_CLOSE:
1051                 if(_openouters) CloseOuters(&(STK(arg1)));
1052                 continue;
1053             }
1054 
1055         }
1056     }
1057 exception_trap:
1058     {
1059         PSObjectPtr currerror = _lasterror;
1060 //      dumpstack(_stackbase);

1061 //      PSInteger n = 0;

1062         PSInteger last_top = _top;
1063 
1064         if(_ss(this)->_notifyallexceptions || (!traps && raiseerror)) CallErrorHandler(currerror);
1065 
1066         while( ci ) {
1067             if(ci->_etraps > 0) {
1068                 PSExceptionTrap &et = _etraps.top();
1069                 ci->_ip = et._ip;
1070                 _top = et._stacksize;
1071                 _stackbase = et._stackbase;
1072                 _stack._vals[_stackbase + et._extarget] = currerror;
1073                 _etraps.pop_back(); traps--; ci->_etraps--;
1074                 while(last_top >= _top) _stack._vals[last_top--].Null();
1075                 goto exception_restore;
1076             }
1077             else if (_debughook) {
1078                     //notify debugger of a "return"

1079                     //even if it really an exception unwinding the stack

1080                     for(PSInteger i = 0; i < ci->_ncalls; i++) {
1081                         CallDebugHook(_SC('r'));
1082                     }
1083             }
1084             if(ci->_generator) ci->_generator->Kill();
1085             bool mustbreak = ci && ci->_root;
1086             LeaveFrame();
1087             if(mustbreak) break;
1088         }
1089 
1090         _lasterror = currerror;
1091         return false;
1092     }
1093     assert(0);
1094 }
1095 
1096 bool PSVM::CreateClassInstance(PSClass *theclass, PSObjectPtr &inst, PSObjectPtr &constructor)
1097 {
1098     inst = theclass->CreateInstance();
1099     if(!theclass->GetConstructor(constructor)) {
1100         constructor.Null();
1101     }
1102     return true;
1103 }
1104 
1105 void PSVM::CallErrorHandler(PSObjectPtr &error)
1106 {
1107     if(type(_errorhandler) != OT_NULL) {
1108         PSObjectPtr out;
1109         Push(_roottable); Push(error);
1110         Call(_errorhandler, 2, _top-2, out,PSFalse);
1111         Pop(2);
1112     }
1113 }
1114 
1115 
1116 void PSVM::CallDebugHook(PSInteger type,PSInteger forcedline)
1117 {
1118     _debughook = false;
1119     PSFunctionProto *func=_closure(ci->_closure)->_function;
1120     if(_debughook_native) {
1121         const PSChar *src = type(func->_sourcename) == OT_STRING?_stringval(func->_sourcename):NULL;
1122         const PSChar *fname = type(func->_name) == OT_STRING?_stringval(func->_name):NULL;
1123         PSInteger line = forcedline?forcedline:func->GetLine(ci->_ip);
1124         _debughook_native(this,type,src,line,fname);
1125     }
1126     else {
1127         PSObjectPtr temp_reg;
1128         PSInteger nparams=5;
1129         Push(_roottable); Push(type); Push(func->_sourcename); Push(forcedline?forcedline:func->GetLine(ci->_ip)); Push(func->_name);
1130         Call(_debughook_closure,nparams,_top-nparams,temp_reg,PSFalse);
1131         Pop(nparams);
1132     }
1133     _debughook = true;
1134 }
1135 
1136 bool PSVM::CallNative(PSNativeClosure *nclosure, PSInteger nargs, PSInteger newbase, PSObjectPtr &retval, bool &suspend)
1137 {
1138     PSInteger nparamscheck = nclosure->_nparamscheck;
1139     PSInteger newtop = newbase + nargs + nclosure->_noutervalues;
1140 
1141     if (_nnativecalls + 1 > MAX_NATIVE_CALLS) {
1142         Raise_Error(_SC("Native stack overflow"));
1143         return false;
1144     }
1145 
1146     if(nparamscheck && (((nparamscheck > 0) && (nparamscheck != nargs)) ||
1147         ((nparamscheck < 0) && (nargs < (-nparamscheck)))))
1148     {
1149         Raise_Error(_SC("wrong number of parameters"));
1150         return false;
1151     }
1152 
1153     PSInteger tcs;
1154     PSIntVec &tc = nclosure->_typecheck;
1155     if((tcs = tc.size())) {
1156         for(PSInteger i = 0; i < nargs && i < tcs; i++) {
1157             if((tc._vals[i] != -1) && !(type(_stack._vals[newbase+i]) & tc._vals[i])) {
1158                 Raise_ParamTypeError(i,tc._vals[i],type(_stack._vals[newbase+i]));
1159                 return false;
1160             }
1161         }
1162     }
1163 
1164     if(!EnterFrame(newbase, newtop, false)) return false;
1165     ci->_closure  = nclosure;
1166 
1167     PSInteger outers = nclosure->_noutervalues;
1168     for (PSInteger i = 0; i < outers; i++) {
1169         _stack._vals[newbase+nargs+i] = nclosure->_outervalues[i];
1170     }
1171     if(nclosure->_env) {
1172         _stack._vals[newbase] = nclosure->_env->_obj;
1173     }
1174 
1175     _nnativecalls++;
1176     PSInteger ret = (nclosure->_function)(this);
1177     _nnativecalls--;
1178 
1179     suspend = false;
1180     if (ret == PS_SUSPEND_FLAG) {
1181         suspend = true;
1182     }
1183     else if (ret < 0) {
1184         LeaveFrame();
1185         Raise_Error(_lasterror);
1186         return false;
1187     }
1188     if(ret) {
1189         retval = _stack._vals[_top-1];
1190     }
1191     else {
1192         retval.Null();
1193     }
1194     //retval = ret ? _stack._vals[_top-1] : _null_;

1195     LeaveFrame();
1196     return true;
1197 }
1198 
1199 #define FALLBACK_OK         0
1200 #define FALLBACK_NO_MATCH   1
1201 #define FALLBACK_ERROR      2
1202 
1203 bool PSVM::Get(const PSObjectPtr &self, const PSObjectPtr &key, PSObjectPtr &dest, PSUnsignedInteger getflags, PSInteger selfidx)
1204 {
1205     switch(type(self)){
1206     case OT_TABLE:
1207         if(_table(self)->Get(key,dest))return true;
1208         break;
1209     case OT_ARRAY:
1210         if (ps_isnumeric(key)) { if (_array(self)->Get(tointeger(key), dest)) { return true; } if ((getflags & GET_FLAG_DO_NOT_RAISE_ERROR) == 0) Raise_IdxError(key); return false; }
1211         break;
1212     case OT_INSTANCE:
1213         if(_instance(self)->Get(key,dest)) return true;
1214         break;
1215     case OT_CLASS:
1216         if(_class(self)->Get(key,dest)) return true;
1217         break;
1218     case OT_STRING:
1219         if(ps_isnumeric(key)){
1220             PSInteger n = tointeger(key);
1221             PSInteger len = _string(self)->_len;
1222             if (n < 0) { n += len; }
1223             if (n >= 0 && n < len) {
1224                 dest = PSInteger(_stringval(self)[n]);
1225                 return true;
1226             }
1227             if ((getflags & GET_FLAG_DO_NOT_RAISE_ERROR) == 0) Raise_IdxError(key);
1228             return false;
1229         }
1230         break;
1231     default:break; //shut up compiler

1232     }
1233     if ((getflags & GET_FLAG_RAW) == 0) {
1234         switch(FallBackGet(self,key,dest)) {
1235             case FALLBACK_OK: return true; //okie

1236             case FALLBACK_NO_MATCH: break; //keep falling back

1237             case FALLBACK_ERROR: return false; // the metamethod failed

1238         }
1239         if(InvokeDefaultDelegate(self,key,dest)) {
1240             return true;
1241         }
1242     }
1243 //#ifdef ROOT_FALLBACK

1244     if(selfidx == 0) {
1245         PSWeakRef *w = _closure(ci->_closure)->_root;
1246         if(type(w->_obj) != OT_NULL)
1247         {
1248             if(Get(*((const PSObjectPtr *)&w->_obj),key,dest,0,DONT_FALL_BACK)) return true;
1249         }
1250 
1251     }
1252 //#endif

1253     if ((getflags & GET_FLAG_DO_NOT_RAISE_ERROR) == 0) Raise_IdxError(key);
1254     return false;
1255 }
1256 
1257 bool PSVM::InvokeDefaultDelegate(const PSObjectPtr &self,const PSObjectPtr &key,PSObjectPtr &dest)
1258 {
1259     PSTable *ddel = NULL;
1260     switch(type(self)) {
1261         case OT_CLASS: ddel = _class_ddel; break;
1262         case OT_TABLE: ddel = _table_ddel; break;
1263         case OT_ARRAY: ddel = _array_ddel; break;
1264         case OT_STRING: ddel = _string_ddel; break;
1265         case OT_INSTANCE: ddel = _instance_ddel; break;
1266         case OT_INTEGER:case OT_FLOAT:case OT_BOOL: ddel = _number_ddel; break;
1267         case OT_GENERATOR: ddel = _generator_ddel; break;
1268         case OT_CLOSURE: case OT_NATIVECLOSURE: ddel = _closure_ddel; break;
1269         case OT_THREAD: ddel = _thread_ddel; break;
1270         case OT_WEAKREF: ddel = _weakref_ddel; break;
1271         default: return false;
1272     }
1273     return  ddel->Get(key,dest);
1274 }
1275 
1276 
1277 PSInteger PSVM::FallBackGet(const PSObjectPtr &self,const PSObjectPtr &key,PSObjectPtr &dest)
1278 {
1279     switch(type(self)){
1280     case OT_TABLE:
1281     case OT_USERDATA:
1282         //delegation

1283         if(_delegable(self)->_delegate) {
1284             if(Get(PSObjectPtr(_delegable(self)->_delegate),key,dest,0,DONT_FALL_BACK)) return FALLBACK_OK;
1285         }
1286         else {
1287             return FALLBACK_NO_MATCH;
1288         }
1289         //go through

1290     case OT_INSTANCE: {
1291         PSObjectPtr closure;
1292         if(_delegable(self)->GetMetaMethod(this, MT_GET, closure)) {
1293             Push(self);Push(key);
1294             _nmetamethodscall++;
1295             AutoDec ad(&_nmetamethodscall);
1296             if(Call(closure, 2, _top - 2, dest, PSFalse)) {
1297                 Pop(2);
1298                 return FALLBACK_OK;
1299             }
1300             else {
1301                 Pop(2);
1302                 if(type(_lasterror) != OT_NULL) { //NULL means "clean failure" (not found)

1303                     return FALLBACK_ERROR;
1304                 }
1305             }
1306         }
1307                       }
1308         break;
1309     default: break;//shutup GCC 4.x

1310     }
1311     // no metamethod or no fallback type

1312     return FALLBACK_NO_MATCH;
1313 }
1314 
1315 bool PSVM::Set(const PSObjectPtr &self,const PSObjectPtr &key,const PSObjectPtr &val,PSInteger selfidx)
1316 {
1317     switch(type(self)){
1318     case OT_TABLE:
1319         if(_table(self)->Set(key,val)) return true;
1320         break;
1321     case OT_INSTANCE:
1322         if(_instance(self)->Set(key,val)) return true;
1323         break;
1324     case OT_ARRAY:
1325         if(!ps_isnumeric(key)) { Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key)); return false; }
1326         if(!_array(self)->Set(tointeger(key),val)) {
1327             Raise_IdxError(key);
1328             return false;
1329         }
1330         return true;
1331     default:
1332         Raise_Error(_SC("trying to set '%s'"),GetTypeName(self));
1333         return false;
1334     }
1335 
1336     switch(FallBackSet(self,key,val)) {
1337         case FALLBACK_OK: return true; //okie

1338         case FALLBACK_NO_MATCH: break; //keep falling back

1339         case FALLBACK_ERROR: return false; // the metamethod failed

1340     }
1341     if(selfidx == 0) {
1342         if(_table(_roottable)->Set(key,val))
1343             return true;
1344     }
1345     Raise_IdxError(key);
1346     return false;
1347 }
1348 
1349 PSInteger PSVM::FallBackSet(const PSObjectPtr &self,const PSObjectPtr &key,const PSObjectPtr &val)
1350 {
1351     switch(type(self)) {
1352     case OT_TABLE:
1353         if(_table(self)->_delegate) {
1354             if(Set(_table(self)->_delegate,key,val,DONT_FALL_BACK)) return FALLBACK_OK;
1355         }
1356         //keps on going

1357     case OT_INSTANCE:
1358     case OT_USERDATA:{
1359         PSObjectPtr closure;
1360         PSObjectPtr t;
1361         if(_delegable(self)->GetMetaMethod(this, MT_SET, closure)) {
1362             Push(self);Push(key);Push(val);
1363             _nmetamethodscall++;
1364             AutoDec ad(&_nmetamethodscall);
1365             if(Call(closure, 3, _top - 3, t, PSFalse)) {
1366                 Pop(3);
1367                 return FALLBACK_OK;
1368             }
1369             else {
1370                 if(type(_lasterror) != OT_NULL) { //NULL means "clean failure" (not found)

1371                     //error

1372                     Pop(3);
1373                     return FALLBACK_ERROR;
1374                 }
1375             }
1376         }
1377                      }
1378         break;
1379         default: break;//shutup GCC 4.x

1380     }
1381     // no metamethod or no fallback type

1382     return FALLBACK_NO_MATCH;
1383 }
1384 
1385 bool PSVM::Clone(const PSObjectPtr &self,PSObjectPtr &target)
1386 {
1387     PSObjectPtr temp_reg;
1388     PSObjectPtr newobj;
1389     switch(type(self)){
1390     case OT_TABLE:
1391         newobj = _table(self)->Clone();
1392         goto cloned_mt;
1393     case OT_INSTANCE: {
1394         newobj = _instance(self)->Clone(_ss(this));
1395 cloned_mt:
1396         PSObjectPtr closure;
1397         if(_delegable(newobj)->_delegate && _delegable(newobj)->GetMetaMethod(this,MT_CLONED,closure)) {
1398             Push(newobj);
1399             Push(self);
1400             if(!CallMetaMethod(closure,MT_CLONED,2,temp_reg))
1401                 return false;
1402         }
1403         }
1404         target = newobj;
1405         return true;
1406     case OT_ARRAY:
1407         target = _array(self)->Clone();
1408         return true;
1409     default:
1410         Raise_Error(_SC("cloning a %s"), GetTypeName(self));
1411         return false;
1412     }
1413 }
1414 
1415 bool PSVM::NewSlotA(const PSObjectPtr &self,const PSObjectPtr &key,const PSObjectPtr &val,const PSObjectPtr &attrs,bool bstatic,bool raw)
1416 {
1417     if(type(self) != OT_CLASS) {
1418         Raise_Error(_SC("object must be a class"));
1419         return false;
1420     }
1421     PSClass *c = _class(self);
1422     if(!raw) {
1423         PSObjectPtr &mm = c->_metamethods[MT_NEWMEMBER];
1424         if(type(mm) != OT_NULL ) {
1425             Push(self); Push(key); Push(val);
1426             Push(attrs);
1427             Push(bstatic);
1428             return CallMetaMethod(mm,MT_NEWMEMBER,5,temp_reg);
1429         }
1430     }
1431     if(!NewSlot(self, key, val,bstatic))
1432         return false;
1433     if(type(attrs) != OT_NULL) {
1434         c->SetAttributes(key,attrs);
1435     }
1436     return true;
1437 }
1438 
1439 bool PSVM::NewSlot(const PSObjectPtr &self,const PSObjectPtr &key,const PSObjectPtr &val,bool bstatic)
1440 {
1441     if(type(key) == OT_NULL) { Raise_Error(_SC("null cannot be used as index")); return false; }
1442     switch(type(self)) {
1443     case OT_TABLE: {
1444         bool rawcall = true;
1445         if(_table(self)->_delegate) {
1446             PSObjectPtr res;
1447             if(!_table(self)->Get(key,res)) {
1448                 PSObjectPtr closure;
1449                 if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_NEWSLOT,closure)) {
1450                     Push(self);Push(key);Push(val);
1451                     if(!CallMetaMethod(closure,MT_NEWSLOT,3,res)) {
1452                         return false;
1453                     }
1454                     rawcall = false;
1455                 }
1456                 else {
1457                     rawcall = true;
1458                 }
1459             }
1460         }
1461         if(rawcall) _table(self)->NewSlot(key,val); //cannot fail

1462 
1463         break;}
1464     case OT_INSTANCE: {
1465         PSObjectPtr res;
1466         PSObjectPtr closure;
1467         if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_NEWSLOT,closure)) {
1468             Push(self);Push(key);Push(val);
1469             if(!CallMetaMethod(closure,MT_NEWSLOT,3,res)) {
1470                 return false;
1471             }
1472             break;
1473         }
1474         Raise_Error(_SC("class instances do not support the new slot operator"));
1475         return false;
1476         break;}
1477     case OT_CLASS:
1478         if(!_class(self)->NewSlot(_ss(this),key,val,bstatic)) {
1479             if(_class(self)->_locked) {
1480                 Raise_Error(_SC("trying to modify a class that has already been instantiated"));
1481                 return false;
1482             }
1483             else {
1484                 PSObjectPtr oval = PrintObjVal(key);
1485                 Raise_Error(_SC("the property '%s' already exists"),_stringval(oval));
1486                 return false;
1487             }
1488         }
1489         break;
1490     default:
1491         Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key));
1492         return false;
1493         break;
1494     }
1495     return true;
1496 }
1497 
1498 
1499 
1500 bool PSVM::DeleteSlot(const PSObjectPtr &self,const PSObjectPtr &key,PSObjectPtr &res)
1501 {
1502     switch(type(self)) {
1503     case OT_TABLE:
1504     case OT_INSTANCE:
1505     case OT_USERDATA: {
1506         PSObjectPtr t;
1507         //bool handled = false;

1508         PSObjectPtr closure;
1509         if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_DELSLOT,closure)) {
1510             Push(self);Push(key);
1511             return CallMetaMethod(closure,MT_DELSLOT,2,res);
1512         }
1513         else {
1514             if(type(self) == OT_TABLE) {
1515                 if(_table(self)->Get(key,t)) {
1516                     _table(self)->Remove(key);
1517                 }
1518                 else {
1519                     Raise_IdxError((const PSObject &)key);
1520                     return false;
1521                 }
1522             }
1523             else {
1524                 Raise_Error(_SC("cannot delete a slot from %s"),GetTypeName(self));
1525                 return false;
1526             }
1527         }
1528         res = t;
1529                 }
1530         break;
1531     default:
1532         Raise_Error(_SC("attempt to delete a slot from a %s"),GetTypeName(self));
1533         return false;
1534     }
1535     return true;
1536 }
1537 
1538 bool PSVM::Call(PSObjectPtr &closure,PSInteger nparams,PSInteger stackbase,PSObjectPtr &outres,PSBool raiseerror)
1539 {
1540 #ifdef _DEBUG
1541 PSInteger prevstackbase = _stackbase;
1542 #endif
1543     switch(type(closure)) {
1544     case OT_CLOSURE:
1545         return Execute(closure, nparams, stackbase, outres, raiseerror);
1546         break;
1547     case OT_NATIVECLOSURE:{
1548         bool suspend;
1549         return CallNative(_nativeclosure(closure), nparams, stackbase, outres,suspend);
1550 
1551                           }
1552         break;
1553     case OT_CLASS: {
1554         PSObjectPtr constr;
1555         PSObjectPtr temp;
1556         CreateClassInstance(_class(closure),outres,constr);
1557         PSObjectType ctype = type(constr);
1558         if (ctype == OT_NATIVECLOSURE || ctype == OT_CLOSURE) {
1559             _stack[stackbase] = outres;
1560             return Call(constr,nparams,stackbase,temp,raiseerror);
1561         }
1562         return true;
1563                    }
1564         break;
1565     default:
1566         return false;
1567     }
1568 #ifdef _DEBUG
1569     if(!_suspended) {
1570         assert(_stackbase == prevstackbase);
1571     }
1572 #endif
1573     return true;
1574 }
1575 
1576 bool PSVM::CallMetaMethod(PSObjectPtr &closure,PSMetaMethod PS_UNUSED_ARG(mm),PSInteger nparams,PSObjectPtr &outres)
1577 {
1578     //PSObjectPtr closure;

1579 
1580     _nmetamethodscall++;
1581     if(Call(closure, nparams, _top - nparams, outres, PSFalse)) {
1582         _nmetamethodscall--;
1583         Pop(nparams);
1584         return true;
1585     }
1586     _nmetamethodscall--;
1587     //}

1588     Pop(nparams);
1589     return false;
1590 }
1591 
1592 void PSVM::FindOuter(PSObjectPtr &target, PSObjectPtr *stackindex)
1593 {
1594     PSOuter **pp = &_openouters;
1595     PSOuter *p;
1596     PSOuter *otr;
1597 
1598     while ((p = *pp) != NULL && p->_valptr >= stackindex) {
1599         if (p->_valptr == stackindex) {
1600             target = PSObjectPtr(p);
1601             return;
1602         }
1603         pp = &p->_next;
1604     }
1605     otr = PSOuter::Create(_ss(this), stackindex);
1606     otr->_next = *pp;
1607     otr->_idx  = (stackindex - _stack._vals);
1608     __ObjAddRef(otr);
1609     *pp = otr;
1610     target = PSObjectPtr(otr);
1611 }
1612 
1613 bool PSVM::EnterFrame(PSInteger newbase, PSInteger newtop, bool tailcall)
1614 {
1615     if( !tailcall ) {
1616         if( _callsstacksize == _alloccallsstacksize ) {
1617             GrowCallStack();
1618         }
1619         ci = &_callsstack[_callsstacksize++];
1620         ci->_prevstkbase = (PSInt32)(newbase - _stackbase);
1621         ci->_prevtop = (PSInt32)(_top - _stackbase);
1622         ci->_etraps = 0;
1623         ci->_ncalls = 1;
1624         ci->_generator = NULL;
1625         ci->_root = PSFalse;
1626     }
1627     else {
1628         ci->_ncalls++;
1629     }
1630 
1631     _stackbase = newbase;
1632     _top = newtop;
1633     if(newtop + MIN_STACK_OVERHEAD > (PSInteger)_stack.size()) {
1634         if(_nmetamethodscall) {
1635             Raise_Error(_SC("stack overflow, cannot resize stack while in  a metamethod"));
1636             return false;
1637         }
1638         _stack.resize(newtop + (MIN_STACK_OVERHEAD << 2));
1639         RelocateOuters();
1640     }
1641     return true;
1642 }
1643 
1644 void PSVM::LeaveFrame() {
1645     PSInteger last_top = _top;
1646     PSInteger last_stackbase = _stackbase;
1647     PSInteger css = --_callsstacksize;
1648 
1649     /* First clean out the call stack frame */
1650     ci->_closure.Null();
1651     _stackbase -= ci->_prevstkbase;
1652     _top = _stackbase + ci->_prevtop;
1653     ci = (css) ? &_callsstack[css-1] : NULL;
1654 
1655     if(_openouters) CloseOuters(&(_stack._vals[last_stackbase]));
1656     while (last_top >= _top) {
1657         _stack._vals[last_top--].Null();
1658     }
1659 }
1660 
1661 void PSVM::RelocateOuters()
1662 {
1663     PSOuter *p = _openouters;
1664     while (p) {
1665         p->_valptr = _stack._vals + p->_idx;
1666         p = p->_next;
1667     }
1668 }
1669 
1670 void PSVM::CloseOuters(PSObjectPtr *stackindex) {
1671   PSOuter *p;
1672   while ((p = _openouters) != NULL && p->_valptr >= stackindex) {
1673     p->_value = *(p->_valptr);
1674     p->_valptr = &p->_value;
1675     _openouters = p->_next;
1676     __ObjRelease(p);
1677   }
1678 }
1679 
1680 void PSVM::Remove(PSInteger n) {
1681     n = (n >= 0)?n + _stackbase - 1:_top + n;
1682     for(PSInteger i = n; i < _top; i++){
1683         _stack[i] = _stack[i+1];
1684     }
1685     _stack[_top].Null();
1686     _top--;
1687 }
1688 
1689 void PSVM::Pop() {
1690     _stack[--_top].Null();
1691 }
1692 
1693 void PSVM::Pop(PSInteger n) {
1694     for(PSInteger i = 0; i < n; i++){
1695         _stack[--_top].Null();
1696     }
1697 }
1698 
1699 void PSVM::PushNull() { _stack[_top++].Null(); }
1700 void PSVM::Push(const PSObjectPtr &o) { _stack[_top++] = o; }
1701 PSObjectPtr &PSVM::Top() { return _stack[_top-1]; }
1702 PSObjectPtr &PSVM::PopGet() { return _stack[--_top]; }
1703 PSObjectPtr &PSVM::GetUp(PSInteger n) { return _stack[_top+n]; }
1704 PSObjectPtr &PSVM::GetAt(PSInteger n) { return _stack[n]; }
1705 
1706 #ifdef _DEBUG_DUMP
1707 void PSVM::dumpstack(PSInteger stackbase,bool dumpall)
1708 {
1709     PSInteger size=dumpall?_stack.size():_top;
1710     PSInteger n=0;
1711     scprintf(_SC("\n>>>>stack dump<<<<\n"));
1712     CallInfo &ci=_callsstack[_callsstacksize-1];
1713     scprintf(_SC("IP: %p\n"),ci._ip);
1714     scprintf(_SC("prev stack base: %d\n"),ci._prevstkbase);
1715     scprintf(_SC("prev top: %d\n"),ci._prevtop);
1716     for(PSInteger i=0;i<size;i++){
1717         PSObjectPtr &obj=_stack[i];
1718         if(stackbase==i)scprintf(_SC(">"));else scprintf(_SC(" "));
1719         scprintf(_SC("[%d]:"),n);
1720         switch(type(obj)){
1721         case OT_FLOAT:          scprintf(_SC("FLOAT %.3f"),_float(obj));break;
1722         case OT_INTEGER:        scprintf(_SC("INTEGER %d"),_integer(obj));break;
1723         case OT_BOOL:           scprintf(_SC("BOOL %s"),_integer(obj)?"true":"false");break;
1724         case OT_STRING:         scprintf(_SC("STRING %s"),_stringval(obj));break;
1725         case OT_NULL:           scprintf(_SC("NULL"));  break;
1726         case OT_TABLE:          scprintf(_SC("TABLE %p[%p]"),_table(obj),_table(obj)->_delegate);break;
1727         case OT_ARRAY:          scprintf(_SC("ARRAY %p"),_array(obj));break;
1728         case OT_CLOSURE:        scprintf(_SC("CLOSURE [%p]"),_closure(obj));break;
1729         case OT_NATIVECLOSURE:  scprintf(_SC("NATIVECLOSURE"));break;
1730         case OT_USERDATA:       scprintf(_SC("USERDATA %p[%p]"),_userdataval(obj),_userdata(obj)->_delegate);break;
1731         case OT_GENERATOR:      scprintf(_SC("GENERATOR %p"),_generator(obj));break;
1732         case OT_THREAD:         scprintf(_SC("THREAD [%p]"),_thread(obj));break;
1733         case OT_USERPOINTER:    scprintf(_SC("USERPOINTER %p"),_userpointer(obj));break;
1734         case OT_CLASS:          scprintf(_SC("CLASS %p"),_class(obj));break;
1735         case OT_INSTANCE:       scprintf(_SC("INSTANCE %p"),_instance(obj));break;
1736         case OT_WEAKREF:        scprintf(_SC("WEAKERF %p"),_weakref(obj));break;
1737         default:
1738             assert(0);
1739             break;
1740         };
1741         scprintf(_SC("\n"));
1742         ++n;
1743     }
1744 }
1745 
1746 
1747 
1748 #endif