diff --git a/src/Mono/Assembly.cpp b/src/Mono/Assembly.cpp new file mode 100644 index 0000000..9a5cb8a --- /dev/null +++ b/src/Mono/Assembly.cpp @@ -0,0 +1,23 @@ +#include "Mono.hpp" + +namespace Mono { + +Assembly::Assembly(MonoAssembly *ptr) + : ptr(ptr), image(mono_assembly_get_image(ptr)) +{ +} + +Assembly::~Assembly(){ + // Tt causes SEGFAULT. + // Is it even possible to unload assembly from domain? + // mono_assembly_close(ptr); +} + +std::shared_ptr Assembly::getClass(const std::string &name_space, const std::string &name){ + MonoClass* ptr = mono_class_from_name(image, name_space.c_str(), name.c_str()); + if(!ptr) + throw UsefulException(format("can't find class '%s.%s'", name_space.c_str(), name.c_str())); + return std::make_shared(ptr, name_space, name); +} + +} diff --git a/src/Mono/Class.cpp b/src/Mono/Class.cpp new file mode 100644 index 0000000..e2225cc --- /dev/null +++ b/src/Mono/Class.cpp @@ -0,0 +1,33 @@ +#include "Mono.hpp" + +namespace Mono { + +Class::Class(MonoClass *ptr, const std::string& name_space, const std::string& name) + : ptr(ptr), name_space(name_space), name(name) +{ + void* iter = nullptr; + MonoMethod* m = nullptr; + while( (m = mono_class_get_methods(ptr, &iter)) ){ + auto name = std::string_view(mono_method_get_name(m)); + methods.emplace(std::piecewise_construct, + std::forward_as_tuple(name), + std::forward_as_tuple(m, name)); + } +} + + +template<> +void* _valueToVoidPtr(Object& v){ return v; } +template<> +void* _valueToVoidPtr(String& v){ return v; } + +template<> +Object _valueFromMonoObject(MonoObject* o){ + return (Object)o; +} +template<> +String _valueFromMonoObject(MonoObject* o){ + return (String)((void*)o); +} + +} diff --git a/src/Mono/Method.cpp b/src/Mono/Method.cpp new file mode 100644 index 0000000..d55714c --- /dev/null +++ b/src/Mono/Method.cpp @@ -0,0 +1,16 @@ +#include "Mono.hpp" + +namespace Mono { + +Method::Method(MonoMethod *ptr, const std::string_view& name) + : ptr(ptr), signature(mono_method_signature(ptr)), name(name) +{ + 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/Mono/Mono.cpp b/src/Mono/Mono.cpp index 3fe21f2..0a7b0eb 100644 --- a/src/Mono/Mono.cpp +++ b/src/Mono/Mono.cpp @@ -1,80 +1,22 @@ #include "Mono.hpp" -#include "../UsefulException.hpp" -#include "../format.hpp" -#include -#include -#include -#include +#include namespace Mono { -RuntimeJIT::RuntimeJIT(const std::string& domain_name){ - mono_set_dirs("mono-libs", "mono-libs"); - mono_set_assemblies_path("mono-libs"); - mono_config_parse("mono-libs/config.xml"); +template <> MonoClass* getClass(){ return mono_get_sbyte_class(); } +template <> MonoClass* getClass(){ return mono_get_byte_class(); } +template <> MonoClass* getClass(){ return mono_get_int16_class(); } +template <> MonoClass* getClass(){ return mono_get_uint16_class(); } +template <> MonoClass* getClass(){ return mono_get_int32_class(); } +template <> MonoClass* getClass(){ return mono_get_uint32_class(); } +template <> MonoClass* getClass(){ return mono_get_int64_class(); } +template <> MonoClass* getClass(){ return mono_get_uint64_class(); } +template <> MonoClass* getClass(){ return mono_get_single_class(); } +template <> MonoClass* getClass(){ return mono_get_double_class(); } +template <> MonoClass* getClass(){ return mono_get_boolean_class(); } +template <> MonoClass* getClass(){ return mono_get_char_class(); } +template <> MonoClass* getClass(){ return mono_get_string_class(); } +template <> MonoClass* getClass(){ return mono_get_object_class(); } +template <> MonoClass* getClass(){ return mono_get_void_class(); } - domain = mono_jit_init(domain_name.c_str()); - if(!domain) - throw UsefulException("can't initialize mono domain"); } - -RuntimeJIT::~RuntimeJIT(){ - mono_jit_cleanup(domain); -} - -std::shared_ptr RuntimeJIT::loadAssembly(const std::string &name){ - MonoAssembly* ptr = mono_domain_assembly_open(domain, "app.exe"); - if(!ptr) - throw UsefulException(format("can't load assembly '%s'", name.c_str())); - return std::make_shared(ptr); -} - -Assembly::Assembly(MonoAssembly *ptr) - : ptr(ptr), image(mono_assembly_get_image(ptr)) -{ -} - -Assembly::~Assembly(){ - // Tt causes SEGFAULT. - // Is it even possible to unload assembly from domain? - // mono_assembly_close(ptr); -} - -std::shared_ptr Assembly::getClass(const std::string &name_space, const std::string &name){ - MonoClass* ptr = mono_class_from_name(image, name_space.c_str(), name.c_str()); - if(!ptr) - throw UsefulException(format("can't find class '%s.%s'", name_space.c_str(), name.c_str())); - return std::make_shared(ptr); -} - -Class::Class(MonoClass *ptr) - : ptr(ptr) -{ - void* iter = nullptr; - MonoMethod* m = nullptr; - while( (m = mono_class_get_methods(ptr, &iter)) ){ - auto name = std::string_view(mono_method_get_name(m)); - methods.emplace(std::piecewise_construct, - std::forward_as_tuple(name), - std::forward_as_tuple(name, m)); - } -} - -template -std::shared_ptr> getMethod(const std::string& name){ - - return std::make_shared>(); -} - -Method::Method(const std::string_view &name, MonoMethod *ptr) - : ptr(ptr), signature(mono_method_signature(ptr)), name(name) -{ - void* iter = nullptr; - MonoType* rt = mono_signature_get_return_type(signature); - MonoType* pt = nullptr; - while( (pt = mono_signature_get_params(signature, &iter)) ){ - std::cout<<"name: "< #include #include @@ -16,34 +18,105 @@ typedef u8 Byte; typedef i16 Short; typedef u16 UShort; typedef i32 Int; -typedef i32 UInt; +typedef u32 UInt; typedef i64 Long; -typedef i64 ULong; +typedef u64 ULong; typedef f32 Float; typedef f64 Double; +typedef union { mono_bool wide_bool; } Bool; //USAGE: Bool t = {true}; +typedef char16_t Char; typedef MonoString* String; +typedef MonoObject* Object; +typedef void Void; +template +MonoClass* getClass(); class Method { +public: MonoMethod* ptr; MonoMethodSignature* signature; - -public: const std::string_view name; - Method(const std::string_view& name, MonoMethod* ptr); + MonoType* return_type; + std::vector argument_types; + + Method(MonoMethod* ptr, const std::string_view& name); }; + +template +void* _valueToVoidPtr(T& v){ + return &v; +} +template +T _valueFromMonoObject(MonoObject* o){ + void* result_value_ptr = mono_object_unbox(o); + if(result_value_ptr == nullptr) + throw UsefulException("can't unbox method value"); + return *((T*)result_value_ptr); +} + class Class { - std::multimap methods; - MonoClass* ptr; public: - Class(MonoClass* ptr); + std::multimap methods; + MonoClass* ptr; + const std::string name_space; + const std::string name; + + Class(MonoClass* ptr, const std::string& name_space, const std::string& name); Class(const Class&) = delete; + /// @brief all types must have template implementation of getClass() + /// @tparam ReturnT return type + /// @tparam ...ArgTypes argument types + /// @return function which takes arguments and returns value of ReturnT template - std::shared_ptr> getMethod(const std::string& name); + std::shared_ptr> getMethod(const std::string& name){ + Method* m = nullptr; + static std::vector arg_classes { getClass()... }; + // iterate each method overload + for(auto it = methods.find(name); it != methods.end(); it++){ + m = &it->second; + // compare argument count + if(m->argument_types.size() != arg_classes.size()) + continue; + // compare return type + if(!mono_metadata_type_equal(m->return_type, mono_class_get_type(getClass()))) + continue; + // compare argument types + bool argument_types_mismatch = false; + for(size_t i = 0; i < arg_classes.size(); i++){ + if(!mono_metadata_type_equal(m->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; + } + + // if method not found throw exception + if(m == nullptr) + throw UsefulException(format("can't get method '%s' from class '%s'", + name.c_str(), this->name.c_str())); + + MonoMethod* m_ptr = m->ptr; + return std::make_shared>( + [m_ptr](MonoObject* class_instance, ArgTypes... args) -> ReturnT + { + void* arg_array[] = { _valueToVoidPtr(args)..., nullptr }; + // MonoException* ex = nullptr; + // TODO: exception catch + MonoObject* result = mono_runtime_invoke(m_ptr, class_instance, arg_array, nullptr); + return _valueFromMonoObject(result); + } + ); + } }; + class Assembly { MonoAssembly* ptr; MonoImage* image; @@ -69,4 +142,4 @@ public: std::shared_ptr loadAssembly(const std::string& name); }; -} +} // namespace Mono diff --git a/src/Mono/Runtime.cpp b/src/Mono/Runtime.cpp new file mode 100644 index 0000000..a85ebdf --- /dev/null +++ b/src/Mono/Runtime.cpp @@ -0,0 +1,28 @@ +#include "Mono.hpp" +#include +#include + +namespace Mono { + +RuntimeJIT::RuntimeJIT(const std::string& domain_name){ + mono_set_dirs("mono-libs", "mono-libs"); + mono_set_assemblies_path("mono-libs"); + mono_config_parse("mono-libs/config.xml"); + + domain = mono_jit_init(domain_name.c_str()); + if(!domain) + throw UsefulException("can't initialize mono domain"); +} + +RuntimeJIT::~RuntimeJIT(){ + mono_jit_cleanup(domain); +} + +std::shared_ptr RuntimeJIT::loadAssembly(const std::string &name){ + MonoAssembly* ptr = mono_domain_assembly_open(domain, "app.exe"); + if(!ptr) + throw UsefulException(format("can't load assembly '%s'", name.c_str())); + return std::make_shared(ptr); +} + +} diff --git a/src/main.cpp b/src/main.cpp index d4be044..a69f8e8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,12 +15,19 @@ void update(f64 deltaTime){ int main(int argc, const char** argv){ try { - Resources::init(); - std::cout<<"initialized resource loader"<getClass("", "A"); + auto m = c->getMethod("Method"); + std::cout<<"method has been found"<operator()(nullptr, 16, 0.32); + std::cout<<"result: "<