[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:
Rolf Bjarne Kvinge 2016-11-01 19:34:56 +01:00 коммит произвёл Sebastien Pouliot
Родитель dddd243dfd
Коммит 7728c4cd19
12 изменённых файлов: 301 добавлений и 195 удалений

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

@ -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 = &registration_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
//