#define TOP() (_stack._vals[_top-1])
+#define CLEARSTACK(_last_top) { if((_last_top) >= _top) ClearStack(_last_top); }
+void SQVM::ClearStack(SQInteger last_top)
+{
+ SQObjectType tOldType;
+ SQObjectValue unOldVal;
+ while (last_top >= _top) {
+ SQObjectPtr &o = _stack._vals[last_top--];
+ tOldType = o._type;
+ unOldVal = o._unVal;
+ o._type = OT_NULL;
+ o._unVal.pUserPointer = NULL;
+ __Release(tOldType,unOldVal);
+ }
+}
+
bool SQVM::BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2)
{
SQInteger res;
res = i1 / i2;
break;
case '*': res = i1 * i2; break;
- case '%': res = i1 % i2; break;
+ case '%': if(i2 == 0) { Raise_Error(_SC("modulo by zero")); return false; }
+ res = i1 % i2;
+ break;
default: res = 0xDEADBEEF;
}
trg = res;
_errorhandler = _null_;
_debughook = _null_;
temp_reg = _null_;
+ _callstackdata.resize(0);
SQInteger size=_stack.size();
for(SQInteger i=0;i<size;i++)
_stack[i]=_null_;
SQVM::~SQVM()
{
Finalize();
- sq_free(_callsstack,_alloccallsstacksize*sizeof(CallInfo));
+ //sq_free(_callsstack,_alloccallsstacksize*sizeof(CallInfo));
REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);
}
return true;
}
-const SQChar *IdType2Name(SQObjectType type)
-{
- switch(_RAW_TYPE(type))
- {
- case _RT_NULL:return _SC("null");
- case _RT_INTEGER:return _SC("integer");
- case _RT_FLOAT:return _SC("float");
- case _RT_BOOL:return _SC("bool");
- case _RT_STRING:return _SC("string");
- case _RT_TABLE:return _SC("table");
- case _RT_ARRAY:return _SC("array");
- case _RT_GENERATOR:return _SC("generator");
- case _RT_CLOSURE:
- case _RT_NATIVECLOSURE:
- return _SC("function");
- case _RT_USERDATA:
- case _RT_USERPOINTER:
- return _SC("userdata");
- case _RT_THREAD: return _SC("thread");
- case _RT_FUNCPROTO: return _SC("function");
- case _RT_CLASS: return _SC("class");
- case _RT_INSTANCE: return _SC("instance");
- case _RT_WEAKREF: return _SC("weakref");
- default:
- return NULL;
- }
-}
-
-const SQChar *GetTypeName(const SQObjectPtr &obj1)
-{
- return IdType2Name(type(obj1));
-}
-
void SQVM::TypeOf(const SQObjectPtr &obj1,SQObjectPtr &dest)
{
if(is_delegable(obj1) && _delegable(obj1)->_delegate) {
bool SQVM::Init(SQVM *friendvm, SQInteger stacksize)
{
_stack.resize(stacksize);
- //_callsstack.reserve(4);
_alloccallsstacksize = 4;
+ _callstackdata.resize(_alloccallsstacksize);
_callsstacksize = 0;
- _callsstack = (CallInfo*)sq_malloc(_alloccallsstacksize*sizeof(CallInfo));
+ _callsstack = &_callstackdata[0];
_stackbase = 0;
_top = 0;
if(!friendvm)
extern SQInstructionDesc g_InstrDesc[];
-bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger nargs,SQInteger stackbase,bool tailcall)
+bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger args,SQInteger stackbase,bool tailcall)
{
SQFunctionProto *func = _funcproto(closure->_function);
const SQInteger paramssize = func->_nparameters;
const SQInteger newtop = stackbase + func->_stacksize;
-
-
+ SQInteger nargs = args;
if (paramssize != nargs) {
- if(func->_varparams)
+ SQInteger ndef = func->_ndefaultparams;
+ if(ndef && nargs < paramssize) {
+ SQInteger diff = paramssize - nargs;
+ for(SQInteger n = ndef - diff; n < ndef; n++) {
+ _stack._vals[stackbase + (nargs++)] = closure->_defaultparams[n];
+ }
+ }
+ else if(func->_varparams)
{
if (nargs < paramssize) {
Raise_Error(_SC("wrong number of parameters"));
if (!tailcall) {
CallInfo lc;
+ lc._generator = NULL;
lc._etraps = 0;
lc._prevstkbase = (SQInt32) ( stackbase - _stackbase );
lc._target = (SQInt32) target;
ci->_ncalls++;
}
ci->_vargs.size = (SQInt32)(nargs - paramssize);
- ci->_vargs.base = (SQInt32) (_vargsstack.size()-(ci->_vargs.size));
- ci->_closure._unVal.pClosure = closure;
- ci->_closure._type = OT_CLOSURE;
+ ci->_vargs.base = (SQInt32)(_vargsstack.size()-(ci->_vargs.size));
+ ci->_closure = closure;
ci->_literals = func->_literals;
ci->_ip = func->_instructions;
//grows the stack if needed
_top = newtop;
_stackbase = stackbase;
+ if (type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure))
+ CallDebugHook(_SC('c'));
return true;
}
}
}
- while (last_top >= _top) _stack._vals[last_top--].Null();
+ CLEARSTACK(last_top);
assert(oldstackbase >= _stackbase);
return broot?true:false;
}
}
}
}
+ SQInteger ndefparams;
+ if((ndefparams = func->_ndefaultparams)) {
+ closure->_defaultparams.reserve(ndefparams);
+ for(SQInteger i = 0; i < ndefparams; i++) {
+ SQInteger spos = func->_defaultparams[i];
+ closure->_defaultparams.push_back(_stack._vals[_stackbase + spos]);
+ }
+ }
target = closure;
return true;
bool ct_tailcall;
switch(et) {
- case ET_CALL:
- if(!StartCall(_closure(closure), _top - nargs, nargs, stackbase, false)) {
+ case ET_CALL: {
+ SQInteger last_top = _top;
+ temp_reg = closure;
+ if(!StartCall(_closure(temp_reg), _top - nargs, nargs, stackbase, false)) {
//call the handler if there are no calls in the stack, if not relies on the previous node
if(ci == NULL) CallErrorHandler(_lasterror);
return false;
}
+ if (_funcproto(_closure(temp_reg)->_function)->_bgenerator) {
+ SQFunctionProto *f = _funcproto(_closure(temp_reg)->_function);
+ SQGenerator *gen = SQGenerator::Create(_ss(this), _closure(temp_reg));
+ _GUARD(gen->Yield(this));
+ Return(1, ci->_target, temp_reg);
+ outres = gen;
+ CLEARSTACK(last_top);
+ return true;
+ }
ci->_root = SQTrue;
+ }
break;
case ET_RESUME_GENERATOR: _generator(closure)->Resume(this, target); ci->_root = SQTrue; traps += ci->_etraps; break;
case ET_RESUME_VM:
+ case ET_RESUME_THROW_VM:
traps = _suspended_traps;
ci->_root = _suspended_root;
ci->_vargs = _suspend_varargs;
_suspended = SQFalse;
+ if(et == ET_RESUME_THROW_VM) { SQ_THROW(); }
break;
}
case _OP_DLOAD: TARGET = ci->_literals[arg1]; STK(arg2) = ci->_literals[arg3];continue;
case _OP_TAILCALL:
temp_reg = STK(arg1);
- if (type(temp_reg) == OT_CLOSURE){
+ if (type(temp_reg) == OT_CLOSURE && !_funcproto(_closure(temp_reg)->_function)->_bgenerator){
ct_tailcall = true;
if(ci->_vargs.size) PopVarArgs(ci->_vargs);
for (SQInteger i = 0; i < arg3; i++) STK(i) = STK(arg2 + i);
ct_stackbase = _stackbase+arg2;
common_call:
+ SQObjectPtr clo = temp_reg;
SQInteger last_top = _top;
- switch (type(temp_reg)) {
+ switch (type(clo)) {
case OT_CLOSURE:{
- _GUARD(StartCall(_closure(temp_reg), ct_target, arg3, ct_stackbase, ct_tailcall));
- if (_funcproto(_closure(temp_reg)->_function)->_bgenerator) {
- SQGenerator *gen = SQGenerator::Create(_ss(this), _closure(temp_reg));
+ _GUARD(StartCall(_closure(clo), ct_target, arg3, ct_stackbase, ct_tailcall));
+ if (_funcproto(_closure(clo)->_function)->_bgenerator) {
+ SQGenerator *gen = SQGenerator::Create(_ss(this), _closure(clo));
_GUARD(gen->Yield(this));
- Return(1, ct_target, temp_reg);
-
-
-
-
+ Return(1, ct_target, clo);
STK(ct_target) = gen;
- while (last_top >= _top) _stack._vals[last_top--].Null();
+ CLEARSTACK(last_top);
continue;
}
- if (type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure))
- CallDebugHook(_SC('c'));
}
continue;
case OT_NATIVECLOSURE: {
bool suspend;
- _GUARD(CallNative(_nativeclosure(temp_reg), arg3, ct_stackbase, temp_reg,suspend));
+ _GUARD(CallNative(_nativeclosure(clo), arg3, ct_stackbase, clo,suspend));
if(suspend){
_suspended = SQTrue;
_suspended_target = ct_target;
_suspended_root = ci->_root;
_suspended_traps = traps;
_suspend_varargs = ci->_vargs;
- outres = temp_reg;
+ outres = clo;
return true;
}
if(ct_target != -1) { //skip return value for constructors
- STK(ct_target) = temp_reg;
+ STK(ct_target) = clo;
}
}
continue;
case OT_CLASS:{
SQObjectPtr inst;
- _GUARD(CreateClassInstance(_class(temp_reg),inst,temp_reg));
+ _GUARD(CreateClassInstance(_class(clo),inst,temp_reg));
STK(ct_target) = inst;
ct_target = -1; //fakes return value target so that is not overwritten by the constructor
if(type(temp_reg) != OT_NULL) {
case OT_USERDATA:
case OT_INSTANCE:
{
- Push(temp_reg);
+ Push(clo);
for (SQInteger i = 0; i < arg3; i++) Push(STK(arg2 + i));
- if (_delegable(temp_reg) && CallMetaMethod(_delegable(temp_reg), MT_CALL, arg3+1, temp_reg)){
- STK(ct_target) = temp_reg;
+ if (_delegable(clo) && CallMetaMethod(_delegable(clo), MT_CALL, arg3+1, clo)){
+ STK(ct_target) = clo;
break;
}
- Raise_Error(_SC("attempt to call '%s'"), GetTypeName(temp_reg));
+ Raise_Error(_SC("attempt to call '%s'"), GetTypeName(clo));
SQ_THROW();
}
default:
- Raise_Error(_SC("attempt to call '%s'"), GetTypeName(temp_reg));
+ Raise_Error(_SC("attempt to call '%s'"), GetTypeName(clo));
SQ_THROW();
}
}
case _OP_ARITH: _GUARD(ARITH_OP( arg3 , temp_reg, STK(arg2), STK(arg1))); TARGET = temp_reg; continue;
case _OP_BITW: _GUARD(BW_OP( arg3,TARGET,STK(arg2),STK(arg1))); continue;
case _OP_RETURN:
- if(type((ci)->_generator) == OT_GENERATOR) {
- _generator((ci)->_generator)->Kill();
+ if(ci->_generator) {
+ ci->_generator->Kill();
}
if(Return(arg0, arg1, temp_reg)){
assert(traps==0);
continue;
}
case _OP_YIELD:{
- if(type(ci->_generator) == OT_GENERATOR) {
+ if(ci->_generator) {
if(sarg1 != MAX_FUNC_STACKSIZE) temp_reg = STK(arg1);
- _GUARD(_generator(ci->_generator)->Yield(this));
+ _GUARD(ci->_generator->Yield(this));
traps -= ci->_etraps;
if(sarg1 != MAX_FUNC_STACKSIZE) STK(arg1) = temp_reg;
}
_stackbase = et._stackbase;
_stack._vals[_stackbase+et._extarget] = currerror;
_etraps.pop_back(); traps--; ci->_etraps--;
- while(last_top >= _top) _stack._vals[last_top--].Null();
+ CLEARSTACK(last_top);
goto exception_restore;
}
//if is a native closure
if(type(ci->_closure) != OT_CLOSURE && n)
break;
- if(type(ci->_generator) == OT_GENERATOR) _generator(ci->_generator)->Kill();
+ if(ci->_generator) ci->_generator->Kill();
PopVarArgs(ci->_vargs);
POP_CALLINFO(this);
n++;
//remove call stack until a C function is found or the cstack is empty
if(ci) do {
SQBool exitafterthisone = ci->_root;
- if(type(ci->_generator) == OT_GENERATOR) _generator(ci->_generator)->Kill();
+ if(ci->_generator) ci->_generator->Kill();
_stackbase -= ci->_prevstkbase;
_top = _stackbase + ci->_prevtop;
PopVarArgs(ci->_vargs);
if( (ci && type(ci->_closure) != OT_CLOSURE) || exitafterthisone) break;
} while(_callsstacksize);
- while(last_top >= _top) _stack._vals[last_top--].Null();
+ CLEARSTACK(last_top);
}
_lasterror = currerror;
return false;
{
inst = theclass->CreateInstance();
if(!theclass->Get(_ss(this)->_constructoridx,constructor)) {
- //if(!Call(constr,nargs,stackbase,constr,false))
- // return false;
constructor = _null_;
}
return true;
SQInteger oldstackbase = _stackbase;
_top = stackbase + nargs;
CallInfo lci;
+ lci._closure = nclosure;
+ lci._generator = NULL;
lci._etraps = 0;
- lci._closure._unVal.pNativeClosure = nclosure;
- lci._closure._type = OT_NATIVECLOSURE;
lci._prevstkbase = (SQInt32) (stackbase - _stackbase);
lci._ncalls = 1;
lci._prevtop = (SQInt32) (oldtop - oldstackbase);
return false;
}
- if (ret != 0){ retval = TOP(); }
+ if (ret != 0){ retval = TOP(); TOP().Null(); }
else { retval = _null_; }
_stackbase = oldstackbase;
_top = oldtop;
if(rawcall) _table(self)->NewSlot(key,val); //cannot fail
break;}
+ case OT_INSTANCE: {
+ SQObjectPtr res;
+ Push(self);Push(key);Push(val);
+ if(!CallMetaMethod(_instance(self),MT_NEWSLOT,3,res)) {
+ Raise_Error(_SC("class instances do not support the new slot operator"));
+ return false;
+ }
+ break;}
case OT_CLASS:
if(!_class(self)->NewSlot(_ss(this),key,val,bstatic)) {
if(_class(self)->_locked) {
case OT_CLOSURE: scprintf(_SC("CLOSURE [%p]"),_closure(obj));break;
case OT_NATIVECLOSURE: scprintf(_SC("NATIVECLOSURE"));break;
case OT_USERDATA: scprintf(_SC("USERDATA %p[%p]"),_userdataval(obj),_userdata(obj)->_delegate);break;
- case OT_GENERATOR: scprintf(_SC("GENERATOR"));break;
+ case OT_GENERATOR: scprintf(_SC("GENERATOR %p"),_generator(obj));break;
case OT_THREAD: scprintf(_SC("THREAD [%p]"),_thread(obj));break;
case OT_USERPOINTER: scprintf(_SC("USERPOINTER %p"),_userpointer(obj));break;
case OT_CLASS: scprintf(_SC("CLASS %p"),_class(obj));break;