Permalink
Browse files

Make begin-invoke/end-invoke wrappers for generic delegates like Func…

…/Action generic, similarly to 8eae1a7.
  • Loading branch information...
1 parent 4f0f577 commit dea604078b3a7eee5c6c96e841141008fd3a635c @vargaz vargaz committed Mar 7, 2013
Showing with 173 additions and 55 deletions.
  1. +2 −0 mono/metadata/image.c
  2. +138 −53 mono/metadata/marshal.c
  3. +2 −0 mono/metadata/metadata-internals.h
  4. +26 −0 mono/mini/gshared.cs
  5. +5 −2 mono/mini/method-to-ir.c
View
@@ -1622,6 +1622,8 @@ mono_image_close_except_pools (MonoImage *image)
free_hash (image->delegate_abstract_invoke_cache);
free_hash (image->delegate_bound_static_invoke_cache);
free_hash (image->delegate_invoke_generic_cache);
+ free_hash (image->delegate_begin_invoke_generic_cache);
+ free_hash (image->delegate_end_invoke_generic_cache);
free_hash (image->remoting_invoke_cache);
free_hash (image->runtime_invoke_cache);
free_hash (image->runtime_invoke_direct_cache);
View
@@ -2660,6 +2660,59 @@ get_wrapper_target_class (MonoImage *image)
return klass;
}
+static MonoMethod*
+check_generic_delegate_wrapper_cache (GHashTable *cache, MonoMethod *orig_method, MonoMethod *def_method, MonoGenericContext *ctx)
+{
+ MonoMethod *res;
+ MonoMethod *inst, *def;
+
+ /*
+ * Look for the instance
+ */
+ res = mono_marshal_find_in_cache (cache, orig_method->klass);
+ if (res)
+ return res;
+
+ /*
+ * Look for the definition
+ */
+ def = mono_marshal_find_in_cache (cache, def_method->klass);
+ if (def) {
+ inst = mono_class_inflate_generic_method (def, ctx);
+ /* Cache it */
+ mono_memory_barrier ();
+ mono_marshal_lock ();
+ res = g_hash_table_lookup (cache, orig_method->klass);
+ if (!res) {
+ g_hash_table_insert (cache, orig_method->klass, inst);
+ res = inst;
+ }
+ mono_marshal_unlock ();
+ return res;
+ }
+ return NULL;
+}
+
+static MonoMethod*
+cache_generic_delegate_wrapper (GHashTable *cache, MonoMethod *orig_method, MonoMethod *def, MonoGenericContext *ctx)
+{
+ MonoMethod *inst, *res;
+
+ /*
+ * We use the same cache for the generic definition and the instances.
+ */
+ inst = mono_class_inflate_generic_method (def, ctx);
+ mono_memory_barrier ();
+ mono_marshal_lock ();
+ res = g_hash_table_lookup (cache, orig_method->klass);
+ if (!res) {
+ g_hash_table_insert (cache, orig_method->klass, inst);
+ res = inst;
+ }
+ mono_marshal_unlock ();
+ return res;
+}
+
MonoMethod *
mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
{
@@ -2669,22 +2722,46 @@ mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
GHashTable *cache;
int params_var;
char *name;
+ MonoGenericContext *ctx = NULL;
+ MonoMethod *orig_method = NULL;
g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
!strcmp (method->name, "BeginInvoke"));
+ /*
+ * For generic delegates, create a generic wrapper, and returns an instance to help AOT.
+ */
+ if (method->is_inflated) {
+ orig_method = method;
+ ctx = &((MonoMethodInflated*)method)->context;
+ method = ((MonoMethodInflated*)method)->declaring;
+ }
+
sig = mono_signature_no_pinvoke (method);
- cache = get_cache (&method->klass->image->delegate_begin_invoke_cache,
- (GHashFunc)mono_signature_hash,
- (GCompareFunc)mono_metadata_signature_equal);
- if ((res = mono_marshal_find_in_cache (cache, sig)))
- return res;
+ /*
+ * Check cache
+ */
+ if (ctx) {
+ cache = get_cache (&method->klass->image->delegate_begin_invoke_generic_cache, mono_aligned_addr_hash, NULL);
+ res = check_generic_delegate_wrapper_cache (cache, orig_method, method, ctx);
+ if (res)
+ return res;
+ } else {
+ cache = get_cache (&method->klass->image->delegate_begin_invoke_cache,
+ (GHashFunc)mono_signature_hash,
+ (GCompareFunc)mono_metadata_signature_equal);
+ if ((res = mono_marshal_find_in_cache (cache, sig)))
+ return res;
+ }
g_assert (sig->hasthis);
name = mono_signature_to_name (sig, "begin_invoke");
- mb = mono_mb_new (get_wrapper_target_class (method->klass->image), name, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE);
+ if (ctx)
+ mb = mono_mb_new (method->klass, name, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE);
+ else
+ mb = mono_mb_new (get_wrapper_target_class (method->klass->image), name, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE);
g_free (name);
#ifndef DISABLE_JIT
@@ -2696,7 +2773,14 @@ mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
mono_mb_emit_byte (mb, CEE_RET);
#endif
- res = mono_mb_create_and_cache (cache, sig, mb, sig, sig->param_count + 16);
+ if (ctx) {
+ MonoMethod *def;
+ def = mono_mb_create_and_cache (cache, method->klass, mb, sig, sig->param_count + 16);
+ res = cache_generic_delegate_wrapper (cache, orig_method, def, ctx);
+ } else {
+ res = mono_mb_create_and_cache (cache, sig, mb, sig, sig->param_count + 16);
+ }
+
mono_mb_free (mb);
return res;
}
@@ -2823,6 +2907,12 @@ mono_mb_emit_restore_result (MonoMethodBuilder *mb, MonoType *return_type)
mono_mb_emit_op (mb, CEE_LDOBJ, klass);
break;
}
+ case MONO_TYPE_VAR:
+ case MONO_TYPE_MVAR: {
+ MonoClass *klass = mono_class_from_mono_type (return_type);
+ mono_mb_emit_op (mb, CEE_UNBOX_ANY, klass);
+ break;
+ }
default:
g_warning ("type 0x%x not handled", return_type->type);
g_assert_not_reached ();
@@ -2842,22 +2932,46 @@ mono_marshal_get_delegate_end_invoke (MonoMethod *method)
GHashTable *cache;
int params_var;
char *name;
+ MonoGenericContext *ctx = NULL;
+ MonoMethod *orig_method = NULL;
g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
!strcmp (method->name, "EndInvoke"));
+ /*
+ * For generic delegates, create a generic wrapper, and returns an instance to help AOT.
+ */
+ if (method->is_inflated) {
+ orig_method = method;
+ ctx = &((MonoMethodInflated*)method)->context;
+ method = ((MonoMethodInflated*)method)->declaring;
+ }
+
sig = mono_signature_no_pinvoke (method);
- cache = get_cache (&method->klass->image->delegate_end_invoke_cache,
- (GHashFunc)mono_signature_hash,
- (GCompareFunc)mono_metadata_signature_equal);
- if ((res = mono_marshal_find_in_cache (cache, sig)))
- return res;
+ /*
+ * Check cache
+ */
+ if (ctx) {
+ cache = get_cache (&method->klass->image->delegate_end_invoke_generic_cache, mono_aligned_addr_hash, NULL);
+ res = check_generic_delegate_wrapper_cache (cache, orig_method, method, ctx);
+ if (res)
+ return res;
+ } else {
+ cache = get_cache (&method->klass->image->delegate_end_invoke_cache,
+ (GHashFunc)mono_signature_hash,
+ (GCompareFunc)mono_metadata_signature_equal);
+ if ((res = mono_marshal_find_in_cache (cache, sig)))
+ return res;
+ }
g_assert (sig->hasthis);
name = mono_signature_to_name (sig, "end_invoke");
- mb = mono_mb_new (get_wrapper_target_class (method->klass->image), name, MONO_WRAPPER_DELEGATE_END_INVOKE);
+ if (ctx)
+ mb = mono_mb_new (method->klass, name, MONO_WRAPPER_DELEGATE_END_INVOKE);
+ else
+ mb = mono_mb_new (get_wrapper_target_class (method->klass->image), name, MONO_WRAPPER_DELEGATE_END_INVOKE);
g_free (name);
#ifndef DISABLE_JIT
@@ -2874,8 +2988,14 @@ mono_marshal_get_delegate_end_invoke (MonoMethod *method)
mono_mb_emit_restore_result (mb, sig->ret);
#endif
- res = mono_mb_create_and_cache (cache, sig,
- mb, sig, sig->param_count + 16);
+ if (ctx) {
+ MonoMethod *def;
+ def = mono_mb_create_and_cache (cache, method->klass, mb, sig, sig->param_count + 16);
+ res = cache_generic_delegate_wrapper (cache, orig_method, def, ctx);
+ } else {
+ res = mono_mb_create_and_cache (cache, sig,
+ mb, sig, sig->param_count + 16);
+ }
mono_mb_free (mb);
return res;
@@ -4022,33 +4142,10 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del)
* Check cache
*/
if (ctx) {
- MonoMethod *def, *inst;
-
- /*
- * Look for the instance
- */
cache = get_cache (&method->klass->image->delegate_invoke_generic_cache, mono_aligned_addr_hash, NULL);
- res = mono_marshal_find_in_cache (cache, orig_method->klass);
+ res = check_generic_delegate_wrapper_cache (cache, orig_method, method, ctx);
if (res)
return res;
-
- /*
- * Look for the definition
- */
- def = mono_marshal_find_in_cache (cache, method->klass);
- if (def) {
- inst = mono_class_inflate_generic_method (def, ctx);
- /* Cache it */
- mono_memory_barrier ();
- mono_marshal_lock ();
- res = g_hash_table_lookup (cache, orig_method->klass);
- if (!res) {
- g_hash_table_insert (cache, orig_method->klass, inst);
- res = inst;
- }
- mono_marshal_unlock ();
- return res;
- }
} else if (callvirt || static_method_with_first_arg_bound) {
GHashTable **cache_ptr;
if (static_method_with_first_arg_bound)
@@ -4197,22 +4294,10 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del)
#endif /* DISABLE_JIT */
if (ctx) {
- MonoMethod *def, *inst;
+ MonoMethod *def;
- /*
- * We use the same cache for the generic definition and the instances.
- */
def = mono_mb_create_and_cache (cache, method->klass, mb, sig, sig->param_count + 16);
-
- inst = mono_class_inflate_generic_method (def, ctx);
- mono_memory_barrier ();
- mono_marshal_lock ();
- res = g_hash_table_lookup (cache, orig_method->klass);
- if (!res) {
- g_hash_table_insert (cache, orig_method->klass, inst);
- res = inst;
- }
- mono_marshal_unlock ();
+ res = cache_generic_delegate_wrapper (cache, orig_method, def, ctx);
} else if (static_method_with_first_arg_bound || callvirt) {
// From mono_mb_create_and_cache
newm = mono_mb_create_method (mb, sig, sig->param_count + 16);
@@ -293,6 +293,8 @@ struct _MonoImage {
GHashTable *proxy_isinst_cache;
GHashTable *rgctx_template_hash; /* LOCKING: templates lock */
GHashTable *delegate_invoke_generic_cache;
+ GHashTable *delegate_begin_invoke_generic_cache;
+ GHashTable *delegate_end_invoke_generic_cache;
/* Contains rarely used fields of runtime structures belonging to this image */
MonoPropertyHash *property_hash;
View
@@ -1058,4 +1058,30 @@ public object Enumerate (List<KeyValuePair<T, string>> alist)
}
return 0;
}
+
+ interface IFace6 {
+ T[] Del<T> (T t);
+ }
+
+ class Class6 : IFace6 {
+ public T[] Del<T> (T t) {
+ var res = new T [5];
+ Func<T, T, T, T, T> func = delegate(T t1, T t2, T t3, T t4) { res [0] = t1; res [1] = t2; res [2] = t3; res [3] = t4; return t1; };
+ var v = func.BeginInvoke(t, t, t, t, null, null);
+ res [4] = func.EndInvoke (v);
+ return res;
+ }
+ }
+
+ public static int test_0_begin_end_invoke () {
+ IFace6 o = new Class6 ();
+ var arr1 = o.Del (1);
+ if (arr1 [0] != 1 || arr1 [1] != 1 || arr1 [2] != 1 || arr1 [3] != 1 || arr1 [4] != 1)
+ return 1;
+ var arr2 = o.Del (2.0);
+ if (arr2 [0] != 2.0 || arr2 [1] != 2.0 || arr2 [2] != 2.0 || arr2 [3] != 2.0 || arr2 [4] != 2.0)
+ return 2;
+ return 0;
+ }
+
}
View
@@ -5651,10 +5651,13 @@ mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
{
MonoClass *klass;
- if (method->wrapper_type != MONO_WRAPPER_NONE)
+ if (method->wrapper_type != MONO_WRAPPER_NONE) {
klass = mono_method_get_wrapper_data (method, token);
- else
+ if (context)
+ klass = mono_class_inflate_generic_class (klass, context);
+ } else {
klass = mono_class_get_full (method->klass->image, token, context);
+ }
if (klass)
mono_class_init (klass);
return klass;

0 comments on commit dea6040

Please sign in to comment.