[registrar] Use metadata tokens instead of strings to find types and methods. (#1085)
Use metadata tokens instead of strings to find types and methods. This makes the code to find methods more compact (a lot less strings in the executable, and additionally in most cases a compact representation (32-bit integer) of the corresponding metadata token and additional information can be used, which results in less executable code (fewer parameters to methods, etc)), resulting in smaller executables. Size savings are around 200kb for dont link apps, and 20-60kb for linked apps (this obviously varies a lot depending on how much has to registered by the registrar). | | Before | After | Diff | |----------------|--------------:|--------------:|------------------:| | dontlink/32bit | 102.810.144 | 102.609.456 | -200.688 = -0,20% | | dontlink/64bit | 107.420.576 | 107.221.792 | -198.784 = -0,19% | | linksdk/32bit | 40.957.296 | 40.936.864 | -20.432 = -0,05% | | linksdk/64bit | 43.113.136 | 43.093.936 | -19.200 = -0,04% | | linkall/32bit | 38.410.032 | 38.348.288 | -61.744 = -0,16% | | linkall/64bit | 40.315.200 | 40.267.344 | -47.856 = -0,12% | Additionally I've removed the `lazy_map` dictionary, which we populated at startup and was used to map between Class instances and the corresponding managed type's FullName, and instead iterate over a native array of Class -> metadata token mappings whenever we need to look up the managed type for a certain Class instance. This is slightly slower for each type we need to look up (for a non-linked app there might be a 2000-3000 entries in the native array, which would be iterated instead of using a hashtable lookup), but it's only done once per type and there's a significant startup memory improvement. For a non-linked test app I get the following using the Xamarin profiler: | | Before | After | Diff | |-------------------|--------:|--------:|----------------:| | Memory allocated | 2,8 MB | 2,4 MB | -0,4 MB = -14 % | | Objects allocated | 43678 | 38463 | -5215 = -12 % | | Private bytes | 26,6 MB | 24,4 MB | -2,2 MB = -8,3% | | Working set | 26,6 MB | 24,4 MB | -2,2 MB = -8,3% |
This commit is contained in:
Родитель
dddd243dfd
Коммит
7728c4cd19
|
@ -1449,4 +1449,22 @@ This usually indicates a bug in Xamarin.iOS; please file a bug at [http://bugzil
|
|||
|
||||
This indicates a bug in Xamarin.iOS. Please file a bug at [http://bugzilla.xamarin.com](https://bugzilla.xamarin.com/enter_bug.cgi?product=iOS).
|
||||
|
||||
<h3><
|
||||
<h3><a name="MT8019"/>MT8019: Could not find the assembly * in the loaded assemblies.</h3>
|
||||
|
||||
This indicates a bug in Xamarin.iOS. Please file a bug at [http://bugzilla.xamarin.com](https://bugzilla.xamarin.com/enter_bug.cgi?product=iOS).
|
||||
|
||||
<h3><a name="MT8020"/>MT8020: Could not find the module with MetadataToken * in the assembly *.</h3>
|
||||
|
||||
This indicates a bug in Xamarin.iOS. Please file a bug at [http://bugzilla.xamarin.com](https://bugzilla.xamarin.com/enter_bug.cgi?product=iOS).
|
||||
|
||||
<h3><a name="MT8021"/>MT8021: Unknown implicit token type: *.</h3>
|
||||
|
||||
This indicates a bug in Xamarin.iOS. Please file a bug at [http://bugzilla.xamarin.com](https://bugzilla.xamarin.com/enter_bug.cgi?product=iOS).
|
||||
|
||||
<h3><a name="MT8022"/>MT8022: Expected the token reference * to be a *, but it's a *. Please file a bug report at http://bugzilla.xamarin.com.</h3>
|
||||
|
||||
This indicates a bug in Xamarin.iOS. Please file a bug at [http://bugzilla.xamarin.com](https://bugzilla.xamarin.com/enter_bug.cgi?product=iOS).
|
||||
|
||||
<h3><a name="MT8023"/>MT8023: An instance object is required to construct a closed generic method for the open generic method: * (token reference: *). Please file a bug report at http://bugzilla.xamarin.com.</h3>
|
||||
|
||||
This indicates a bug in Xamarin.iOS. Please file a bug at [http://bugzilla.xamarin.com](https://bugzilla.xamarin.com/enter_bug.cgi?product=iOS).
|
||||
|
|
|
@ -91,21 +91,6 @@
|
|||
"MonoObject *", "IntPtr", "managed_obj"
|
||||
) { WrappedManagedFunction = "UnregisterNSObject" },
|
||||
|
||||
new XDelegate ("MonoReflectionMethod *", "IntPtr", "xamarin_get_method_direct",
|
||||
"const char *", "IntPtr", "typeptr",
|
||||
"const char *", "IntPtr", "methodptr",
|
||||
"int", "int", "paramCount",
|
||||
"const char **", "IntPtr*", "paramptr"
|
||||
) { WrappedManagedFunction = "GetMethodDirect" },
|
||||
|
||||
new XDelegate ("MonoReflectionMethod *", "IntPtr", "xamarin_get_generic_method_direct",
|
||||
"MonoObject *", "IntPtr", "obj",
|
||||
"const char *", "IntPtr", "typeptr",
|
||||
"const char *", "IntPtr", "methodptr",
|
||||
"int", "int", "paramCount",
|
||||
"const char **", "IntPtr*", "paramptr"
|
||||
) { WrappedManagedFunction = "GetGenericMethodDirect" },
|
||||
|
||||
new XDelegate ("MonoObject *", "IntPtr", "xamarin_try_get_or_construct_nsobject",
|
||||
"id", "IntPtr", "obj"
|
||||
) { WrappedManagedFunction = "TryGetOrConstructNSObjectWrapped" },
|
||||
|
@ -116,6 +101,15 @@
|
|||
"void *", "IntPtr", "type"
|
||||
) { WrappedManagedFunction = "GetINativeObject_Dynamic" },
|
||||
|
||||
new XDelegate ("MonoReflectionMethod *", "IntPtr", "xamarin_get_method_from_token",
|
||||
"unsigned int", "uint", "token_ref"
|
||||
) { WrappedManagedFunction = "GetMethodFromToken" },
|
||||
|
||||
new XDelegate ("MonoReflectionMethod *", "IntPtr", "xamarin_get_generic_method_from_token",
|
||||
"MonoObject *", "IntPtr", "obj",
|
||||
"unsigned int", "uint", "token_ref"
|
||||
) { WrappedManagedFunction = "GetGenericMethodFromToken" },
|
||||
|
||||
new XDelegate ("MonoObject *", "IntPtr", "xamarin_get_inative_object_static",
|
||||
"id", "IntPtr", "obj",
|
||||
"bool", "bool", "owns",
|
||||
|
|
|
@ -85,13 +85,6 @@ xamarin_extension_main_callback xamarin_extension_main = NULL;
|
|||
|
||||
/* Local variable */
|
||||
|
||||
typedef struct {
|
||||
struct MTRegistrationMap *map;
|
||||
int total_count; // SUM (registration_map->map_count)
|
||||
} RegistrationData;
|
||||
|
||||
static RegistrationData registration_data;
|
||||
|
||||
static MonoClass *inativeobject_class;
|
||||
static MonoClass *nsobject_class;
|
||||
|
||||
|
@ -141,7 +134,7 @@ struct InitializationOptions {
|
|||
enum InitializationFlags flags;
|
||||
struct Delegates* Delegates;
|
||||
struct Trampolines* Trampolines;
|
||||
RegistrationData* RegistrationData;
|
||||
struct MTRegistrationMap* RegistrationData;
|
||||
enum MarshalObjectiveCExceptionMode MarshalObjectiveCExceptionMode;
|
||||
enum MarshalManagedExceptionMode MarshalManagedExceptionMode;
|
||||
};
|
||||
|
@ -908,9 +901,7 @@ void
|
|||
xamarin_add_registration_map (struct MTRegistrationMap *map)
|
||||
{
|
||||
// COOP: no managed memory access: any mode
|
||||
map->next = registration_data.map;
|
||||
registration_data.map = map;
|
||||
registration_data.total_count += map->map_count;
|
||||
options.RegistrationData = map;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1192,7 +1183,6 @@ xamarin_initialize ()
|
|||
|
||||
options.Delegates = &delegates;
|
||||
options.Trampolines = &trampolines;
|
||||
options.RegistrationData = ®istration_data;
|
||||
options.MarshalObjectiveCExceptionMode = xamarin_marshal_objectivec_exception_mode;
|
||||
options.MarshalManagedExceptionMode = xamarin_marshal_managed_exception_mode;
|
||||
|
||||
|
|
|
@ -51,21 +51,36 @@ typedef struct {
|
|||
const char *argument_semantic;
|
||||
} MTProperty;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const char *_typename;
|
||||
// This structure completely describes everything required to resolve a metadata token
|
||||
typedef struct MTFullTokenReference {
|
||||
const char *assembly_name; /* the name of the assembly */
|
||||
uint32_t module_token;
|
||||
uint32_t token;
|
||||
} MTFullTokenReference;
|
||||
|
||||
// This structure is packed to be exactly 32 bits
|
||||
// If 'is_full_reference' is 1, then the remaining bits are an index into a table of MTFullTokenReference.
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t is_full_reference:1;
|
||||
uint8_t assembly_index:7; /* 0-based index into the '__xamarin_registration_assemblies' array. Max 127 (registered) assemblies before a full token reference has to be used */
|
||||
uint32_t token:24; /* RID of the corresponding metadata token. The exact type of metadata token depends on the context where the token reference is used. */
|
||||
} MTTokenReference;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
void *handle;
|
||||
uint32_t /* MTTokenReference */ type_reference;
|
||||
} MTClassMap;
|
||||
|
||||
struct MTRegistrationMap;
|
||||
|
||||
struct MTRegistrationMap {
|
||||
struct MTRegistrationMap *next;
|
||||
const char **assembly;
|
||||
MTClassMap *map;
|
||||
MTFullTokenReference *full_token_references;
|
||||
int assembly_count;
|
||||
int map_count;
|
||||
int custom_type_count;
|
||||
int full_token_reference_count;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
@ -189,8 +204,8 @@ bool xamarin_has_nsobject (id obj, guint32 *exception_gchandle);
|
|||
MonoObject* xamarin_get_nsobject (id obj, guint32 *exception_gchandle);
|
||||
id xamarin_get_handle_for_inativeobject (MonoObject *obj, guint32 *exception_gchandle);
|
||||
void xamarin_unregister_nsobject (id native_obj, MonoObject *managed_obj, guint32 *exception_gchandle);
|
||||
MonoReflectionMethod* xamarin_get_method_direct (const char *typeptr, const char *methodptr, int paramCount, const char **parameters, guint32 *exception_gchandle);
|
||||
MonoReflectionMethod* xamarin_get_generic_method_direct (MonoObject *self, const char *typeptr, const char *methodptr, int paramCount, const char **parameters, guint32 *exception_gchandle);
|
||||
MonoReflectionMethod* xamarin_get_method_from_token (guint32 token_ref, guint32 *exception_gchandle);
|
||||
MonoReflectionMethod* xamarin_get_generic_method_from_token (MonoObject *obj, guint32 token_ref, guint32 *exception_gchandle);
|
||||
MonoObject* xamarin_try_get_or_construct_nsobject (id obj, guint32 *exception_gchandle);
|
||||
MonoObject* xamarin_get_inative_object_dynamic (id obj, bool owns, void *type, guint32 *exception_gchandle);
|
||||
MonoObject* xamarin_get_inative_object_static (id obj, bool owns, const char *type_name, const char *iface_name, guint32 *exception_gchandle);
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
// Copyright 2011 - 2015 Xamarin Inc. All rights reserved.
|
||||
//
|
||||
|
||||
// #define LOG_TYPELOAD
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
|
@ -25,51 +27,14 @@ namespace XamCore.ObjCRuntime {
|
|||
|
||||
internal unsafe static void Initialize (Runtime.InitializationOptions* options)
|
||||
{
|
||||
if (options->RegistrationData != null) {
|
||||
var map = options->RegistrationData->map;
|
||||
var lazy_map = Runtime.Registrar.GetRegistrationMap (options->RegistrationData->total_count);
|
||||
while (map != null) {
|
||||
RegisterMap (map, lazy_map);
|
||||
map = map->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
var map = options->RegistrationMap;
|
||||
|
||||
static unsafe void RegisterMap (Runtime.MTRegistrationMap *registration_map, Dictionary<IntPtr, LazyMapEntry> lazy_map)
|
||||
{
|
||||
var map = registration_map->map;
|
||||
var size = registration_map->map_count;
|
||||
var first_custom_type = size - registration_map->custom_type_count;
|
||||
if (map == null)
|
||||
return;
|
||||
|
||||
#if LOG_MAP
|
||||
Runtime.NSLog ("RegisterMap () {0} assemblies with {1} types", registration_map->assembly_count, registration_map->map_count);
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < registration_map->assembly_count; i++) {
|
||||
var assembly = Marshal.PtrToStringAuto (Marshal.ReadIntPtr (registration_map->assembly, i * IntPtr.Size));
|
||||
#if LOG_MAP
|
||||
Runtime.NSLog (" {0}", assembly);
|
||||
#endif
|
||||
Runtime.Registrar.SetAssemblyRegistered (assembly);
|
||||
}
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (map [i].handle == IntPtr.Zero)
|
||||
continue;
|
||||
|
||||
sbyte* ptr = map [i].typename;
|
||||
int num = 0;
|
||||
while (0 != *ptr++)
|
||||
num++;
|
||||
|
||||
var entry = new LazyMapEntry ();
|
||||
entry.Typename = new String (map [i].typename, 0, num, System.Text.Encoding.UTF8);
|
||||
entry.IsCustomType = i >= first_custom_type;
|
||||
lazy_map [map [i].handle] = entry;
|
||||
|
||||
#if LOG_MAP
|
||||
Runtime.NSLog (" {0} => 0x{1} IsCustomType: {2}", entry.Typename, map [i].handle.ToString ("x"), entry.IsCustomType);
|
||||
#endif
|
||||
for (int i = 0; i < map->assembly_count; i++) {
|
||||
var ptr = Marshal.ReadIntPtr (map->assembly, i * IntPtr.Size);
|
||||
Runtime.Registrar.SetAssemblyRegistered (Marshal.PtrToStringAuto (ptr));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,6 +136,145 @@ namespace XamCore.ObjCRuntime {
|
|||
return Runtime.Registrar.GetMethods (t);
|
||||
}
|
||||
|
||||
internal unsafe static Type FindType (IntPtr @class, out bool is_custom_type)
|
||||
{
|
||||
var map = Runtime.options->RegistrationMap;
|
||||
Runtime.MTClassMap? entry = null;
|
||||
|
||||
is_custom_type = false;
|
||||
|
||||
if (map == null) {
|
||||
#if LOG_TYPELOAD
|
||||
Console.WriteLine ($"FindType (0x{@class:X} = {Marshal.PtrToStringAuto (class_getName (@class))}) => found no map.");
|
||||
#endif
|
||||
return null;
|
||||
}
|
||||
|
||||
// Find the ObjC class pointer in our map
|
||||
// Potential improvement: order the type handles after loading them, which means we could do a binary search here.
|
||||
// A binary search will likely be faster than a dictionary for any real-world scenario (and if slower, not much slower),
|
||||
// but it would need a lot less memory (very little when sorting, could probably use stack memory, and then nothing at all afterwards).
|
||||
for (int i = 0; i < map->map_count; i++) {
|
||||
if (map->map [i].handle != @class)
|
||||
continue;
|
||||
|
||||
entry = map->map [i];
|
||||
is_custom_type = i >= (map->map_count - map->custom_type_count);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!entry.HasValue) {
|
||||
#if LOG_TYPELOAD
|
||||
Console.WriteLine ($"FindType (0x{@class:X} = {Marshal.PtrToStringAuto (class_getName (@class))}) => found no type.");
|
||||
#endif
|
||||
return null;
|
||||
}
|
||||
|
||||
// Resolve the map entry we found to a managed type
|
||||
var member = ResolveTokenReference (entry.Value.type_reference, 0x02000000);
|
||||
var type = member as Type;
|
||||
|
||||
if (type == null && member != null)
|
||||
throw ErrorHelper.CreateError (8022, $"Expected the token reference 0x{entry.Value.type_reference:X} to be a type, but it's a {member.GetType ().Name}. Please file a bug report at http://bugzilla.xamarin.com.");
|
||||
|
||||
#if LOG_TYPELOAD
|
||||
Console.WriteLine ($"FindType (0x{@class:X} = {Marshal.PtrToStringAuto (class_getName (@class))}) => {type.FullName}; is custom: {is_custom_type} (token reference: 0x{entry.Value.type_reference:X}).");
|
||||
#endif
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
internal unsafe static MemberInfo ResolveFullTokenReference (uint token_reference)
|
||||
{
|
||||
// sizeof (MTFullTokenReference) = IntPtr.Size + 4 + 4
|
||||
var entry = Runtime.options->RegistrationMap->full_token_references + (IntPtr.Size + 8) * (int) (token_reference >> 1);
|
||||
var assembly_name = Marshal.PtrToStringAuto (Marshal.ReadIntPtr (entry));
|
||||
var module_token = (uint) Marshal.ReadInt32 (entry + IntPtr.Size);
|
||||
var token = (uint) Marshal.ReadInt32 (entry + IntPtr.Size + 4);
|
||||
|
||||
#if LOG_TYPELOAD
|
||||
Console.WriteLine ($"ResolveFullTokenReference (0x{token_reference:X}) assembly name: {assembly_name} module token: 0x{module_token:X} token: 0x{token:X}.");
|
||||
#endif
|
||||
|
||||
var assembly = ResolveAssembly (assembly_name);
|
||||
var module = ResolveModule (assembly, module_token);
|
||||
return ResolveToken (module, token);
|
||||
}
|
||||
|
||||
internal unsafe static MemberInfo ResolveTokenReference (uint token_reference, uint implicit_token_type)
|
||||
{
|
||||
var map = Runtime.options->RegistrationMap;
|
||||
|
||||
if ((token_reference & 0x1) == 0x1)
|
||||
return ResolveFullTokenReference (token_reference);
|
||||
|
||||
var assembly_index = (token_reference >> 1) & 0x7F;
|
||||
uint token = (token_reference >> 8) + implicit_token_type;
|
||||
|
||||
#if LOG_TYPELOAD
|
||||
Console.WriteLine ($"ResolveTokenReference (0x{token_reference:X}) assembly index: {assembly_index} token: 0x{token:X}.");
|
||||
#endif
|
||||
|
||||
var assembly_name = Marshal.PtrToStringAuto (Marshal.ReadIntPtr (map->assembly, (int) assembly_index * IntPtr.Size));
|
||||
var assembly = ResolveAssembly (assembly_name);
|
||||
var module = ResolveModule (assembly, 0x1);
|
||||
|
||||
return ResolveToken (module, token | implicit_token_type);
|
||||
}
|
||||
|
||||
static MemberInfo ResolveToken (Module module, uint token)
|
||||
{
|
||||
// Finally resolve the token.
|
||||
var token_type = token & 0xFF000000;
|
||||
switch (token & 0xFF000000) {
|
||||
case 0x02000000: // TypeDef
|
||||
var type = module.ResolveType ((int) token);
|
||||
#if LOG_TYPELOAD
|
||||
Console.WriteLine ($"ResolveToken (0x{token:X}) => Type: {type.FullName}");
|
||||
#endif
|
||||
return type;
|
||||
case 0x06000000: // Method
|
||||
var method = module.ResolveMethod ((int) token);
|
||||
#if LOG_TYPELOAD
|
||||
Console.WriteLine ($"ResolveToken (0x{token:X}) => Method: {method.DeclaringType.FullName}.{method.Name}");
|
||||
#endif
|
||||
return method;
|
||||
default:
|
||||
throw ErrorHelper.CreateError (8021, $"Unknown implicit token type: 0x{token_type}.");
|
||||
}
|
||||
}
|
||||
|
||||
static Module ResolveModule (Assembly assembly, uint token)
|
||||
{
|
||||
foreach (var mod in assembly.GetModules ()) {
|
||||
if (mod.MetadataToken != token)
|
||||
continue;
|
||||
|
||||
#if LOG_TYPELOAD
|
||||
Console.WriteLine ($"ResolveModule (\"{assembly.FullName}\", 0x{token:X}): {mod.Name}.");
|
||||
#endif
|
||||
return mod;
|
||||
}
|
||||
|
||||
throw ErrorHelper.CreateError (8020, $"Could not find the module with MetadataToken 0x{token:X} in the assembly {assembly}.");
|
||||
}
|
||||
|
||||
static Assembly ResolveAssembly (string assembly_name)
|
||||
{
|
||||
// Find the assembly. We've already loaded all the assemblies that contain registered types, so just look at those assemblies.
|
||||
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies ()) {
|
||||
if (assembly_name != asm.GetName ().Name)
|
||||
continue;
|
||||
|
||||
#if LOG_TYPELOAD
|
||||
Console.WriteLine ($"ResolveAssembly (\"{assembly_name}\"): {asm.FullName}.");
|
||||
#endif
|
||||
return asm;
|
||||
}
|
||||
|
||||
throw ErrorHelper.CreateError (8019, $"Could not find the assembly ${assembly_name} in the loaded assemblies.");
|
||||
}
|
||||
|
||||
/*
|
||||
Type must have been previously registered.
|
||||
*/
|
||||
|
|
|
@ -69,7 +69,6 @@ namespace XamCore.Registrar {
|
|||
|
||||
class DynamicRegistrar : Registrar {
|
||||
Dictionary<IntPtr, ObjCType> type_map;
|
||||
Dictionary <IntPtr, LazyMapEntry> lazy_map;
|
||||
Dictionary <Type, Dictionary <IntPtr, MethodDescription>> method_map;
|
||||
Dictionary <string, object> registered_assemblies; // Use Dictionary instead of HashSet to avoid pulling in System.Core.dll.
|
||||
|
||||
|
@ -89,13 +88,6 @@ namespace XamCore.Registrar {
|
|||
custom_type_map = new Dictionary <Type, object> (Runtime.TypeEqualityComparer);
|
||||
}
|
||||
|
||||
public Dictionary<IntPtr, LazyMapEntry> GetRegistrationMap (int initial_capacity)
|
||||
{
|
||||
if (lazy_map == null)
|
||||
lazy_map = new Dictionary <IntPtr, LazyMapEntry> (initial_capacity, Runtime.IntPtrEqualityComparer);
|
||||
return lazy_map;
|
||||
}
|
||||
|
||||
protected override bool SkipRegisterAssembly (Assembly assembly)
|
||||
{
|
||||
return registered_assemblies != null && registered_assemblies.ContainsKey (GetAssemblyName (assembly));
|
||||
|
@ -939,13 +931,12 @@ namespace XamCore.Registrar {
|
|||
do {
|
||||
if (type_map.TryGetValue (@class, out type))
|
||||
return type.Type;
|
||||
|
||||
LazyMapEntry entry;
|
||||
if (lazy_map != null && lazy_map.TryGetValue (@class, out entry)) {
|
||||
lazy_map.Remove (@class);
|
||||
var tp = Type.GetType (entry.Typename);
|
||||
|
||||
bool is_custom_type;
|
||||
var tp = Class.FindType (@class, out is_custom_type);
|
||||
if (tp != null) {
|
||||
type = RegisterType (tp);
|
||||
if (entry.IsCustomType)
|
||||
if (is_custom_type)
|
||||
AddCustomType (tp);
|
||||
return tp;
|
||||
}
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
//
|
||||
// IDynamicRegistrar.cs:
|
||||
//
|
||||
// Authors:
|
||||
// Rolf Bjarne Kvinge <rolf@xamarin.com>
|
||||
//
|
||||
// Copyright 2013 - 2014 Xamarin Inc.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
using XamCore.Foundation;
|
||||
using XamCore.ObjCRuntime;
|
||||
|
||||
namespace XamCore.Registrar {
|
||||
#if !COREBUILD
|
||||
class LazyMapEntry {
|
||||
public string Typename;
|
||||
public bool IsCustomType;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -50,24 +50,20 @@ namespace XamCore.ObjCRuntime {
|
|||
|
||||
internal static DynamicRegistrar Registrar;
|
||||
|
||||
internal unsafe struct RegistrationData {
|
||||
public MTRegistrationMap *map;
|
||||
public int total_count;
|
||||
}
|
||||
|
||||
internal unsafe struct MTRegistrationMap {
|
||||
public MTRegistrationMap *next;
|
||||
public IntPtr assembly;
|
||||
public MTClassMap *map;
|
||||
public IntPtr full_token_references; /* array of MTFullTokenReference */
|
||||
public int assembly_count;
|
||||
public int map_count;
|
||||
public int custom_type_count;
|
||||
public int full_token_reference_count;
|
||||
}
|
||||
|
||||
internal unsafe struct MTClassMap {
|
||||
public sbyte *name;
|
||||
public sbyte *typename;
|
||||
[StructLayout (LayoutKind.Sequential, Pack = 1)]
|
||||
internal struct MTClassMap {
|
||||
public IntPtr handle;
|
||||
public uint type_reference;
|
||||
}
|
||||
|
||||
/* Keep Delegates, Trampolines and InitializationOptions in sync with monotouch-glue.m */
|
||||
|
@ -108,7 +104,7 @@ namespace XamCore.ObjCRuntime {
|
|||
public InitializationFlags Flags;
|
||||
public Delegates *Delegates;
|
||||
public Trampolines *Trampolines;
|
||||
public RegistrationData *RegistrationData;
|
||||
public MTRegistrationMap *RegistrationMap;
|
||||
public MarshalObjectiveCExceptionMode MarshalObjectiveCExceptionMode;
|
||||
public MarshalManagedExceptionMode MarshalManagedExceptionMode;
|
||||
|
||||
|
@ -541,29 +537,38 @@ namespace XamCore.ObjCRuntime {
|
|||
NativeObjectHasDied (native_obj, ObjectWrapper.Convert (managed_obj) as NSObject);
|
||||
}
|
||||
|
||||
static unsafe IntPtr GetMethodDirect (IntPtr typeptr, IntPtr methodptr, int paramCount, IntPtr* paramptr)
|
||||
static unsafe IntPtr GetMethodFromToken (uint token_ref)
|
||||
{
|
||||
var method = FindMethod (typeptr, methodptr, paramCount, paramptr);
|
||||
var method = Class.ResolveTokenReference (token_ref, 0x06000000);
|
||||
|
||||
var mb = method as MethodBase;
|
||||
if (method != null && mb == null)
|
||||
throw ErrorHelper.CreateError (8022, $"Expected the token reference 0x{token_ref:X} to be a method, but it's a {method.GetType ().Name}. Please file a bug report at http://bugzilla.xamarin.com.");
|
||||
|
||||
if (method != null)
|
||||
return ObjectWrapper.Convert (method);
|
||||
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
static unsafe IntPtr GetGenericMethodDirect (IntPtr obj, IntPtr typeptr, IntPtr methodptr, int paramCount, IntPtr* paramptr)
|
||||
static unsafe IntPtr GetGenericMethodFromToken (IntPtr obj, uint token_ref)
|
||||
{
|
||||
#if MONOMAC
|
||||
throw new NotSupportedException ();
|
||||
#else
|
||||
var method = FindMethod (typeptr, methodptr, paramCount, paramptr);
|
||||
var method = Class.ResolveTokenReference (token_ref, 0x06000000);
|
||||
if (method == null)
|
||||
return IntPtr.Zero;
|
||||
|
||||
var mb = method as MethodBase;
|
||||
if (mb == null)
|
||||
throw ErrorHelper.CreateError (8022, $"Expected the token reference 0x{token_ref:X} to be a method, but it's a {method.GetType ().Name}. Please file a bug report at http://bugzilla.xamarin.com.");
|
||||
|
||||
var nsobj = ObjectWrapper.Convert (obj) as NSObject;
|
||||
if (nsobj == null)
|
||||
throw new NotSupportedException ();
|
||||
throw ErrorHelper.CreateError (8023, $"An instance object is required to construct a closed generic method for the open generic method: {mb.DeclaringType.FullName}.{mb.Name} (token reference: 0x{token_ref:X}). Please file a bug report at http://bugzilla.xamarin.com.");
|
||||
|
||||
return ObjectWrapper.Convert (DynamicRegistrar.FindClosedMethod (nsobj.GetType (), method));
|
||||
return ObjectWrapper.Convert (DynamicRegistrar.FindClosedMethod (nsobj.GetType (), mb));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -1456,7 +1456,6 @@ SHARED_SOURCES = \
|
|||
ObjCRuntime/ErrorHelper.cs \
|
||||
ObjCRuntime/Exceptions.cs \
|
||||
ObjCRuntime/ExceptionMode.cs \
|
||||
ObjCRuntime/IDynamicRegistrar.cs \
|
||||
ObjCRuntime/Method.cs \
|
||||
ObjCRuntime/MethodDescription.cs \
|
||||
ObjCRuntime/NSStringMarshal.cs \
|
||||
|
|
|
@ -35,21 +35,12 @@ namespace XamarinTests.ObjCRuntime {
|
|||
[Register ("__registration_test_CLASS")]
|
||||
class RegistrationTestClass : NSObject {}
|
||||
|
||||
static FieldInfo GetPrivateField (Type type, string name)
|
||||
{
|
||||
var fld = type.GetField (name, BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (fld != null)
|
||||
return fld;
|
||||
if (type.BaseType == null)
|
||||
return null;
|
||||
return GetPrivateField (type.BaseType, name);
|
||||
}
|
||||
|
||||
public static Registrars CurrentRegistrar {
|
||||
get {
|
||||
var registrar = typeof(Runtime).GetField ("Registrar", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).GetValue (null);
|
||||
var dict = (System.Collections.IDictionary) GetPrivateField (registrar.GetType (), "lazy_map").GetValue (registrar);
|
||||
var is_static = dict.Contains (Class.GetHandle (typeof (RegistrationTestClass)));
|
||||
var find_type = typeof (Class).GetMethod ("FindType", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
var type_to_find = typeof (RegistrationTestClass);
|
||||
var type = (Type) find_type.Invoke (null, new object [] { Class.GetHandle (type_to_find), false });
|
||||
var is_static = type_to_find == type;
|
||||
if (is_static) {
|
||||
return Registrars.Static;
|
||||
} else {
|
||||
|
|
|
@ -1648,6 +1648,10 @@ namespace XamCore.Registrar {
|
|||
|
||||
Dictionary<Body, Body> bodies = new Dictionary<Body, Body> ();
|
||||
|
||||
AutoIndentStringBuilder full_token_references = new AutoIndentStringBuilder ();
|
||||
uint full_token_reference_count;
|
||||
List<string> registered_assemblies = new List<string> ();
|
||||
|
||||
static bool IsPlatformType (TypeReference type)
|
||||
{
|
||||
if (type.IsNested)
|
||||
|
@ -2311,6 +2315,13 @@ namespace XamCore.Registrar {
|
|||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty (single_assembly)) {
|
||||
foreach (var assembly in GetAssemblies ())
|
||||
registered_assemblies.Add (GetAssemblyName (assembly));
|
||||
} else {
|
||||
registered_assemblies.Add (single_assembly);
|
||||
}
|
||||
|
||||
var customTypeCount = 0;
|
||||
foreach (var @class in allTypes) {
|
||||
var isPlatformType = IsPlatformType (@class.Type);
|
||||
|
@ -2322,7 +2333,10 @@ namespace XamCore.Registrar {
|
|||
customTypeCount++;
|
||||
|
||||
CheckNamespace (@class, exceptions);
|
||||
map.AppendLine ("{{\"{0}\", \"{1}\", NULL }},", @class.ExportedName, GetAssemblyQualifiedName (@class.Type));
|
||||
map.AppendLine ("{{ NULL, 0x{1:X} /* '{0}' => '{2}' */ }},",
|
||||
@class.ExportedName,
|
||||
CreateTokenReference (@class.Type, TokenType.TypeDef),
|
||||
GetAssemblyQualifiedName (@class.Type));
|
||||
|
||||
bool use_dynamic;
|
||||
|
||||
|
@ -2526,19 +2540,12 @@ namespace XamCore.Registrar {
|
|||
sb.WriteLine ();
|
||||
}
|
||||
|
||||
map.AppendLine ("{ NULL, NULL, NULL },");
|
||||
map.AppendLine ("{ NULL, 0 },");
|
||||
map.AppendLine ("};");
|
||||
map.AppendLine ();
|
||||
|
||||
map.AppendLine ("static const char *__xamarin_registration_assemblies []= {");
|
||||
int count = 0;
|
||||
var registered_assemblies = new List<string> ();
|
||||
if (string.IsNullOrEmpty (single_assembly)) {
|
||||
foreach (var assembly in GetAssemblies ())
|
||||
registered_assemblies.Add (GetAssemblyName (assembly));
|
||||
} else {
|
||||
registered_assemblies.Add (single_assembly);
|
||||
}
|
||||
foreach (var assembly in registered_assemblies) {
|
||||
count++;
|
||||
if (count > 1)
|
||||
|
@ -2551,15 +2558,22 @@ namespace XamCore.Registrar {
|
|||
map.AppendLine ("};");
|
||||
map.AppendLine ();
|
||||
|
||||
map.AppendLine ("static struct MTFullTokenReference __xamarin_token_references [] = {");
|
||||
map.AppendLine (full_token_references);
|
||||
map.AppendLine ("};");
|
||||
map.AppendLine ();
|
||||
|
||||
map.AppendLine ("static struct MTRegistrationMap __xamarin_registration_map = {");
|
||||
map.AppendLine ("NULL,");
|
||||
map.AppendLine ("__xamarin_registration_assemblies,");
|
||||
map.AppendLine ("__xamarin_class_map,");
|
||||
map.AppendLine ("__xamarin_token_references,");
|
||||
map.AppendLine ("{0},", count);
|
||||
map.AppendLine ("{0},", i);
|
||||
map.AppendLine ("{0}", customTypeCount);
|
||||
map.AppendLine ("{0},", customTypeCount);
|
||||
map.AppendLine ("{0}", full_token_reference_count);
|
||||
map.AppendLine ("};");
|
||||
|
||||
|
||||
map_init.AppendLine ("xamarin_add_registration_map (&__xamarin_registration_map);");
|
||||
map_init.AppendLine ("}");
|
||||
|
||||
|
@ -2668,7 +2682,6 @@ namespace XamCore.Registrar {
|
|||
var descriptiveMethodName = method.DescriptiveMethodName;
|
||||
var name = GetUniqueTrampolineName ("native_to_managed_trampoline_" + descriptiveMethodName);
|
||||
var isVoid = returntype.FullName == "System.Void";
|
||||
var arguments = new List<string> ();
|
||||
var merge_bodies = true;
|
||||
|
||||
switch (method.CurrentTrampoline) {
|
||||
|
@ -2733,6 +2746,8 @@ namespace XamCore.Registrar {
|
|||
setup_call_stack.Indentation = indent;
|
||||
setup_return.Indentation = indent;
|
||||
|
||||
var token_ref = CreateTokenReference (method.Method, TokenType.Method);
|
||||
|
||||
// A comment describing the managed signature
|
||||
if (trace) {
|
||||
nslog_start.Indentation = sb.Indentation;
|
||||
|
@ -3357,48 +3372,22 @@ namespace XamCore.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) {");
|
||||
if (num_arg > 0) {
|
||||
body.Write ("const char *paramptr[{0}] = {{ ", num_arg);
|
||||
for (int i = 0; i < num_arg; i++) {
|
||||
string paramtype;
|
||||
if (isGeneric) {
|
||||
paramtype = GetAssemblyQualifiedName (method.Method.Parameters [i].ParameterType);
|
||||
} else {
|
||||
paramtype = GetAssemblyQualifiedName (method.Parameters [i]);
|
||||
}
|
||||
|
||||
if (merge_bodies) {
|
||||
body.Write ("r{0}", arguments.Count);
|
||||
arguments.Add (paramtype);
|
||||
} else {
|
||||
body.Write ("\"{0}\"", paramtype);
|
||||
}
|
||||
if (i < num_arg - 1)
|
||||
body.Write (", ");
|
||||
}
|
||||
body.WriteLine (" };");
|
||||
}
|
||||
|
||||
body.Write ("managed_method = ");
|
||||
body.Write ("MonoReflectionMethod *reflection_method = ");
|
||||
if (isGeneric)
|
||||
body.Write ("xamarin_get_reflection_method_method (xamarin_get_generic_method_direct (mthis, ");
|
||||
body.Write ("xamarin_get_generic_method_from_token (mthis, ");
|
||||
else
|
||||
body.Write ("xamarin_get_reflection_method_method (xamarin_get_method_direct(");
|
||||
body.Write ("xamarin_get_method_from_token (");
|
||||
|
||||
if (merge_bodies) {
|
||||
body.WriteLine ("r{2}, r{3}, {0}, {1}, &exception_gchandle));",
|
||||
num_arg, num_arg > 0 ? "paramptr" : "NULL",
|
||||
arguments.Count, arguments.Count + 1);
|
||||
arguments.Add (GetAssemblyQualifiedName (method.Method.DeclaringType));
|
||||
arguments.Add (method.Method.Name);
|
||||
body.WriteLine ("token_ref, &exception_gchandle);");
|
||||
} else {
|
||||
body.WriteLine ("\"{0}\", \"{1}\", {2}, {3}, &exception_gchandle));",
|
||||
GetAssemblyQualifiedName (method.Method.DeclaringType),
|
||||
method.Method.Name, num_arg, num_arg > 0 ? "paramptr" : "NULL");
|
||||
body.WriteLine ("0x{0:X}, &exception_gchandle);", token_ref);
|
||||
}
|
||||
body.WriteLine ("if (exception_gchandle != 0) goto exception_handling;");
|
||||
body.WriteLine ("managed_method = xamarin_get_reflection_method_method (reflection_method);");
|
||||
if (merge_bodies)
|
||||
body.WriteLine ("*managed_method_ptr = managed_method;");
|
||||
|
||||
body.WriteLine ("}");
|
||||
|
||||
if (!isStatic && !isInstanceCategory && !isCtor) {
|
||||
|
@ -3470,10 +3459,9 @@ namespace XamCore.Registrar {
|
|||
methods.Append (", ").Append (ToObjCParameterType (method.Method.Parameters [i].ParameterType, descriptiveMethodName, exceptions, method.Method));
|
||||
methods.Append (" ").Append ("p").Append (i.ToString ());
|
||||
}
|
||||
for (int i = 0; i < arguments.Count; i++)
|
||||
methods.Append (", const char *").Append ("r").Append (i.ToString ());
|
||||
if (isCtor)
|
||||
methods.Append (", bool* call_super");
|
||||
methods.Append (", uint32_t token_ref");
|
||||
methods.AppendLine (")");
|
||||
methods.AppendLine (body);
|
||||
methods.AppendLine ();
|
||||
|
@ -3501,10 +3489,9 @@ namespace XamCore.Registrar {
|
|||
paramCount--;
|
||||
for (int i = 0; i < paramCount; i++)
|
||||
sb.Write (", p{0}", i);
|
||||
for (int i = 0; i < arguments.Count; i++)
|
||||
sb.Write (", \"").Write (arguments [i]).Write ("\"");
|
||||
if (isCtor)
|
||||
sb.Write (", &call_super");
|
||||
sb.Write (", 0x{0:X}", token_ref);
|
||||
sb.WriteLine (");");
|
||||
if (isCtor) {
|
||||
sb.WriteLine ("if (call_super && rv) {");
|
||||
|
@ -3555,6 +3542,38 @@ namespace XamCore.Registrar {
|
|||
}
|
||||
}
|
||||
|
||||
uint CreateFullTokenReference (MemberReference member)
|
||||
{
|
||||
var rv = (full_token_reference_count++ << 1) + 1;
|
||||
full_token_references.AppendFormat ("\t\t{{ /* #{3} = 0x{4:X} */ \"{0}\", 0x{1:X}, 0x{2:X} }},\n", GetAssemblyName (member.Module.Assembly), member.Module.MetadataToken.ToUInt32 (), member.MetadataToken.ToUInt32 (), full_token_reference_count, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
uint CreateTokenReference (MemberReference member, TokenType implied_type)
|
||||
{
|
||||
var token = member.MetadataToken;
|
||||
|
||||
/* We can't create small token references if we're in partial mode, because we may have multiple arrays of registered assemblies, and no way of saying which one we refer to with the assembly index */
|
||||
if (IsSingleAssembly)
|
||||
return CreateFullTokenReference (member);
|
||||
|
||||
/* If the implied token type doesn't match, we need a full token */
|
||||
if (implied_type != token.TokenType)
|
||||
return CreateFullTokenReference (member);
|
||||
|
||||
/* For small token references the only valid module is the first one */
|
||||
if (member.Module.MetadataToken.ToInt32 () != 1)
|
||||
return CreateFullTokenReference (member);
|
||||
|
||||
/* The assembly must be a registered one, and only within the first 128 assemblies */
|
||||
var assembly_name = GetAssemblyName (member.Module.Assembly);
|
||||
var index = registered_assemblies.IndexOf (assembly_name);
|
||||
if (index < 0 || index > 127)
|
||||
return CreateFullTokenReference (member);
|
||||
|
||||
return (token.RID << 8) + ((uint) index << 1);
|
||||
}
|
||||
|
||||
public void GeneratePInvokeWrappersStart (AutoIndentStringBuilder hdr, AutoIndentStringBuilder decls, AutoIndentStringBuilder mthds)
|
||||
{
|
||||
header = hdr;
|
||||
|
|
|
@ -344,6 +344,11 @@ namespace Xamarin.Bundler {
|
|||
// MT8016 Unable to convert delegate to block for the return value for the method {0}.{1}, because the input isn't a delegate, it's a {1}. Please file a bug at http://bugzilla.xamarin.com.
|
||||
// MT8017 ** reserved Xamarin.Mac **
|
||||
// MT8018 Internal consistency error. Please file a bug report at http://bugzilla.xamarin.com.
|
||||
// MT8019 Could not find the assembly {0} in the loaded assemblies.
|
||||
// MT8020 Could not find the module with MetadataToken {0} in the assembly {1}.
|
||||
// MT8021 Unknown implicit token type: 0x{0}.
|
||||
// MT8022 Expected the token reference 0x{0} to be a {1}, but it's a {2}. Please file a bug report at http://bugzilla.xamarin.com.
|
||||
// MT8023 An instance object is required to construct a closed generic method for the open generic method: {0}.{1} (token reference: 0x{2}). Please file a bug report at http://bugzilla.xamarin.com.
|
||||
// MT9xxx Licensing
|
||||
//
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче