Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ObjCRuntime/bgen] Add support for (s)byte, (u)short and nuint fields. #21141

Merged
merged 1 commit into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions src/ObjCRuntime/Dlfcn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,114 @@ public static IntPtr GetIndirect (IntPtr handle, string symbol)
return Runtime.GetNSObject<NSNumber> (actual);
}

/// <summary>Gets the signed byte value exposed with the given symbol from the dynamic library.</summary>
/// <param name="handle">Handle to the dynamic library previously opened with <see cref="dlopen(System.String,System.Int32)" /> or <see cref="dlopen(System.String,Mode)" />.</param>
/// <param name="symbol">Name of the public symbol in the dynamic library to look up.</param>
/// <returns>The value from the library, or zero on failure.</returns>
/// <remarks>If this routine fails, it will return zero.</remarks>
public static sbyte GetSByte (IntPtr handle, string symbol)
{
var indirect = dlsym (handle, symbol);
if (indirect == IntPtr.Zero)
return 0;
unchecked {
return (sbyte) Marshal.ReadByte (indirect);
}
}

/// <summary>Sets the specified symbol in the library handle to the specified signed byte value.</summary>
/// <param name="handle">Handle to the dynamic library previously opened with <see cref="dlopen(System.String,System.Int32)" /> or <see cref="dlopen(System.String,Mode)" />.</param>
/// <param name="symbol">Name of the public symbol in the dynamic library to look up.</param>
/// <param name="value">The value to set.</param>
public static void SetSByte (IntPtr handle, string symbol, sbyte value)
{
var indirect = dlsym (handle, symbol);
if (indirect == IntPtr.Zero)
return;
unsafe {
Marshal.WriteByte (indirect, (byte) value);
}
}

/// <summary>Gets the byte value exposed with the given symbol from the dynamic library.</summary>
/// <param name="handle">Handle to the dynamic library previously opened with <see cref="dlopen(System.String,System.Int32)" /> or <see cref="dlopen(System.String,Mode)" />.</param>
/// <param name="symbol">Name of the public symbol in the dynamic library to look up.</param>
/// <returns>The value from the library, or zero on failure.</returns>
/// <remarks>If this routine fails, it will return zero.</remarks>
public static byte GetByte (IntPtr handle, string symbol)
{
var indirect = dlsym (handle, symbol);
if (indirect == IntPtr.Zero)
return 0;
return Marshal.ReadByte (indirect);
}

/// <summary>Sets the specified symbol in the library handle to the specified byte value.</summary>
/// <param name="handle">Handle to the dynamic library previously opened with <see cref="dlopen(System.String,System.Int32)" /> or <see cref="dlopen(System.String,Mode)" />.</param>
/// <param name="symbol">Name of the public symbol in the dynamic library to look up.</param>
/// <param name="value">The value to set.</param>
public static void SetByte (IntPtr handle, string symbol, byte value)
{
var indirect = dlsym (handle, symbol);
if (indirect == IntPtr.Zero)
return;
Marshal.WriteByte (indirect, value);
}

/// <summary>Gets the short value exposed with the given symbol from the dynamic library.</summary>
/// <param name="handle">Handle to the dynamic library previously opened with <see cref="dlopen(System.String,System.Int32)" /> or <see cref="dlopen(System.String,Mode)" />.</param>
/// <param name="symbol">Name of the public symbol in the dynamic library to look up.</param>
/// <returns>The value from the library, or zero on failure.</returns>
/// <remarks>If this routine fails, it will return zero.</remarks>
public static short GetInt16 (IntPtr handle, string symbol)
{
var indirect = dlsym (handle, symbol);
if (indirect == IntPtr.Zero)
return 0;
return Marshal.ReadInt16 (indirect);
}

/// <summary>Sets the specified symbol in the library handle to the specified short value.</summary>
/// <param name="handle">Handle to the dynamic library previously opened with <see cref="dlopen(System.String,System.Int32)" /> or <see cref="dlopen(System.String,Mode)" />.</param>
/// <param name="symbol">Name of the public symbol in the dynamic library to look up.</param>
/// <param name="value">The value to set.</param>
public static void SetInt16 (IntPtr handle, string symbol, short value)
{
var indirect = dlsym (handle, symbol);
if (indirect == IntPtr.Zero)
return;
Marshal.WriteInt16 (indirect, value);
}

