Browse Source

Add support for array initialization based on RuntimeHelpers.CreateSpan<T>

pull/3380/head
ds5678 6 months ago committed by Siegfried Pammer
parent
commit
b0d6fa2276
  1. 13
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.cs
  2. 6
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  3. 55
      ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs

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

@ -805,6 +805,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests @@ -805,6 +805,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests
array[0] = 1;
Console.WriteLine(array.Length);
}
#if !NET40 && CS70
public static ReadOnlySpan<byte> ReadOnlySpanInitializer_ByteArray()
{
return new byte[3] { 1, 2, 3 };
}
public static ReadOnlySpan<int> ReadOnlySpanInitializer_Int32Array()
{
return new int[3] { 1, 2, 3 };
}
#endif
#endregion
#region Object initializers

6
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -289,6 +289,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -289,6 +289,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
replacement.AcceptVisitor(this);
return;
}
if (TransformArrayInitializers.TransformRuntimeHelpersCreateSpanInitialization(inst, context, out var replacement2))
{
context.Step("TransformRuntimeHelpersCreateSpanInitialization: single-dim", inst);
inst.ReplaceWith(replacement2);
return;
}
base.VisitCall(inst);
TransformAssignment.HandleCompoundAssign(inst, context);
}

55
ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs

@ -143,6 +143,40 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -143,6 +143,40 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
}
internal static bool TransformRuntimeHelpersCreateSpanInitialization(Call inst, StatementTransformContext context, out ILInstruction replacement)
{
replacement = null;
if (!context.Settings.ArrayInitializers)
return false;
if (MatchRuntimeHelpersCreateSpan(inst, context, out var elementType, out var field))
{
if (field.HasFlag(System.Reflection.FieldAttributes.HasFieldRVA))
{
var valuesList = new List<ILInstruction>();
var initialValue = field.GetInitialValue(context.PEFile, context.TypeSystem);
var elementTypeSize = elementType.GetSize();
if (elementTypeSize <= 0 || initialValue.Length % elementTypeSize != 0)
return false;
var size = initialValue.Length / elementTypeSize;
if (context.Settings.Utf8StringLiterals &&
elementType.IsKnownType(KnownTypeCode.Byte) &&
DecodeUTF8String(initialValue, size, out string text))
{
replacement = new LdStrUtf8(text);
return true;
}
if (DecodeArrayInitializer(elementType, initialValue, new[] { size }, valuesList))
{
var tempStore = context.Function.RegisterVariable(VariableKind.InitializerTarget, new ArrayType(context.TypeSystem, elementType));
replacement = BlockFromInitializer(tempStore, elementType, new[] { size }, valuesList.ToArray());
return true;
}
}
}
return false;
}
private static unsafe bool DecodeUTF8String(BlobReader blob, int size, out string text)
{
if (size > blob.RemainingBytes)
@ -187,6 +221,27 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -187,6 +221,27 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true;
}
static bool MatchRuntimeHelpersCreateSpan(Call inst, StatementTransformContext context, out IType elementType, out FieldDefinition field)
{
field = default;
elementType = null;
IType type = inst.Method.DeclaringType;
if (type.Namespace != "System.Runtime.CompilerServices" || type.Name != "RuntimeHelpers" || type.TypeParameterCount != 0)
return false;
if (inst.Arguments.Count != 1)
return false;
IMethod method = inst.Method;
if (method.Name != "CreateSpan" || method.TypeArguments.Count != 1)
return false;
elementType = method.TypeArguments[0];
if (!inst.Arguments[0].UnwrapConv(ConversionKind.StopGCTracking).MatchLdMemberToken(out var member))
return false;
if (member.MetadataToken.IsNil)
return false;
field = context.PEFile.Metadata.GetFieldDefinition((FieldDefinitionHandle)member.MetadataToken);
return true;
}
bool DoTransformMultiDim(ILFunction function, Block body, int pos)
{
if (pos >= body.Instructions.Count - 2)

Loading…
Cancel
Save