Browse Source

Remove definition-chasing pointer recovery in DeconstructInstruction.IsAssignment

GetPointerElementType existed because a pointer passing through a stack
slot could be typed IntPtr: ILReader replaced the slot type with
FindType(StackType) whenever the inferred type did not match the stack
type. With InferType() implemented on every ILInstruction that fallback
is gone (FlushExpressionStack now asserts the inferred type is
stack-accurate), so the target's inferred type is precise and the
definition chain no longer needs to be walked. Merged stack slots were
never recovered by the helper anyway (it required a single store).

Disabling the PointerType arm makes the uint*/byte* deconstruction
fixtures fail, so the sign-agnostic stobj.Type fallback remains guarded.

Assisted-by: Claude:claude-fable-5:Claude Code
pull/4090/head
Siegfried Pammer 2 weeks ago
parent
commit
9aa3911f3a
  1. 41
      ICSharpCode.Decompiler/IL/Instructions/DeconstructInstruction.cs

41
ICSharpCode.Decompiler/IL/Instructions/DeconstructInstruction.cs

@ -256,17 +256,14 @@ namespace ICSharpCode.Decompiler.IL @@ -256,17 +256,14 @@ namespace ICSharpCode.Decompiler.IL
{
return false;
}
if (stobj.Target.InferType(typeSystem) is ByReferenceType brt)
expectedType = brt.ElementType;
else
{
// Pointer targets do not infer a ByReferenceType. stobj.Type cannot stand
// in for the element type: it comes from the store opcode, which is
// sign-agnostic, so a uint* and an int* both report int32 and a byte*
// reports sbyte. Recover the declared type instead, and only fall back to
// the store where the target is not a pointer at all.
expectedType = GetPointerElementType(stobj.Target, typeSystem) ?? stobj.Type;
}
// stobj.Type comes from the store opcode and is sign-agnostic (an int* and a
// uint* target both store int32), so for pointer targets the element type of
// the target's inferred type must be used instead.
expectedType = stobj.Target.InferType(typeSystem) switch {
ByReferenceType brt => brt.ElementType,
PointerType ptr => ptr.ElementType,
_ => stobj.Type
};
value = stobj.Value;
return true;
default:
@ -274,28 +271,6 @@ namespace ICSharpCode.Decompiler.IL @@ -274,28 +271,6 @@ namespace ICSharpCode.Decompiler.IL
}
}
/// <summary>
/// The element type of a pointer-typed target. A pointer passing through a stack slot
/// is typed IntPtr there, so the declared type has to be taken from the definition the
/// slot was filled from. Returns null if the target is not a pointer.
/// </summary>
static IType GetPointerElementType(ILInstruction target, ICompilation typeSystem)
{
// Bounded because a definition chain could be cyclic in invalid IL.
for (int step = 0; step < 4; step++)
{
if (target.InferType(typeSystem) is PointerType pointerType)
return pointerType.ElementType;
if (!target.MatchLdLoc(out var v) || !v.IsSingleDefinition
|| v.StoreInstructions.Count != 1 || !(v.StoreInstructions[0] is StLoc store))
{
return null;
}
target = store.Value;
}
return null;
}
internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{
base.CheckInvariant(phase, compilation);

Loading…
Cancel
Save