added sq_tailcall()

This commit is contained in:
albertodemichelis 2017-11-17 03:55:35 +08:00
parent 8471ad1aea
commit 3c2de4bd59
5 changed files with 61 additions and 10 deletions

View File

@ -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);

View File

@ -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();

View File

@ -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)

View File

@ -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;

View File

@ -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);