Skip to content

Commit 8487485

Browse files
committed
Fixed issues with typedefs. Removed early NativeBoolean/NativeChar stuff.
Fixes #200
1 parent 91da8d8 commit 8487485

17 files changed

+367
-43
lines changed

Biohazrd.CSharp/#Declarations/NativeBooleanDeclaration.cs

+7-1
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,17 @@ TransformationResult ICustomTranslatedDeclaration.TransformTypeChildren(ITypeTra
2424
=> this;
2525

2626
void ICustomCSharpTranslatedDeclaration.GenerateOutput(ICSharpOutputGenerator outputGenerator, VisitorContext context, CSharpCodeWriter writer)
27+
=> Emit(Name, writer);
28+
29+
internal static void Emit(CSharpCodeWriter writer)
30+
=> Emit("NativeBoolean", writer);
31+
32+
private static void Emit(string name, CSharpCodeWriter writer)
2733
{
2834
writer.Using("System"); // IComprable, IComparable<T>, IEquatable<T>
2935
writer.Using("System.Runtime.InteropServices"); // StructLayoutAttribute, LayoutKind
3036
writer.Using("System.Runtime.CompilerServices"); // MethodImplAttribute, MethodImplOptions, Unsafe
31-
string sanitizedName = SanitizeIdentifier(Name);
37+
string sanitizedName = SanitizeIdentifier(name);
3238

3339
// Developers should typically not use this type directly anyway, but we provide the same instance methods as System.Boolean
3440
// for scenarios where the return type of a native function is immeidately consumed.

Biohazrd.CSharp/#Declarations/NativeCharDeclaration.cs

+7-1
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,17 @@ TransformationResult ICustomTranslatedDeclaration.TransformTypeChildren(ITypeTra
2020
=> this;
2121

2222
void ICustomCSharpTranslatedDeclaration.GenerateOutput(ICSharpOutputGenerator outputGenerator, VisitorContext context, CSharpCodeWriter writer)
23+
=> Emit(Name, writer);
24+
25+
internal static void Emit(CSharpCodeWriter writer)
26+
=> Emit("NativeChar", writer);
27+
28+
private static void Emit(string name, CSharpCodeWriter writer)
2329
{
2430
writer.Using("System"); // IComparable, IComparable<T>, IEquatable<T>
2531
writer.Using("System.Runtime.InteropServices"); // StructLayoutAttribute, LayoutKind
2632
writer.Using("System.Runtime.CompilerServices"); // MethodImplAttribute, MethodImplOptions, Unsafe
27-
string sanitizedName = SanitizeIdentifier(Name);
33+
string sanitizedName = SanitizeIdentifier(name);
2834

2935
// Developers should typically not use this type directly anyway, but we provide the same instance methods as System.Char
3036
// for scenarios where the return type of a native function is immeidately consumed.

Biohazrd.CSharp/#Transformations/CreateTrampolinesTransformation.cs

+38-26
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using Biohazrd.CSharp.Trampolines;
22
using Biohazrd.Transformation;
33
using ClangSharp.Pathogen;
4-
using System;
54
using System.Collections.Generic;
65
using System.Collections.Immutable;
76
using System.Diagnostics;
@@ -62,13 +61,20 @@ void AddFriendlyAdapter(Adapter target, Adapter adapter)
6261
TypeReference returnType = declaration.ReturnType;
6362

6463
// Handle returning bool
65-
if (TargetRuntime < TargetRuntime.Net7 && returnType == CSharpBuiltinType.Bool)
64+
if (TargetRuntime < TargetRuntime.Net7 && returnType.IsCSharpType(context.Library, CSharpBuiltinType.Bool))
6665
{
67-
//TODO: If function is virtual method rewrite to NativeBoolean instead.
68-
nativeReturnAdapter = new PassthroughReturnAdapter(CSharpBuiltinType.Byte);
69-
friendlyReturnAdapter = new ByteToBoolReturnAdapter(nativeReturnAdapter);
66+
// If the function is virtual, use NativeBoolean on the native side and allow the friendly side to just be passthrough
67+
if (declaration.IsVirtual)
68+
{ nativeReturnAdapter = NonBlittableTypeReturnAdapter.NativeBoolean; }
69+
else
70+
{
71+
nativeReturnAdapter = new PassthroughReturnAdapter(CSharpBuiltinType.Byte);
72+
friendlyReturnAdapter = new ByteToBoolReturnAdapter(nativeReturnAdapter);
73+
}
7074
}
71-
//TODO: Handle char for virtual methods
75+
// Handle virtual methods returning bool
76+
else if (declaration.IsVirtual && TargetRuntime < TargetRuntime.Net7 && returnType.IsCSharpType(context.Library, CSharpBuiltinType.Char))
77+
{ nativeReturnAdapter = NonBlittableTypeReturnAdapter.NativeChar; }
7278
// Handle returning void
7379
else if (returnType is VoidTypeReference)
7480
{ nativeReturnAdapter = VoidReturnAdapter.Instance; }
@@ -129,26 +135,6 @@ void CreateNativeReturnByReferenceAdapter()
129135
// Handle explicit parameters
130136
foreach (TranslatedParameter parameter in declaration.Parameters)
131137
{
132-
// Handle pre-.NET 7 non-blittables
133-
if (TargetRuntime < TargetRuntime.Net7)
134-
{
135-
// Handle bool
136-
if (parameter.Type == CSharpBuiltinType.Bool)
137-
{
138-
//TODO: Rewrite to NativeBoolean for virtual methods
139-
Adapter nativeAdapter = new PassthroughAdapter(parameter, CSharpBuiltinType.Byte);
140-
nativeAdapters.Add(nativeAdapter);
141-
AddFriendlyAdapter(nativeAdapter, new BoolToByteAdapter(nativeAdapter));
142-
continue;
143-
}
144-
145-
// Handle char
146-
if (declaration.IsVirtual && parameter.Type == CSharpBuiltinType.Char)
147-
{
148-
//TODO: Rewrite to NativeChar for virtual methods
149-
}
150-
}
151-
152138
// Handle implicit pass by reference
153139
if (parameter.ImplicitlyPassedByReference)
154140
{
@@ -164,6 +150,32 @@ void CreateNativeReturnByReferenceAdapter()
164150
continue;
165151
}
166152

153+
// Handle pre-.NET 7 non-blittables
154+
if (TargetRuntime < TargetRuntime.Net7)
155+
{
156+
// Handle bool
157+
if (parameter.Type.IsCSharpType(context.Library, CSharpBuiltinType.Bool))
158+
{
159+
// If the function is virtual, use NativeBoolean on the native side and allow the friendly side to just be passthrough
160+
if (declaration.IsVirtual)
161+
{ nativeAdapters.Add(new NonBlittableTypeAdapter(parameter, NonBlittableTypeKind.NativeBoolean)); }
162+
else
163+
{
164+
Adapter nativeAdapter = new PassthroughAdapter(parameter, CSharpBuiltinType.Byte);
165+
nativeAdapters.Add(nativeAdapter);
166+
AddFriendlyAdapter(nativeAdapter, new BoolToByteAdapter(nativeAdapter));
167+
}
168+
continue;
169+
}
170+
171+
// Handle char -- No friendly adapter needed, it can just be passthrough
172+
if (declaration.IsVirtual && parameter.Type.IsCSharpType(context.Library, CSharpBuiltinType.Char))
173+
{
174+
nativeAdapters.Add(new NonBlittableTypeAdapter(parameter, NonBlittableTypeKind.NativeChar));
175+
continue;
176+
}
177+
}
178+
167179
// Typical case
168180
{
169181
Adapter nativeAdapter = new PassthroughAdapter(parameter);

Biohazrd.CSharp/#Transformations/WrapNonBlittableTypesWhereNecessaryTransformation.cs

+2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
using Biohazrd.Transformation;
2+
using System;
23
using System.Diagnostics;
34
using System.Linq;
45

56
namespace Biohazrd.CSharp
67
{
8+
[Obsolete($"This transformation has been superseded by '{nameof(CreateTrampolinesTransformation)}'")]
79
public sealed class WrapNonBlittableTypesWhereNecessaryTransformation : CSharpTypeTransformationBase
810
{
911
private NativeBooleanDeclaration? NativeBoolean = null;

Biohazrd.CSharp/CSharpGenerationOptions.cs

+4
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ public TargetLanguageVersion TargetLanguageVersion
9999
/// </remarks>
100100
public bool SuppressDefaultParameterValuesOnNonPublicMethods { get; init; } = true;
101101

102+
//TODO: We shold automatically prefix this with whatever is configured on OrganizeOutputFilesByNamespaceTransformation
103+
public string InfrastructureTypesNamespace { get; init; } = "Infrastructure";
104+
public string InfrastructureTypesDirectoryPath { get; init; } = "Infrastructure";
105+
102106
public CSharpGenerationOptions()
103107
#pragma warning disable CS0618 // Type or member is obsolete
104108
=> DumpOptions = ClangSharpInfoDumper.DefaultOptions;

Biohazrd.CSharp/CSharpLibraryGenerator.Functions.cs

+14-5
Original file line numberDiff line numberDiff line change
@@ -53,18 +53,18 @@ protected override void VisitFunction(VisitorContext context, TranslatedFunction
5353
{
5454
//TODO: Add enumerator to TrampolineCollection and change this to a foreach
5555
Writer.EnsureSeparation();
56-
trampolines.NativeFunction.Write(this, context, declaration, Writer);
56+
trampolines.NativeFunction.Emit(this, context, declaration, Writer);
5757

5858
if (!ReferenceEquals(trampolines.NativeFunction, trampolines.PrimaryTrampoline))
5959
{
6060
Writer.EnsureSeparation();
61-
trampolines.PrimaryTrampoline.Write(this, context, declaration, Writer);
61+
trampolines.PrimaryTrampoline.Emit(this, context, declaration, Writer);
6262
}
6363

6464
foreach (Trampoline trampoline in trampolines.SecondaryTrampolines)
6565
{
6666
Writer.EnsureSeparation();
67-
trampoline.Write(this, context, declaration, Writer);
67+
trampoline.Emit(this, context, declaration, Writer);
6868
}
6969

7070
return;
@@ -340,7 +340,11 @@ private void EmitFunctionPointerForVTable(VisitorContext context, EmitFunctionCo
340340
if (declaration.ReturnByReference)
341341
{ WriteTypeAsReference(context, declaration, declaration.ReturnType); }
342342
else
343-
{ WriteType(context, declaration, declaration.ReturnType); }
343+
{
344+
string typeString = GetTypeAsString(context, declaration, declaration.ReturnType);
345+
typeString = FixNonBlittableTypeForFunctionPointer(typeString);
346+
Writer.Write(typeString);
347+
}
344348

345349
Writer.Write('>');
346350
}
@@ -447,7 +451,12 @@ void WriteOutReturnBuffer(EmitFunctionContext emitContext)
447451
if (mode == EmitParameterListMode.TrampolineParameters)
448452
{ WriteTypeForTrampoline(parameterContext, parameter, parameter.Type); }
449453
else
450-
{ WriteType(parameterContext, parameter, parameter.Type); }
454+
{
455+
string typeString = GetTypeAsString(parameterContext, parameter, parameter.Type);
456+
if (mode == EmitParameterListMode.VTableFunctionPointerParameters)
457+
{ typeString = FixNonBlittableTypeForFunctionPointer(typeString); }
458+
Writer.Write(typeString);
459+
}
451460
}
452461

453462
if (writeNames)

Biohazrd.CSharp/CSharpLibraryGenerator.ICSharpOutputGenerator.cs

+26-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
using Biohazrd.CSharp.Infrastructure;
22
using Biohazrd.Expressions;
3+
using System;
34

45
namespace Biohazrd.CSharp
56
{
6-
partial class CSharpLibraryGenerator : ICSharpOutputGenerator
7+
partial class CSharpLibraryGenerator : ICSharpOutputGenerator, ICSharpOutputGeneratorInternal
78
{
89
CSharpGenerationOptions ICSharpOutputGenerator.Options => Options;
910

@@ -21,5 +22,29 @@ void ICSharpOutputGenerator.Visit(VisitorContext context, TranslatedDeclaration
2122

2223
void ICSharpOutputGenerator.AddDiagnostic(TranslationDiagnostic diagnostic)
2324
=> Diagnostics.Add(diagnostic);
25+
26+
void ICSharpOutputGeneratorInternal.Fatal(VisitorContext context, TranslatedDeclaration declaration, string? reason)
27+
=> Fatal(context, declaration, reason);
28+
29+
void ICSharpOutputGeneratorInternal.Fatal(VisitorContext context, TranslatedDeclaration declaration, string? reason, string? extraDescription)
30+
=> Fatal(context, declaration, reason, extraDescription);
31+
32+
// These are used for a dirty hack to work around lack of proper support for late-generated infrastructure types
33+
private bool __NeedsNativeBoolean;
34+
private bool __NeedsNativeChar;
35+
void ICSharpOutputGeneratorInternal.__IndicateInfrastructureTypeDependency(NonBlittableTypeKind kind)
36+
{
37+
switch (kind)
38+
{
39+
case NonBlittableTypeKind.NativeBoolean:
40+
__NeedsNativeBoolean = true;
41+
break;
42+
case NonBlittableTypeKind.NativeChar:
43+
__NeedsNativeChar = true;
44+
break;
45+
default:
46+
throw new NotSupportedException();
47+
}
48+
}
2449
}
2550
}

Biohazrd.CSharp/CSharpLibraryGenerator.Records.cs

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Linq;
1+
using Biohazrd.CSharp.Trampolines;
2+
using System.Linq;
23
using static Biohazrd.CSharp.CSharpCodeWriter;
34

45
namespace Biohazrd.CSharp
@@ -89,8 +90,15 @@ private void EmitVTable(VisitorContext context, TranslatedVTableField field, Tra
8990

9091
if (entry.IsFunctionPointer && entry.MethodReference?.TryResolve(context.Library) is TranslatedFunction associatedFunction)
9192
{
92-
EmitFunctionContext emitContext = new(context, associatedFunction);
93-
EmitFunctionPointerForVTable(context, emitContext, associatedFunction);
93+
if (associatedFunction.Metadata.TryGet(out TrampolineCollection trampolines))
94+
{
95+
trampolines.NativeFunction.EmitFunctionPointer(this, context, associatedFunction, Writer);
96+
}
97+
else
98+
{
99+
EmitFunctionContext emitContext = new(context, associatedFunction);
100+
EmitFunctionPointerForVTable(context, emitContext, associatedFunction);
101+
}
94102
}
95103
else
96104
{ WriteType(context.Add(entry), entry, VoidTypeReference.PointerInstance); }

Biohazrd.CSharp/CSharpLibraryGenerator.WriteType.cs

+31-2
Original file line numberDiff line numberDiff line change
@@ -136,16 +136,21 @@ private string GetTypeAsString(VisitorContext context, TranslatedDeclaration dec
136136
returnType += '*';
137137
functionPointerResult += $"{returnType}, ";
138138
}
139+
else
140+
{ returnType = FixNonBlittableTypeForFunctionPointer(returnType); }
139141

140142
int abiIndex = 0;
141143
foreach (TypeReference parameterType in functionPointer.ParameterTypes)
142144
{
143-
functionPointerResult += GetTypeAsString(context, declaration, parameterType);
145+
string parameterTypeString = GetTypeAsString(context, declaration, parameterType);
144146

145147
// Handle parameters implicitly passed by reference
146148
if (haveFunctionAbi && functionPointer.FunctionAbi!.Arguments[abiIndex].Kind == PathogenArgumentKind.Indirect)
147-
{ functionPointerResult += '*'; }
149+
{ parameterTypeString += '*'; }
150+
else
151+
{ parameterTypeString = FixNonBlittableTypeForFunctionPointer(parameterTypeString); }
148152

153+
functionPointerResult += parameterTypeString;
149154
functionPointerResult += ", ";
150155
abiIndex++;
151156
}
@@ -170,5 +175,29 @@ private string GetTypeAsString(VisitorContext context, TranslatedDeclaration dec
170175
return "int";
171176
}
172177
}
178+
179+
/// <summary>Handles types which cannot be blittable in the context of function pointers prior to .NET 7</summary>
180+
/// <remarks>It is never necessary to call this helper when the type is known to be a pointer</remarks>
181+
private string FixNonBlittableTypeForFunctionPointer(string typeString)
182+
{
183+
if (Options.TargetRuntime < TargetRuntime.Net7)
184+
{
185+
// We don't want to compare the actual type with CSharpBuiltinType.Bool/Char here because that would not properly account for typedefs and such.
186+
if (typeString == "bool")
187+
{
188+
__NeedsNativeBoolean = true;
189+
Writer.Using(Options.InfrastructureTypesNamespace);
190+
return "NativeBoolean";
191+
}
192+
else if (typeString == "char")
193+
{
194+
__NeedsNativeChar = true;
195+
Writer.Using(Options.InfrastructureTypesNamespace);
196+
return "NativeChar";
197+
}
198+
}
199+
200+
return typeString;
201+
}
173202
}
174203
}

Biohazrd.CSharp/CSharpLibraryGenerator.cs

+29
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Collections.Immutable;
88
using System.Diagnostics;
99
using System.IO;
10+
using System.Linq;
1011
using static Biohazrd.CSharp.CSharpCodeWriter;
1112

1213
namespace Biohazrd.CSharp
@@ -94,6 +95,34 @@ public static ImmutableArray<TranslationDiagnostic> Generate(CSharpGenerationOpt
9495
generator.Visit(rootVisitorContext, declaration);
9596
}
9697

98+
// Emit autolate-generated infrastructure types
99+
// (This is a bit of a hack until we have proper support for these sort of thigns.)
100+
{
101+
CSharpCodeWriter OpenInfrastructureTypeFile(string fileName)
102+
{
103+
fileName = Path.Combine(options.InfrastructureTypesDirectoryPath, fileName);
104+
return session.Open<CSharpCodeWriter>(fileName);
105+
}
106+
107+
if (generators.Values.Any(g => g.__NeedsNativeBoolean))
108+
{
109+
using (CSharpCodeWriter writer = OpenInfrastructureTypeFile("NativeBoolean.cs"))
110+
using (writer.Namespace(options.InfrastructureTypesNamespace))
111+
{
112+
NativeBooleanDeclaration.Emit(writer);
113+
}
114+
}
115+
116+
if (generators.Values.Any(g => g.__NeedsNativeChar))
117+
{
118+
using (CSharpCodeWriter writer = OpenInfrastructureTypeFile("NativeChar.cs"))
119+
using (writer.Namespace(options.InfrastructureTypesNamespace))
120+
{
121+
NativeCharDeclaration.Emit(writer);
122+
}
123+
}
124+
}
125+
97126
// Finish all writers and collect diagnostics
98127
foreach (CSharpLibraryGenerator generator in generators.Values)
99128
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace Biohazrd.CSharp.Infrastructure;
2+
3+
internal interface ICSharpOutputGeneratorInternal : ICSharpOutputGenerator
4+
{
5+
void Fatal(VisitorContext context, TranslatedDeclaration declaration, string? reason, string? extraDescription);
6+
void Fatal(VisitorContext context, TranslatedDeclaration declaration, string? reason);
7+
8+
// This is used for a dirty hack to work around our lack of proper support for late-generate infrastructure types
9+
void __IndicateInfrastructureTypeDependency(NonBlittableTypeKind kind);
10+
}
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Biohazrd.CSharp;
2+
3+
internal enum NonBlittableTypeKind
4+
{
5+
NativeBoolean,
6+
NativeChar
7+
}

0 commit comments

Comments
 (0)