Merge pull request #1103 from nathanaeljones/patch-1
[mono.git] / mono / metadata / metadata.c
index 7f5a1757a1b20e18db2f9fe52e09f0936f592e36..c2c697060813ad769abb485ac6a8a78ec82315f0 100644 (file)
@@ -26,7 +26,8 @@
 #include "marshal.h"
 #include "debug-helpers.h"
 #include <mono/utils/mono-error-internals.h>
+#include <mono/utils/bsearch.h>
+
 /* Auxiliary structure used for caching inflated signatures */
 typedef struct {
        MonoMethodSignature *sig;
@@ -46,6 +47,7 @@ static void free_generic_class (MonoGenericClass *ginst);
 static void free_inflated_method (MonoMethodInflated *method);
 static void free_inflated_signature (MonoInflatedMethodSignature *sig);
 static void mono_metadata_field_info_full (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva, MonoMarshalSpec **marshal_spec, gboolean alloc_from_image);
+static guint mono_metadata_generic_param_hash (MonoGenericParam *p);
 
 /*
  * This enumeration is used to describe the data types in the metadata
@@ -882,6 +884,7 @@ mono_metadata_locate_token (MonoImage *meta, guint32 token)
 const char *
 mono_metadata_string_heap (MonoImage *meta, guint32 index)
 {
+       g_assert (index < meta->heap_strings.size);
        g_return_val_if_fail (index < meta->heap_strings.size, "");
        return meta->heap_strings.data + index;
 }
@@ -896,6 +899,7 @@ mono_metadata_string_heap (MonoImage *meta, guint32 index)
 const char *
 mono_metadata_user_string (MonoImage *meta, guint32 index)
 {
+       g_assert (index < meta->heap_us.size);
        g_return_val_if_fail (index < meta->heap_us.size, "");
        return meta->heap_us.data + index;
 }
@@ -910,6 +914,7 @@ mono_metadata_user_string (MonoImage *meta, guint32 index)
 const char *
 mono_metadata_blob_heap (MonoImage *meta, guint32 index)
 {
+       g_assert (index < meta->heap_blob.size);
        g_return_val_if_fail (index < meta->heap_blob.size, "");/*FIXME shouldn't we return NULL and check for index == 0?*/
        return meta->heap_blob.data + index;
 }
@@ -1366,8 +1371,11 @@ builtin_types[] = {
 static GHashTable *type_cache = NULL;
 static int next_generic_inst_id = 0;
 
+/* Protected by image_sets_mutex */
 static MonoImageSet *mscorlib_image_set;
+/* Protected by image_sets_mutex */
 static GPtrArray *image_sets;
+static CRITICAL_SECTION image_sets_mutex;
 
 static guint mono_generic_class_hash (gconstpointer data);
 
@@ -1480,6 +1488,8 @@ mono_metadata_init (void)
 
        for (i = 0; i < NBUILTIN_TYPES (); ++i)
                g_hash_table_insert (type_cache, (gpointer) &builtin_types [i], (gpointer) &builtin_types [i]);
+
+       InitializeCriticalSection (&image_sets_mutex);
 }
 
 /**
@@ -1495,6 +1505,7 @@ mono_metadata_cleanup (void)
        type_cache = NULL;
        g_ptr_array_free (image_sets, TRUE);
        image_sets = NULL;
+       DeleteCriticalSection (&image_sets_mutex);
 }
 
 /**
@@ -2177,12 +2188,22 @@ retry:
        }
 }
 
+static inline void
+image_sets_lock (void)
+{
+       EnterCriticalSection (&image_sets_mutex);
+}
+
+static inline void
+image_sets_unlock (void)
+{
+       LeaveCriticalSection (&image_sets_mutex);
+}
+
 /*
  * get_image_set:
  *
  *   Return a MonoImageSet representing the set of images in IMAGES.
- * 
- * LOCKING: Assumes the loader lock is held.
  */
 static MonoImageSet*
 get_image_set (MonoImage **images, int nimages)
