[xcode16] Merge main into xcode16.
This commit is contained in:
Коммит
73683f8124
|
@ -718,6 +718,14 @@ public partial class Generator : IMemberGatherer {
|
|||
}
|
||||
}
|
||||
|
||||
if (pi.ParameterType.IsPointer && pi.ParameterType.GetElementType ().IsValueType) {
|
||||
// Technically we should only allow blittable types here, but the C# compiler shows an error later on if any non-blittable types
|
||||
// are used, because this ends up in the signature of a UnmanagedCallersOnly method.
|
||||
pars.Add (new TrampolineParameterInfo (TypeManager.FormatType (null, pi.ParameterType), safe_name));
|
||||
invoke.Append (safe_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pi.ParameterType.IsSubclassOf (TypeCache.System_Delegate)) {
|
||||
if (!delegate_types.ContainsKey (pi.ParameterType.Name)) {
|
||||
delegate_types [pi.ParameterType.FullName] = pi.ParameterType.GetMethod ("Invoke");
|
||||
|
@ -4732,11 +4740,13 @@ public partial class Generator : IMemberGatherer {
|
|||
print ("[MonoNativeFunctionWrapper]\n");
|
||||
|
||||
var accessibility = mi.DeclaringType.IsInternal (this) ? "internal" : "public";
|
||||
print ("{3} delegate {0} {1} ({2});",
|
||||
var isUnsafe = mi.GetParameters ().Any ((v => v.ParameterType.IsPointer)) || mi.ReturnType.IsPointer;
|
||||
print ("{3}{4} delegate {0} {1} ({2});",
|
||||
TypeManager.RenderType (mi.ReturnType, mi.ReturnTypeCustomAttributes),
|
||||
shortName,
|
||||
RenderParameterDecl (mi.GetParameters ()),
|
||||
accessibility);
|
||||
accessibility,
|
||||
isUnsafe ? " unsafe" : string.Empty);
|
||||
}
|
||||
|
||||
if (group.Namespace is not null) {
|
||||
|
@ -5075,6 +5085,7 @@ public partial class Generator : IMemberGatherer {
|
|||
foreach (var docId in docIds) {
|
||||
print ($"[DynamicDependencyAttribute (\"{docId}\")]");
|
||||
}
|
||||
print ("[BindingImpl (BindingImplOptions.GeneratedCode | BindingImplOptions.Optimizable)]");
|
||||
print ($"static I{TypeName} ()");
|
||||
print ("{");
|
||||
print ("\tGC.KeepAlive (null);"); // need to do _something_ (doesn't seem to matter what), otherwise the static cctor (and the DynamicDependency attributes) are trimmed away.
|
||||
|
|
|
@ -1719,5 +1719,20 @@ namespace GeneratorTests {
|
|||
var delegateCallback = bgen.ApiAssembly.MainModule.GetType ("NS", "MyCallback").Methods.First ((v) => v.Name == "EndInvoke");
|
||||
Assert.That (delegateCallback.MethodReturnType.CustomAttributes.Any (v => v.AttributeType.Name == "NullableAttribute"), "Nullable return type");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase (Profile.iOS)]
|
||||
public void DelegatesWithPointerTypes (Profile profile)
|
||||
{
|
||||
Configuration.IgnoreIfIgnoredPlatform (profile.AsPlatform ());
|
||||
var bgen = BuildFile (profile, "tests/delegate-types.cs");
|
||||
bgen.AssertNoWarnings ();
|
||||
|
||||
var delegateCallback = bgen.ApiAssembly.MainModule.GetType ("NS", "MyCallback").Methods.First ((v) => v.Name == "EndInvoke");
|
||||
Assert.IsTrue (delegateCallback.MethodReturnType.ReturnType.IsPointer, "Pointer return type");
|
||||
foreach (var p in delegateCallback.Parameters.Where (v => v.Name != "result")) {
|
||||
Assert.IsTrue (p.ParameterType.IsPointer, $"Pointer parameter type: {p.Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
|
||||
using Foundation;
|
||||
using ObjCRuntime;
|
||||
|
||||
namespace NS {
|
||||
unsafe delegate byte* MyCallback (sbyte* a, short* b, ushort* c, int* d, uint* e, long* f, ulong* g, float* h, double* i);
|
||||
|
||||
[BaseType (typeof (NSObject))]
|
||||
interface Widget {
|
||||
[Export ("foo")]
|
||||
[NullAllowed]
|
||||
MyCallback Foo { get; set; }
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading;
|
||||
|
@ -5536,6 +5537,37 @@ namespace MonoTouchFixtures.ObjCRuntime {
|
|||
Assert.AreEqual (EnumUL.b, ul, "out: UL");
|
||||
}
|
||||
}
|
||||
|
||||
#if NET && HAS_UIKIT
|
||||
[Test]
|
||||
public void ProtocolsTrimmedAway ()
|
||||
{
|
||||
PreserveIUIApplicationDelegate (null);
|
||||
|
||||
// A little indirection to try to make the trimmer not be helpful and preserve all the methods on IUIApplicationDelegate.
|
||||
AssertMemberCount (typeof (IUIApplicationDelegate));
|
||||
}
|
||||
|
||||
void AssertMemberCount (Type type)
|
||||
{
|
||||
var members = type.GetMembers (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
|
||||
#if OPTIMIZEALL || NATIVEAOT
|
||||
var expectNoMembers = true;
|
||||
#else
|
||||
var expectNoMembers = false;
|
||||
#endif
|
||||
if (expectNoMembers) {
|
||||
Assert.AreEqual (0, members.Length, $"All members should be trimmed away in {type.FullName}:\n\t{string.Join ("\n\t", members.Select (v => v.ToString ()))}");
|
||||
} else {
|
||||
Assert.AreNotEqual (0, members.Length, $"All members should not be trimmed away in {type.FullName}");
|
||||
}
|
||||
}
|
||||
|
||||
void PreserveIUIApplicationDelegate (IUIApplicationDelegate obj)
|
||||
{
|
||||
GC.KeepAlive (obj);
|
||||
}
|
||||
#endif // NET && HAS_UIKIT
|
||||
}
|
||||
|
||||
#if !__WATCHOS__
|
||||
|
|
|
@ -26,6 +26,12 @@ namespace Xamarin.Linker {
|
|||
if (!Annotations.IsMarked (type))
|
||||
LinkContext.AddLinkedAwayType (type);
|
||||
|
||||
if (type.IsInterface &&
|
||||
Configuration.DerivedLinkContext.App.Optimizations.RegisterProtocols == true &&
|
||||
type.HasCustomAttribute (LinkContext, Namespaces.Foundation, "ProtocolAttribute")) {
|
||||
Configuration.DerivedLinkContext.StoreProtocolMethods (type);
|
||||
}
|
||||
|
||||
if (type.HasInterfaces) {
|
||||
foreach (var iface in type.Interfaces) {
|
||||
if (Annotations.IsMarked (iface))
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace Xamarin.Linker.Steps {
|
|||
class PreMarkDispatcher : SubStepsDispatcher {
|
||||
public PreMarkDispatcher ()
|
||||
: base (new BaseSubStep [] {
|
||||
new SetBeforeFieldInitStep (),
|
||||
new CollectUnmarkedMembersSubStep (),
|
||||
new StoreAttributesStep ()
|
||||
})
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
using Mono.Linker.Steps;
|
||||
using Xamarin.Linker;
|
||||
|
||||
using Mono.Cecil;
|
||||
using Mono.Tuner;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Xamarin.Linker.Steps {
|
||||
public class SetBeforeFieldInitStep : ConfigurationAwareSubStep {
|
||||
protected override string Name { get; } = "Set BeforeFieldInit";
|
||||
protected override int ErrorCode { get; } = 2380;
|
||||
|
||||
public override SubStepTargets Targets {
|
||||
get {
|
||||
return SubStepTargets.Type;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Process (TypeDefinition type)
|
||||
{
|
||||
// If we're registering protocols, we want to remove the static
|
||||
// constructor on the protocol interface, because it's not needed
|
||||
// (because we've removing all the DynamicDependency attributes
|
||||
// from the cctor).
|
||||
//
|
||||
// However, just removing the static constructor from the type
|
||||
// causes problems later on in the trimming process, so we want
|
||||
// the trimmer to just not mark it.
|
||||
//
|
||||
// The trimmer marks it, because it has a static constructor, so
|
||||
// we're in a bit of a cyclic dependency here.
|
||||
//
|
||||
// This is complicated by a few facts:
|
||||
// - When we optimize the cctor (i.e. removing the
|
||||
// DynamicDependency attributes), the cctor is already marked.
|
||||
// - Adding a MarkHandler that processes types doesn't work
|
||||
// either, because it may be called after the cctor is marked:
|
||||
// https://github.com/dotnet/runtime/blob/6177a9f920861900681cfda2b6cc66ac3557e93b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs#L1928-L1952
|
||||
//
|
||||
// So this is a pre-mark step that just sets
|
||||
// IsBeforeFieldInit=true for interfaces we want trimmed away by
|
||||
// the linker.
|
||||
|
||||
if (Configuration.DerivedLinkContext.App.Optimizations.RegisterProtocols != true)
|
||||
return;
|
||||
|
||||
if (!type.IsBeforeFieldInit && type.IsInterface && type.HasMethods) {
|
||||
var cctor = type.GetTypeConstructor ();
|
||||
if (cctor is not null && cctor.IsBindingImplOptimizableCode (LinkContext))
|
||||
type.IsBeforeFieldInit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -755,6 +755,9 @@ namespace Xamarin.Linker {
|
|||
return; // nothing else to do here.
|
||||
}
|
||||
|
||||
if (ProcessProtocolInterfaceStaticConstructor (method))
|
||||
return;
|
||||
|
||||
var instructions = method.Body.Instructions;
|
||||
for (int i = 0; i < instructions.Count; i++) {
|
||||
var ins = instructions [i];
|
||||
|
@ -1191,6 +1194,19 @@ namespace Xamarin.Linker {
|
|||
return ins;
|
||||
}
|
||||
|
||||
static Instruction SkipNops (Instruction ins)
|
||||
{
|
||||
if (ins is null)
|
||||
return null;
|
||||
|
||||
while (ins.OpCode == OpCodes.Nop) {
|
||||
if (ins.Next is null)
|
||||
return null;
|
||||
ins = ins.Next;
|
||||
}
|
||||
return ins;
|
||||
}
|
||||
|
||||
int ProcessIsARM64CallingConvention (MethodDefinition caller, Instruction ins)
|
||||
{
|
||||
const string operation = "inline Runtime.IsARM64CallingConvention";
|
||||
|
@ -1345,5 +1361,66 @@ namespace Xamarin.Linker {
|
|||
}
|
||||
return caller.Module.ImportReference (block_ctor_def);
|
||||
}
|
||||
|
||||
bool ProcessProtocolInterfaceStaticConstructor (MethodDefinition method)
|
||||
{
|
||||
// The static cctor in protocol interfaces exists only to preserve the protocol's members, for inspection by the registrar(s).
|
||||
// If we're registering protocols, then we don't need to preserve protocol members, because the registrar
|
||||
// already knows everything about it => we can remove the static cctor.
|
||||
|
||||
if (!(method.DeclaringType.IsInterface && method.DeclaringType.IsInterface && method.IsStatic && method.IsConstructor && method.HasBody))
|
||||
return false;
|
||||
|
||||
if (Optimizations.RegisterProtocols != true) {
|
||||
Driver.Log (4, "Did not optimize static constructor in the protocol interface {0}: the 'register-protocols' optimization is disabled.", method.DeclaringType.FullName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!method.DeclaringType.HasCustomAttributes || !method.DeclaringType.CustomAttributes.Any (v => v.AttributeType.Is ("Foundation", "ProtocolAttribute"))) {
|
||||
Driver.Log (4, "Did not optimize static constructor in the protocol interface {0}: no Protocol attribute found.", method.DeclaringType.FullName);
|
||||
return false;
|
||||
}
|
||||
|
||||
var ins = SkipNops (method.Body.Instructions.First ());
|
||||
if (ins is null) {
|
||||
ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.App, 2112, method, ins, Errors.MX2112_A /* Could not optimize the static constructor in the interface {0} because it did not have the expected instruction sequence (found end of method too soon). */, method.DeclaringType.FullName));
|
||||
return false;
|
||||
} else if (ins.OpCode != OpCodes.Ldnull) {
|
||||
ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.App, 2112, method, ins, Errors.MX2112_B /* Could not optimize the static constructor in the interface {0} because it had an unexpected instruction {1} at offset {2}. */, method.DeclaringType.FullName, ins.OpCode, ins.Offset));
|
||||
return false;
|
||||
}
|
||||
|
||||
ins = SkipNops (ins.Next);
|
||||
var callGCKeepAlive = ins;
|
||||
if (ins is null) {
|
||||
ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.App, 2112, method, ins, Errors.MX2112_A /* Could not optimize the static constructor in the interface {0} because it did not have the expected instruction sequence (found end of method too soon). */, method.DeclaringType.FullName));
|
||||
return false;
|
||||
} else if (callGCKeepAlive.OpCode != OpCodes.Call || !(callGCKeepAlive.Operand is MethodReference methodOperand) || methodOperand.Name != "KeepAlive" || !methodOperand.DeclaringType.Is ("System", "GC")) {
|
||||
ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.App, 2112, method, ins, Errors.MX2112_B /* Could not optimize the static constructor in the interface {0} because it had an unexpected instruction {1} at offset {2}. */, method.DeclaringType.FullName, ins.OpCode, ins.Offset));
|
||||
return false;
|
||||
}
|
||||
|
||||
ins = SkipNops (ins.Next);
|
||||
if (ins is null) {
|
||||
ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.App, 2112, method, ins, Errors.MX2112_A /* Could not optimize the static constructor in the interface {0} because it did not have the expected instruction sequence (found end of method too soon). */, method.DeclaringType.FullName));
|
||||
return false;
|
||||
} else if (ins.OpCode != OpCodes.Ret) {
|
||||
ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.App, 2112, method, ins, Errors.MX2112_B /* Could not optimize the static constructor in the interface {0} because it had an unexpected instruction {1} at offset {2}. */, method.DeclaringType.FullName, ins.OpCode, ins.Offset));
|
||||
return false;
|
||||
}
|
||||
|
||||
ins = SkipNops (ins.Next);
|
||||
if (ins is not null) {
|
||||
ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.App, 2112, method, ins, Errors.MX2112_B /* Could not optimize the static constructor in the interface {0} because it had an unexpected instruction {1} at offset {2}. */, method.DeclaringType.FullName, ins.OpCode, ins.Offset));
|
||||
return false;
|
||||
}
|
||||
|
||||
// We can just remove the entire method, however that confuses the linker later on, so just empty it out and remove all the attributes.
|
||||
Driver.Log (4, "Optimized static constructor in the protocol interface {0} (static constructor was cleared and custom attributes removed)", method.DeclaringType.FullName);
|
||||
method.Body.Instructions.Clear ();
|
||||
method.Body.Instructions.Add (Instruction.Create (OpCodes.Ret));
|
||||
method.CustomAttributes.Clear ();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3932,6 +3932,24 @@ namespace Xamarin.Bundler {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Could not optimize the static constructor in the interface {0} because it did not have the expected instruction sequence (found end of method too soon)..
|
||||
/// </summary>
|
||||
public static string MX2112_A {
|
||||
get {
|
||||
return ResourceManager.GetString("MX2112_A", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Could not optimize the static constructor in the interface {0} because it had an unexpected instruction {1} at offset {2}..
|
||||
/// </summary>
|
||||
public static string MX2112_B {
|
||||
get {
|
||||
return ResourceManager.GetString("MX2112_B", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Could not {0} the assembly '{1}'
|
||||
/// .
|
||||
|
|
|
@ -1327,6 +1327,13 @@
|
|||
</value>
|
||||
</data>
|
||||
|
||||
<data name="MX2112_A" xml:space="preserve">
|
||||
<value>Could not optimize the static constructor in the interface {0} because it did not have the expected instruction sequence (found end of method too soon).</value>
|
||||
</data>
|
||||
|
||||
<data name="MX2112_B" xml:space="preserve">
|
||||
<value>Could not optimize the static constructor in the interface {0} because it had an unexpected instruction {1} at offset {2}.</value>
|
||||
</data>
|
||||
<!-- 2200 -> 2299 is used by/reserved for ExceptionalSubStep subclasses in the linker -->
|
||||
<!-- 220x: PreserveSmartEnumConversionsSubStep -->
|
||||
<!-- 221x: RemoveBitcodeIncompatibleCodeStep -->
|
||||
|
|
Загрузка…
Ссылка в новой задаче