88using System ;
99using System . Runtime . ConstrainedExecution ;
1010using System . Runtime . InteropServices ;
11+ using System . Runtime . Versioning ;
1112
1213//[assembly: PythonModule("_ctypes", typeof(IronPython.Modules.CTypes))]
1314namespace IronPython . Modules {
@@ -19,60 +20,96 @@ internal static class NativeFunctions {
1920 private static MoveMemoryDelegate _moveMem = MoveMemory ;
2021
2122 [ UnmanagedFunctionPointer ( CallingConvention . Cdecl ) ]
22- private delegate IntPtr SetMemoryDelegate ( IntPtr dest , byte value , IntPtr length ) ;
23+ private delegate IntPtr SetMemoryDelegate ( IntPtr dest , byte value , nuint length ) ;
2324 [ UnmanagedFunctionPointer ( CallingConvention . Cdecl ) ]
24- private delegate IntPtr MoveMemoryDelegate ( IntPtr dest , IntPtr src , IntPtr length ) ;
25+ private delegate IntPtr MoveMemoryDelegate ( IntPtr dest , IntPtr src , nuint length ) ;
2526
27+ [ SupportedOSPlatform ( "windows" ) ]
28+ [ DllImport ( "kernel32.dll" , SetLastError = true ) ]
29+ private static extern IntPtr LoadLibrary ( string lpFileName ) ;
30+
31+ [ SupportedOSPlatform ( "windows" ) ]
2632 [ DllImport ( "kernel32.dll" ) ]
2733 [ return : MarshalAs ( UnmanagedType . Bool ) ]
2834 public static extern bool FreeLibrary ( IntPtr hModule ) ;
2935
30- [ DllImport ( "kernel32.dll" , SetLastError = true ) ]
31- private static extern IntPtr LoadLibrary ( string lpFileName ) ;
32-
36+ [ SupportedOSPlatform ( "windows" ) ]
3337 [ DllImport ( "kernel32.dll" ) ]
3438 public static extern void SetLastError ( int errorCode ) ;
3539
40+ [ SupportedOSPlatform ( "windows" ) ]
3641 [ DllImport ( "kernel32.dll" ) ]
3742 public static extern int GetLastError ( ) ;
43+ [ SupportedOSPlatform ( "windows" ) ]
3844
45+ [ SupportedOSPlatform ( "windows" ) ]
3946 [ DllImport ( "kernel32.dll" ) ]
4047 private static extern IntPtr GetProcAddress ( IntPtr module , string lpFileName ) ;
4148
49+ [ SupportedOSPlatform ( "windows" ) ]
4250 [ DllImport ( "kernel32.dll" ) ]
4351 private static extern IntPtr GetProcAddress ( IntPtr module , IntPtr ordinal ) ;
4452
53+ [ SupportedOSPlatform ( "linux" ) ]
4554 [ DllImport ( "libc" ) ]
46- private static extern void memcpy ( IntPtr dst , IntPtr src , IntPtr length ) ;
55+ private static extern unsafe void memcpy ( void * dst , void * src , nuint length ) ;
4756
48- [ DllImport ( "kernel32.dll" , EntryPoint = "RtlMoveMemory" , ExactSpelling = true ) ]
49- private static extern void CopyMemory ( IntPtr destination , IntPtr source , IntPtr length ) ;
57+ [ SupportedOSPlatform ( "macos" ) ]
58+ [ DllImport ( "libSystem.dylib" , EntryPoint = "memcpy" ) ]
59+ private static extern unsafe void memcpy_darwin ( void * dst , void * src , nuint length ) ;
5060
51- public static void MemCopy ( IntPtr destination , IntPtr source , IntPtr length ) {
52- if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) ||
53- RuntimeInformation . IsOSPlatform ( OSPlatform . OSX ) ) {
54- memcpy ( destination , source , length ) ;
61+ [ SupportedOSPlatform ( "windows" ) ]
62+ [ DllImport ( "kernel32.dll" , EntryPoint = "RtlMoveMemory" , ExactSpelling = true ) ]
63+ private static extern unsafe void CopyMemory ( void * destination , void * source , nuint length ) ;
64+
65+ public static unsafe void MemCopy ( IntPtr destination , IntPtr source , nuint length ) {
66+ void * dst = ( void * ) destination ;
67+ void * src = ( void * ) source ;
68+ #if NET7_0_OR_GREATER
69+ NativeMemory . Copy ( source : src , destination : dst , length ) ;
70+ #else
71+ if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) ) {
72+ memcpy ( dst , src , length ) ;
73+ } else if ( RuntimeInformation . IsOSPlatform ( OSPlatform . OSX ) ) {
74+ memcpy_darwin ( dst , src , length ) ;
75+ } else if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) ) {
76+ CopyMemory ( dst , src , length ) ;
5577 } else {
56- CopyMemory ( destination , source , length ) ;
78+ throw new PlatformNotSupportedException ( ) ;
5779 }
80+ #endif
5881 }
5982
6083 // unix entry points, VM needs to map the filenames.
84+ [ SupportedOSPlatform ( "linux" ) ]
6185 [ DllImport ( "libc" ) ]
6286 private static extern IntPtr dlopen ( string filename , int flags ) ;
6387
88+ [ SupportedOSPlatform ( "linux" ) ]
6489 [ DllImport ( "libdl" , EntryPoint = "dlopen" ) ]
6590 private static extern IntPtr dlopen_dl ( string filename , int flags ) ;
6691
92+ [ SupportedOSPlatform ( "macos" ) ]
93+ [ DllImport ( "libSystem.dylib" , EntryPoint = "dlopen" ) ]
94+ private static extern IntPtr dlopen_darwin ( string filename , int flags ) ;
95+
96+ [ SupportedOSPlatform ( "linux" ) ]
6797 [ DllImport ( "libc" ) ]
68- private static extern IntPtr dlsym ( IntPtr handle , string symbol ) ;
98+ private static extern unsafe void * dlsym ( IntPtr handle , string symbol ) ;
6999
100+ [ SupportedOSPlatform ( "linux" ) ]
70101 [ DllImport ( "libdl" , EntryPoint = "dlsym" ) ]
71- private static extern IntPtr dlsym_dl ( IntPtr handle , string symbol ) ;
102+ private static extern unsafe void * dlsym_dl ( IntPtr handle , string symbol ) ;
72103
104+ [ SupportedOSPlatform ( "macos" ) ]
105+ [ DllImport ( "libSystem.dylib" , EntryPoint = "dlsym" ) ]
106+ private static extern unsafe void * dlsym_darwin ( IntPtr handle , string symbol ) ;
107+
108+ [ SupportedOSPlatform ( "linux" ) ]
73109 [ DllImport ( "libc" ) ]
74110 private static extern IntPtr gnu_get_libc_version ( ) ;
75111
112+ [ SupportedOSPlatform ( "linux" ) ]
76113 private static bool GetGNULibCVersion ( out int major , out int minor ) {
77114 major = minor = 0 ;
78115 try {
@@ -91,6 +128,7 @@ private static bool GetGNULibCVersion(out int major, out int minor) {
91128
92129 private const int RTLD_NOW = 2 ;
93130
131+ [ SupportedOSPlatform ( "linux" ) ]
94132 private static bool UseLibDL ( ) {
95133 if ( ! _useLibDL . HasValue ) {
96134 bool success = GetGNULibCVersion ( out int major , out int minor ) ;
@@ -107,45 +145,53 @@ public static IntPtr LoadDLL(string filename, int flags) {
107145
108146 if ( flags == 0 ) flags = RTLD_NOW ;
109147
110- if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) && UseLibDL ( ) ) {
111- return dlopen_dl ( filename , flags ) ;
148+ if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) ) {
149+ return UseLibDL ( ) ? dlopen_dl ( filename , flags ) : dlopen ( filename , flags ) ;
150+ } else if ( RuntimeInformation . IsOSPlatform ( OSPlatform . OSX ) ) {
151+ return dlopen_darwin ( filename , flags ) ;
152+ } else {
153+ throw new PlatformNotSupportedException ( ) ;
112154 }
113-
114- return dlopen ( filename , flags ) ;
115155 }
116156
117- public static IntPtr LoadFunction ( IntPtr module , string functionName ) {
157+ public static unsafe IntPtr LoadFunction ( IntPtr module , string functionName ) {
118158 if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) ) {
119159 return GetProcAddress ( module , functionName ) ;
160+ } else if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) ) {
161+ return ( IntPtr ) ( UseLibDL ( ) ? dlsym_dl ( module , functionName ) : dlsym ( module , functionName ) ) ;
162+ } else if ( RuntimeInformation . IsOSPlatform ( OSPlatform . OSX ) ) {
163+ return ( IntPtr ) dlsym_darwin ( module , functionName ) ;
164+ } else {
165+ throw new PlatformNotSupportedException ( ) ;
120166 }
121-
122- if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) && UseLibDL ( ) ) {
123- return dlsym_dl ( module , functionName ) ;
124- }
125-
126- return dlsym ( module , functionName ) ;
127167 }
128168
129169 public static IntPtr LoadFunction ( IntPtr module , IntPtr ordinal ) {
130- if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) ||
131- RuntimeInformation . IsOSPlatform ( OSPlatform . OSX ) ) {
132- return IntPtr . Zero ;
170+ if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) ) {
171+ return GetProcAddress ( module , ordinal ) ;
133172 }
134-
135- return GetProcAddress ( module , ordinal ) ;
173+ return IntPtr . Zero ;
136174 }
137175
138176 /// <summary>
139177 /// Allocates memory that's zero-filled
140178 /// </summary>
141179 [ ReliabilityContract ( Consistency . WillNotCorruptState , Cer . MayFail ) ]
142- public static IntPtr Calloc ( IntPtr size ) {
143- if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) ||
144- RuntimeInformation . IsOSPlatform ( OSPlatform . OSX ) ) {
145- return calloc ( ( IntPtr ) 1 , size ) ;
180+ public static unsafe IntPtr Calloc ( nuint size ) {
181+ #if NET7_0_OR_GREATER
182+ return new IntPtr ( NativeMemory . AllocZeroed ( size ) ) ;
183+ #else
184+ if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) ) {
185+ return ( IntPtr ) calloc ( 1 , size ) ;
186+ } else if ( RuntimeInformation . IsOSPlatform ( OSPlatform . OSX ) ) {
187+ return ( IntPtr ) calloc_darwin ( 1 , size ) ;
188+ } else if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) ) {
189+ const uint LMEM_ZEROINIT = 0x0040 ;
190+ return ( IntPtr ) LocalAlloc ( LMEM_ZEROINIT , size ) ;
191+ } else {
192+ throw new PlatformNotSupportedException ( ) ;
146193 }
147-
148- return LocalAlloc ( LMEM_ZEROINIT , size ) ;
194+ #endif
149195 }
150196
151197 public static IntPtr GetMemMoveAddress ( ) {
@@ -156,40 +202,67 @@ public static IntPtr GetMemSetAddress() {
156202 return Marshal . GetFunctionPointerForDelegate ( _setMem ) ;
157203 }
158204
205+ [ SupportedOSPlatform ( "windows" ) ]
159206 [ DllImport ( "kernel32.dll" ) , ReliabilityContract ( Consistency . WillNotCorruptState , Cer . MayFail ) ]
160- private static extern IntPtr LocalAlloc ( uint flags , IntPtr size ) ;
207+ private static extern unsafe void * LocalAlloc ( uint flags , nuint size ) ;
161208
209+ [ SupportedOSPlatform ( "linux" ) ]
162210 [ DllImport ( "libc" ) ]
163- private static extern IntPtr calloc ( IntPtr num , IntPtr size ) ;
211+ private static extern unsafe void * calloc ( nuint num , nuint size ) ;
164212
165- private const int LMEM_ZEROINIT = 0x0040 ;
213+
214+ [ SupportedOSPlatform ( "macos" ) ]
215+ [ DllImport ( "libSystem.dylib" , EntryPoint = "calloc" ) ]
216+ private static extern unsafe void * calloc_darwin ( nuint num , nuint size ) ;
166217
218+ [ SupportedOSPlatform ( "windows" ) ]
167219 [ DllImport ( "kernel32.dll" ) ]
168- private static extern void RtlMoveMemory ( IntPtr Destination , IntPtr src , IntPtr length ) ;
220+ private static extern unsafe void RtlMoveMemory ( void * dest , void * src , nuint length ) ;
169221
222+ [ SupportedOSPlatform ( "linux" ) ]
170223 [ DllImport ( "libc" ) ]
171- private static extern IntPtr memmove ( IntPtr dst , IntPtr src , IntPtr length ) ;
224+ private static extern unsafe void * memmove ( void * dest , void * src , nuint length ) ;
225+
226+ [ SupportedOSPlatform ( "macos" ) ]
227+ [ DllImport ( "libSystem.dylib" , EntryPoint = "memmove" ) ]
228+ private static extern unsafe void * memmove_darwin ( void * dest , void * src , nuint count ) ;
172229
173230 /// <summary>
174- /// Helper function for implementing memset. Could be more efficient if we
175- /// could P/Invoke or call some otherwise native code to do this.
231+ /// Helper function for implementing memset.
176232 /// </summary>
177- private static IntPtr MemSet ( IntPtr dest , byte value , IntPtr length ) {
178- IntPtr end = dest . Add ( length . ToInt32 ( ) ) ;
179- for ( IntPtr cur = dest ; cur != end ; cur = new IntPtr ( cur . ToInt64 ( ) + 1 ) ) {
180- Marshal . WriteByte ( cur , value ) ;
233+ private static unsafe IntPtr MemSet ( IntPtr dest , byte value , nuint length ) {
234+ #if NET7_0_OR_GREATER
235+ NativeMemory . Fill ( ( void * ) dest , length , value ) ;
236+ #else
237+ const int blockSize = 1 << 30 ; // 1 GiB
238+ byte * cur = ( byte * ) dest ;
239+ while ( length > 0 ) {
240+ int to_fill = length < blockSize ? ( int ) length : blockSize ;
241+ new Span < byte > ( cur , to_fill ) . Fill ( value ) ;
242+ length -= ( nuint ) to_fill ;
243+ cur += to_fill ;
181244 }
245+ #endif
182246 return dest ;
183247 }
184248
185- private static IntPtr MoveMemory ( IntPtr dest , IntPtr src , IntPtr length ) {
186- if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) ||
187- RuntimeInformation . IsOSPlatform ( OSPlatform . OSX ) ) {
188- memmove ( dest , src , length ) ;
249+ private static unsafe IntPtr MoveMemory ( IntPtr destination , IntPtr source , nuint length ) {
250+ void * dst = ( void * ) destination ;
251+ void * src = ( void * ) source ;
252+ #if NET7_0_OR_GREATER
253+ NativeMemory . Copy ( ( void * ) src , ( void * ) dst , length ) ;
254+ #else
255+ if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) ) {
256+ memmove ( dst , src , length ) ;
257+ } else if ( RuntimeInformation . IsOSPlatform ( OSPlatform . OSX ) ) {
258+ memmove_darwin ( dst , src , length ) ;
259+ } else if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) ) {
260+ RtlMoveMemory ( dst , src , length ) ;
189261 } else {
190- RtlMoveMemory ( dest , src , length ) ;
262+ throw new PlatformNotSupportedException ( ) ;
191263 }
192- return dest ;
264+ #endif
265+ return destination ;
193266 }
194267 }
195268}
0 commit comments