From abf1d8d442f76a3d75526d037ed242c97e3dde96 Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Tue, 27 Aug 2024 20:09:23 +0200 Subject: [PATCH] [ObjCRuntime/bgen] Add support for (s)byte, (u)short and nuint fields. --- src/ObjCRuntime/Dlfcn.cs | 108 ++++++++++++++++++ src/bgen/Generator.cs | 20 ++++ tests/generator/BGenTests.cs | 16 +++ tests/generator/tests/underlyingfieldtype.cs | 40 +++++++ tests/monotouch-test/ObjCRuntime/DlfcnTest.cs | 78 +++++++++++++ tests/monotouch-test/dotnet/shared.csproj | 1 + tests/test-libraries/libtest.h | 2 + tests/test-libraries/rename.h | 2 + 8 files changed, 267 insertions(+) create mode 100644 tests/generator/tests/underlyingfieldtype.cs diff --git a/src/ObjCRuntime/Dlfcn.cs b/src/ObjCRuntime/Dlfcn.cs index 1aa8a74c4f09..541ce35ec247 100644 --- a/src/ObjCRuntime/Dlfcn.cs +++ b/src/ObjCRuntime/Dlfcn.cs @@ -203,6 +203,114 @@ public static IntPtr GetIndirect (IntPtr handle, string symbol) return Runtime.GetNSObject (actual); } + /// Gets the signed byte value exposed with the given symbol from the dynamic library. + /// Handle to the dynamic library previously opened with or . + /// Name of the public symbol in the dynamic library to look up. + /// The value from the library, or zero on failure. + /// If this routine fails, it will return zero. + 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); + } + } + + /// Sets the specified symbol in the library handle to the specified signed byte value. + /// Handle to the dynamic library previously opened with or . + /// Name of the public symbol in the dynamic library to look up. + /// The value to set. + 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); + } + } + + /// Gets the byte value exposed with the given symbol from the dynamic library. + /// Handle to the dynamic library previously opened with or . + /// Name of the public symbol in the dynamic library to look up. + /// The value from the library, or zero on failure. + /// If this routine fails, it will return zero. + public static byte GetByte (IntPtr handle, string symbol) + { + var indirect = dlsym (handle, symbol); + if (indirect == IntPtr.Zero) + return 0; + return Marshal.ReadByte (indirect); + } + + /// Sets the specified symbol in the library handle to the specified byte value. + /// Handle to the dynamic library previously opened with or . + /// Name of the public symbol in the dynamic library to look up. + /// The value to set. + public static void SetByte (IntPtr handle, string symbol, byte value) + { + var indirect = dlsym (handle, symbol); + if (indirect == IntPtr.Zero) + return; + Marshal.WriteByte (indirect, value); + } + + /// Gets the short value exposed with the given symbol from the dynamic library. + /// Handle to the dynamic library previously opened with or . + /// Name of the public symbol in the dynamic library to look up. + /// The value from the library, or zero on failure. + /// If this routine fails, it will return zero. + public static short GetInt16 (IntPtr handle, string symbol) + { + var indirect = dlsym (handle, symbol); + if (indirect == IntPtr.Zero) + return 0; + return Marshal.ReadInt16 (indirect); + } + + /// Sets the specified symbol in the library handle to the specified short value. + /// Handle to the dynamic library previously opened with or . + /// Name of the public symbol in the dynamic library to look up. + /// The value to set. + public static void SetInt16 (IntPtr handle, string symbol, short value) + { + var indirect = dlsym (handle, symbol); + if (indirect == IntPtr.Zero) + return; + Marshal.WriteInt16 (indirect, value); + } + + /// Gets the ushort value exposed with the given symbol from the dynamic library. + /// Handle to the dynamic library previously opened with or . + /// Name of the public symbol in the dynamic library to look up. + /// The value from the library, or zero on failure. + /// If this routine fails, it will return zero. + 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); + } + } + + /// Sets the specified symbol in the library handle to the specified ushort value. + /// Handle to the dynamic library previously opened with or . + /// Name of the public symbol in the dynamic library to look up. + /// The value to set. + 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); diff --git a/src/bgen/Generator.cs b/src/bgen/Generator.cs index 8a80a982f224..6693e44f5743 100644 --- a/src/bgen/Generator.cs +++ b/src/bgen/Generator.cs @@ -6339,6 +6339,14 @@ public void Generate (Type type) print ("_{0} = Runtime.GetNSObject (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) { @@ -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) { @@ -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) { diff --git a/tests/generator/BGenTests.cs b/tests/generator/BGenTests.cs index 36793ff83aee..c231d2082bce 100644 --- a/tests/generator/BGenTests.cs +++ b/tests/generator/BGenTests.cs @@ -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) diff --git a/tests/generator/tests/underlyingfieldtype.cs b/tests/generator/tests/underlyingfieldtype.cs new file mode 100644 index 000000000000..5fed436b373c --- /dev/null +++ b/tests/generator/tests/underlyingfieldtype.cs @@ -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; } + } +} diff --git a/tests/monotouch-test/ObjCRuntime/DlfcnTest.cs b/tests/monotouch-test/ObjCRuntime/DlfcnTest.cs index 27e4cfa46839..909dbecdca53 100644 --- a/tests/monotouch-test/ObjCRuntime/DlfcnTest.cs +++ b/tests/monotouch-test/ObjCRuntime/DlfcnTest.cs @@ -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 } } diff --git a/tests/monotouch-test/dotnet/shared.csproj b/tests/monotouch-test/dotnet/shared.csproj index 5e49cc55f80d..e72462bc7823 100644 --- a/tests/monotouch-test/dotnet/shared.csproj +++ b/tests/monotouch-test/dotnet/shared.csproj @@ -48,6 +48,7 @@ + diff --git a/tests/test-libraries/libtest.h b/tests/test-libraries/libtest.h index 219a0e59b7b8..fa765586d097 100644 --- a/tests/test-libraries/libtest.h +++ b/tests/test-libraries/libtest.h @@ -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" diff --git a/tests/test-libraries/rename.h b/tests/test-libraries/rename.h index 9ba236efdf0e..6b35363e9ce9 100644 --- a/tests/test-libraries/rename.h +++ b/tests/test-libraries/rename.h @@ -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 @@ -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