Mono::Method

This commit is contained in:
Timerix 2024-09-10 19:15:41 +05:00
parent 42b233e6a4
commit 71f77ce89c
5 changed files with 115 additions and 74 deletions

View File

@ -19,4 +19,54 @@ template <> MonoClass* getClass<String>(){ return mono_get_string_class(); }
template <> MonoClass* getClass<Object>(){ return mono_get_object_class(); }
template <> MonoClass* getClass<Void>(){ return mono_get_void_class(); }
void getMethodSignatureTypes(MonoMethod* mono_method,
MonoType** return_type,
std::vector<MonoType*>& 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<MonoType*> 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;
}
}

View File

@ -3,9 +3,7 @@
#include "../std.hpp"
#include "../UsefulException.hpp"
#include "../format.hpp"
#include <functional>
#include <vector>
#include <map>
#include <mono/metadata/metadata.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/object.h>
@ -55,61 +53,37 @@ void getMethodSignatureTypes(MonoMethod* mono_method,
MonoType** return_type,
std::vector<MonoType*>& argument_types);
/// all types must implement getClass<T>()
/// 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<typename SignatureT> class Method;
template<typename ReturnT, typename... ArgTypes>
std::shared_ptr<std::function<ReturnT(MonoObject*, ArgTypes...)>> getMethod(
MonoClass* target_class,
const std::string& name)
class Method<ReturnT(ArgTypes...)>
{
static MonoClass* arg_classes[] = { getClass<ArgTypes>()... };
static MonoClass* return_class = getClass<ReturnT>();
if(target_class == nullptr)
throw UsefulException("target_class is nullptr");
MonoMethod* method_ptr;
// iterate each method
void* iter = nullptr;
MonoMethod* m = nullptr;
MonoType* return_type = nullptr;
std::vector<MonoType*> 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;
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<ReturnT>(result);
};
/// all types must implement getClass<T>()
Method(MonoClass* target_class, const std::string& name){
static MonoClass* arg_classes[] { getClass<ArgTypes>()... };
static MonoClass* return_class { getClass<ReturnT>() };
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<std::function<ReturnT(MonoObject*, ArgTypes...)>>(
[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<ReturnT>(result);
}
);
}
};
class Assembly {

View File

@ -25,17 +25,4 @@ std::shared_ptr<Assembly> RuntimeJIT::loadAssembly(const std::string &name){
return std::make_shared<Assembly>(ptr);
}
void getMethodSignatureTypes(MonoMethod* mono_method,
MonoType** return_type,
std::vector<MonoType*>& 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);
}
}
}

View File

@ -0,0 +1,30 @@
#pragma once
#include <functional>
#include <memory>
template <typename SignatureT>
class function_shared_ptr;
template<typename ReturnT, typename... ArgTypes>
class function_shared_ptr<ReturnT(ArgTypes...)> {
public:
using func_t = std::function<ReturnT(ArgTypes...)>;
using ptr_t = std::shared_ptr<func_t>;
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<typename FunctionT>
function_shared_ptr(FunctionT f){ func_ptr = std::make_shared<func_t>(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;
};

View File

@ -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<Mono::Int, Mono::Byte, Mono::Float>(c, "Method");
auto m = Mono::Method<Mono::Int(Mono::Byte, Mono::Float)>(c, "Method");
std::cout<<"method has been found"<<std::endl;
Mono::Int r = m->operator()(nullptr, 16, 0.32);
Mono::Int r = m(nullptr, 16, 0.32);
std::cout<<"result: "<<r<<std::endl;
return 0;
std::cout<<"initialized mono jit runtime"<<std::endl;
GUI::MainWindow w;
w.open("ougge", update);
std::cout<<"created sdl window"<<std::endl;
w.startUpdateLoop();
std::cout<<"sdl window has been cosed"<<std::endl;
// GUI::MainWindow w;
// w.open("ougge", update);
// std::cout<<"created sdl window"<<std::endl;
// w.startUpdateLoop();
// std::cout<<"sdl window has been cosed"<<std::endl;
}
catch(const std::exception& e){
std::cerr<<"Catched exception: "<<e.what()<<std::endl;