Add a BindingImpl attribute and use to to teach the linker look for it to search for optimizable code. (#3299)

* [ObjCRuntime] Add a BindingImplAttribute.

* [linker] Make ProviderToString an extension method on ICustomAttributeProvider to make it more discoverable.

* [generator] Use [BindingImpl] instead of [CompilerGenerated].

The entire diff is big (89MB), so it can't be gisted. However, most of it is
either removal of `using System.Runtime.CompilerServices;` or the change from
`[CompilerGenerated]` to `[BindingImpl (...)]` like this:
https://gist.github.com/rolfbjarne/8bfda3ed37b956d0342a1c1e9b079244

If I remove those parts of the diff, there's nothing significant left:
https://gist.github.com/rolfbjarne/4156164d6bdb1376366200394eb8a091

* [linker] Teach the linker about the new [BindingImpl] attribute.

In addition to the existing logic where the linker would optimize some
[CompilerGenerated] code (sometimes with additional requirements), it will now
also optimize all [BindingImpl (Optimizable)] code (without any additional
requirements).

* [tests] Add tests to make sure [BindingImpl (Optimizable)] works as expected.

* [linker] Check for [BindingImpl] before [CompilerGenerated] and stop checking for [CompilerGenerated] in XAMCORE_4_0.

Check for [BindingImpl] before checking for [CompilerGenerated], since the
former is more common.

Also stop checking for [CompilerGenerated] (at least to mean that code is
optimizable) in our next non-compatible evolutionary leap (XAMCORE_4_0):

* [introspection] Impl a better typo check.
This commit is contained in:
Rolf Bjarne Kvinge 2018-01-26 18:38:23 +01:00 коммит произвёл GitHub
Родитель f0b2c254c7
Коммит b2bcad7a94
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
19 изменённых файлов: 234 добавлений и 54 удалений

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

@ -1296,6 +1296,10 @@ Mixed-mode assemblies can not be processed by the linker.
See https://msdn.microsoft.com/en-us/library/x0w2664k.aspx for more information on mixed-mode assemblies.
### <a name="MT2105"/>MT2105: The [BindingImpl] attribute on the member * is invalid: *
The `[BindingImpl]` attribute on the mentioned member is invalid. The expected format is `[BindingImpl (BindingImplOptions.ValueA | BindingImplOptions.ValueB)]`.
# MT3xxx: AOT error messages
<!--

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

@ -42,6 +42,7 @@ GENERATOR_ATTRIBUTE_SOURCES = \
$(TOP)/src/ObjCRuntime/AlphaAttribute.cs \
$(TOP)/src/ObjCRuntime/ArgumentSemantic.cs \
$(TOP)/src/ObjCRuntime/BindAsAttribute.cs \
$(TOP)/src/ObjCRuntime/BindingImplAttribute.cs \
$(TOP)/src/ObjCRuntime/LinkWithAttribute.cs \
$(TOP)/src/ObjCRuntime/NativeAttribute.cs \
$(TOP)/src/ObjCRuntime/PlatformAvailability2.cs \

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

@ -0,0 +1,27 @@
//
// BindingImplAttrobute.cs: Apply this to binding methods to describe them.
//
using System;
using System.Runtime.InteropServices;
namespace XamCore.ObjCRuntime {
[AttributeUsage (AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Class, AllowMultiple = false)]
public class BindingImplAttribute : Attribute
{
public BindingImplAttribute (BindingImplOptions options)
{
Options = options;
}
public BindingImplOptions Options { get; set; }
}
[Flags]
public enum BindingImplOptions
{
GeneratedCode = 1,
Optimizable = 2,
}
}

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

@ -1559,6 +1559,7 @@ SHARED_SOURCES = \
ObjCRuntime/BackingField.cs \
ObjCRuntime/BaseWrapper.cs \
ObjCRuntime/BlockProxyAttribute.cs \
ObjCRuntime/BindingImplAttribute.cs \
ObjCRuntime/CategoryAttribute.cs \
ObjCRuntime/Class.mac.cs \
ObjCRuntime/CompileFlagsAttribute.cs \

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

@ -101,7 +101,7 @@ public partial class Generator {
print ("");
// the *Extensions has the same version requirement as the enum itself
PrintPlatformAttributes (type);
print ("[CompilerGenerated]");
print_generated_code ();
print ("static public partial class {0}Extensions {{", type.Name);
indent++;

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

@ -45,7 +45,7 @@ public partial class Generator {
if (!is_abstract) {
v = GetVisibility (filter.DefaultCtorVisibility);
if (v.Length > 0) {
print ("[CompilerGenerated]");
print_generated_code ();
print ("{0}{1} () : base (\"{2}\")", v, type.Name, native_name);
PrintEmptyBody ();
}
@ -61,18 +61,18 @@ public partial class Generator {
intptrctor_visibility = MethodAttributes.Public;
}
}
print ("[CompilerGenerated]");
print_generated_code ();
print ("{0}{1} (IntPtr handle) : base (handle)", GetVisibility (intptrctor_visibility), type_name);
PrintEmptyBody ();
// NSObjectFlag constructor - always present (needed to implement NSCoder for subclasses)
print ("[CompilerGenerated]");
print_generated_code ();
print ("[EditorBrowsable (EditorBrowsableState.Advanced)]");
print ("protected {0} (NSObjectFlag t) : base (t)", type_name);
PrintEmptyBody ();
// NSCoder constructor - all filters conforms to NSCoding
print ("[CompilerGenerated]");
print_generated_code ();
print ("[EditorBrowsable (EditorBrowsableState.Advanced)]");
print ("[Export (\"initWithCoder:\")]");
print ("public {0} (NSCoder coder) : base (NSObjectFlag.Empty)", type_name);
@ -99,7 +99,7 @@ public partial class Generator {
if (is_abstract && (v.Length == 0))
v = "protected ";
if (v.Length > 0) {
print ("[CompilerGenerated]");
print_generated_code ();
print ("{0} {1} (string name) : base (CreateFilter (name))", v, type_name);
PrintEmptyBody ();
}
@ -110,7 +110,7 @@ public partial class Generator {
continue;
print ("");
print ("[CompilerGenerated]");
print_generated_code ();
var ptype = p.PropertyType.Name;
// keep C# names as they are reserved keywords (e.g. Boolean also exists in OpenGL for Mac)
switch (ptype) {

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

@ -671,7 +671,6 @@ public class NamespaceManager
ImplicitNamespaces = new HashSet<string> ();
ImplicitNamespaces.Add ("System");
ImplicitNamespaces.Add ("System.Runtime.CompilerServices");
ImplicitNamespaces.Add ("System.Runtime.InteropServices");
ImplicitNamespaces.Add ("System.Diagnostics");
ImplicitNamespaces.Add ("System.ComponentModel");
@ -2353,6 +2352,7 @@ public partial class Generator : IMemberGatherer {
case "CompilerGeneratedAttribute":
case "ManualAttribute":
case "MarshalDirectiveAttribute":
case "BindingImplAttribute":
continue;
default:
throw new BindingException (1007, true, "Unknown attribute {0} on {1}.{2}", attr.GetType (), mi.DeclaringType, mi.Name);
@ -2474,7 +2474,7 @@ public partial class Generator : IMemberGatherer {
Header (sw);
print ("namespace {0} {{", ns.CoreObjCRuntime); indent++;
print ("");
print ("[CompilerGenerated]");
print_generated_code ();
print ("static partial class Trampolines {"); indent++;
print ("");
@ -2653,7 +2653,7 @@ public partial class Generator : IMemberGatherer {
Header (sw);
print ("namespace {0} {{", ns.CoreObjCRuntime); indent++;
print ("[CompilerGenerated]");
print_generated_code ();
print ("static partial class Libraries {"); indent++;
foreach (var library_info in libraries.OrderBy (v => v.Key, StringComparer.Ordinal)) {
var library_name = library_info.Key;
@ -2913,7 +2913,7 @@ public partial class Generator : IMemberGatherer {
print ("static IntPtr {0};", kn);
print ("");
// linker will remove the attributes (but it's useful for testing)
print ("[CompilerGenerated]");
print_generated_code ();
print ("{0} {1}{2} {3} {{",
is_internal ? "internal" : "public",
propertyType,
@ -3039,7 +3039,7 @@ public partial class Generator : IMemberGatherer {
{
for (int i=0; i < tabs; i++)
sw.Write ('\t');
sw.WriteLine ("[CompilerGenerated]");
sw.WriteLine ("[BindingImpl (BindingImplOptions.GeneratedCode | BindingImplOptions.Optimizable)]");
}
static void WriteIsDirectBindingCondition (StreamWriter sw, ref int tabs, bool? is_direct_binding, string is_direct_binding_value, Func<string> trueCode, Func<string> falseCode)
@ -4595,7 +4595,7 @@ public partial class Generator : IMemberGatherer {
if (!is_model && DoesPropertyNeedBackingField (pi) && !is_interface_impl && !minfo.is_static && !DoesPropertyNeedDirtyCheck (pi, export)) {
var_name = string.Format ("__mt_{0}_var{1}", pi.Name, minfo.is_static ? "_static" : "");
print ("[CompilerGenerated]");
print_generated_code ();
if (minfo.is_thread_static)
print ("[ThreadStatic]");
@ -5961,7 +5961,7 @@ public partial class Generator : IMemberGatherer {
var selectorField = SelectorField (ea, true);
if (!InlineSelectors) {
selectorField = selectorField.Substring (0, selectorField.Length - 6 /* Handle */);
print ("[CompilerGenerated]");
print_generated_code ();
print ("const string {0} = \"{1}\";", selectorField, ea);
print ("static readonly IntPtr {0} = Selector.GetHandle (\"{1}\");", SelectorField (ea), ea);
}
@ -5975,7 +5975,7 @@ public partial class Generator : IMemberGatherer {
objc_type_name = FormatCategoryClassName (bta);
if (!is_model) {
print ("[CompilerGenerated]");
print_generated_code ();
print ("static readonly IntPtr class_ptr = Class.GetHandle (\"{0}\");\n", objc_type_name);
}
}
@ -6226,7 +6226,7 @@ public partial class Generator : IMemberGatherer {
// Value types we dont cache for now, to avoid Nullable<T>
if (!field_pi.PropertyType.IsValueType || smartEnumTypeName != null) {
print ("[CompilerGenerated]");
print_generated_code ();
PrintPreserveAttribute (field_pi);
print ("static {0} _{1};", fieldTypeName, field_pi.Name);
}
@ -6753,7 +6753,7 @@ public partial class Generator : IMemberGatherer {
if (!is_static_class){
var disposeAttr = AttributeManager.GetCustomAttributes<DisposeAttribute> (type);
if (disposeAttr.Length > 0 || instance_fields_to_clear_on_dispose.Count > 0){
print ("[CompilerGenerated]");
print_generated_code ();
print ("protected override void Dispose (bool disposing)");
print ("{");
indent++;

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

@ -238,6 +238,7 @@ namespace Introspection
"Imap",
"Imaps",
"Img",
"Impl", // BindingImplAttribute
"Indoorrun",
"Indoorcycle",
"Inklist",

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

@ -186,18 +186,30 @@ namespace Linker.Shared {
[Test]
public void IntPtrSizeTest ()
{
MethodInfo passingMethod = null;
MethodInfo failingMethod = null;
var S8methods = new MethodInfo []
{
GetType ().GetMethod (nameof (Size8Test), BindingFlags.NonPublic | BindingFlags.Instance),
GetType ().GetMethod (nameof (Size8Test_Optimizable), BindingFlags.NonPublic | BindingFlags.Instance)
};
var S4methods = new MethodInfo []
{
GetType ().GetMethod (nameof (Size4Test), BindingFlags.NonPublic | BindingFlags.Instance),
GetType ().GetMethod (nameof (Size4Test_Optimizable), BindingFlags.NonPublic | BindingFlags.Instance)
};
MethodInfo[] passingMethods = null;
MethodInfo[] failingMethods = null;
switch (IntPtr.Size) {
case 4:
Size4Test ();
passingMethod = GetType ().GetMethod (nameof (Size4Test), BindingFlags.NonPublic | BindingFlags.Instance);
failingMethod = GetType ().GetMethod (nameof (Size8Test), BindingFlags.NonPublic | BindingFlags.Instance);
Size4Test_Optimizable ();
passingMethods = S4methods;
failingMethods = S8methods;
break;
case 8:
Size8Test ();
passingMethod = GetType ().GetMethod (nameof (Size8Test), BindingFlags.NonPublic | BindingFlags.Instance);
failingMethod = GetType ().GetMethod (nameof (Size4Test), BindingFlags.NonPublic | BindingFlags.Instance);
Size8Test_Optimizable ();
passingMethods = S8methods;
failingMethods = S4methods;
break;
default:
Assert.Fail ("Invalid size: {0}", IntPtr.Size);
@ -209,12 +221,16 @@ namespace Linker.Shared {
// Unfortunately in debug mode csc produces IL sequences the optimizer doesn't understand (a lot of unnecessary instructions),
// which means we can only check this in release mode. Also on device this will probably always pass,
// since we strip assemblies (and the methods will always be empty), but running the test shouldn't hurt.
IEnumerable<ILInstruction> passingInstructions = new ILReader (passingMethod);
IEnumerable<ILInstruction> failingInstructions = new ILReader (failingMethod);
passingInstructions = passingInstructions.Where ((v) => v.OpCode.Name != "nop");
failingInstructions = failingInstructions.Where ((v) => v.OpCode.Name != "nop");
Assert.AreEqual (1, passingInstructions.Count (), "empty body");
Assert.That (failingInstructions.Count (), Is.GreaterThan (1), "non-empty body");
foreach (var passingMethod in passingMethods) {
IEnumerable<ILInstruction> passingInstructions = new ILReader (passingMethod);
passingInstructions = passingInstructions.Where ((v) => v.OpCode.Name != "nop");
Assert.AreEqual (1, passingInstructions.Count (), "empty body");
}
foreach (var failingMethod in failingMethods) {
IEnumerable<ILInstruction> failingInstructions = new ILReader (failingMethod);
failingInstructions = failingInstructions.Where ((v) => v.OpCode.Name != "nop");
Assert.That (failingInstructions.Count (), Is.GreaterThan (1), "non-empty body");
}
#endif
}
@ -255,6 +271,42 @@ namespace Linker.Shared {
if (IntPtr.Size <= 3)
throw new NUnit.Framework.Internal.NUnitException ("6");
}
[BindingImplAttribute (BindingImplOptions.Optimizable)]
void Size8Test_Optimizable ()
{
// Everything in this method should be optimized away (when building for 64-bits)
if (IntPtr.Size != 8)
throw new NUnit.Framework.Internal.NUnitException ("1");
if (IntPtr.Size == 4)
throw new NUnit.Framework.Internal.NUnitException ("2");
if (IntPtr.Size > 8)
throw new NUnit.Framework.Internal.NUnitException ("3");
if (IntPtr.Size < 8)
throw new NUnit.Framework.Internal.NUnitException ("4");
if (IntPtr.Size >= 9)
throw new NUnit.Framework.Internal.NUnitException ("5");
if (IntPtr.Size <= 7)
throw new NUnit.Framework.Internal.NUnitException ("6");
}
[BindingImplAttribute (BindingImplOptions.Optimizable)]
void Size4Test_Optimizable ()
{
// Everything in this method should be optimized away (when building for 32-bits)
if (IntPtr.Size != 4)
throw new NUnit.Framework.Internal.NUnitException ("1");
if (IntPtr.Size == 8)
throw new NUnit.Framework.Internal.NUnitException ("2");
if (IntPtr.Size > 4)
throw new NUnit.Framework.Internal.NUnitException ("3");
if (IntPtr.Size < 4)
throw new NUnit.Framework.Internal.NUnitException ("4");
if (IntPtr.Size >= 5)
throw new NUnit.Framework.Internal.NUnitException ("5");
if (IntPtr.Size <= 3)
throw new NUnit.Framework.Internal.NUnitException ("6");
}
#endif
}
}

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

@ -166,6 +166,8 @@ namespace Xamarin.Bundler {
get { return verbose; }
}
public const bool IsXAMCORE_4_0 = false;
#if MONOMAC
#pragma warning disable 0414
static string userTargetFramework = TargetFramework.Default.ToString ();

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

@ -66,7 +66,7 @@ namespace Xamarin.Linker.Steps {
if (!Annotations.IsMarked (od))
continue;
// we do NOT process non-generated code - we could break user code
if (!od.IsGeneratedCode (LinkContext))
if (!od.IsOptimizableCode (LinkContext))
continue;
ProcessDispose (skip ? bd : cd, od);
@ -142,7 +142,7 @@ namespace Xamarin.Linker.Steps {
{
if (!method.IsFamily || !method.IsVirtual || method.IsNewSlot || !method.HasParameters || !method.HasBody)
return false;
return ((method.Name == "Dispose") && method.IsGeneratedCode (LinkContext));
return ((method.Name == "Dispose") && method.IsOptimizableCode (LinkContext));
}
protected override TypeDefinition MarkType (TypeReference reference)
@ -254,7 +254,7 @@ namespace Xamarin.Linker.Steps {
var td = i.Module.GetType (i.Namespace, i.Name.Substring (1) + "_Extensions");
if (td != null && td.HasMethods) {
foreach (var m in td.Methods) {
if (!m.HasParameters || (m.Name != name) || !m.IsGeneratedCode (LinkContext))
if (!m.HasParameters || (m.Name != name) || !m.IsOptimizableCode (LinkContext))
continue;
bool proxy = false;
match = method.Parameters.Count == m.Parameters.Count - 1;

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

@ -22,7 +22,7 @@ namespace Xamarin.Linker {
protected override string Name { get; } = "Binding Optimizer";
protected override int ErrorCode { get; } = 2020;
protected bool HasGeneratedCode { get; private set; }
protected bool HasOptimizableCode { get; private set; }
protected bool IsExtensionType { get; private set; }
protected LinkerOptions Options { get; set; }
@ -73,19 +73,24 @@ namespace Xamarin.Linker {
}
// if the assembly does not refer to [CompilerGeneratedAttribute] then there's not much we can do
HasGeneratedCode = false;
HasOptimizableCode = false;
foreach (TypeReference tr in assembly.MainModule.GetTypeReferences ()) {
if (tr.Is ("System.Runtime.CompilerServices", "CompilerGeneratedAttribute")) {
if (tr.Is (Namespaces.ObjCRuntime, "BindingImplAttribute")) {
HasOptimizableCode = true;
break;
}
if (!Driver.IsXAMCORE_4_0 && tr.Is ("System.Runtime.CompilerServices", "CompilerGeneratedAttribute")) {
#if DEBUG
Console.WriteLine ("Assembly {0} : processing", assembly);
#endif
HasGeneratedCode = true;
HasOptimizableCode = true;
break;
}
}
#if DEBUG
if (!HasGeneratedCode)
Console.WriteLine ("Assembly {0} : no [CompilerGeneratedAttribute] present (applying basic optimizations)", assembly);
if (!HasOptimizableCode)
Console.WriteLine ("Assembly {0} : no [CompilerGeneratedAttribute] nor [BindingImplAttribute] present (applying basic optimizations)", assembly);
#endif
// we always apply the step
return true;
@ -93,7 +98,7 @@ namespace Xamarin.Linker {
protected override void Process (TypeDefinition type)
{
if (!HasGeneratedCode)
if (!HasOptimizableCode)
return;
isdirectbinding_constant = type.IsNSObject (LinkContext) ? type.GetIsDirectBindingConstant (LinkContext) : null;
@ -537,7 +542,9 @@ namespace Xamarin.Linker {
if (!method.HasBody)
return;
if (method.IsGeneratedCode (LinkContext) && (IsExtensionType || IsExport (method))) {
if (method.IsBindingImplOptimizableCode (LinkContext)) {
// We optimize all methods that have the [BindingImpl (BindingImplAttributes.Optimizable)] attribute.
} else if (!Driver.IsXAMCORE_4_0 && (method.IsGeneratedCode (LinkContext) && (IsExtensionType || IsExport (method)))) {
// We optimize methods that have the [GeneratedCodeAttribute] and is either an extension type or an exported method
} else {
// but it would be too risky to apply on user-generated code

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

@ -43,6 +43,7 @@ namespace Xamarin.Linker {
case "LinkWithAttribute":
case "DesignatedInitializerAttribute":
case "RequiresSuperAttribute":
case "BindingImplAttribute":
return attr_type.Namespace == Namespaces.ObjCRuntime;
default:
return base.IsRemovedAttribute (attribute);
@ -60,6 +61,9 @@ namespace Xamarin.Linker {
case "IntroducedAttribute":
LinkContext.StoreCustomAttribute (provider, attribute, "Availability");
break;
case "BindingImplAttribute":
LinkContext.StoreCustomAttribute (provider, attribute);
break;
}
}

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

@ -1,15 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
using Mono.Tuner;
using XamCore.ObjCRuntime;
using Xamarin.Bundler;
using Xamarin.Tuner;
namespace Xamarin.Linker {
public static class MobileExtensions {
// Returns a string representation of the specified provider that is suitable for user-visible error/warning messages.
public static string AsString (this ICustomAttributeProvider provider)
{
if (provider is MemberReference member)
return member.DeclaringType.FullName + "." + member.Name;
if (provider is MethodReturnType returnType)
return AsString ((ICustomAttributeProvider) returnType.Method);
return provider.ToString ();
}
// This method will look in any stored attributes in the link context as well as the provider itself.
public static bool HasCustomAttribute (this ICustomAttributeProvider provider, DerivedLinkContext context, string @namespace, string name)
{
@ -37,6 +50,48 @@ namespace Xamarin.Linker {
return provider.HasCustomAttribute (context, "System.Runtime.CompilerServices", "CompilerGeneratedAttribute");
}
// The 'provider' parameter is only used in error messages to explain where the broken attribute comes from
// (in particular it's not used to get the custom attributes themselves, since those may not come from this provider instance)
static BindingImplOptions? GetBindingImplAttribute (ICustomAttributeProvider provider, IEnumerable<ICustomAttribute> attributes)
{
if (attributes == null)
return null;
foreach (var ca in attributes) {
TypeReference tr = ca.AttributeType;
if (!tr.Is (Namespaces.ObjCRuntime, "BindingImplAttribute"))
continue;
if (ca.HasFields)
throw ErrorHelper.CreateError (2105, "The [BindingImpl] attribute on the member '{0}' is invalid: did not expect fields.", provider.AsString ());
if (ca.HasProperties)
throw ErrorHelper.CreateError (2105, "The [BindingImpl] attribute on the member '{0}' is invalid: did not expect properties.", provider.AsString ());
switch (ca.ConstructorArguments.Count) {
case 1:
var arg = ca.ConstructorArguments [0];
if (!arg.Type.Is (Namespaces.ObjCRuntime, "BindingImplOptions"))
throw ErrorHelper.CreateError (2105, "The [BindingImpl] attribute on the member '{0}' is invalid: did not expect a constructor with a '{1}' parameter type (expected 'ObjCRuntime.BindingImplOptions).", provider.AsString (), arg.Type.FullName);
return (BindingImplOptions) (int) arg.Value;
default:
throw ErrorHelper.CreateError (2105, "The [BindingImpl] attribute on the member '{0}' is invalid: did not expect a constructor with a {1} parameters (expected 1 parameters).", provider.AsString (), ca.ConstructorArguments.Count);
}
}
return null;
}
static BindingImplOptions? GetBindingImplAttribute (ICustomAttributeProvider provider, DerivedLinkContext context)
{
if (provider != null && provider.HasCustomAttributes) {
var rv = GetBindingImplAttribute (provider, provider.CustomAttributes);
if (rv != null)
return rv;
}
return GetBindingImplAttribute (provider, context?.GetCustomAttributes (provider, Namespaces.ObjCRuntime, "BindingImplOptions"));
}
static PropertyDefinition GetPropertyByAccessor (MethodDefinition method)
{
foreach (PropertyDefinition property in method.DeclaringType.Properties) {
@ -55,5 +110,32 @@ namespace Xamarin.Linker {
}
return HasGeneratedCodeAttribute (self, link_context);
}
public static bool IsBindingImplOptimizableCode (this MethodDefinition self, DerivedLinkContext link_context)
{
var attrib = GetBindingImplAttribute (self, link_context);
if ((attrib & BindingImplOptions.Optimizable) == BindingImplOptions.Optimizable)
return true;
// Check the property too
if (self.IsGetter || self.IsSetter) {
attrib = GetBindingImplAttribute (GetPropertyByAccessor (self), link_context);
if ((attrib & BindingImplOptions.Optimizable) == BindingImplOptions.Optimizable)
return true;
}
return false;
}
public static bool IsOptimizableCode (this MethodDefinition self, DerivedLinkContext link_context)
{
if (IsBindingImplOptimizableCode (self, link_context))
return true;
if (!Driver.IsXAMCORE_4_0 && IsGeneratedCode (self, link_context))
return true;
return false;
}
}
}

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

@ -51,15 +51,6 @@ namespace Xamarin.Linker.Steps
}
}
static string ProviderToString (ICustomAttributeProvider provider)
{
if (provider is MemberReference member)
return member.DeclaringType.FullName + "." + member.Name;
if (provider is MethodReturnType returnType)
return ProviderToString ((ICustomAttributeProvider) returnType.Method);
return provider.ToString ();
}
void ProcessAttributeProvider (ICustomAttributeProvider provider, MethodDefinition conditionA, MethodDefinition conditionB = null)
{
if (provider?.HasCustomAttributes != true)
@ -72,14 +63,14 @@ namespace Xamarin.Linker.Steps
continue;
if (ca.ConstructorArguments.Count != 1) {
ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.Target.App, 4124, provider, "Invalid BindAsAttribute found on '{0}': should have 1 constructor arguments, found {1}. Please file a bug report at https://bugzilla.xamarin.com", ProviderToString (provider), ca.ConstructorArguments.Count));
ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.Target.App, 4124, provider, "Invalid BindAsAttribute found on '{0}': should have 1 constructor arguments, found {1}. Please file a bug report at https://bugzilla.xamarin.com", provider.AsString (), ca.ConstructorArguments.Count));
continue;
}
var managedType = ca.ConstructorArguments [0].Value as TypeReference;
var managedEnumType = managedType?.GetElementType ().Resolve ();
if (managedEnumType == null) {
ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.Target.App, 4124, provider, "Invalid BindAsAttribute found on '{0}': could not find the underlying enum type of {1}. Please file a bug report at https://bugzilla.xamarin.com", ProviderToString (provider), managedType?.FullName));
ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.Target.App, 4124, provider, "Invalid BindAsAttribute found on '{0}': could not find the underlying enum type of {1}. Please file a bug report at https://bugzilla.xamarin.com", provider.AsString (), managedType?.FullName));
continue;
}
@ -105,7 +96,7 @@ namespace Xamarin.Linker.Steps
break;
}
if (extensionType == null) {
Driver.Log (1, $"Could not find a smart extension type for the enum {managedEnumType.FullName} (due to BindAs attribute on {ProviderToString (provider)}): most likely this is because the enum isn't a smart enum.");
Driver.Log (1, $"Could not find a smart extension type for the enum {managedEnumType.FullName} (due to BindAs attribute on {provider.AsString ()}): most likely this is because the enum isn't a smart enum.");
continue;
}
@ -134,12 +125,12 @@ namespace Xamarin.Linker.Steps
}
if (getConstant == null) {
Driver.Log (1, $"Could not find the GetConstant method on the supposedly smart extension type {extensionType.FullName} for the enum {managedEnumType.FullName} (due to BindAs attribute on {ProviderToString (provider)}): most likely this is because the enum isn't a smart enum.");
Driver.Log (1, $"Could not find the GetConstant method on the supposedly smart extension type {extensionType.FullName} for the enum {managedEnumType.FullName} (due to BindAs attribute on {provider.AsString ()}): most likely this is because the enum isn't a smart enum.");
continue;
}
if (getValue == null) {
Driver.Log (1, $"Could not find the GetValue method on the supposedly smart extension type {extensionType.FullName} for the enum {managedEnumType.FullName} (due to BindAs attribute on {ProviderToString (provider)}): most likely this is because the enum isn't a smart enum.");
Driver.Log (1, $"Could not find the GetValue method on the supposedly smart extension type {extensionType.FullName} for the enum {managedEnumType.FullName} (due to BindAs attribute on {provider.AsString ()}): most likely this is because the enum isn't a smart enum.");
continue;
}

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

@ -136,6 +136,7 @@ mmp_sources = \
$(TOP)/src/Foundation/ConnectAttribute.cs \
$(TOP)/src/Foundation/ExportAttribute.cs \
$(TOP)/src/ObjCRuntime/ArgumentSemantic.cs \
$(TOP)/src/ObjCRuntime/BindingImplAttribute.cs \
$(TOP)/src/ObjCRuntime/LinkWithAttribute.cs \
$(TOP)/src/ObjCRuntime/PlatformAvailability2.cs \

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

@ -341,6 +341,9 @@
<Compile Include="..\..\src\ObjCRuntime\PlatformAvailability2.cs">
<Link>external\PlatformAvailability2.cs</Link>
</Compile>
<Compile Include="..\..\src\ObjCRuntime\BindingImplAttribute.cs">
<Link>external\BindingImplAttribute.cs</Link>
</Compile>
<Compile Include="..\common\PInvokeWrapperGenerator.cs">
<Link>external\PInvokeWrapperGenerator.cs</Link>
</Compile>

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

@ -105,6 +105,7 @@ MTOUCH_SOURCES = \
$(COMMON_SOURCES) \
$(LINKER_SOURCES) \
$(TOP)/src/ObjCRuntime/ArgumentSemantic.cs \
$(TOP)/src/ObjCRuntime/BindingImplAttribute.cs \
$(TOP)/src/ObjCRuntime/LinkWithAttribute.cs \
$(TOP)/src/ObjCRuntime/NativeAttribute.cs \
$(TOP)/src/ObjCRuntime/PlatformAvailability2.cs \

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

@ -360,6 +360,9 @@
<Compile Include="..\common\Optimizations.cs">
<Link>external\Optimizations.cs</Link>
</Compile>
<Compile Include="..\..\src\ObjCRuntime\BindingImplAttribute.cs">
<Link>external\maccore\BindingImplAttribute.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<Reference Include="System.Core" />