Browse Source

Extract localloc initializer prefix and store offset matching

HandleSequentialLocAllocInitializer mixed three concerns in one method
body: consuming an optional initblk/cpblk prefix, matching the offset of
each sequential store, and assembling the values array. Moving the first
two into TryHandleLocAllocInitializerPrefix and TryGetSequentialStoreOffset
reduces the method to the scan loop itself. Behavior-preserving; the
break-vs-abort distinction of the offset matcher is kept via an out flag.
master
Siegfried Pammer 2 days ago committed by Siegfried Pammer
parent
commit
58edd4f38f
  1. 101
      ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs

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

@ -428,28 +428,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -428,28 +428,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
BlobReader blob = default;
if (lengthInstruction.MatchLdcI(out long byteCount))
if (lengthInstruction.MatchLdcI(out long byteCount)
&& !TryHandleLocAllocInitializerPrefix(block, ref pos, store, byteCount, ref blob, ref instructionsToRemove))
{
if (block.Instructions[pos].MatchInitblk(out var dest, out var value, out var size))
{
if (!dest.MatchLdLoc(store) || !size.MatchLdcI(byteCount))
return false;
instructionsToRemove++;
pos++;
}
else if (block.Instructions[pos].MatchCpblk(out dest, out var src, out size))
{
if (!dest.MatchLdLoc(store) || !size.MatchLdcI(byteCount))
return false;
if (!MatchGetStaticFieldAddress(src, out var field))
return false;
var fd = context.PEFile.Metadata.GetFieldDefinition((FieldDefinitionHandle)field.MetadataToken);
if (!fd.HasFlag(System.Reflection.FieldAttributes.HasFieldRVA))
return false;
blob = fd.GetInitialValue(context.PEFile, context.TypeSystem);
instructionsToRemove++;
pos++;
}
return false;
}
for (int i = pos; i < block.Instructions.Count; i++)
@ -480,22 +462,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -480,22 +462,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
break;
}
// match the target
// should be either ldloc store (at offset 0)
// or binary.add(ldloc store, offset) where offset is either 'elementSize' or 'i * elementSize'
if (!target.MatchLdLoc(store))
if (!TryGetSequentialStoreOffset(target, store, elementType, minExpectedOffset, out var offset, out var abortTransform))
{
if (!target.MatchBinaryNumericInstruction(BinaryNumericOperator.Add, out var left, out var right))
if (abortTransform)
return false;
if (!left.MatchLdLoc(store))
break;
var offsetInst = PointerArithmeticOffset.Detect(right, elementType, ((BinaryNumericInstruction)target).CheckForOverflow);
if (offsetInst == null)
return false;
if (!offsetInst.MatchLdcI(out long offset) || offset < 0 || offset < minExpectedOffset)
break;
minExpectedOffset = offset;
break;
}
minExpectedOffset = offset;
if (values == null)
{
var countInstruction = PointerArithmeticOffset.Detect(lengthInstruction, elementType, checkForOverflow: true);
@ -526,6 +499,66 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -526,6 +499,66 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return elementCount <= values.Length;
}
bool TryHandleLocAllocInitializerPrefix(Block block, ref int pos, ILVariable store, long byteCount, ref BlobReader blob, ref int instructionsToRemove)
{
// initblk(ldloc store, value, byteCount)
if (block.Instructions[pos].MatchInitblk(out var dest, out _, out var size))
{
if (!dest.MatchLdLoc(store) || !size.MatchLdcI(byteCount))
return false;
instructionsToRemove++;
pos++;
return true;
}
// cpblk(ldloc store, ldsflda/call get_Item(CreateSpan(field)) data, byteCount)
if (block.Instructions[pos].MatchCpblk(out dest, out var src, out size))
{
if (!dest.MatchLdLoc(store) || !size.MatchLdcI(byteCount))
return false;
if (!MatchGetStaticFieldAddress(src, out var field))
return false;
var fd = context.PEFile.Metadata.GetFieldDefinition((FieldDefinitionHandle)field.MetadataToken);
if (!fd.HasFlag(System.Reflection.FieldAttributes.HasFieldRVA))
return false;
blob = fd.GetInitialValue(context.PEFile, context.TypeSystem);
instructionsToRemove++;
pos++;
}
return true;
}
static bool TryGetSequentialStoreOffset(ILInstruction target, ILVariable store, IType elementType, long minExpectedOffset, out long offset, out bool abortTransform)
{
offset = 0;
abortTransform = false;
// stobj T(ldloc store, value) writes at the current expected offset, initially 0.
if (target.MatchLdLoc(store))
{
offset = minExpectedOffset;
return true;
}
// stobj T(binary.add(ldloc store, offset), value)
// The offset is either sizeof(T) or an element index multiplied by sizeof(T).
if (!target.MatchBinaryNumericInstruction(BinaryNumericOperator.Add, out var left, out var right))
{
abortTransform = true;
return false;
}
if (!left.MatchLdLoc(store))
return false;
var offsetInst = PointerArithmeticOffset.Detect(right, elementType, ((BinaryNumericInstruction)target).CheckForOverflow);
if (offsetInst == null)
{
abortTransform = true;
return false;
}
return offsetInst.MatchLdcI(out offset) && offset >= 0 && offset >= minExpectedOffset;
}
ILInstruction RewrapStore(ILVariable target, StObj storeInstruction, IType type)
{
ILInstruction targetInst;

Loading…
Cancel
Save