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 SQRESULT sq_throwobject(HSQUIRRELVM v);
|
||||||
SQUIRREL_API void sq_reseterror(HSQUIRRELVM v);
|
SQUIRREL_API void sq_reseterror(HSQUIRRELVM v);
|
||||||
SQUIRREL_API void sq_getlasterror(HSQUIRRELVM v);
|
SQUIRREL_API void sq_getlasterror(HSQUIRRELVM v);
|
||||||
|
SQUIRREL_API SQRESULT sq_tailcall(HSQUIRRELVM v, SQInteger nparams);
|
||||||
|
|
||||||
/*raw object handling*/
|
/*raw object handling*/
|
||||||
SQUIRREL_API SQRESULT sq_getstackobj(HSQUIRRELVM v,SQInteger idx,HSQOBJECT *po);
|
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"));
|
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)
|
SQRESULT sq_suspendvm(HSQUIRRELVM v)
|
||||||
{
|
{
|
||||||
return v->Suspend();
|
return v->Suspend();
|
||||||
|
@ -885,7 +885,12 @@ static SQInteger closure_pcall(HSQUIRRELVM v)
|
|||||||
|
|
||||||
static SQInteger closure_call(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)
|
static SQInteger _closure_acall(HSQUIRRELVM v,SQBool raiseerror)
|
||||||
|
@ -744,7 +744,8 @@ exception_restore:
|
|||||||
continue;
|
continue;
|
||||||
case OT_NATIVECLOSURE: {
|
case OT_NATIVECLOSURE: {
|
||||||
bool suspend;
|
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){
|
if(suspend){
|
||||||
_suspended = SQTrue;
|
_suspended = SQTrue;
|
||||||
_suspended_target = sarg0;
|
_suspended_target = sarg0;
|
||||||
@ -753,7 +754,7 @@ exception_restore:
|
|||||||
outres = clo;
|
outres = clo;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(sarg0 != -1) {
|
if(sarg0 != -1 && !tailcall) {
|
||||||
STK(arg0) = clo;
|
STK(arg0) = clo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -772,10 +773,10 @@ exception_restore:
|
|||||||
_GUARD(StartCall(_closure(clo), -1, arg3, stkbase, false));
|
_GUARD(StartCall(_closure(clo), -1, arg3, stkbase, false));
|
||||||
break;
|
break;
|
||||||
case OT_NATIVECLOSURE:
|
case OT_NATIVECLOSURE:
|
||||||
bool suspend;
|
bool dummy;
|
||||||
stkbase = _stackbase+arg2;
|
stkbase = _stackbase+arg2;
|
||||||
_stack._vals[stkbase] = inst;
|
_stack._vals[stkbase] = inst;
|
||||||
_GUARD(CallNative(_nativeclosure(clo), arg3, stkbase, clo,suspend));
|
_GUARD(CallNative(_nativeclosure(clo), arg3, stkbase, clo, -1, dummy, dummy));
|
||||||
break;
|
break;
|
||||||
default: break; //shutup GCC 4.x
|
default: break; //shutup GCC 4.x
|
||||||
}
|
}
|
||||||
@ -1139,7 +1140,7 @@ void SQVM::CallDebugHook(SQInteger type,SQInteger forcedline)
|
|||||||
_debughook = true;
|
_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 nparamscheck = nclosure->_nparamscheck;
|
||||||
SQInteger newtop = newbase + nargs + nclosure->_noutervalues;
|
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;
|
if(!EnterFrame(newbase, newtop, false)) return false;
|
||||||
ci->_closure = nclosure;
|
ci->_closure = nclosure;
|
||||||
|
ci->_target = target;
|
||||||
|
|
||||||
SQInteger outers = nclosure->_noutervalues;
|
SQInteger outers = nclosure->_noutervalues;
|
||||||
for (SQInteger i = 0; i < outers; i++) {
|
for (SQInteger i = 0; i < outers; i++) {
|
||||||
@ -1183,7 +1185,12 @@ bool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newb
|
|||||||
_nnativecalls--;
|
_nnativecalls--;
|
||||||
|
|
||||||
suspend = false;
|
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;
|
suspend = true;
|
||||||
}
|
}
|
||||||
else if (ret < 0) {
|
else if (ret < 0) {
|
||||||
@ -1202,6 +1209,23 @@ bool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newb
|
|||||||
return true;
|
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_OK 0
|
||||||
#define FALLBACK_NO_MATCH 1
|
#define FALLBACK_NO_MATCH 1
|
||||||
#define FALLBACK_ERROR 2
|
#define FALLBACK_ERROR 2
|
||||||
@ -1551,8 +1575,8 @@ SQInteger prevstackbase = _stackbase;
|
|||||||
return Execute(closure, nparams, stackbase, outres, raiseerror);
|
return Execute(closure, nparams, stackbase, outres, raiseerror);
|
||||||
break;
|
break;
|
||||||
case OT_NATIVECLOSURE:{
|
case OT_NATIVECLOSURE:{
|
||||||
bool suspend;
|
bool dummy;
|
||||||
return CallNative(_nativeclosure(closure), nparams, stackbase, outres,suspend);
|
return CallNative(_nativeclosure(closure), nparams, stackbase, outres, -1, dummy, dummy);
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#define MIN_STACK_OVERHEAD 15
|
#define MIN_STACK_OVERHEAD 15
|
||||||
|
|
||||||
#define SQ_SUSPEND_FLAG -666
|
#define SQ_SUSPEND_FLAG -666
|
||||||
|
#define SQ_TAILCALL_FLAG -777
|
||||||
#define DONT_FALL_BACK 666
|
#define DONT_FALL_BACK 666
|
||||||
//#define EXISTS_FALL_BACK -1
|
//#define EXISTS_FALL_BACK -1
|
||||||
|
|
||||||
@ -56,7 +57,8 @@ public:
|
|||||||
bool Init(SQVM *friendvm, SQInteger stacksize);
|
bool Init(SQVM *friendvm, SQInteger stacksize);
|
||||||
bool Execute(SQObjectPtr &func, SQInteger nargs, SQInteger stackbase, SQObjectPtr &outres, SQBool raiseerror, ExecutionType et = ET_CALL);
|
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
|
//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"
|
//starts a SQUIRREL call in the same "Execution loop"
|
||||||
bool StartCall(SQClosure *closure, SQInteger target, SQInteger nargs, SQInteger stackbase, bool tailcall);
|
bool StartCall(SQClosure *closure, SQInteger target, SQInteger nargs, SQInteger stackbase, bool tailcall);
|
||||||
bool CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor);
|
bool CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user