188 lines
6.0 KiB
C++
188 lines
6.0 KiB
C++
#pragma once
|
|
|
|
#include "../common/std.hpp"
|
|
#include "../common/UsefulException.hpp"
|
|
#include "../common/ougge_format.hpp"
|
|
#include <vector>
|
|
#include <type_traits>
|
|
#include <mono/metadata/class.h>
|
|
#include <mono/metadata/assembly.h>
|
|
#include <mono/metadata/object.h>
|
|
|
|
namespace Mono {
|
|
|
|
typedef i8 SByte;
|
|
typedef u8 Byte;
|
|
typedef i16 Short;
|
|
typedef u16 UShort;
|
|
typedef i32 Int;
|
|
typedef u32 UInt;
|
|
typedef i64 Long;
|
|
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;
|
|
/// @warning MonoObject can be moved in memory by GC in any time and raw pointer will be invalid.
|
|
/// Use ObjectHandle where it is possible.
|
|
typedef MonoObject* Object;
|
|
typedef void Void;
|
|
|
|
|
|
template<typename PrimitiveT>
|
|
MonoClass* getClass();
|
|
|
|
template<typename T>
|
|
void* valueToVoidPtr(T& v){ return &v; }
|
|
template<>
|
|
inline void* valueToVoidPtr<Object>(Object& v){ return v; }
|
|
template<>
|
|
inline void* valueToVoidPtr<String>(String& v){ return v; }
|
|
|
|
template<typename T>
|
|
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);
|
|
}
|
|
template<>
|
|
inline Object valueFromMonoObject<Object>(MonoObject* o){ return o; }
|
|
template<>
|
|
inline String valueFromMonoObject<String>(MonoObject* o){ return (String)((void*)o); }
|
|
|
|
void getMethodSignatureTypes(MonoMethod* mono_method,
|
|
MonoType** return_type,
|
|
std::vector<MonoType*>& argument_types);
|
|
|
|
/// 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>
|
|
class Method<ReturnT(ArgTypes...)>
|
|
{
|
|
MonoMethod* method_ptr;
|
|
|
|
public:
|
|
Method() { method_ptr = nullptr; }
|
|
|
|
/// 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(ougge_format("can't get method '%s' from class '%s'",
|
|
name.c_str(), mono_class_get_name(target_class)));
|
|
}
|
|
}
|
|
|
|
// ReturnT not is void
|
|
template<typename RT = ReturnT>
|
|
std::enable_if_t<!std::is_void<RT>::value, RT> operator()(MonoObject* class_instance, ArgTypes... args) const {
|
|
if(method_ptr == nullptr)
|
|
throw UsefulException("method_ptr is null");
|
|
|
|
void* arg_array[] = { valueToVoidPtr(args)..., nullptr };
|
|
MonoObject* ex = nullptr;
|
|
MonoObject* result = mono_runtime_invoke(method_ptr, class_instance, arg_array, &ex);
|
|
if(ex){
|
|
//TODO: call mono_trace_set_printerr_handler from mono/mono/utils/mono-logger.h
|
|
mono_print_unhandled_exception(ex);
|
|
throw UsefulException("Some C# exception occured");
|
|
}
|
|
return valueFromMonoObject<ReturnT>(result);
|
|
};
|
|
|
|
// ReturnT is void
|
|
template<typename RT = ReturnT>
|
|
std::enable_if_t<std::is_void<RT>::value, RT> operator()(MonoObject* class_instance, ArgTypes... args) const {
|
|
if(method_ptr == nullptr)
|
|
throw UsefulException("method_ptr is null");
|
|
|
|
void* arg_array[] = { valueToVoidPtr(args)..., nullptr };
|
|
MonoObject* ex = nullptr;
|
|
mono_runtime_invoke(method_ptr, class_instance, arg_array, &ex);
|
|
if(ex){
|
|
//TODO: call mono_trace_set_printerr_handler from mono/mono/utils/mono-logger.h
|
|
mono_print_unhandled_exception(ex);
|
|
throw UsefulException("Some C# exception occured");
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
class Assembly {
|
|
MonoAssembly* ptr;
|
|
MonoImage* image;
|
|
|
|
public:
|
|
Assembly(MonoAssembly* ptr);
|
|
Assembly(const Assembly&) = delete;
|
|
|
|
MonoClass* getClass(const std::string& name_space, const std::string& name);
|
|
MonoAssembly* getMonoAssembly() const { return ptr; }
|
|
MonoImage* getMonoImage() const { return image; }
|
|
};
|
|
|
|
|
|
///LINUX: `config.xml`, `mscorelib.dll`, `libmono-native.so` in `mono-libs` directory
|
|
///
|
|
///WINDOWS: `config.xml`, `mscorelib.dll` in `mono-libs` directory
|
|
class RuntimeJIT {
|
|
MonoDomain* domain;
|
|
public:
|
|
RuntimeJIT(const std::string& domain_name = "OuggeDomain");
|
|
RuntimeJIT(const RuntimeJIT&) = delete;
|
|
~RuntimeJIT();
|
|
|
|
inline MonoDomain* getDomain() { return domain; }
|
|
std::shared_ptr<Assembly> loadAssembly(const std::string& name);
|
|
|
|
inline Object createObject(MonoClass* klass) { return mono_object_new(domain, klass); }
|
|
inline String createString(const std::string& v) { return mono_string_new_len(domain, v.c_str(), v.size()); }
|
|
inline String createString(const char* v) { return mono_string_new(domain, v); }
|
|
};
|
|
|
|
/// @brief ObjectHandle can be used to store reliable reference to MonoObject.
|
|
/// MonoObject can be moved in memory by GC in any time and raw pointer will be invalid.
|
|
struct ObjectHandle {
|
|
u32 gc_handle;
|
|
|
|
inline ObjectHandle() : gc_handle(0) {}
|
|
|
|
inline ObjectHandle(Object obj) {
|
|
gc_handle = mono_gchandle_new(obj, false);
|
|
}
|
|
|
|
/// implicitly create new ObjectHandle instead
|
|
inline ObjectHandle(const ObjectHandle& o) = delete;
|
|
|
|
inline ObjectHandle(ObjectHandle&& o) {
|
|
gc_handle = o.gc_handle;
|
|
o.gc_handle = 0;
|
|
}
|
|
|
|
inline ObjectHandle& operator=(ObjectHandle&& o) {
|
|
gc_handle = o.gc_handle;
|
|
o.gc_handle = 0;
|
|
return *this;
|
|
}
|
|
|
|
inline ~ObjectHandle() {
|
|
if(gc_handle)
|
|
mono_gchandle_free(gc_handle);
|
|
}
|
|
|
|
inline Object getObject() const {
|
|
return mono_gchandle_get_target(gc_handle);
|
|
}
|
|
};
|
|
|
|
}
|