/// <summary>Gets the ushort value exposed with the given symbol from the dynamic library.</summary>
/// <param name="handle">Handle to the dynamic library previously opened with <see cref="dlopen(System.String,System.Int32)" /> or <see cref="dlopen(System.String,Mode)" />.</param>
/// <param name="symbol">Name of the public symbol in the dynamic library to look up.</param>
/// <returns>The value from the library, or zero on failure.</returns>
/// <remarks>If this routine fails, it will return zero.</remarks>
public static ushort GetUInt16 (IntPtr handle, string symbol)
{
var indirect = dlsym (handle, symbol);
if (indirect == IntPtr.Zero)
return 0;
unchecked {
return (ushort) Marshal.ReadInt16 (indirect);
}
}

/// <summary>Sets the specified symbol in the library handle to the specified ushort value.</summary>
/// <param name="handle">Handle to the dynamic library previously opened with <see cref="dlopen(System.String,System.Int32)" /> or <see cref="dlopen(System.String,Mode)" />.</param>
/// <param name="symbol">Name of the public symbol in the dynamic library to look up.</param>
/// <param name="value">The value to set.</param>
public static void SetUInt16 (IntPtr handle, string symbol, ushort value)
{
var indirect = dlsym (handle, symbol);
if (indirect == IntPtr.Zero)
return;
unchecked {
Marshal.WriteInt16 (indirect, (short) value);
}
}

