Skip to content

Commit

Permalink
[runtime] Refactor mono_marshal_get_delegate_invoke_internal ().
Browse files Browse the repository at this point in the history
  • Loading branch information
vargaz committed Apr 6, 2014
1 parent a2e69ce commit 3d469b9
Showing 1 changed file with 76 additions and 60 deletions.
136 changes: 76 additions & 60 deletions mono/metadata/marshal.c
Expand Up @@ -2475,13 +2475,16 @@ mono_marshal_find_in_cache (GHashTable *cache, gpointer key)
}

/* Create the method from the builder and place it in the cache */
MonoMethod*
mono_mb_create_and_cache (GHashTable *cache, gpointer key,
static MonoMethod*
mono_mb_create_and_cache_full (GHashTable *cache, gpointer key,
MonoMethodBuilder *mb, MonoMethodSignature *sig,
int max_stack)
int max_stack, gboolean *out_found)
{
MonoMethod *res;

if (out_found)
*out_found = FALSE;

mono_marshal_lock ();
res = g_hash_table_lookup (cache, key);
mono_marshal_unlock ();
Expand All @@ -2496,6 +2499,8 @@ mono_mb_create_and_cache (GHashTable *cache, gpointer key,
mono_marshal_set_wrapper_info (res, key);
mono_marshal_unlock ();
} else {
if (out_found)
*out_found = TRUE;
mono_marshal_unlock ();
mono_free_method (newm);
}
Expand All @@ -2504,6 +2509,13 @@ mono_mb_create_and_cache (GHashTable *cache, gpointer key,
return res;
}

MonoMethod*
mono_mb_create_and_cache (GHashTable *cache, gpointer key,
MonoMethodBuilder *mb, MonoMethodSignature *sig,
int max_stack)
{
return mono_mb_create_and_cache_full (cache, key, mb, sig, max_stack, NULL);
}

static inline MonoMethod*
mono_marshal_remoting_find_in_cache (MonoMethod *method, int wrapper_type)
Expand Down Expand Up @@ -4171,40 +4183,41 @@ free_signature_method_pair (SignatureMethodPair *pair)
g_free (pair);
}

/*
* the returned method invokes all methods in a multicast delegate.
*/
MonoMethod *
mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del)
static MonoMethod *
mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt, gboolean static_method_with_first_arg_bound, MonoMethod *target_method)
{
MonoMethodSignature *sig, *static_sig, *invoke_sig;
int i;
MonoMethodBuilder *mb;
MonoMethod *res, *newm;
MonoMethod *res;
GHashTable *cache;
gpointer cache_key = NULL;
SignatureMethodPair key;
SignatureMethodPair *new_key;
int local_prev, local_target;
int pos0;
char *name;
MonoMethod *target_method = NULL;
MonoClass *target_class = NULL;
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;
WrapperInfo *info;
WrapperSubtype subtype = WRAPPER_SUBTYPE_NONE;
gboolean found;

g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
!strcmp (method->name, "Invoke"));

invoke_sig = sig = mono_signature_no_pinvoke (method);

/*
* If the delegate target is null, and the target method is not static, a virtual
* call is made to that method with the first delegate argument as this. This is
* a non-documented .NET feature.
*/
if (del && !del->target && del->method && mono_method_signature (del->method)->hasthis) {
callvirt = TRUE;
target_method = del->method;
if (callvirt) {
subtype = WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL;
if (target_method->is_inflated) {
MonoType *target_type;

Expand All @@ -4213,29 +4226,22 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del)
mono_method_get_context (method));
target_class = mono_class_from_mono_type (target_type);
} else {
target_class = del->method->klass;
target_class = target_method->klass;
}
}

g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
!strcmp (method->name, "Invoke"));

invoke_sig = sig = mono_signature_no_pinvoke (method);

if (callvirt)
closed_over_null = sig->param_count == mono_method_signature (del->method)->param_count;
closed_over_null = sig->param_count == mono_method_signature (target_method)->param_count;
}

