xamarin-macios/tools/linker/CoreTypeMapStep.cs

252 строки
7.9 KiB
C#
Исходник Обычный вид История

2016-04-21 15:57:02 +03:00
//
// CoreTypeMapStep.cs
2016-04-21 15:57:02 +03:00
//
// Authors:
// Sebastien Pouliot <sebastien@xamarin.com>
//
// Copyright 2012-2013 Xamarin Inc.
//
using System;
using System.Collections.Generic;
using System.Diagnostics;
2016-04-21 15:57:02 +03:00
using Mono.Cecil;
using Mono.Linker.Steps;
using Mono.Tuner;
using Xamarin.Linker;
using Xamarin.Tuner;
2016-04-21 15:57:02 +03:00
namespace MonoTouch.Tuner {
// This class is shared between Xamarin.Mac and Xamarin.iOS
public class CoreTypeMapStep :
#if NET
ConfigurationAwareStep
#else
TypeMapStep
#endif
{
#if NET
protected override string Name { get; } = "CoreTypeMap";
protected override int ErrorCode { get; } = 2390;
Profile Profile => new Profile (Configuration);
// Get the reverse mapping from assemblies to assemblies which reference them directly.
Dictionary<AssemblyDefinition, HashSet<AssemblyDefinition>> _reversedReferences;
Dictionary<AssemblyDefinition, HashSet<AssemblyDefinition>> GetReversedReferences ()
{
if (_reversedReferences != null)
return _reversedReferences;
_reversedReferences = new Dictionary<AssemblyDefinition, HashSet<AssemblyDefinition>> ();
foreach (var assembly in Configuration.Assemblies) {
if (!_reversedReferences.ContainsKey (assembly))
_reversedReferences.Add (assembly, new HashSet<AssemblyDefinition> ());
foreach (var reference in assembly.MainModule.AssemblyReferences) {
var resolvedReference = Configuration.Context.GetLoadedAssembly (reference.Name);
if (resolvedReference == null)
continue;
if (!_reversedReferences.TryGetValue (resolvedReference, out var referrers)) {
referrers = new HashSet<AssemblyDefinition> ();
_reversedReferences.Add (resolvedReference, referrers);
}
referrers.Add (assembly);
}
}
return _reversedReferences;
}
2016-04-21 15:57:02 +03:00
Dictionary<AssemblyDefinition, bool> _transitivelyReferencesProduct;
bool TransitivelyReferencesProduct (AssemblyDefinition assembly)
{
if (_transitivelyReferencesProduct != null) {
Debug.Assert (_transitivelyReferencesProduct.ContainsKey (assembly));
return _transitivelyReferencesProduct.TryGetValue (assembly, out bool result) && result;
}
_transitivelyReferencesProduct = new Dictionary<AssemblyDefinition, bool> ();
// A depth-first search is insufficient because there are reference cycles, so we
// get the set of transitive references, and do a reverse BFS.
var reversedReferences = GetReversedReferences ();
Debug.Assert (reversedReferences.ContainsKey (assembly));
var referencesProductToProcess = new Queue<AssemblyDefinition> ();
// We start the BFS from the product assembly.
foreach (var reference in reversedReferences.Keys) {
if (Profile.IsProductAssembly (reference)) {
_transitivelyReferencesProduct.Add (reference, true);
referencesProductToProcess.Enqueue (reference);
}
}
// Scan the reverse references to find out which referencing assemblies
// are reachable from the product assembly (that is, transitively reference the product).
while (referencesProductToProcess.TryDequeue (out var reference)) {
foreach (var referrer in reversedReferences[reference]) {
if (_transitivelyReferencesProduct.TryGetValue (referrer, out bool referencesProduct)) {
Debug.Assert (referencesProduct);
// Any which were already determined to reference the product assembly
// don't need to be scanned again.
continue;
}
_transitivelyReferencesProduct.Add (referrer, true);
referencesProductToProcess.Enqueue (referrer);
}
}
// Any remaining references that we didn't discover during the search
// don't reference the product assembly.
foreach (var reference in reversedReferences.Keys)
_transitivelyReferencesProduct.TryAdd (reference, false);
return _transitivelyReferencesProduct[assembly];
}
protected override void TryProcessAssembly (AssemblyDefinition assembly)
{
// We are only interested in types transitively derived from NSObject,
// which lives in the product assembly.
if (!TransitivelyReferencesProduct (assembly))
return;
foreach (var type in assembly.MainModule.Types)
ProcessType (type);
}
void ProcessType (TypeDefinition type)
{
MapType (type);
if (!type.HasNestedTypes)
return;
foreach (var nestedType in type.NestedTypes)
ProcessType (nestedType);
}
DerivedLinkContext LinkContext => Configuration.DerivedLinkContext;
#else
DerivedLinkContext LinkContext {
get {
return (DerivedLinkContext) base.Context;
}
2016-04-21 15:57:02 +03:00
}
#endif
2016-04-21 15:57:02 +03:00
HashSet<TypeDefinition> cached_isnsobject = new HashSet<TypeDefinition> ();
Dictionary<TypeDefinition, bool?> isdirectbinding_value = new Dictionary<TypeDefinition, bool?> ();
#if NET
protected override void TryEndProcess ()
{
#else
2016-04-21 15:57:02 +03:00
protected override void EndProcess ()
{
base.EndProcess ();
#endif
LinkContext.CachedIsNSObject = cached_isnsobject;
[linker] Improve inlining of IsDirectBinding check to inline both true and false values. (#3214) Previous behavior ================= * The linker would determine if a class is a generated binding class or not. This was determined by the presence of a constructor taking a single IntPtr argument, and with a [CompilerGenerated] attribute. * If a class was not a generated binding class, then that class and all its superclasses were marked as not optimizable (in the context of inlining the IsDirectBinding check). * The end result was that all classes with a [CompilerGenerated] IntPtr constructor that weren't subclassed, were optimized (the IsDirectBinding value was implied to be 'true'). Unfortunately this does not match how the IsDirectBinding value is actually computed, and is in many cases quite wrong. Background ========== The authorative value for the IsDirectBinding value is the register attribute: ```csharp [Register ("MyClass", true)] // the second parameter specifies the IsDirectBinding value class MyClass : NSObject {} ``` Due to history this second parameter is called `IsWrapper` and not `IsDirectBinding`, but it's the exact same thing. Unfortunately looking up this attribute every time a class is instantiated is slow (since fetching attributes is slow), so we guess this value in NSObject's initialization: if the actual type of the object is in the platform assembly, then we assume IsDirectBinding=true: ```csharp IsDirectBinding = (this.GetType ().Assembly == PlatformAssembly); ``` and any subclasses in the platform assembly which is not a direct binding have to set the correct value in their constructors. New behavior ============ In the linker we now track three states for the IsDirectBinding value for each class: if it can be inlined into a constant true or false, or if it has to be checked at runtime (a nullable bool is used, and null corresponds with this last undetermined state). * The linker will look at the `[Register]` attribute for a class, and: * If the type is CIFilter, store that IsDirectBinding=undetermined. * If IsWrapper=False, store that IsDirectBinding=False for that class, and that IsDirectBinding=undetermined for all super classes where IsWrapper=True. * If IsWrapper=True, tentatively assume IsDirectBinding=True in that class unless already determined to be undetermined (which will be overruled if a non-wrapper subclass is found later). Results ======= For monotouch-test, the changes are as follows: * Classes we can now assume IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L1-L25 * Classes we previously assumed incorrectly that IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L27-L645 * Classes we can now assume IsDirectBinding=false: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L647-L2281 There are also minor size improvements (in the iPhone/Debug64 configuration): The executable is 17.632 bytes smaller: -rwxr-xr-x 1 rolf staff 73038384 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/monotouchtest -rwxr-xr-x 1 rolf staff 73020752 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/monotouchtest Xamarin.iOS.dll is 3.072 bytes smaller (this will probably be 0 on a release (stripped) build). -rw-r--r-- 1 rolf staff 2522624 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/Xamarin.iOS.dll -rw-r--r-- 1 rolf staff 2519552 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/Xamarin.iOS.dll CIFilter ======== There's a complication with CIFilters [1] [2], their implementation is somewhat special, so we do not want to optimize anything for those classes to not risk getting anything wrong. [1] https://github.com/xamarin/xamarin-macios/pull/3055 [2] https://bugzilla.xamarin.com/show_bug.cgi?id=15465
2018-01-15 14:28:34 +03:00
LinkContext.IsDirectBindingValue = isdirectbinding_value;
2016-04-21 15:57:02 +03:00
}
protected
#if !NET
override
#endif
void MapType (TypeDefinition type)
2016-04-21 15:57:02 +03:00
{
#if !NET
2016-04-21 15:57:02 +03:00
base.MapType (type);
#endif
2016-04-21 15:57:02 +03:00
// additional checks for NSObject to check if the type is a *generated* bindings
// bonus: we cache, for every type, whether or not it inherits from NSObject (very useful later)
if (!IsNSObject (type))
return;
// if not, it's a user type, the IsDirectBinding check is required by all ancestors
[linker] Improve inlining of IsDirectBinding check to inline both true and false values. (#3214) Previous behavior ================= * The linker would determine if a class is a generated binding class or not. This was determined by the presence of a constructor taking a single IntPtr argument, and with a [CompilerGenerated] attribute. * If a class was not a generated binding class, then that class and all its superclasses were marked as not optimizable (in the context of inlining the IsDirectBinding check). * The end result was that all classes with a [CompilerGenerated] IntPtr constructor that weren't subclassed, were optimized (the IsDirectBinding value was implied to be 'true'). Unfortunately this does not match how the IsDirectBinding value is actually computed, and is in many cases quite wrong. Background ========== The authorative value for the IsDirectBinding value is the register attribute: ```csharp [Register ("MyClass", true)] // the second parameter specifies the IsDirectBinding value class MyClass : NSObject {} ``` Due to history this second parameter is called `IsWrapper` and not `IsDirectBinding`, but it's the exact same thing. Unfortunately looking up this attribute every time a class is instantiated is slow (since fetching attributes is slow), so we guess this value in NSObject's initialization: if the actual type of the object is in the platform assembly, then we assume IsDirectBinding=true: ```csharp IsDirectBinding = (this.GetType ().Assembly == PlatformAssembly); ``` and any subclasses in the platform assembly which is not a direct binding have to set the correct value in their constructors. New behavior ============ In the linker we now track three states for the IsDirectBinding value for each class: if it can be inlined into a constant true or false, or if it has to be checked at runtime (a nullable bool is used, and null corresponds with this last undetermined state). * The linker will look at the `[Register]` attribute for a class, and: * If the type is CIFilter, store that IsDirectBinding=undetermined. * If IsWrapper=False, store that IsDirectBinding=False for that class, and that IsDirectBinding=undetermined for all super classes where IsWrapper=True. * If IsWrapper=True, tentatively assume IsDirectBinding=True in that class unless already determined to be undetermined (which will be overruled if a non-wrapper subclass is found later). Results ======= For monotouch-test, the changes are as follows: * Classes we can now assume IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L1-L25 * Classes we previously assumed incorrectly that IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L27-L645 * Classes we can now assume IsDirectBinding=false: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L647-L2281 There are also minor size improvements (in the iPhone/Debug64 configuration): The executable is 17.632 bytes smaller: -rwxr-xr-x 1 rolf staff 73038384 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/monotouchtest -rwxr-xr-x 1 rolf staff 73020752 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/monotouchtest Xamarin.iOS.dll is 3.072 bytes smaller (this will probably be 0 on a release (stripped) build). -rw-r--r-- 1 rolf staff 2522624 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/Xamarin.iOS.dll -rw-r--r-- 1 rolf staff 2519552 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/Xamarin.iOS.dll CIFilter ======== There's a complication with CIFilters [1] [2], their implementation is somewhat special, so we do not want to optimize anything for those classes to not risk getting anything wrong. [1] https://github.com/xamarin/xamarin-macios/pull/3055 [2] https://bugzilla.xamarin.com/show_bug.cgi?id=15465
2018-01-15 14:28:34 +03:00
SetIsDirectBindingValue (type);
2016-04-21 15:57:02 +03:00
}
// called once for each 'type' so it's a nice place to cache the result
// and ensure later steps re-use the same, pre-computed, result
bool IsNSObject (TypeDefinition type)
2016-04-21 15:57:02 +03:00
{
if (!type.IsNSObject (LinkContext))
2016-04-21 15:57:02 +03:00
return false;
cached_isnsobject.Add (type);
return true;
}
[linker] Improve inlining of IsDirectBinding check to inline both true and false values. (#3214) Previous behavior ================= * The linker would determine if a class is a generated binding class or not. This was determined by the presence of a constructor taking a single IntPtr argument, and with a [CompilerGenerated] attribute. * If a class was not a generated binding class, then that class and all its superclasses were marked as not optimizable (in the context of inlining the IsDirectBinding check). * The end result was that all classes with a [CompilerGenerated] IntPtr constructor that weren't subclassed, were optimized (the IsDirectBinding value was implied to be 'true'). Unfortunately this does not match how the IsDirectBinding value is actually computed, and is in many cases quite wrong. Background ========== The authorative value for the IsDirectBinding value is the register attribute: ```csharp [Register ("MyClass", true)] // the second parameter specifies the IsDirectBinding value class MyClass : NSObject {} ``` Due to history this second parameter is called `IsWrapper` and not `IsDirectBinding`, but it's the exact same thing. Unfortunately looking up this attribute every time a class is instantiated is slow (since fetching attributes is slow), so we guess this value in NSObject's initialization: if the actual type of the object is in the platform assembly, then we assume IsDirectBinding=true: ```csharp IsDirectBinding = (this.GetType ().Assembly == PlatformAssembly); ``` and any subclasses in the platform assembly which is not a direct binding have to set the correct value in their constructors. New behavior ============ In the linker we now track three states for the IsDirectBinding value for each class: if it can be inlined into a constant true or false, or if it has to be checked at runtime (a nullable bool is used, and null corresponds with this last undetermined state). * The linker will look at the `[Register]` attribute for a class, and: * If the type is CIFilter, store that IsDirectBinding=undetermined. * If IsWrapper=False, store that IsDirectBinding=False for that class, and that IsDirectBinding=undetermined for all super classes where IsWrapper=True. * If IsWrapper=True, tentatively assume IsDirectBinding=True in that class unless already determined to be undetermined (which will be overruled if a non-wrapper subclass is found later). Results ======= For monotouch-test, the changes are as follows: * Classes we can now assume IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L1-L25 * Classes we previously assumed incorrectly that IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L27-L645 * Classes we can now assume IsDirectBinding=false: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L647-L2281 There are also minor size improvements (in the iPhone/Debug64 configuration): The executable is 17.632 bytes smaller: -rwxr-xr-x 1 rolf staff 73038384 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/monotouchtest -rwxr-xr-x 1 rolf staff 73020752 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/monotouchtest Xamarin.iOS.dll is 3.072 bytes smaller (this will probably be 0 on a release (stripped) build). -rw-r--r-- 1 rolf staff 2522624 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/Xamarin.iOS.dll -rw-r--r-- 1 rolf staff 2519552 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/Xamarin.iOS.dll CIFilter ======== There's a complication with CIFilters [1] [2], their implementation is somewhat special, so we do not want to optimize anything for those classes to not risk getting anything wrong. [1] https://github.com/xamarin/xamarin-macios/pull/3055 [2] https://bugzilla.xamarin.com/show_bug.cgi?id=15465
2018-01-15 14:28:34 +03:00
bool IsWrapperType (TypeDefinition type)
2016-04-21 15:57:02 +03:00
{
[linker] Improve inlining of IsDirectBinding check to inline both true and false values. (#3214) Previous behavior ================= * The linker would determine if a class is a generated binding class or not. This was determined by the presence of a constructor taking a single IntPtr argument, and with a [CompilerGenerated] attribute. * If a class was not a generated binding class, then that class and all its superclasses were marked as not optimizable (in the context of inlining the IsDirectBinding check). * The end result was that all classes with a [CompilerGenerated] IntPtr constructor that weren't subclassed, were optimized (the IsDirectBinding value was implied to be 'true'). Unfortunately this does not match how the IsDirectBinding value is actually computed, and is in many cases quite wrong. Background ========== The authorative value for the IsDirectBinding value is the register attribute: ```csharp [Register ("MyClass", true)] // the second parameter specifies the IsDirectBinding value class MyClass : NSObject {} ``` Due to history this second parameter is called `IsWrapper` and not `IsDirectBinding`, but it's the exact same thing. Unfortunately looking up this attribute every time a class is instantiated is slow (since fetching attributes is slow), so we guess this value in NSObject's initialization: if the actual type of the object is in the platform assembly, then we assume IsDirectBinding=true: ```csharp IsDirectBinding = (this.GetType ().Assembly == PlatformAssembly); ``` and any subclasses in the platform assembly which is not a direct binding have to set the correct value in their constructors. New behavior ============ In the linker we now track three states for the IsDirectBinding value for each class: if it can be inlined into a constant true or false, or if it has to be checked at runtime (a nullable bool is used, and null corresponds with this last undetermined state). * The linker will look at the `[Register]` attribute for a class, and: * If the type is CIFilter, store that IsDirectBinding=undetermined. * If IsWrapper=False, store that IsDirectBinding=False for that class, and that IsDirectBinding=undetermined for all super classes where IsWrapper=True. * If IsWrapper=True, tentatively assume IsDirectBinding=True in that class unless already determined to be undetermined (which will be overruled if a non-wrapper subclass is found later). Results ======= For monotouch-test, the changes are as follows: * Classes we can now assume IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L1-L25 * Classes we previously assumed incorrectly that IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L27-L645 * Classes we can now assume IsDirectBinding=false: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L647-L2281 There are also minor size improvements (in the iPhone/Debug64 configuration): The executable is 17.632 bytes smaller: -rwxr-xr-x 1 rolf staff 73038384 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/monotouchtest -rwxr-xr-x 1 rolf staff 73020752 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/monotouchtest Xamarin.iOS.dll is 3.072 bytes smaller (this will probably be 0 on a release (stripped) build). -rw-r--r-- 1 rolf staff 2522624 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/Xamarin.iOS.dll -rw-r--r-- 1 rolf staff 2519552 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/Xamarin.iOS.dll CIFilter ======== There's a complication with CIFilters [1] [2], their implementation is somewhat special, so we do not want to optimize anything for those classes to not risk getting anything wrong. [1] https://github.com/xamarin/xamarin-macios/pull/3055 [2] https://bugzilla.xamarin.com/show_bug.cgi?id=15465
2018-01-15 14:28:34 +03:00
var registerAttribute = LinkContext.StaticRegistrar.GetRegisterAttribute (type);
return registerAttribute?.IsWrapper == true || registerAttribute?.SkipRegistration == true;
}
// Cache the results of the IsCIFilter check in a dictionary. It makes this method slightly faster
// (total time spent in IsCIFilter when linking monotouch-test went from 11 ms to 3ms).
static Dictionary<TypeReference, bool> ci_filter_types = new Dictionary<TypeReference, bool> ();
[linker] Improve inlining of IsDirectBinding check to inline both true and false values. (#3214) Previous behavior ================= * The linker would determine if a class is a generated binding class or not. This was determined by the presence of a constructor taking a single IntPtr argument, and with a [CompilerGenerated] attribute. * If a class was not a generated binding class, then that class and all its superclasses were marked as not optimizable (in the context of inlining the IsDirectBinding check). * The end result was that all classes with a [CompilerGenerated] IntPtr constructor that weren't subclassed, were optimized (the IsDirectBinding value was implied to be 'true'). Unfortunately this does not match how the IsDirectBinding value is actually computed, and is in many cases quite wrong. Background ========== The authorative value for the IsDirectBinding value is the register attribute: ```csharp [Register ("MyClass", true)] // the second parameter specifies the IsDirectBinding value class MyClass : NSObject {} ``` Due to history this second parameter is called `IsWrapper` and not `IsDirectBinding`, but it's the exact same thing. Unfortunately looking up this attribute every time a class is instantiated is slow (since fetching attributes is slow), so we guess this value in NSObject's initialization: if the actual type of the object is in the platform assembly, then we assume IsDirectBinding=true: ```csharp IsDirectBinding = (this.GetType ().Assembly == PlatformAssembly); ``` and any subclasses in the platform assembly which is not a direct binding have to set the correct value in their constructors. New behavior ============ In the linker we now track three states for the IsDirectBinding value for each class: if it can be inlined into a constant true or false, or if it has to be checked at runtime (a nullable bool is used, and null corresponds with this last undetermined state). * The linker will look at the `[Register]` attribute for a class, and: * If the type is CIFilter, store that IsDirectBinding=undetermined. * If IsWrapper=False, store that IsDirectBinding=False for that class, and that IsDirectBinding=undetermined for all super classes where IsWrapper=True. * If IsWrapper=True, tentatively assume IsDirectBinding=True in that class unless already determined to be undetermined (which will be overruled if a non-wrapper subclass is found later). Results ======= For monotouch-test, the changes are as follows: * Classes we can now assume IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L1-L25 * Classes we previously assumed incorrectly that IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L27-L645 * Classes we can now assume IsDirectBinding=false: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L647-L2281 There are also minor size improvements (in the iPhone/Debug64 configuration): The executable is 17.632 bytes smaller: -rwxr-xr-x 1 rolf staff 73038384 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/monotouchtest -rwxr-xr-x 1 rolf staff 73020752 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/monotouchtest Xamarin.iOS.dll is 3.072 bytes smaller (this will probably be 0 on a release (stripped) build). -rw-r--r-- 1 rolf staff 2522624 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/Xamarin.iOS.dll -rw-r--r-- 1 rolf staff 2519552 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/Xamarin.iOS.dll CIFilter ======== There's a complication with CIFilters [1] [2], their implementation is somewhat special, so we do not want to optimize anything for those classes to not risk getting anything wrong. [1] https://github.com/xamarin/xamarin-macios/pull/3055 [2] https://bugzilla.xamarin.com/show_bug.cgi?id=15465
2018-01-15 14:28:34 +03:00
bool IsCIFilter (TypeReference type)
{
if (type == null)
2016-04-21 15:57:02 +03:00
return false;
bool rv;
if (!ci_filter_types.TryGetValue (type, out rv)) {
rv = type.Is (Namespaces.CoreImage, "CIFilter") || IsCIFilter (Context.Resolve (type).BaseType);
ci_filter_types [type] = rv;
}
return rv;
2016-04-21 15:57:02 +03:00
}
[linker] Improve inlining of IsDirectBinding check to inline both true and false values. (#3214) Previous behavior ================= * The linker would determine if a class is a generated binding class or not. This was determined by the presence of a constructor taking a single IntPtr argument, and with a [CompilerGenerated] attribute. * If a class was not a generated binding class, then that class and all its superclasses were marked as not optimizable (in the context of inlining the IsDirectBinding check). * The end result was that all classes with a [CompilerGenerated] IntPtr constructor that weren't subclassed, were optimized (the IsDirectBinding value was implied to be 'true'). Unfortunately this does not match how the IsDirectBinding value is actually computed, and is in many cases quite wrong. Background ========== The authorative value for the IsDirectBinding value is the register attribute: ```csharp [Register ("MyClass", true)] // the second parameter specifies the IsDirectBinding value class MyClass : NSObject {} ``` Due to history this second parameter is called `IsWrapper` and not `IsDirectBinding`, but it's the exact same thing. Unfortunately looking up this attribute every time a class is instantiated is slow (since fetching attributes is slow), so we guess this value in NSObject's initialization: if the actual type of the object is in the platform assembly, then we assume IsDirectBinding=true: ```csharp IsDirectBinding = (this.GetType ().Assembly == PlatformAssembly); ``` and any subclasses in the platform assembly which is not a direct binding have to set the correct value in their constructors. New behavior ============ In the linker we now track three states for the IsDirectBinding value for each class: if it can be inlined into a constant true or false, or if it has to be checked at runtime (a nullable bool is used, and null corresponds with this last undetermined state). * The linker will look at the `[Register]` attribute for a class, and: * If the type is CIFilter, store that IsDirectBinding=undetermined. * If IsWrapper=False, store that IsDirectBinding=False for that class, and that IsDirectBinding=undetermined for all super classes where IsWrapper=True. * If IsWrapper=True, tentatively assume IsDirectBinding=True in that class unless already determined to be undetermined (which will be overruled if a non-wrapper subclass is found later). Results ======= For monotouch-test, the changes are as follows: * Classes we can now assume IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L1-L25 * Classes we previously assumed incorrectly that IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L27-L645 * Classes we can now assume IsDirectBinding=false: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L647-L2281 There are also minor size improvements (in the iPhone/Debug64 configuration): The executable is 17.632 bytes smaller: -rwxr-xr-x 1 rolf staff 73038384 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/monotouchtest -rwxr-xr-x 1 rolf staff 73020752 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/monotouchtest Xamarin.iOS.dll is 3.072 bytes smaller (this will probably be 0 on a release (stripped) build). -rw-r--r-- 1 rolf staff 2522624 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/Xamarin.iOS.dll -rw-r--r-- 1 rolf staff 2519552 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/Xamarin.iOS.dll CIFilter ======== There's a complication with CIFilters [1] [2], their implementation is somewhat special, so we do not want to optimize anything for those classes to not risk getting anything wrong. [1] https://github.com/xamarin/xamarin-macios/pull/3055 [2] https://bugzilla.xamarin.com/show_bug.cgi?id=15465
2018-01-15 14:28:34 +03:00
void SetIsDirectBindingValue (TypeDefinition type)
2016-04-21 15:57:02 +03:00
{
[linker] Improve inlining of IsDirectBinding check to inline both true and false values. (#3214) Previous behavior ================= * The linker would determine if a class is a generated binding class or not. This was determined by the presence of a constructor taking a single IntPtr argument, and with a [CompilerGenerated] attribute. * If a class was not a generated binding class, then that class and all its superclasses were marked as not optimizable (in the context of inlining the IsDirectBinding check). * The end result was that all classes with a [CompilerGenerated] IntPtr constructor that weren't subclassed, were optimized (the IsDirectBinding value was implied to be 'true'). Unfortunately this does not match how the IsDirectBinding value is actually computed, and is in many cases quite wrong. Background ========== The authorative value for the IsDirectBinding value is the register attribute: ```csharp [Register ("MyClass", true)] // the second parameter specifies the IsDirectBinding value class MyClass : NSObject {} ``` Due to history this second parameter is called `IsWrapper` and not `IsDirectBinding`, but it's the exact same thing. Unfortunately looking up this attribute every time a class is instantiated is slow (since fetching attributes is slow), so we guess this value in NSObject's initialization: if the actual type of the object is in the platform assembly, then we assume IsDirectBinding=true: ```csharp IsDirectBinding = (this.GetType ().Assembly == PlatformAssembly); ``` and any subclasses in the platform assembly which is not a direct binding have to set the correct value in their constructors. New behavior ============ In the linker we now track three states for the IsDirectBinding value for each class: if it can be inlined into a constant true or false, or if it has to be checked at runtime (a nullable bool is used, and null corresponds with this last undetermined state). * The linker will look at the `[Register]` attribute for a class, and: * If the type is CIFilter, store that IsDirectBinding=undetermined. * If IsWrapper=False, store that IsDirectBinding=False for that class, and that IsDirectBinding=undetermined for all super classes where IsWrapper=True. * If IsWrapper=True, tentatively assume IsDirectBinding=True in that class unless already determined to be undetermined (which will be overruled if a non-wrapper subclass is found later). Results ======= For monotouch-test, the changes are as follows: * Classes we can now assume IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L1-L25 * Classes we previously assumed incorrectly that IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L27-L645 * Classes we can now assume IsDirectBinding=false: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L647-L2281 There are also minor size improvements (in the iPhone/Debug64 configuration): The executable is 17.632 bytes smaller: -rwxr-xr-x 1 rolf staff 73038384 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/monotouchtest -rwxr-xr-x 1 rolf staff 73020752 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/monotouchtest Xamarin.iOS.dll is 3.072 bytes smaller (this will probably be 0 on a release (stripped) build). -rw-r--r-- 1 rolf staff 2522624 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/Xamarin.iOS.dll -rw-r--r-- 1 rolf staff 2519552 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/Xamarin.iOS.dll CIFilter ======== There's a complication with CIFilters [1] [2], their implementation is somewhat special, so we do not want to optimize anything for those classes to not risk getting anything wrong. [1] https://github.com/xamarin/xamarin-macios/pull/3055 [2] https://bugzilla.xamarin.com/show_bug.cgi?id=15465
2018-01-15 14:28:34 +03:00
if (isdirectbinding_value.ContainsKey (type))
2016-04-21 15:57:02 +03:00
return;
[linker] Improve inlining of IsDirectBinding check to inline both true and false values. (#3214) Previous behavior ================= * The linker would determine if a class is a generated binding class or not. This was determined by the presence of a constructor taking a single IntPtr argument, and with a [CompilerGenerated] attribute. * If a class was not a generated binding class, then that class and all its superclasses were marked as not optimizable (in the context of inlining the IsDirectBinding check). * The end result was that all classes with a [CompilerGenerated] IntPtr constructor that weren't subclassed, were optimized (the IsDirectBinding value was implied to be 'true'). Unfortunately this does not match how the IsDirectBinding value is actually computed, and is in many cases quite wrong. Background ========== The authorative value for the IsDirectBinding value is the register attribute: ```csharp [Register ("MyClass", true)] // the second parameter specifies the IsDirectBinding value class MyClass : NSObject {} ``` Due to history this second parameter is called `IsWrapper` and not `IsDirectBinding`, but it's the exact same thing. Unfortunately looking up this attribute every time a class is instantiated is slow (since fetching attributes is slow), so we guess this value in NSObject's initialization: if the actual type of the object is in the platform assembly, then we assume IsDirectBinding=true: ```csharp IsDirectBinding = (this.GetType ().Assembly == PlatformAssembly); ``` and any subclasses in the platform assembly which is not a direct binding have to set the correct value in their constructors. New behavior ============ In the linker we now track three states for the IsDirectBinding value for each class: if it can be inlined into a constant true or false, or if it has to be checked at runtime (a nullable bool is used, and null corresponds with this last undetermined state). * The linker will look at the `[Register]` attribute for a class, and: * If the type is CIFilter, store that IsDirectBinding=undetermined. * If IsWrapper=False, store that IsDirectBinding=False for that class, and that IsDirectBinding=undetermined for all super classes where IsWrapper=True. * If IsWrapper=True, tentatively assume IsDirectBinding=True in that class unless already determined to be undetermined (which will be overruled if a non-wrapper subclass is found later). Results ======= For monotouch-test, the changes are as follows: * Classes we can now assume IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L1-L25 * Classes we previously assumed incorrectly that IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L27-L645 * Classes we can now assume IsDirectBinding=false: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L647-L2281 There are also minor size improvements (in the iPhone/Debug64 configuration): The executable is 17.632 bytes smaller: -rwxr-xr-x 1 rolf staff 73038384 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/monotouchtest -rwxr-xr-x 1 rolf staff 73020752 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/monotouchtest Xamarin.iOS.dll is 3.072 bytes smaller (this will probably be 0 on a release (stripped) build). -rw-r--r-- 1 rolf staff 2522624 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/Xamarin.iOS.dll -rw-r--r-- 1 rolf staff 2519552 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/Xamarin.iOS.dll CIFilter ======== There's a complication with CIFilters [1] [2], their implementation is somewhat special, so we do not want to optimize anything for those classes to not risk getting anything wrong. [1] https://github.com/xamarin/xamarin-macios/pull/3055 [2] https://bugzilla.xamarin.com/show_bug.cgi?id=15465
2018-01-15 14:28:34 +03:00
// We have a special implementation of CIFilters, and we do not want to
// optimize anything for those classes to not risk optimizing this wrong.
// This means we must set the IsDirectBinding value to null for CIFilter
// and all its base classes to allow both code paths and determine at runtime.
// References:
// * https://github.com/xamarin/xamarin-macios/pull/3055
// * https://bugzilla.xamarin.com/show_bug.cgi?id=15465
if (IsCIFilter (type)) {
isdirectbinding_value [type] = null;
var base_type = Context.Resolve (type.BaseType);
[linker] Improve inlining of IsDirectBinding check to inline both true and false values. (#3214) Previous behavior ================= * The linker would determine if a class is a generated binding class or not. This was determined by the presence of a constructor taking a single IntPtr argument, and with a [CompilerGenerated] attribute. * If a class was not a generated binding class, then that class and all its superclasses were marked as not optimizable (in the context of inlining the IsDirectBinding check). * The end result was that all classes with a [CompilerGenerated] IntPtr constructor that weren't subclassed, were optimized (the IsDirectBinding value was implied to be 'true'). Unfortunately this does not match how the IsDirectBinding value is actually computed, and is in many cases quite wrong. Background ========== The authorative value for the IsDirectBinding value is the register attribute: ```csharp [Register ("MyClass", true)] // the second parameter specifies the IsDirectBinding value class MyClass : NSObject {} ``` Due to history this second parameter is called `IsWrapper` and not `IsDirectBinding`, but it's the exact same thing. Unfortunately looking up this attribute every time a class is instantiated is slow (since fetching attributes is slow), so we guess this value in NSObject's initialization: if the actual type of the object is in the platform assembly, then we assume IsDirectBinding=true: ```csharp IsDirectBinding = (this.GetType ().Assembly == PlatformAssembly); ``` and any subclasses in the platform assembly which is not a direct binding have to set the correct value in their constructors. New behavior ============ In the linker we now track three states for the IsDirectBinding value for each class: if it can be inlined into a constant true or false, or if it has to be checked at runtime (a nullable bool is used, and null corresponds with this last undetermined state). * The linker will look at the `[Register]` attribute for a class, and: * If the type is CIFilter, store that IsDirectBinding=undetermined. * If IsWrapper=False, store that IsDirectBinding=False for that class, and that IsDirectBinding=undetermined for all super classes where IsWrapper=True. * If IsWrapper=True, tentatively assume IsDirectBinding=True in that class unless already determined to be undetermined (which will be overruled if a non-wrapper subclass is found later). Results ======= For monotouch-test, the changes are as follows: * Classes we can now assume IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L1-L25 * Classes we previously assumed incorrectly that IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L27-L645 * Classes we can now assume IsDirectBinding=false: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L647-L2281 There are also minor size improvements (in the iPhone/Debug64 configuration): The executable is 17.632 bytes smaller: -rwxr-xr-x 1 rolf staff 73038384 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/monotouchtest -rwxr-xr-x 1 rolf staff 73020752 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/monotouchtest Xamarin.iOS.dll is 3.072 bytes smaller (this will probably be 0 on a release (stripped) build). -rw-r--r-- 1 rolf staff 2522624 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/Xamarin.iOS.dll -rw-r--r-- 1 rolf staff 2519552 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/Xamarin.iOS.dll CIFilter ======== There's a complication with CIFilters [1] [2], their implementation is somewhat special, so we do not want to optimize anything for those classes to not risk getting anything wrong. [1] https://github.com/xamarin/xamarin-macios/pull/3055 [2] https://bugzilla.xamarin.com/show_bug.cgi?id=15465
2018-01-15 14:28:34 +03:00
while (base_type != null && IsNSObject (base_type)) {
isdirectbinding_value [base_type] = null;
base_type = Context.Resolve (base_type.BaseType);
[linker] Improve inlining of IsDirectBinding check to inline both true and false values. (#3214) Previous behavior ================= * The linker would determine if a class is a generated binding class or not. This was determined by the presence of a constructor taking a single IntPtr argument, and with a [CompilerGenerated] attribute. * If a class was not a generated binding class, then that class and all its superclasses were marked as not optimizable (in the context of inlining the IsDirectBinding check). * The end result was that all classes with a [CompilerGenerated] IntPtr constructor that weren't subclassed, were optimized (the IsDirectBinding value was implied to be 'true'). Unfortunately this does not match how the IsDirectBinding value is actually computed, and is in many cases quite wrong. Background ========== The authorative value for the IsDirectBinding value is the register attribute: ```csharp [Register ("MyClass", true)] // the second parameter specifies the IsDirectBinding value class MyClass : NSObject {} ``` Due to history this second parameter is called `IsWrapper` and not `IsDirectBinding`, but it's the exact same thing. Unfortunately looking up this attribute every time a class is instantiated is slow (since fetching attributes is slow), so we guess this value in NSObject's initialization: if the actual type of the object is in the platform assembly, then we assume IsDirectBinding=true: ```csharp IsDirectBinding = (this.GetType ().Assembly == PlatformAssembly); ``` and any subclasses in the platform assembly which is not a direct binding have to set the correct value in their constructors. New behavior ============ In the linker we now track three states for the IsDirectBinding value for each class: if it can be inlined into a constant true or false, or if it has to be checked at runtime (a nullable bool is used, and null corresponds with this last undetermined state). * The linker will look at the `[Register]` attribute for a class, and: * If the type is CIFilter, store that IsDirectBinding=undetermined. * If IsWrapper=False, store that IsDirectBinding=False for that class, and that IsDirectBinding=undetermined for all super classes where IsWrapper=True. * If IsWrapper=True, tentatively assume IsDirectBinding=True in that class unless already determined to be undetermined (which will be overruled if a non-wrapper subclass is found later). Results ======= For monotouch-test, the changes are as follows: * Classes we can now assume IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L1-L25 * Classes we previously assumed incorrectly that IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L27-L645 * Classes we can now assume IsDirectBinding=false: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L647-L2281 There are also minor size improvements (in the iPhone/Debug64 configuration): The executable is 17.632 bytes smaller: -rwxr-xr-x 1 rolf staff 73038384 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/monotouchtest -rwxr-xr-x 1 rolf staff 73020752 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/monotouchtest Xamarin.iOS.dll is 3.072 bytes smaller (this will probably be 0 on a release (stripped) build). -rw-r--r-- 1 rolf staff 2522624 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/Xamarin.iOS.dll -rw-r--r-- 1 rolf staff 2519552 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/Xamarin.iOS.dll CIFilter ======== There's a complication with CIFilters [1] [2], their implementation is somewhat special, so we do not want to optimize anything for those classes to not risk getting anything wrong. [1] https://github.com/xamarin/xamarin-macios/pull/3055 [2] https://bugzilla.xamarin.com/show_bug.cgi?id=15465
2018-01-15 14:28:34 +03:00
}
return;
}
var isWrapperType = IsWrapperType (type);
if (!isWrapperType) {
isdirectbinding_value [type] = false;
// We must clear IsDirectBinding for any wrapper superclasses.
var base_type = Context.Resolve (type.BaseType);
[linker] Improve inlining of IsDirectBinding check to inline both true and false values. (#3214) Previous behavior ================= * The linker would determine if a class is a generated binding class or not. This was determined by the presence of a constructor taking a single IntPtr argument, and with a [CompilerGenerated] attribute. * If a class was not a generated binding class, then that class and all its superclasses were marked as not optimizable (in the context of inlining the IsDirectBinding check). * The end result was that all classes with a [CompilerGenerated] IntPtr constructor that weren't subclassed, were optimized (the IsDirectBinding value was implied to be 'true'). Unfortunately this does not match how the IsDirectBinding value is actually computed, and is in many cases quite wrong. Background ========== The authorative value for the IsDirectBinding value is the register attribute: ```csharp [Register ("MyClass", true)] // the second parameter specifies the IsDirectBinding value class MyClass : NSObject {} ``` Due to history this second parameter is called `IsWrapper` and not `IsDirectBinding`, but it's the exact same thing. Unfortunately looking up this attribute every time a class is instantiated is slow (since fetching attributes is slow), so we guess this value in NSObject's initialization: if the actual type of the object is in the platform assembly, then we assume IsDirectBinding=true: ```csharp IsDirectBinding = (this.GetType ().Assembly == PlatformAssembly); ``` and any subclasses in the platform assembly which is not a direct binding have to set the correct value in their constructors. New behavior ============ In the linker we now track three states for the IsDirectBinding value for each class: if it can be inlined into a constant true or false, or if it has to be checked at runtime (a nullable bool is used, and null corresponds with this last undetermined state). * The linker will look at the `[Register]` attribute for a class, and: * If the type is CIFilter, store that IsDirectBinding=undetermined. * If IsWrapper=False, store that IsDirectBinding=False for that class, and that IsDirectBinding=undetermined for all super classes where IsWrapper=True. * If IsWrapper=True, tentatively assume IsDirectBinding=True in that class unless already determined to be undetermined (which will be overruled if a non-wrapper subclass is found later). Results ======= For monotouch-test, the changes are as follows: * Classes we can now assume IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L1-L25 * Classes we previously assumed incorrectly that IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L27-L645 * Classes we can now assume IsDirectBinding=false: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L647-L2281 There are also minor size improvements (in the iPhone/Debug64 configuration): The executable is 17.632 bytes smaller: -rwxr-xr-x 1 rolf staff 73038384 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/monotouchtest -rwxr-xr-x 1 rolf staff 73020752 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/monotouchtest Xamarin.iOS.dll is 3.072 bytes smaller (this will probably be 0 on a release (stripped) build). -rw-r--r-- 1 rolf staff 2522624 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/Xamarin.iOS.dll -rw-r--r-- 1 rolf staff 2519552 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/Xamarin.iOS.dll CIFilter ======== There's a complication with CIFilters [1] [2], their implementation is somewhat special, so we do not want to optimize anything for those classes to not risk getting anything wrong. [1] https://github.com/xamarin/xamarin-macios/pull/3055 [2] https://bugzilla.xamarin.com/show_bug.cgi?id=15465
2018-01-15 14:28:34 +03:00
while (base_type != null && IsNSObject (base_type)) {
if (IsWrapperType (base_type))
isdirectbinding_value [base_type] = null;
base_type = Context.Resolve (base_type.BaseType);
[linker] Improve inlining of IsDirectBinding check to inline both true and false values. (#3214) Previous behavior ================= * The linker would determine if a class is a generated binding class or not. This was determined by the presence of a constructor taking a single IntPtr argument, and with a [CompilerGenerated] attribute. * If a class was not a generated binding class, then that class and all its superclasses were marked as not optimizable (in the context of inlining the IsDirectBinding check). * The end result was that all classes with a [CompilerGenerated] IntPtr constructor that weren't subclassed, were optimized (the IsDirectBinding value was implied to be 'true'). Unfortunately this does not match how the IsDirectBinding value is actually computed, and is in many cases quite wrong. Background ========== The authorative value for the IsDirectBinding value is the register attribute: ```csharp [Register ("MyClass", true)] // the second parameter specifies the IsDirectBinding value class MyClass : NSObject {} ``` Due to history this second parameter is called `IsWrapper` and not `IsDirectBinding`, but it's the exact same thing. Unfortunately looking up this attribute every time a class is instantiated is slow (since fetching attributes is slow), so we guess this value in NSObject's initialization: if the actual type of the object is in the platform assembly, then we assume IsDirectBinding=true: ```csharp IsDirectBinding = (this.GetType ().Assembly == PlatformAssembly); ``` and any subclasses in the platform assembly which is not a direct binding have to set the correct value in their constructors. New behavior ============ In the linker we now track three states for the IsDirectBinding value for each class: if it can be inlined into a constant true or false, or if it has to be checked at runtime (a nullable bool is used, and null corresponds with this last undetermined state). * The linker will look at the `[Register]` attribute for a class, and: * If the type is CIFilter, store that IsDirectBinding=undetermined. * If IsWrapper=False, store that IsDirectBinding=False for that class, and that IsDirectBinding=undetermined for all super classes where IsWrapper=True. * If IsWrapper=True, tentatively assume IsDirectBinding=True in that class unless already determined to be undetermined (which will be overruled if a non-wrapper subclass is found later). Results ======= For monotouch-test, the changes are as follows: * Classes we can now assume IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L1-L25 * Classes we previously assumed incorrectly that IsDirectBinding=true: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L27-L645 * Classes we can now assume IsDirectBinding=false: https://gist.github.com/rolfbjarne/acd6a8cf1236562a832d6db9400afee9#file-foo-diff-L647-L2281 There are also minor size improvements (in the iPhone/Debug64 configuration): The executable is 17.632 bytes smaller: -rwxr-xr-x 1 rolf staff 73038384 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/monotouchtest -rwxr-xr-x 1 rolf staff 73020752 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/monotouchtest Xamarin.iOS.dll is 3.072 bytes smaller (this will probably be 0 on a release (stripped) build). -rw-r--r-- 1 rolf staff 2522624 Jan 12 12:40 /Users/rolf/test/old/monotouchtest.app/Xamarin.iOS.dll -rw-r--r-- 1 rolf staff 2519552 Jan 12 12:50 /Users/rolf/test/new/monotouchtest.app/Xamarin.iOS.dll CIFilter ======== There's a complication with CIFilters [1] [2], their implementation is somewhat special, so we do not want to optimize anything for those classes to not risk getting anything wrong. [1] https://github.com/xamarin/xamarin-macios/pull/3055 [2] https://bugzilla.xamarin.com/show_bug.cgi?id=15465
2018-01-15 14:28:34 +03:00
}
} else {
isdirectbinding_value [type] = true; // Let's try 'true' first, any derived non-wrapper classes will clear it if needed
}
2016-04-21 15:57:02 +03:00
}
}
}