mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 03:11:51 +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);
|
||||
|
||||
//#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(
|
||||
SFUNC_BASE(0x0, IApplicationProxy, BaseProxy, GetCommonStateGetter),
|
||||
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) {
|
||||
std::pair<std::function<Result(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &)>, std::string_view> function;
|
||||
ServiceFunctionDescriptor function;
|
||||
try {
|
||||
function = GetServiceFunction(request.payload->value);
|
||||
state.logger->DebugNoPrefix("Service: {} @ {}", function.second, GetName());
|
||||
state.logger->DebugNoPrefix("Service: {}", function.name);
|
||||
} 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));
|
||||
return {};
|
||||
}
|
||||
try {
|
||||
return function.first(session, request, response);
|
||||
return function(session, request, response);
|
||||
} 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>
|
||||
|
||||
#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 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 SERVICE_STRINGIFY(string) #string
|
||||
#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(...) \
|
||||
SERVICE_DECL_AUTO(functions, frz::make_unordered_map({__VA_ARGS__})); \
|
||||
std::pair<std::function<Result(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &)>, std::string_view> GetServiceFunction(u32 id) override { \
|
||||
auto& function{functions.at(id)}; \
|
||||
return std::make_pair(std::bind(function.first, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), function.second); \
|
||||
#define SERVICE_DECL(...) \
|
||||
private: \
|
||||
template<typename BaseClass, typename BaseFunctionType, BaseFunctionType BaseFunction> \
|
||||
Result CallBaseFunction(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { \
|
||||
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__)
|
||||
|
||||
@ -37,10 +48,20 @@ namespace skyline::service {
|
||||
const DeviceState &state;
|
||||
ServiceManager &manager;
|
||||
|
||||
template<typename Class, typename BaseClass, typename BaseFunctionType, BaseFunctionType BaseFunction>
|
||||
static constexpr Result CallBaseFunction(Class *clazz, type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
return (static_cast<BaseClass *>(clazz)->*BaseFunction)(session, request, response);
|
||||
}
|
||||
class DerivedService; //!< A placeholder derived class which is used for class function semantics
|
||||
|
||||
/**
|
||||
* @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:
|
||||
BaseService(const DeviceState &state, ServiceManager &manager) : state(state), manager(manager) {}
|
||||
@ -50,12 +71,12 @@ namespace skyline::service {
|
||||
*/
|
||||
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");
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
const std::string &GetName();
|
||||
|
Loading…
Reference in New Issue
Block a user