Skip to content

Commit

Permalink
Merge branch 'main' into Nullable-CoreText
Browse files Browse the repository at this point in the history
  • Loading branch information
tj-devel709 authored Jun 14, 2022
2 parents 5f199c3 + f2d0a16 commit 1726846
Show file tree
Hide file tree
Showing 13 changed files with 260 additions and 131 deletions.
1 change: 0 additions & 1 deletion runtime/trampolines.m
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,6 @@
case '}':
return type++;
default:
type++;
break;
}
}
Expand Down
13 changes: 13 additions & 0 deletions tests/monotouch-test/ObjCRuntime/Messaging.cs
Original file line number Diff line number Diff line change
Expand Up @@ -260,5 +260,18 @@ public struct objc_super {

[DllImport (LIBOBJC_DYLIB, EntryPoint = "objc_msgSend")]
public extern static void void_objc_msgSend_IntPtr_IntPtr_BlockLiteral (IntPtr receiver, IntPtr selector, IntPtr p1, IntPtr p2, ref BlockLiteral p3);

[DllImport (LIBOBJC_DYLIB, EntryPoint = "objc_msgSend")]
public extern static void void_objc_msgSend_NSRange_out_NSRange_ref_NSRange (IntPtr receiver, IntPtr selector, _LongNSRange p1, out _LongNSRange p2, ref _LongNSRange p3);
}

public struct _LongNSRange {
public long Location;
public long Length;
public _LongNSRange (long location, long length)
{
Location = location;
Length = length;
}
}
}
31 changes: 30 additions & 1 deletion tests/monotouch-test/ObjCRuntime/RegistrarTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,36 @@ public static Registrars CurrentRegistrar {
}
}

[Test]
public void NSRangeOutParameter ()
{
using var obj = new NSRangeOutParameterClass ();
var a = new _LongNSRange (-1, -2);
var c = new _LongNSRange (-5, -6);
Messaging.void_objc_msgSend_NSRange_out_NSRange_ref_NSRange (obj.Handle, Selector.GetHandle ("passRange:getRange:refRange:"), a, out var b, ref c);
Assert.AreEqual (a.Location, (long) (-1), "post a Location");
Assert.AreEqual (a.Length, (long) (-2), "post a Length");
Assert.AreEqual (b.Location, (long) 3, "post b Location");
Assert.AreEqual (b.Length, (long) 4, "post b Length");
Assert.AreEqual (c.Location, (long) 5, "post c Location");
Assert.AreEqual (c.Length, (long) 6, "post c Length");
}

class NSRangeOutParameterClass : NSObject {
[Export ("passRange:getRange:refRange:")]
public void DoIt (_LongNSRange a, out _LongNSRange b, ref _LongNSRange c)
{
Assert.AreEqual (a.Location, (long) (-1), "a Location");
Assert.AreEqual (a.Length, (long) (-2), "a Length");
Assert.AreEqual (c.Location, (long) (-5), "c Location");
Assert.AreEqual (c.Length, (long) (-6), "c Length");

a = new _LongNSRange (1, 2);
b = new _LongNSRange (3, 4);
c = new _LongNSRange (5, 6);
}
}

[Test]
public void RegistrarRemoval ()
{
Expand Down Expand Up @@ -5426,7 +5456,6 @@ public static unsafe void Invoke (IntPtr block, nint value)
}
}
#endif // !__WATCHOS__ && !__TVOS__

}

#if !__WATCHOS__
Expand Down
6 changes: 0 additions & 6 deletions tools/devops/automation/templates/build/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,6 @@ steps:
provisioning_extra_args: '-vvvv'
timeoutInMinutes: 250

- bash: |
set -x
set -e
$(Build.SourcesDirectory)/xamarin-macios/system-dependencies.sh --provision-simulators
displayName: 'Provision simulators'

# Use the env variables that were set by the label parsing in the configure step
# print some useful logging to allow to know what is going on AND allow make some
# choices, there are labels that contradict each other (skip-package vs build-packages)
Expand Down
68 changes: 51 additions & 17 deletions tools/nnyeah/nnyeah/ConstructorTransforms.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Microsoft.MaciOS.Nnyeah.AssemblyComparator;
using System.Collections.Generic;
using Mono.Cecil.Cil;
using System.Diagnostics.CodeAnalysis;

