|
|
@ -20,6 +20,7 @@ using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.Linq; |
|
|
|
using System.Linq; |
|
|
|
using System.Reflection.Metadata; |
|
|
|
using System.Reflection.Metadata; |
|
|
|
|
|
|
|
using System.Text; |
|
|
|
|
|
|
|
|
|
|
|
using ICSharpCode.Decompiler.TypeSystem; |
|
|
|
using ICSharpCode.Decompiler.TypeSystem; |
|
|
|
using ICSharpCode.Decompiler.Util; |
|
|
|
using ICSharpCode.Decompiler.Util; |
|
|
@ -113,9 +114,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
internal static bool TransformSpanTArrayInitialization(NewObj inst, StatementTransformContext context, out Block block) |
|
|
|
internal static bool TransformSpanTArrayInitialization(NewObj inst, StatementTransformContext context, out ILInstruction replacement) |
|
|
|
{ |
|
|
|
{ |
|
|
|
block = null; |
|
|
|
replacement = null; |
|
|
|
if (!context.Settings.ArrayInitializers) |
|
|
|
if (!context.Settings.ArrayInitializers) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
if (MatchSpanTCtorWithPointerAndSize(inst, context, out var elementType, out var field, out var size)) |
|
|
|
if (MatchSpanTCtorWithPointerAndSize(inst, context, out var elementType, out var field, out var size)) |
|
|
@ -124,10 +125,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
{ |
|
|
|
{ |
|
|
|
var valuesList = new List<ILInstruction>(); |
|
|
|
var valuesList = new List<ILInstruction>(); |
|
|
|
var initialValue = field.GetInitialValue(context.PEFile.Reader, context.TypeSystem); |
|
|
|
var initialValue = field.GetInitialValue(context.PEFile.Reader, context.TypeSystem); |
|
|
|
|
|
|
|
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)) |
|
|
|
if (DecodeArrayInitializer(elementType, initialValue, new[] { size }, valuesList)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
var tempStore = context.Function.RegisterVariable(VariableKind.InitializerTarget, new ArrayType(context.TypeSystem, elementType)); |
|
|
|
var tempStore = context.Function.RegisterVariable(VariableKind.InitializerTarget, new ArrayType(context.TypeSystem, elementType)); |
|
|
|
block = BlockFromInitializer(tempStore, elementType, new[] { size }, valuesList.ToArray()); |
|
|
|
replacement = BlockFromInitializer(tempStore, elementType, new[] { size }, valuesList.ToArray()); |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -135,13 +143,36 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static unsafe bool DecodeUTF8String(BlobReader blob, int size, out string text) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (size > blob.RemainingBytes) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
text = null; |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
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')) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
text = null; |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
text = Encoding.UTF8.GetString(blob.CurrentPointer, size); |
|
|
|
|
|
|
|
// Only use UTF8 string literal if we can perfectly roundtrip the data
|
|
|
|
|
|
|
|
byte[] bytes = Encoding.UTF8.GetBytes(text); |
|
|
|
|
|
|
|
return MemoryExtensions.SequenceEqual(bytes, new ReadOnlySpan<byte>(blob.CurrentPointer, size)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool MatchSpanTCtorWithPointerAndSize(NewObj newObj, StatementTransformContext context, out IType elementType, out FieldDefinition field, out int size) |
|
|
|
static bool MatchSpanTCtorWithPointerAndSize(NewObj newObj, StatementTransformContext context, out IType elementType, out FieldDefinition field, out int size) |
|
|
|
{ |
|
|
|
{ |
|
|
|
field = default; |
|
|
|
field = default; |
|
|
|
size = default; |
|
|
|
size = default; |
|
|
|
elementType = null; |
|
|
|
elementType = null; |
|
|
|
IType type = newObj.Method.DeclaringType; |
|
|
|
IType type = newObj.Method.DeclaringType; |
|
|
|
if (!type.IsKnownType(KnownTypeCode.SpanOfT) && !type.IsKnownType(KnownTypeCode.ReadOnlySpanOfT)) |
|
|
|
if (!type.IsKnownType(KnownTypeCode.ReadOnlySpanOfT)) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
if (newObj.Arguments.Count != 2 || type.TypeArguments.Count != 1) |
|
|
|
if (newObj.Arguments.Count != 2 || type.TypeArguments.Count != 1) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|