Browse Source

Fix #1336: multi-dimensional array initializers with custom objects not detected.

pull/1405/head
Siegfried Pammer 7 years ago
parent
commit
64686b9547
  1. 337
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/InitializerTests.cs
  2. 496
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.cs
  3. 1116
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.il
  4. 1109
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.il
  5. 1111
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.roslyn.il
  6. 1132
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.roslyn.il
  7. 8
      ICSharpCode.Decompiler/IL/Transforms/DynamicCallSiteTransform.cs
  8. 150
      ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs

337
ICSharpCode.Decompiler.Tests/TestCases/Correctness/InitializerTests.cs

@ -129,10 +129,6 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -129,10 +129,6 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
return null;
}
#region Array Initializers
#endregion
public static void CollectionInitializerList()
{
InitializerTests.X(InitializerTests.Y(), new List<int>
@ -414,340 +410,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -414,340 +410,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
}
public int[,] MultidimensionalInit()
{
return new int[,]
{
{
0,
0,
0,
0
},
{
1,
1,
1,
1
},
{
0,
0,
0,
0
},
{
0,
0,
0,
0
},
{
0,
0,
1,
0
},
{
0,
0,
1,
0
},
{
0,
0,
1,
0
},
{
0,
0,
1,
0
},
{
0,
0,
0,
0
},
{
1,
1,
1,
1
},
{
0,
0,
0,
0
},
{
0,
0,
0,
0
},
{
0,
0,
1,
0
},
{
0,
0,
1,
0
},
{
0,
0,
1,
0
},
{
0,
0,
1,
0
}
};
}
public int[][,] MultidimensionalInit2()
{
return new int[][,]
{
new int[,]
{
{
0,
0,
0,
0
},
{
1,
1,
1,
1
},
{
0,
0,
0,
0
},
{
0,
0,
0,
0
}
},
new int[,]
{
{
0,
0,
1,
0
},
{
0,
0,
1,
0
},
{
0,
0,
1,
0
},
{
0,
0,
1,
0
}
},
new int[,]
{
{
0,
0,
0,
0
},
{
1,
1,
1,
1
},
{
0,
0,
0,
0
},
{
0,
0,
0,
0
}
},
new int[,]
{
{
0,
0,
1,
0
},
{
0,
0,
1,
0
},
{
0,
0,
1,
0
},
{
0,
0,
1,
0
}
}
};
}
public int[][,,] ArrayOfArrayOfArrayInit()
{
return new int[][,,]
{
new int[,,]
{
{
{
1,
2,
3
},
{
4,
5,
6
},
{
7,
8,
9
}
},
{
{
11,
12,
13
},
{
14,
15,
16
},
{
17,
18,
19
}
}
},
new int[,,]
{
{
{
21,
22,
23
},
{
24,
25,
26
},
{
27,
28,
29
}
},
{
{
31,
32,
33
},
{
34,
35,
36
},
{
37,
38,
39
}
}
}
};
}
class Issue855
{

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

@ -34,7 +34,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests @@ -34,7 +34,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests
public class TestCases
{
#region Types and helpers
#region Types
public class CustomList<T> : IEnumerable<T>, IEnumerable
{
public IEnumerator<T> GetEnumerator()
@ -260,7 +260,175 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests @@ -260,7 +260,175 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests
#endif
}
// Helper methods used to ensure initializers used within expressions work correctly
public class V3f
{
private float x;
private float y;
private float z;
public V3f(float _x, float _y, float _z)
{
x = _x;
y = _y;
z = _z;
}
}
#endregion
#region Field initializer tests
private static V3f[] Issue1336_rg0 = new V3f[3] {
new V3f(1f, 1f, 1f),
new V3f(2f, 2f, 2f),
new V3f(3f, 3f, 3f)
};
private static V3f[,] Issue1336_rg1 = new V3f[3, 3] {
{
new V3f(1f, 1f, 1f),
new V3f(2f, 2f, 2f),
new V3f(3f, 3f, 3f)
},
{
new V3f(2f, 2f, 2f),
new V3f(3f, 3f, 3f),
new V3f(4f, 4f, 4f)
},
{
new V3f(3f, 3f, 3f),
new V3f(4f, 4f, 4f),
new V3f(5f, 5f, 5f)
}
};
private static V3f[][] Issue1336_rg1b = new V3f[3][] {
new V3f[3] {
new V3f(1f, 1f, 1f),
new V3f(2f, 2f, 2f),
new V3f(3f, 3f, 3f)
},
new V3f[3] {
new V3f(2f, 2f, 2f),
new V3f(3f, 3f, 3f),
new V3f(4f, 4f, 4f)
},
new V3f[3] {
new V3f(3f, 3f, 3f),
new V3f(4f, 4f, 4f),
new V3f(5f, 5f, 5f)
}
};
private static V3f[,][] Issue1336_rg1c = new V3f[3, 3][] {
{
new V3f[3] {
new V3f(1f, 1f, 1f),
new V3f(2f, 2f, 2f),
new V3f(3f, 3f, 3f)
},
new V3f[3] {
new V3f(2f, 2f, 2f),
new V3f(3f, 3f, 3f),
new V3f(4f, 4f, 4f)
},
new V3f[3] {
new V3f(3f, 3f, 3f),
new V3f(4f, 4f, 4f),
new V3f(5f, 5f, 5f)
}
},
{
new V3f[3] {
new V3f(1f, 1f, 1f),
new V3f(2f, 2f, 2f),
new V3f(3f, 3f, 3f)
},
new V3f[3] {
new V3f(2f, 2f, 2f),
new V3f(3f, 3f, 3f),
new V3f(4f, 4f, 4f)
},
new V3f[3] {
new V3f(3f, 3f, 3f),
new V3f(4f, 4f, 4f),
new V3f(5f, 5f, 5f)
}
},
{
new V3f[3] {
new V3f(1f, 1f, 1f),
new V3f(2f, 2f, 2f),
new V3f(3f, 3f, 3f)
},
new V3f[3] {
new V3f(2f, 2f, 2f),
new V3f(3f, 3f, 3f),
new V3f(4f, 4f, 4f)
},
new V3f[3] {
new V3f(3f, 3f, 3f),
new V3f(4f, 4f, 4f),
new V3f(5f, 5f, 5f)
}
}
};
private static V3f[][,] Issue1336_rg1d = new V3f[2][,] {
new V3f[3, 3] {
{
new V3f(1f, 1f, 1f),
new V3f(2f, 2f, 2f),
new V3f(3f, 3f, 3f)
},
{
new V3f(2f, 2f, 2f),
new V3f(3f, 3f, 3f),
new V3f(4f, 4f, 4f)
},
{
new V3f(3f, 3f, 3f),
new V3f(4f, 4f, 4f),
new V3f(5f, 5f, 5f)
}
},
new V3f[3, 3] {
{
new V3f(1f, 1f, 1f),
new V3f(2f, 2f, 2f),
new V3f(3f, 3f, 3f)
},
{
new V3f(2f, 2f, 2f),
new V3f(3f, 3f, 3f),
new V3f(4f, 4f, 4f)
},
{
new V3f(3f, 3f, 3f),
new V3f(4f, 4f, 4f),
new V3f(5f, 5f, 5f)
}
}
};
private static int[,] Issue1336_rg2 = new int[3, 3] {
{
1,
1,
1
},
{
1,
1,
1
},
{
1,
1,
1
}
};
#endregion
#region Helper methods used to ensure initializers used within expressions work correctly
private static void X(object a, object b)
{
}
@ -393,6 +561,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests @@ -393,6 +561,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests
}
});
}
public unsafe static void NestedPointerArray(int a, int b, int c)
{
X(Y(), new void*[3][] {
@ -592,6 +761,329 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests @@ -592,6 +761,329 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests
});
}
public int[,] MultidimensionalInit()
{
return new int[16, 4] {
{
0,
0,
0,
0
},
{
1,
1,
1,
1
},
{
0,
0,
0,
0
},
{
0,
0,
0,
0
},
{
0,
0,
1,
0
},
{
0,
0,
1,
0
},
{
0,
0,
1,
0
},
{
0,
0,
1,
0
},
{
0,
0,
0,
0
},
{
1,
1,
1,
1
},
{
0,
0,
0,
0
},
{
0,
0,
0,
0
},
{
0,
0,
1,
0
},
{
0,
0,
1,
0
},
{
0,
0,
1,
0
},
{
0,
0,
1,
0
}
};
}
public int[][,] MultidimensionalInit2()
{
return new int[4][,] {
new int[4, 4] {
{
0,
0,
0,
0
},
{
1,
1,
1,
1
},
{
0,
0,
0,
0
},
{
0,
0,
0,
0
}
},
new int[4, 4] {
{
0,
0,
1,
0
},
{
0,
0,
1,
0
},
{
0,
0,
1,
0
},
{
0,
0,
1,
0
}
},
new int[4, 4] {
{
0,
0,
0,
0
},
{
1,
1,
1,
1
},
{
0,
0,
0,
0
},
{
0,
0,
0,
0
}
},
new int[4, 4] {
{
0,
0,
1,
0
},
{
0,
0,
1,
0
},
{
0,
0,
1,
0
},
{
0,
0,
1,
0
}
}
};
}
public int[][,,] ArrayOfArrayOfArrayInit()
{
return new int[2][,,] {
new int[2, 3, 3] {
{
{
1,
2,
3
},
{
4,
5,
6
},
{
7,
8,
9
}
},
{
{
11,
12,
13
},
{
14,
15,
16
},
{
17,
18,
19
}
}
},
new int[2, 3, 3] {
{
{
21,
22,
23
},
{
24,
25,
26
},
{
27,
28,
29
}
},
{
{
31,
32,
33
},
{
34,
35,
36
},
{
37,
38,
39
}
}
}
};
}
public static void RecursiveArrayInitializer()
{
int[] array = new int[3];

1116
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.il

File diff suppressed because it is too large Load Diff

1109
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.il

File diff suppressed because it is too large Load Diff

1111
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.roslyn.il

File diff suppressed because it is too large Load Diff

1132
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.roslyn.il

File diff suppressed because it is too large Load Diff

8
ICSharpCode.Decompiler/IL/Transforms/DynamicCallSiteTransform.cs

@ -322,11 +322,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -322,11 +322,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
int numberOfTypeArguments = 0;
if (!value.MatchLdNull()) {
if (value is NewArr typeArgsNewArr && typeArgsNewArr.Type.IsKnownType(KnownTypeCode.Type) && typeArgsNewArr.Indices.Count == 1 && typeArgsNewArr.Indices[0].MatchLdcI4(out numberOfTypeArguments)) {
if (!TransformArrayInitializers.HandleSimpleArrayInitializer(context.Function, callSiteInitBlock, 3, variableOrTemporary, typeArgsNewArr.Type, numberOfTypeArguments, out var typeArguments, out _))
if (!TransformArrayInitializers.HandleSimpleArrayInitializer(context.Function, callSiteInitBlock, 3, variableOrTemporary, typeArgsNewArr.Type, new[] { numberOfTypeArguments }, out var typeArguments, out _))
return false;
int i = 0;
callSiteInfo.TypeArguments = new IType[numberOfTypeArguments];
foreach (var typeArg in typeArguments) {
foreach (var (_, typeArg) in typeArguments) {
if (!TransformExpressionTrees.MatchGetTypeFromHandle(typeArg, out var type))
return false;
callSiteInfo.TypeArguments[i] = type;
@ -496,12 +496,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -496,12 +496,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
if (!(value is NewArr newArr2 && newArr2.Type.FullName == "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo" && newArr2.Indices.Count == 1 && newArr2.Indices[0].MatchLdcI4(out var numberOfArguments)))
return false;
if (!TransformArrayInitializers.HandleSimpleArrayInitializer(context.Function, callSiteInfo.InitBlock, instructionOffset, variable, newArr2.Type, numberOfArguments, out var arguments, out _))
if (!TransformArrayInitializers.HandleSimpleArrayInitializer(context.Function, callSiteInfo.InitBlock, instructionOffset, variable, newArr2.Type, new[] { numberOfArguments }, out var arguments, out _))
return false;
int i = 0;
callSiteInfo.ArgumentInfos = new CSharpArgumentInfo[numberOfArguments];
var compileTimeTypes = callSiteInfo.DelegateType.GetDelegateInvokeMethod().Parameters.SelectReadOnlyArray(p => p.Type);
foreach (var arg in arguments) {
foreach (var (_, arg) in arguments) {
if (!(arg is Call createCall))
return false;
if (!(createCall.Method.Name == "Create" && createCall.Method.DeclaringType.FullName == "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo" && createCall.Arguments.Count == 2))

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

@ -41,7 +41,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -41,7 +41,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
try {
if (DoTransform(context.Function, block, pos))
return;
if (DoTransformMultiDim(block, pos))
if (DoTransformMultiDim(context.Function, block, pos))
return;
if (context.Settings.StackAllocInitializers && DoTransformStackAllocInitializer(block, pos))
return;
@ -57,7 +57,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -57,7 +57,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
ILInstruction inst = body.Instructions[pos];
if (inst.MatchStLoc(out var v, out var newarrExpr) && MatchNewArr(newarrExpr, out var elementType, out var arrayLength)) {
if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, elementType, arrayLength, out var values, out var initArrayPos)) {
context.Step("ForwardScanInitializeArrayRuntimeHelper", inst);
context.Step("ForwardScanInitializeArrayRuntimeHelper: single-dim", inst);
var tempStore = context.Function.RegisterVariable(VariableKind.InitializerTarget, v.Type);
var block = BlockFromInitializer(tempStore, elementType, arrayLength, values);
body.Instructions[pos] = new StLoc(v, block);
@ -66,16 +66,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -66,16 +66,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true;
}
if (arrayLength.Length == 1) {
if (HandleSimpleArrayInitializer(function, body, pos + 1, v, elementType, arrayLength[0], out values, out var instructionsToRemove)) {
context.Step("HandleSimpleArrayInitializer", inst);
if (HandleSimpleArrayInitializer(function, body, pos + 1, v, elementType, arrayLength, out var arrayValues, out var instructionsToRemove)) {
context.Step("HandleSimpleArrayInitializer: single-dim", inst);
var block = new Block(BlockKind.ArrayInitializer);
var tempStore = context.Function.RegisterVariable(VariableKind.InitializerTarget, v.Type);
block.Instructions.Add(new StLoc(tempStore, new NewArr(elementType, arrayLength.Select(l => new LdcI4(l)).ToArray())));
block.Instructions.AddRange(values.SelectWithIndex(
(i, value) => {
block.Instructions.AddRange(arrayValues.Select(
t => {
var (indices, value) = t;
if (value == null)
value = GetNullExpression(elementType);
return StElem(new LdLoc(tempStore), new[] { new LdcI4(i) }, value, elementType);
return StElem(new LdLoc(tempStore), indices, value, elementType);
}
));
block.FinalInstruction = new LdLoc(tempStore);
@ -85,7 +86,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -85,7 +86,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true;
}
if (HandleJaggedArrayInitializer(body, pos + 1, v, elementType, arrayLength[0], out ILVariable finalStore, out values, out instructionsToRemove)) {
context.Step("HandleJaggedArrayInitializer", inst);
context.Step("HandleJaggedArrayInitializer: single-dim", inst);
var block = new Block(BlockKind.ArrayInitializer);
var tempStore = context.Function.RegisterVariable(VariableKind.InitializerTarget, v.Type);
block.Instructions.Add(new StLoc(tempStore, new NewArr(elementType, arrayLength.Select(l => new LdcI4(l)).ToArray())));
@ -101,19 +102,39 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -101,19 +102,39 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
}
bool DoTransformMultiDim(Block body, int pos)
bool DoTransformMultiDim(ILFunction function, Block body, int pos)
{
if (pos >= body.Instructions.Count - 2)
return false;
ILInstruction instr = body.Instructions[pos];
if (instr.MatchStLoc(out var v, out var newarrExpr) && MatchNewArr(newarrExpr, out var arrayType, out var length)) {
if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, arrayType, length, out var values, out var initArrayPos)) {
var block = BlockFromInitializer(v, arrayType, length, values);
ILInstruction inst = body.Instructions[pos];
if (inst.MatchStLoc(out var v, out var newarrExpr) && MatchNewArr(newarrExpr, out var elementType, out var length)) {
if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, elementType, length, out var values, out var initArrayPos)) {
context.Step("ForwardScanInitializeArrayRuntimeHelper: multi-dim", inst);
var block = BlockFromInitializer(v, elementType, length, values);
body.Instructions[pos].ReplaceWith(new StLoc(v, block));
body.Instructions.RemoveAt(initArrayPos);
ILInlining.InlineIfPossible(body, pos, context);
return true;
}
if (HandleSimpleArrayInitializer(function, body, pos + 1, v, elementType, length, out var arrayValues, out var instructionsToRemove)) {
context.Step("HandleSimpleArrayInitializer: multi-dim", inst);
var block = new Block(BlockKind.ArrayInitializer);
var tempStore = context.Function.RegisterVariable(VariableKind.InitializerTarget, v.Type);
block.Instructions.Add(new StLoc(tempStore, new NewArr(elementType, length.Select(l => new LdcI4(l)).ToArray())));
block.Instructions.AddRange(arrayValues.Select(
t => {
var (indices, value) = t;
if (value == null)
value = GetNullExpression(elementType);
return StElem(new LdLoc(tempStore), indices, value, elementType);
}
));
block.FinalInstruction = new LdLoc(tempStore);
body.Instructions[pos] = new StLoc(v, block);
body.Instructions.RemoveRange(pos + 1, instructionsToRemove);
ILInlining.InlineIfPossible(body, pos, context);
return true;
}
}
return false;
}
@ -277,35 +298,92 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -277,35 +298,92 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// <summary>
/// Handle simple case where RuntimeHelpers.InitializeArray is not used.
/// </summary>
internal static bool HandleSimpleArrayInitializer(ILFunction function, Block block, int pos, ILVariable store, IType elementType, int length, out ILInstruction[] values, out int elementCount)
internal static bool HandleSimpleArrayInitializer(ILFunction function, Block block, int pos, ILVariable store, IType elementType, int[] arrayLength, out (ILInstruction[] Indices, ILInstruction Value)[] values, out int elementCount)
{
elementCount = 0;
values = new ILInstruction[length];
int nextMinimumIndex = 0;
for (int i = pos; i < block.Instructions.Count; i++) {
if (nextMinimumIndex >= length)
var length = arrayLength.Aggregate(1, (t, l) => t * l);
values = new (ILInstruction[] Indices, ILInstruction Value)[length];
int[] nextMinimumIndex = new int[arrayLength.Length];
ILInstruction[] CalculateNextIndices(InstructionCollection<ILInstruction> indices, out bool exactMatch)
{
var nextIndices = new ILInstruction[arrayLength.Length];
exactMatch = true;
if (indices == null) {
for (int k = 0; k < nextIndices.Length; k++) {
nextIndices[k] = new LdcI4(nextMinimumIndex[k]);
}
} else {
for (int k = 0; k < indices.Count; k++) {
if (!indices[k].MatchLdcI4(out int index))
return nextIndices;
// index must be in range [0..length[ and must be greater than or equal to nextMinimumIndex
// to avoid running out of bounds or accidentally reordering instructions or overwriting previous instructions.
// However, leaving array slots empty is allowed, as those are filled with default values when the
// initializer block is generated.
if (index < 0 || index >= arrayLength[k] || index < nextMinimumIndex[k])
return null;
if (index != nextMinimumIndex[k]) {
exactMatch = false;
nextIndices[k] = new LdcI4(nextMinimumIndex[k]);
} else {
nextIndices[k] = indices[k];
}
}
}
for (int k = nextMinimumIndex.Length - 1; k >= 0; k--) {
nextMinimumIndex[k]++;
if (nextMinimumIndex[k] < arrayLength[k])
break;
nextMinimumIndex[k] = 0;
}
return nextIndices;
}
int j = 0;
int i = pos;
for (; i < block.Instructions.Count; i++) {
if (!block.Instructions[i].MatchStObj(out ILInstruction target, out ILInstruction value, out IType type))
break;
if (!block.Instructions[i].MatchStObj(out ILInstruction target, out ILInstruction value, out IType type)
|| value.Descendants.OfType<IInstructionWithVariableOperand>().Any(inst => inst.Variable == store))
{
if (value.Descendants.OfType<IInstructionWithVariableOperand>().Any(inst => inst.Variable == store))
break;
}
if (!(target is LdElema ldelem && ldelem.Array.MatchLdLoc(store)))
break;
var indices = ldelem.Indices;
if (!(target is LdElema ldelem) || !ldelem.Array.MatchLdLoc(store) || ldelem.Indices.Count != 1
|| !ldelem.Indices[0].MatchLdcI4(out int index))
{
if (indices.Count != arrayLength.Length)
break;
bool exact;
do {
var nextIndices = CalculateNextIndices(indices, out exact);
if (nextIndices == null)
return false;
if (exact) {
values[j] = (nextIndices, value);
elementCount++;
} else {
values[j] = (nextIndices, null);
}
j++;
} while (!exact);
}
if (i < block.Instructions.Count) {
if (block.Instructions[i].MatchStObj(out ILInstruction target, out ILInstruction value, out IType type)) {
// An element of the array is modified directly after the initializer:
// Abort transform, so that partial initializers are not constructed.
if (target is LdElema ldelem && ldelem.Array.MatchLdLoc(store))
return false;
}
// index must be in range [0..length[ and must be greater than or equal to nextMinimumIndex
// to avoid running out of bounds or accidentally reordering instructions or overwriting previous instructions.
// However, leaving array slots empty is allowed, as those are filled with default values when the
// initializer block is generated.
if (index < 0 || index >= length || index < nextMinimumIndex)
}
while (j < values.Length) {
var nextIndices = CalculateNextIndices(null, out _);
if (nextIndices == null)
return false;
nextMinimumIndex = index;
values[nextMinimumIndex] = value;
nextMinimumIndex++;
elementCount++;
values[j] = (nextIndices, null);
j++;
}
if (pos + elementCount >= block.Instructions.Count)
return false;
@ -314,7 +392,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -314,7 +392,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
static bool ShouldTransformToInitializer(ILFunction function, Block block, int startPos, int elementCount, int length)
{
if (elementCount >= Math.Min(length / 3 + 5, length))
if (elementCount == 0)
return false;
if (elementCount >= length / 3 - 5)
return true;
int? unused = null;
if (ILInlining.IsCatchWhenBlock(block) || ILInlining.IsInConstructorInitializer(function, block.Instructions[startPos], ref unused))

Loading…
Cancel
Save