Skip to content

Commit

Permalink
[generator] Use '[U]IntPtr' in P/Invoke signatures instead of 'n[u]in…
Browse files Browse the repository at this point in the history
…t'. (#13043)

* [generator] Use '[U]IntPtr' in the P/Invoke signature for native enums.

* Use '[U]IntPtr' as the parameter type in the P/Invoke signature for native enum
  parameters.
* Use '[U]IntPtr' in the P/Invoke method name for native enum parameters.
* Add an explicit conversion from UIntPtr to nuint (like we already have from IntPtr
  to nint).

This makes the code identical between .NET and legacy Xamarin when using C# n[u]ints,
because those are really [U]IntPtrs.

* Use IntPtr/UIntPtr for all nint/nuint types in P/Invokes, not only native enums.

* Add a few more casts

Fixes these generator tests:

* GeneratorTests.BGenTests.FieldEnumTests
* GeneratorTests.BGenTests.NativeEnum

* [registrar] Handle UIntPtr like we do IntPtr.

Fixes this error in numerous tests:

    error MT4169: Failed to generate a P/Invoke wrapper for objc_msgSend(System.IntPtr,System.IntPtr): The registrar cannot build a signature for type `System.Void' in method `ObjCRuntime.Messaging.objc_msgSend`.

* [NativeTypes] Make IntPtr and UIntPtr behave the same.

This fixes an issue where the linked output for a 32-bit mscorlib.dll and a
64-bit mscorlib.dll would be different, because different explicit operators
for UIntPtr would be kept.

The fix works because the conversion operators for nuint will not use
UIntPtr's explicit conversion operators anymore, it will just operate on plain
memory instead.
  • Loading branch information
rolfbjarne authored Oct 25, 2021
1 parent 2ff5743 commit c3574a5
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 108 deletions.
109 changes: 22 additions & 87 deletions runtime/bindings-generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1088,21 +1088,6 @@ static IEnumerable<FunctionData> GetFunctionData ()
}
);

data.Add (
new FunctionData {
Comment = " // IntPtr func (IntPtr, nint, nint, nint); @try",
Variants = Variants.msgSend | Variants.msgSendSuper,
ReturnType = Types.IntPtr,
Parameters = new ParameterData[] {
new ParameterData { TypeData = Types.IntPtr },
new ParameterData { TypeData = Types.NInt },
new ParameterData { TypeData = Types.NInt },
new ParameterData { TypeData = Types.NInt },
},
MarshalExceptions = true,
}
);

data.Add (
new FunctionData {
Comment = " // IntPtr func (IntPtr, Vector2); @try",
Expand Down Expand Up @@ -1272,18 +1257,6 @@ static IEnumerable<FunctionData> GetFunctionData ()
}
);

data.Add (
new FunctionData {
Comment = " // Vector2 func (nint)",
Prefix = "simd__",
Variants = Variants.All,
ReturnType = Types.Vector2,
Parameters = new ParameterData[] {
new ParameterData { TypeData = Types.NInt },
},
}
);

data.Add (
new FunctionData {
Comment = " // void func (Matrix2)",
Expand Down Expand Up @@ -1390,22 +1363,6 @@ static IEnumerable<FunctionData> GetFunctionData ()
}
);

data.Add (
new FunctionData {
Comment = " // IntPtr func (Vector3, Vector2i, bool, IntPtr, IntPtr)",
Prefix = "simd__",
Variants = Variants.NonStret,
ReturnType = Types.IntPtr,
Parameters = new ParameterData[] {
new ParameterData { TypeData = Types.Vector3 },
new ParameterData { TypeData = Types.Vector2i },
new ParameterData { TypeData = Types.Bool },
new ParameterData { TypeData = Types.IntPtr },
new ParameterData { TypeData = Types.IntPtr },
},
}
);

data.Add (
new FunctionData {
Comment = " // IntPtr func (Matrix4, bool);",
Expand Down Expand Up @@ -2413,18 +2370,6 @@ static IEnumerable<FunctionData> GetFunctionData ()
}
);

data.Add (
new FunctionData {
Comment = " // NMatrix4 func (IntPtr)",
Prefix = "simd__",
Variants = Variants.All,
ReturnType = Types.NMatrix4,
Parameters = new ParameterData [] {
new ParameterData { TypeData = Types.IntPtr }
}
}
);

data.Add (
new FunctionData {
Comment = " // void func (NVector3, IntPtr)",
Expand Down Expand Up @@ -2466,20 +2411,7 @@ static IEnumerable<FunctionData> GetFunctionData ()

data.Add (
new FunctionData {
Comment = " // IntPtr func (Vector2D, IntPtr)",
Prefix = "simd__",
Variants = Variants.All,
ReturnType = Types.IntPtr,
Parameters = new ParameterData [] {
new ParameterData { TypeData = Types.Vector2d},
new ParameterData { TypeData = Types.IntPtr }
},
}
);

data.Add (
new FunctionData {
Comment = " // IntPtr func (Vector2D, int)",
Comment = " // IntPtr func (Vector2D, nint)",
Prefix = "simd__",
Variants = Variants.All,
ReturnType = Types.IntPtr,
Expand Down Expand Up @@ -3378,22 +3310,31 @@ public static class Types {
RequireMarshal = false,
};
public static TypeData NInt = new TypeData {
ManagedType = "nint",
NativeType = "xm_nint_t",
NativeWrapperType = "xm_nint_t",
ManagedType = "IntPtr",
NativeType = "void *",
NativeWrapperType = "void *",
RequireMarshal = false,
IsNativeType = true,
Bit32Type = Int32,
Bit64Type = Int64,
};
public static TypeData NUInt = new TypeData {
ManagedType = "nuint",
NativeType = "xm_nuint_t",
NativeWrapperType = "xm_nuint_t",
ManagedType = "UIntPtr",
NativeType = "void *",
NativeWrapperType = "void *",
RequireMarshal = false,
IsNativeType = true,
Bit32Type = UInt32,
Bit64Type = UInt64,
};
public static TypeData NFloat = new TypeData {
ManagedType = "nfloat",
NativeType = "xm_nfloat_t",
NativeWrapperType = "xm_nfloat_t",
RequireMarshal = false,
IsNativeType = true,
Bit32Type = Float,
Bit64Type = Double,
};
public static TypeData Bool = new TypeData {
ManagedType = "bool",
Expand Down Expand Up @@ -3524,21 +3465,15 @@ class TypeData {
public bool IsARMStret;
#pragma warning restore 649
public bool IsAnyStret { get { return IsX86Stret || IsX64Stret || IsARMStret; } }
public bool IsNativeType { get { return ManagedType == "nint" || ManagedType == "nuint" || ManagedType == "nfloat"; } }
public bool IsNativeType;
public TypeData Bit32Type;
public TypeData Bit64Type;

public TypeData AsSpecificNativeType (bool as32bit)
{
switch (ManagedType) {
case "nint":
return as32bit ? MainClass.Types.Int32 : MainClass.Types.Int64;
case "nuint":
return as32bit ? MainClass.Types.UInt32 : MainClass.Types.UInt64;
case "nfloat":
return as32bit ? MainClass.Types.Float : MainClass.Types.Double;
default:
return this;
}

if (as32bit)
return Bit32Type ?? this;
return Bit64Type ?? this;
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/CoreImage/CIVector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ public unsafe CIVector (nfloat [] values, nint count) : base (NSObjectFlag.Empty
fixed (nfloat *ptr = values) {
var handle = IntPtr.Zero;
if (IsDirectBinding) {
handle = Messaging.IntPtr_objc_msgSend_IntPtr_nint (Handle, Selector.GetHandle ("initWithValues:count:"), (IntPtr) ptr, count);
handle = Messaging.IntPtr_objc_msgSend_IntPtr_IntPtr (Handle, Selector.GetHandle ("initWithValues:count:"), (IntPtr) ptr, (IntPtr) count);
} else {
handle = Messaging.IntPtr_objc_msgSendSuper_IntPtr_nint (SuperHandle, Selector.GetHandle ("initWithValues:count:"), (IntPtr) ptr, count);
handle = Messaging.IntPtr_objc_msgSendSuper_IntPtr_IntPtr (SuperHandle, Selector.GetHandle ("initWithValues:count:"), (IntPtr) ptr, (IntPtr) count);
}
InitializeHandle (handle, "initWithValues:count:");
}
Expand Down
2 changes: 1 addition & 1 deletion src/CoreML/MLMultiArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ static NSNumber[] ConvertArray (nint[] value)
// NSArray<NSNumber> => nint[]
internal static nint[] ConvertArray (IntPtr handle)
{
return NSArray.ArrayFromHandle<nint> (handle, (v) => Messaging.nint_objc_msgSend (v, Selector.GetHandle ("integerValue")));
return NSArray.ArrayFromHandle<nint> (handle, (v) => (nint) Messaging.IntPtr_objc_msgSend (v, Selector.GetHandle ("integerValue")));
}

public MLMultiArray (nint [] shape, MLMultiArrayDataType dataType, out NSError error)
Expand Down
8 changes: 4 additions & 4 deletions src/Foundation/NSArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,18 +235,18 @@ static public NSArray FromIntPtrs (IntPtr [] vals)
internal static nuint GetCount (IntPtr handle)
{
#if MONOMAC
return Messaging.nuint_objc_msgSend (handle, selCountHandle);
return (nuint) Messaging.UIntPtr_objc_msgSend (handle, selCountHandle);
#else
return Messaging.nuint_objc_msgSend (handle, Selector.GetHandle ("count"));
return (nuint) Messaging.UIntPtr_objc_msgSend (handle, Selector.GetHandle ("count"));
#endif
}

internal static IntPtr GetAtIndex (IntPtr handle, nuint i)
{
#if MONOMAC
return Messaging.IntPtr_objc_msgSend_nuint (handle, selObjectAtIndex_Handle, i);
return Messaging.IntPtr_objc_msgSend_UIntPtr (handle, selObjectAtIndex_Handle, (UIntPtr) i);
#else
return Messaging.IntPtr_objc_msgSend_nuint (handle, Selector.GetHandle ("objectAtIndex:"), i);
return Messaging.IntPtr_objc_msgSend_UIntPtr (handle, Selector.GetHandle ("objectAtIndex:"), (UIntPtr) i);
#endif
}

Expand Down
2 changes: 1 addition & 1 deletion src/Metal/MTLCompat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public static void SampleCounters (this IMTLComputeCommandEncoder This, IMTLCoun
{
if (sampleBuffer == null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (sampleBuffer));
global::ObjCRuntime.Messaging.void_objc_msgSend_IntPtr_nuint_bool (This.Handle, Selector.GetHandle ("sampleCountersInBuffer:atSampleIndex:withBarrier:"), sampleBuffer.Handle, sampleIndex, barrier);
global::ObjCRuntime.Messaging.void_objc_msgSend_IntPtr_UIntPtr_bool (This.Handle, Selector.GetHandle ("sampleCountersInBuffer:atSampleIndex:withBarrier:"), sampleBuffer.Handle, (UIntPtr) sampleIndex, barrier);
}
}
#endif // MONOMAC
Expand Down
8 changes: 5 additions & 3 deletions src/NativeTypes/Primitives.tt
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,10 @@ namespace System
break;
}

if (fromType == "IntPtr") {
if (fromType == "IntPtr" || fromType == "UIntPtr") {
Write ("*(({0} *)&v)", Cast (arch));
} else if (toType == "IntPtr") {
Write ("*((IntPtr *)&v.v)");
} else if (toType == "IntPtr" || toType == "UIntPtr") {
Write ("*(({0} *)&v.v)", toType);
} else {
Write ("({0})", Cast (arch));

Expand Down Expand Up @@ -206,6 +206,8 @@ namespace System
Imp ("nuint", "nfloat");
Exp ("IntPtr", "nuint");
Exp ("nuint", "IntPtr");
Exp ("UIntPtr", "nuint");
Exp ("nuint", "UIntPtr");
Exp ("sbyte", "nuint");
Exp ("nuint", "sbyte");
Imp ("byte", "nuint");
Expand Down
41 changes: 31 additions & 10 deletions src/generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1154,6 +1154,13 @@ string ParameterGetMarshalType (MarshalInfo mai, bool formatted = false)
if (IsWrappedType (mai.Type))
return mai.Type.IsByRef ? "ref IntPtr" : "IntPtr";

if (mai.Type.Namespace == "System") {
if (mai.Type.Name == "nint")
return "IntPtr";
if (mai.Type.Name == "nuint")
return "UIntPtr";
}

if (IsNativeType (mai.Type))
return PrimitiveType (mai.Type, formatted);

Expand Down Expand Up @@ -1824,6 +1831,13 @@ public string MarshalParameter (MethodInfo mi, ParameterInfo pi, bool null_allow
if (castEnum && pi.ParameterType.IsEnum)
return "(" + PrimitiveType (pi.ParameterType) + ")" + safe_name;

if (castEnum && pi.ParameterType.Namespace == "System") {
if (pi.ParameterType.Name == "nint")
return "(IntPtr) " + safe_name;
else if (pi.ParameterType.Name == "nuint")
return "(UIntPtr) " + safe_name;
}

if (IsNativeType (pi.ParameterType))
return safe_name;

Expand Down Expand Up @@ -2092,17 +2106,20 @@ bool GetNativeEnumToManagedExpression (Type enumType, out string preExpression,
var underlyingEnumType = TypeManager.GetUnderlyingEnumType (enumType);
var underlyingTypeName = RenderType (underlyingEnumType);
string itype;
string intermediateType;
object maxValue;
Func<FieldInfo, bool> isMaxDefinedFunc;
Func<FieldInfo, bool> isMinDefinedFunc = null;
if (TypeManager.System_Int64 == underlyingEnumType) {
nativeType = "nint";
nativeType = "IntPtr";
intermediateType = "nint";
itype = "int";
maxValue = long.MaxValue;
isMaxDefinedFunc = (v) => (long) v.GetRawConstantValue () == long.MaxValue;
isMinDefinedFunc = (v) => (long) v.GetRawConstantValue () == long.MinValue;
} else if (TypeManager.System_UInt64 == underlyingEnumType) {
nativeType = "nuint";
nativeType = "UIntPtr";
intermediateType = "nuint";
itype = "uint";
maxValue = ulong.MaxValue;
isMaxDefinedFunc = (v) => (ulong) v.GetRawConstantValue () == ulong.MaxValue;
Expand All @@ -2111,7 +2128,7 @@ bool GetNativeEnumToManagedExpression (Type enumType, out string preExpression,
}

if (!string.IsNullOrEmpty (attrib.ConvertToManaged)) {
preExpression = attrib.ConvertToManaged + " (";
preExpression = attrib.ConvertToManaged + " ((" + intermediateType + ") ";
postExpression = ")";
} else {
preExpression = "(" + renderedEnumType + ") (" + RenderType (underlyingEnumType) + ") ";
Expand Down Expand Up @@ -2156,15 +2173,15 @@ bool GetNativeEnumToNativeExpression (Type enumType, out string preExpression, o

var underlyingEnumType = TypeManager.GetUnderlyingEnumType (enumType);
if (TypeManager.System_Int64 == underlyingEnumType) {
nativeType = "nint";
nativeType = "IntPtr";
} else if (TypeManager.System_UInt64 == underlyingEnumType) {
nativeType = "nuint";
nativeType = "UIntPtr";
} else {
throw new BindingException (1029, enumType);
}

if (!string.IsNullOrEmpty (attrib.ConvertToNative)) {
preExpression = attrib.ConvertToNative + " (";
preExpression = "(" + nativeType + ") " + attrib.ConvertToNative + " (";
postExpression = ")";
} else {
preExpression = "(" + nativeType + ") (" + RenderType (underlyingEnumType) + ") ";
Expand All @@ -2188,9 +2205,9 @@ bool IsNativeEnum (Type enumType, out Type underlyingType, out string nativeType

underlyingType = enumType.GetEnumUnderlyingType ();
if (underlyingType == TypeManager.System_Int64) {
nativeType = "nint";
nativeType = "IntPtr";
} else if (underlyingType == TypeManager.System_UInt64) {
nativeType = "nuint";
nativeType = "UIntPtr";
} else {
throw new BindingException (1026, true, enumType.FullName, "NativeAttribute");
}
Expand Down Expand Up @@ -3923,6 +3940,10 @@ void GetReturnsWrappers (MethodInfo mi, MemberInformation minfo, Type declaringT
cast_a = "CFArray.ArrayFromHandle<" + FormatType (mi.DeclaringType, etype) + ">(";
cast_b = ")!";
}
} else if (mi.ReturnType.Namespace == "System" && mi.ReturnType.Name == "nint") {
cast_a = "(nint) ";
} else if (mi.ReturnType.Namespace == "System" && mi.ReturnType.Name == "nuint") {
cast_a = "(nuint) ";
}
}

Expand Down Expand Up @@ -7072,9 +7093,9 @@ public void Generate (Type type)
print ($"Dlfcn.SetString (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\", value.GetConstant ());");
else if (GetNativeEnumToNativeExpression (field_pi.PropertyType, out var preExpression, out var postExpression, out var _)) {
if (btype == TypeManager.System_nint || (BindThirdPartyLibrary && btype == TypeManager.System_Int64))
print ($"Dlfcn.SetNInt (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\", {preExpression}value{postExpression});");
print ($"Dlfcn.SetNInt (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\", (nint) {preExpression}value{postExpression});");
else if (btype == TypeManager.System_nuint || (BindThirdPartyLibrary && btype == TypeManager.System_UInt64))
print ($"Dlfcn.SetNUInt (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\", {preExpression}value{postExpression});");
print ($"Dlfcn.SetNUInt (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\", (nuint) {preExpression}value{postExpression});");
else
throw new BindingException (1021, true, fieldTypeName, field_pi.DeclaringType.FullName, field_pi.Name);
} else {
Expand Down
1 change: 1 addition & 0 deletions tools/common/StaticRegistrar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2306,6 +2306,7 @@ void ProcessStructure (StringBuilder name, AutoIndentStringBuilder body, TypeDef
size += 8;
break;
case "System.IntPtr":
case "System.UIntPtr":
name.Append ('p');
body.AppendLine ("void *v{0};", size);
size += 4; // for now at least...
Expand Down

6 comments on commit c3574a5

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ [CI Build] Tests failed on Build ❌

Tests failed on Build.

API diff

✅ API Diff from stable

View API diff
View dotnet API diff
View dotnet legacy API diff
View dotnet iOS-MacCatalayst API diff

Packages generated

View packages

Test results

2 tests failed, 216 tests passed.

Failed tests

  • dont link/Mac Catalyst [dotnet]/Debug [dotnet]: Failed (Test run crashed (exit code: 134).
    Tests run: 11 Passed: 6 Inconclusive: 0 Failed: 0 Ignored: 5)
  • Generator tests/.NET: Failed (Execution failed with exit code 1)

Pipeline on Agent XAMBOT-1036.BigSur
[generator] Use '[U]IntPtr' in P/Invoke signatures instead of 'n[u]int'. (#13043)

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔥 Tests failed catastrophically on VSTS: device tests iOS 🔥

Not enough free space in the host.

Pipeline on Agent
[generator] Use '[U]IntPtr' in P/Invoke signatures instead of 'n[u]int'. (#13043)

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Tests were not ran (VSTS: device tests iOS). ⚠️

Results were skipped for this run due to provisioning problems Azure Devops. Please contact the bot administrator.

Pipeline on Agent
[generator] Use '[U]IntPtr' in P/Invoke signatures instead of 'n[u]int'. (#13043)

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Tests were not ran (VSTS: device tests tvOS). ⚠️

Results were skipped for this run due to provisioning problems Azure Devops. Please contact the bot administrator.

Pipeline on Agent
[generator] Use '[U]IntPtr' in P/Invoke signatures instead of 'n[u]int'. (#13043)

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ Tests failed on macOS M1 - Mac Big Sur (11.5) ❌

Tests failed on M1 - Mac Big Sur (11.5).

Failed tests are:

  • monotouch-test

Pipeline on Agent
[generator] Use '[U]IntPtr' in P/Invoke signatures instead of 'n[u]int'. (#13043)

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Tests passed on macOS Mac Mojave (10.14) ✅

Tests passed

All tests on macOS X Mac Mojave (10.14) passed.

Pipeline on Agent
[generator] Use '[U]IntPtr' in P/Invoke signatures instead of 'n[u]int'. (#13043)

Please sign in to comment.