namespace Microsoft.MaciOS.Nnyeah {
// Converting constructors from Legacy to NET6 have some special concerns:
Expand All @@ -26,13 +27,15 @@ public class ConstructorTransforms {
MethodDefinition IntPtrCtorWithBool;

// NativeHandle::op_Implicit(IntPtr)
MethodDefinition NativeHandleOpImplicit;
MethodReference NativeHandleOpImplicit;

EventHandler<WarningEventArgs>? WarningIssued;
EventHandler<TransformEventArgs>? Transformed;

Dictionary<string, MethodDefinition> TransformedConstructors = new Dictionary<string, MethodDefinition> ();

public ConstructorTransforms (TypeReference newNativeHandleTypeDefinition, MethodDefinition intPtrCtor, MethodDefinition intPtrCtorWithBool,
EventHandler<WarningEventArgs>? warningIssued, EventHandler<TransformEventArgs>? transformed)
MethodReference nativeHandleOpImplicit, EventHandler<WarningEventArgs>? warningIssued, EventHandler<TransformEventArgs>? transformed)
{
NewNativeHandleTypeDefinition = newNativeHandleTypeDefinition;
IntPtrCtor = intPtrCtor;
Expand All @@ -43,7 +46,7 @@ public ConstructorTransforms (TypeReference newNativeHandleTypeDefinition, Metho
// Get the definition of System.Bool from the ctor we already have
BoolTypeDefinition = intPtrCtorWithBool.Parameters[1].ParameterType;

NativeHandleOpImplicit = NewNativeHandleTypeDefinition.Resolve ().GetMethods ().First (m => m.FullName == "ObjCRuntime.NativeHandle ObjCRuntime.NativeHandle::op_Implicit(System.IntPtr)");
NativeHandleOpImplicit = nativeHandleOpImplicit;
}

public void AddTransforms (TypeAndMemberMap moduleMap)
Expand Down Expand Up @@ -123,45 +126,47 @@ public void ReworkAsNeeded (TypeDefinition definition)
if (ctor.Body.Instructions.Count > 7) {
throw new ConversionException (Errors.E0016, definition);
}

ctor.Parameters [0].ParameterType = NewNativeHandleTypeDefinition;
Transformed?.Invoke (this, new TransformEventArgs (ctor.DeclaringType.FullName,
ctor.Name, "IntPtr", 0, 0));
TransformedConstructors.Add (ctor.ToString (), ctor);
}
}

}

// TODO - There is non-trivial overlap between this and the TryGetConstructorCallTransformation
// codepath below. While it works, unification would be nice.
void ReworkCodeBlockAsNeeded (IEnumerable<MethodDefinition> methods)
{
foreach (var method in methods) {
ReworkCodeBlockAsNeeded (method);
}
}