public static int GetInt32 (IntPtr handle, string symbol)
{
var indirect = dlsym (handle, symbol);
Expand Down
20 changes: 20 additions & 0 deletions src/bgen/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6339,6 +6339,14 @@ public void Generate (Type type)
print ("_{0} = Runtime.GetNSObject<UTType> (Dlfcn.GetIntPtr (Libraries.{2}.Handle, \"{1}\"))!;", field_pi.Name, fieldAttr.SymbolName, library_name);
indent--;
print ("return _{0};", field_pi.Name);
} else if (field_pi.PropertyType == TypeCache.System_Byte) {
print ("return Dlfcn.GetByte (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, library_name);
} else if (field_pi.PropertyType == TypeCache.System_SByte) {
print ("return Dlfcn.GetSByte (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, library_name);
} else if (field_pi.PropertyType == TypeCache.System_Int16) {
print ("return Dlfcn.GetInt16 (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, library_name);
} else if (field_pi.PropertyType == TypeCache.System_UInt16) {
print ("return Dlfcn.GetUInt16 (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, library_name);
} else if (field_pi.PropertyType == TypeCache.System_Int32) {
print ("return Dlfcn.GetInt32 (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, library_name);
} else if (field_pi.PropertyType == TypeCache.System_UInt32) {
Expand All @@ -6349,6 +6357,8 @@ public void Generate (Type type)
print ("return Dlfcn.GetFloat (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, library_name);
} else if (field_pi.PropertyType == TypeCache.System_IntPtr) {
print ("return Dlfcn.GetIntPtr (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, library_name);
} else if (field_pi.PropertyType == TypeCache.System_UIntPtr) {
print ("return Dlfcn.GetUIntPtr (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, library_name);
} else if (field_pi.PropertyType.FullName == "System.Drawing.SizeF") {
print ("return Dlfcn.GetSizeF (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, library_name);
} else if (field_pi.PropertyType == TypeCache.System_Int64) {
Expand Down Expand Up @@ -6419,10 +6429,20 @@ public void Generate (Type type)
print ("Dlfcn.SetUInt32 (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name);
} else if (field_pi.PropertyType == TypeCache.System_Double) {
print ("Dlfcn.SetDouble (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name);
} else if (field_pi.PropertyType == TypeCache.System_Byte) {
print ("Dlfcn.SetByte (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name);
} else if (field_pi.PropertyType == TypeCache.System_SByte) {
print ("Dlfcn.SetSByte (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name);
} else if (field_pi.PropertyType == TypeCache.System_Int16) {
print ("Dlfcn.SetInt16 (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name);
} else if (field_pi.PropertyType == TypeCache.System_UInt16) {
print ("Dlfcn.SetUInt16 (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name);
} else if (field_pi.PropertyType == TypeCache.System_Float) {
print ("Dlfcn.SetFloat (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name);
} else if (field_pi.PropertyType == TypeCache.System_IntPtr) {
print ("Dlfcn.SetIntPtr (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name);
} else if (field_pi.PropertyType == TypeCache.System_UIntPtr) {
print ("Dlfcn.SetUIntPtr (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name);
} else if (field_pi.PropertyType.FullName == "System.Drawing.SizeF") {
print ("Dlfcn.SetSizeF (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name);
} else if (field_pi.PropertyType == TypeCache.System_Int64) {
Expand Down
16 changes: 16 additions & 0 deletions tests/generator/BGenTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1675,6 +1675,22 @@ public void BackingFieldType (Profile profile)
}
}

[Test]
[TestCase (Profile.iOS)]
public void UnderlyingFieldType (Profile profile)
{
Configuration.IgnoreIfIgnoredPlatform (profile.AsPlatform ());
var bgen = BuildFile (profile, true, true, "tests/underlyingfieldtype.cs");

#if NET
const string nintName = "System.IntPtr";
const string nuintName = "System.UIntPtr";
#else
const string nintName = "System.nint";
const string nuintName = "System.nuint";
#endif
}

[Test]
[TestCase (Profile.iOS)]
public void DelegatesWithNullableReturnType (Profile profile)
Expand Down
40 changes: 40 additions & 0 deletions tests/generator/tests/underlyingfieldtype.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using Foundation;

namespace UnderlyingFieldType {
[BaseType (typeof (NSObject))]
interface FieldClass {
[Field ("SByteField", "__Internal")]
sbyte SByteField { get; set; }

[Field ("ByteField", "__Internal")]
byte ByteField { get; set; }

[Field ("ShortField", "__Internal")]
short ShortField { get; set; }

[Field ("UShortField", "__Internal")]
ushort UShortField { get; set; }

[Field ("IntField", "__Internal")]
int IntField { get; set; }

[Field ("UIntField", "__Internal")]
uint UIntField { get; set; }

[Field ("LongField", "__Internal")]
long LongField { get; set; }

[Field ("ULongField", "__Internal")]
ulong ULongField { get; set; }

[Field ("DoubleField", "__Internal")]
double DoubleField { get; set; }

[Field ("UIntPtrField", "__Internal")]
UIntPtr UIntPtrField { get; set; }

[Field ("IntPtrield", "__Internal")]
IntPtr IntPtrField { get; set; }
}
}
78 changes: 78 additions & 0 deletions tests/monotouch-test/ObjCRuntime/DlfcnTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,83 @@ public void OpenClose_libSystem ()
#endif
Assert.That (err, Is.EqualTo (expected), "dlclose");
}

#if NET
[Test]
public void GetVariables ()
{
var symbol = "x_native_field";
var handle = (IntPtr) Dlfcn.RTLD.Default;

Assert.AreNotEqual (IntPtr.Zero, Dlfcn.dlsym (handle, symbol), "Symbol");

var originalValue = Dlfcn.GetUInt64 (handle, symbol);
Assert.Multiple (() => {
unchecked {
// the n(uint) and (U)IntPtr asserts only work in 64-bit, which is fine because we only care about 64-bit right now.
Assert.AreEqual ((ushort) 0x8899, (ushort) Dlfcn.GetInt16 (handle, symbol), "GetInt16");
Assert.AreEqual ((uint) 0xeeff8899, (uint) Dlfcn.GetInt32 (handle, symbol), "GetInt32");
Assert.AreEqual ((ulong) 0xaabbccddeeff8899, (ulong) Dlfcn.GetInt64 (handle, symbol), "GetInt64");
Assert.AreEqual ((nuint) 0xaabbccddeeff8899, (nuint) Dlfcn.GetNInt (handle, symbol), "GetNInt");
Assert.AreEqual ((ushort) 0x8899, Dlfcn.GetUInt16 (handle, symbol), "GetUInt16");
Assert.AreEqual ((uint) 0xeeff8899, Dlfcn.GetUInt32 (handle, symbol), "GetUInt32");
Assert.AreEqual ((ulong) 0xaabbccddeeff8899, Dlfcn.GetUInt64 (handle, symbol), "GetUInt64");
Assert.AreEqual ((nuint) 0xaabbccddeeff8899, Dlfcn.GetNUInt (handle, symbol), "GetNUInt");
Assert.AreEqual ((nfloat) (-7.757653393002521E-103), Dlfcn.GetNFloat (handle, symbol), "GetNFloat");
Assert.AreEqual (-7.7576533930025207E-103d, Dlfcn.GetDouble (handle, symbol), "GetDouble");
Assert.AreEqual ((nuint) 0xaabbccddeeff8899, (nuint) Dlfcn.GetIntPtr (handle, symbol), "GetIntPtr"); // won't work in 32-bit, but we don't care about that anymore
Assert.AreEqual ((nuint) 0xaabbccddeeff8899, Dlfcn.GetUIntPtr (handle, symbol), "GetUIntPtr");

Dlfcn.SetInt16 (handle, symbol, 0x77);
Assert.AreEqual ((short) 0x77, Dlfcn.GetInt16 (handle, symbol), "SetInt16");
Dlfcn.SetUInt64 (handle, symbol, originalValue);

Dlfcn.SetInt32 (handle, symbol, 0x77);
Assert.AreEqual ((int) 0x77, Dlfcn.GetInt32 (handle, symbol), "SetInt32");
Dlfcn.SetUInt64 (handle, symbol, originalValue);

Dlfcn.SetInt64 (handle, symbol, 0x77);
Assert.AreEqual ((long) 0x77, Dlfcn.GetInt64 (handle, symbol), "SetInt64");
Dlfcn.SetUInt64 (handle, symbol, originalValue);

Dlfcn.SetNInt (handle, symbol, 0x77);
Assert.AreEqual ((nint) 0x77, Dlfcn.GetNInt (handle, symbol), "SetNInt");
Dlfcn.SetUInt64 (handle, symbol, originalValue);

Dlfcn.SetUInt16 (handle, symbol, 0x77);
Assert.AreEqual ((ushort) 0x77, Dlfcn.GetUInt16 (handle, symbol), "SetUInt16");
Dlfcn.SetUInt64 (handle, symbol, originalValue);

Dlfcn.SetUInt32 (handle, symbol, 0x77);
Assert.AreEqual ((uint) 0x77, Dlfcn.GetUInt32 (handle, symbol), "SetUInt32");
Dlfcn.SetUInt64 (handle, symbol, originalValue);

Dlfcn.SetUInt64 (handle, symbol, 0x77);
Assert.AreEqual ((ulong) 0x77, Dlfcn.GetUInt64 (handle, symbol), "SetUInt64");
Dlfcn.SetUInt64 (handle, symbol, originalValue);

Dlfcn.SetNUInt (handle, symbol, 0x77);
Assert.AreEqual ((nuint) 0x77, Dlfcn.GetNUInt (handle, symbol), "SetNUInt");
Dlfcn.SetUInt64 (handle, symbol, originalValue);

Dlfcn.SetNFloat (handle, symbol, 0x77);
Assert.AreEqual ((nfloat) 0x77, Dlfcn.GetNFloat (handle, symbol), "SetNFloat");
Dlfcn.SetUInt64 (handle, symbol, originalValue);

Dlfcn.SetDouble (handle, symbol, 0x77);
Assert.AreEqual (0x77, Dlfcn.GetDouble (handle, symbol), "SetDouble");
Dlfcn.SetUInt64 (handle, symbol, originalValue);

Dlfcn.SetIntPtr (handle, symbol, 0x77);
Assert.AreEqual ((nint) 0x77, Dlfcn.GetIntPtr (handle, symbol), "SetIntPtr");
Dlfcn.SetUInt64 (handle, symbol, originalValue);

Dlfcn.SetUIntPtr (handle, symbol, 0x77);
Assert.AreEqual ((nuint) 0x77, Dlfcn.GetUIntPtr (handle, symbol), "SetUIntPtr");
Dlfcn.SetUInt64 (handle, symbol, originalValue);
}
});
}
#endif
}
}
1 change: 1 addition & 0 deletions tests/monotouch-test/dotnet/shared.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@

<ItemGroup>
<ReferenceNativeSymbol Include="Inexistent" SymbolType="ObjectiveCClass" SymbolMode="Ignore" />
<ReferenceNativeSymbol Include="x_native_field" SymbolType="Field" />
</ItemGroup>

<Import Project="$(RootTestsDirectory)/common/shared-dotnet.csproj" />
Expand Down
2 changes: 2 additions & 0 deletions tests/test-libraries/libtest.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ extern "C" {
int theUltimateAnswer ();
void useZLib ();

__attribute__ ((used)) unsigned long long x_native_field = 0xAABBCCDDEEFF8899;

// NS_ASSUME_NONNULL_BEGIN doesn't work
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnullability-completeness"
Expand Down
2 changes: 2 additions & 0 deletions tests/test-libraries/rename.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
#define x_SCNMatrix4MakeScale object_x_SCNMatrix4MakeScale
#define x_SCNMatrix4Translate object_x_SCNMatrix4Translate
#define x_GlobalString object_x_GlobalString
#define x_native_field object_x_native_field
#elif PREFIX == 2
#define theUltimateAnswer ar_theUltimateAnswer
#define useZLib ar_useZLib
Expand Down Expand Up @@ -149,6 +150,7 @@
#define x_SCNMatrix4MakeScale ar_x_SCNMatrix4MakeScale
#define x_SCNMatrix4Translate ar_x_SCNMatrix4Translate
#define x_GlobalString ar_x_GlobalString
#define x_native_field ar_x_native_field
#else
// keep original names
#endif