Skip to content

Commit

Permalink
[ObjCRuntime/bgen] Add support for (s)byte, (u)short and nuint fields.
Browse files Browse the repository at this point in the history
  • Loading branch information
rolfbjarne committed Aug 28, 2024
1 parent 6ffc8a0 commit abf1d8d
Show file tree
Hide file tree
Showing 8 changed files with 267 additions and 0 deletions.
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

0 comments on commit abf1d8d

Please sign in to comment.