Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
114 changes: 58 additions & 56 deletions src/tasks/AotCompilerTask/MonoAOTCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
using Microsoft.Build.Utilities;
using System.Reflection.PortableExecutable;

using JoinedString;

public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
{
/// <summary>
Expand Down Expand Up @@ -714,16 +716,12 @@ private PrecompileArguments GetPrecompileArgumentsFor(ITaskItem assemblyItem, st

if (DirectPInvokes.Length > 0)
{
var directPInvokesSB = new StringBuilder("direct-pinvokes=");
Array.ForEach(DirectPInvokes, directPInvokeItem => directPInvokesSB.Append($"{directPInvokeItem.ItemSpec};"));
aotArgs.Add(directPInvokesSB.ToString());
aotArgs.Add($$"""direct-pinvokes={{DirectPInvokes.Join("", d => $"{d.ItemSpec};")}}""");
}

if (DirectPInvokeLists.Length > 0)
{
var directPInvokeListsSB = new StringBuilder("direct-pinvoke-lists=");
Array.ForEach(DirectPInvokeLists, directPInvokeListItem => directPInvokeListsSB.Append($"{directPInvokeListItem.GetMetadata("FullPath")};"));
aotArgs.Add(directPInvokeListsSB.ToString());
aotArgs.Add($$"""direct-pinvoke-lists={{DirectPInvokeLists.Join("", d => $"{d.GetMetadata("FullPath")};")}}""");
}

if (UseDwarfDebug)
Expand Down Expand Up @@ -1109,62 +1107,66 @@ private bool GenerateAotModulesTable(IEnumerable<ITaskItem> assemblies, string[]
Directory.CreateDirectory(Path.GetDirectoryName(outputFile)!);

using TempFileName tmpAotModulesTablePath = new();
using (var writer = File.CreateText(tmpAotModulesTablePath.Path))
using (var writer = new JoinedStringStreamWriter(tmpAotModulesTablePath.Path, false))
{
if (parsedAotModulesTableLanguage == MonoAotModulesTableLanguage.C)
{
writer.WriteLine("#include <mono/jit/jit.h>");

foreach (var symbol in symbols)
{
writer.WriteLine($"extern void *{symbol};");
}
writer.WriteLine("void register_aot_modules (void);");
writer.WriteLine("void register_aot_modules (void)");
writer.WriteLine("{");
foreach (var symbol in symbols)
{
writer.WriteLine($"\tmono_aot_register_module ({symbol});");
}
writer.WriteLine("}");

foreach (var profiler in profilers ?? Enumerable.Empty<string>())
{
writer.WriteLine($"void mono_profiler_init_{profiler} (const char *desc);");
writer.WriteLine("EMSCRIPTEN_KEEPALIVE void mono_wasm_load_profiler_" + profiler + " (const char *desc) { mono_profiler_init_" + profiler + " (desc); }");
}

if (parsedAotMode == MonoAotMode.LLVMOnly)
{
writer.WriteLine("#define EE_MODE_LLVMONLY 1");
}

if (parsedAotMode == MonoAotMode.LLVMOnlyInterp)
{
writer.WriteLine("#define EE_MODE_LLVMONLY_INTERP 1");
}
profilers ??= Array.Empty<string>();
writer.Write(
$$"""
#include <mono/jit/jit.h>"
{{symbols.Join(writer.NewLine, s =>
$"extern void *{s};")
}}

void register_aot_modules (void);
void register_aot_modules (void)
{
{{symbols.Join(writer.NewLine, s =>
$" mono_aot_register_module ({s});")
}}
}

{{profilers.Join(writer.NewLine, profiler =>
$$$""""
void mono_profiler_init_{{{profiler}}} (const char *desc);
EMSCRIPTEN_KEEPALIVE void mono_wasm_load_profiler_{{{profiler}}} (const char *desc)
{
mono_profiler_init_{{{profiler}}} (desc);
}
"""")
}}

{{parsedAotMode switch
{
MonoAotMode.LLVMOnly => "#define EE_MODE_LLVMONLY 1",
MonoAotMode.LLVMOnlyInterp => "#define EE_MODE_LLVMONLY_INTERP 1",
_ => ""
}
}}
""");
}
else if (parsedAotModulesTableLanguage == MonoAotModulesTableLanguage.ObjC)
{
writer.WriteLine("#include <mono/jit/jit.h>");
writer.WriteLine("#include <TargetConditionals.h>");
writer.WriteLine("");
writer.WriteLine("#if TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || FORCE_AOT)");

foreach (var symbol in symbols)
{
writer.WriteLine($"extern void *{symbol};");
}

writer.WriteLine("void register_aot_modules (void);");
writer.WriteLine("void register_aot_modules (void)");
writer.WriteLine("{");
foreach (var symbol in symbols)
{
writer.WriteLine($"\tmono_aot_register_module ({symbol});");
}
writer.WriteLine("}");
writer.WriteLine("#endif");
writer.Write(
$$"""
#include <mono/jit/jit.h>
#include <TargetConditionals.h>

#if TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || FORCE_AOT)
{{symbols.Join(writer.NewLine, s =>
$"extern void *{s};")
}}

void register_aot_modules (void);
void register_aot_modules (void)
{
{{symbols.Join(writer.NewLine, s =>
$" mono_aot_register_module ({s});")
}}
}
#endif
""");
}
else
{
Expand Down
2 changes: 2 additions & 0 deletions src/tasks/AotCompilerTask/MonoAOTCompiler.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
<Compile Include="..\Common\Utils.cs" />
<Compile Include="..\Common\LogAsErrorException.cs" />
<Compile Include="..\Common\TempFileName.cs" />
<Compile Include="..\Common\JoinedString.cs" />
<Compile Include="..\Common\IsExternalInit.cs" Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'" />
<Compile Include="$(RepoRoot)src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs" Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'" />
</ItemGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ namespace JoinedString;

internal static class JoinedStringExtensions
{
public static JoinedStringEnumerable Join(this IEnumerable<string> list, string separator)
=> JoinedStringEnumerable.Join(list, separator);
public static JoinedStringEnumerable Join<T>(this IEnumerable<T> list, string separator, Func<T, string> formatter)
=> JoinedStringEnumerable.Join(list, separator, formatter);
public static JoinedStringEnumerable Join<T>(this IEnumerable<T> list, string separator, Func<T, int, string> formatter)
=> JoinedStringEnumerable.Join(list, separator, formatter);
public static ConcatinatedString Join(this IEnumerable<string> list, string separator)
=> ConcatinatedString.Join(list, separator);
public static ConcatinatedString Join<T>(this IEnumerable<T> list, string separator, Func<T, string> formatter)
=> ConcatinatedString.Join(list, separator, formatter);
public static ConcatinatedString Join<T>(this IEnumerable<T> list, string separator, Func<T, int, string> formatter)
=> ConcatinatedString.Join(list, separator, formatter);

public static JoinedList<T> Join<T>(this IList<T> list, string separator)
=> new JoinedList<T>(list, separator, (item, _) => $"{item}");
Expand All @@ -27,14 +27,15 @@ public static JoinedList<T> Join<T>(this IList<T> list, string separator, Func<T
=> new JoinedList<T>(list, separator, formatter);
}


internal sealed record JoinedList<T>(IList<T> items, string separator, Func<T, int, string> formatter)
internal sealed record JoinedList<T>(IList<T> items, string separator, Func<T, int, string> formatter) : IStringSegments
{
public IEnumerator<string> GetEnumerator()
{
bool hasSeparator = !string.IsNullOrEmpty(separator);

for (int i = 0; i < items.Count; i++)
{
if (i != 0)
if (hasSeparator && i != 0)
yield return separator;
yield return formatter(items[i], i);
}
Expand All @@ -51,30 +52,36 @@ public override string ToString()
}
}

internal sealed class JoinedStringEnumerable : IEnumerable<string>
internal interface IStringSegments {
public IEnumerator<string> GetEnumerator();
}

internal sealed class ConcatinatedString : IStringSegments, IEnumerable<string>
{
private readonly IEnumerable<string> _values;

private JoinedStringEnumerable(IEnumerable<string> values)
public ConcatinatedString(IEnumerable<string> values)
{
_values = values;
}

public static JoinedStringEnumerable Join(IEnumerable<string> values, string separator)
=> new JoinedStringEnumerable(JoinInternal(values, separator, (x, _) => x));
public static ConcatinatedString Join(IEnumerable<string> values, string separator)
=> new ConcatinatedString(JoinInternal(values, separator, (x, _) => x));

public static JoinedStringEnumerable Join<T>(IEnumerable<T> values, string separator, Func<T, string> format)
=> new JoinedStringEnumerable(JoinInternal(values, separator, (x, _) => format(x)));
public static ConcatinatedString Join<T>(IEnumerable<T> values, string separator, Func<T, string> format)
=> new ConcatinatedString(JoinInternal(values, separator, (x, _) => format(x)));

public static JoinedStringEnumerable Join<T>(IEnumerable<T> values, string separator, Func<T, int, string> format)
=> new JoinedStringEnumerable(JoinInternal(values, separator, format));
public static ConcatinatedString Join<T>(IEnumerable<T> values, string separator, Func<T, int, string> format)
=> new ConcatinatedString(JoinInternal(values, separator, format));

private static IEnumerable<string> JoinInternal<T>(IEnumerable<T> values, string separator, Func<T, int, string> format)
{
int index = 0;
bool hasSeparator = !string.IsNullOrEmpty(separator);

foreach (var value in values)
{
if (index != 0)
if (hasSeparator && index != 0)
yield return separator;
yield return format(value, index++);
}
Expand All @@ -96,11 +103,9 @@ public override string ToString()

internal sealed class JoinedStringStreamWriter : StreamWriter
{

// since we are intentionally using multi-line string writes,
// we want to capture the compile-time new line
private string CompileTimeNewLine =
@"
private string CompileTimeNewLine = @"
";

public JoinedStringStreamWriter(Stream stream) : base(stream)
Expand All @@ -116,25 +121,41 @@ public JoinedStringStreamWriter(string path, bool append) : base(path, append)
#if NET8_0_OR_GREATER
#pragma warning disable CA1822 // Mark members as static
#pragma warning disable IDE0060 // Remove unused parameter
public void Write([InterpolatedStringHandlerArgument("")] JoinedStringWriterHandler builder)
public void Write([InterpolatedStringHandlerArgument("")] StringSegmentStreamWriterHandler builder)
{
// The builder writes directly to the writer
}
#pragma warning restore IDE0060
#pragma warning restore CA1822
#endif

public void Write(IStringSegments list)
{
foreach (var item in list)
{
Write(item);
}
}

public void WriteLine(IStringSegments list)
{
foreach (var item in list)
{
Write(item);
}
WriteLine();
}
}

#if NET8_0_OR_GREATER
[InterpolatedStringHandler]
internal ref struct JoinedStringWriterHandler
internal ref struct StringSegmentStreamWriterHandler
{
private JoinedStringStreamWriter _writer;

#pragma warning disable IDE0060
public JoinedStringWriterHandler(int literalLength, int formattedCount, JoinedStringStreamWriter writer)
public StringSegmentStreamWriterHandler(int literalLength, int formattedCount, JoinedStringStreamWriter writer)
{
writer.Flush();
_writer = writer;
}
#pragma warning restore IDE0060
Expand All @@ -145,15 +166,7 @@ public JoinedStringWriterHandler(int literalLength, int formattedCount, JoinedSt
public void AppendFormatted(char[] buffer, int index, int count) => _writer.Write(buffer, index, count);
public void AppendFormatted(string format, object? arg0, object? arg1, object? arg2) => _writer.Write(format, arg0, arg1, arg2);

public void AppendFormatted(JoinedStringEnumerable list)
{
foreach (var item in list)
{
_writer.Write(item);
}
}

public void AppendFormatted<T>(JoinedList<T> list)
public void AppendFormatted(IStringSegments list)
{
foreach (var item in list)
{
Expand All @@ -162,8 +175,7 @@ public void AppendFormatted<T>(JoinedList<T> list)
}

public override string ToString()
{
_writer.Flush();
{;
return "";
}
}
Expand Down
Loading