[xcode16] Merge main into xcode16.

This commit is contained in:
Rolf Bjarne Kvinge 2024-09-02 19:51:07 +02:00
Родитель 6ba3c7893d 3b6a5c20c6
Коммит 73683f8124
10 изменённых файлов: 239 добавлений и 2 удалений

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

@ -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;
}
}
}

18
tools/mtouch/Errors.designer.cs сгенерированный
Просмотреть файл

@ -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 &apos;{1}&apos;
/// .

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

@ -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 -->