@@ -2191,9 +2212,6 @@ get_image_set (MonoImage **images, int nimages)
        MonoImageSet *set;
        GSList *l;
 
-       if (!image_sets)
-               image_sets = g_ptr_array_new ();
-
        /* Common case */
        if (nimages == 1 && images [0] == mono_defaults.corlib && mscorlib_image_set)
                return mscorlib_image_set;
@@ -2202,6 +2220,11 @@ get_image_set (MonoImage **images, int nimages)
        if (nimages == 0)
                return mscorlib_image_set;
 
+       image_sets_lock ();
+
+       if (!image_sets)
+               image_sets = g_ptr_array_new ();
+
        if (images [0] == mono_defaults.corlib && nimages > 1)
                l = images [1]->image_sets;
        else
@@ -2245,8 +2268,12 @@ get_image_set (MonoImage **images, int nimages)
                g_ptr_array_add (image_sets, set);
        }
 
-       if (nimages == 1 && images [0] == mono_defaults.corlib)
+       if (nimages == 1 && images [0] == mono_defaults.corlib) {
+               mono_memory_barrier ();
                mscorlib_image_set = set;
+       }
+
+       image_sets_unlock ();
 
        return set;
 }
@@ -2261,11 +2288,15 @@ delete_image_set (MonoImageSet *set)
        g_hash_table_destroy (set->gmethod_cache);
        g_hash_table_destroy (set->gsignature_cache);
 
+       image_sets_lock ();
+
        for (i = 0; i < set->nimages; ++i)
                set->images [i]->image_sets = g_slist_remove (set->images [i]->image_sets, set);
 
        g_ptr_array_remove (image_sets, set);
 
+       image_sets_unlock ();
+
        if (set->mempool)
                mono_mempool_destroy (set->mempool);
        g_free (set->images);
@@ -2427,15 +2458,18 @@ collect_inflated_signature_images (MonoInflatedMethodSignature *sig, CollectData
 static void
 collect_method_images (MonoMethodInflated *method, CollectData *data)
 {
+       MonoMethod *m = method->declaring;
+
        add_image (method->declaring->klass->image, data);
        if (method->context.class_inst)
                collect_ginst_images (method->context.class_inst, data);
        if (method->context.method_inst)
                collect_ginst_images (method->context.method_inst, data);
        /*
-       if (((MonoMethod*)method)->signature)
-               collect_signature_images (mono_method_signature ((MonoMethod*)method), data);
-       */
+        * Dynamic assemblies have no references, so the images they depend on can be unloaded before them.
+        */
+       if (m->klass->image->dynamic)
+               collect_signature_images (mono_method_signature (m), data);
 }
 
 static void
@@ -2602,11 +2636,11 @@ check_image_sets (MonoImage *image)
        }
 }
 
-GSList*
+void
 mono_metadata_clean_for_image (MonoImage *image)
 {
        CleanForImageUserData ginst_data, gclass_data;
-       GSList *l, *set_list, *free_list = NULL;
+       GSList *l, *set_list;
 
        //check_image_sets (image);
 
@@ -2623,10 +2657,12 @@ mono_metadata_clean_for_image (MonoImage *image)
        for (l = image->image_sets; l; l = l->next) {
                MonoImageSet *set = l->data;
 
+               mono_image_set_lock (set);
                g_hash_table_foreach_steal (set->gclass_cache, steal_gclass_in_image, &gclass_data);
                g_hash_table_foreach_steal (set->ginst_cache, steal_ginst_in_image, &ginst_data);
                g_hash_table_foreach_remove (set->gmethod_cache, inflated_method_in_image, image);
                g_hash_table_foreach_remove (set->gsignature_cache, inflated_signature_in_image, image);
+               mono_image_set_unlock (set);
        }
 
        /* Delete the removed items */
@@ -2646,8 +2682,6 @@ mono_metadata_clean_for_image (MonoImage *image)
        g_slist_free (set_list);
 
        mono_loader_unlock ();
-
-       return free_list;
 }
 
 static void
