Convert Runtime.GetBlockWrapperCreator, Runtime.CreateBlockProxy and Runtime.Get[Generic]MethodFromToken to use GCHandle.

The native methods xamarin_get_[generic_]method_from_token are a bit unusual
in that they return an actual GCHandle. This is for performance reasons, since
in some cases their return value is passed as parameters to other function
calls to managed code, in which case we need the GCHandle. This way we avoid
round-tripping a GCHandle multiple times.
This commit is contained in:
Rolf Bjarne Kvinge 2020-05-04 11:08:30 +02:00
Родитель a7d68ddfbc
Коммит 632fd10328
4 изменённых файлов: 30 добавлений и 23 удалений

Просмотреть файл

@ -50,16 +50,18 @@
OnlyDynamicUsage = false,
},
new XDelegate ("MonoObject *", "IntPtr", "xamarin_get_block_wrapper_creator",
"MonoObject *", "IntPtr", "method",
new XDelegate ("GCHandle->MonoObject *", "IntPtr", "xamarin_get_block_wrapper_creator",
"GCHandle->MonoReflectionMethod *", "IntPtr", "method",
"int", "int", "parameter"
) {
WrappedManagedFunction = "GetBlockWrapperCreator",
OnlyDynamicUsage = true,
},
new XDelegate ("MonoObject *", "IntPtr", "xamarin_create_block_proxy",
"MonoObject *", "IntPtr", "method",
new XDelegate ("GCHandle->MonoObject *", "IntPtr", "xamarin_create_block_proxy",
// Don't convert the 'method' parameter, we already have a GCHandle
// available we can use.
"GCHandle", "IntPtr", "method",
"void *", "IntPtr", "block"
) {
WrappedManagedFunction = "CreateBlockProxy",
@ -145,15 +147,17 @@
OnlyDynamicUsage = false,
},
new XDelegate ("MonoReflectionMethod *", "IntPtr", "xamarin_get_method_from_token",
// Do not automatically unwrap the return value, because otherwise we might need to immediately wrap it in a GCHandle again.
new XDelegate ("GCHandle", "IntPtr", "xamarin_get_method_from_token",
"unsigned int", "uint", "token_ref"
) {
WrappedManagedFunction = "GetMethodFromToken",
OnlyDynamicUsage = false,
},
new XDelegate ("MonoReflectionMethod *", "IntPtr", "xamarin_get_generic_method_from_token",
"MonoObject *", "IntPtr", "obj",
// Do not automatically unwrap the return value, because otherwise we might need to immediately wrap it in a GCHandle again.
new XDelegate ("GCHandle", "IntPtr", "xamarin_get_generic_method_from_token",
"GCHandle->MonoObject *", "IntPtr", "obj_handle",
"unsigned int", "uint", "token_ref"
) {
WrappedManagedFunction = "GetGenericMethodFromToken",

Просмотреть файл

@ -2074,7 +2074,7 @@ static MonoReferenceQueue *block_wrapper_queue;
* that can be used to create a new delegate, this returns the method that can
* create the method
*/
static MonoObject *
static GCHandle
get_method_block_wrapper_creator (MonoMethod *method, int par, guint32 *exception_gchandle)
{
// COOP: accesses managed memory: unsafe mode.
@ -2098,12 +2098,12 @@ get_method_block_wrapper_creator (MonoMethod *method, int par, guint32 *exceptio
pthread_mutex_unlock (&wrapper_hash_lock);
if (res != NULL){
// PRINT ("Found match: %x", (int) res);
return res;
return xamarin_gchandle_new (res, false);
}
res = xamarin_get_block_wrapper_creator ((MonoObject *) mono_method_get_object (mono_domain_get (), method, NULL), (int) par, exception_gchandle);
res = xamarin_get_block_wrapper_creator (mono_method_get_object (mono_domain_get (), method, NULL), (int) par, exception_gchandle);
if (*exception_gchandle != 0)
return NULL;
return INVALID_GCHANDLE;
// PRINT ("New value: %x", (int) res);
nmp = (MethodAndPar *) malloc (sizeof (MethodAndPar));
@ -2114,7 +2114,7 @@ get_method_block_wrapper_creator (MonoMethod *method, int par, guint32 *exceptio
MONO_EXIT_GC_SAFE;
mono_g_hash_table_insert (xamarin_wrapper_hash, nmp, res);
pthread_mutex_unlock (&wrapper_hash_lock);
return res;
return xamarin_gchandle_new (res, false);
}
void
@ -2149,15 +2149,15 @@ xamarin_get_delegate_for_block_parameter (MonoMethod *method, guint32 token_ref,
MONO_ASSERT_GC_UNSAFE;
MonoObject *delegate = NULL;
GCHandle obj_handle = INVALID_GCHANDLE;
if (nativeBlock == NULL)
return NULL;
MonoObject *obj;
if (token_ref != INVALID_TOKEN_REF) {
obj = (MonoObject *) xamarin_get_method_from_token (token_ref, exception_gchandle);
obj_handle = xamarin_get_method_from_token (token_ref, exception_gchandle);
} else {
obj = get_method_block_wrapper_creator (method, par, exception_gchandle);
obj_handle = get_method_block_wrapper_creator (method, par, exception_gchandle);
}
if (*exception_gchandle != 0)
goto cleanup;
@ -2165,7 +2165,7 @@ xamarin_get_delegate_for_block_parameter (MonoMethod *method, guint32 token_ref,
/* retain or copy (if it's a stack block) the block */
nativeBlock = _Block_copy (nativeBlock);
delegate = xamarin_create_block_proxy (obj, nativeBlock, exception_gchandle);
delegate = xamarin_create_block_proxy (obj_handle, nativeBlock, exception_gchandle);
if (*exception_gchandle != 0) {
_Block_release (nativeBlock);
delegate = NULL;
@ -2183,6 +2183,7 @@ xamarin_get_delegate_for_block_parameter (MonoMethod *method, guint32 token_ref,
pthread_mutex_unlock (&wrapper_hash_lock);
cleanup:
xamarin_gchandle_free (obj_handle);
return delegate;
}
@ -2662,7 +2663,7 @@ xamarin_get_managed_method_for_token (guint32 token_ref, guint32 *exception_gcha
{
MonoReflectionMethod *reflection_method;
reflection_method = xamarin_get_method_from_token (token_ref, exception_gchandle);
reflection_method = (MonoReflectionMethod *) xamarin_gchandle_unwrap (xamarin_get_method_from_token (token_ref, exception_gchandle));
if (*exception_gchandle != 0) return NULL;
return xamarin_get_reflection_method_method (reflection_method);

Просмотреть файл

@ -454,12 +454,12 @@ namespace ObjCRuntime {
static IntPtr GetBlockWrapperCreator (IntPtr method, int parameter)
{
return ObjectWrapper.Convert (GetBlockWrapperCreator ((MethodInfo) ObjectWrapper.Convert (method), parameter));
return AllocGCHandle (GetBlockWrapperCreator ((MethodInfo) GetGCHandleTarget (method), parameter));
}
static IntPtr CreateBlockProxy (IntPtr method, IntPtr block)
{
return ObjectWrapper.Convert (CreateBlockProxy ((MethodInfo) ObjectWrapper.Convert (method), block));
return AllocGCHandle (CreateBlockProxy ((MethodInfo) GetGCHandleTarget (method), block));
}
static IntPtr CreateDelegateProxy (IntPtr method, IntPtr @delegate, IntPtr signature, uint token_ref)
@ -661,7 +661,7 @@ namespace ObjCRuntime {
{
var method = Class.ResolveMethodTokenReference (token_ref);
if (method != null)
return ObjectWrapper.Convert (method);
return AllocGCHandle (method);
return IntPtr.Zero;
}
@ -672,11 +672,11 @@ namespace ObjCRuntime {
if (method == null)
return IntPtr.Zero;
var nsobj = ObjectWrapper.Convert (obj) as NSObject;
var nsobj = GetGCHandleTarget (obj) as NSObject;
if (nsobj == null)
throw ErrorHelper.CreateError (8023, $"An instance object is required to construct a closed generic method for the open generic method: {method.DeclaringType.FullName}.{method.Name} (token reference: 0x{token_ref:X}). Please file a bug report at https://github.com/xamarin/xamarin-macios/issues/new.");
return ObjectWrapper.Convert (FindClosedMethod (nsobj.GetType (), method));
return AllocGCHandle (FindClosedMethod (nsobj.GetType (), method));
}
static IntPtr TryGetOrConstructNSObjectWrapped (IntPtr ptr)

Просмотреть файл

@ -3906,7 +3906,7 @@ namespace Registrar {
// no locking should be required here, it doesn't matter if we overwrite the field (it'll be the same value).
body.WriteLine ("if (!managed_method) {");
body.Write ("MonoReflectionMethod *reflection_method = ");
body.Write ("GCHandle reflection_method_handle = ");
if (isGeneric)
body.Write ("xamarin_get_generic_method_from_token (mthis, ");
else
@ -3917,6 +3917,8 @@ namespace Registrar {
} else {
body.WriteLine ("0x{0:X}, &exception_gchandle);", token_ref);
}
body.Write ("MonoReflectionMethod *reflection_method = (MonoReflectionMethod *) xamarin_gchandle_unwrap (reflection_method_handle);");
body.WriteLine ("if (exception_gchandle != 0) goto exception_handling;");
body.WriteLine ("managed_method = xamarin_get_reflection_method_method (reflection_method);");
if (merge_bodies)