diff --git a/runtime/runtime.m b/runtime/runtime.m index c838994cc378..8e829b39a987 100644 --- a/runtime/runtime.m +++ b/runtime/runtime.m @@ -131,7 +131,7 @@ }; enum InitializationFlags : int { - /* unused = 0x01,*/ + InitializationFlagsIsPartialStaticRegistrar = 0x01, /* unused = 0x02,*/ InitializationFlagsDynamicRegistrar = 0x04, /* unused = 0x08,*/ @@ -1014,10 +1014,12 @@ -(void) xamarinSetGCHandle: (int) gc_handle; } void -xamarin_add_registration_map (struct MTRegistrationMap *map) +xamarin_add_registration_map (struct MTRegistrationMap *map, bool partial) { // COOP: no managed memory access: any mode options.RegistrationData = map; + if (partial) + options.flags = (InitializationFlags) (options.flags | InitializationFlagsIsPartialStaticRegistrar); // Sort the type map according to Class qsort (map->map, map->map_count, sizeof (MTClassMap), compare_mtclassmap); @@ -1894,11 +1896,42 @@ -(void) xamarinSetGCHandle: (int) gc_handle; set_raw_gchandle (self, gchandle); } +static int +find_user_type_index (MTClassMap *map, int lo, int hi, Class cls) +{ + if (hi >= lo) { + int mid = lo + (hi - lo) / 2; + + if (map [mid].handle == cls) + return mid; + + if ((intptr_t) map [mid].handle > (intptr_t) cls) + return find_user_type_index (map, lo, mid - 1, cls); + + return find_user_type_index (map, mid + 1, hi, cls); + } + + return -1; +} + static inline bool is_user_type (id self) { + Class cls = object_getClass (self); + + if (options.RegistrationData != NULL && options.RegistrationData->map_count > 0) { + MTClassMap *map = options.RegistrationData->map; + int idx = find_user_type_index (map, 0, options.RegistrationData->map_count - 1, cls); + if (idx >= 0) + return (map [idx].flags & MTTypeFlagsUserType) == MTTypeFlagsUserType; + // If using the partial static registrar, we need to continue + // If full static registrar, we can return false + if ((options.flags & InitializationFlagsIsPartialStaticRegistrar) != InitializationFlagsIsPartialStaticRegistrar) + return false; + } + // COOP: no managed memory access: any mode - return class_getInstanceMethod (object_getClass (self), @selector (xamarinSetGCHandle:)) != NULL; + return class_getInstanceMethod (cls, @selector (xamarinSetGCHandle:)) != NULL; } #if defined(DEBUG_REF_COUNTING) diff --git a/runtime/xamarin/runtime.h b/runtime/xamarin/runtime.h index 277ff3fb884b..bfb443fd4d5b 100644 --- a/runtime/xamarin/runtime.h +++ b/runtime/xamarin/runtime.h @@ -71,6 +71,7 @@ static const uint32_t INVALID_TOKEN_REF = 0xFFFFFFFF; enum MTTypeFlags { MTTypeFlagsNone = 0, MTTypeFlagsCustomType = 1, // not a platform type + MTTypeFlagsUserType = 2, // not a wrapped type }; typedef struct __attribute__((packed)) { @@ -203,7 +204,7 @@ void xamarin_unhandled_exception_handler (MonoObject *exc, gpointer user_data) void xamarin_ftnptr_exception_handler (guint32 gchandle); void xamarin_create_classes (); const char * xamarin_skip_encoding_flags (const char *encoding); -void xamarin_add_registration_map (struct MTRegistrationMap *map); +void xamarin_add_registration_map (struct MTRegistrationMap *map, bool partial); uint32_t xamarin_find_protocol_wrapper_type (uint32_t token_ref); void xamarin_release_block_on_main_thread (void *obj); diff --git a/src/ObjCRuntime/Runtime.cs b/src/ObjCRuntime/Runtime.cs index 76901b0d5cd6..ab4a161aa2bb 100644 --- a/src/ObjCRuntime/Runtime.cs +++ b/src/ObjCRuntime/Runtime.cs @@ -76,6 +76,7 @@ internal enum MTTypeFlags : uint { None = 0, CustomType = 1, + UserType = 2, } [StructLayout (LayoutKind.Sequential, Pack = 1)] @@ -131,7 +132,7 @@ internal struct Trampolines { [Flags] internal enum InitializationFlags : int { - /* unused = 0x01 */ + IsPartialStaticRegistrar= 0x01, /* unused = 0x02,*/ DynamicRegistrar = 0x04, /* unused = 0x08,*/ diff --git a/tools/common/StaticRegistrar.cs b/tools/common/StaticRegistrar.cs index ec629c5dfdd9..52a26776fe12 100644 --- a/tools/common/StaticRegistrar.cs +++ b/tools/common/StaticRegistrar.cs @@ -2743,6 +2743,9 @@ void Specialize (AutoIndentStringBuilder sb) if (!isPlatformType) flags |= MTTypeFlags.CustomType; + if (!@class.IsWrapper && !@class.IsModel) + flags |= MTTypeFlags.UserType; + CheckNamespace (@class, exceptions); token_ref = CreateTokenReference (@class.Type, TokenType.TypeDef); map.AppendLine ("{{ NULL, 0x{1:X} /* #{3} '{0}' => '{2}' */, (MTTypeFlags) ({4}) /* {5} */ }},", @@ -3100,7 +3103,7 @@ void Specialize (AutoIndentStringBuilder sb) map.AppendLine ("};"); - map_init.AppendLine ("xamarin_add_registration_map (&__xamarin_registration_map);"); + map_init.AppendLine ("xamarin_add_registration_map (&__xamarin_registration_map, {0});", string.IsNullOrEmpty (single_assembly) ? "false" : "true"); map_init.AppendLine ("}"); sb.WriteLine (map.ToString ()); @@ -4993,5 +4996,6 @@ internal enum MTTypeFlags : uint { None = 0, CustomType = 1, + UserType = 2, } }