-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Replace usages of Marshal.AllocHGlobal with malloc in libraries #54468
Changes from 29 commits
10f15f7
61340eb
96d410b
f93fe74
6badbdd
d2b561f
38824c5
8ec610e
2db0e86
658bf85
0930248
89ded43
340735a
7038fca
453f15e
325b20d
36c48a4
09d0361
190fb6b
673925a
29e37a5
2510792
935a77a
68a9dc7
443c362
5dd3cf6
8783e8c
3184c15
6a0746a
59cfa9b
f8d77c2
8bc626d
d52bb61
aa86b70
e6b6e8e
f0fb97a
3423d98
b5dd0da
8a1f781
6fe4d7c
c2275fc
068248c
b875528
f89bc04
2a961d3
1b0f51a
af272a8
a2042c6
6e57302
db1ee0c
e79d136
b7c3292
7156b1e
3ea5947
fc6147a
1b3e561
1f60dbf
852508b
332e3aa
de3481e
8d3fbdd
c31c674
8a12cec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
#nullable enable | ||
|
||
using System.Diagnostics; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Runtime.InteropServices; | ||
using System.Text; | ||
|
||
namespace System | ||
{ | ||
internal static unsafe class NativeMemoryHelper | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be called There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That can work for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would avoid touching StringToHGlobalUni in this PR. If it is useful to have NativeMemory variant of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This might be worth profiling more and its probably worth opening a proposal. On my box, a benchmark which does simply the following, over a var ptr = Marshal.StringToHGlobalUni(s);
Marshal.FreeHGlobal(ptr); Compared to an equivalent API using
Of course, in comparison to the GC transition and any work the call itself does, this is probably not that meaningful but ~10% overhead can add up. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
{ | ||
public static IntPtr Alloc(int byteCount) | ||
{ | ||
#if NET6_0_OR_GREATER | ||
return (nint)NativeMemory.Alloc((uint)byteCount); | ||
#else | ||
return Marshal.AllocHGlobal(byteCount); | ||
#endif | ||
} | ||
|
||
public static IntPtr Realloc(IntPtr pointer, int byteCount) | ||
{ | ||
#if NET6_0_OR_GREATER | ||
return (nint)NativeMemory.Realloc((void*)(nint)pointer, (uint)byteCount); | ||
#else | ||
return Marshal.ReAllocHGlobal(pointer, (nint)byteCount); | ||
#endif | ||
} | ||
|
||
public static IntPtr AllocStringUnicode(string? s) | ||
{ | ||
if (s is null) | ||
{ | ||
return IntPtr.Zero; | ||
} | ||
|
||
var byteCount = (s.Length + 1) * 2; | ||
|
||
// Overflow checking | ||
if (byteCount < s.Length) | ||
{ | ||
ThrowArgumentOutOfRangeException(nameof(s)); | ||
} | ||
|
||
#if NET6_0_OR_GREATER | ||
char* memory = (char*)NativeMemory.Alloc((uint)byteCount); | ||
s.CopyTo(new Span<char>(memory, s.Length)); | ||
#else | ||
char* memory = (char*)(nint)Marshal.AllocHGlobal(byteCount); | ||
// Avoid pulling in System.Memory for netstandard2.0 targets. | ||
fixed (char* str = s) | ||
{ | ||
Buffer.MemoryCopy(str, memory, byteCount, s.Length * 2); | ||
} | ||
#endif | ||
|
||
memory[s.Length] = '\0'; | ||
return (nint)memory; | ||
} | ||
|
||
public static IntPtr AllocStringAnsi(string? s) | ||
{ | ||
if (s is null) | ||
{ | ||
return IntPtr.Zero; | ||
} | ||
|
||
long longByteCount = (s.Length + 1) * (long)Marshal.SystemMaxDBCSCharSize; | ||
int byteCount = (int)longByteCount; | ||
|
||
// Overflow checking | ||
if (byteCount != longByteCount) | ||
{ | ||
ThrowArgumentOutOfRangeException(nameof(s)); | ||
} | ||
|
||
#if NET6_0_OR_GREATER | ||
byte* memory = (byte*)NativeMemory.Alloc((uint)byteCount); | ||
#else | ||
byte* memory = (byte*)(nint)Marshal.AllocHGlobal(byteCount); | ||
#endif | ||
|
||
fixed (char* str = s) | ||
{ | ||
int convertedBytes = Encoding.UTF8.GetBytes(str, s.Length, memory, byteCount); | ||
memory[convertedBytes] = 0; | ||
} | ||
|
||
return (nint)memory; | ||
} | ||
|
||
|
||
public static void Free(IntPtr pointer) | ||
{ | ||
#if NET6_0_OR_GREATER | ||
NativeMemory.Free((void*)(nint)pointer); | ||
#else | ||
Marshal.FreeHGlobal(pointer); | ||
#endif | ||
} | ||
|
||
|
||
#if NET6_0_OR_GREATER | ||
[StackTraceHidden] | ||
#endif | ||
[DoesNotReturn] | ||
private static void ThrowArgumentOutOfRangeException(string argument) | ||
{ | ||
throw new ArgumentOutOfRangeException(argument); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: ReAllocHGlobal