From 5149b333d764039622b4a1a32488894b46139585 Mon Sep 17 00:00:00 2001 From: PixelyIon Date: Sat, 20 Mar 2021 01:19:55 +0530 Subject: [PATCH] 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. --- .../services/am/proxy/IApplicationProxy.h | 3 -- .../cpp/skyline/services/base_service.cpp | 8 ++-- .../main/cpp/skyline/services/base_service.h | 47 ++++++++++++++----- 3 files changed, 38 insertions(+), 20 deletions(-) diff --git a/app/src/main/cpp/skyline/services/am/proxy/IApplicationProxy.h b/app/src/main/cpp/skyline/services/am/proxy/IApplicationProxy.h index 47b713f3..f3cfa6f8 100644 --- a/app/src/main/cpp/skyline/services/am/proxy/IApplicationProxy.h +++ b/app/src/main/cpp/skyline/services/am/proxy/IApplicationProxy.h @@ -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, std::string_view>>{id, {&CallBaseFunction, #Function}} - SERVICE_DECL( SFUNC_BASE(0x0, IApplicationProxy, BaseProxy, GetCommonStateGetter), SFUNC_BASE(0x1, IApplicationProxy, BaseProxy, GetSelfController), diff --git a/app/src/main/cpp/skyline/services/base_service.cpp b/app/src/main/cpp/skyline/services/base_service.cpp index 4f2c64a4..fa9f7125 100644 --- a/app/src/main/cpp/skyline/services/base_service.cpp +++ b/app/src/main/cpp/skyline/services/base_service.cpp @@ -19,18 +19,18 @@ namespace skyline::service { } Result service::BaseService::HandleRequest(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - std::pair, 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(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); } } } diff --git a/app/src/main/cpp/skyline/services/base_service.h b/app/src/main/cpp/skyline/services/base_service.h index 6f2bd7cd..bb3c094a 100644 --- a/app/src/main/cpp/skyline/services/base_service.h +++ b/app/src/main/cpp/skyline/services/base_service.h @@ -5,14 +5,25 @@ #include -#define SFUNC(id, Class, Function) std::pair, std::string_view>>{id, {&Class::Function, #Function}} -#define SFUNC_BASE(id, Class, BaseClass, Function) std::pair, std::string_view>>{id, {&CallBaseFunction, #Function}} +#define SERVICE_STRINGIFY(string) #string +#define SFUNC(id, Class, Function) std::pair>{id, {&Class::Function, SERVICE_STRINGIFY(Class::Function)}} +#define SFUNC_BASE(id, Class, BaseClass, Function) std::pair>{id, {&Class::CallBaseFunction, 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::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 \ +Result CallBaseFunction(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { \ + return (static_cast(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(this), \ + reinterpret_cast(function.first), \ + function.second \ + }; \ } #define SRVREG(class, ...) std::make_shared(state, manager, ##__VA_ARGS__) @@ -37,10 +48,20 @@ namespace skyline::service { const DeviceState &state; ServiceManager &manager; - template - static constexpr Result CallBaseFunction(Class *clazz, type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - return (static_cast(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::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();