From b3d9af902387c719edf27251049c5214854897b1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Aleksey=20Kliger=20=28=CE=BBgeek=29?= Date: Fri, 20 Jan 2017 10:35:02 -0500 Subject: [PATCH] [reflection] Use coop handles for MonoMethod icalls (#4272) * [reflection] Use coop handles for MonoMethod.GetGenericArguments * [reflection] Use handles for ves_icall_MonoMethod_GetGenericMethodDefinition and two more trivial functions: - ves_icall_MonoMethod_get_IsGenericMethod - ves_icall_MonoMethod_get_IsGenericMethodDefinition * [runtime] Add mono_method_get_base_method function - Internal function in class-internals.h, for now. - Code factored out from ves_icall_MonoMethod_get_base_method - ves_icall_MonoMethod_get_base_method just calls this utility and wraps on reflection objects, using handles. * [reflection] Use coop handles for ves_icall_MonoMethod_MakeGenericMethod_impl * [reflection] Use coop handles for ves_icall_MonoMethod_GetPInvoke * [reflection] Use coop handles for ves_icall_MonoMethod_get_core_clr_security_level * [reflection] Use coop handles for ves_icall_MonoMethod_get_name --- mono/metadata/class-internals.h | 3 + mono/metadata/class.c | 153 ++++++++++++++ mono/metadata/icall-def.h | 22 +- mono/metadata/icall.c | 335 ++++++++++--------------------- mono/metadata/object-internals.h | 4 +- mono/metadata/reflection.c | 92 +++++---- 6 files changed, 325 insertions(+), 284 deletions(-) diff --git a/mono/metadata/class-internals.h b/mono/metadata/class-internals.h index 57a9a145e9f..5ae0374e89a 100644 --- a/mono/metadata/class-internals.h +++ b/mono/metadata/class-internals.h @@ -1326,6 +1326,9 @@ mono_method_get_vtable_slot (MonoMethod *method); int mono_method_get_vtable_index (MonoMethod *method); +MonoMethod* +mono_method_get_base_method (MonoMethod *method, gboolean definition, MonoError *error); + MonoMethod* mono_method_search_in_array_class (MonoClass *klass, const char *name, MonoMethodSignature *sig); diff --git a/mono/metadata/class.c b/mono/metadata/class.c index fd9f2e98987..4cf5fcf4575 100644 --- a/mono/metadata/class.c +++ b/mono/metadata/class.c @@ -10594,3 +10594,156 @@ mono_class_full_name (MonoClass *klass) /* Declare all shared lazy type lookup functions */ GENERATE_TRY_GET_CLASS_WITH_CACHE (safehandle, System.Runtime.InteropServices, SafeHandle) + +/** + * mono_method_get_base_method: + * @method: a method + * @definition: if true, get the definition + * @error: set on failure + * + * Given a virtual method associated with a subclass, return the corresponding + * method from an ancestor. If @definition is FALSE, returns the method in the + * superclass of the given method. If @definition is TRUE, return the method + * in the ancestor class where it was first declared. The type arguments will + * be inflated in the ancestor classes. If the method is not associated with a + * class, or isn't virtual, returns the method itself. On failure returns NULL + * and sets @error. + */ +MonoMethod* +mono_method_get_base_method (MonoMethod *method, gboolean definition, MonoError *error) +{ + MonoClass *klass, *parent; + MonoGenericContext *generic_inst = NULL; + MonoMethod *result = NULL; + int slot; + + if (method->klass == NULL) + return method; + + if (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || + MONO_CLASS_IS_INTERFACE (method->klass) || + method->flags & METHOD_ATTRIBUTE_NEW_SLOT) + return method; + + slot = mono_method_get_vtable_slot (method); + if (slot == -1) + return method; + + klass = method->klass; + if (mono_class_is_ginst (klass)) { + generic_inst = mono_class_get_context (klass); + klass = mono_class_get_generic_class (klass)->container_class; + } + +retry: + if (definition) { + /* At the end of the loop, klass points to the eldest class that has this virtual function slot. */ + for (parent = klass->parent; parent != NULL; parent = parent->parent) { + /* on entry, klass is either a plain old non-generic class and generic_inst == NULL + or klass is the generic container class and generic_inst is the instantiation. + + when we go to the parent, if the parent is an open constructed type, we need to + replace the type parameters by the definitions from the generic_inst, and then take it + apart again into the klass and the generic_inst. + + For cases like this: + class C : B { + public override void Foo () { ... } + } + class B : A> { + public override void Foo () { ... } + } + class A { + public virtual void Foo () { ... } + } + + if at each iteration the parent isn't open, we can skip inflating it. if at some + iteration the parent isn't generic (after possible inflation), we set generic_inst to + NULL; + */ + MonoGenericContext *parent_inst = NULL; + if (mono_class_is_open_constructed_type (mono_class_get_type (parent))) { + parent = mono_class_inflate_generic_class_checked (parent, generic_inst, error); + return_val_if_nok (error, NULL); + } + if (mono_class_is_ginst (parent)) { + parent_inst = mono_class_get_context (parent); + parent = mono_class_get_generic_class (parent)->container_class; + } + + mono_class_setup_vtable (parent); + if (parent->vtable_size <= slot) + break; + klass = parent; + generic_inst = parent_inst; + } + } else { + klass = klass->parent; + if (!klass) + return method; + if (mono_class_is_open_constructed_type (mono_class_get_type (klass))) { + klass = mono_class_inflate_generic_class_checked (klass, generic_inst, error); + return_val_if_nok (error, NULL); + + generic_inst = NULL; + } + if (mono_class_is_ginst (klass)) { + generic_inst = mono_class_get_context (klass); + klass = mono_class_get_generic_class (klass)->container_class; + } + + } + + if (generic_inst) { + klass = mono_class_inflate_generic_class_checked (klass, generic_inst, error); + return_val_if_nok (error, NULL); + } + + if (klass == method->klass) + return method; + + /*This is possible if definition == FALSE. + * Do it here to be really sure we don't read invalid memory. + */ + if (slot >= klass->vtable_size) + return method; + + mono_class_setup_vtable (klass); + + result = klass->vtable [slot]; + if (result == NULL) { + /* It is an abstract method */ + gboolean found = FALSE; + gpointer iter = NULL; + while ((result = mono_class_get_methods (klass, &iter))) { + if (result->slot == slot) { + found = TRUE; + break; + } + } + /* found might be FALSE if we looked in an abstract class + * that doesn't override an abstract method of its + * parent: + * abstract class Base { + * public abstract void Foo (); + * } + * abstract class Derived : Base { } + * class Child : Derived { + * public override void Foo () { } + * } + * + * if m was Child.Foo and we ask for the base method, + * then we get here with klass == Derived and found == FALSE + */ + /* but it shouldn't be the case that if we're looking + * for the definition and didn't find a result; the + * loop above should've taken us as far as we could + * go! */ + g_assert (!(definition && !found)); + if (!found) + goto retry; + } + + g_assert (result != NULL); + return result; +} diff --git a/mono/metadata/icall-def.h b/mono/metadata/icall-def.h index 189d6f57fae..e6ec1e4a21d 100644 --- a/mono/metadata/icall-def.h +++ b/mono/metadata/icall-def.h @@ -599,9 +599,9 @@ HANDLES(ICALL(MODULE_12, "ResolveTypeToken", ves_icall_System_Reflection_Module_ HANDLES(ICALL(MODULE_13, "get_MetadataToken", ves_icall_reflection_get_token)) ICALL_TYPE(MCMETH, "System.Reflection.MonoCMethod", MCMETH_1) -ICALL(MCMETH_1, "GetGenericMethodDefinition_impl", ves_icall_MonoMethod_GetGenericMethodDefinition) +HANDLES(ICALL(MCMETH_1, "GetGenericMethodDefinition_impl", ves_icall_MonoMethod_GetGenericMethodDefinition)) ICALL(MCMETH_2, "InternalInvoke", ves_icall_InternalInvoke) -ICALL(MCMETH_3, "get_core_clr_security_level", ves_icall_MonoMethod_get_core_clr_security_level) +HANDLES(ICALL(MCMETH_3, "get_core_clr_security_level", ves_icall_MonoMethod_get_core_clr_security_level)) ICALL_TYPE(MEVIN, "System.Reflection.MonoEventInfo", MEVIN_1) ICALL(MEVIN_1, "get_event_info", ves_icall_MonoEventInfo_get_event_info) @@ -616,16 +616,16 @@ ICALL(MFIELD_4, "SetValueInternal", ves_icall_MonoField_SetValueInternal) ICALL(MFIELD_7, "get_core_clr_security_level", ves_icall_MonoField_get_core_clr_security_level) ICALL_TYPE(MMETH, "System.Reflection.MonoMethod", MMETH_2) -ICALL(MMETH_2, "GetGenericArguments", ves_icall_MonoMethod_GetGenericArguments) -ICALL(MMETH_3, "GetGenericMethodDefinition_impl", ves_icall_MonoMethod_GetGenericMethodDefinition) -ICALL(MMETH_11, "GetPInvoke", ves_icall_MonoMethod_GetPInvoke) +HANDLES(ICALL(MMETH_2, "GetGenericArguments", ves_icall_MonoMethod_GetGenericArguments)) +HANDLES(ICALL(MMETH_3, "GetGenericMethodDefinition_impl", ves_icall_MonoMethod_GetGenericMethodDefinition)) +HANDLES(ICALL(MMETH_11, "GetPInvoke", ves_icall_MonoMethod_GetPInvoke)) ICALL(MMETH_4, "InternalInvoke", ves_icall_InternalInvoke) -ICALL(MMETH_5, "MakeGenericMethod_impl", ves_icall_MonoMethod_MakeGenericMethod_impl) -ICALL(MMETH_6, "get_IsGenericMethod", ves_icall_MonoMethod_get_IsGenericMethod) -ICALL(MMETH_7, "get_IsGenericMethodDefinition", ves_icall_MonoMethod_get_IsGenericMethodDefinition) -ICALL(MMETH_8, "get_base_method", ves_icall_MonoMethod_get_base_method) -ICALL(MMETH_10, "get_core_clr_security_level", ves_icall_MonoMethod_get_core_clr_security_level) -ICALL(MMETH_9, "get_name", ves_icall_MonoMethod_get_name) +HANDLES(ICALL(MMETH_5, "MakeGenericMethod_impl", ves_icall_MonoMethod_MakeGenericMethod_impl)) +HANDLES(ICALL(MMETH_6, "get_IsGenericMethod", ves_icall_MonoMethod_get_IsGenericMethod)) +HANDLES(ICALL(MMETH_7, "get_IsGenericMethodDefinition", ves_icall_MonoMethod_get_IsGenericMethodDefinition)) +HANDLES(ICALL(MMETH_8, "get_base_method", ves_icall_MonoMethod_get_base_method)) +HANDLES(ICALL(MMETH_10, "get_core_clr_security_level", ves_icall_MonoMethod_get_core_clr_security_level)) +HANDLES(ICALL(MMETH_9, "get_name", ves_icall_MonoMethod_get_name)) ICALL_TYPE(MMETHI, "System.Reflection.MonoMethodInfo", MMETHI_4) ICALL(MMETHI_4, "get_method_attributes", vell_icall_get_method_attributes) diff --git a/mono/metadata/icall.c b/mono/metadata/icall.c index 772483e99dc..b798a6e7c29 100644 --- a/mono/metadata/icall.c +++ b/mono/metadata/icall.c @@ -2965,11 +2965,12 @@ ves_icall_System_RuntimeType_IsWindowsRuntimeObjectType (MonoError *error) } ICALL_EXPORT void -ves_icall_MonoMethod_GetPInvoke (MonoReflectionMethod *method, int* flags, MonoString** entry_point, MonoString** dll_name) +ves_icall_MonoMethod_GetPInvoke (MonoReflectionMethodHandle ref_method, int* flags, MonoStringHandleOut entry_point, MonoStringHandleOut dll_name, MonoError *error) { MonoDomain *domain = mono_domain_get (); - MonoImage *image = method->method->klass->image; - MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method->method; + MonoMethod *method = MONO_HANDLE_GETVAL (ref_method, method); + MonoImage *image = method->klass->image; + MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method; MonoTableInfo *tables = image->tables; MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP]; MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF]; @@ -2978,16 +2979,18 @@ ves_icall_MonoMethod_GetPInvoke (MonoReflectionMethod *method, int* flags, MonoS const char *import = NULL; const char *scope = NULL; + mono_error_init (error); + if (image_is_dynamic (image)) { MonoReflectionMethodAux *method_aux = - (MonoReflectionMethodAux *)g_hash_table_lookup (((MonoDynamicImage*)image)->method_aux_hash, method->method); + (MonoReflectionMethodAux *)g_hash_table_lookup (((MonoDynamicImage*)image)->method_aux_hash, method); if (method_aux) { import = method_aux->dllentry; scope = method_aux->dll; } if (!import || !scope) { - mono_set_pending_exception (mono_get_exception_argument ("method", "System.Reflection.Emit method with invalid pinvoke information")); + mono_error_set_argument (error, "method", "System.Refleciton.Emit method with invalid pinvoke information"); return; } } @@ -3003,44 +3006,42 @@ ves_icall_MonoMethod_GetPInvoke (MonoReflectionMethod *method, int* flags, MonoS } *flags = piinfo->piflags; - *entry_point = mono_string_new (domain, import); - *dll_name = mono_string_new (domain, scope); + MONO_HANDLE_ASSIGN (entry_point, mono_string_new_handle (domain, import, error)); + return_if_nok (error); + MONO_HANDLE_ASSIGN (dll_name, mono_string_new_handle (domain, scope, error)); } -ICALL_EXPORT MonoReflectionMethod * -ves_icall_MonoMethod_GetGenericMethodDefinition (MonoReflectionMethod *method) +ICALL_EXPORT MonoReflectionMethodHandle +ves_icall_MonoMethod_GetGenericMethodDefinition (MonoReflectionMethodHandle ref_method, MonoError *error) { - MonoMethodInflated *imethod; - MonoMethod *result; - MonoReflectionMethod *ret = NULL; - MonoError error; + mono_error_init (error); + MonoMethod *method = MONO_HANDLE_GETVAL (ref_method, method); - if (method->method->is_generic) - return method; + if (method->is_generic) + return ref_method; - if (!method->method->is_inflated) - return NULL; + if (!method->is_inflated) + return MONO_HANDLE_CAST (MonoReflectionMethod, NULL_HANDLE); - imethod = (MonoMethodInflated *) method->method; + MonoMethodInflated *imethod = (MonoMethodInflated *) method; - result = imethod->declaring; + MonoMethod *result = imethod->declaring; /* Not a generic method. */ if (!result->is_generic) - return NULL; + return MONO_HANDLE_CAST (MonoReflectionMethod, NULL_HANDLE); - if (image_is_dynamic (method->method->klass->image)) { - MonoDynamicImage *image = (MonoDynamicImage*)method->method->klass->image; - MonoReflectionMethod *res; + if (image_is_dynamic (method->klass->image)) { + MonoDynamicImage *image = (MonoDynamicImage*)method->klass->image; /* * FIXME: Why is this stuff needed at all ? Why can't the code below work for * the dynamic case as well ? */ mono_image_lock ((MonoImage*)image); - res = (MonoReflectionMethod *)mono_g_hash_table_lookup (image->generic_def_objects, imethod); + MonoReflectionMethodHandle res = MONO_HANDLE_NEW (MonoReflectionMethod, mono_g_hash_table_lookup (image->generic_def_objects, imethod)); mono_image_unlock ((MonoImage*)image); - if (res) + if (!MONO_HANDLE_IS_NULL (res)) return res; } @@ -3048,80 +3049,90 @@ ves_icall_MonoMethod_GetGenericMethodDefinition (MonoReflectionMethod *method) MonoClass *klass = ((MonoMethod *) imethod)->klass; /*Generic methods gets the context of the GTD.*/ if (mono_class_get_context (klass)) { - result = mono_class_inflate_generic_method_full_checked (result, klass, mono_class_get_context (klass), &error); - if (!mono_error_ok (&error)) - goto leave; + result = mono_class_inflate_generic_method_full_checked (result, klass, mono_class_get_context (klass), error); + return_val_if_nok (error, MONO_HANDLE_CAST (MonoReflectionMethod, NULL_HANDLE)); } } - ret = mono_method_get_object_checked (mono_object_domain (method), result, NULL, &error); -leave: - if (!mono_error_ok (&error)) - mono_error_set_pending_exception (&error); - return ret; + return mono_method_get_object_handle (MONO_HANDLE_DOMAIN (ref_method), result, NULL, error); } ICALL_EXPORT gboolean -ves_icall_MonoMethod_get_IsGenericMethod (MonoReflectionMethod *method) +ves_icall_MonoMethod_get_IsGenericMethod (MonoReflectionMethodHandle ref_method, MonoError *erro) { - return mono_method_signature (method->method)->generic_param_count != 0; + MonoMethod *method = MONO_HANDLE_GETVAL (ref_method, method); + return mono_method_signature (method)->generic_param_count != 0; } ICALL_EXPORT gboolean -ves_icall_MonoMethod_get_IsGenericMethodDefinition (MonoReflectionMethod *method) +ves_icall_MonoMethod_get_IsGenericMethodDefinition (MonoReflectionMethodHandle ref_method, MonoError *Error) { - return method->method->is_generic; + MonoMethod *method = MONO_HANDLE_GETVAL (ref_method, method); + return method->is_generic; } -ICALL_EXPORT MonoArray* -ves_icall_MonoMethod_GetGenericArguments (MonoReflectionMethod *method) +static gboolean +set_array_generic_argument_handle_inflated (MonoDomain *domain, MonoGenericInst *inst, int i, MonoArrayHandle arr, MonoError *error) { - MonoError error; - MonoReflectionType *rt; - MonoArray *res; - MonoDomain *domain; - int count, i; + HANDLE_FUNCTION_ENTER (); + mono_error_init (error); + MonoReflectionTypeHandle rt = mono_type_get_object_handle (domain, inst->type_argv [i], error); + if (!is_ok (error)) + goto leave; + MONO_HANDLE_ARRAY_SETREF (arr, i, rt); +leave: + HANDLE_FUNCTION_RETURN_VAL (is_ok (error)); +} + +static gboolean +set_array_generic_argument_handle_gparam (MonoDomain *domain, MonoGenericContainer *container, int i, MonoArrayHandle arr, MonoError *error) +{ + HANDLE_FUNCTION_ENTER (); + mono_error_init (error); + MonoGenericParam *param = mono_generic_container_get_param (container, i); + MonoClass *pklass = mono_class_from_generic_parameter_internal (param); + MonoReflectionTypeHandle rt = mono_type_get_object_handle (domain, &pklass->byval_arg, error); + if (!is_ok (error)) + goto leave; + MONO_HANDLE_ARRAY_SETREF (arr, i, rt); +leave: + HANDLE_FUNCTION_RETURN_VAL (is_ok (error)); +} - domain = mono_object_domain (method); +ICALL_EXPORT MonoArrayHandle +ves_icall_MonoMethod_GetGenericArguments (MonoReflectionMethodHandle ref_method, MonoError *error) +{ + mono_error_init (error); + MonoDomain *domain = MONO_HANDLE_DOMAIN (ref_method); + MonoMethod *method = MONO_HANDLE_GETVAL (ref_method, method); - if (method->method->is_inflated) { - MonoGenericInst *inst = mono_method_get_context (method->method)->method_inst; + if (method->is_inflated) { + MonoGenericInst *inst = mono_method_get_context (method)->method_inst; if (inst) { - count = inst->type_argc; - res = mono_array_new_checked (domain, mono_defaults.systemtype_class, count, &error); - if (mono_error_set_pending_exception (&error)) - return NULL; - - for (i = 0; i < count; i++) { - rt = mono_type_get_object_checked (domain, inst->type_argv [i], &error); - if (mono_error_set_pending_exception (&error)) - return NULL; + int count = inst->type_argc; + MonoArrayHandle res = mono_array_new_handle (domain, mono_defaults.systemtype_class, count, error); + return_val_if_nok (error, MONO_HANDLE_CAST (MonoArray, NULL_HANDLE)); - mono_array_setref (res, i, rt); + for (int i = 0; i < count; i++) { + if (!set_array_generic_argument_handle_inflated (domain, inst, i, res, error)) + break; } - + return_val_if_nok (error, MONO_HANDLE_CAST (MonoArray, NULL_HANDLE)); return res; } } - count = mono_method_signature (method->method)->generic_param_count; - res = mono_array_new_checked (domain, mono_defaults.systemtype_class, count, &error); - if (mono_error_set_pending_exception (&error)) - return NULL; - - for (i = 0; i < count; i++) { - MonoGenericContainer *container = mono_method_get_generic_container (method->method); - MonoGenericParam *param = mono_generic_container_get_param (container, i); - MonoClass *pklass = mono_class_from_generic_parameter_internal (param); - - rt = mono_type_get_object_checked (domain, &pklass->byval_arg, &error); - if (mono_error_set_pending_exception (&error)) - return NULL; + int count = mono_method_signature (method)->generic_param_count; + MonoArrayHandle res = mono_array_new_handle (domain, mono_defaults.systemtype_class, count, error); + return_val_if_nok (error, MONO_HANDLE_CAST (MonoArray, NULL_HANDLE)); - mono_array_setref (res, i, rt); + MonoGenericContainer *container = mono_method_get_generic_container (method); + for (int i = 0; i < count; i++) { + if (!set_array_generic_argument_handle_gparam (domain, container, i, res, error)) + break; } - + return_val_if_nok (error, MONO_HANDLE_CAST (MonoArray, NULL_HANDLE)); return res; } @@ -5236,9 +5247,10 @@ ves_icall_MonoField_get_core_clr_security_level (MonoReflectionField *rfield) } ICALL_EXPORT int -ves_icall_MonoMethod_get_core_clr_security_level (MonoReflectionMethod *rfield) +ves_icall_MonoMethod_get_core_clr_security_level (MonoReflectionMethodHandle rfield, MonoError *error) { - MonoMethod *method = rfield->method; + mono_error_init (error); + MonoMethod *method = MONO_HANDLE_GETVAL (rfield, method); return mono_security_core_clr_method_level (method, TRUE); } @@ -7257,168 +7269,31 @@ ves_icall_System_Activator_CreateInstanceInternal (MonoReflectionTypeHandle ref_ return MONO_HANDLE_NEW (MonoObject, mono_object_new_checked (domain, klass, error)); } -ICALL_EXPORT MonoReflectionMethod * -ves_icall_MonoMethod_get_base_method (MonoReflectionMethod *m, gboolean definition) +ICALL_EXPORT MonoReflectionMethodHandle +ves_icall_MonoMethod_get_base_method (MonoReflectionMethodHandle m, gboolean definition, MonoError *error) { - MonoReflectionMethod *ret = NULL; - MonoError error; - - MonoClass *klass, *parent; - MonoGenericContext *generic_inst = NULL; - MonoMethod *method = m->method; - MonoMethod *result = NULL; - int slot; - - if (method->klass == NULL) - return m; - - if (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || - MONO_CLASS_IS_INTERFACE (method->klass) || - method->flags & METHOD_ATTRIBUTE_NEW_SLOT) - return m; - - slot = mono_method_get_vtable_slot (method); - if (slot == -1) - return m; - - klass = method->klass; - if (mono_class_is_ginst (klass)) { - generic_inst = mono_class_get_context (klass); - klass = mono_class_get_generic_class (klass)->container_class; - } - -retry: - if (definition) { - /* At the end of the loop, klass points to the eldest class that has this virtual function slot. */ - for (parent = klass->parent; parent != NULL; parent = parent->parent) { - /* on entry, klass is either a plain old non-generic class and generic_inst == NULL - or klass is the generic container class and generic_inst is the instantiation. - - when we go to the parent, if the parent is an open constructed type, we need to - replace the type parameters by the definitions from the generic_inst, and then take it - apart again into the klass and the generic_inst. - - For cases like this: - class C : B { - public override void Foo () { ... } - } - class B : A> { - public override void Foo () { ... } - } - class A { - public virtual void Foo () { ... } - } - - if at each iteration the parent isn't open, we can skip inflating it. if at some - iteration the parent isn't generic (after possible inflation), we set generic_inst to - NULL; - */ - MonoGenericContext *parent_inst = NULL; - if (mono_class_is_open_constructed_type (mono_class_get_type (parent))) { - parent = mono_class_inflate_generic_class_checked (parent, generic_inst, &error); - if (!mono_error_ok (&error)) { - mono_error_set_pending_exception (&error); - return NULL; - } - } - if (mono_class_is_ginst (parent)) { - parent_inst = mono_class_get_context (parent); - parent = mono_class_get_generic_class (parent)->container_class; - } - - mono_class_setup_vtable (parent); - if (parent->vtable_size <= slot) - break; - klass = parent; - generic_inst = parent_inst; - } - } else { - klass = klass->parent; - if (!klass) - return m; - if (mono_class_is_open_constructed_type (mono_class_get_type (klass))) { - klass = mono_class_inflate_generic_class_checked (klass, generic_inst, &error); - if (!mono_error_ok (&error)) { - mono_error_set_pending_exception (&error); - return NULL; - } - - generic_inst = NULL; - } - if (mono_class_is_ginst (klass)) { - generic_inst = mono_class_get_context (klass); - klass = mono_class_get_generic_class (klass)->container_class; - } - - } - - if (generic_inst) { - klass = mono_class_inflate_generic_class_checked (klass, generic_inst, &error); - if (!mono_error_ok (&error)) { - mono_error_set_pending_exception (&error); - return NULL; - } - } - - if (klass == method->klass) - return m; + mono_error_init (error); + MonoMethod *method = MONO_HANDLE_GETVAL (m, method); - /*This is possible if definition == FALSE. - * Do it here to be really sure we don't read invalid memory. - */ - if (slot >= klass->vtable_size) + MonoMethod *base = mono_method_get_base_method (method, definition, error); + return_val_if_nok (error, MONO_HANDLE_CAST (MonoReflectionMethod, NULL_HANDLE)); + if (base == method) return m; - - mono_class_setup_vtable (klass); - - result = klass->vtable [slot]; - if (result == NULL) { - /* It is an abstract method */ - gboolean found = FALSE; - gpointer iter = NULL; - while ((result = mono_class_get_methods (klass, &iter))) { - if (result->slot == slot) { - found = TRUE; - break; - } - } - /* found might be FALSE if we looked in an abstract class - * that doesn't override an abstract method of its - * parent: - * abstract class Base { - * public abstract void Foo (); - * } - * abstract class Derived : Base { } - * class Child : Derived { - * public override void Foo () { } - * } - * - * if m was Child.Foo and we ask for the base method, - * then we get here with klass == Derived and found == FALSE - */ - /* but it shouldn't be the case that if we're looking - * for the definition and didn't find a result; the - * loop above should've taken us as far as we could - * go! */ - g_assert (!(definition && !found)); - if (!found) - goto retry; - } - - g_assert (result != NULL); - - ret = mono_method_get_object_checked (mono_domain_get (), result, NULL, &error); - mono_error_set_pending_exception (&error); - return ret; + else + return mono_method_get_object_handle (mono_domain_get (), base, NULL, error); } -ICALL_EXPORT MonoString* -ves_icall_MonoMethod_get_name (MonoReflectionMethod *m) +ICALL_EXPORT MonoStringHandle +ves_icall_MonoMethod_get_name (MonoReflectionMethodHandle m, MonoError *error) { - MonoMethod *method = m->method; + mono_error_init (error); + MonoMethod *method = MONO_HANDLE_GETVAL (m, method); - MONO_OBJECT_SETREF (m, name, mono_string_new (mono_object_domain (m), method->name)); - return m->name; + MonoStringHandle s = mono_string_new_handle (MONO_HANDLE_DOMAIN (m), method->name, error); + if (!is_ok (error)) + return NULL_HANDLE_STRING; + MONO_HANDLE_SET (m, name, s); + return s; } ICALL_EXPORT void diff --git a/mono/metadata/object-internals.h b/mono/metadata/object-internals.h index 8cd694f24f8..67a185e07fa 100644 --- a/mono/metadata/object-internals.h +++ b/mono/metadata/object-internals.h @@ -1837,8 +1837,8 @@ mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError * int mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc); -MonoReflectionMethod* -ves_icall_MonoMethod_MakeGenericMethod_impl (MonoReflectionMethod *rmethod, MonoArray *types); +MonoReflectionMethodHandle +ves_icall_MonoMethod_MakeGenericMethod_impl (MonoReflectionMethodHandle rmethod, MonoArrayHandle types, MonoError *error); gint32 ves_icall_ModuleBuilder_getToken (MonoReflectionModuleBuilderHandle mb, MonoObjectHandle obj, gboolean create_open_instance, MonoError *error); diff --git a/mono/metadata/reflection.c b/mono/metadata/reflection.c index fc88d2b7f55..c6d637cb61c 100644 --- a/mono/metadata/reflection.c +++ b/mono/metadata/reflection.c @@ -2442,50 +2442,74 @@ mono_class_bind_generic_parameters (MonoClass *klass, int type_argc, MonoType ** return mono_generic_class_get_class (gclass); } -static MonoReflectionMethod* -reflection_bind_generic_method_parameters (MonoReflectionMethod *rmethod, MonoArray *types, MonoError *error) +static MonoGenericInst* +generic_inst_from_type_array_handle (MonoArrayHandle types, MonoError *error) +{ + HANDLE_FUNCTION_ENTER (); + mono_error_init (error); + MonoGenericInst *ginst = NULL; + int count = mono_array_handle_length (types); + MonoType **type_argv = g_new0 (MonoType *, count); + MonoReflectionTypeHandle garg = MONO_HANDLE_NEW (MonoReflectionType, NULL); + for (int i = 0; i < count; i++) { + MONO_HANDLE_ARRAY_GETREF (garg, types, i); + type_argv [i] = mono_reflection_type_handle_mono_type (garg, error); + if (!is_ok (error)) + goto leave; + + } + ginst = mono_metadata_get_generic_inst (count, type_argv); +leave: + g_free (type_argv); + HANDLE_FUNCTION_RETURN_VAL (ginst); +} + +static MonoMethod* +reflection_bind_generic_method_parameters (MonoMethod *method, MonoArrayHandle types, MonoError *error) { MonoClass *klass; - MonoMethod *method, *inflated; - MonoMethodInflated *imethod; + MonoMethod *inflated; MonoGenericContext tmp_context; - MonoGenericInst *ginst; - MonoType **type_argv; - int count, i; mono_error_init (error); - g_assert (strcmp (rmethod->object.vtable->klass->name, "MethodBuilder")); - - method = rmethod->method; - klass = method->klass; if (method->is_inflated) method = ((MonoMethodInflated *) method)->declaring; - count = mono_method_signature (method)->generic_param_count; - if (count != mono_array_length (types)) + int count = mono_method_signature (method)->generic_param_count; + if (count != mono_array_handle_length (types)) { + mono_error_set_argument (error, "typeArguments", "Incorrect number of generic arguments"); return NULL; - - type_argv = g_new0 (MonoType *, count); - for (i = 0; i < count; i++) { - MonoReflectionType *garg = (MonoReflectionType *)mono_array_get (types, gpointer, i); - type_argv [i] = mono_reflection_type_get_handle (garg, error); - if (!is_ok (error)) { - g_free (type_argv); - return NULL; - } } - ginst = mono_metadata_get_generic_inst (count, type_argv); - g_free (type_argv); + + MonoGenericInst *ginst = generic_inst_from_type_array_handle (types, error); + return_val_if_nok (error, NULL); tmp_context.class_inst = mono_class_is_ginst (klass) ? mono_class_get_generic_class (klass)->context.class_inst : NULL; tmp_context.method_inst = ginst; inflated = mono_class_inflate_generic_method_checked (method, &tmp_context, error); mono_error_assert_ok (error); - imethod = (MonoMethodInflated *) inflated; + + if (!mono_verifier_is_method_valid_generic_instantiation (inflated)) { + mono_error_set_argument (error, "typeArguments", "Invalid generic arguments"); + return NULL; + } + + return inflated; +} + +MonoReflectionMethodHandle +ves_icall_MonoMethod_MakeGenericMethod_impl (MonoReflectionMethodHandle rmethod, MonoArrayHandle types, MonoError *error) +{ + mono_error_init (error); + g_assert (0 != strcmp (mono_handle_class (rmethod)->name, "MethodBuilder")); + + MonoMethod *method = MONO_HANDLE_GETVAL (rmethod, method); + MonoMethod *imethod = reflection_bind_generic_method_parameters (method, types, error); + return_val_if_nok (error, MONO_HANDLE_CAST (MonoReflectionMethod, NULL_HANDLE)); /*FIXME but I think this is no longer necessary*/ if (image_is_dynamic (method->klass->image)) { @@ -2495,25 +2519,11 @@ reflection_bind_generic_method_parameters (MonoReflectionMethod *rmethod, MonoAr * to the reflection objects representing their generic definitions. */ mono_image_lock ((MonoImage*)image); - mono_g_hash_table_insert (image->generic_def_objects, imethod, rmethod); + mono_g_hash_table_insert (image->generic_def_objects, imethod, MONO_HANDLE_RAW (rmethod)); mono_image_unlock ((MonoImage*)image); } - if (!mono_verifier_is_method_valid_generic_instantiation (inflated)) { - mono_error_set_argument (error, "typeArguments", "Invalid generic arguments"); - return NULL; - } - - return mono_method_get_object_checked (mono_object_domain (rmethod), inflated, NULL, error); -} - -MonoReflectionMethod* -ves_icall_MonoMethod_MakeGenericMethod_impl (MonoReflectionMethod *rmethod, MonoArray *types) -{ - MonoError error; - MonoReflectionMethod *result = reflection_bind_generic_method_parameters (rmethod, types, &error); - mono_error_set_pending_exception (&error); - return result; + return mono_method_get_object_handle (MONO_HANDLE_DOMAIN (rmethod), imethod, NULL, error); } -- 2.25.1