From a81ec226dcb61acc8ac48465ba0f4c5a14a1f267 Mon Sep 17 00:00:00 2001 From: Christopher Redden Date: Thu, 19 Feb 2026 10:56:35 +0100 Subject: [PATCH 1/8] Adding basic utilities for accessing attribute arguments --- mono/metadata/unity-utils.c | 56 +++++++++++++++++++++++++++++++++++++ mono/metadata/unity-utils.h | 15 +++++++++- 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/mono/metadata/unity-utils.c b/mono/metadata/unity-utils.c index 7a0ea2d221ff..823c5d832dd0 100644 --- a/mono/metadata/unity-utils.c +++ b/mono/metadata/unity-utils.c @@ -1,3 +1,4 @@ +#include "unity-utils.h" #include @@ -31,6 +32,7 @@ #include #include #include +#include "mono/metadata/custom-attrs-internals.h" #if HAVE_BOEHM_GC #include @@ -2049,3 +2051,57 @@ ves_icall_Unity_Android_Network_Interface_Up_State (MonoString *ifName, MonoBool } #endif +MonoAttrArgsInfo* mono_unity_get_attr_args_info(MonoCustomAttrInfo *cainfo, int index) +{ + g_assert(index < cainfo->num_attrs); + + MonoCustomAttrEntry *centry = &cainfo->attrs [index]; + if (centry->ctor == NULL) + return NULL; + + //MonoClass *klass = centry->ctor->klass; + //if (strcmp (m_class_get_name (klass), "CategoryAttribute") || mono_method_signature_internal (centry->ctor)->param_count != 1) + // continue; + + MonoAttrArgsInfo *attr_args_info = g_malloc(sizeof(MonoAttrArgsInfo)); + MonoMethodSignature *sig = mono_method_signature_internal(centry->ctor); + attr_args_info->num_type_args = sig->param_count; + + ERROR_DECL (error); + mono_reflection_create_custom_attr_data_args_noalloc ( + cainfo->image, centry->ctor, centry->data, centry->data_size, + &attr_args_info->typed_args, &attr_args_info->named_args, &attr_args_info->num_named_args, &attr_args_info->arginfo, error); + if (!is_ok (error)) + { + mono_error_cleanup (error); + g_free(attr_args_info); + return NULL; + } + + mono_error_cleanup (error); + + return attr_args_info; + + //g_free (typed_args); + //g_free (named_args); + //g_free (arginfo); +} + +void mono_unity_get_attr_args_info_free(MonoAttrArgsInfo *ainfo) +{ + g_free(ainfo->typed_args); + g_free(ainfo->named_args); + g_free(ainfo->arginfo); + g_free(ainfo); +} + +gint32 mono_unity_get_attr_args_info_type_arg_count(MonoAttrArgsInfo *ainfo) +{ + return ainfo->num_type_args; +} + +MonoClass* mono_unity_get_attr_type_arg_as_class(MonoAttrArgsInfo *ainfo, int index) +{ + g_assert(index < ainfo->num_type_args); + return mono_class_from_mono_type((MonoType*)ainfo->typed_args[index]); +} \ No newline at end of file diff --git a/mono/metadata/unity-utils.h b/mono/metadata/unity-utils.h index 7cf694aeafa2..7aac113f4107 100644 --- a/mono/metadata/unity-utils.h +++ b/mono/metadata/unity-utils.h @@ -276,4 +276,17 @@ mono_unity_set_android_network_up_state_func(android_network_up_state func); MonoBoolean ves_icall_Unity_Android_Network_Interface_Up_State (MonoString *ifName, MonoBoolean* is_up); -#endif +typedef struct { + gpointer *typed_args; + gpointer *named_args; + CattrNamedArg *arginfo; + int num_type_args; + int num_named_args; +} MonoAttrArgsInfo; + +MONO_API MonoAttrArgsInfo* mono_unity_get_attr_args_info(MonoCustomAttrInfo *cainfo, int index); +MONO_API void mono_unity_get_attr_args_info_free(MonoAttrArgsInfo *ainfo); +MONO_API gint32 mono_unity_get_attr_args_info_type_arg_count(MonoAttrArgsInfo *ainfo); +MONO_API MonoClass* mono_unity_get_attr_type_arg_as_class(MonoAttrArgsInfo *ainfo, int index); + +#endif \ No newline at end of file From 2551315f866ddbb41a58c155ec54dd5f180aa412 Mon Sep 17 00:00:00 2001 From: Christopher Redden Date: Thu, 26 Feb 2026 13:11:00 +0100 Subject: [PATCH 2/8] Exposing more methods for FastReflection --- mono/metadata/class.h | 3 ++ mono/metadata/unity-utils.c | 55 +++++++++++++++++++++++++++++++++++++ mono/metadata/unity-utils.h | 16 +++++++---- 3 files changed, 68 insertions(+), 6 deletions(-) diff --git a/mono/metadata/class.h b/mono/metadata/class.h index 01b0274ff85d..bab7b5e9f03a 100644 --- a/mono/metadata/class.h +++ b/mono/metadata/class.h @@ -163,6 +163,9 @@ MONO_API MONO_RT_EXTERNAL_ONLY mono_bool mono_class_is_enum (MonoClass *klass); +MONO_API mono_bool +mono_class_is_array (MonoClass *klass); + MONO_API MONO_RT_EXTERNAL_ONLY MonoType* mono_class_enum_basetype (MonoClass *klass); diff --git a/mono/metadata/unity-utils.c b/mono/metadata/unity-utils.c index 823c5d832dd0..01b4d9503ff9 100644 --- a/mono/metadata/unity-utils.c +++ b/mono/metadata/unity-utils.c @@ -2104,4 +2104,59 @@ MonoClass* mono_unity_get_attr_type_arg_as_class(MonoAttrArgsInfo *ainfo, int in { g_assert(index < ainfo->num_type_args); return mono_class_from_mono_type((MonoType*)ainfo->typed_args[index]); +} + +int mono_unity_get_attr_type_arg_as_int(MonoAttrArgsInfo *ainfo, int index) +{ + g_assert(index < ainfo->num_type_args); + return *(int*)(ainfo->typed_args[index]); +} + +uint64_t mono_unity_get_attr_type_arg_as_uint64(MonoAttrArgsInfo *ainfo, int index) +{ + g_assert(index < ainfo->num_type_args); + return *(uint64_t*)(ainfo->typed_args[index]); +} + +const char* mono_unity_class_get_assembly_name_cstring(MonoClass *klass) +{ + MonoAssembly *ta = m_class_get_image (klass)->assembly; + return (const char*)mono_stringify_assembly_name (&ta->aname); +} + +gboolean mono_unity_type_is_blittable_primitive(MonoType *type) +{ + return (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_R8) || + type-> type == MONO_TYPE_I || type->type == MONO_TYPE_U || type->type == MONO_TYPE_PTR; +} + +gboolean mono_unity_type_is_unmanaged(MonoType *type) +{ + if (mono_unity_type_is_blittable_primitive(type)) + return TRUE; + + MonoClass* klass = mono_class_from_mono_type(type); + + // if it's not a valuetype, we're done + if (!mono_class_is_valuetype(klass)) + return FALSE; + + // if it's a blittable valuetype, we're done + if (mono_class_is_blittable(klass)) + return TRUE; + + // It's a non-blittable valuetype. We have to look at its fields, + // because we want to allow bools, chars, and other unmanaged fields + // that are not "CLR Blittable" + gpointer iter = NULL; + MonoClassField *field; + while ((field = mono_class_get_fields(klass, &iter))) + { + if ((mono_field_get_flags(field) & FIELD_ATTRIBUTE_STATIC) != 0) + continue; + if (!mono_unity_type_is_unmanaged(mono_field_get_type(field))) + return FALSE; + } + + return TRUE; } \ No newline at end of file diff --git a/mono/metadata/unity-utils.h b/mono/metadata/unity-utils.h index 7aac113f4107..6587b7aee26a 100644 --- a/mono/metadata/unity-utils.h +++ b/mono/metadata/unity-utils.h @@ -103,7 +103,7 @@ int mono_unity_class_get_instance_size(MonoClass *klass); MonoClass* mono_unity_class_get_castclass(MonoClass *klass); guint32 mono_unity_class_get_native_size(MonoClass* klass); MonoBoolean mono_unity_class_is_string(MonoClass* klass); -MonoBoolean mono_unity_class_is_class_type(MonoClass* klass); +MONO_API MonoBoolean mono_unity_class_is_class_type(MonoClass* klass); MONO_API gboolean mono_unity_class_is_inited(MonoClass* klass); MONO_API gboolean mono_class_is_generic(MonoClass *klass); MONO_API gboolean mono_class_is_blittable(MonoClass *klass); @@ -144,15 +144,15 @@ MonoClass* mono_unity_array_get_class(MonoArray *arr); mono_array_size_t mono_unity_array_get_max_length(MonoArray *arr); //type -gboolean mono_unity_type_is_generic_instance(MonoType *type); -MonoGenericClass* mono_unity_type_get_generic_class(MonoType *type); +MONO_API gboolean mono_unity_type_is_generic_instance(MonoType *type); +MONO_API MonoGenericClass* mono_unity_type_get_generic_class(MonoType *type); gboolean mono_unity_type_is_enum_type(MonoType *type); gboolean mono_unity_type_is_boolean(MonoType *type); MonoClass* mono_unity_type_get_element_class(MonoType *type); //only safe to call when the type has a defined klass data element guint64 mono_unity_type_get_hash(MonoType *type, gboolean inflate); //generic class -MonoGenericContext mono_unity_generic_class_get_context(MonoGenericClass *klass); +MONO_API MonoGenericContext mono_unity_generic_class_get_context(MonoGenericClass *klass); MonoClass* mono_unity_generic_class_get_container_class(MonoGenericClass *klass); //method signature @@ -161,8 +161,8 @@ int mono_unity_signature_num_parameters(MonoMethodSignature *sig); gboolean mono_unity_signature_param_is_byref(MonoMethodSignature *sig, int index); //generic inst -guint mono_unity_generic_inst_get_type_argc(MonoGenericInst *inst); -MonoType* mono_unity_generic_inst_get_type_argument(MonoGenericInst *inst, int index); +MONO_API guint mono_unity_generic_inst_get_type_argc(MonoGenericInst *inst); +MONO_API MonoType* mono_unity_generic_inst_get_type_argument(MonoGenericInst *inst, int index); //exception MonoString* mono_unity_exception_get_message(MonoException *exc); @@ -288,5 +288,9 @@ MONO_API MonoAttrArgsInfo* mono_unity_get_attr_args_info(MonoCustomAttrInfo *cai MONO_API void mono_unity_get_attr_args_info_free(MonoAttrArgsInfo *ainfo); MONO_API gint32 mono_unity_get_attr_args_info_type_arg_count(MonoAttrArgsInfo *ainfo); MONO_API MonoClass* mono_unity_get_attr_type_arg_as_class(MonoAttrArgsInfo *ainfo, int index); +MONO_API int mono_unity_get_attr_type_arg_as_int(MonoAttrArgsInfo *ainfo, int index); +MONO_API uint64_t mono_unity_get_attr_type_arg_as_uint64(MonoAttrArgsInfo *ainfo, int index); +MONO_API const char* mono_unity_class_get_assembly_name_cstring(MonoClass *klass); +MONO_API gboolean mono_unity_type_is_unmanaged(MonoType *type); #endif \ No newline at end of file From bc35dc5710cb5b5886253652ff10723b9c99ea88 Mon Sep 17 00:00:00 2001 From: Christopher Redden Date: Thu, 26 Feb 2026 13:46:47 +0100 Subject: [PATCH 3/8] Fixing change to header --- mono/metadata/class.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/mono/metadata/class.h b/mono/metadata/class.h index bab7b5e9f03a..01b0274ff85d 100644 --- a/mono/metadata/class.h +++ b/mono/metadata/class.h @@ -163,9 +163,6 @@ MONO_API MONO_RT_EXTERNAL_ONLY mono_bool mono_class_is_enum (MonoClass *klass); -MONO_API mono_bool -mono_class_is_array (MonoClass *klass); - MONO_API MONO_RT_EXTERNAL_ONLY MonoType* mono_class_enum_basetype (MonoClass *klass); From 304bbf196fe6d7ae6526e41cd9f6a58bb876b3bf Mon Sep 17 00:00:00 2001 From: Christopher Redden Date: Thu, 26 Feb 2026 14:18:40 +0100 Subject: [PATCH 4/8] Exporting unity special method --- mono/metadata/unity-utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mono/metadata/unity-utils.h b/mono/metadata/unity-utils.h index 6587b7aee26a..d1ef145e8523 100644 --- a/mono/metadata/unity-utils.h +++ b/mono/metadata/unity-utils.h @@ -96,7 +96,7 @@ MonoClass* mono_unity_class_get_generic_definition(MonoClass* klass); MonoClass* mono_unity_class_inflate_generic_class(MonoClass *gklass, MonoGenericContext *context); gboolean mono_unity_class_has_parent_unsafe(MonoClass *klass, MonoClass *parent); MonoAssembly* mono_unity_class_get_assembly(MonoClass *klass); -gboolean mono_unity_class_is_array(MonoClass *klass); +MONO_API gboolean mono_unity_class_is_array(MonoClass *klass); MonoClass* mono_unity_class_get_element_class(MonoClass *klass); gboolean mono_unity_class_is_delegate(MonoClass *klass); int mono_unity_class_get_instance_size(MonoClass *klass); From 819a147ef8544a2c0de6eaadc4296fd3f8814040 Mon Sep 17 00:00:00 2001 From: "anne.vanede" Date: Fri, 27 Feb 2026 11:44:30 +0100 Subject: [PATCH 5/8] Exposed has default constructor --- mono/metadata/class-internals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mono/metadata/class-internals.h b/mono/metadata/class-internals.h index 8f9d3cd93dc1..05941381dbdc 100644 --- a/mono/metadata/class-internals.h +++ b/mono/metadata/class-internals.h @@ -1569,7 +1569,7 @@ mono_class_enum_basetype_internal (MonoClass *klass); gboolean mono_method_is_constructor (MonoMethod *method); -gboolean +MONO_API gboolean mono_class_has_default_constructor (MonoClass *klass, gboolean public_only); gboolean From c40603cde0ab3477bace3e5851139d61bd85c0f2 Mon Sep 17 00:00:00 2001 From: Christopher Redden Date: Fri, 27 Feb 2026 14:16:25 +0100 Subject: [PATCH 6/8] Adding general call to get attr arg data ptr --- mono/metadata/unity-utils.c | 6 ++++++ mono/metadata/unity-utils.h | 1 + 2 files changed, 7 insertions(+) diff --git a/mono/metadata/unity-utils.c b/mono/metadata/unity-utils.c index 01b4d9503ff9..c3421d566db4 100644 --- a/mono/metadata/unity-utils.c +++ b/mono/metadata/unity-utils.c @@ -2118,6 +2118,12 @@ uint64_t mono_unity_get_attr_type_arg_as_uint64(MonoAttrArgsInfo *ainfo, int ind return *(uint64_t*)(ainfo->typed_args[index]); } +void* mono_unity_get_attr_type_arg(MonoAttrArgsInfo *ainfo, int index) +{ + g_assert(index < ainfo->num_type_args); + return ainfo->typed_args[index]; +} + const char* mono_unity_class_get_assembly_name_cstring(MonoClass *klass) { MonoAssembly *ta = m_class_get_image (klass)->assembly; diff --git a/mono/metadata/unity-utils.h b/mono/metadata/unity-utils.h index d1ef145e8523..949bfae2970f 100644 --- a/mono/metadata/unity-utils.h +++ b/mono/metadata/unity-utils.h @@ -289,6 +289,7 @@ MONO_API void mono_unity_get_attr_args_info_free(MonoAttrArgsInfo *ainfo); MONO_API gint32 mono_unity_get_attr_args_info_type_arg_count(MonoAttrArgsInfo *ainfo); MONO_API MonoClass* mono_unity_get_attr_type_arg_as_class(MonoAttrArgsInfo *ainfo, int index); MONO_API int mono_unity_get_attr_type_arg_as_int(MonoAttrArgsInfo *ainfo, int index); +MONO_API void* mono_unity_get_attr_type_arg(MonoAttrArgsInfo *ainfo, int index); MONO_API uint64_t mono_unity_get_attr_type_arg_as_uint64(MonoAttrArgsInfo *ainfo, int index); MONO_API const char* mono_unity_class_get_assembly_name_cstring(MonoClass *klass); MONO_API gboolean mono_unity_type_is_unmanaged(MonoType *type); From 01035894c334318c584348b56eb468f540e9d799 Mon Sep 17 00:00:00 2001 From: "anne.vanede" Date: Mon, 2 Mar 2026 12:02:44 +0100 Subject: [PATCH 7/8] HasInterface for generic interfaces --- mono/metadata/unity-utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mono/metadata/unity-utils.h b/mono/metadata/unity-utils.h index d1ef145e8523..8275251ed5b3 100644 --- a/mono/metadata/unity-utils.h +++ b/mono/metadata/unity-utils.h @@ -92,7 +92,7 @@ gboolean mono_unity_object_check_box_cast(MonoObject *obj, MonoClass *klass); //class const char* mono_unity_class_get_image_name(MonoClass* klass); -MonoClass* mono_unity_class_get_generic_definition(MonoClass* klass); +MONO_API MonoClass* mono_unity_class_get_generic_definition(MonoClass* klass); MonoClass* mono_unity_class_inflate_generic_class(MonoClass *gklass, MonoGenericContext *context); gboolean mono_unity_class_has_parent_unsafe(MonoClass *klass, MonoClass *parent); MonoAssembly* mono_unity_class_get_assembly(MonoClass *klass); From 08446c5bb59ded9f1f1ef3bb051a39d2b4a2bca6 Mon Sep 17 00:00:00 2001 From: "anne.vanede" Date: Tue, 10 Mar 2026 16:35:52 +0100 Subject: [PATCH 8/8] Generic context by pointer --- mono/metadata/unity-utils.c | 5 +++++ mono/metadata/unity-utils.h | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/mono/metadata/unity-utils.c b/mono/metadata/unity-utils.c index c3421d566db4..8f0067f3025e 100644 --- a/mono/metadata/unity-utils.c +++ b/mono/metadata/unity-utils.c @@ -825,6 +825,11 @@ MonoGenericContext mono_unity_generic_class_get_context(MonoGenericClass *klass) return klass->context; } +void mono_unity_generic_class_get_context_by_ptr(MonoGenericClass *klass, MonoGenericContext *context) +{ + *context = klass->context; +} + MonoClass* mono_unity_generic_class_get_container_class(MonoGenericClass *klass) { return klass->container_class; diff --git a/mono/metadata/unity-utils.h b/mono/metadata/unity-utils.h index e25121e7ec5e..121232333b80 100644 --- a/mono/metadata/unity-utils.h +++ b/mono/metadata/unity-utils.h @@ -152,7 +152,8 @@ MonoClass* mono_unity_type_get_element_class(MonoType *type); //only safe to cal guint64 mono_unity_type_get_hash(MonoType *type, gboolean inflate); //generic class -MONO_API MonoGenericContext mono_unity_generic_class_get_context(MonoGenericClass *klass); +MonoGenericContext mono_unity_generic_class_get_context(MonoGenericClass *klass); +MONO_API void mono_unity_generic_class_get_context_by_ptr(MonoGenericClass *klass, MonoGenericContext *context); MonoClass* mono_unity_generic_class_get_container_class(MonoGenericClass *klass); //method signature