Skip to content

Commit 748b7b5

Browse files
authored
Add a mechanism to selectively initialize allocated unmanaged memory in the default constructor.
* feature: Add a mechanism to selectively initialize unmanaged memory in the default constructor. (C# Only at this point). * Use the global:: prefix when calling InitBlock
1 parent b3a7cd0 commit 748b7b5

File tree

5 files changed

+39
-0
lines changed

5 files changed

+39
-0
lines changed

src/Generator/Generators/CSharp/CSharpSources.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2942,6 +2942,9 @@ private void GenerateClassConstructor(Method method, Class @class)
29422942
}
29432943
else
29442944
{
2945+
if (method.IsDefaultConstructor && Context.Options.ZeroAllocatedMemory(@class))
2946+
WriteLine($"global::System.Runtime.CompilerServices.Unsafe.InitBlock((void*){Helpers.InstanceIdentifier}, 0, (uint)sizeof({@internal}));");
2947+
29452948
if (!method.IsDefaultConstructor || @class.HasNonTrivialDefaultConstructor)
29462949
GenerateInternalFunctionCall(method);
29472950
}

src/Generator/Options.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,18 @@ public bool DoAllModulesHaveLibraries() =>
119119
/// </summary>
120120
public bool GenerateFinalizers;
121121

122+
/// <summary>
123+
/// If <see cref="ZeroAllocatedMemory"/> returns <c>true</c> for a given <see cref="Class"/>,
124+
/// unmanaged memory allocated in the class' default constructor will be initialized with
125+
/// zeros. The default implementation always returns <c>false</c>. Currently, C# only.
126+
/// </summary>
127+
/// <remarks>
128+
/// If this option returns <c>true</c>, you must take a reference to the nuget package
129+
/// System.Runtime.CompilerServices.Unsafe in the project(s) containing the generated file(s) to
130+
/// resolve the Unsafe.InitBlock method.
131+
/// </remarks>
132+
public Func<Class, bool> ZeroAllocatedMemory = (@class) => false;
133+
122134
public string IncludePrefix;
123135
public Func<TranslationUnit, string> GenerateName;
124136

tests/CSharp/CSharp.Gen.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ where macroRegex.IsMatch(macro.Name)
6565
Name = "MacroTest",
6666
Namespace = ctx.TranslationUnits.First(u => u.IsValid && !u.IsSystemHeader)
6767
};
68+
69+
// Preserve the original semantics except for our one test class.
70+
driver.Options.ZeroAllocatedMemory = (@class) => @class.Name == "ClassZeroAllocatedMemoryTest";
6871
}
6972

7073
public override void Postprocess(Driver driver, ASTContext ctx)

tests/CSharp/CSharp.Tests.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,19 @@ public void TestStdStringConstant()
708708
Assert.That(CSharp.HasFreeConstant.AnotherUnit.STD_STRING_CONSTANT, Is.EqualTo("test"));
709709
}
710710

711+
[Test]
712+
public void TestZeroAllocatedMemoryOption()
713+
{
714+
// We've arranged in the generator for the ZeroAllocatedMemory option to return true for this one
715+
// class.
716+
var test = new ClassZeroAllocatedMemoryTest();
717+
Assert.That(test.P1, Is.EqualTo(0));
718+
Assert.That(test.p2.P2p1, Is.EqualTo(0));
719+
Assert.That(test.p2.P2p2, Is.EqualTo(0));
720+
Assert.That(test.P3, Is.EqualTo(false));
721+
Assert.That(test.P4, Is.EqualTo('\0'));
722+
}
723+
711724
[Test]
712725
public void TestAlignment()
713726
{

tests/CSharp/CSharp.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,6 +1487,14 @@ struct TestVariableWithoutType
14871487
static constexpr auto variable = create(n...);
14881488
};
14891489

1490+
struct DLL_API ClassZeroAllocatedMemoryTest
1491+
{
1492+
int p1;
1493+
struct { int p2p1; int p2p2; } p2;
1494+
bool p3;
1495+
char p4;
1496+
};
1497+
14901498
struct DLL_API ConversionFunctions
14911499
{
14921500
ConversionFunctions();

0 commit comments

Comments
 (0)