|
|
|
@ -119,28 +119,57 @@ namespace ICSharpCode.Decompiler.IL.Transforms
@@ -119,28 +119,57 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
|
|
|
|
replacement = null; |
|
|
|
|
if (!context.Settings.ArrayInitializers) |
|
|
|
|
return false; |
|
|
|
|
if (MatchSpanTCtorWithPointerAndSize(inst, context, out var elementType, out var field, out var size)) |
|
|
|
|
{ |
|
|
|
|
if (field.HasFlag(System.Reflection.FieldAttributes.HasFieldRVA)) |
|
|
|
|
if (!MatchSpanTCtorWithPointerAndSize(inst, context, out var elementType, out var field, out var size)) |
|
|
|
|
return false; |
|
|
|
|
if (!field.HasFlag(System.Reflection.FieldAttributes.HasFieldRVA)) |
|
|
|
|
return false; |
|
|
|
|
var initialValue = field.GetInitialValue(context.PEFile, context.TypeSystem); |
|
|
|
|
replacement = DecodeArrayInitializerOrUTF8StringLiteral(context, elementType, initialValue, size); |
|
|
|
|
return replacement != null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
internal static bool TransformRuntimeHelpersCreateSpanInitialization(Call inst, StatementTransformContext context, out ILInstruction replacement) |
|
|
|
|
{ |
|
|
|
|
var valuesList = new List<ILInstruction>(); |
|
|
|
|
replacement = null; |
|
|
|
|
if (!context.Settings.ArrayInitializers) |
|
|
|
|
return false; |
|
|
|
|
if (!MatchRuntimeHelpersCreateSpan(inst, context, out var elementType, out var field)) |
|
|
|
|
return false; |
|
|
|
|
if (!field.HasFlag(System.Reflection.FieldAttributes.HasFieldRVA)) |
|
|
|
|
return false; |
|
|
|
|
if (IsSubPatternOfCpblkInitializer(inst)) |
|
|
|
|
return false; |
|
|
|
|
var initialValue = field.GetInitialValue(context.PEFile, context.TypeSystem); |
|
|
|
|
if (context.Settings.Utf8StringLiterals && |
|
|
|
|
elementType.IsKnownType(KnownTypeCode.Byte) && |
|
|
|
|
DecodeUTF8String(initialValue, size, out string text)) |
|
|
|
|
var elementTypeSize = elementType.GetSize(); |
|
|
|
|
if (elementTypeSize <= 0 || initialValue.Length % elementTypeSize != 0) |
|
|
|
|
return false; |
|
|
|
|
var size = initialValue.Length / elementTypeSize; |
|
|
|
|
replacement = DecodeArrayInitializerOrUTF8StringLiteral(context, elementType, initialValue, size); |
|
|
|
|
return replacement != null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static bool IsSubPatternOfCpblkInitializer(Call inst) |
|
|
|
|
{ |
|
|
|
|
replacement = new LdStrUtf8(text); |
|
|
|
|
return true; |
|
|
|
|
if (inst.Parent is not AddressOf { Parent: Call { Parent: Cpblk cpblk } get_Item }) |
|
|
|
|
return false; |
|
|
|
|
return MatchGetStaticFieldAddress(get_Item, out _); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static ILInstruction DecodeArrayInitializerOrUTF8StringLiteral(StatementTransformContext context, IType elementType, BlobReader initialValue, int size) |
|
|
|
|
{ |
|
|
|
|
if (context.Settings.Utf8StringLiterals && elementType.IsKnownType(KnownTypeCode.Byte) |
|
|
|
|
&& DecodeUTF8String(initialValue, size, out string text)) |
|
|
|
|
{ |
|
|
|
|
return new LdStrUtf8(text); |
|
|
|
|
} |
|
|
|
|
var valuesList = new List<ILInstruction>(); |
|
|
|
|
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 BlockFromInitializer(tempStore, elementType, new[] { size }, valuesList.ToArray()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static unsafe bool DecodeUTF8String(BlobReader blob, int size, out string text) |
|
|
|
@ -153,9 +182,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
@@ -153,9 +182,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
|
|
|
|
for (int i = 0; i < size; i++) |
|
|
|
|
{ |
|
|
|
|
byte val = blob.CurrentPointer[i]; |
|
|
|
|
// If the string has control characters, it's probably binary data and not a string.
|
|
|
|
|
if (val < 0x20 && val is not ((byte)'\r' or (byte)'\n' or (byte)'\t')) |
|
|
|
|
if (val == 0 && i == size - 1 && size > 1) |
|
|
|
|
{ |
|
|
|
|
// Allow explicit null-termination character.
|
|
|
|
|
} |
|
|
|
|
else if (val < 0x20 && val is not ((byte)'\r' or (byte)'\n' or (byte)'\t')) |
|
|
|
|
{ |
|
|
|
|
// If the string has control characters, it's probably binary data and not a string.
|
|
|
|
|
text = null; |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
@ -187,6 +220,25 @@ namespace ICSharpCode.Decompiler.IL.Transforms
@@ -187,6 +220,25 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static bool MatchRuntimeHelpersCreateSpan(Call inst, StatementTransformContext context, out IType elementType, out FieldDefinition field) |
|
|
|
|
{ |
|
|
|
|
field = default; |
|
|
|
|
elementType = null; |
|
|
|
|
if (!IsRuntimeHelpers(inst.Method.DeclaringType)) |
|
|
|
|
return false; |
|
|
|
|
if (inst.Arguments.Count != 1) |
|
|
|
|
return false; |
|
|
|
|
if (inst.Method is not { Name: "CreateSpan", TypeArguments: [var type] }) |
|
|
|
|
return false; |
|
|
|
|
elementType = type; |
|
|
|
|
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) |
|
|
|
@ -334,7 +386,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
@@ -334,7 +386,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool MatchGetStaticFieldAddress(ILInstruction input, out IField field) |
|
|
|
|
static bool MatchGetStaticFieldAddress(ILInstruction input, out IField field) |
|
|
|
|
{ |
|
|
|
|
if (input.MatchLdsFlda(out field)) |
|
|
|
|
return true; |
|
|
|
@ -357,7 +409,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
@@ -357,7 +409,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
|
|
|
|
return field != null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static bool IsRuntimeHelpers(IType type) => type is { Name: "RuntimeHelpers", Namespace: "System.Runtime.CompilerServices" }; |
|
|
|
|
static bool IsRuntimeHelpers(IType type) => type is { Name: "RuntimeHelpers", Namespace: "System.Runtime.CompilerServices", TypeParameterCount: 0 }; |
|
|
|
|
|
|
|
|
|
unsafe bool HandleSequentialLocAllocInitializer(Block block, int pos, ILVariable store, ILInstruction locAllocInstruction, out IType elementType, out StObj[] values, out int instructionsToRemove) |
|
|
|
|
{ |
|
|
|
|