Skip to content

Commit b0d6fa2

Browse files
ds5678siegfriedpammer
authored andcommitted
Add support for array initialization based on RuntimeHelpers.CreateSpan<T>
1 parent 53522c4 commit b0d6fa2

File tree

3 files changed

+74
-0
lines changed

3 files changed

+74
-0
lines changed

ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,19 @@ private static void OutOfMemory()
805805
array[0] = 1;
806806
Console.WriteLine(array.Length);
807807
}
808+
809+
#if !NET40 && CS70
810+
public static ReadOnlySpan<byte> ReadOnlySpanInitializer_ByteArray()
811+
{
812+
return new byte[3] { 1, 2, 3 };
813+
}
814+
815+
public static ReadOnlySpan<int> ReadOnlySpanInitializer_Int32Array()
816+
{
817+
return new int[3] { 1, 2, 3 };
818+
}
819+
#endif
820+
808821
#endregion
809822

810823
#region Object initializers

ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,12 @@ protected internal override void VisitCall(Call inst)
289289
replacement.AcceptVisitor(this);
290290
return;
291291
}
292+
if (TransformArrayInitializers.TransformRuntimeHelpersCreateSpanInitialization(inst, context, out var replacement2))
293+
{
294+
context.Step("TransformRuntimeHelpersCreateSpanInitialization: single-dim", inst);
295+
inst.ReplaceWith(replacement2);
296+
return;
297+
}
292298
base.VisitCall(inst);
293299
TransformAssignment.HandleCompoundAssign(inst, context);
294300
}

ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,40 @@ internal static bool TransformSpanTArrayInitialization(NewObj inst, StatementTra
143143
return false;
144144
}
145145

146+
internal static bool TransformRuntimeHelpersCreateSpanInitialization(Call inst, StatementTransformContext context, out ILInstruction replacement)
147+
{
148+
replacement = null;
149+
if (!context.Settings.ArrayInitializers)
150+
return false;
151+
if (MatchRuntimeHelpersCreateSpan(inst, context, out var elementType, out var field))
152+
{
153+
if (field.HasFlag(System.Reflection.FieldAttributes.HasFieldRVA))
154+
{
155+
var valuesList = new List<ILInstruction>();
156+
var initialValue = field.GetInitialValue(context.PEFile, context.TypeSystem);
157+
var elementTypeSize = elementType.GetSize();
158+
if (elementTypeSize <= 0 || initialValue.Length % elementTypeSize != 0)
159+
return false;
160+
161+
var size = initialValue.Length / elementTypeSize;
162+
if (context.Settings.Utf8StringLiterals &&
163+
elementType.IsKnownType(KnownTypeCode.Byte) &&
164+
DecodeUTF8String(initialValue, size, out string text))
165+
{
166+
replacement = new LdStrUtf8(text);
167+
return true;
168+
}
169+
if (DecodeArrayInitializer(elementType, initialValue, new[] { size }, valuesList))
170+
{
171+
var tempStore = context.Function.RegisterVariable(VariableKind.InitializerTarget, new ArrayType(context.TypeSystem, elementType));
172+
replacement = BlockFromInitializer(tempStore, elementType, new[] { size }, valuesList.ToArray());
173+
return true;
174+
}
175+
}
176+
}
177+
return false;
178+
}
179+
146180
private static unsafe bool DecodeUTF8String(BlobReader blob, int size, out string text)
147181
{
148182
if (size > blob.RemainingBytes)
@@ -187,6 +221,27 @@ static bool MatchSpanTCtorWithPointerAndSize(NewObj newObj, StatementTransformCo
187221
return true;
188222
}
189223

224+
static bool MatchRuntimeHelpersCreateSpan(Call inst, StatementTransformContext context, out IType elementType, out FieldDefinition field)
225+
{
226+
field = default;
227+
elementType = null;
228+
IType type = inst.Method.DeclaringType;
229+
if (type.Namespace != "System.Runtime.CompilerServices" || type.Name != "RuntimeHelpers" || type.TypeParameterCount != 0)
230+
return false;
231+
if (inst.Arguments.Count != 1)
232+
return false;
233+
IMethod method = inst.Method;
234+
if (method.Name != "CreateSpan" || method.TypeArguments.Count != 1)
235+
return false;
236+
elementType = method.TypeArguments[0];
237+
if (!inst.Arguments[0].UnwrapConv(ConversionKind.StopGCTracking).MatchLdMemberToken(out var member))
238+
return false;
239+
if (member.MetadataToken.IsNil)
240+
return false;
241+
field = context.PEFile.Metadata.GetFieldDefinition((FieldDefinitionHandle)member.MetadataToken);
242+
return true;
243+
}
244+
190245
bool DoTransformMultiDim(ILFunction function, Block body, int pos)
191246
{
192247
if (pos >= body.Instructions.Count - 2)

0 commit comments

Comments
 (0)