|
|
@ -531,19 +531,24 @@ namespace CppSharp.Generators.CSharp |
|
|
|
|
|
|
|
|
|
|
|
public void GenerateClassInternals(Class @class) |
|
|
|
public void GenerateClassInternals(Class @class) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
var sequentialLayout = Options.GenerateSequentialLayout && CanUseSequentialLayout(@class); |
|
|
|
|
|
|
|
|
|
|
|
PushBlock(BlockKind.InternalsClass); |
|
|
|
PushBlock(BlockKind.InternalsClass); |
|
|
|
if (!Options.GenerateSequentialLayout || @class.IsUnion) |
|
|
|
|
|
|
|
WriteLine($"[StructLayout(LayoutKind.Explicit, Size = {@class.Layout.GetSize()})]"); |
|
|
|
if (@class.Layout.GetSize() > 0) |
|
|
|
else if (@class.MaxFieldAlignment > 0) |
|
|
|
{ |
|
|
|
WriteLine($"[StructLayout(LayoutKind.Sequential, Pack = {@class.MaxFieldAlignment})]"); |
|
|
|
var layout = sequentialLayout ? "Sequential" : "Explicit"; |
|
|
|
|
|
|
|
var pack = @class.MaxFieldAlignment > 0 ? $", Pack = {@class.MaxFieldAlignment}" : string.Empty; |
|
|
|
|
|
|
|
WriteLine($"[StructLayout(LayoutKind.{layout}, Size = {@class.Layout.GetSize()}{pack})]"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
GenerateClassInternalHead(@class); |
|
|
|
GenerateClassInternalHead(@class); |
|
|
|
WriteOpenBraceAndIndent(); |
|
|
|
WriteOpenBraceAndIndent(); |
|
|
|
|
|
|
|
|
|
|
|
TypePrinter.PushContext(TypePrinterContextKind.Native); |
|
|
|
TypePrinter.PushContext(TypePrinterContextKind.Native); |
|
|
|
|
|
|
|
|
|
|
|
foreach (var field in @class.Layout.Fields) |
|
|
|
GenerateClassInternalsFields(@class, sequentialLayout); |
|
|
|
GenerateClassInternalsField(field, @class); |
|
|
|
|
|
|
|
if (@class.IsGenerated) |
|
|
|
if (@class.IsGenerated) |
|
|
|
{ |
|
|
|
{ |
|
|
|
var functions = GatherClassInternalFunctions(@class); |
|
|
|
var functions = GatherClassInternalFunctions(@class); |
|
|
@ -764,24 +769,71 @@ namespace CppSharp.Generators.CSharp |
|
|
|
Write(" : {0}", string.Join(", ", bases)); |
|
|
|
Write(" : {0}", string.Join(", ", bases)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void GenerateClassInternalsField(LayoutField field, Class @class) |
|
|
|
private bool CanUseSequentialLayout(Class @class) |
|
|
|
{ |
|
|
|
{ |
|
|
|
TypePrinterResult retType = TypePrinter.VisitFieldDecl( |
|
|
|
if (@class.IsUnion) |
|
|
|
new Field { Name = field.Name, QualifiedType = field.QualifiedType }); |
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
|
|
PushBlock(BlockKind.Field); |
|
|
|
var fields = @class.Layout.Fields; |
|
|
|
|
|
|
|
|
|
|
|
if (!Options.GenerateSequentialLayout || @class.IsUnion) |
|
|
|
if (fields.Count > 1) |
|
|
|
WriteLine($"[FieldOffset({field.Offset})]"); |
|
|
|
{ |
|
|
|
Write($"internal {retType}"); |
|
|
|
for (var i = 1; i < fields.Count; ++i) |
|
|
|
if (field.Expression != null) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (fields[i].Offset == fields[i - 1].Offset) |
|
|
|
var fieldValuePrinted = field.Expression.CSharpValue(ExpressionPrinter); |
|
|
|
return false; |
|
|
|
Write($" = {fieldValuePrinted}"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
WriteLine(";"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PopBlock(NewLineKind.BeforeNextBlock); |
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void GenerateClassInternalsFields(Class @class, bool sequentalLayout) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
var fields = @class.Layout.Fields; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < fields.Count; ++i) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
var field = fields[i]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TypePrinterResult retType = TypePrinter.VisitFieldDecl( |
|
|
|
|
|
|
|
new Field { Name = field.Name, QualifiedType = field.QualifiedType }); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PushBlock(BlockKind.Field); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!sequentalLayout) |
|
|
|
|
|
|
|
WriteLine($"[FieldOffset({field.Offset})]"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Write($"internal {retType}"); |
|
|
|
|
|
|
|
if (field.Expression != null) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
var fieldValuePrinted = field.Expression.CSharpValue(ExpressionPrinter); |
|
|
|
|
|
|
|
Write($" = {fieldValuePrinted}"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
WriteLine(";"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// HACK: work around the lack of alignment in StructLayout
|
|
|
|
|
|
|
|
// it's been requested multiple times to no avail:
|
|
|
|
|
|
|
|
// https://github.com/dotnet/runtime/issues/5931, https://github.com/dotnet/runtime/issues/9089, https://github.com/dotnet/runtime/issues/22990
|
|
|
|
|
|
|
|
// Sometimes padding is needed due to aligment.
|
|
|
|
|
|
|
|
// The linux 32 bit target pads at the end the structure
|
|
|
|
|
|
|
|
// which is already handled by using [StructLayout(Size = n)].
|
|
|
|
|
|
|
|
// However the windows 32 bit target pads at the front,
|
|
|
|
|
|
|
|
// right after the vtable pointer, which is what we are handling here
|
|
|
|
|
|
|
|
if (sequentalLayout && fields[i].IsVTablePtr) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
var nativePointerSize = Context.TargetInfo.PointerWidth / 8; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (i + 1 < fields.Count) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
var padding = fields[i + 1].Offset - field.Offset - nativePointerSize; |
|
|
|
|
|
|
|
if (padding > 0 && padding <= @class.Layout.Size) |
|
|
|
|
|
|
|
WriteLine($"internal fixed byte {field.Name}Padding[{padding}];"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PopBlock(sequentalLayout && i + 1 != fields.Count ? NewLineKind.Never : NewLineKind.BeforeNextBlock); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void GenerateClassField(Field field, bool @public = false) |
|
|
|
private void GenerateClassField(Field field, bool @public = false) |
|
|
|