mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2025-01-31 18:07:14 +01:00
Improve performance in overloaded methods calls by cheating a little and calling the overload directly instead of pushing the parameters back on the stack and performing a regular function call.
This commit is contained in:
parent
5c859fb5aa
commit
086eeae7b4
@ -556,24 +556,35 @@ protected:
|
|||||||
|
|
||||||
// Bind a function and it's associated Squirrel closure to the object
|
// Bind a function and it's associated Squirrel closure to the object
|
||||||
inline void BindOverload(const SQChar* name, void* method, size_t methodSize, SQFUNCTION func, SQFUNCTION overload, int argCount, bool staticVar = false) {
|
inline void BindOverload(const SQChar* name, void* method, size_t methodSize, SQFUNCTION func, SQFUNCTION overload, int argCount, bool staticVar = false) {
|
||||||
string overloadName = SqOverloadName::Get(name, argCount);
|
string overloadName;
|
||||||
|
overloadName.reserve(15);
|
||||||
|
SqOverloadName::Get(name, argCount, overloadName);
|
||||||
|
|
||||||
sq_pushobject(vm, GetObject());
|
sq_pushobject(vm, GetObject());
|
||||||
|
|
||||||
// Bind overload handler
|
// Bind overload handler
|
||||||
sq_pushstring(vm, name, -1);
|
sq_pushstring(vm, name, -1);
|
||||||
sq_pushstring(vm, name, -1); // function name is passed as a free variable
|
// function name is passed as a free variable
|
||||||
|
//sq_pushstring(vm, name, -1);
|
||||||
|
sq_push(vm, -1); // <- Let's cheat(?) by pushing the same object
|
||||||
sq_newclosure(vm, overload, 1);
|
sq_newclosure(vm, overload, 1);
|
||||||
|
// Set the closure name (for debug purposes)
|
||||||
|
sq_setnativeclosurename(vm, -1, name);
|
||||||
|
// Include it into the object
|
||||||
sq_newslot(vm, -3, staticVar);
|
sq_newslot(vm, -3, staticVar);
|
||||||
|
|
||||||
// Bind overloaded function
|
// Bind overloaded function
|
||||||
sq_pushstring(vm, overloadName.c_str(), -1);
|
sq_pushstring(vm, overloadName.c_str(), static_cast<SQInteger>(overloadName.size()));
|
||||||
|
// Push the native closure pointer as a free variable
|
||||||
SQUserPointer methodPtr = sq_newuserdata(vm, static_cast<SQUnsignedInteger>(methodSize));
|
SQUserPointer methodPtr = sq_newuserdata(vm, static_cast<SQUnsignedInteger>(methodSize));
|
||||||
memcpy(methodPtr, method, methodSize);
|
memcpy(methodPtr, method, methodSize);
|
||||||
sq_newclosure(vm, func, 1);
|
sq_newclosure(vm, func, 1);
|
||||||
|
// Set the closure name (for debug purposes)
|
||||||
|
sq_setnativeclosurename(vm, -1, overloadName.c_str());
|
||||||
|
// Include it into the object
|
||||||
sq_newslot(vm, -3, staticVar);
|
sq_newslot(vm, -3, staticVar);
|
||||||
|
|
||||||
sq_pop(vm,1); // pop table
|
sq_pop(vm,1); // pop object
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the value of a variable on the object. Changes to values set this way are not reciprocated
|
// Set the value of a variable on the object. Changes to values set this way are not reciprocated
|
||||||
|
@ -51,15 +51,77 @@ namespace Sqrat {
|
|||||||
class SqOverloadName {
|
class SqOverloadName {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static string Get(const SQChar* name, int args) {
|
static void Get(const SQChar* name, int args, string & out) {
|
||||||
std::basic_stringstream<SQChar> overloadName;
|
SQChar buf[16] = {'_', 'o'};
|
||||||
overloadName << _SC("__overload_") << name << args;
|
itoa(args, &buf[2], 10);
|
||||||
|
out.append(buf);
|
||||||
|
out.push_back('_');
|
||||||
|
out.append(name);
|
||||||
|
}
|
||||||
|
|
||||||
return overloadName.str();
|
static string Get(const SQChar* name, int args) {
|
||||||
|
string out;
|
||||||
|
out.reserve(15);
|
||||||
|
Get(name, args, out);
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Don't include the overloaded call forwarder into the templated class
|
||||||
|
// to avoid duplicating code that doesn't need to be specialized.
|
||||||
|
//
|
||||||
|
inline SQInteger OverloadExecutionForwarder(HSQUIRRELVM vm) {
|
||||||
|
// Get the argument count
|
||||||
|
const int argCount = static_cast<int>(sq_gettop(vm) - 2);
|
||||||
|
// Subtract environment and base name in free variable^
|
||||||
|
const SQChar* funcName;
|
||||||
|
SQInteger funcNameSize;
|
||||||
|
// Get the un-mangled function name (free variable)
|
||||||
|
sq_getstringandsize(vm, -1, &funcName, &funcNameSize);
|
||||||
|
// Generate the overload mangled name
|
||||||
|
string overloadName;
|
||||||
|
overloadName.reserve(funcNameSize+5);
|
||||||
|
SqOverloadName::Get(funcName, argCount, overloadName);
|
||||||
|
// Pop the un-mangled closure name from the stack so we can replace it later
|
||||||
|
sq_poptop(vm); // `funcName` becomes invalid after this
|
||||||
|
// Push the overload mangled name on the stack
|
||||||
|
sq_pushstring(vm, overloadName.c_str(), static_cast<SQInteger>(overloadName.size()));
|
||||||
|
// Lookup the proper overload and get it on the stack
|
||||||
|
#if !defined (SCRAT_NO_ERROR_CHECKING)
|
||||||
|
if (SQ_FAILED(sq_get(vm, 1))) {
|
||||||
|
sq_pushnull(vm); // Push something to take the place of the free variable
|
||||||
|
return sq_throwerror(vm, _SC("wrong number of parameters"));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
sq_get(vm, 1);
|
||||||
|
#endif
|
||||||
|
SQFUNCTION f = nullptr;
|
||||||
|
// Get the native closure pointer that we must invoke
|
||||||
|
SQRESULT res = sq_getnativeclosurepointer(vm, -1, &f);
|
||||||
|
if (SQ_FAILED(res)) return res;
|
||||||
|
// Make sure a native closure pointer is available
|
||||||
|
if (!f) {
|
||||||
|
return sq_throwerror(vm, _SC("unable to acquire the proper overload closure"));
|
||||||
|
}
|
||||||
|
// Attempt to get the free variable containing the native closure pointer on the stack
|
||||||
|
const SQChar *name = sq_getonefreevariable(vm, 0);
|
||||||
|
// This is simply a hack to implement a direct call and gain some performance
|
||||||
|
// Since both closures expect a free variable we simply replace the free variable
|
||||||
|
// containing closure name with the free variable containing the closure pointer
|
||||||
|
|
||||||
|
// Perform a direct call and store the result
|
||||||
|
res = f(vm);
|
||||||
|
// If there was a free variable and the closure on the stack was native
|
||||||
|
// Then we must push something to take the place of the free variable
|
||||||
|
if (name && name[0] == '@') {
|
||||||
|
sq_pushnull(vm);
|
||||||
|
}
|
||||||
|
// Return the result back to the caller
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Squirrel Overload Functions
|
// Squirrel Overload Functions
|
||||||
//
|
//
|
||||||
@ -69,39 +131,7 @@ class SqOverload {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
static SQInteger Func(HSQUIRRELVM vm) {
|
static SQInteger Func(HSQUIRRELVM vm) {
|
||||||
// Get the arg count
|
return OverloadExecutionForwarder(vm);
|
||||||
int argCount = sq_gettop(vm) - 2;
|
|
||||||
|
|
||||||
const SQChar* funcName;
|
|
||||||
sq_getstring(vm, -1, &funcName); // get the function name (free variable)
|
|
||||||
|
|
||||||
string overloadName = SqOverloadName::Get(funcName, argCount);
|
|
||||||
|
|
||||||
sq_pushstring(vm, overloadName.c_str(), static_cast<SQInteger>(overloadName.size()));
|
|
||||||
|
|
||||||
#if !defined (SCRAT_NO_ERROR_CHECKING)
|
|
||||||
if (SQ_FAILED(sq_get(vm, 1))) { // Lookup the proper overload
|
|
||||||
return sq_throwerror(vm, _SC("wrong number of parameters"));
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
sq_get(vm, 1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Push the args again
|
|
||||||
for (int i = 1; i <= argCount + 1; ++i) {
|
|
||||||
sq_push(vm, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined (SCRAT_NO_ERROR_CHECKING)
|
|
||||||
SQRESULT result = sq_call(vm, argCount + 1, true, ErrorHandling::IsEnabled());
|
|
||||||
if (SQ_FAILED(result)) {
|
|
||||||
return sq_throwerror(vm, LastErrorString(vm).c_str());
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
sq_call(vm, argCount + 1, true, ErrorHandling::IsEnabled());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -115,39 +145,7 @@ class SqOverload<void> {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
static SQInteger Func(HSQUIRRELVM vm) {
|
static SQInteger Func(HSQUIRRELVM vm) {
|
||||||
// Get the arg count
|
return OverloadExecutionForwarder(vm);
|
||||||
int argCount = sq_gettop(vm) - 2;
|
|
||||||
|
|
||||||
const SQChar* funcName;
|
|
||||||
sq_getstring(vm, -1, &funcName); // get the function name (free variable)
|
|
||||||
|
|
||||||
string overloadName = SqOverloadName::Get(funcName, argCount);
|
|
||||||
|
|
||||||
sq_pushstring(vm, overloadName.c_str(), -1);
|
|
||||||
|
|
||||||
#if !defined (SCRAT_NO_ERROR_CHECKING)
|
|
||||||
if (SQ_FAILED(sq_get(vm, 1))) { // Lookup the proper overload
|
|
||||||
return sq_throwerror(vm, _SC("wrong number of parameters"));
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
sq_get(vm, 1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Push the args again
|
|
||||||
for (int i = 1; i <= argCount + 1; ++i) {
|
|
||||||
sq_push(vm, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined (SCRAT_NO_ERROR_CHECKING)
|
|
||||||
SQRESULT result = sq_call(vm, argCount + 1, false, ErrorHandling::IsEnabled());
|
|
||||||
if (SQ_FAILED(result)) {
|
|
||||||
return sq_throwerror(vm, LastErrorString(vm).c_str());
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
sq_call(vm, argCount + 1, false, ErrorHandling::IsEnabled());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user