Browse Source

generate calls to cctor when passing paramters by value

pull/1766/head
Joao Matos 2 years ago
parent
commit
1697112147
  1. 24
      src/Generator/Generators/CSharp/CSharpMarshal.cs
  2. 10
      src/Generator/Generators/CSharp/CSharpSources.cs
  3. 15
      tests/dotnet/CSharp/CSharp.Tests.cs
  4. 26
      tests/dotnet/CSharp/CSharp.cpp
  5. 13
      tests/dotnet/CSharp/CSharp.h

24
src/Generator/Generators/CSharp/CSharpMarshal.cs

@ -767,13 +767,37 @@ namespace CppSharp.Generators.CSharp @@ -767,13 +767,37 @@ namespace CppSharp.Generators.CSharp
if (type.IsPointer())
{
if (Context.Parameter.IsIndirect)
{
Method cctor = @class.HasNonTrivialCopyConstructor ? @class.Methods.First(c => c.IsCopyConstructor) : null;
if (cctor != null && cctor.IsGenerated)
{
Context.Before.WriteLine($"if (ReferenceEquals({Context.Parameter.Name}, null))");
Context.Before.WriteLineIndent(
$@"throw new global::System.ArgumentNullException(""{
Context.Parameter.Name}"", ""Cannot be null because it is passed by value."");");
var nativeClass = typePrinter.PrintNative(@class);
var cctorName = CSharpSources.GetFunctionNativeIdentifier(Context.Context, cctor);
Context.Before.WriteLine($"byte* __{Context.Parameter.Name}Memory = stackalloc byte[sizeof({nativeClass})];");
Context.Before.WriteLine($"__IntPtr __{Context.Parameter.Name}Ptr = (__IntPtr)__{Context.Parameter.Name}Memory;");
Context.Before.WriteLine($"{nativeClass}.{cctorName}(__{Context.Parameter.Name}Ptr, {Context.Parameter.Name}.__Instance);");
Context.Return.Write($"__{Context.Parameter.Name}Ptr");
if (Context.Context.ParserOptions.IsItaniumLikeAbi && @class.HasNonTrivialDestructor)
{
Method dtor = @class.Destructors.FirstOrDefault();
if (dtor != null)
{
// todo: virtual destructors?
Context.Cleanup.WriteLine($"{nativeClass}.dtor(__{Context.Parameter.Name}Ptr);");
}
}
}
else
{
Context.Return.Write(paramInstance);
}
}
else
{
Context.Return.Write("{0}{1}",

10
src/Generator/Generators/CSharp/CSharpSources.cs

@ -3464,6 +3464,12 @@ internal static{(@new ? " new" : string.Empty)} {printedClass} __GetInstance({Ty @@ -3464,6 +3464,12 @@ internal static{(@new ? " new" : string.Empty)} {printedClass} __GetInstance({Ty
public string GetFunctionNativeIdentifier(Function function,
bool isForDelegate = false)
{
return GetFunctionNativeIdentifier(Context, function, isForDelegate);
}
public static string GetFunctionNativeIdentifier(BindingContext context, Function function,
bool isForDelegate = false)
{
var identifier = new StringBuilder();
@ -3494,12 +3500,12 @@ internal static{(@new ? " new" : string.Empty)} {printedClass} __GetInstance({Ty @@ -3494,12 +3500,12 @@ internal static{(@new ? " new" : string.Empty)} {printedClass} __GetInstance({Ty
identifier.Append(Helpers.GetSuffixFor(specialization));
var internalParams = function.GatherInternalParams(
Context.ParserOptions.IsItaniumLikeAbi);
context.ParserOptions.IsItaniumLikeAbi);
var overloads = function.Namespace.GetOverloads(function)
.Where(f => (!f.Ignore ||
(f.OriginalFunction != null && !f.OriginalFunction.Ignore)) &&
(isForDelegate || internalParams.SequenceEqual(
f.GatherInternalParams(Context.ParserOptions.IsItaniumLikeAbi),
f.GatherInternalParams(context.ParserOptions.IsItaniumLikeAbi),
new MarshallingParamComparer()))).ToList();
var index = -1;
if (overloads.Count > 1)

15
tests/dotnet/CSharp/CSharp.Tests.cs

@ -1995,4 +1995,19 @@ public unsafe class CSharpTests @@ -1995,4 +1995,19 @@ public unsafe class CSharpTests
Assert.IsTrue(CSharp.CSharp.PointerToClass.IsDefaultInstance);
Assert.IsTrue(CSharp.CSharp.PointerToClass.IsValid);
}
[Test]
public void TestCallByValueCopyConstructor()
{
using (var s = new CallByValueCopyConstructor())
{
s.A = 500;
CSharp.CSharp.CallByValueCopyConstructorFunction(s);
Assert.That(s.A, Is.EqualTo(500));
}
Assert.That(CallByValueCopyConstructor.ConstructorCalls, Is.EqualTo(1));
Assert.That(CallByValueCopyConstructor.CopyConstructorCalls, Is.EqualTo(1));
Assert.That(CallByValueCopyConstructor.DestructorCalls, Is.EqualTo(2));
}
}

26
tests/dotnet/CSharp/CSharp.cpp

@ -1791,3 +1791,29 @@ bool PointerTester::IsValid() @@ -1791,3 +1791,29 @@ bool PointerTester::IsValid()
}
PointerTester* PointerToClass = &internalPointerTesterInstance;
int CallByValueCopyConstructor::constructorCalls = 0;
int CallByValueCopyConstructor::destructorCalls = 0;
int CallByValueCopyConstructor::copyConstructorCalls = 0;
CallByValueCopyConstructor::CallByValueCopyConstructor()
{
a = 0;
constructorCalls++;
}
CallByValueCopyConstructor::CallByValueCopyConstructor(const CallByValueCopyConstructor& other)
{
a = other.a;
copyConstructorCalls++;
}
CallByValueCopyConstructor::~CallByValueCopyConstructor()
{
destructorCalls++;
}
void CallByValueCopyConstructorFunction(CallByValueCopyConstructor s)
{
s.a = 99999;
}

13
tests/dotnet/CSharp/CSharp.h

@ -1603,3 +1603,16 @@ public: @@ -1603,3 +1603,16 @@ public:
};
DLL_API extern PointerTester* PointerToClass;
struct DLL_API CallByValueCopyConstructor {
int a;
static int constructorCalls;
static int destructorCalls;
static int copyConstructorCalls;
CallByValueCopyConstructor();
~CallByValueCopyConstructor();
CallByValueCopyConstructor(const CallByValueCopyConstructor& other);
};
DLL_API void CallByValueCopyConstructorFunction(CallByValueCopyConstructor s);

Loading…
Cancel
Save