-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Change callvirt
into calli
for virtual delegates
#83461
Changes from 18 commits
a175351
f9ed58c
a381c06
d91a78f
1291fe3
9a58bb3
8db950e
f587d24
f5dbeaf
287419e
fbc1526
afd58dd
45f4845
91c3920
81973db
3b0d6cb
f67f5fb
dc2c525
4ba3366
7b65607
e7e8913
d6e1d3d
0074bea
be6daed
596837e
414f451
1d2c4fb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -324,6 +324,7 @@ mono_marshal_init (void) | |
register_icall (monoeg_g_free, mono_icall_sig_void_ptr, FALSE); | ||
register_icall (mono_object_isinst_icall, mono_icall_sig_object_object_ptr, TRUE); | ||
register_icall (mono_struct_delete_old, mono_icall_sig_void_ptr_ptr, FALSE); | ||
register_icall (mono_get_addr_compiled_method, mono_icall_sig_ptr_object_ptr, FALSE); | ||
register_icall (mono_delegate_begin_invoke, mono_icall_sig_object_object_ptr, FALSE); | ||
register_icall (mono_delegate_end_invoke, mono_icall_sig_object_object_ptr, FALSE); | ||
register_icall (mono_gc_wbarrier_generic_nostore_internal, mono_icall_sig_void_ptr, TRUE); | ||
|
@@ -2085,7 +2086,7 @@ free_signature_pointer_pair (SignaturePointerPair *pair) | |
MonoMethod * | ||
mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt, gboolean static_method_with_first_arg_bound, MonoMethod *target_method) | ||
{ | ||
MonoMethodSignature *sig, *invoke_sig; | ||
MonoMethodSignature *sig, *invoke_sig, *target_method_sig = NULL; | ||
MonoMethodBuilder *mb; | ||
MonoMethod *res; | ||
GHashTable *cache; | ||
|
@@ -2129,6 +2130,11 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt | |
} | ||
|
||
closed_over_null = sig->param_count == mono_method_signature_internal (target_method)->param_count; | ||
|
||
/* | ||
* We don't want to use target_method's signature because it can be freed early | ||
*/ | ||
target_method_sig = mono_method_signature_internal (target_method); | ||
} | ||
|
||
if (static_method_with_first_arg_bound) { | ||
|
@@ -2188,17 +2194,16 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt | |
|
||
cache_ptr = &mono_method_get_wrapper_cache (method)->delegate_abstract_invoke_cache; | ||
|
||
/* We need to cache the signature+method pair */ | ||
/* We need to cache the signature */ | ||
mono_marshal_lock (); | ||
if (!*cache_ptr) | ||
*cache_ptr = g_hash_table_new_full (signature_pointer_pair_hash, (GEqualFunc)signature_pointer_pair_equal, (GDestroyNotify)free_signature_pointer_pair, NULL); | ||
cache = *cache_ptr; | ||
key.sig = invoke_sig; | ||
key.pointer = target_method; | ||
res = (MonoMethod *)g_hash_table_lookup (cache, &key); | ||
cache = get_cache (cache_ptr, | ||
(GHashFunc)mono_signature_hash, | ||
(GCompareFunc)mono_metadata_signature_equal); | ||
res = (MonoMethod *)g_hash_table_lookup (cache, invoke_sig); | ||
mono_marshal_unlock (); | ||
if (res) | ||
return res; | ||
cache_key = invoke_sig; | ||
} else { | ||
// Inflated methods should not be in this cache because it's not stored on the imageset. | ||
g_assert (!method->is_inflated); | ||
|
@@ -2239,7 +2244,7 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt | |
/* FIXME: Other subtypes */ | ||
mb->mem_manager = m_method_get_mem_manager (method); | ||
|
||
get_marshal_cb ()->emit_delegate_invoke_internal (mb, sig, invoke_sig, static_method_with_first_arg_bound, callvirt, closed_over_null, method, target_method, target_class, ctx, container); | ||
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); | ||
|
||
get_marshal_cb ()->mb_skip_visibility (mb); | ||
|
||
|
@@ -2251,13 +2256,6 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt | |
|
||
def = mono_mb_create_and_cache_full (cache, cache_key, mb, sig, sig->param_count + 16, info, NULL); | ||
res = cache_generic_delegate_wrapper (cache, orig_method, def, ctx); | ||
} else if (callvirt) { | ||
new_key = g_new0 (SignaturePointerPair, 1); | ||
*new_key = key; | ||
|
||
res = mono_mb_create_and_cache_full (cache, new_key, mb, sig, sig->param_count + 16, info, &found); | ||
if (found) | ||
g_free (new_key); | ||
} else { | ||
res = mono_mb_create_and_cache_full (cache, cache_key, mb, sig, sig->param_count + 16, info, NULL); | ||
} | ||
|
@@ -5481,6 +5479,35 @@ mono_struct_delete_old (MonoClass *klass, char *ptr) | |
} | ||
} | ||
|
||
void* | ||
mono_get_addr_compiled_method (MonoObject *object, MonoDelegate *del) | ||
{ | ||
ERROR_DECL (error); | ||
MonoMethod *res, *method = del->method; | ||
gpointer addr; | ||
gboolean need_unbox = FALSE; | ||
|
||
if (object == NULL) { | ||
mono_error_set_null_reference (error); | ||
mono_error_set_pending_exception (error); | ||
return NULL; | ||
} | ||
|
||
res = mono_object_get_virtual_method_internal (object, method); | ||
|
||
addr = mono_compile_method_checked (res, error); | ||
|
||
if (!is_ok (error)) { | ||
mono_error_set_pending_exception (error); | ||
return NULL; | ||
} | ||
|
||
need_unbox = m_class_is_valuetype (res->klass) && !m_class_is_valuetype (method->klass); | ||
addr = mono_get_runtime_callbacks ()->add_delegate_trampolines (res, addr, need_unbox); | ||
|
||
return addr; | ||
} | ||
|
||
void | ||
ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src, MonoReflectionTypeHandle type, MonoError *error) | ||
{ | ||
|
@@ -6256,7 +6283,7 @@ mono_marshal_free_dynamic_wrappers (MonoMethod *method) | |
if (image->wrapper_caches.runtime_invoke_method_cache) | ||
clear_runtime_invoke_method_cache (image->wrapper_caches.runtime_invoke_method_cache, method); | ||
if (image->wrapper_caches.delegate_abstract_invoke_cache) | ||
g_hash_table_foreach_remove (image->wrapper_caches.delegate_abstract_invoke_cache, signature_pointer_pair_matches_pointer, method); | ||
g_hash_table_remove (image->wrapper_caches.delegate_abstract_invoke_cache, mono_method_signature_internal (method)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not be needed anymore since the wrappers are no longer associated with the method. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And how is that cache going to be freed if we remove it from here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Its freed already in marshal.c, we just don't need to handle it here, since these wrappers will no longer depend on dynamic methods. |
||
// FIXME: Need to clear the caches in other images as well | ||
if (image->wrapper_caches.delegate_bound_static_invoke_cache) | ||
g_hash_table_remove (image->wrapper_caches.delegate_bound_static_invoke_cache, mono_method_signature_internal (method)); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
|
||
using System; | ||
using System.Runtime.InteropServices; | ||
|
||
public class VirtualDelegate | ||
{ | ||
public static int Main () { | ||
int retVal = 100; | ||
try { | ||
var del = (Func<string, string>)Delegate.CreateDelegate (typeof (Func<string, string>), null, typeof (object).GetMethod ("ToString")); | ||
if (del ("FOO") != "FOO") | ||
retVal = 1; | ||
} catch(Exception e) { | ||
Console.WriteLine(e); | ||
retVal = 1; | ||
} | ||
|
||
return retVal; | ||
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
</PropertyGroup> | ||
<PropertyGroup> | ||
<DebugType>PdbOnly</DebugType> | ||
<Optimize>True</Optimize> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<Compile Include="VirtualDelegate.cs" /> | ||
</ItemGroup> | ||
</Project> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The caching code needs to be modified to cache based on either the class or the signature. I.e. this code:
and: