diff --git a/unity/UnityEmbedHost.Generator/NativeGeneration.cs b/unity/UnityEmbedHost.Generator/NativeGeneration.cs index 458728b65b0b61..35d8aa5789d69f 100644 --- a/unity/UnityEmbedHost.Generator/NativeGeneration.cs +++ b/unity/UnityEmbedHost.Generator/NativeGeneration.cs @@ -36,36 +36,34 @@ static void ReplaceNativeWrapperImplementations(GeneratorExecutionContext contex return; } - var methodToWrapper = new Dictionary(); - 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 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"); @@ -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] != "}") { @@ -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. @@ -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 { @@ -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(); } @@ -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(); } @@ -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("}"); } diff --git a/unity/unity-embed-host/NoNativeWrapperAttribute.cs b/unity/unity-embed-host/NativeWrapperOptionsAttribute.cs similarity index 100% rename from unity/unity-embed-host/NoNativeWrapperAttribute.cs rename to unity/unity-embed-host/NativeWrapperOptionsAttribute.cs