Skip to content

Source gen adjustments to deal with GCX_PREEMP #123

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 29 additions & 23 deletions unity/UnityEmbedHost.Generator/NativeGeneration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,36 +36,34 @@ static void ReplaceNativeWrapperImplementations(GeneratorExecutionContext contex
return;
}

var methodToWrapper = new Dictionary<string, string>();
foreach (var method in callbackMethods)
{
// Some methods don't need a native wrapper. Check for that before writing
if (method.HasAttribute(NoNativeWrapperAttributeName))
continue;
methodToWrapper.Add(method.NativeWrapperName(), GenerateNativeWrapperMethod(method));
}
var nativeMethodsToWrite = callbackMethods.Where(m => !m.HasAttribute(NoNativeWrapperAttributeName))
.Select(m => (m.NativeWrapperName(), m))
.ToList();

bool TryGetWrapperDeclarationLine(string line, Dictionary<string, string> wrappers, out string matchingWrapperName)
bool TryGetWrapperDeclarationLine(string line, List<(string, IMethodSymbol)> wrappers, out (string, IMethodSymbol) match)
{
if (!IsMethodDeclarationLine(line))
{
matchingWrapperName = string.Empty;
match = default;
return false;
}

foreach (var wrapperName in wrappers.Keys)
foreach (var wrapperData in wrappers)
{
if (line.Contains(wrapperName))
if (line.Contains(wrapperData.Item1))
{
matchingWrapperName = wrapperName;
match = wrapperData;
return true;
}
}

matchingWrapperName = string.Empty;
match = default;
return false;
}

bool IsGCPreEmp(string line)
=> line.Contains("GCX_PREEMP();");

bool IsMethodDeclarationLine(string line)
=> line.StartsWith("extern \"C\" EXPORT_API");

Expand All @@ -80,10 +78,11 @@ bool IsHostStructDeclarationLine(string line)
for (int index = 0; index < lines.Length; index++)
{
string? line = lines[index];
if (TryGetWrapperDeclarationLine(line, methodToWrapper, out var match))
if (TryGetWrapperDeclarationLine(line, nativeMethodsToWrite, out var match))
{
bool foundEndOfMethod = true;
var temporaryBackup = new StringBuilder();
var hasGcxPreEmp = false;

while (lines[index] != "}")
{
Expand All @@ -95,6 +94,10 @@ bool IsHostStructDeclarationLine(string line)
foundEndOfMethod = false;
break;
}

if (IsGCPreEmp(lines[index]))
hasGcxPreEmp = true;

if (IsMethodDeclarationLine(lines[index]))
{
// We hit the next method without finding the end of the current one. Also bad.
Expand All @@ -105,9 +108,9 @@ bool IsHostStructDeclarationLine(string line)

if (foundEndOfMethod)
{
sb.Append(methodToWrapper[match]);
sb.Append(GenerateNativeWrapperMethod(match.Item2, hasGcxPreEmp));
// Remove so that we know which have not been written
methodToWrapper.Remove(match);
nativeMethodsToWrite.Remove(match);
}
else
{
Expand All @@ -133,9 +136,11 @@ bool IsHostStructDeclarationLine(string line)
}
}

foreach (var unwritten in methodToWrapper.Keys)
foreach (var unwritten in nativeMethodsToWrite)
{
sb.Append(methodToWrapper[unwritten]);
sb.Append(GenerateNativeWrapperMethod(unwritten.m,
// Better safe than sorry? Control may need to be exposed
includeGcxPreEmp: true));
sb.AppendLine();
}

Expand All @@ -161,10 +166,10 @@ private static string GenerateNativeHostStruct(IMethodSymbol[] callbackMethods)
return sb.ToString();
}

private static string GenerateNativeWrapperMethod(IMethodSymbol method)
private static string GenerateNativeWrapperMethod(IMethodSymbol method, bool includeGcxPreEmp)
{
var sb = new StringBuilder();
AppendNativeWrapperMethod(sb, method);
AppendNativeWrapperMethod(sb, method, includeGcxPreEmp);
return sb.ToString();
}

Expand All @@ -179,12 +184,13 @@ private static void AppendAutoGeneratedComment(StringBuilder sb, string? message
sb.AppendLine();
}

private static void AppendNativeWrapperMethod(StringBuilder sb, IMethodSymbol method)
private static void AppendNativeWrapperMethod(StringBuilder sb, IMethodSymbol method, bool includeGcxPreEmp)
{
AppendAutoGeneratedComment(sb);
sb.AppendLine(FormatNativeWrapperMethodSignature(method));
sb.AppendLine("{");
sb.AppendLine(" GCX_PREEMP(); // temporary until we sort out our GC thread model");
if (includeGcxPreEmp)
sb.AppendLine(" GCX_PREEMP(); // temporary until we sort out our GC thread model");
sb.AppendLine($" {FormatManagedCallbackCall(method)}");
sb.AppendLine("}");
}
Expand Down