if (del && del->method && mono_method_signature (del->method)->param_count == sig->param_count + 1 && (del->method->flags & METHOD_ATTRIBUTE_STATIC)) {
if (static_method_with_first_arg_bound) {
subtype = WRAPPER_SUBTYPE_DELEGATE_INVOKE_BOUND;
g_assert (!callvirt);
invoke_sig = mono_method_signature (del->method);
target_method = NULL;
static_method_with_first_arg_bound = TRUE;
invoke_sig = mono_method_signature (target_method);
}

/*
* For generic delegates, create a generic wrapper, and returns an instance to help AOT.
* For generic delegates, create a generic wrapper, and return an instance to help AOT.
*/
if (method->is_inflated && !callvirt && !static_method_with_first_arg_bound) {
if (method->is_inflated && subtype == WRAPPER_SUBTYPE_NONE) {
orig_method = method;
ctx = &((MonoMethodInflated*)method)->context;
method = ((MonoMethodInflated*)method)->declaring;
Expand All @@ -4256,6 +4262,7 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del)
res = check_generic_delegate_wrapper_cache (cache, orig_method, method, ctx);
if (res)
return res;
cache_key = method->klass;
} else if (static_method_with_first_arg_bound) {
cache = get_cache (&method->klass->image->delegate_bound_static_invoke_cache,
(GHashFunc)mono_signature_hash,
Expand All @@ -4266,6 +4273,7 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del)
res = mono_marshal_find_in_cache (cache, invoke_sig);
if (res)
return res;
cache_key = invoke_sig;
} else if (callvirt) {
GHashTable **cache_ptr;

Expand All @@ -4289,6 +4297,7 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del)
res = mono_marshal_find_in_cache (cache, sig);
if (res)
return res;
cache_key = sig;
}

static_sig = signature_dup (method->klass->image, sig);
Expand All @@ -4303,7 +4312,7 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del)
else if (callvirt)
name = mono_signature_to_name (invoke_sig, "invoke_callvirt");
else
name = mono_signature_to_name (sig, "invoke");
name = mono_signature_to_name (invoke_sig, "invoke");
if (ctx)
mb = mono_mb_new (method->klass, name, MONO_WRAPPER_DELEGATE_INVOKE);
else
Expand Down Expand Up @@ -4421,47 +4430,54 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del)
if (ctx) {
MonoMethod *def;

def = mono_mb_create_and_cache (cache, method->klass, mb, sig, sig->param_count + 16);
def = mono_mb_create_and_cache (cache, cache_key, mb, sig, sig->param_count + 16);
res = cache_generic_delegate_wrapper (cache, orig_method, def, ctx);
} else if (static_method_with_first_arg_bound) {
res = mono_mb_create_and_cache (cache, invoke_sig, mb, sig, sig->param_count + 16);

info = mono_wrapper_info_create (res, WRAPPER_SUBTYPE_DELEGATE_INVOKE_BOUND);
mono_marshal_set_wrapper_info (res, info);
} else if (callvirt) {
// From mono_mb_create_and_cache
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_marshal_lock ();
res = g_hash_table_lookup (cache, &key);
if (!res) {
res = newm;
new_key = g_new0 (SignatureMethodPair, 1);
*new_key = key;
if (static_method_with_first_arg_bound)
new_key->sig = signature_dup (del->method->klass->image, key.sig);
g_hash_table_insert (cache, new_key, res);

info = mono_wrapper_info_create (res, WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL);
mono_marshal_set_wrapper_info (res, info);
new_key = g_new0 (SignatureMethodPair, 1);
*new_key = key;

mono_marshal_unlock ();
} else {
mono_marshal_unlock ();
mono_free_method (newm);
}
res = mono_mb_create_and_cache_full (cache, new_key, mb, sig, sig->param_count + 16, &found);
if (found)
g_free (new_key);
info = mono_wrapper_info_create (res, subtype);
mono_marshal_set_wrapper_info (res, info);
} else {
res = mono_mb_create_and_cache (cache, sig, mb, sig, sig->param_count + 16);
res = mono_mb_create_and_cache (cache, cache_key, mb, sig, sig->param_count + 16);

info = mono_wrapper_info_create (res, WRAPPER_SUBTYPE_NONE);
info = mono_wrapper_info_create (res, subtype);
mono_marshal_set_wrapper_info (res, info);
}
mono_mb_free (mb);

return res;
}

/*
* the returned method invokes all methods in a multicast delegate.
*/
MonoMethod *
mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del)
{
gboolean callvirt = FALSE;
gboolean static_method_with_first_arg_bound = FALSE;
MonoMethod *target_method = NULL;
MonoMethodSignature *sig;

sig = mono_signature_no_pinvoke (method);

if (del && !del->target && del->method && mono_method_signature (del->method)->hasthis) {
callvirt = TRUE;
target_method = del->method;
}

if (del && del->method && mono_method_signature (del->method)->param_count == sig->param_count + 1 && (del->method->flags & METHOD_ATTRIBUTE_STATIC)) {
static_method_with_first_arg_bound = TRUE;
target_method = del->method;
}

return mono_marshal_get_delegate_invoke_internal (method, callvirt, static_method_with_first_arg_bound, target_method);
}

/*
* signature_dup_add_this:
*
Expand Down

0 comments on commit 3d469b9

Please sign in to comment.