Merge pull request #3320 from lambdageek/dev/reflection-in-managed
authorAleksey Kliger (λgeek) <akliger@gmail.com>
Fri, 29 Jul 2016 20:05:32 +0000 (16:05 -0400)
committerGitHub <noreply@github.com>
Fri, 29 Jul 2016 20:05:32 +0000 (16:05 -0400)
[reflection] Marshal name strings from managed

mcs/class/corlib/Mono/SafeStringMarshal.cs [new file with mode: 0644]
mcs/class/corlib/ReferenceSources/RuntimeType.cs
mcs/class/corlib/corlib.dll.sources
mono/metadata/icall-def.h
mono/metadata/icall.c

diff --git a/mcs/class/corlib/Mono/SafeStringMarshal.cs b/mcs/class/corlib/Mono/SafeStringMarshal.cs
new file mode 100644 (file)
index 0000000..c18f0d3
--- /dev/null
@@ -0,0 +1,46 @@
+//
+// Safe wrapper for a string and its UTF8 encoding
+//
+// Authors:
+//   Aleksey Kliger <aleksey@xamarin.com>
+//   Rodrigo Kumpera <kumpera@xamarin.com>
+//
+// Copyright 2016 Dot net foundation.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Runtime.CompilerServices;
+
+namespace Mono  {
+       internal struct SafeStringMarshal : IDisposable {
+               readonly string str;
+               IntPtr marshaled_string;
+
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               public extern static IntPtr StringToUtf8 (string str);
+
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               public extern static void GFree (IntPtr ptr);
+
+               public SafeStringMarshal (string str) {
+                       this.str = str;
+                       this.marshaled_string = IntPtr.Zero;
+               }
+
+               public IntPtr Value {
+                       get {
+                               if (marshaled_string == IntPtr.Zero && str != null)
+                                       marshaled_string = StringToUtf8 (str);
+                               return marshaled_string;
+                       }
+               }
+
+               public void Dispose () {
+                       if (marshaled_string != IntPtr.Zero) {
+                               GFree (marshaled_string);
+                               marshaled_string = IntPtr.Zero;
+                       }
+               }
+       }
+}
index 189ad1dc7fd9ce7f2ffb617ae904c662f898cef1..8a49451936e5fd80e95e17913a2a3025084c5f7d 100644 (file)
@@ -472,12 +472,13 @@ namespace System
                static extern Type MakeGenericType (Type gt, Type [] types);
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               internal extern IntPtr GetMethodsByName_native (string name, BindingFlags bindingAttr, bool ignoreCase);
+               internal extern IntPtr GetMethodsByName_native (IntPtr namePtr, BindingFlags bindingAttr, bool ignoreCase);
 
                internal RuntimeMethodInfo[] GetMethodsByName (string name, BindingFlags bindingAttr, bool ignoreCase, RuntimeType reflectedType)
                {
                        var refh = new RuntimeTypeHandle (reflectedType);
-                       using (var h = new Mono.SafeGPtrArrayHandle (GetMethodsByName_native (name, bindingAttr, ignoreCase))) {
+                       using (var namePtr = new Mono.SafeStringMarshal (name))
+                       using (var h = new Mono.SafeGPtrArrayHandle (GetMethodsByName_native (namePtr.Value, bindingAttr, ignoreCase))) {
                                var n = h.Length;
                                var a = new RuntimeMethodInfo [n];
                                for (int i = 0; i < n; i++) {
@@ -489,7 +490,7 @@ namespace System
                }
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               extern IntPtr GetPropertiesByName_native (string name, BindingFlags bindingAttr, bool icase);           
+               extern IntPtr GetPropertiesByName_native (IntPtr name, BindingFlags bindingAttr, bool icase);           
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                extern IntPtr GetConstructors_native (BindingFlags bindingAttr);
@@ -511,7 +512,8 @@ namespace System
                RuntimePropertyInfo[] GetPropertiesByName (string name, BindingFlags bindingAttr, bool icase, RuntimeType reflectedType)
                {
                        var refh = new RuntimeTypeHandle (reflectedType);
-                       using (var h = new Mono.SafeGPtrArrayHandle (GetPropertiesByName_native (name, bindingAttr, icase))) {
+                       using (var namePtr = new Mono.SafeStringMarshal (name))
+                       using (var h = new Mono.SafeGPtrArrayHandle (GetPropertiesByName_native (namePtr.Value, bindingAttr, icase))) {
                                var n = h.Length;
                                var a = new RuntimePropertyInfo [n];
                                for (int i = 0; i < n; i++) {
@@ -669,15 +671,16 @@ namespace System
                extern int GetGenericParameterPosition ();
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               extern IntPtr GetEvents_native (string name, BindingFlags bindingAttr);
+               extern IntPtr GetEvents_native (IntPtr name, BindingFlags bindingAttr);
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               extern IntPtr GetFields_native (string name, BindingFlags bindingAttr);
+               extern IntPtr GetFields_native (IntPtr name, BindingFlags bindingAttr);
 
                RuntimeFieldInfo[] GetFields_internal (string name, BindingFlags bindingAttr, RuntimeType reflectedType)
                {
                        var refh = new RuntimeTypeHandle (reflectedType);
-                       using (var h = new Mono.SafeGPtrArrayHandle (GetFields_native (name, bindingAttr))) {
+                       using (var namePtr = new Mono.SafeStringMarshal (name))
+                       using (var h = new Mono.SafeGPtrArrayHandle (GetFields_native (namePtr.Value, bindingAttr))) {
                                int n = h.Length;
                                var a = new RuntimeFieldInfo[n];
                                for (int i = 0; i < n; i++) {
@@ -691,7 +694,8 @@ namespace System
                RuntimeEventInfo[] GetEvents_internal (string name, BindingFlags bindingAttr, RuntimeType reflectedType)
                {
                        var refh = new RuntimeTypeHandle (reflectedType);
-                       using (var h = new Mono.SafeGPtrArrayHandle (GetEvents_native (name, bindingAttr))) {
+                       using (var namePtr = new Mono.SafeStringMarshal (name))
+                       using (var h = new Mono.SafeGPtrArrayHandle (GetEvents_native (namePtr.Value, bindingAttr))) {
                                int n = h.Length;
                                var a = new RuntimeEventInfo[n];
                                for (int i = 0; i < n; i++) {
@@ -706,7 +710,24 @@ namespace System
                public extern override Type[] GetInterfaces();
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               extern RuntimeType[] GetNestedTypes_internal (string name, BindingFlags bindingAttr);           
+               extern IntPtr GetNestedTypes_native (IntPtr name, BindingFlags bindingAttr);
+
+               RuntimeType[] GetNestedTypes_internal (string displayName, BindingFlags bindingAttr)
+               {
+                       string internalName = null;
+                       if (displayName != null)
+                               internalName = TypeIdentifiers.FromDisplay (displayName).InternalName;
+                       using (var namePtr = new Mono.SafeStringMarshal (internalName))
+                       using (var h = new Mono.SafeGPtrArrayHandle (GetNestedTypes_native (namePtr.Value, bindingAttr))) {
+                               int n = h.Length;
+                               var a = new RuntimeType [n];
+                               for (int i = 0; i < n; i++) {
+                                       var th = new RuntimeTypeHandle (h[i]);
+                                       a[i] = (RuntimeType) Type.GetTypeFromHandle (th);
+                               }
+                               return a;
+                       }
+               }
 
                public override string AssemblyQualifiedName {
                        get {
index b36d3d446bc4cea25a3674a2ca7ffe6724df5484..e17878fe2cfe735aa501c9016a50327c67728d03 100644 (file)
@@ -26,6 +26,7 @@ Mono/Runtime.cs
 Mono/RuntimeStructs.cs
 Mono/RuntimeHandles.cs
 Mono/SafeGPtrArrayHandle.cs
+Mono/SafeStringMarshal.cs
 Mono/DataConverter.cs
 Mono.Interop/ComInteropProxy.cs
 Mono.Interop/IDispatch.cs
index 757ed8c5be79f0dbc270a476f5eb2c9c359d997a..89ca81bea1313120e6b34f2d7835a7ed93815c3d 100644 (file)
@@ -68,6 +68,10 @@ ICALL(RTCLASS_1, "GetTypeFromClass", ves_icall_Mono_RuntimeClassHandle_GetTypeFr
 ICALL_TYPE(RTPTRARRAY, "Mono.RuntimeGPtrArrayHandle", RTPTRARRAY_1)
 ICALL(RTPTRARRAY_1, "GPtrArrayFree", ves_icall_Mono_RuntimeGPtrArrayHandle_GPtrArrayFree)
 
+ICALL_TYPE(SAFESTRMARSHAL, "Mono.SafeStringMarshal", SAFESTRMARSHAL_1)
+ICALL(SAFESTRMARSHAL_1, "GFree", ves_icall_Mono_SafeStringMarshal_GFree)
+ICALL(SAFESTRMARSHAL_2, "StringToUtf8", ves_icall_Mono_SafeStringMarshal_StringToUtf8)
+
 #ifndef PLATFORM_RO_FS
 ICALL_TYPE(KPAIR, "Mono.Security.Cryptography.KeyPairPersistence", KPAIR_1)
 ICALL(KPAIR_1, "_CanSecure", ves_icall_Mono_Security_Cryptography_KeyPairPersistence_CanSecure)
@@ -752,7 +756,7 @@ ICALL(RT_9, "GetGenericParameterPosition", ves_icall_RuntimeType_GetGenericParam
 ICALL(RT_10, "GetInterfaceMapData", ves_icall_RuntimeType_GetInterfaceMapData)
 ICALL(RT_11, "GetInterfaces", ves_icall_RuntimeType_GetInterfaces)
 ICALL(RT_12, "GetMethodsByName_native", ves_icall_RuntimeType_GetMethodsByName_native)
-ICALL(RT_13, "GetNestedTypes_internal", ves_icall_RuntimeType_GetNestedTypes)
+ICALL(RT_13, "GetNestedTypes_native", ves_icall_RuntimeType_GetNestedTypes_native)
 ICALL(RT_14, "GetPacking", ves_icall_RuntimeType_GetPacking)
 ICALL(RT_15, "GetPropertiesByName_native", ves_icall_RuntimeType_GetPropertiesByName_native)
 ICALL(RT_16, "GetTypeCodeImplInternal", ves_icall_type_GetTypeCodeInternal)
index 587fd8c1c129ebef17fd779112b96696c87631a9..165cdd39d8fb39480187deee89e1c49e3ea89892 100644 (file)
@@ -1541,6 +1541,21 @@ ves_icall_Mono_RuntimeGPtrArrayHandle_GPtrArrayFree (GPtrArray *ptr_array)
        g_ptr_array_free (ptr_array, TRUE);
 }
 
+ICALL_EXPORT void
+ves_icall_Mono_SafeStringMarshal_GFree (void *c_str)
+{
+       g_free (c_str);
+}
+
+ICALL_EXPORT char*
+ves_icall_Mono_SafeStringMarshal_StringToUtf8 (MonoString *s)
+{
+       MonoError error;
+       char *res = mono_string_to_utf8_checked (s, &error);
+       mono_error_set_pending_exception (&error);
+       return res;
+}
+
 /* System.TypeCode */
 typedef enum {
        TYPECODE_EMPTY,
@@ -3790,29 +3805,29 @@ enum {
 };
 
 ICALL_EXPORT GPtrArray*
-ves_icall_RuntimeType_GetFields_native (MonoReflectionType *type, MonoString *name, guint32 bflags)
+ves_icall_RuntimeType_GetFields_native (MonoReflectionType *type, char *utf8_name, guint32 bflags)
 {
        MonoError error;
-       MonoDomain *domain; 
        MonoClass *startklass, *klass;
        int match;
        gpointer iter;
-       char *utf8_name = NULL;
        int (*compare_func) (const char *s1, const char *s2) = NULL;    
        MonoClassField *field;
 
-       domain = ((MonoObject *)type)->vtable->domain;
        if (type->type->byref) {
                return g_ptr_array_new ();
        }
 
+       mono_error_init (&error);
+
+       compare_func = (bflags & BFLAGS_IgnoreCase) ? mono_utf8_strcasecmp : strcmp;
+
        klass = startklass = mono_class_from_mono_type (type->type);
 
        GPtrArray *ptr_array = g_ptr_array_sized_new (16);
        
 handle_parent: 
        if (mono_class_has_failure (klass)) {
-               mono_error_init (&error);
                mono_error_set_for_class_failure (&error, klass);
                goto fail;
        }
@@ -3846,25 +3861,14 @@ handle_parent:
                if (!match)
                        continue;
 
-               if (name != NULL) {
-                       if (utf8_name == NULL) {
-                               utf8_name = mono_string_to_utf8_checked (name, &error);
-                               if (!is_ok (&error))
-                                       goto fail;
-                               compare_func = (bflags & BFLAGS_IgnoreCase) ? mono_utf8_strcasecmp : strcmp;
-                       }
-
-                       if (compare_func (mono_field_get_name (field), utf8_name))
+               if (utf8_name != NULL && compare_func (mono_field_get_name (field), utf8_name))
                                continue;
-               }
 
                g_ptr_array_add (ptr_array, field);
        }
        if (!(bflags & BFLAGS_DeclaredOnly) && (klass = klass->parent))
                goto handle_parent;
 
-       if (utf8_name != NULL)
-               g_free (utf8_name);
        return ptr_array;
 
 fail:
@@ -3998,28 +4002,18 @@ loader_error:
 }
 
 ICALL_EXPORT GPtrArray*
-ves_icall_RuntimeType_GetMethodsByName_native (MonoReflectionType *type, MonoString *name, guint32 bflags, MonoBoolean ignore_case)
+ves_icall_RuntimeType_GetMethodsByName_native (MonoReflectionType *type, const char *mname, guint32 bflags, MonoBoolean ignore_case)
 {
        MonoError error;
-       MonoDomain *domain; 
-       const char *mname = NULL;
        GPtrArray *method_array;
        MonoClass *klass;
 
        klass = mono_class_from_mono_type (type->type);
-       domain = ((MonoObject *)type)->vtable->domain;
        if (type->type->byref) {
                return g_ptr_array_new ();
        }
 
-       if (name) {
-               mname = mono_string_to_utf8_checked (name, &error);
-               if (mono_error_set_pending_exception (&error))
-                   return NULL;
-       }
-
        method_array = mono_class_get_methods_by_name (klass, mname, bflags, ignore_case, FALSE, &error);
-       g_free ((char*)mname);
        mono_error_set_pending_exception (&error);
        return method_array;
 }
@@ -4146,7 +4140,7 @@ property_accessor_nonpublic (MonoMethod* accessor, gboolean start_klass)
 }
 
 ICALL_EXPORT GPtrArray*
-ves_icall_RuntimeType_GetPropertiesByName_native (MonoReflectionType *type, MonoString *name, guint32 bflags, MonoBoolean ignore_case)
+ves_icall_RuntimeType_GetPropertiesByName_native (MonoReflectionType *type, gchar *propname, guint32 bflags, MonoBoolean ignore_case)
 {
        MonoError error;
        MonoClass *startklass, *klass;
@@ -4154,7 +4148,6 @@ ves_icall_RuntimeType_GetPropertiesByName_native (MonoReflectionType *type, Mono
        MonoProperty *prop;
        int match;
        guint32 flags;
-       gchar *propname = NULL;
        int (*compare_func) (const char *s1, const char *s2) = NULL;
        gpointer iter;
        GHashTable *properties = NULL;
@@ -4168,12 +4161,7 @@ ves_icall_RuntimeType_GetPropertiesByName_native (MonoReflectionType *type, Mono
        
        klass = startklass = mono_class_from_mono_type (type->type);
 
-       if (name != NULL) {
-               propname = mono_string_to_utf8_checked (name, &error);
-               if (mono_error_set_pending_exception (&error))
-                       return NULL;
-               compare_func = (ignore_case) ? mono_utf8_strcasecmp : strcmp;
-       }
+       compare_func = (ignore_case) ? mono_utf8_strcasecmp : strcmp;
 
        res_array = g_ptr_array_sized_new (8); /*This the average for ASP.NET types*/
 
@@ -4181,8 +4169,10 @@ ves_icall_RuntimeType_GetPropertiesByName_native (MonoReflectionType *type, Mono
 handle_parent:
        mono_class_setup_methods (klass);
        mono_class_setup_vtable (klass);
-       if (mono_class_has_failure (klass))
+       if (mono_class_has_failure (klass)) {
+               mono_error_set_for_class_failure (&error, klass);
                goto loader_error;
+       }
 
        iter = NULL;
        while ((prop = mono_class_get_properties (klass, &iter))) {
@@ -4220,10 +4210,8 @@ handle_parent:
                        continue;
                match = 0;
 
-               if (name != NULL) {
-                       if (compare_func (propname, prop->name))
-                               continue;
-               }
+               if (propname != NULL && compare_func (propname, prop->name))
+                       continue;
                
                if (g_hash_table_lookup (properties, prop))
                        continue;
@@ -4236,19 +4224,13 @@ handle_parent:
                goto handle_parent;
 
        g_hash_table_destroy (properties);
-       g_free (propname);
 
        return res_array;
 
 
 loader_error:
-       if (mono_class_has_failure (klass))
-               mono_error_set_for_class_failure (&error, klass);
-
        if (properties)
                g_hash_table_destroy (properties);
-       if (name)
-               g_free (propname);
        g_ptr_array_free (res_array, TRUE);
 
        mono_error_set_pending_exception (&error);
@@ -4272,7 +4254,7 @@ event_equal (MonoEvent *event1, MonoEvent *event2)
 }
 
 ICALL_EXPORT GPtrArray*
-ves_icall_RuntimeType_GetEvents_native (MonoReflectionType *type, MonoString *name, guint32 bflags)
+ves_icall_RuntimeType_GetEvents_native (MonoReflectionType *type, char *utf8_name, guint32 bflags)
 {
        MonoError error;
        MonoClass *startklass, *klass;
@@ -4280,7 +4262,6 @@ ves_icall_RuntimeType_GetEvents_native (MonoReflectionType *type, MonoString *na
        MonoEvent *event;
        int match;
        gpointer iter;
-       char *utf8_name = NULL;
        int (*compare_func) (const char *s1, const char *s2) = NULL;    
        GHashTable *events = NULL;
        GPtrArray *res_array;
@@ -4291,6 +4272,8 @@ ves_icall_RuntimeType_GetEvents_native (MonoReflectionType *type, MonoString *na
 
        mono_error_init (&error);
 
+       compare_func = (bflags & BFLAGS_IgnoreCase) ? mono_utf8_strcasecmp : strcmp;
+
        res_array = g_ptr_array_sized_new (4);
 
        klass = startklass = mono_class_from_mono_type (type->type);
@@ -4299,8 +4282,10 @@ ves_icall_RuntimeType_GetEvents_native (MonoReflectionType *type, MonoString *na
 handle_parent:
        mono_class_setup_methods (klass);
        mono_class_setup_vtable (klass);
-       if (mono_class_has_failure (klass))
-               goto loader_error;
+       if (mono_class_has_failure (klass)) {
+               mono_error_set_for_class_failure (&error, klass);
+               goto failure;
+       }
 
        iter = NULL;
        while ((event = mono_class_get_events (klass, &iter))) {
@@ -4341,17 +4326,8 @@ handle_parent:
                if (!match)
                        continue;
 
-               if (name != NULL) {
-                       if (utf8_name == NULL) {
-                               utf8_name = mono_string_to_utf8_checked (name, &error);
-                               if (!is_ok (&error))
-                                       goto failure;
-                               compare_func = (bflags & BFLAGS_IgnoreCase) ? mono_utf8_strcasecmp : strcmp;
-                       }
-
-                       if (compare_func (event->name, utf8_name))
-                               continue;
-               }               
+               if (utf8_name != NULL && compare_func (event->name, utf8_name))
+                       continue;
 
                if (g_hash_table_lookup (events, event))
                        continue;
@@ -4365,21 +4341,11 @@ handle_parent:
 
        g_hash_table_destroy (events);
 
-       if (utf8_name != NULL)
-               g_free (utf8_name);
-
        return res_array;
 
-loader_error:
-       if (mono_class_has_failure (klass))
-               mono_error_set_for_class_failure (&error, klass);
-
 failure:
-       
        if (events != NULL)
                g_hash_table_destroy (events);
-       if (utf8_name != NULL)
-               g_free (utf8_name);
 
        g_ptr_array_free (res_array, TRUE);
 
@@ -4387,28 +4353,19 @@ failure:
        return NULL;
 }
 
-ICALL_EXPORT MonoArray*
-ves_icall_RuntimeType_GetNestedTypes (MonoReflectionType *type, MonoString *name, guint32 bflags)
+ICALL_EXPORT GPtrArray *
+ves_icall_RuntimeType_GetNestedTypes_native (MonoReflectionType *type, char *str, guint32 bflags)
 {
-       MonoError error;
-       MonoReflectionType *rt;
-       MonoDomain *domain; 
        MonoClass *klass;
-       MonoArray *res = NULL;
-       int i, match;
+       int match;
        MonoClass *nested;
        gpointer iter;
-       char *str = NULL;
-       MonoPtrArray tmp_array;
-
-       mono_error_init (&error);
+       GPtrArray *res_array;
 
-       domain = ((MonoObject *)type)->vtable->domain;
        if (type->type->byref) {
-               MonoArray *result = mono_array_new_cached (domain, mono_defaults.runtimetype_class, 0, &error);
-               mono_error_set_pending_exception (&error);
-               return result;
+               return g_ptr_array_new ();
        }
+
        klass = mono_class_from_mono_type (type->type);
 
        /*
@@ -4423,7 +4380,8 @@ ves_icall_RuntimeType_GetNestedTypes (MonoReflectionType *type, MonoString *name
        if (klass->generic_class)
                klass = klass->generic_class->container_class;
 
-       mono_ptr_array_init (tmp_array, 1, MONO_ROOT_SOURCE_REFLECTION, "temporary reflection nested types list");
+       res_array = g_ptr_array_new ();
+       
        iter = NULL;
        while ((nested = mono_class_get_nested_types (klass, &iter))) {
                match = 0;
@@ -4437,39 +4395,13 @@ ves_icall_RuntimeType_GetNestedTypes (MonoReflectionType *type, MonoString *name
                if (!match)
                        continue;
 
-               if (name != NULL) {
-                       if (str == NULL) {
-                               str = mono_string_to_utf8_checked (name, &error);
-                               if (!is_ok (&error))
-                                       goto leave;
-                               mono_identifier_unescape_type_name_chars (str);
-                       }
-
-                       if (strcmp (nested->name, str))
+               if (str != NULL && strcmp (nested->name, str))
                                continue;
-               }
-
-               rt = mono_type_get_object_checked (domain, &nested->byval_arg, &error);
-               if (!is_ok (&error))
-                       goto leave;
 
-               mono_ptr_array_append (tmp_array, (MonoObject*) rt);
+               g_ptr_array_add (res_array, &nested->byval_arg);
        }
 
-       res = mono_array_new_cached (domain, mono_defaults.runtimetype_class, mono_ptr_array_size (tmp_array), &error);
-       if (!is_ok (&error))
-               goto leave;
-
-       for (i = 0; i < mono_ptr_array_size (tmp_array); ++i)
-               mono_array_setref (res, i, mono_ptr_array_get (tmp_array, i));
-
-leave:
-       mono_ptr_array_destroy (tmp_array);
-
-       g_free (str);
-
-       mono_error_set_pending_exception (&error);
-       return res;
+       return res_array;
 }
 
 ICALL_EXPORT MonoReflectionType*