From: Aleksey Kliger (λgeek) Date: Fri, 29 Jul 2016 20:05:32 +0000 (-0400) Subject: Merge pull request #3320 from lambdageek/dev/reflection-in-managed X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=35671f29a75557cce71204311539475fcc145ddb;hp=6af085036b89785c44bd908bee8c426f4ed25f5c;p=mono.git Merge pull request #3320 from lambdageek/dev/reflection-in-managed [reflection] Marshal name strings from managed --- diff --git a/mcs/class/corlib/Mono/SafeStringMarshal.cs b/mcs/class/corlib/Mono/SafeStringMarshal.cs new file mode 100644 index 00000000000..c18f0d388a2 --- /dev/null +++ b/mcs/class/corlib/Mono/SafeStringMarshal.cs @@ -0,0 +1,46 @@ +// +// Safe wrapper for a string and its UTF8 encoding +// +// Authors: +// Aleksey Kliger +// Rodrigo Kumpera +// +// 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; + } + } + } +} diff --git a/mcs/class/corlib/ReferenceSources/RuntimeType.cs b/mcs/class/corlib/ReferenceSources/RuntimeType.cs index 189ad1dc7fd..8a49451936e 100644 --- a/mcs/class/corlib/ReferenceSources/RuntimeType.cs +++ b/mcs/class/corlib/ReferenceSources/RuntimeType.cs @@ -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 { diff --git a/mcs/class/corlib/corlib.dll.sources b/mcs/class/corlib/corlib.dll.sources index b36d3d446bc..e17878fe2cf 100644 --- a/mcs/class/corlib/corlib.dll.sources +++ b/mcs/class/corlib/corlib.dll.sources @@ -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 diff --git a/mono/metadata/icall-def.h b/mono/metadata/icall-def.h index 757ed8c5be7..89ca81bea13 100644 --- a/mono/metadata/icall-def.h +++ b/mono/metadata/icall-def.h @@ -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) diff --git a/mono/metadata/icall.c b/mono/metadata/icall.c index 587fd8c1c12..165cdd39d8f 100644 --- a/mono/metadata/icall.c +++ b/mono/metadata/icall.c @@ -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*