Skip to content

Commit

Permalink
WIP handling of RuntimeHelpers.CreateSpan<T>
Browse files Browse the repository at this point in the history
  • Loading branch information
ds5678 committed Jan 24, 2025
1 parent e94eb91 commit 6b6b1ed
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,17 @@ public static void StructInitializerWithinObjectInitializer()
});
}

#if true
public static ReadOnlySpan<byte> ReadOnlySpanInitializer_ByteArray()
{
return new byte[] { 1, 2, 3 };
}
public static ReadOnlySpan<int> ReadOnlySpanInitializer_Int32Array()
{
return new int[] { 1, 2, 3 };
}
#endif

public static void Bug270_NestedInitialisers()
{
NumberFormatInfo[] numberFormats = null;
Expand Down
6 changes: 6 additions & 0 deletions ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,12 @@ protected internal override void VisitCall(Call inst)
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);
}
Expand Down
55 changes: 55 additions & 0 deletions ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,40 @@ internal static bool TransformSpanTArrayInitialization(NewObj inst, StatementTra
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)
Expand Down Expand Up @@ -187,6 +221,27 @@ static bool MatchSpanTCtorWithPointerAndSize(NewObj newObj, StatementTransformCo
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)
Expand Down

0 comments on commit 6b6b1ed

Please sign in to comment.