[reflection] Use coop handles for MonoMethod icalls (#4272)
authorAleksey Kliger (λgeek) <akliger@gmail.com>
Fri, 20 Jan 2017 15:35:02 +0000 (10:35 -0500)
committerGitHub <noreply@github.com>
Fri, 20 Jan 2017 15:35:02 +0000 (10:35 -0500)
* [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
mono/metadata/class.c
mono/metadata/icall-def.h
mono/metadata/icall.c
mono/metadata/object-internals.h
mono/metadata/reflection.c

index 57a9a145e9f33a3dbaafe88b7de97d0e148785c6..5ae0374e89a682a275d57d3241b231a49dc9ee39 100644 (file)
@@ -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);
 
index fd9f2e9898754d2026bc2bfaec4265738ec08b14..4cf5fcf45754804080565adb1ab40e4b2f8c377e 100644 (file)
@@ -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<T> : B<T, int> {
+                              public override void Foo () { ... }
+                          }
+                          class B<U,V> : A<HashMap<U,V>> {
+                              public override void Foo () { ... }
+                          }
+                          class A<X> {
+                              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;
+}
index 189d6f57fae4a8239f99f03d4d3554ac9fa9e559..e6ec1e4a21d9e779e68c13cabd595e669a6c796a 100644 (file)
@@ -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)
index 772483e99dcb5082c7aa2eb1a2813d79918eed63..b798a6e7c29f7b328ee0a02ac9c906587f9b07a1 100644 (file)
@@ -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<T> : B<T, int> {
-                              public override void Foo () { ... }
-                          }
-                          class B<U,V> : A<HashMap<U,V>> {
-                              public override void Foo () { ... }
-                          }
-                          class A<X> {
-                              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
index 8cd694f24f845c4d8019bbb0254c490517ed150a..67a185e07fa7565497e266f7cdcac2fe40df8220 100644 (file)
@@ -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);
index fc88d2b7f55c18c22dce1cc84247aa8e7c765c3a..c6d637cb61c16ed0a280a1152fba4cc17f9dd623 100644 (file)
@@ -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);
 }