From 71f77ce89c6485fe71c4542d562cb1a540d8989a Mon Sep 17 00:00:00 2001 From: Timerix Date: Tue, 10 Sep 2024 19:15:41 +0500 Subject: [PATCH] Mono::Method --- src/Mono/Mono.cpp | 50 ++++++++++++++++++++++ src/Mono/Mono.hpp | 82 +++++++++++++------------------------ src/Mono/Runtime.cpp | 13 ------ src/function_shared_ptr.hpp | 30 ++++++++++++++ src/main.cpp | 14 +++---- 5 files changed, 115 insertions(+), 74 deletions(-) create mode 100644 src/function_shared_ptr.hpp diff --git a/src/Mono/Mono.cpp b/src/Mono/Mono.cpp index 0a7b0eb..a157196 100644 --- a/src/Mono/Mono.cpp +++ b/src/Mono/Mono.cpp @@ -19,4 +19,54 @@ template <> MonoClass* getClass(){ return mono_get_string_class(); } template <> MonoClass* getClass(){ return mono_get_object_class(); } template <> MonoClass* getClass(){ return mono_get_void_class(); } + +void getMethodSignatureTypes(MonoMethod* mono_method, + MonoType** return_type, + std::vector& argument_types) +{ + auto signature = mono_method_signature(mono_method); + void* iter = nullptr; + *return_type = mono_signature_get_return_type(signature); + MonoType* pt = nullptr; + while( (pt = mono_signature_get_params(signature, &iter)) ){ + argument_types.push_back(pt); + } +} + +MonoMethod* tryGetMonoMethod(MonoClass* target_class, const std::string& name, + MonoClass* return_class, MonoClass* arg_classes[], size_t arg_classes_size) +{ + if(target_class == nullptr) + throw UsefulException("target_class is nullptr"); + // iterate each method + void* iter = nullptr; + MonoMethod* m = nullptr; + MonoType* return_type = nullptr; + std::vector argument_types; + while( (m = mono_class_get_methods(target_class, &iter)) ){ + argument_types.clear(); + getMethodSignatureTypes(m, &return_type, argument_types); + // compare argument count + if(argument_types.size() != arg_classes_size) + continue; + // compare return type + if(!mono_metadata_type_equal(return_type, mono_class_get_type(return_class))) + continue; + // compare argument types + bool argument_types_mismatch = false; + for(size_t i = 0; i < arg_classes_size; i++){ + if(!mono_metadata_type_equal(argument_types[i], mono_class_get_type(arg_classes[i]))){ + argument_types_mismatch = true; + break; + } + } + if(argument_types_mismatch) + continue; + // passed all tests successfully + break; + } + + return m; +} + } diff --git a/src/Mono/Mono.hpp b/src/Mono/Mono.hpp index 1805a6f..021d0c6 100644 --- a/src/Mono/Mono.hpp +++ b/src/Mono/Mono.hpp @@ -3,9 +3,7 @@ #include "../std.hpp" #include "../UsefulException.hpp" #include "../format.hpp" -#include #include -#include #include #include #include @@ -55,61 +53,37 @@ void getMethodSignatureTypes(MonoMethod* mono_method, MonoType** return_type, std::vector& argument_types); -/// all types must implement getClass() +/// searches for method `name` in `target_class` with return type `return_class` and argument types `arg_classes` +/// @return found method or nullptr +MonoMethod* tryGetMonoMethod(MonoClass* target_class, const std::string& name, + MonoClass* return_class, MonoClass* arg_classes[], size_t arg_classes_size); + + +template class Method; template -std::shared_ptr> getMethod( - MonoClass* target_class, - const std::string& name) +class Method { - static MonoClass* arg_classes[] = { getClass()... }; - static MonoClass* return_class = getClass(); - if(target_class == nullptr) - throw UsefulException("target_class is nullptr"); - - // iterate each method - void* iter = nullptr; - MonoMethod* m = nullptr; - MonoType* return_type = nullptr; - std::vector argument_types; - while( (m = mono_class_get_methods(target_class, &iter)) ){ - argument_types.clear(); - getMethodSignatureTypes(m, &return_type, argument_types); - // compare argument count - if(argument_types.size() != sizeof...(ArgTypes)) - continue; - // compare return type - if(!mono_metadata_type_equal(return_type, mono_class_get_type(return_class))) - continue; - // compare argument types - bool argument_types_mismatch = false; - for(size_t i = 0; i < sizeof...(ArgTypes); i++){ - if(!mono_metadata_type_equal(argument_types[i], mono_class_get_type(arg_classes[i]))){ - argument_types_mismatch = true; - break; - } - } - if(argument_types_mismatch) - continue; - // passed all tests successfully - break; + MonoMethod* method_ptr; + +public: + ReturnT operator()(MonoObject* class_instance, ArgTypes... args) { + void* arg_array[] = { valueToVoidPtr(args)..., nullptr }; + // TODO: exception catch + // MonoException* ex = nullptr; + MonoObject* result = mono_runtime_invoke(method_ptr, class_instance, arg_array, nullptr); + return valueFromMonoObject(result); + }; + + /// all types must implement getClass() + Method(MonoClass* target_class, const std::string& name){ + static MonoClass* arg_classes[] { getClass()... }; + static MonoClass* return_class { getClass() }; + method_ptr = tryGetMonoMethod(target_class, name, return_class, arg_classes, sizeof...(ArgTypes)); + if(method_ptr == nullptr) + throw UsefulException(format("can't get method '%s' from class '%s'", + name.c_str(), mono_class_get_name(target_class))); } - - // if method not found throw exception - if(m == nullptr) - throw UsefulException(format("can't get method '%s' from class '%s'", - name.c_str(), mono_class_get_name(target_class))); - - return std::make_shared>( - [m](MonoObject* class_instance, ArgTypes... args) -> ReturnT - { - void* arg_array[] = { valueToVoidPtr(args)..., nullptr }; - // MonoException* ex = nullptr; - // TODO: exception catch - MonoObject* result = mono_runtime_invoke(m, class_instance, arg_array, nullptr); - return valueFromMonoObject(result); - } - ); -} +}; class Assembly { diff --git a/src/Mono/Runtime.cpp b/src/Mono/Runtime.cpp index 2a070eb..a85ebdf 100644 --- a/src/Mono/Runtime.cpp +++ b/src/Mono/Runtime.cpp @@ -25,17 +25,4 @@ std::shared_ptr RuntimeJIT::loadAssembly(const std::string &name){ return std::make_shared(ptr); } -void getMethodSignatureTypes(MonoMethod* mono_method, - MonoType** return_type, - std::vector& argument_types) -{ - auto signature = mono_method_signature(mono_method); - void* iter = nullptr; - *return_type = mono_signature_get_return_type(signature); - MonoType* pt = nullptr; - while( (pt = mono_signature_get_params(signature, &iter)) ){ - argument_types.push_back(pt); - } -} - } diff --git a/src/function_shared_ptr.hpp b/src/function_shared_ptr.hpp new file mode 100644 index 0000000..bd7a575 --- /dev/null +++ b/src/function_shared_ptr.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +template +class function_shared_ptr; + +template +class function_shared_ptr { +public: + using func_t = std::function; + using ptr_t = std::shared_ptr; +protected: + ptr_t func_ptr; + +public: + function_shared_ptr() = default; + function_shared_ptr(function_shared_ptr&) = default; + function_shared_ptr(function_shared_ptr&&) = default; + function_shared_ptr(ptr_t& p) { func_ptr = p; } + function_shared_ptr(ptr_t&& p) { func_ptr = p; } + template + function_shared_ptr(FunctionT f){ func_ptr = std::make_shared(f); } + + ReturnT operator()(ArgTypes... args){ return func_ptr->operator()(args...); } + + function_shared_ptr& operator=(function_shared_ptr&) = default; + function_shared_ptr& operator=(function_shared_ptr&&) = default; +}; diff --git a/src/main.cpp b/src/main.cpp index edf6d87..98e7068 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,18 +21,18 @@ int main(int argc, const char** argv){ Mono::RuntimeJIT mono; auto a = mono.loadAssembly("app.exe"); auto c = a->getClass("", "A"); - auto m = Mono::getMethod(c, "Method"); + auto m = Mono::Method(c, "Method"); std::cout<<"method has been found"<operator()(nullptr, 16, 0.32); + Mono::Int r = m(nullptr, 16, 0.32); std::cout<<"result: "<