// (Instruction Index, Number of Ctor Arguments)
List<(int, int)> FindConstructorInstructionIndex (IList<Instruction> instructions)
// (Instruction, Number of Ctor Arguments)
List<(Instruction, int)> FindConstructorInstruction (IList<Instruction> instructions)
{
var index = new List<(int, int)> ();
var index = new List<(Instruction, int)> ();
for (int i = 0 ; i < instructions.Count ; i++) {
Instruction instruction = instructions[i];
if (instruction.OpCode.Code == Code.Newobj && instruction.Operand is MethodDefinition invokedMethod) {
if (invokedMethod.IsConstructor && IsNSObjectDerived (invokedMethod.DeclaringType)) {
switch (invokedMethod.Parameters.Count) {
case 1: {
if (invokedMethod.Parameters[0].ParameterType.ToString () == "System.IntPtr") {
index.Add ((i, 1));
index.Add ((instruction, 1));
}
break;
}
case 2: {
if (invokedMethod.Parameters[0].ParameterType.ToString () == "System.IntPtr" &&
invokedMethod.Parameters[1].ParameterType.ToString () == "System.Boolean") {
index.Add ((i, 2));
index.Add ((instruction, 2));
}
break;
}
default:
throw new ConversionException (Errors.E0017, invokedMethod, invokedMethod.DeclaringType);
}
}
}
Expand All @@ -173,23 +178,52 @@ void ReworkCodeBlockAsNeeded (IEnumerable<MethodDefinition> methods)

void ReworkCodeBlockAsNeeded (MethodDefinition method)
{
foreach ((int index, int argCount) in FindConstructorInstructionIndex (method.Body.Instructions)) {
if (method.Body is null)
return;
var processor = method.Body.GetILProcessor ();
foreach ((Instruction instruction, int argCount) in FindConstructorInstruction (method.Body.Instructions)) {
switch (argCount) {
case 1:
method.Body.Instructions.Insert (index, Instruction.Create (OpCodes.Call, NativeHandleOpImplicit));
processor.InsertBefore (instruction, Instruction.Create (OpCodes.Call, NativeHandleOpImplicit));
break;
case 2: {
var variable = new VariableDefinition (BoolTypeDefinition);
method.Body.Variables.Add (variable);
method.Body.Instructions.Insert (index, Instruction.Create (OpCodes.Ldloc, variable));
method.Body.Instructions.Insert (index, Instruction.Create (OpCodes.Call, NativeHandleOpImplicit));
method.Body.Instructions.Insert (index, Instruction.Create (OpCodes.Stloc, variable));
processor.InsertBefore (instruction, Instruction.Create (OpCodes.Stloc, variable));
processor.InsertBefore (instruction, Instruction.Create (OpCodes.Call, NativeHandleOpImplicit));
processor.InsertBefore (instruction, Instruction.Create (OpCodes.Ldloc, variable));
break;
}
default:
throw new ConversionException (Errors.E0017, method, method.DeclaringType);
}
}
}

public bool TryGetConstructorCallTransformation (Instruction instruction, [NotNullWhen (returnValue: true)] out Transformation? result)
{
if (instruction.OpCode == OpCodes.Newobj &&
instruction.Operand is MethodReference invokedMethod &&
TransformedConstructors.TryGetValue (invokedMethod.ToString (), out var originalCtor)) {
switch (originalCtor.Parameters.Count) {
case 1:
result = new Transformation (instruction.ToString (), TransformationAction.Insert, new List<Instruction> () {
Instruction.Create (OpCodes.Call, NativeHandleOpImplicit)
});
break;
case 2:
result = new Transformation (instruction.ToString (), TransformationAction.Insert, new List<Instruction> () {
Instruction.Create (OpCodes.Stloc, new VariableDefinition (BoolTypeDefinition)),
Instruction.Create (OpCodes.Call, NativeHandleOpImplicit),
Instruction.Create (OpCodes.Ldloc, new VariableDefinition (BoolTypeDefinition)),
});
break;
default:
result = null;
return false;
}
return true;
}
result = null;
return false;
}
}
}
9 changes: 0 additions & 9 deletions tools/nnyeah/nnyeah/Errors.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 0 additions & 3 deletions tools/nnyeah/nnyeah/Errors.resx
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,5 @@
<data name="E0016" xml:space="preserve">
<value>Error while processing constructor on type {0} in the old assembly. Constructors that do non-trivial work are not supported.</value>
</data>
<data name="E0017" xml:space="preserve">
<value>Error while processing method {0} on type {1} in the old assembly. Method was not of expected structure. Conversion can't continue. Your best option is to port the old assembly to .NET 6.</value>
</data>
</root>

11 changes: 9 additions & 2 deletions tools/nnyeah/nnyeah/Reworker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ public static bool NeedsReworking (ModuleDefinition module)
// These must be called last as they depend on Module and NativeIntegerAttributeTypeRef to be setup
var intPtrCtor = modules.XamarinModule.Types.First (t => t.FullName == "Foundation.NSObject").Methods.First (m => m.FullName == "System.Void Foundation.NSObject::.ctor(System.IntPtr)");
var intPtrCtorWithBool = modules.XamarinModule.Types.First (t => t.FullName == "Foundation.NSObject").Methods.First (m => m.FullName == "System.Void Foundation.NSObject::.ctor(System.IntPtr,System.Boolean)");
ConstructorTransforms = new ConstructorTransforms (ModuleToEdit.ImportReference (NewNativeHandleTypeDefinition), intPtrCtor, intPtrCtorWithBool, WarningIssued, Transformed);
var nativeHandleOpImplicit = NewNativeHandleTypeDefinition.Resolve ().GetMethods ().First (m => m.FullName == "ObjCRuntime.NativeHandle ObjCRuntime.NativeHandle::op_Implicit(System.IntPtr)");
ConstructorTransforms = new ConstructorTransforms (ModuleToEdit.ImportReference (NewNativeHandleTypeDefinition), intPtrCtor, intPtrCtorWithBool, ModuleToEdit.ImportReference (nativeHandleOpImplicit), WarningIssued, Transformed);
ConstructorTransforms.AddTransforms (ModuleMap);
NativeHandleGetHandleReference = NewNativeHandleTypeDefinition.Methods.First (m => m.Name == "get_Handle");

Expand Down Expand Up @@ -339,6 +340,8 @@ static bool IsXamarinReference (AssemblyNameReference reference)

void ReworkType (TypeDefinition definition)
{
// This must occur before general processing as
// the list of transformed constructors is used later for rewriting
ConstructorTransforms.ReworkAsNeeded (definition);

foreach (var field in definition.Fields) {
Expand Down Expand Up @@ -524,6 +527,10 @@ void ReworkCodeBlock (MethodBody body)
changes.Add (new Tuple<Instruction, Transformation> (instruction, transform));
continue;
}
if (ConstructorTransforms.TryGetConstructorCallTransformation (instruction, out transform)) {
changes.Add (new Tuple<Instruction, Transformation> (instruction, transform));
continue;
}
}

foreach (var (instr, trans) in changes) {
Expand All @@ -540,7 +547,7 @@ void ReworkCodeBlock (MethodBody body)
// a need to patch class handle references if and only
// if there had been a prior change to this method.
// This is because the call to get_ClassHandle gets
// retdirected by TryGetMappedMember
// redirected by TryGetMappedMember
if (changes.Count > 0)
PatchClassHandleReference (body);
}
Expand Down
46 changes: 2 additions & 44 deletions tools/nnyeah/tests/unit/ClassHandleUnitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,52 +8,10 @@
namespace Microsoft.MaciOS.Nnyeah.Tests {
[TestFixture]
public class ClassHandleUnitTests {
static ReaderParameters ReaderParameters {
get {
var legacyPlatform = Compiler.XamarinPlatformLibraryPath (PlatformName.macOS);
var netPlatform = Compiler.MicrosoftPlatformLibraryPath (PlatformName.macOS);

// We must use a resolver here as the types will be Resolved()'ed later
return new ReaderParameters { AssemblyResolver = new NNyeahAssemblyResolver (legacyPlatform, netPlatform) };
}
}

static async Task<string> CompileTypeForTest (string code)
{
return await TestRunning.BuildTemporaryLibrary (code);
}

Reworker? CreateReworker (string modulePath)
{
var readerParameters = ReaderParameters;
var resolver = (readerParameters.AssemblyResolver as NNyeahAssemblyResolver)!;
var stm = new FileStream (modulePath, FileMode.Open, FileAccess.Read, FileShare.Read);
var moduleToEdit = ModuleDefinition.ReadModule (stm, readerParameters);
var typeAndModuleMap = new TypeAndModuleMap (Compiler.XamarinPlatformLibraryPath (PlatformName.macOS),
Compiler.MicrosoftPlatformLibraryPath (PlatformName.macOS), resolver);

var moduleContainer = new ModuleContainer (moduleToEdit, typeAndModuleMap.XamarinModule,
typeAndModuleMap.MicrosoftModule);

return Reworker.CreateReworker (stm, moduleContainer, typeAndModuleMap.TypeMap);
}

ModuleDefinition? GetReworkedModule (string inModule)
{
var reworker = CreateReworker (inModule);
if (reworker is null)
return null;

var outStm = new MemoryStream ();
reworker.Rework (outStm);
outStm.Seek (0, SeekOrigin.Begin);
return ModuleDefinition.ReadModule (outStm, ReaderParameters);
}

[Test]
public async Task ChangeClassHandleUsage ()
{
var pathToModule = await CompileTypeForTest (@"
var pathToModule = await TestRunning.BuildTemporaryLibrary (@"
using System;
using Foundation;
public class Handlicious : NSObject {
Expand All @@ -64,7 +22,7 @@ public IntPtr DoAThing () {
}
");

var editedModule = GetReworkedModule (pathToModule);
var editedModule = ReworkerHelper.GetReworkedModule (pathToModule);
Assert.IsNotNull (editedModule, "edited module is null (oops)");

var type = editedModule!.Types.First (t => t.Name == "Handlicious");
Expand Down
Loading

0 comments on commit 1726846

Please sign in to comment.