mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-26 07:04:17 +01:00
Optimize Service Function Lookup
This moves from using std::function with a this pointer binding (which would likely cause a heap allocation) to returning the this pointer in a structure which implements operator() to do the call with it. It also moves to using const char* for strings from std::string_view which was pointless in this scenario due to it's usage being limited to being a C-string for the most part, it also integrates the class name directly into the string which allows us to avoid runtime string concatenation in libfmt and RTTI for finding the class name.
This commit is contained in:
parent
2b4a094cd8
commit
33f1a3e1b3
@ -20,9 +20,6 @@ namespace skyline::service::am {
|
|||||||
*/
|
*/
|
||||||
Result GetApplicationFunctions(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
Result GetApplicationFunctions(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||||
|
|
||||||
//#undef SFUNC_BASE
|
|
||||||
//#define SFUNC_BASE(id, Class, BaseClass, Function) std::pair<u32, std::pair<std::function<Result(Class*, type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &)>, std::string_view>>{id, {&CallBaseFunction<Class, BaseClass, BaseClass::Function>, #Function}}
|
|
||||||
|
|
||||||
SERVICE_DECL(
|
SERVICE_DECL(
|
||||||
SFUNC_BASE(0x0, IApplicationProxy, BaseProxy, GetCommonStateGetter),
|
SFUNC_BASE(0x0, IApplicationProxy, BaseProxy, GetCommonStateGetter),
|
||||||
SFUNC_BASE(0x1, IApplicationProxy, BaseProxy, GetSelfController),
|
SFUNC_BASE(0x1, IApplicationProxy, BaseProxy, GetSelfController),
|
||||||
|
@ -19,18 +19,18 @@ namespace skyline::service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result service::BaseService::HandleRequest(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result service::BaseService::HandleRequest(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
std::pair<std::function<Result(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &)>, std::string_view> function;
|
ServiceFunctionDescriptor function;
|
||||||
try {
|
try {
|
||||||
function = GetServiceFunction(request.payload->value);
|
function = GetServiceFunction(request.payload->value);
|
||||||
state.logger->DebugNoPrefix("Service: {} @ {}", function.second, GetName());
|
state.logger->DebugNoPrefix("Service: {}", function.name);
|
||||||
} catch (const std::out_of_range &) {
|
} catch (const std::out_of_range &) {
|
||||||
state.logger->Warn("Cannot find function in service '{0}': 0x{1:X} ({1})", GetName(), static_cast<u32>(request.payload->value));
|
state.logger->Warn("Cannot find function in service '{0}': 0x{1:X} ({1})", GetName(), static_cast<u32>(request.payload->value));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return function.first(session, request, response);
|
return function(session, request, response);
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
throw exception("{} (Service: {} @ {})", e.what(), function.second, GetName());
|
throw exception("{} (Service: {})", e.what(), function.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,25 @@
|
|||||||
|
|
||||||
#include <kernel/ipc.h>
|
#include <kernel/ipc.h>
|
||||||
|
|
||||||
#define SFUNC(id, Class, Function) std::pair<u32, std::pair<std::function<Result(Class*, type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &)>, std::string_view>>{id, {&Class::Function, #Function}}
|
#define SERVICE_STRINGIFY(string) #string
|
||||||
#define SFUNC_BASE(id, Class, BaseClass, Function) std::pair<u32, std::pair<std::function<Result(Class*, type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &)>, std::string_view>>{id, {&CallBaseFunction<Class, BaseClass, decltype(&BaseClass::Function), &BaseClass::Function>, #Function}}
|
#define SFUNC(id, Class, Function) std::pair<u32, std::pair<Result(Class::*)(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &), const char*>>{id, {&Class::Function, SERVICE_STRINGIFY(Class::Function)}}
|
||||||
|
#define SFUNC_BASE(id, Class, BaseClass, Function) std::pair<u32, std::pair<Result(Class::*)(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &), const char*>>{id, {&Class::CallBaseFunction<BaseClass, decltype(&BaseClass::Function), &BaseClass::Function>, SERVICE_STRINGIFY(Class::Function)}}
|
||||||
#define SERVICE_DECL_AUTO(name, value) decltype(value) name = value
|
#define SERVICE_DECL_AUTO(name, value) decltype(value) name = value
|
||||||
#define SERVICE_DECL(...) \
|
#define SERVICE_DECL(...) \
|
||||||
SERVICE_DECL_AUTO(functions, frz::make_unordered_map({__VA_ARGS__})); \
|
private: \
|
||||||
std::pair<std::function<Result(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &)>, std::string_view> GetServiceFunction(u32 id) override { \
|
template<typename BaseClass, typename BaseFunctionType, BaseFunctionType BaseFunction> \
|
||||||
auto& function{functions.at(id)}; \
|
Result CallBaseFunction(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { \
|
||||||
return std::make_pair(std::bind(function.first, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), function.second); \
|
return (static_cast<BaseClass *>(this)->*BaseFunction)(session, request, response); \
|
||||||
|
} \
|
||||||
|
SERVICE_DECL_AUTO(functions, frz::make_unordered_map({__VA_ARGS__})); \
|
||||||
|
protected: \
|
||||||
|
ServiceFunctionDescriptor GetServiceFunction(u32 id) override { \
|
||||||
|
auto& function{functions.at(id)}; \
|
||||||
|
return ServiceFunctionDescriptor{ \
|
||||||
|
reinterpret_cast<DerivedService*>(this), \
|
||||||
|
reinterpret_cast<decltype(ServiceFunctionDescriptor::function)>(function.first), \
|
||||||
|
function.second \
|
||||||
|
}; \
|
||||||
}
|
}
|
||||||
#define SRVREG(class, ...) std::make_shared<class>(state, manager, ##__VA_ARGS__)
|
#define SRVREG(class, ...) std::make_shared<class>(state, manager, ##__VA_ARGS__)
|
||||||
|
|
||||||
@ -37,10 +48,20 @@ namespace skyline::service {
|
|||||||
const DeviceState &state;
|
const DeviceState &state;
|
||||||
ServiceManager &manager;
|
ServiceManager &manager;
|
||||||
|
|
||||||
template<typename Class, typename BaseClass, typename BaseFunctionType, BaseFunctionType BaseFunction>
|
class DerivedService; //!< A placeholder derived class which is used for class function semantics
|
||||||
static constexpr Result CallBaseFunction(Class *clazz, type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
|
||||||
return (static_cast<BaseClass *>(clazz)->*BaseFunction)(session, request, response);
|
/**
|
||||||
}
|
* @brief A per-service-function descriptor with it's name and a function pointer to it
|
||||||
|
*/
|
||||||
|
struct ServiceFunctionDescriptor {
|
||||||
|
DerivedService *clazz; //!< A pointer to the class that this was derived from, it's used as the 'this' pointer for the function
|
||||||
|
Result (DerivedService::*function)(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &); //!< A function pointer to a HLE implementation of the service function
|
||||||
|
const char *name; //!< A pointer to a static string in the format "Class::Function" for the specific service class/function
|
||||||
|
|
||||||
|
constexpr Result operator()(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
|
return (clazz->*function)(session, request, response);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BaseService(const DeviceState &state, ServiceManager &manager) : state(state), manager(manager) {}
|
BaseService(const DeviceState &state, ServiceManager &manager) : state(state), manager(manager) {}
|
||||||
@ -50,12 +71,12 @@ namespace skyline::service {
|
|||||||
*/
|
*/
|
||||||
virtual ~BaseService() = default;
|
virtual ~BaseService() = default;
|
||||||
|
|
||||||
virtual std::pair<std::function<Result(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &)>, std::string_view> GetServiceFunction(u32 id) {
|
virtual ServiceFunctionDescriptor GetServiceFunction(u32 id) {
|
||||||
throw std::out_of_range("GetServiceFunction not implemented");
|
throw std::out_of_range("GetServiceFunction not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The name of the class
|
* @return A string with the name of the service class
|
||||||
* @note The lifetime of the returned string is tied to that of the class
|
* @note The lifetime of the returned string is tied to that of the class
|
||||||
*/
|
*/
|
||||||
const std::string &GetName();
|
const std::string &GetName();
|
||||||
|
Loading…
Reference in New Issue
Block a user