#ifndef GD_MONO_METHOD_THUNK_H #define GD_MONO_METHOD_THUNK_H #include #include "gd_mono_class.h" #include "gd_mono_header.h" #include "gd_mono_marshal.h" #include "gd_mono_method.h" #include "gd_mono_utils.h" #if !defined(JAVASCRIPT_ENABLED) #define HAVE_METHOD_THUNKS #endif #ifdef HAVE_METHOD_THUNKS template struct GDMonoMethodThunk { typedef void(GD_MONO_STDCALL *M)(ParamTypes... p_args, MonoException **); M mono_method_thunk; public: _FORCE_INLINE_ void invoke(ParamTypes... p_args, MonoException **r_exc) { GD_MONO_BEGIN_RUNTIME_INVOKE; mono_method_thunk(p_args..., r_exc); GD_MONO_END_RUNTIME_INVOKE; } _FORCE_INLINE_ bool is_null() { return mono_method_thunk == NULL; } _FORCE_INLINE_ void nullify() { mono_method_thunk = NULL; } _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) { #ifdef DEBUG_ENABLED CRASH_COND(p_mono_method == NULL); CRASH_COND(p_mono_method->get_return_type().type_encoding != MONO_TYPE_VOID); if (p_mono_method->is_static()) { CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes)); } else { CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1)); } #endif mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method->get_mono_ptr()); } GDMonoMethodThunk() : mono_method_thunk(NULL) { } explicit GDMonoMethodThunk(GDMonoMethod *p_mono_method) { set_from_method(p_mono_method); } }; template struct GDMonoMethodThunkR { typedef R(GD_MONO_STDCALL *M)(ParamTypes... p_args, MonoException **); M mono_method_thunk; public: _FORCE_INLINE_ R invoke(ParamTypes... p_args, MonoException **r_exc) { GD_MONO_BEGIN_RUNTIME_INVOKE; R r = mono_method_thunk(p_args..., r_exc); GD_MONO_END_RUNTIME_INVOKE; return r; } _FORCE_INLINE_ bool is_null() { return mono_method_thunk == NULL; } _FORCE_INLINE_ void nullify() { mono_method_thunk = NULL; } _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) { #ifdef DEBUG_ENABLED CRASH_COND(p_mono_method == NULL); CRASH_COND(p_mono_method->get_return_type().type_encoding == MONO_TYPE_VOID); if (p_mono_method->is_static()) { CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes)); } else { CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1)); } #endif mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method->get_mono_ptr()); } GDMonoMethodThunkR() : mono_method_thunk(NULL) { } explicit GDMonoMethodThunkR(GDMonoMethod *p_mono_method) { #ifdef DEBUG_ENABLED CRASH_COND(p_mono_method == NULL); #endif mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method->get_mono_ptr()); } }; #else template struct VariadicInvokeMonoMethodImpl { static void invoke(GDMonoMethod *p_mono_method, P1 p_arg1, ParamTypes... p_args, MonoException **r_exc) { if (p_mono_method->is_static()) { void *args[ThunkParamCount] = { p_arg1, p_args... }; p_mono_method->invoke_raw(NULL, args, r_exc); } else { void *args[ThunkParamCount] = { p_args... }; p_mono_method->invoke_raw((MonoObject *)p_arg1, args, r_exc); } } }; template struct VariadicInvokeMonoMethod { static void invoke(GDMonoMethod *p_mono_method, ParamTypes... p_args, MonoException **r_exc) { VariadicInvokeMonoMethodImpl::invoke(p_mono_method, p_args..., r_exc); } }; template <> struct VariadicInvokeMonoMethod<0> { static void invoke(GDMonoMethod *p_mono_method, MonoException **r_exc) { #ifdef DEBUG_ENABLED CRASH_COND(!p_mono_method->is_static()); #endif p_mono_method->invoke_raw(NULL, NULL, r_exc); } }; template struct VariadicInvokeMonoMethod<1, P1> { static void invoke(GDMonoMethod *p_mono_method, P1 p_arg1, MonoException **r_exc) { if (p_mono_method->is_static()) { void *args[1] = { p_arg1 }; p_mono_method->invoke_raw(NULL, args, r_exc); } else { p_mono_method->invoke_raw((MonoObject *)p_arg1, NULL, r_exc); } } }; template R unbox_if_needed(MonoObject *p_val, const ManagedType &, typename std::enable_if::value>::type * = 0) { return GDMonoMarshal::unbox(p_val); } template R unbox_if_needed(MonoObject *p_val, const ManagedType &p_type, typename std::enable_if::value>::type * = 0) { if (mono_class_is_valuetype(p_type.type_class->get_mono_ptr())) { return GDMonoMarshal::unbox(p_val); } else { // If it's not a value type, we assume 'R' is a pointer to 'MonoObject' or a compatible type, like 'MonoException'. return (R)p_val; } } template struct VariadicInvokeMonoMethodRImpl { static R invoke(GDMonoMethod *p_mono_method, P1 p_arg1, ParamTypes... p_args, MonoException **r_exc) { if (p_mono_method->is_static()) { void *args[ThunkParamCount] = { p_arg1, p_args... }; MonoObject *r = p_mono_method->invoke_raw(NULL, args, r_exc); return unbox_if_needed(r, p_mono_method->get_return_type()); } else { void *args[ThunkParamCount] = { p_args... }; MonoObject *r = p_mono_method->invoke_raw((MonoObject *)p_arg1, args, r_exc); return unbox_if_needed(r, p_mono_method->get_return_type()); } } }; template struct VariadicInvokeMonoMethodR { static R invoke(GDMonoMethod *p_mono_method, ParamTypes... p_args, MonoException **r_exc) { return VariadicInvokeMonoMethodRImpl::invoke(p_mono_method, p_args..., r_exc); } }; template struct VariadicInvokeMonoMethodR<0, R> { static R invoke(GDMonoMethod *p_mono_method, MonoException **r_exc) { #ifdef DEBUG_ENABLED CRASH_COND(!p_mono_method->is_static()); #endif MonoObject *r = p_mono_method->invoke_raw(NULL, NULL, r_exc); return unbox_if_needed(r, p_mono_method->get_return_type()); } }; template struct VariadicInvokeMonoMethodR<1, R, P1> { static R invoke(GDMonoMethod *p_mono_method, P1 p_arg1, MonoException **r_exc) { if (p_mono_method->is_static()) { void *args[1] = { p_arg1 }; MonoObject *r = p_mono_method->invoke_raw(NULL, args, r_exc); return unbox_if_needed(r, p_mono_method->get_return_type()); } else { MonoObject *r = p_mono_method->invoke_raw((MonoObject *)p_arg1, NULL, r_exc); return unbox_if_needed(r, p_mono_method->get_return_type()); } } }; template struct GDMonoMethodThunk { GDMonoMethod *mono_method; public: _FORCE_INLINE_ void invoke(ParamTypes... p_args, MonoException **r_exc) { VariadicInvokeMonoMethod::invoke(mono_method, p_args..., r_exc); } _FORCE_INLINE_ bool is_null() { return mono_method == NULL; } _FORCE_INLINE_ void nullify() { mono_method = NULL; } _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) { #ifdef DEBUG_ENABLED CRASH_COND(p_mono_method == NULL); CRASH_COND(p_mono_method->get_return_type().type_encoding != MONO_TYPE_VOID); if (p_mono_method->is_static()) { CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes)); } else { CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1)); } #endif mono_method = p_mono_method; } GDMonoMethodThunk() : mono_method(NULL) { } explicit GDMonoMethodThunk(GDMonoMethod *p_mono_method) { set_from_method(p_mono_method); } }; template struct GDMonoMethodThunkR { GDMonoMethod *mono_method; public: _FORCE_INLINE_ R invoke(ParamTypes... p_args, MonoException **r_exc) { return VariadicInvokeMonoMethodR::invoke(mono_method, p_args..., r_exc); } _FORCE_INLINE_ bool is_null() { return mono_method == NULL; } _FORCE_INLINE_ void nullify() { mono_method = NULL; } _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) { #ifdef DEBUG_ENABLED CRASH_COND(p_mono_method == NULL); CRASH_COND(p_mono_method->get_return_type().type_encoding == MONO_TYPE_VOID); if (p_mono_method->is_static()) { CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes)); } else { CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1)); } #endif mono_method = p_mono_method; } GDMonoMethodThunkR() : mono_method(NULL) { } explicit GDMonoMethodThunkR(GDMonoMethod *p_mono_method) { set_from_method(p_mono_method); } }; #endif #endif // GD_MONO_METHOD_THUNK_H