[runtime] Implement several xamarin_is_class_* variants for CoreCLR. (#11481)
When using the MonoVM, we compare MonoClass instances by pointer. This turns out a bit complicated for CoreCLR, because our MonoClass instances are not unique (there can be multiple MonoClass instances that refer to the same type), so instead implement helper methods that do the comparison. This also has the benefit of not requiring any memory allocations on CoreCLR.
This commit is contained in:
Родитель
3623a13ab2
Коммит
e4fbc5198b
|
@ -426,5 +426,52 @@ mono_class_is_valuetype (MonoClass * klass)
|
|||
return rv;
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_nsobject (MonoClass *cls)
|
||||
{
|
||||
return xamarin_bridge_is_class_of_type (cls, XamarinLookupTypes_Foundation_NSObject);
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_inativeobject (MonoClass *cls)
|
||||
{
|
||||
return xamarin_bridge_is_class_of_type (cls, XamarinLookupTypes_ObjCRuntime_INativeObject);
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_array (MonoClass *cls)
|
||||
{
|
||||
return xamarin_bridge_is_class_of_type (cls, XamarinLookupTypes_System_Array);
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_nsnumber (MonoClass *cls)
|
||||
{
|
||||
return xamarin_bridge_is_class_of_type (cls, XamarinLookupTypes_Foundation_NSNumber);
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_nsvalue (MonoClass *cls)
|
||||
{
|
||||
return xamarin_bridge_is_class_of_type (cls, XamarinLookupTypes_Foundation_NSValue);
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_nsstring (MonoClass *cls)
|
||||
{
|
||||
return xamarin_bridge_is_class_of_type (cls, XamarinLookupTypes_Foundation_NSString);
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_intptr (MonoClass *cls)
|
||||
{
|
||||
return xamarin_bridge_is_class_of_type (cls, XamarinLookupTypes_System_IntPtr);
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_string (MonoClass *cls)
|
||||
{
|
||||
return xamarin_bridge_is_class_of_type (cls, XamarinLookupTypes_System_String);
|
||||
}
|
||||
|
||||
#endif // CORECLR_RUNTIME
|
||||
|
|
|
@ -466,6 +466,15 @@
|
|||
OnlyDynamicUsage = false,
|
||||
OnlyCoreCLR = true,
|
||||
},
|
||||
|
||||
new XDelegate ("bool", "bool", "xamarin_bridge_is_class_of_type",
|
||||
"MonoObject *", "MonoObject *", "classobj",
|
||||
"enum XamarinLookupTypes", "Runtime.TypeLookup", "type"
|
||||
) {
|
||||
WrappedManagedFunction = "IsClassOfType",
|
||||
OnlyDynamicUsage = false,
|
||||
OnlyCoreCLR = true,
|
||||
},
|
||||
};
|
||||
delegates.CalculateLengths ();
|
||||
#><#+
|
||||
|
|
|
@ -57,7 +57,9 @@
|
|||
"MonoClass *", "klass",
|
||||
"MonoClass *", "klassc",
|
||||
"mono_bool", "check_interfaces"
|
||||
),
|
||||
) {
|
||||
XamarinRuntime = RuntimeMode.MonoVM,
|
||||
},
|
||||
|
||||
new Export ("mono_bool", "mono_class_is_valuetype",
|
||||
"MonoClass *", "klass"
|
||||
|
@ -355,13 +357,17 @@
|
|||
HasCoreCLRBridgeFunction = true,
|
||||
},
|
||||
|
||||
new Export ("MonoClass *", "mono_get_intptr_class"),
|
||||
new Export ("MonoClass *", "mono_get_intptr_class") {
|
||||
XamarinRuntime = RuntimeMode.MonoVM,
|
||||
},
|
||||
|
||||
new Export ("MonoClass *", "mono_get_string_class"),
|
||||
|
||||
new Export ("MonoImage *", "mono_get_corlib"),
|
||||
|
||||
new Export ("MonoClass *", "mono_get_array_class"),
|
||||
new Export ("MonoClass *", "mono_get_array_class") {
|
||||
XamarinRuntime = RuntimeMode.MonoVM,
|
||||
},
|
||||
|
||||
new Export ("MonoDomain *", "mono_get_root_domain") {
|
||||
XamarinRuntime = RuntimeMode.MonoVM,
|
||||
|
|
|
@ -291,6 +291,84 @@ xamarin_bridge_free_mono_signature (MonoMethodSignature **psig)
|
|||
*psig = NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_nsobject (MonoClass *cls)
|
||||
{
|
||||
// COOP: Reading managed data, must be in UNSAFE mode
|
||||
MONO_ASSERT_GC_UNSAFE;
|
||||
|
||||
return mono_class_is_subclass_of (cls, xamarin_get_nsobject_class (), false);
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_inativeobject (MonoClass *cls)
|
||||
{
|
||||
// COOP: Reading managed data, must be in UNSAFE mode
|
||||
MONO_ASSERT_GC_UNSAFE;
|
||||
|
||||
return mono_class_is_subclass_of (cls, xamarin_get_inativeobject_class (), true);
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_array (MonoClass *cls)
|
||||
{
|
||||
// COOP: Reading managed data, must be in UNSAFE mode
|
||||
MONO_ASSERT_GC_UNSAFE;
|
||||
|
||||
return mono_class_is_subclass_of (cls, mono_get_array_class (), false);
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_nsnumber (MonoClass *cls)
|
||||
{
|
||||
// COOP: Reading managed data, must be in UNSAFE mode
|
||||
MONO_ASSERT_GC_UNSAFE;
|
||||
|
||||
MonoClass *nsnumber_class = xamarin_get_nsnumber_class ();
|
||||
if (nsnumber_class == NULL)
|
||||
return false;
|
||||
|
||||
return mono_class_is_subclass_of (cls, nsnumber_class, false);
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_nsvalue (MonoClass *cls)
|
||||
{
|
||||
// COOP: Reading managed data, must be in UNSAFE mode
|
||||
MONO_ASSERT_GC_UNSAFE;
|
||||
|
||||
MonoClass *nsvalue_class = xamarin_get_nsvalue_class ();
|
||||
if (nsvalue_class == NULL)
|
||||
return false;
|
||||
|
||||
return mono_class_is_subclass_of (cls, nsvalue_class, false);
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_nsstring (MonoClass *cls)
|
||||
{
|
||||
// COOP: Reading managed data, must be in UNSAFE mode
|
||||
MONO_ASSERT_GC_UNSAFE;
|
||||
|
||||
MonoClass *nsstring_class = xamarin_get_nsstring_class ();
|
||||
if (nsstring_class == NULL)
|
||||
return false;
|
||||
|
||||
return mono_class_is_subclass_of (cls, nsstring_class, false);
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_intptr (MonoClass *cls)
|
||||
{
|
||||
return cls == mono_get_intptr_class ();
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_string (MonoClass *cls)
|
||||
{
|
||||
return cls == mono_get_string_class ();
|
||||
}
|
||||
|
||||
#if DOTNET
|
||||
|
||||
bool
|
||||
|
|
|
@ -376,72 +376,6 @@ xamarin_new_nsobject (id self, MonoClass *klass, GCHandle *exception_gchandle)
|
|||
return xamarin_gchandle_unwrap (obj);
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_nsobject (MonoClass *cls)
|
||||
{
|
||||
// COOP: Reading managed data, must be in UNSAFE mode
|
||||
MONO_ASSERT_GC_UNSAFE;
|
||||
|
||||
return mono_class_is_subclass_of (cls, xamarin_get_nsobject_class (), false);
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_inativeobject (MonoClass *cls)
|
||||
{
|
||||
// COOP: Reading managed data, must be in UNSAFE mode
|
||||
MONO_ASSERT_GC_UNSAFE;
|
||||
|
||||
return mono_class_is_subclass_of (cls, xamarin_get_inativeobject_class (), true);
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_array (MonoClass *cls)
|
||||
{
|
||||
// COOP: Reading managed data, must be in UNSAFE mode
|
||||
MONO_ASSERT_GC_UNSAFE;
|
||||
|
||||
return mono_class_is_subclass_of (cls, mono_get_array_class (), false);
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_nsnumber (MonoClass *cls)
|
||||
{
|
||||
// COOP: Reading managed data, must be in UNSAFE mode
|
||||
MONO_ASSERT_GC_UNSAFE;
|
||||
|
||||
MonoClass *nsnumber_class = xamarin_get_nsnumber_class ();
|
||||
if (nsnumber_class == NULL)
|
||||
return false;
|
||||
|
||||
return mono_class_is_subclass_of (cls, nsnumber_class, false);
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_nsvalue (MonoClass *cls)
|
||||
{
|
||||
// COOP: Reading managed data, must be in UNSAFE mode
|
||||
MONO_ASSERT_GC_UNSAFE;
|
||||
|
||||
MonoClass *nsvalue_class = xamarin_get_nsvalue_class ();
|
||||
if (nsvalue_class == NULL)
|
||||
return false;
|
||||
|
||||
return mono_class_is_subclass_of (cls, nsvalue_class, false);
|
||||
}
|
||||
|
||||
bool
|
||||
xamarin_is_class_nsstring (MonoClass *cls)
|
||||
{
|
||||
// COOP: Reading managed data, must be in UNSAFE mode
|
||||
MONO_ASSERT_GC_UNSAFE;
|
||||
|
||||
MonoClass *nsstring_class = xamarin_get_nsstring_class ();
|
||||
if (nsstring_class == NULL)
|
||||
return false;
|
||||
|
||||
return mono_class_is_subclass_of (cls, nsstring_class, false);
|
||||
}
|
||||
|
||||
// Returns if a MonoClass is nullable.
|
||||
// Will also return the element type (it the type is nullable, and if out pointer is not NULL).
|
||||
bool
|
||||
|
|
|
@ -311,7 +311,7 @@ xamarin_invoke_trampoline (enum TrampolineType type, id self, SEL sel, iterator_
|
|||
arg_frame [ofs] = mobj;
|
||||
ADD_TO_MONOOBJECT_RELEASE_LIST (mobj);
|
||||
LOGZ (" argument %i is a ref ptr/INativeObject %p: %p\n", i + 1, arg, arg_frame [ofs]);
|
||||
} else if (p_klass == mono_get_string_class ()) {
|
||||
} else if (xamarin_is_class_string (p_klass)) {
|
||||
MonoString *mstr = xamarin_nsstring_to_string (domain, *(NSString **) arg);
|
||||
arg_frame [ofs] = mstr;
|
||||
ADD_TO_MONOOBJECT_RELEASE_LIST (mstr);
|
||||
|
@ -426,7 +426,7 @@ xamarin_invoke_trampoline (enum TrampolineType type, id self, SEL sel, iterator_
|
|||
id id_arg = (id) arg;
|
||||
MonoClass *p_klass = mono_class_from_mono_type (p);
|
||||
ADD_TO_MONOOBJECT_RELEASE_LIST (p_klass);
|
||||
if (p_klass == mono_get_intptr_class ()) {
|
||||
if (xamarin_is_class_intptr (p_klass)) {
|
||||
arg_frame [ofs] = id_arg;
|
||||
arg_ptrs [i + mofs] = &arg_frame [frameofs];
|
||||
LOGZ (" argument %i is IntPtr: %p\n", i + 1, id_arg);
|
||||
|
@ -435,7 +435,7 @@ xamarin_invoke_trampoline (enum TrampolineType type, id self, SEL sel, iterator_
|
|||
arg_ptrs [i + mofs] = NULL;
|
||||
break;
|
||||
} else {
|
||||
if (p_klass == mono_get_string_class ()) {
|
||||
if (xamarin_is_class_string (p_klass)) {
|
||||
NSString *str = (NSString *) id_arg;
|
||||
MonoString *mstr = xamarin_nsstring_to_string (domain, str);
|
||||
arg_ptrs [i + mofs] = mstr;
|
||||
|
@ -639,7 +639,7 @@ xamarin_invoke_trampoline (enum TrampolineType type, id self, SEL sel, iterator_
|
|||
continue;
|
||||
} else if (value == NULL) {
|
||||
LOGZ (" writing back null to argument at index %i (%p)\n", i + 1, arg);
|
||||
} else if (p_klass == mono_get_string_class ()) {
|
||||
} else if (xamarin_is_class_string (p_klass)) {
|
||||
obj = xamarin_string_to_nsstring ((MonoString *) value, false);
|
||||
LOGZ (" writing back managed string %p to argument at index %i (%p)\n", value, i + 1, arg);
|
||||
} else if (xamarin_is_class_nsobject (p_klass)) {
|
||||
|
|
|
@ -102,7 +102,7 @@ xamarin_marshal_return_value_impl (MonoType *mtype, const char *type, MonoObject
|
|||
MonoType *original_tp = mono_reflection_type_get_type (original_type);
|
||||
xamarin_mono_object_release (&original_type);
|
||||
returnValue = xamarin_generate_conversion_to_native (retval, mono_class_get_type (r_klass), original_tp, method, (void *) INVALID_TOKEN_REF, exception_gchandle);
|
||||
} else if (r_klass == mono_get_string_class ()) {
|
||||
} else if (xamarin_is_class_string (r_klass)) {
|
||||
returnValue = xamarin_string_to_nsstring ((MonoString *) retval, retain);
|
||||
} else if (xamarin_is_class_array (r_klass)) {
|
||||
NSArray *rv = xamarin_managed_array_to_nsarray ((MonoArray *) retval, NULL, r_klass, exception_gchandle);
|
||||
|
@ -1245,7 +1245,7 @@ xamarin_managed_array_to_nsarray (MonoArray *array, MonoType *managed_type, Mono
|
|||
|
||||
xamarin_mono_object_release (&mclass);
|
||||
|
||||
if (e_klass == mono_get_string_class ()) {
|
||||
if (xamarin_is_class_string (e_klass)) {
|
||||
return xamarin_managed_string_array_to_nsarray (array, exception_gchandle);
|
||||
} else if (xamarin_is_class_nsobject (e_klass)) {
|
||||
return xamarin_managed_nsobject_array_to_nsarray (array, exception_gchandle);
|
||||
|
@ -1344,7 +1344,7 @@ xamarin_nsarray_to_managed_array (NSArray *array, MonoType *managed_type, MonoCl
|
|||
xamarin_mono_object_release (&mclass);
|
||||
|
||||
MonoClass *e_klass = mono_class_get_element_class (managed_class);
|
||||
if (e_klass == mono_get_string_class ()) {
|
||||
if (xamarin_is_class_string (e_klass)) {
|
||||
return xamarin_nsarray_to_managed_string_array (array, exception_gchandle);
|
||||
} else if (xamarin_is_class_nsobject (e_klass)) {
|
||||
return xamarin_nsarray_to_managed_nsobject_array (array, managed_type, e_klass, exception_gchandle);
|
||||
|
|
|
@ -63,6 +63,18 @@ enum XamarinGCHandleType : int {
|
|||
XamarinGCHandleTypePinned = 3,
|
||||
};
|
||||
|
||||
// Keep in sync with Runtime.LookupTypes in Runtime.CoreCLR.cs
|
||||
enum XamarinLookupTypes : int {
|
||||
XamarinLookupTypes_System_Array,
|
||||
XamarinLookupTypes_System_String,
|
||||
XamarinLookupTypes_System_IntPtr,
|
||||
XamarinLookupTypes_Foundation_NSNumber,
|
||||
XamarinLookupTypes_Foundation_NSObject,
|
||||
XamarinLookupTypes_Foundation_NSString,
|
||||
XamarinLookupTypes_Foundation_NSValue,
|
||||
XamarinLookupTypes_ObjCRuntime_INativeObject,
|
||||
};
|
||||
|
||||
extern bool mono_use_llvm; // this is defined inside mono
|
||||
|
||||
#if DEBUG
|
||||
|
|
|
@ -167,6 +167,8 @@ bool xamarin_is_class_nsnumber (MonoClass *cls);
|
|||
bool xamarin_is_class_nsvalue (MonoClass *cls);
|
||||
bool xamarin_is_class_nsstring (MonoClass *cls);
|
||||
bool xamarin_is_class_nullable (MonoClass *cls, MonoClass **element_type, GCHandle *exception_gchandle);
|
||||
bool xamarin_is_class_intptr (MonoClass *cls);
|
||||
bool xamarin_is_class_string (MonoClass *cls);
|
||||
MonoClass * xamarin_get_nullable_type (MonoClass *cls, GCHandle *exception_gchandle);
|
||||
MonoType * xamarin_get_parameter_type (MonoMethod *managed_method, int index);
|
||||
MonoObject * xamarin_get_nsobject_with_type_for_ptr (id self, bool owns, MonoType* type, GCHandle *exception_gchandle);
|
||||
|
|
|
@ -23,6 +23,18 @@ using MonoObjectPtr=System.IntPtr;
|
|||
namespace ObjCRuntime {
|
||||
|
||||
public partial class Runtime {
|
||||
// Keep in sync with XamarinLookupTypes in coreclr-bridge.h
|
||||
internal enum TypeLookup {
|
||||
System_Array,
|
||||
System_String,
|
||||
System_IntPtr,
|
||||
Foundation_NSNumber,
|
||||
Foundation_NSObject,
|
||||
Foundation_NSString,
|
||||
Foundation_NSValue,
|
||||
ObjCRuntime_INativeObject,
|
||||
}
|
||||
|
||||
// This struct must be kept in sync with the _MonoObject struct in coreclr-bridge.h
|
||||
[StructLayout (LayoutKind.Sequential)]
|
||||
internal struct MonoObject {
|
||||
|
@ -75,6 +87,49 @@ namespace ObjCRuntime {
|
|||
throw new InvalidOperationException ($"Could not find any assemblies named {name}");
|
||||
}
|
||||
|
||||
unsafe static bool IsClassOfType (MonoObject *typeobj, TypeLookup match)
|
||||
{
|
||||
return IsClassOfType ((Type) GetMonoObjectTarget (typeobj), match);
|
||||
}
|
||||
|
||||
static bool IsClassOfType (Type type, TypeLookup match)
|
||||
{
|
||||
var rv = false;
|
||||
|
||||
switch (match) {
|
||||
case TypeLookup.System_Array:
|
||||
rv = type.IsArray;
|
||||
break;
|
||||
case TypeLookup.System_String:
|
||||
rv = type == typeof (System.String);
|
||||
break;
|
||||
case TypeLookup.System_IntPtr:
|
||||
rv = type == typeof (System.IntPtr);
|
||||
break;
|
||||
case TypeLookup.Foundation_NSNumber:
|
||||
rv = typeof (Foundation.NSNumber).IsAssignableFrom (type);
|
||||
break;
|
||||
case TypeLookup.Foundation_NSObject:
|
||||
rv = typeof (Foundation.NSObject).IsAssignableFrom (type);
|
||||
break;
|
||||
case TypeLookup.Foundation_NSString:
|
||||
rv = typeof (Foundation.NSString).IsAssignableFrom (type);
|
||||
break;
|
||||
case TypeLookup.Foundation_NSValue:
|
||||
rv = typeof (Foundation.NSValue).IsAssignableFrom (type);
|
||||
break;
|
||||
case TypeLookup.ObjCRuntime_INativeObject:
|
||||
rv = typeof (ObjCRuntime.INativeObject).IsAssignableFrom (type);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException (nameof (type));
|
||||
}
|
||||
|
||||
log_coreclr ($"IsClassOfType ({type}, {match}) => {rv}");
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static IntPtr CreateGCHandle (IntPtr gchandle, GCHandleType type)
|
||||
{
|
||||
// It's valid to create a GCHandle to a null value.
|
||||
|
|
Загрузка…
Ссылка в новой задаче