diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/App.config b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/App.config
index 18110d074d9..4431c3954ae 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/App.config
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/App.config
@@ -7,6 +7,12 @@
+
+
+
+
+
+
diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs
index eafeb39e173..2a35b407b67 100644
--- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs
+++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs
@@ -1,4 +1,5 @@
using System;
+using System.Buffers;
using System.Collections.Generic;
using System.IO;
using System.Text;
@@ -405,22 +406,22 @@ void WriteGlobalSymbolStart (string symbolName, LlvmIrVariableOptions options, T
{
output = EnsureOutput (output);
- var sb = new StringBuilder (llvmLinkage[options.Linkage]);
- if (options.AddressSignificance != LlvmIrAddressSignificance.Default) {
- if (sb.Length > 0) {
- sb.Append (' ');
- }
+ output.Write ('@');
+ output.Write (symbolName);
+ output.Write (" = ");
- sb.Append (llvmAddressSignificance[options.AddressSignificance]);
+ var linkage = llvmLinkage [options.Linkage];
+ if (!string.IsNullOrEmpty (linkage)) {
+ output.Write (linkage);
+ output.Write (' ');
}
-
- if (sb.Length > 0) {
- sb.Append (' ');
+ if (options.AddressSignificance != LlvmIrAddressSignificance.Default) {
+ output.Write (llvmAddressSignificance[options.AddressSignificance]);
+ output.Write (' ');
}
- sb.Append (llvmWritability[options.Writability]);
-
- output.Write ($"@{symbolName} = {sb.ToString ()} ");
+ output.Write (llvmWritability[options.Writability]);
+ output.Write (' ');
}
object? GetTypedMemberValue (StructureInfo info, StructureMemberInfo smi, StructureInstance instance, Type expectedType, object? defaultValue = null)
@@ -476,7 +477,15 @@ bool MaybeWritePreAllocatedBuffer (StructureInfo info, StructureMemberInfo
WriteGlobalSymbolStart (variableName, preAllocatedBufferVariableOptions, output);
ulong size = bufferSize * smi.BaseTypeSize;
- output.WriteLine ($"[{bufferSize} x {irType}] zeroinitializer, align {GetAggregateAlignment ((int)smi.BaseTypeSize, size)}");
+
+ // WriteLine $"[{bufferSize} x {irType}] zeroinitializer, align {GetAggregateAlignment ((int)smi.BaseTypeSize, size)}"
+ output.Write ('[');
+ output.Write (bufferSize);
+ output.Write (" x ");
+ output.Write (irType);
+ output.Write ("] zeroinitializer, align ");
+ output.WriteLine (GetAggregateAlignment ((int) smi.BaseTypeSize, size));
+
instance.AddPointerData (smi, variableName, size);
return true;
}
@@ -505,7 +514,8 @@ void WriteStructureArrayEnd (StructureInfo info, string? symbolName, ulong
output = EnsureOutput (output);
int alignment = isArrayOfPointers ? PointerSize : GetAggregateAlignment (info.MaxFieldAlignment, info.Size * count);
- output.Write ($", align {alignment}");
+ output.Write (", align ");
+ output.Write (alignment);
if (named && !skipFinalComment) {
WriteEOL ($"end of '{symbolName!}' array", output);
} else {
@@ -519,8 +529,17 @@ void WriteStructureArrayEnd (StructureInfo info, string? symbolName, ulong
public void WriteStructureArray (StructureInfo info, ulong count, LlvmIrVariableOptions options, string? symbolName = null, bool writeFieldComment = true, string? initialComment = null, bool isArrayOfPointers = false)
{
bool named = WriteStructureArrayStart (info, null, options, symbolName, initialComment);
- string pointerAsterisk = isArrayOfPointers ? "*" : String.Empty;
- Output.Write ($"[{count} x %{info.NativeTypeDesignator}.{info.Name}{pointerAsterisk}] zeroinitializer");
+
+ // $"[{count} x %{info.NativeTypeDesignator}.{info.Name}{pointerAsterisk}] zeroinitializer"
+ Output.Write ('[');
+ Output.Write (count);
+ Output.Write (" x %");
+ Output.Write (info.NativeTypeDesignator);
+ Output.Write ('.');
+ Output.Write (info.Name);
+ if (isArrayOfPointers)
+ Output.Write ('*');
+ Output.Write ("] zeroinitializer");
WriteStructureArrayEnd (info, symbolName, (ulong)count, named, skipFinalComment: true, isArrayOfPointers: isArrayOfPointers);
}
@@ -545,7 +564,15 @@ public void WriteStructureArray (StructureInfo info, IList (info, instances, options, symbolName, initialComment, arrayOutput);
int count = instances != null ? instances.Count : 0;
- arrayOutput.Write ($"[{count} x %{info.NativeTypeDesignator}.{info.Name}] ");
+ // $"[{count} x %{info.NativeTypeDesignator}.{info.Name}] "
+ arrayOutput.Write ('[');
+ arrayOutput.Write (count);
+ arrayOutput.Write (" x %");
+ arrayOutput.Write (info.NativeTypeDesignator);
+ arrayOutput.Write ('.');
+ arrayOutput.Write (info.Name);
+ arrayOutput.Write ("] ");
+
if (instances != null) {
var bodyWriterOptions = new StructureBodyWriterOptions (
writeFieldComment: true,
@@ -556,18 +583,20 @@ public void WriteStructureArray (StructureInfo info, IList instance = instances[i];
- arrayOutput.WriteLine ($"{Indent}; {i}");
+ arrayOutput.Write (Indent);
+ arrayOutput.Write ("; ");
+ arrayOutput.WriteLine (i);
WriteStructureBody (info, instance, bodyWriterOptions, nestedStructureWriter);
if (i < count - 1) {
arrayOutput.Write (", ");
}
WriteEOL (output: arrayOutput);
}
- arrayOutput.Write ("]");
+ arrayOutput.Write (']');
WriteBufferToOutput (bodyWriterOptions.StringsOutput);
WriteBufferToOutput (bodyWriterOptions.BuffersOutput);
@@ -614,14 +643,25 @@ public void WriteArray (IList values, LlvmIrVariableOptions options, strin
WriteGlobalSymbolStart (symbolName, options);
string elementType = MapManagedTypeToIR (typeof (T), out ulong size);
- Output.WriteLine ($"[{values.Count} x {elementType}] [");
+
+ // WriteLine $"[{values.Count} x {elementType}] ["
+ Output.Write ('[');
+ Output.Write (values.Count);
+ Output.Write (" x ");
+ Output.Write (elementType);
+ Output.WriteLine ("] [");
+
Output.Write (Indent);
for (int i = 0; i < values.Count; i++) {
if (i != 0) {
if (optimizeOutput) {
Output.Write (',');
if (i % 8 == 0) {
- Output.WriteLine ($" ; {i - 8}..{i - 1}");
+ Output.Write (" ; ");
+ Output.Write (i - 8);
+ Output.Write ("..");
+ Output.WriteLine (i - 1);
+
Output.Write (Indent);
} else {
Output.Write (' ');
@@ -631,7 +671,9 @@ public void WriteArray (IList values, LlvmIrVariableOptions options, strin
}
}
- Output.Write ($"{elementType} {values[i]}");
+ Output.Write (elementType);
+ Output.Write (' ');
+ Output.Write (values [i]);
if (!optimizeOutput) {
bool last = i == values.Count - 1;
@@ -641,7 +683,8 @@ public void WriteArray (IList values, LlvmIrVariableOptions options, strin
string? comment = commentProvider (i, values[i]);
if (!String.IsNullOrEmpty (comment)) {
- Output.Write ($" ; {comment}");
+ Output.Write (" ; ");
+ Output.Write (comment);
}
if (!last) {
@@ -651,11 +694,15 @@ public void WriteArray (IList values, LlvmIrVariableOptions options, strin
}
if (optimizeOutput && values.Count / 8 != 0) {
int idx = values.Count - (values.Count % 8);
- Output.Write ($" ; {idx}..{values.Count - 1}");
+ Output.Write (" ; ");
+ Output.Write (idx);
+ Output.Write ("..");
+ Output.Write (values.Count - 1);
}
Output.WriteLine ();
- Output.WriteLine ($"], align {GetAggregateAlignment ((int)size, size * (ulong)values.Count)}");
+ Output.Write ("], align ");
+ Output.WriteLine (GetAggregateAlignment ((int) size, size * (ulong) values.Count));
}
void AssertArraySize (StructureInfo info, StructureMemberInfo smi, ulong length, ulong expectedLength)
@@ -671,7 +718,8 @@ void RenderArray (StructureInfo info, StructureMemberInfo smi, byte[] b
{
// Byte arrays are represented in the same way as strings, without the explicit NUL termination byte
AssertArraySize (info, smi, expectedArraySize ?? (ulong)bytes.Length, smi.ArrayElements);
- output.Write ($"c{QuoteString (bytes, out _, nullTerminated: false)}");
+ output.Write ('c');
+ output.Write (QuoteString (bytes, bytes.Length, out _, nullTerminated: false));
}
void MaybeWriteStructureStringsAndBuffers (StructureInfo info, StructureMemberInfo smi, StructureInstance instance, StructureBodyWriterOptions options)
@@ -704,7 +752,9 @@ void WriteStructureField (StructureInfo info, StructureInstance instanc
throw new InvalidOperationException ($"Out of line arrays aren't supported at this time (structure '{info.Name}', field '{smi.Info.Name}')");
}
- output.Write ($"{options.FieldIndent}{smi.IRType} ");
+ output.Write (options.FieldIndent);
+ output.Write (smi.IRType);
+ output.Write (" ");
value = valueOverride ?? GetTypedMemberValue (info, smi, instance, smi.MemberType);
if (smi.MemberType == typeof(byte[])) {
@@ -724,10 +774,17 @@ void WriteStructureField (StructureInfo info, StructureInstance instanc
void WriteStructureBody (StructureInfo info, StructureInstance? instance, StructureBodyWriterOptions options, Action? nestedStructureWriter = null)
{
TextWriter structureOutput = EnsureOutput (options.StructureOutput);
- structureOutput.Write ($"{options.StructIndent}%{info.NativeTypeDesignator}.{info.Name} ");
+
+ // $"{options.StructIndent}%{info.NativeTypeDesignator}.{info.Name} "
+ structureOutput.Write (options.StructIndent);
+ structureOutput.Write ('%');
+ structureOutput.Write (info.NativeTypeDesignator);
+ structureOutput.Write ('.');
+ structureOutput.Write (info.Name);
+ structureOutput.Write (' ');
if (instance != null) {
- structureOutput.WriteLine ("{");
+ structureOutput.WriteLine ('{');
for (int i = 0; i < info.Members.Count; i++) {
StructureMemberInfo smi = info.Members[i];
@@ -735,7 +792,8 @@ void WriteStructureBody (StructureInfo info, StructureInstance? instanc
WriteStructureField (info, instance, smi, i, options, structureOutput, nestedStructureWriter: nestedStructureWriter);
}
- structureOutput.Write ($"{options.StructIndent}}}");
+ structureOutput.Write (options.StructIndent);
+ structureOutput.Write ('}');
} else {
structureOutput.Write ("zeroinitializer");
}
@@ -751,8 +809,9 @@ void MaybeWriteFieldComment (StructureInfo info, StructureMemberInfo sm
if (String.IsNullOrEmpty (comment)) {
var sb = new StringBuilder (smi.Info.Name);
if (value != null && smi.MemberType.IsPrimitive && smi.MemberType != typeof(bool)) {
- sb.Append (" (");
- sb.Append ($"0x{value:x})");
+ sb.Append (" (0x");
+ sb.Append ($"{value:x}");
+ sb.Append (')');
}
comment = sb.ToString ();
}
@@ -771,7 +830,9 @@ void FinishStructureField (StructureInfo info, StructureMemberInfo smi,
void WritePrimitiveField (StructureInfo info, StructureMemberInfo smi, StructureInstance instance, TextWriter output, object? overrideValue = null)
{
object? value = overrideValue ?? GetTypedMemberValue (info, smi, instance, smi.MemberType);
- output.Write ($"{smi.IRType} {value}");
+ output.Write (smi.IRType);
+ output.Write (' ');
+ output.Write (value);
}
void WritePointer (StructureInfo info, StructureMemberInfo smi, StructureInstance instance, TextWriter output, object? overrideValue = null)
@@ -829,7 +890,8 @@ void WritePointer (StructureInfo info, StructureMemberInfo smi, Structu
void WriteNullPointer (StructureMemberInfo smi, TextWriter output)
{
- output.Write ($"{smi.IRType} null");
+ output.Write (smi.IRType);
+ output.Write (" null");
}
// In theory, functionality implemented here should be folded into WriteStructureArray, but in practice it would slow processing for most of the structures we
@@ -900,7 +962,10 @@ public void WritePackedStructureArray (StructureInfo info, IList (StructureInfo info, IList");
+ // $"<{{ {psm.ValueIRType}, {psm.PaddingIRType} }}>"
+ instanceType.Append ("<{ ");
+ instanceType.Append (psm.ValueIRType);
+ instanceType.Append (", ");
+ instanceType.Append (psm.PaddingIRType);
+ instanceType.Append (" }>");
}
instanceType.Append (" }");
@@ -946,12 +1016,27 @@ public void WritePackedStructureArray (StructureInfo info, IList <{{ {psm.ValueIRType} c{QuoteString ((byte[])psm.Value)}, {psm.PaddingIRType} zeroinitializer }}> ");
+
+ // $"{bodyWriterOptions.FieldIndent}<{{ {psm.ValueIRType}, {psm.PaddingIRType} }}> <{{ {psm.ValueIRType} c{QuoteString ((byte[])psm.Value)}, {psm.PaddingIRType} zeroinitializer }}> "
+ structureBodyOutput.Write (bodyWriterOptions.FieldIndent);
+ structureBodyOutput.Write ("<{ ");
+ structureBodyOutput.Write (psm.ValueIRType);
+ structureBodyOutput.Write (", ");
+ structureBodyOutput.Write (psm.PaddingIRType);
+ structureBodyOutput.Write (" }> <{ ");
+ structureBodyOutput.Write (psm.ValueIRType);
+ structureBodyOutput.Write (" c");
+ structureBodyOutput.Write (QuoteString ((byte []) psm.Value));
+ structureBodyOutput.Write (", ");
+ structureBodyOutput.Write (psm.PaddingIRType);
+ structureBodyOutput.Write (" zeroinitializer }> ");
+
MaybeWriteFieldComment (info, psm.MemberInfo, instance, bodyWriterOptions, value: null, output: structureBodyOutput);
previousFieldWasPadded = true;
}
structureBodyOutput.WriteLine ();
- structureBodyOutput.Write ($"{Indent}}}");
+ structureBodyOutput.Write (Indent);
+ structureBodyOutput.Write ('}');
}
structureOutput.WriteLine ("<{");
@@ -993,7 +1078,8 @@ StructureBodyWriterOptions InitStructureWrite (StructureInfo info, LlvmIrV
void FinishStructureWrite (StructureInfo info, StructureBodyWriterOptions bodyWriterOptions)
{
- bodyWriterOptions.StructureOutput.WriteLine ($", align {info.MaxFieldAlignment}");
+ bodyWriterOptions.StructureOutput.Write (", align ");
+ bodyWriterOptions.StructureOutput.WriteLine (info.MaxFieldAlignment);
WriteBufferToOutput (bodyWriterOptions.StringsOutput);
WriteBufferToOutput (bodyWriterOptions.BuffersOutput);
@@ -1064,7 +1150,8 @@ void WriteGetBufferPointer (string? variableName, string irType, ulong size, boo
}
if (String.IsNullOrEmpty (variableName)) {
- output.Write ($"{irType} null");
+ output.Write (irType);
+ output.Write (" null");
} else {
string irBaseType;
if (irType[irType.Length - 1] == '*') {
@@ -1073,7 +1160,19 @@ void WriteGetBufferPointer (string? variableName, string irType, ulong size, boo
irBaseType = irType;
}
- output.Write ($"{irType} getelementptr inbounds ([{size} x {irBaseType}], [{size} x {irBaseType}]* @{variableName}, i32 0, i32 0)");
+ // $"{irType} getelementptr inbounds ([{size} x {irBaseType}], [{size} x {irBaseType}]* @{variableName}, i32 0, i32 0)"
+ output.Write (irType);
+ output.Write (" getelementptr inbounds ([");
+ output.Write (size);
+ output.Write (" x ");
+ output.Write (irBaseType);
+ output.Write ("], [");
+ output.Write (size);
+ output.Write (" x ");
+ output.Write (irBaseType);
+ output.Write ("]* @");
+ output.Write (variableName);
+ output.Write (", i32 0, i32 0)");
}
}
@@ -1114,7 +1213,11 @@ void WriteArrayString (string str, string symbolSuffix)
void WriteStringArray (string symbolName, LlvmIrVariableOptions options, List strings)
{
WriteGlobalSymbolStart (symbolName, options);
- Output.Write ($"[{strings.Count} x i8*]");
+
+ // $"[{strings.Count} x i8*]"
+ Output.Write ('[');
+ Output.Write (strings.Count);
+ Output.Write (" x i8*]");
if (strings.Count > 0) {
Output.WriteLine (" [");
@@ -1134,7 +1237,7 @@ void WriteStringArray (string symbolName, LlvmIrVariableOptions options, List 0) {
- Output.Write ("]");
+ Output.Write (']');
}
- Output.WriteLine ($", align {GetAggregateAlignment (PointerSize, arraySize)}");
+ Output.Write (", align ");
+ Output.WriteLine (GetAggregateAlignment (PointerSize, arraySize));
}
///
@@ -1168,7 +1272,11 @@ public void WriteVariable (string symbolName, T value, LlvmIrVariableOptions
string irType = GetIRType (out ulong size, value);
WriteGlobalSymbolStart (symbolName, options);
- Output.WriteLine ($"{irType} {GetValue (value)}, align {size}");
+ Output.Write (irType);
+ Output.Write (' ');
+ Output.Write (GetValue (value));
+ Output.Write (", align ");
+ Output.WriteLine (size);
}
///
@@ -1236,14 +1344,35 @@ public string WriteString (string symbolName, string value, LlvmIrVariableOption
// It might seem counter-intuitive that when we're requested to write a global string, here we generate a **local** one,
// but global strings are actually pointers to local storage.
WriteGlobalSymbolStart (strSymbolName, global ? LlvmIrVariableOptions.LocalConstexprString : options);
- Output.WriteLine ($"[{stringSize} x i8] c{quotedString}, align {GetAggregateAlignment (1, stringSize)}");
+
+ // WriteLine $"[{stringSize} x i8] c{quotedString}, align {GetAggregateAlignment (1, stringSize)}"
+ Output.Write ('[');
+ Output.Write (stringSize);
+ Output.Write (" x i8] c");
+ Output.Write (quotedString);
+ Output.Write (", align ");
+ Output.WriteLine (GetAggregateAlignment (1, stringSize));
+
if (!global) {
return symbolName;
}
string indexType = Is64Bit ? "i64" : "i32";
WriteGlobalSymbolStart (symbolName, LlvmIrVariableOptions.GlobalConstantStringPointer);
- Output.WriteLine ($"i8* getelementptr inbounds ([{stringSize} x i8], [{stringSize} x i8]* @{strSymbolName}, {indexType} 0, {indexType} 0), align {GetAggregateAlignment (PointerSize, stringSize)}");
+
+ // WriteLine $"i8* getelementptr inbounds ([{stringSize} x i8], [{stringSize} x i8]* @{strSymbolName}, {indexType} 0, {indexType} 0), align {GetAggregateAlignment (PointerSize, stringSize)}"
+ Output.Write ("i8* getelementptr inbounds ([");
+ Output.Write (stringSize);
+ Output.Write (" x i8], [");
+ Output.Write (stringSize);
+ Output.Write (" x i8]* @");
+ Output.Write (strSymbolName);
+ Output.Write (", ");
+ Output.Write (indexType);
+ Output.Write (" 0, ");
+ Output.Write (indexType);
+ Output.Write (" 0), align ");
+ Output.WriteLine (GetAggregateAlignment (PointerSize, stringSize));
return symbolName;
}
@@ -1317,7 +1446,14 @@ public void WriteStructureDeclarations ()
public void WriteStructureDeclarationStart (string typeDesignator, string name, bool forOpaqueType = false)
{
WriteEOL ();
- Output.Write ($"%{typeDesignator}.{name} = type ");
+
+ // $"%{typeDesignator}.{name} = type "
+ Output.Write ('%');
+ Output.Write (typeDesignator);
+ Output.Write ('.');
+ Output.Write (name);
+ Output.Write (" = type ");
+
if (forOpaqueType) {
Output.WriteLine ("opaque");
} else {
@@ -1327,12 +1463,13 @@ public void WriteStructureDeclarationStart (string typeDesignator, string name,
public void WriteStructureDeclarationEnd ()
{
- Output.WriteLine ("}");
+ Output.WriteLine ('}');
}
public void WriteStructureDeclarationField (string typeName, string comment, bool last)
{
- Output.Write ($"{Indent}{typeName}");
+ Output.Write (Indent);
+ Output.Write (typeName);
if (!last) {
Output.Write (",");
}
@@ -1400,7 +1537,8 @@ public void WriteDirectiveWithComment (TextWriter writer, string name, string? c
writer.Write (name);
if (!String.IsNullOrEmpty (value)) {
- writer.Write ($" = {value}");
+ writer.Write (" = ");
+ writer.Write (value);
}
WriteEOL (writer, comment);
@@ -1433,28 +1571,39 @@ public static string QuoteString (string value, bool nullTerminated = true)
public static string QuoteString (byte[] bytes)
{
- return QuoteString (bytes, out _, nullTerminated: false);
+ return QuoteString (bytes, bytes.Length, out _, nullTerminated: false);
}
public static string QuoteString (string value, out ulong stringSize, bool nullTerminated = true)
{
- return QuoteString (Encoding.UTF8.GetBytes (value), out stringSize, nullTerminated);
+ var encoding = Encoding.UTF8;
+ int byteCount = encoding.GetByteCount (value);
+ var bytes = ArrayPool.Shared.Rent (byteCount);
+ try {
+ encoding.GetBytes (value, 0, value.Length, bytes, 0);
+ return QuoteString (bytes, byteCount, out stringSize, nullTerminated);
+ } finally {
+ ArrayPool.Shared.Return (bytes);
+ }
}
- public static string QuoteString (byte[] bytes, out ulong stringSize, bool nullTerminated = true)
+ public static string QuoteString (byte[] bytes, int byteCount, out ulong stringSize, bool nullTerminated = true)
{
- var sb = new StringBuilder ();
+ var sb = new StringBuilder (byteCount * 2); // rough estimate of capacity
- foreach (byte b in bytes) {
+ byte b;
+ for (int i = 0; i < byteCount; i++) {
+ b = bytes [i];
if (b != '"' && b != '\\' && b >= 32 && b < 127) {
sb.Append ((char)b);
continue;
}
- sb.Append ($"\\{b:X2}");
+ sb.Append ('\\');
+ sb.Append ($"{b:X2}");
}
- stringSize = (ulong)bytes.Length;
+ stringSize = (ulong) byteCount;
if (nullTerminated) {
stringSize++;
sb.Append ("\\00");