added sq_tailcall()
This commit is contained in:
parent
8471ad1aea
commit
3c2de4bd59
@ -332,6 +332,7 @@ SQUIRREL_API SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err);
|
||||
SQUIRREL_API SQRESULT sq_throwobject(HSQUIRRELVM v);
|
||||
SQUIRREL_API void sq_reseterror(HSQUIRRELVM v);
|
||||
SQUIRREL_API void sq_getlasterror(HSQUIRRELVM v);
|
||||
SQUIRREL_API SQRESULT sq_tailcall(HSQUIRRELVM v, SQInteger nparams);
|
||||
|
||||
/*raw object handling*/
|
||||
SQUIRREL_API SQRESULT sq_getstackobj(HSQUIRRELVM v,SQInteger idx,HSQOBJECT *po);
|
||||
|
@ -1188,6 +1188,25 @@ SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror)
|
||||
return sq_throwerror(v,_SC("call failed"));
|
||||
}
|
||||
|
||||
SQRESULT sq_tailcall(HSQUIRRELVM v, SQInteger nparams)
|
||||
{
|
||||
SQObjectPtr &res = v->GetUp(-(nparams + 1));
|
||||
if (type(res) != OT_CLOSURE) {
|
||||
return sq_throwerror(v, _SC("only closure can be tail called"));
|
||||
}
|
||||
SQClosure *clo = _closure(res);
|
||||
if (clo->_function->_bgenerator)
|
||||
{
|
||||
return sq_throwerror(v, _SC("generators cannot be tail called"));
|
||||
}
|
||||
|
||||
SQInteger stackbase = (v->_top - nparams) - v->_stackbase;
|
||||
if (!v->TailCall(clo, stackbase, nparams)) {
|
||||
return SQ_ERROR;
|
||||
}
|
||||
return SQ_TAILCALL_FLAG;
|
||||
}
|
||||
|
||||
SQRESULT sq_suspendvm(HSQUIRRELVM v)
|
||||
{
|
||||
return v->Suspend();
|
||||
|
@ -885,7 +885,12 @@ static SQInteger closure_pcall(HSQUIRRELVM v)
|
||||
|
||||
static SQInteger closure_call(HSQUIRRELVM v)
|
||||
{
|
||||
return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQTrue))?1:SQ_ERROR;
|
||||
SQObjectPtr &c = stack_get(v, -1);
|
||||
if (type(c) == OT_CLOSURE && (_closure(c)->_function->_bgenerator == false))
|
||||
{
|
||||
return sq_tailcall(v, sq_gettop(v) - 1);
|
||||
}
|
||||
return SQ_SUCCEEDED(sq_call(v, sq_gettop(v) - 1, SQTrue, SQTrue)) ? 1 : SQ_ERROR;
|
||||
}
|
||||
|
||||
static SQInteger _closure_acall(HSQUIRRELVM v,SQBool raiseerror)
|
||||
|
@ -744,7 +744,8 @@ exception_restore:
|
||||
continue;
|
||||
case OT_NATIVECLOSURE: {
|
||||
bool suspend;
|
||||
_GUARD(CallNative(_nativeclosure(clo), arg3, _stackbase+arg2, clo,suspend));
|
||||
bool tailcall;
|
||||
_GUARD(CallNative(_nativeclosure(clo), arg3, _stackbase+arg2, clo, (SQInt32)sarg0, suspend, tailcall));
|
||||
if(suspend){
|
||||
_suspended = SQTrue;
|
||||
_suspended_target = sarg0;
|
||||
@ -753,7 +754,7 @@ exception_restore:
|
||||
outres = clo;
|
||||
return true;
|
||||
}
|
||||
if(sarg0 != -1) {
|
||||
if(sarg0 != -1 && !tailcall) {
|
||||
STK(arg0) = clo;
|
||||
}
|
||||
}
|
||||
@ -772,10 +773,10 @@ exception_restore:
|
||||
_GUARD(StartCall(_closure(clo), -1, arg3, stkbase, false));
|
||||
break;
|
||||
case OT_NATIVECLOSURE:
|
||||
bool suspend;
|
||||
bool dummy;
|
||||
stkbase = _stackbase+arg2;
|
||||
_stack._vals[stkbase] = inst;
|
||||
_GUARD(CallNative(_nativeclosure(clo), arg3, stkbase, clo,suspend));
|
||||
_GUARD(CallNative(_nativeclosure(clo), arg3, stkbase, clo, -1, dummy, dummy));
|
||||
break;
|
||||
default: break; //shutup GCC 4.x
|
||||
}
|
||||
@ -1139,7 +1140,7 @@ void SQVM::CallDebugHook(SQInteger type,SQInteger forcedline)
|
||||
_debughook = true;
|
||||
}
|
||||
|
||||
bool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval, bool &suspend)
|
||||
bool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval, SQInt32 target,bool &suspend, bool &tailcall)
|
||||
{
|
||||
SQInteger nparamscheck = nclosure->_nparamscheck;
|
||||
SQInteger newtop = newbase + nargs + nclosure->_noutervalues;
|
||||
@ -1169,6 +1170,7 @@ bool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newb
|
||||
|
||||
if(!EnterFrame(newbase, newtop, false)) return false;
|
||||
ci->_closure = nclosure;
|
||||
ci->_target = target;
|
||||
|
||||
SQInteger outers = nclosure->_noutervalues;
|
||||
for (SQInteger i = 0; i < outers; i++) {
|
||||
@ -1183,7 +1185,12 @@ bool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newb
|
||||
_nnativecalls--;
|
||||
|
||||
suspend = false;
|
||||
if (ret == SQ_SUSPEND_FLAG) {
|
||||
tailcall = false;
|
||||
if (ret == SQ_TAILCALL_FLAG) {
|
||||
tailcall = true;
|
||||
return true;
|
||||
}
|
||||
else if (ret == SQ_SUSPEND_FLAG) {
|
||||
suspend = true;
|
||||
}
|
||||
else if (ret < 0) {
|
||||
@ -1202,6 +1209,23 @@ bool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newb
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SQVM::TailCall(SQClosure *closure, SQInteger parambase,SQInteger nparams)
|
||||
{
|
||||
SQInteger last_top = _top;
|
||||
SQObjectPtr clo = closure;
|
||||
if (ci->_root)
|
||||
{
|
||||
Raise_Error("root calls cannot invoke tailcalls");
|
||||
return false;
|
||||
}
|
||||
for (SQInteger i = 0; i < nparams; i++) STK(i) = STK(parambase + i);
|
||||
bool ret = StartCall(closure, ci->_target, nparams, _stackbase, true);
|
||||
if (last_top >= _top) {
|
||||
_top = last_top;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define FALLBACK_OK 0
|
||||
#define FALLBACK_NO_MATCH 1
|
||||
#define FALLBACK_ERROR 2
|
||||
@ -1551,8 +1575,8 @@ SQInteger prevstackbase = _stackbase;
|
||||
return Execute(closure, nparams, stackbase, outres, raiseerror);
|
||||
break;
|
||||
case OT_NATIVECLOSURE:{
|
||||
bool suspend;
|
||||
return CallNative(_nativeclosure(closure), nparams, stackbase, outres,suspend);
|
||||
bool dummy;
|
||||
return CallNative(_nativeclosure(closure), nparams, stackbase, outres, -1, dummy, dummy);
|
||||
|
||||
}
|
||||
break;
|
||||
|
@ -8,6 +8,7 @@
|
||||
#define MIN_STACK_OVERHEAD 15
|
||||
|
||||
#define SQ_SUSPEND_FLAG -666
|
||||
#define SQ_TAILCALL_FLAG -777
|
||||
#define DONT_FALL_BACK 666
|
||||
//#define EXISTS_FALL_BACK -1
|
||||
|
||||
@ -56,7 +57,8 @@ public:
|
||||
bool Init(SQVM *friendvm, SQInteger stacksize);
|
||||
bool Execute(SQObjectPtr &func, SQInteger nargs, SQInteger stackbase, SQObjectPtr &outres, SQBool raiseerror, ExecutionType et = ET_CALL);
|
||||
//starts a native call return when the NATIVE closure returns
|
||||
bool CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval,bool &suspend);
|
||||
bool CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval, SQInt32 target, bool &suspend,bool &tailcall);
|
||||
bool TailCall(SQClosure *closure, SQInteger firstparam, SQInteger nparams);
|
||||
//starts a SQUIRREL call in the same "Execution loop"
|
||||
bool StartCall(SQClosure *closure, SQInteger target, SQInteger nargs, SQInteger stackbase, bool tailcall);
|
||||
bool CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor);
|
||||
|
Loading…
x
Reference in New Issue
Block a user