@@ -2711,6 +2745,7 @@ mono_method_inflated_lookup (MonoMethodInflated* method, gboolean cache)
 {
        CollectData data;
        MonoImageSet *set;
+       gpointer res;
 
        collect_data_init (&data);
 
@@ -2721,11 +2756,17 @@ mono_method_inflated_lookup (MonoMethodInflated* method, gboolean cache)
        collect_data_free (&data);
 
        if (cache) {
+               mono_image_set_lock (set);
                g_hash_table_insert (set->gmethod_cache, method, method);
+               mono_image_set_unlock (set);
 
                return method;
        } else {
-               return g_hash_table_lookup (set->gmethod_cache, method);
+               mono_image_set_lock (set);
+               res = g_hash_table_lookup (set->gmethod_cache, method);
+               mono_image_set_unlock (set);
+
+               return res;
        }
 }
 
@@ -2743,8 +2784,6 @@ mono_metadata_get_inflated_signature (MonoMethodSignature *sig, MonoGenericConte
        CollectData data;
        MonoImageSet *set;
 
-       mono_loader_lock ();
-
        helper.sig = sig;
        helper.context.class_inst = context->class_inst;
        helper.context.method_inst = context->method_inst;
@@ -2757,6 +2796,8 @@ mono_metadata_get_inflated_signature (MonoMethodSignature *sig, MonoGenericConte
 
        collect_data_free (&data);
 
+       mono_image_set_lock (set);
+
        res = g_hash_table_lookup (set->gsignature_cache, &helper);
        if (!res) {
                res = g_new0 (MonoInflatedMethodSignature, 1);
@@ -2766,7 +2807,8 @@ mono_metadata_get_inflated_signature (MonoMethodSignature *sig, MonoGenericConte
                g_hash_table_insert (set->gsignature_cache, res, res);
        }
 
-       mono_loader_unlock ();
+       mono_image_set_unlock (set);
+
        return res->sig;
 }
 
@@ -2799,8 +2841,6 @@ mono_metadata_get_generic_inst (int type_argc, MonoType **type_argv)
        ginst->type_argc = type_argc;
        memcpy (ginst->type_argv, type_argv, type_argc * sizeof (MonoType *));
 
-       mono_loader_lock ();
-
        collect_data_init (&data);
 
        collect_ginst_images (ginst, &data);
@@ -2809,6 +2849,8 @@ mono_metadata_get_generic_inst (int type_argc, MonoType **type_argv)
 
        collect_data_free (&data);
 
+       mono_image_set_lock (set);
+
        ginst = g_hash_table_lookup (set->ginst_cache, ginst);
        if (!ginst) {
                ginst = mono_image_set_alloc0 (set, size);
@@ -2824,7 +2866,7 @@ mono_metadata_get_generic_inst (int type_argc, MonoType **type_argv)
                g_hash_table_insert (set->ginst_cache, ginst, ginst);
        }
 
-       mono_loader_unlock ();
+       mono_image_set_unlock (set);
        return ginst;
 }
 
@@ -2860,8 +2902,6 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst
        helper.is_tb_open = is_tb_open;
        helper.cached_class = NULL;
 
-       mono_loader_lock ();
-
        collect_data_init (&data);
 
        collect_gclass_images (&helper, &data);
@@ -2870,13 +2910,15 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst
 
        collect_data_free (&data);
 
+       mono_image_set_lock (set);
+
        gclass = g_hash_table_lookup (set->gclass_cache, &helper);
 
        /* A tripwire just to keep us honest */
        g_assert (!helper.cached_class);
 
        if (gclass) {
-               mono_loader_unlock ();
+               mono_image_set_unlock (set);
                return gclass;
        }
 
@@ -2898,7 +2940,7 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst
 
        g_hash_table_insert (set->gclass_cache, gclass, gclass);
 
-       mono_loader_unlock ();
+       mono_image_set_unlock (set);
 
        return gclass;
 }
