diff --git a/runtime/runtime.m b/runtime/runtime.m index 2db8a577526c..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,14 +1014,15 @@ -(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 - map->custom_type_count, sizeof (MTClassMap), compare_mtclassmap); - qsort (&map->map [map->map_count - map->custom_type_count], map->custom_type_count, sizeof (MTClassMap), compare_mtclassmap); + qsort (map->map, map->map_count, sizeof (MTClassMap), compare_mtclassmap); } /* @@ -1895,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 df5e85ca8579..bfb443fd4d5b 100644 --- a/runtime/xamarin/runtime.h +++ b/runtime/xamarin/runtime.h @@ -68,9 +68,16 @@ typedef struct __attribute__((packed)) { } MTTokenReference; 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)) { void *handle; uint32_t /* MTTokenReference */ type_reference; + uint32_t /* MTTypeFlags */ flags; } MTClassMap; typedef struct __attribute__((packed)) { @@ -109,7 +116,6 @@ struct MTRegistrationMap { const MTProtocolMap protocols; int assembly_count; int map_count; - int custom_type_count; int full_token_reference_count; int skipped_map_count; int protocol_wrapper_count; @@ -198,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/Class.cs b/src/ObjCRuntime/Class.cs index d348b57f167e..62dec18e7e0d 100644 --- a/src/ObjCRuntime/Class.cs +++ b/src/ObjCRuntime/Class.cs @@ -241,7 +241,7 @@ unsafe static IntPtr FindClass (Type type, out bool is_custom_type) continue; var rv = map->map [i].handle; - is_custom_type = i >= (map->map_count - map->custom_type_count); + is_custom_type = (map->map [i].flags & Runtime.MTTypeFlags.CustomType) == Runtime.MTTypeFlags.CustomType; #if LOG_TYPELOAD Console.WriteLine ($"FindClass ({type.FullName}, {is_custom_type}): 0x{rv.ToString ("x")} = {class_getName (rv)}."); #endif @@ -331,12 +331,7 @@ internal unsafe static Type FindType (IntPtr @class, out bool is_custom_type) } // Find the ObjC class pointer in our map - var mapIndex = FindMapIndex (map->map, 0, map->map_count - map->custom_type_count - 1, @class); - if (mapIndex == -1) { - mapIndex = FindMapIndex (map->map, map->map_count - map->custom_type_count, map->map_count - 1, @class); - is_custom_type = true; - } - + var mapIndex = FindMapIndex (map->map, 0, map->map_count - 1, @class); if (mapIndex == -1) { #if LOG_TYPELOAD Console.WriteLine ($"FindType (0x{@class:X} = {Marshal.PtrToStringAuto (class_getName (@class))}) => found no type."); @@ -344,6 +339,8 @@ internal unsafe static Type FindType (IntPtr @class, out bool is_custom_type) return null; } + is_custom_type = (map->map [mapIndex].flags & Runtime.MTTypeFlags.CustomType) == Runtime.MTTypeFlags.CustomType; + Type type = class_to_type [mapIndex]; if (type != null) return type; diff --git a/src/ObjCRuntime/Runtime.cs b/src/ObjCRuntime/Runtime.cs index 26a0d45fcadf..ab4a161aa2bb 100644 --- a/src/ObjCRuntime/Runtime.cs +++ b/src/ObjCRuntime/Runtime.cs @@ -65,17 +65,25 @@ internal unsafe struct MTRegistrationMap { public MTProtocolMap protocol_map; public int assembly_count; public int map_count; - public int custom_type_count; public int full_token_reference_count; public int skipped_map_count; public int protocol_wrapper_count; public int protocol_count; } + [Flags] + internal enum MTTypeFlags : uint + { + None = 0, + CustomType = 1, + UserType = 2, + } + [StructLayout (LayoutKind.Sequential, Pack = 1)] internal struct MTClassMap { public IntPtr handle; public uint type_reference; + public MTTypeFlags flags; } [StructLayout (LayoutKind.Sequential, Pack = 1)] @@ -124,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 92f1bb605070..52a26776fe12 100644 --- a/tools/common/StaticRegistrar.cs +++ b/tools/common/StaticRegistrar.cs @@ -2725,24 +2725,6 @@ void Specialize (AutoIndentStringBuilder sb) allTypes.Add (@class); } - // Move all the custom types to the end of the list, respecting - // existing order (so that a derived type always comes after - // its base type; the Types.Values has that property, and we - // need to keep it that way). - - var mappedEnd = allTypes.Count; - var counter = 0; - while (counter < mappedEnd) { - if (!IsPlatformType (allTypes [counter].Type)) { - var t = allTypes [counter]; - allTypes.RemoveAt (counter); - allTypes.Add (t); - mappedEnd--; - } else { - counter++; - } - } - if (string.IsNullOrEmpty (single_assembly)) { foreach (var assembly in GetAssemblies ()) registered_assemblies.Add (GetAssemblyName (assembly)); @@ -2750,23 +2732,27 @@ void Specialize (AutoIndentStringBuilder sb) registered_assemblies.Add (single_assembly); } - var customTypeCount = 0; foreach (var @class in allTypes) { var isPlatformType = IsPlatformType (@class.Type); + var flags = MTTypeFlags.None; skip.Clear (); uint token_ref = uint.MaxValue; if (!@class.IsProtocol && !@class.IsCategory) { if (!isPlatformType) - customTypeCount++; - + 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}' */ }},", + map.AppendLine ("{{ NULL, 0x{1:X} /* #{3} '{0}' => '{2}' */, (MTTypeFlags) ({4}) /* {5} */ }},", @class.ExportedName, CreateTokenReference (@class.Type, TokenType.TypeDef), - GetAssemblyQualifiedName (@class.Type), map_entries); + GetAssemblyQualifiedName (@class.Type), map_entries, + (int) flags, flags); map_dict [@class] = map_entries++; bool use_dynamic; @@ -3110,7 +3096,6 @@ void Specialize (AutoIndentStringBuilder sb) } map.AppendLine ("{0},", count); map.AppendLine ("{0},", i); - map.AppendLine ("{0},", customTypeCount); map.AppendLine ("{0},", full_token_reference_count); map.AppendLine ("{0},", skipped_types.Count); map.AppendLine ("{0},", protocol_wrapper_map.Count); @@ -3118,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 ()); @@ -5005,4 +4990,12 @@ class AdoptsAttribute : Attribute { public string ProtocolType { get; set; } } + + [Flags] + internal enum MTTypeFlags : uint + { + None = 0, + CustomType = 1, + UserType = 2, + } }