gboolean callvirt = FALSE;
gboolean closed_over_null = FALSE;
gboolean static_method_with_first_arg_bound = FALSE;
+ MonoGenericContext *ctx = NULL;
+ MonoGenericContainer *container = NULL;
+ MonoMethod *orig_method = NULL;
/*
* If the delegate target is null, and the target method is not static, a virtual
static_method_with_first_arg_bound = TRUE;
}
- if (callvirt || static_method_with_first_arg_bound) {
+ /*
+ * For generic delegates, create a generic wrapper, and returns an instance to help AOT.
+ */
+ if (method->is_inflated && !callvirt && !static_method_with_first_arg_bound) {
+ orig_method = method;
+ ctx = &((MonoMethodInflated*)method)->context;
+ method = ((MonoMethodInflated*)method)->declaring;
+
+ container = mono_method_get_generic_container (method);
+ if (!container)
+ container = method->klass->generic_container;
+ g_assert (container);
+
+ invoke_sig = sig = mono_signature_no_pinvoke (method);
+ }
+
+ /*
+ * 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);
+ 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)
cache_ptr = &method->klass->image->delegate_bound_static_invoke_cache;
cache = get_cache (&method->klass->image->delegate_invoke_cache,
(GHashFunc)mono_signature_hash,
(GCompareFunc)mono_metadata_signature_equal);
- if ((res = mono_marshal_find_in_cache (cache, sig)))
+ res = mono_marshal_find_in_cache (cache, sig);
+ if (res)
return res;
}
invoke_sig = static_sig;
name = mono_signature_to_name (sig, "invoke");
- mb = mono_mb_new (get_wrapper_target_class (method->klass->image), name, MONO_WRAPPER_DELEGATE_INVOKE);
+ if (ctx)
+ mb = mono_mb_new (method->klass, name, MONO_WRAPPER_DELEGATE_INVOKE);
+ else
+ mb = mono_mb_new (get_wrapper_target_class (method->klass->image), name, MONO_WRAPPER_DELEGATE_INVOKE);
g_free (name);
/* allocate local 0 (object) */
mono_mb_emit_ldloc (mb, local_prev);
for (i = 0; i < sig->param_count; i++)
mono_mb_emit_ldarg (mb, i + 1);
- mono_mb_emit_op (mb, CEE_CALLVIRT, method);
+ if (ctx)
+ mono_mb_emit_op (mb, CEE_CALLVIRT, mono_class_inflate_generic_method (method, &container->context));
+ else
+ mono_mb_emit_op (mb, CEE_CALLVIRT, method);
if (sig->ret->type != MONO_TYPE_VOID)
mono_mb_emit_byte (mb, CEE_POP);
mono_mb_emit_byte (mb, CEE_RET);
- if (static_method_with_first_arg_bound || callvirt) {
+ mb->skip_visibility = 1;
+
+ if (ctx) {
+ MonoMethod *def, *inst;
+
+ /*
+ * 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 ();
+ } else if (static_method_with_first_arg_bound || callvirt) {
// From mono_mb_create_and_cache
- mb->skip_visibility = 1;
newm = mono_mb_create_method (mb, sig, sig->param_count + 16);
/*We perform double checked locking, so must fence before publishing*/
mono_memory_barrier ();
mono_free_method (newm);
}
} else {
- mb->skip_visibility = 1;
res = mono_mb_create_and_cache (cache, sig, mb, sig, sig->param_count + 16);
}
mono_mb_free (mb);
if (sig->hasthis) {
if (method->string_ctor) {
- mono_mb_emit_ptr (mb, string_dummy);
+ if (mono_gc_is_moving ()) {
+ mono_mb_emit_ptr (mb, &string_dummy);
+ mono_mb_emit_byte (mb, CEE_LDIND_REF);
+ } else {
+ mono_mb_emit_ptr (mb, string_dummy);
+ }
} else {
mono_mb_emit_ldarg (mb, 0);
}
return ret;
}
+/*
+ * mono_marshal_get_gsharedvt_in_wrapper:
+ *
+ * This wrapper handles calls from normal code to gsharedvt code.
+ *
+ * The wrapper info for the wrapper is a WrapperInfo structure.
+ */
+MonoMethod*
+mono_marshal_get_gsharedvt_in_wrapper (void)
+{
+ static MonoMethod* ret = NULL;
+ MonoMethodSignature *sig;
+ MonoMethodBuilder *mb;
+ WrapperInfo *info;
+
+ if (ret)
+ return ret;
+
+ mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_in", MONO_WRAPPER_UNKNOWN);
+
+ sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
+ sig->ret = &mono_defaults.void_class->byval_arg;
+
+ /*
+ * The body is generated by the JIT, we use a wrapper instead of a trampoline so EH works.
+ */
+ mono_mb_emit_byte (mb, CEE_RET);
+
+ ret = mono_mb_create_method (mb, sig, 4);
+ mono_mb_free (mb);
+
+ info = mono_wrapper_info_create (ret, WRAPPER_SUBTYPE_GSHAREDVT_IN);
+ mono_marshal_set_wrapper_info (ret, info);
+
+ return ret;
+}
+
+/*
+ * mono_marshal_get_gsharedvt_out_wrapper:
+ *
+ * This wrapper handles calls from gsharedvt code to normal code.
+ *
+ * The wrapper info for the wrapper is a WrapperInfo structure.
+ */
+MonoMethod*
+mono_marshal_get_gsharedvt_out_wrapper (void)
+{
+ static MonoMethod* ret = NULL;
+ MonoMethodSignature *sig;
+ MonoMethodBuilder *mb;
+ WrapperInfo *info;
+
+ if (ret)
+ return ret;
+
+ mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out", MONO_WRAPPER_UNKNOWN);
+
+ sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
+ sig->ret = &mono_defaults.void_class->byval_arg;
+
+ /*
+ * The body is generated by the JIT, we use a wrapper instead of a trampoline so EH works.
+ */
+ mono_mb_emit_byte (mb, CEE_RET);
+
+ ret = mono_mb_create_method (mb, sig, 4);
+ mono_mb_free (mb);
+
+ info = mono_wrapper_info_create (ret, WRAPPER_SUBTYPE_GSHAREDVT_OUT);
+ mono_marshal_set_wrapper_info (ret, info);
+
+ return ret;
+}
+
typedef struct {
int rank;
int elem_size;
mono_marshal_unlock ();
}
-/*
- * mono_marshal_free_inflated_wrappers:
- *
- * Free wrappers of the inflated method METHOD.
- */
-
static gboolean
signature_method_pair_matches_signature (gpointer key, gpointer value, gpointer user_data)
{
return mono_metadata_signature_equal (pair->sig, sig);
}
+/*
+ * mono_marshal_free_inflated_wrappers:
+ *
+ * Free wrappers of the inflated method METHOD.
+ */
void
mono_marshal_free_inflated_wrappers (MonoMethod *method)
{