Skip to content

Commit e91db04

Browse files
LeVladIonescuVlad - Alexandru Ionescu
and
Vlad - Alexandru Ionescu
authored
[mono][aot] Enabling AOT wrappers for virtual delegates (#85643)
* Adding AOT virtual delegates wrappers Signed-off-by: Vlad - Alexandru Ionescu <[email protected]> --------- Signed-off-by: Vlad - Alexandru Ionescu <[email protected]> Co-authored-by: Vlad - Alexandru Ionescu <[email protected]>
1 parent 1f15489 commit e91db04

File tree

8 files changed

+140
-41
lines changed

8 files changed

+140
-41
lines changed

src/mono/mono/metadata/loader-internals.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,12 @@ struct _MonoDllMap {
5252
#endif
5353

5454
typedef struct {
55+
GHashTable *delegate_invoke_cache;
56+
GHashTable *delegate_invoke_virtual_cache;
5557
/*
5658
* indexed by MonoMethodSignature
5759
* Protected by the marshal lock
5860
*/
59-
GHashTable *delegate_invoke_cache;
6061
GHashTable *delegate_begin_invoke_cache;
6162
GHashTable *delegate_end_invoke_cache;
6263
GHashTable *runtime_invoke_signature_cache;

src/mono/mono/metadata/marshal-lightweight.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1989,8 +1989,10 @@ emit_delegate_end_invoke_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *sig)
19891989
mono_mb_emit_restore_result (mb, sig->ret);
19901990
}
19911991

1992+
#define MONO_TYPE_IS_PRIMITIVE(t) ((!m_type_is_byref ((t)) && ((((t)->type >= MONO_TYPE_BOOLEAN && (t)->type <= MONO_TYPE_R8) || ((t)->type >= MONO_TYPE_I && (t)->type <= MONO_TYPE_U)))))
1993+
19921994
static void
1993-
emit_delegate_invoke_internal_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodSignature *invoke_sig, MonoMethodSignature *target_method_sig, gboolean static_method_with_first_arg_bound, gboolean callvirt, gboolean closed_over_null, MonoMethod *method, MonoMethod *target_method, MonoClass *target_class, MonoGenericContext *ctx, MonoGenericContainer *container)
1995+
emit_delegate_invoke_internal_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodSignature *invoke_sig, MonoMethodSignature *target_method_sig, gboolean static_method_with_first_arg_bound, gboolean callvirt, gboolean closed_over_null, MonoMethod *method, MonoMethod *target_method, MonoGenericContext *ctx, MonoGenericContainer *container)
19941996
{
19951997
int local_i, local_len, local_delegates, local_d, local_target, local_res = 0;
19961998
int pos0, pos1, pos2;
@@ -2088,9 +2090,15 @@ emit_delegate_invoke_internal_ilgen (MonoMethodBuilder *mb, MonoMethodSignature
20882090

20892091
if (callvirt) {
20902092
if (!closed_over_null) {
2091-
for (i = 1; i <= sig->param_count; ++i)
2093+
for (i = 1; i <= sig->param_count; ++i) {
20922094
mono_mb_emit_ldarg (mb, i);
2093-
mono_mb_emit_ldarg (mb, 1);
2095+
if (i == 1 && (MONO_TYPE_ISSTRUCT (sig->params [0]) || MONO_TYPE_IS_PRIMITIVE (sig->params [0])))
2096+
mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type_internal (sig->params [0]));
2097+
}
2098+
if (MONO_TYPE_ISSTRUCT (sig->params [0]) || MONO_TYPE_IS_PRIMITIVE (sig->params [0]))
2099+
mono_mb_emit_ldarg_addr (mb, 1);
2100+
else
2101+
mono_mb_emit_ldarg (mb, 1);
20942102
mono_mb_emit_ldarg (mb, 0);
20952103
mono_mb_emit_icall (mb, mono_get_addr_compiled_method);
20962104
mono_mb_emit_op (mb, CEE_CALLI, target_method_sig);

src/mono/mono/metadata/marshal.c

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2092,7 +2092,6 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
20922092
GHashTable *cache;
20932093
gpointer cache_key = NULL;
20942094
char *name;
2095-
MonoClass *target_class = NULL;
20962095
gboolean closed_over_null = FALSE;
20972096
MonoGenericContext *ctx = NULL;
20982097
MonoGenericContainer *container = NULL;
@@ -2111,28 +2110,8 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
21112110
* call is made to that method with the first delegate argument as this. This is
21122111
* a non-documented .NET feature.
21132112
*/
2114-
if (callvirt) {
2113+
if (callvirt)
21152114
subtype = WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL;
2116-
if (target_method->is_inflated) {
2117-
ERROR_DECL (error);
2118-
MonoType *target_type;
2119-
2120-
g_assert (method->signature->hasthis);
2121-
target_type = mono_class_inflate_generic_type_checked (method->signature->params [0],
2122-
mono_method_get_context (method), error);
2123-
mono_error_assert_ok (error); /* FIXME don't swallow the error */
2124-
target_class = mono_class_from_mono_type_internal (target_type);
2125-
} else {
2126-
target_class = target_method->klass;
2127-
}
2128-
2129-
closed_over_null = sig->param_count == mono_method_signature_internal (target_method)->param_count;
2130-
2131-
/*
2132-
* We don't want to use target_method's signature because it can be freed early
2133-
*/
2134-
target_method_sig = mono_method_signature_internal (target_method);
2135-
}
21362115

21372116
if (static_method_with_first_arg_bound) {
21382117
subtype = WRAPPER_SUBTYPE_DELEGATE_INVOKE_BOUND;
@@ -2150,7 +2129,7 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
21502129
/*
21512130
* For generic delegates, create a generic wrapper, and return an instance to help AOT.
21522131
*/
2153-
if (method->is_inflated && subtype == WRAPPER_SUBTYPE_NONE) {
2132+
if (method->is_inflated && (subtype == WRAPPER_SUBTYPE_NONE || subtype == WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL)) {
21542133
ctx = &((MonoMethodInflated*)method)->context;
21552134
method = ((MonoMethodInflated*)method)->declaring;
21562135

@@ -2162,11 +2141,23 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
21622141
invoke_sig = sig = mono_signature_no_pinvoke (method);
21632142
}
21642143

2144+
if (subtype == WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL) {
2145+
/*
2146+
* We don't want to use target_method's signature because it can be freed early
2147+
*/
2148+
target_method_sig = mono_metadata_signature_dup_delegate_invoke_to_target (invoke_sig);
2149+
2150+
closed_over_null = sig->param_count == target_method_sig->param_count;
2151+
}
2152+
21652153
/*
21662154
* Check cache
21672155
*/
21682156
if (ctx) {
2169-
cache = get_cache (&((MonoMethodInflated*)orig_method)->owner->wrapper_caches.delegate_invoke_cache, mono_aligned_addr_hash, NULL);
2157+
if (callvirt)
2158+
cache = get_cache (&((MonoMethodInflated*)orig_method)->owner->wrapper_caches.delegate_invoke_virtual_cache, mono_aligned_addr_hash, NULL);
2159+
else
2160+
cache = get_cache (&((MonoMethodInflated*)orig_method)->owner->wrapper_caches.delegate_invoke_cache, mono_aligned_addr_hash, NULL);
21702161
res = check_generic_delegate_wrapper_cache (cache, orig_method, method, ctx);
21712162
if (res)
21722163
return res;
@@ -2241,7 +2232,7 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
22412232
/* FIXME: Other subtypes */
22422233
mb->mem_manager = m_method_get_mem_manager (method);
22432234

2244-
get_marshal_cb ()->emit_delegate_invoke_internal (mb, sig, invoke_sig, target_method_sig, static_method_with_first_arg_bound, callvirt, closed_over_null, method, target_method, target_class, ctx, container);
2235+
get_marshal_cb ()->emit_delegate_invoke_internal (mb, sig, invoke_sig, target_method_sig, static_method_with_first_arg_bound, callvirt, closed_over_null, method, target_method, ctx, container);
22452236

22462237
get_marshal_cb ()->mb_skip_visibility (mb);
22472238

@@ -6384,6 +6375,7 @@ void
63846375
mono_wrapper_caches_free (MonoWrapperCaches *cache)
63856376
{
63866377
free_hash (cache->delegate_invoke_cache);
6378+
free_hash (cache->delegate_invoke_virtual_cache);
63876379
free_hash (cache->delegate_begin_invoke_cache);
63886380
free_hash (cache->delegate_end_invoke_cache);
63896381
free_hash (cache->delegate_bound_static_invoke_cache);

src/mono/mono/metadata/marshal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ typedef struct {
328328
void (*emit_runtime_invoke_dynamic) (MonoMethodBuilder *mb);
329329
void (*emit_delegate_begin_invoke) (MonoMethodBuilder *mb, MonoMethodSignature *sig);
330330
void (*emit_delegate_end_invoke) (MonoMethodBuilder *mb, MonoMethodSignature *sig);
331-
void (*emit_delegate_invoke_internal) (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodSignature *invoke_sig, MonoMethodSignature *target_method_sig, gboolean static_method_with_first_arg_bound, gboolean callvirt, gboolean closed_over_null, MonoMethod *method, MonoMethod *target_method, MonoClass *target_class, MonoGenericContext *ctx, MonoGenericContainer *container);
331+
void (*emit_delegate_invoke_internal) (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodSignature *invoke_sig, MonoMethodSignature *target_method_sig, gboolean static_method_with_first_arg_bound, gboolean callvirt, gboolean closed_over_null, MonoMethod *method, MonoMethod *target_method, MonoGenericContext *ctx, MonoGenericContainer *container);
332332
void (*emit_synchronized_wrapper) (MonoMethodBuilder *mb, MonoMethod *method, MonoGenericContext *ctx, MonoGenericContainer *container, MonoMethod *enter_method, MonoMethod *exit_method, MonoMethod *gettypefromhandle_method);
333333
void (*emit_unbox_wrapper) (MonoMethodBuilder *mb, MonoMethod *method);
334334
void (*emit_array_accessor_wrapper) (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *sig, MonoGenericContext *ctx);

src/mono/mono/metadata/metadata-internals.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -991,6 +991,7 @@ MonoMethodSignature *mono_metadata_signature_dup_full (MonoImage *image,MonoMet
991991
MonoMethodSignature *mono_metadata_signature_dup_mempool (MonoMemPool *mp, MonoMethodSignature *sig);
992992
MonoMethodSignature *mono_metadata_signature_dup_mem_manager (MonoMemoryManager *mem_manager, MonoMethodSignature *sig);
993993
MonoMethodSignature *mono_metadata_signature_dup_add_this (MonoImage *image, MonoMethodSignature *sig, MonoClass *klass);
994+
MonoMethodSignature *mono_metadata_signature_dup_delegate_invoke_to_target (MonoMethodSignature *sig);
994995

995996
MonoGenericInst *
996997
mono_get_shared_generic_inst (MonoGenericContainer *container);

src/mono/mono/metadata/metadata.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2512,6 +2512,29 @@ mono_metadata_signature_dup (MonoMethodSignature *sig)
25122512
return mono_metadata_signature_dup_full (NULL, sig);
25132513
}
25142514

2515+
/**
2516+
* mono_metadata_signature_dup_delegate_invoke_to_target:
2517+
* \param sig method signature
2518+
*
2519+
* Duplicate an existing \c MonoMethodSignature but removes first param from it so it can
2520+
* be used as signature for a delegate target method.
2521+
* This is a Mono runtime internal function.
2522+
*
2523+
* \returns the new \c MonoMethodSignature structure.
2524+
*/
2525+
MonoMethodSignature*
2526+
mono_metadata_signature_dup_delegate_invoke_to_target (MonoMethodSignature *sig)
2527+
{
2528+
MonoMethodSignature *res = mono_metadata_signature_dup_full (NULL, sig);
2529+
2530+
for (int i = 0 ; i < sig->param_count - 1; i ++) {
2531+
res->params [i] = sig->params [i + 1];
2532+
}
2533+
res->param_count --;
2534+
2535+
return res;
2536+
}
2537+
25152538
/*
25162539
* mono_metadata_signature_size:
25172540
*

src/mono/mono/mini/aot-compiler.c

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3922,12 +3922,15 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
39223922
encode_klass_ref (acfg, method->klass, p, &p);
39233923
} else {
39243924
MonoMethodSignature *sig = mono_method_signature_internal (method);
3925-
WrapperInfo *wrapper_info = mono_marshal_get_wrapper_info (method);
39263925

39273926
encode_value (0, p, &p);
39283927
if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE)
3929-
encode_value (wrapper_info ? wrapper_info->subtype : 0, p, &p);
3930-
encode_signature (acfg, sig, p, &p);
3928+
encode_value (info ? info->subtype : 0, p, &p);
3929+
3930+
if (info && info->subtype == WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL)
3931+
encode_klass_ref (acfg, info->d.delegate_invoke.method->klass, p, &p);
3932+
else
3933+
encode_signature (acfg, sig, p, &p);
39313934
}
39323935
break;
39333936
}
@@ -4546,6 +4549,41 @@ can_marshal_struct (MonoClass *klass)
45464549
return can_marshal;
45474550
}
45484551

4552+
/* Create a ref shared instantiation */
4553+
static void
4554+
create_ref_shared_inst (MonoAotCompile *acfg, MonoMethod *method, MonoGenericContext *ctx)
4555+
{
4556+
MonoGenericContext shared_context;
4557+
MonoType **args;
4558+
MonoGenericInst *inst;
4559+
MonoGenericContainer *container;
4560+
4561+
memset (ctx, 0, sizeof (MonoGenericContext));
4562+
4563+
if (mono_class_is_gtd (method->klass)) {
4564+
shared_context = mono_class_get_generic_container (method->klass)->context;
4565+
inst = shared_context.class_inst;
4566+
4567+
args = g_new0 (MonoType*, inst->type_argc);
4568+
for (guint i = 0; i < inst->type_argc; ++i)
4569+
args [i] = mono_get_object_type ();
4570+
ctx->class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
4571+
g_free (args);
4572+
}
4573+
if (method->is_generic) {
4574+
container = mono_method_get_generic_container (method);
4575+
g_assert (!container->is_anonymous && container->is_method);
4576+
shared_context = container->context;
4577+
inst = shared_context.method_inst;
4578+
4579+
args = g_new0 (MonoType*, inst->type_argc);
4580+
for (int i = 0; i < container->type_argc; ++i)
4581+
args [i] = mono_get_object_type ();
4582+
ctx->method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
4583+
g_free (args);
4584+
}
4585+
}
4586+
45494587
static void
45504588
create_gsharedvt_inst (MonoAotCompile *acfg, MonoMethod *method, MonoGenericContext *ctx)
45514589
{
@@ -4962,13 +5000,39 @@ add_full_aot_wrappers (MonoAotCompile *acfg)
49625000
if (!m_class_is_delegate (klass) || klass == mono_defaults.delegate_class || klass == mono_defaults.multicastdelegate_class)
49635001
continue;
49645002

5003+
method = mono_get_delegate_invoke_internal (klass);
5004+
if (mono_class_is_gtd (klass)) {
5005+
MonoGenericContext ctx;
5006+
MonoMethod *inst, *gshared;
5007+
5008+
create_ref_shared_inst (acfg, method, &ctx);
5009+
5010+
inst = mono_class_inflate_generic_method_checked (method, &ctx, error);
5011+
g_assert (is_ok (error)); /* FIXME don't swallow the error */
5012+
5013+
sig = mono_method_signature_internal (method);
5014+
if (sig->param_count && !m_class_is_byreflike (mono_class_from_mono_type_internal (sig->params [0])) && !m_type_is_byref (sig->params [0])) {
5015+
m = mono_marshal_get_delegate_invoke_internal (inst, TRUE, FALSE, NULL);
5016+
5017+
gshared = mini_get_shared_method_full (m, SHARE_MODE_NONE, error);
5018+
mono_error_assert_ok (error);
5019+
5020+
add_extra_method (acfg, gshared);
5021+
}
5022+
}
5023+
49655024
if (!mono_class_is_gtd (klass)) {
4966-
method = mono_get_delegate_invoke_internal (klass);
49675025

49685026
m = mono_marshal_get_delegate_invoke (method, NULL);
49695027

49705028
add_method (acfg, m);
49715029

5030+
sig = mono_method_signature_internal (method);
5031+
if (sig->param_count && !m_class_is_byreflike (mono_class_from_mono_type_internal (sig->params [0])) && !m_type_is_byref (sig->params [0])) {
5032+
m = mono_marshal_get_delegate_invoke_internal (method, TRUE, FALSE, NULL);
5033+
add_method (acfg, m);
5034+
}
5035+
49725036
method = try_get_method_nofail (klass, "BeginInvoke", -1, 0);
49735037
if (method)
49745038
add_method (acfg, mono_marshal_get_delegate_begin_invoke (method));

src/mono/mono/mini/aot-runtime.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,15 +1269,25 @@ decode_method_ref_with_target (MonoAotModule *module, MethodRef *ref, MonoMethod
12691269
ref->method = wrapper;
12701270
}
12711271
} else {
1272-
/*
1273-
* These wrappers are associated with a signature, not with a method.
1274-
* Since we can't decode them into methods, they need a target method.
1275-
*/
1276-
if (!target)
1277-
return FALSE;
1272+
MonoClass *klass;
1273+
MonoMethod *invoke;
1274+
12781275

12791276
if (wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) {
12801277
subtype = (WrapperSubtype)decode_value (p, &p);
1278+
if (subtype == WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL) {
1279+
klass = decode_klass_ref (module, p, &p, error);
1280+
invoke = mono_get_delegate_invoke_internal (klass);
1281+
ref->method = mono_marshal_get_delegate_invoke_internal(invoke, TRUE, FALSE, NULL);
1282+
break;
1283+
}
1284+
1285+
/*
1286+
* These wrappers are associated with a signature, not with a method.
1287+
* Since we can't decode them into methods, they need a target method.
1288+
*/
1289+
if (!target)
1290+
return FALSE;
12811291
info = mono_marshal_get_wrapper_info (target);
12821292
if (info) {
12831293
if (info->subtype != subtype)
@@ -1287,7 +1297,7 @@ decode_method_ref_with_target (MonoAotModule *module, MethodRef *ref, MonoMethod
12871297
return FALSE;
12881298
}
12891299
}
1290-
if (sig_matches_target (module, target, p, &p))
1300+
if (target && sig_matches_target (module, target, p, &p))
12911301
ref->method = target;
12921302
else
12931303
return FALSE;

0 commit comments

Comments
 (0)