diff --git a/src/Generator/Generators/CSharp/CSharpSources.cs b/src/Generator/Generators/CSharp/CSharpSources.cs index 3eeae2e5..1629ff90 100644 --- a/src/Generator/Generators/CSharp/CSharpSources.cs +++ b/src/Generator/Generators/CSharp/CSharpSources.cs @@ -438,7 +438,6 @@ namespace CppSharp.Generators.CSharp var dict = $@"global::System.Collections.Concurrent.ConcurrentDictionary"; WriteLine("internal static readonly {0} NativeToManagedMap = new {0}();", dict); - WriteLine("protected internal void*[] __OriginalVTables;"); } PopBlock(NewLineKind.BeforeNextBlock); } @@ -1521,6 +1520,11 @@ namespace CppSharp.Generators.CSharp if (wrappedEntries.Any(e => e.Method.IsDestructor)) WriteLine("private static void*[] __ManagedVTablesDtorOnly;"); WriteLine("private static void*[] _Thunks;"); + WriteLine("private static void*[] __originalVTables;"); + bool hasDynamicBase = @class.NeedsBase && @class.BaseClass.IsDynamic; + Write($@"protected internal {(hasDynamicBase ? "override" : "virtual" + )} void*[] __OriginalVTables => __originalVTables ?? "); + SaveOriginalVTablePointers(@class); NewLine(); GenerateVTableClassSetup(@class, wrappedEntries); @@ -1535,13 +1539,6 @@ namespace CppSharp.Generators.CSharp WriteLine("private void SetupVTables(bool {0} = false)", destructorOnly); WriteOpenBraceAndIndent(); - WriteLine("if (__OriginalVTables != null)"); - WriteLineIndent("return;"); - - SaveOriginalVTablePointers(@class); - - NewLine(); - var hasVirtualDtor = wrappedEntries.Any(e => e.Method.IsDestructor); if (!hasVirtualDtor) { @@ -1549,7 +1546,6 @@ namespace CppSharp.Generators.CSharp WriteLineIndent("return;"); } - // Get the _Thunks WriteLine("if (_Thunks == null)"); WriteOpenBraceAndIndent(); WriteLine("_Thunks = new void*[{0}];", wrappedEntries.Count); @@ -1567,30 +1563,34 @@ namespace CppSharp.Generators.CSharp WriteLine("_Thunks[{0}] = Marshal.GetFunctionPointerForDelegate({1}).ToPointer();", i, instance); } - UnindentAndWriteCloseBrace(); NewLine(); if (hasVirtualDtor) - { - WriteLine("if ({0})", destructorOnly); - WriteOpenBraceAndIndent(); - WriteLine("if (__ManagedVTablesDtorOnly == null)"); - WriteOpenBraceAndIndent(); + AllocateNewVTables(@class, wrappedEntries, destructorOnly: true); - AllocateNewVTables(@class, wrappedEntries, true); + AllocateNewVTables(@class, wrappedEntries, destructorOnly: false); + Write("__originalVTables = "); + SaveOriginalVTablePointers(@class); + UnindentAndWriteCloseBrace(); + + NewLine(); + if (hasVirtualDtor) + { + WriteLine($"if ({destructorOnly})"); + WriteOpenBraceAndIndent(); + AssignNewVTableEntries(@class, "__ManagedVTablesDtorOnly"); UnindentAndWriteCloseBrace(); WriteLine("else"); WriteOpenBraceAndIndent(); - } - WriteLine("if (__ManagedVTables == null)"); - WriteOpenBraceAndIndent(); - - AllocateNewVTables(@class, wrappedEntries, false); - - if (hasVirtualDtor) + AssignNewVTableEntries(@class, "__ManagedVTables"); UnindentAndWriteCloseBrace(); + } + else + { + AssignNewVTableEntries(@class, "__ManagedVTables"); + } UnindentAndWriteCloseBrace(); NewLine(); @@ -1603,6 +1603,20 @@ namespace CppSharp.Generators.CSharp AllocateNewVTablesMS(@class, wrappedEntries, destructorOnly); else AllocateNewVTablesItanium(@class, wrappedEntries, destructorOnly); + + NewLine(); + } + + private void AssignNewVTableEntries(Class @class, string table) + { + int size = Context.ParserOptions.IsMicrosoftAbi ? + @class.Layout.VTablePointers.Count : 1; + + for (int i = 0; i < size; i++) + { + var offset = @class.Layout.VTablePointers[i].Offset; + WriteLine($"*(void**) ({Helpers.InstanceIdentifier} + {offset}) = {table}[{i}];"); + } } private void SaveOriginalVTablePointers(Class @class) @@ -1610,66 +1624,55 @@ namespace CppSharp.Generators.CSharp if (@class.IsDependent) @class = @class.Specializations[0]; + Write("new void*[] { "); + if (Context.ParserOptions.IsMicrosoftAbi) - WriteLine("__OriginalVTables = new void*[] {{ {0} }};", - string.Join(", ", - @class.Layout.VTablePointers.Select(v => - $"*(void**) ({Helpers.InstanceIdentifier} + {v.Offset})"))); + Write(string.Join(", ", @class.Layout.VTablePointers.Select( + v => $"*(void**) ({Helpers.InstanceIdentifier} + {v.Offset})"))); else - WriteLine( - $@"__OriginalVTables = new void*[] {{ *(void**) ({ - Helpers.InstanceIdentifier} + {@class.Layout.VTablePointers[0].Offset}) }};"); + Write($@"*(void**) ({Helpers.InstanceIdentifier} + { + @class.Layout.VTablePointers[0].Offset})"); + + WriteLine(" };"); } private void AllocateNewVTablesMS(Class @class, IList wrappedEntries, bool destructorOnly) { var managedVTables = destructorOnly ? "__ManagedVTablesDtorOnly" : "__ManagedVTables"; - WriteLine("{0} = new void*[{1}];", managedVTables, @class.Layout.VFTables.Count); + WriteLine($"{managedVTables} = new void*[{@class.Layout.VFTables.Count}];"); for (int i = 0; i < @class.Layout.VFTables.Count; i++) { - var vfptr = @class.Layout.VFTables[i]; - var size = vfptr.Layout.Components.Count; - WriteLine("var vfptr{0} = Marshal.AllocHGlobal({1} * {2});", - i, size, Context.TargetInfo.PointerWidth / 8); - WriteLine("{0}[{1}] = vfptr{1}.ToPointer();", managedVTables, i); + VFTableInfo vftable = @class.Layout.VFTables[i]; + int size = vftable.Layout.Components.Count; + string vfptr = $"vfptr{(destructorOnly ? "_dtor" : string.Empty)}{i}"; + WriteLine($@"var {vfptr} = Marshal.AllocHGlobal({size} * { + Context.TargetInfo.PointerWidth / 8});"); + WriteLine($"{managedVTables}[{i}] = {vfptr}.ToPointer();"); - AllocateNewVTableEntries(vfptr.Layout.Components, wrappedEntries, + AllocateNewVTableEntries(vftable.Layout.Components, wrappedEntries, @class.Layout.VTablePointers[i].Offset, i, destructorOnly); } - - UnindentAndWriteCloseBrace(); - NewLine(); - - for (int i = 0; i < @class.Layout.VTablePointers.Count; i++) - { - var offset = @class.Layout.VTablePointers[i].Offset; - WriteLine($"*(void**) ({Helpers.InstanceIdentifier} + {offset}) = {managedVTables}[{i}];"); - } } private void AllocateNewVTablesItanium(Class @class, IList wrappedEntries, bool destructorOnly) { var managedVTables = destructorOnly ? "__ManagedVTablesDtorOnly" : "__ManagedVTables"; - WriteLine("{0} = new void*[1];", managedVTables); + WriteLine($"{managedVTables} = new void*[1];"); - var size = @class.Layout.Layout.Components.Count; - var pointerSize = Context.TargetInfo.PointerWidth / 8; - WriteLine("var vtptr = Marshal.AllocHGlobal({0} * {1});", size, pointerSize); + string suffix = destructorOnly ? "_dtor" : string.Empty; + int size = @class.Layout.Layout.Components.Count; + uint pointerSize = Context.TargetInfo.PointerWidth / 8; + WriteLine($"var vtptr{suffix} = Marshal.AllocHGlobal({size} * {pointerSize});"); - WriteLine("var vfptr0 = vtptr + {0} * {1};", VTables.ItaniumOffsetToTopAndRTTI, pointerSize); - WriteLine("{0}[0] = vfptr0.ToPointer();", managedVTables); + WriteLine($@"var vfptr{suffix}0 = vtptr{suffix} + { + VTables.ItaniumOffsetToTopAndRTTI} * {pointerSize};"); + WriteLine($"{managedVTables}[0] = vfptr{suffix}0.ToPointer();"); AllocateNewVTableEntries(@class.Layout.Layout.Components, wrappedEntries, @class.Layout.VTablePointers[0].Offset, 0, destructorOnly); - - UnindentAndWriteCloseBrace(); - NewLine(); - - var offset = @class.Layout.VTablePointers[0].Offset; - WriteLine($"*(void**) ({Helpers.InstanceIdentifier} + {offset}) = {managedVTables}[0];"); } private void AllocateNewVTableEntries(IList entries, @@ -1684,7 +1687,8 @@ namespace CppSharp.Generators.CSharp var nativeVftableEntry = $@"*(void**) (new IntPtr(*(void**) { Helpers.InstanceIdentifier}) + {vptrOffset} + {offset})"; - var managedVftableEntry = $"*(void**) (vfptr{tableIndex} + {offset})"; + string vfptr = $"vfptr{(destructorOnly ? "_dtor" : string.Empty)}{tableIndex}"; + var managedVftableEntry = $"*(void**) ({vfptr} + {offset})"; if ((entry.Kind == VTableComponentKind.FunctionPointer || entry.Kind == VTableComponentKind.DeletingDtorPointer) && @@ -2207,17 +2211,7 @@ namespace CppSharp.Generators.CSharp var setupVTables = !@class.IsAbstractImpl && hasVTables && dtor?.IsVirtual == true; if (setupVTables) { - WriteLine("if (skipVTables)"); - Indent(); - } - - if (@class.IsAbstractImpl || hasVTables) - SaveOriginalVTablePointers(@class); - - if (setupVTables) - { - Unindent(); - WriteLine("else"); + WriteLine("if (!skipVTables)"); Indent(); GenerateVTableClassSetupCall(@class, destructorOnly: true); Unindent();