@@ -3911,7 +3953,7 @@ mono_metadata_typedef_from_field (MonoImage *meta, guint32 index)
        if (meta->uncompressed_metadata)
                loc.idx = search_ptr_table (meta, MONO_TABLE_FIELD_POINTER, loc.idx);
 
-       if (!bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, typedef_locator))
+       if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, typedef_locator))
                return 0;
 
        /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
@@ -3942,7 +3984,7 @@ mono_metadata_typedef_from_method (MonoImage *meta, guint32 index)
        if (meta->uncompressed_metadata)
                loc.idx = search_ptr_table (meta, MONO_TABLE_METHOD_POINTER, loc.idx);
 
-       if (!bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, typedef_locator))
+       if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, typedef_locator))
                return 0;
 
        /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
@@ -3984,7 +4026,7 @@ mono_metadata_interfaces_from_typedef_full (MonoImage *meta, guint32 index, Mono
        loc.col_idx = MONO_INTERFACEIMPL_CLASS;
        loc.t = tdef;
 
-       if (!bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
+       if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
                return TRUE;
 
        start = loc.result;
@@ -4065,7 +4107,7 @@ mono_metadata_interfaces_from_typedef (MonoImage *meta, guint32 index, guint *co
  * 
  * Returns: the 1-based index into the TypeDef table of the type
  * where the type described by @index is nested.
- * Retruns 0 if @index describes a non-nested type.
+ * Returns 0 if @index describes a non-nested type.
  */
 guint32
 mono_metadata_nested_in_typedef (MonoImage *meta, guint32 index)
@@ -4080,7 +4122,7 @@ mono_metadata_nested_in_typedef (MonoImage *meta, guint32 index)
        loc.col_idx = MONO_NESTED_CLASS_NESTED;
        loc.t = tdef;
 
-       if (!bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
+       if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
                return 0;
 
        /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
@@ -4144,7 +4186,7 @@ mono_metadata_packing_from_typedef (MonoImage *meta, guint32 index, guint32 *pac
        loc.col_idx = MONO_CLASS_LAYOUT_PARENT;
        loc.t = tdef;
 
-       if (!bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
+       if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
                return 0;
 
        mono_metadata_decode_row (tdef, loc.result, cols, MONO_CLASS_LAYOUT_SIZE);
@@ -4181,7 +4223,7 @@ mono_metadata_custom_attrs_from_index (MonoImage *meta, guint32 index)
 
        /* FIXME: Index translation */
 
-       if (!bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
+       if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
                return 0;
 
        /* Find the first entry by searching backwards */
@@ -4214,7 +4256,7 @@ mono_metadata_declsec_from_index (MonoImage *meta, guint32 index)
        loc.col_idx = MONO_DECL_SECURITY_PARENT;
        loc.t = tdef;
 
-       if (!bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, declsec_locator))
+       if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, declsec_locator))
                return -1;
 
        /* Find the first entry by searching backwards */
@@ -4582,10 +4624,27 @@ mono_metadata_type_hash (MonoType *t1)
                return ((hash << 5) - hash) ^ mono_metadata_type_hash (&t1->data.array->eklass->byval_arg);
        case MONO_TYPE_GENERICINST:
                return ((hash << 5) - hash) ^ mono_generic_class_hash (t1->data.generic_class);
+       case MONO_TYPE_VAR:
+       case MONO_TYPE_MVAR:
+               return ((hash << 5) - hash) ^ mono_metadata_generic_param_hash (t1->data.generic_param);
        }
        return hash;
 }
 
+static guint
+mono_metadata_generic_param_hash (MonoGenericParam *p)
+{
+       guint hash;
+       MonoGenericParamInfo *info;
+
+       hash = (mono_generic_param_num (p) << 2) | p->serial;
+       info = mono_generic_param_info (p);
+       /* Can't hash on the owner klass/method, since those might not be set when this is called */
+       if (info)
+               hash = ((hash << 5) - hash) ^ info->token;
+       return hash;
+}
+
 static gboolean
 mono_metadata_generic_param_equal (MonoGenericParam *p1, MonoGenericParam *p2, gboolean signature_only)
 {
@@ -4928,7 +4987,7 @@ mono_metadata_field_info_full (MonoImage *meta, guint32 index, guint32 *offset,
                loc.col_idx = MONO_FIELD_LAYOUT_FIELD;
                loc.t = tdef;
 
-               if (tdef->base && bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
+               if (tdef->base && mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
                        *offset = mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_LAYOUT_OFFSET);
                } else {
                        *offset = (guint32)-1;
@@ -4940,7 +4999,7 @@ mono_metadata_field_info_full (MonoImage *meta, guint32 index, guint32 *offset,
                loc.col_idx = MONO_FIELD_RVA_FIELD;
                loc.t = tdef;
                
-               if (tdef->base && bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
+               if (tdef->base && mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
                        /*
                         * LAMESPEC: There is no signature, no nothing, just the raw data.
                         */
@@ -4953,7 +5012,7 @@ mono_metadata_field_info_full (MonoImage *meta, guint32 index, guint32 *offset,
                const char *p;
                
                if ((p = mono_metadata_get_marshal_info (meta, index, TRUE))) {
-                       *marshal_spec = mono_metadata_parse_marshal_spec_full (alloc_from_image ? meta : NULL, p);
+                       *marshal_spec = mono_metadata_parse_marshal_spec_full (alloc_from_image ? meta : NULL, meta, p);
                }
        }
 
@@ -5001,7 +5060,7 @@ mono_metadata_get_constant_index (MonoImage *meta, guint32 token, guint32 hint)
        if ((hint > 0) && (hint < tdef->rows) && (mono_metadata_decode_row_col (tdef, hint - 1, MONO_CONSTANT_PARENT) == index))
                return hint;
 
-       if (tdef->base && bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
+       if (tdef->base && mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
                return loc.result + 1;
        }
        return 0;
@@ -5032,7 +5091,7 @@ mono_metadata_events_from_typedef (MonoImage *meta, guint32 index, guint *end_id
        loc.col_idx = MONO_EVENT_MAP_PARENT;
        loc.idx = index + 1;
 
-       if (!bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
+       if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
                return 0;
        
        start = mono_metadata_decode_row_col (tdef, loc.result, MONO_EVENT_MAP_EVENTLIST);
@@ -5074,7 +5133,7 @@ mono_metadata_methods_from_event   (MonoImage *meta, guint32 index, guint *end_i
        loc.col_idx = MONO_METHOD_SEMA_ASSOCIATION;
        loc.idx = ((index + 1) << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT; /* Method association coded index */
 
-       if (!bsearch (&loc, msemt->base, msemt->rows, msemt->row_size, table_locator))
+       if (!mono_binary_search (&loc, msemt->base, msemt->rows, msemt->row_size, table_locator))
                return 0;
 
        start = loc.result;
@@ -5123,7 +5182,7 @@ mono_metadata_properties_from_typedef (MonoImage *meta, guint32 index, guint *en
        loc.col_idx = MONO_PROPERTY_MAP_PARENT;
        loc.idx = index + 1;
 
-       if (!bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
+       if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
                return 0;
        
        start = mono_metadata_decode_row_col (tdef, loc.result, MONO_PROPERTY_MAP_PROPERTY_LIST);
@@ -5165,7 +5224,7 @@ mono_metadata_methods_from_property   (MonoImage *meta, guint32 index, guint *en
        loc.col_idx = MONO_METHOD_SEMA_ASSOCIATION;
        loc.idx = ((index + 1) << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY; /* Method association coded index */
 
-       if (!bsearch (&loc, msemt->base, msemt->rows, msemt->row_size, table_locator))
+       if (!mono_binary_search (&loc, msemt->base, msemt->rows, msemt->row_size, table_locator))
                return 0;
 
        start = loc.result;
@@ -5204,7 +5263,7 @@ mono_metadata_implmap_from_method (MonoImage *meta, guint32 method_idx)
        loc.col_idx = MONO_IMPLMAP_MEMBER;
        loc.idx = ((method_idx + 1) << MONO_MEMBERFORWD_BITS) | MONO_MEMBERFORWD_METHODDEF;
 
-       if (!bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
+       if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
                return 0;
 
        return loc.result + 1;
@@ -5285,11 +5344,15 @@ mono_image_strndup (MonoImage *image, const char *data, guint len)
 MonoMarshalSpec *
 mono_metadata_parse_marshal_spec (MonoImage *image, const char *ptr)
 {
-       return mono_metadata_parse_marshal_spec_full (NULL, ptr);
+       return mono_metadata_parse_marshal_spec_full (NULL, image, ptr);
 }
 
+/*
+ * If IMAGE is non-null, memory will be allocated from its mempool, otherwise it will be allocated using malloc.
+ * PARENT_IMAGE is the image containing the marshal spec.
+ */
 MonoMarshalSpec *
-mono_metadata_parse_marshal_spec_full (MonoImage *image, const char *ptr)
+mono_metadata_parse_marshal_spec_full (MonoImage *image, MonoImage *parent_image, const char *ptr)
 {
        MonoMarshalSpec *res;
        int len;
@@ -5354,6 +5417,7 @@ mono_metadata_parse_marshal_spec_full (MonoImage *image, const char *ptr)
                /* read cookie string */
                len = mono_metadata_decode_value (ptr, &ptr);
                res->data.custom_data.cookie = mono_image_strndup (image, ptr, len);
+               res->data.custom_data.image = parent_image;
        }
 
        if (res->native == MONO_NATIVE_SAFEARRAY) {
@@ -5588,7 +5652,7 @@ mono_metadata_get_marshal_info (MonoImage *meta, guint32 idx, gboolean is_field)
 
        /* FIXME: Index translation */
 
-       if (!bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
+       if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
                return NULL;
 
        return mono_metadata_blob_heap (meta, mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_MARSHAL_NATIVE_TYPE));
@@ -5641,7 +5705,7 @@ mono_class_get_overrides_full (MonoImage *image, guint32 type_token, MonoMethod
        loc.col_idx = MONO_METHODIMPL_CLASS;
        loc.idx = mono_metadata_token_index (type_token);
 
-       if (!bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
+       if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
                return TRUE;
 
        start = loc.result;
@@ -5781,7 +5845,7 @@ mono_metadata_get_generic_param_row (MonoImage *image, guint32 token, guint32 *o
        loc.col_idx = MONO_GENERICPARAM_OWNER;
        loc.t = tdef;
 
-       if (!bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
+       if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
                return 0;
 
        /* Find the first entry by searching backwards */
@@ -6196,6 +6260,21 @@ mono_signature_is_instance (MonoMethodSignature *sig)
        return sig->hasthis;
 }
 
+/**
+ * mono_signature_param_is_out
+ * @sig: the method signature inspected
+ * @param_num: the 0-based index of the inspected parameter
+ * 
+ * Returns: #TRUE if the parameter is an out parameter, #FALSE
+ * otherwise.
+ */
+mono_bool
+mono_signature_param_is_out (MonoMethodSignature *sig, int param_num)
+{
+       g_assert (param_num >= 0 && param_num < sig->param_count);
+       return (sig->params [param_num]->attrs & PARAM_ATTRIBUTE_OUT) != 0;
+}
+
 /**
  * mono_signature_explicit_this:
  * @sig: the method signature inspected