Browse Source

More strictly test the inline assignment pattern.

pull/960/head
Daniel Grunwald 8 years ago
parent
commit
385005b2e5
  1. 17
      ICSharpCode.Decompiler/IL/ILVariable.cs
  2. 12
      ICSharpCode.Decompiler/IL/Instructions.cs
  3. 8
      ICSharpCode.Decompiler/IL/Instructions.tt
  4. 31
      ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

17
ICSharpCode.Decompiler/IL/ILVariable.cs

@ -335,8 +335,23 @@ namespace ICSharpCode.Decompiler.IL @@ -335,8 +335,23 @@ namespace ICSharpCode.Decompiler.IL
{
output.WriteReference(this.Name, this, isLocal: true);
}
/// <summary>
/// Gets whether this variable occurs within the specified instruction.
/// </summary>
internal bool IsUsedWithin(ILInstruction inst)
{
if (inst is IInstructionWithVariableOperand iwvo && iwvo.Variable == this) {
return true;
}
foreach (var child in inst.Children) {
if (IsUsedWithin(child))
return true;
}
return false;
}
}
public interface IInstructionWithVariableOperand
{
ILVariable Variable { get; set; }

12
ICSharpCode.Decompiler/IL/Instructions.cs

@ -93,7 +93,8 @@ namespace ICSharpCode.Decompiler.IL @@ -93,7 +93,8 @@ namespace ICSharpCode.Decompiler.IL
LdLoc,
/// <summary>Loads the address of a local variable. (ldarga/ldloca)</summary>
LdLoca,
/// <summary>Stores a value into a local variable. (starg/stloc)</summary>
/// <summary>Stores a value into a local variable. (IL: starg/stloc)
/// Evaluates to the value that was stored (for byte/short variables: evaluates to the truncated value)</summary>
StLoc,
/// <summary>Stores the value into an anonymous temporary variable, and returns the address of that variable.</summary>
AddressOf,
@ -137,7 +138,8 @@ namespace ICSharpCode.Decompiler.IL @@ -137,7 +138,8 @@ namespace ICSharpCode.Decompiler.IL
IsInst,
/// <summary>Indirect load (ref/pointer dereference).</summary>
LdObj,
/// <summary>Indirect store (store to ref/pointer).</summary>
/// <summary>Indirect store (store to ref/pointer).
/// Evaluates to the value that was stored (when using type byte/short: evaluates to the truncated value)</summary>
StObj,
/// <summary>Boxes a value.</summary>
Box,
@ -2217,7 +2219,8 @@ namespace ICSharpCode.Decompiler.IL @@ -2217,7 +2219,8 @@ namespace ICSharpCode.Decompiler.IL
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Stores a value into a local variable. (starg/stloc)</summary>
/// <summary>Stores a value into a local variable. (IL: starg/stloc)
/// Evaluates to the value that was stored (for byte/short variables: evaluates to the truncated value)</summary>
public sealed partial class StLoc : ILInstruction, IStoreInstruction
{
public StLoc(ILVariable variable, ILInstruction value) : base(OpCode.StLoc)
@ -3540,7 +3543,8 @@ namespace ICSharpCode.Decompiler.IL @@ -3540,7 +3543,8 @@ namespace ICSharpCode.Decompiler.IL
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Indirect store (store to ref/pointer).</summary>
/// <summary>Indirect store (store to ref/pointer).
/// Evaluates to the value that was stored (when using type byte/short: evaluates to the truncated value)</summary>
public sealed partial class StObj : ILInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
{
public StObj(ILInstruction target, ILInstruction value, IType type) : base(OpCode.StObj)

8
ICSharpCode.Decompiler/IL/Instructions.tt

@ -150,7 +150,8 @@ @@ -150,7 +150,8 @@
CustomClassName("LdLoc"), NoArguments, HasVariableOperand("Load"), ResultType("variable.StackType")),
new OpCode("ldloca", "Loads the address of a local variable. (ldarga/ldloca)",
CustomClassName("LdLoca"), NoArguments, ResultType("Ref"), HasVariableOperand("Address")),
new OpCode("stloc", "Stores a value into a local variable. (starg/stloc)",
new OpCode("stloc", "Stores a value into a local variable. (IL: starg/stloc)" + Environment.NewLine
+ "Evaluates to the value that was stored (for byte/short variables: evaluates to the truncated value)",
CustomClassName("StLoc"), HasVariableOperand("Store"), CustomArguments("value"),
ResultType("variable.StackType")),
new OpCode("addressof", "Stores the value into an anonymous temporary variable, and returns the address of that variable.",
@ -204,10 +205,11 @@ @@ -204,10 +205,11 @@
new OpCode("ldobj", "Indirect load (ref/pointer dereference).",
CustomClassName("LdObj"), CustomArguments("target"), HasTypeOperand, MemoryAccess, CustomWriteToButKeepOriginal,
SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, ResultType("type.GetStackType()")),
new OpCode("stobj", "Indirect store (store to ref/pointer).",
new OpCode("stobj", "Indirect store (store to ref/pointer)." + Environment.NewLine
+ "Evaluates to the value that was stored (when using type byte/short: evaluates to the truncated value)",
CustomClassName("StObj"), CustomArguments("target", "value"), HasTypeOperand, MemoryAccess, CustomWriteToButKeepOriginal,
SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, ResultType("type.GetStackType()")),
new OpCode("box", "Boxes a value.",
Unary, HasTypeOperand, MemoryAccess, MayThrow, ResultType("O")),
new OpCode("unbox", "Compute address inside box.",

31
ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

@ -41,7 +41,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -41,7 +41,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
block.Instructions.RemoveAt(i);
continue;
}
if (TransformInlineAssignmentStObj(block, i))
if (TransformInlineAssignmentStObj(block, i) || TransformInlineAssignmentLocal(block, i))
continue;
if (TransformInlineCompoundAssignmentCall(block, i))
continue;
@ -59,13 +59,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -59,13 +59,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// -->
/// stloc l(stobj (..., value))
/// </code>
/// e.g. used for inline assignment to instance field
///
/// -or-
///
/// <code>
/// stloc s(value)
/// stobj (..., ldloc s)
/// -->
/// stloc s(stobj (..., value))
/// </code>
/// e.g. used for inline assignment to static field
bool TransformInlineAssignmentStObj(Block block, int i)
{
var inst = block.Instructions[i] as StLoc;
@ -76,27 +80,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -76,27 +80,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms
ILInstruction replacement;
StObj fieldStore;
ILVariable local;
if (nextInst is StLoc) { // instance fields
var localStore = (StLoc)nextInst;
if (localStore.Variable.Kind == VariableKind.StackSlot || !localStore.Value.MatchLdLoc(inst.Variable))
if (nextInst is StLoc localStore) { // with extra local
if (localStore.Variable.Kind != VariableKind.Local || !localStore.Value.MatchLdLoc(inst.Variable))
return false;
if (!(inst.Variable.IsSingleDefinition && inst.Variable.LoadCount == 2))
return false;
var memberStore = block.Instructions.ElementAtOrDefault(i + 2);
if (memberStore is StObj) {
fieldStore = memberStore as StObj;
if (!fieldStore.Value.MatchLdLoc(inst.Variable))
if (!fieldStore.Value.MatchLdLoc(inst.Variable) || localStore.Variable.IsUsedWithin(fieldStore.Target))
return false;
replacement = new StObj(fieldStore.Target, inst.Value, fieldStore.Type);
} else { // otherwise it must be local
return TransformInlineAssignmentLocal(block, i);
} else {
return false;
}
context.Step("Inline assignment to instance field", fieldStore);
context.Step("Inline assignment stobj (with extra local)", fieldStore);
local = localStore.Variable;
block.Instructions.RemoveAt(i + 1);
} else if (nextInst is StObj) { // static fields
} else if (nextInst is StObj) { // without extra local
fieldStore = (StObj)nextInst;
if (!fieldStore.Value.MatchLdLoc(inst.Variable) || (fieldStore.Target.MatchLdFlda(out var target, out _) && target.MatchLdLoc(inst.Variable)))
if (!fieldStore.Value.MatchLdLoc(inst.Variable) || inst.Variable.IsUsedWithin(fieldStore.Target))
return false;
context.Step("Inline assignment to static field", fieldStore);
context.Step("Inline assignment stobj", fieldStore);
local = inst.Variable;
replacement = new StObj(fieldStore.Target, inst.Value, fieldStore.Type);
} else {
@ -246,7 +251,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -246,7 +251,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var nextInst = block.Instructions.ElementAtOrDefault(i + 1) as StLoc;
if (inst == null || nextInst == null)
return false;
if (nextInst.Variable.Kind == VariableKind.StackSlot || !nextInst.Value.MatchLdLoc(inst.Variable))
if (inst.Variable.Kind != VariableKind.StackSlot)
return false;
if (nextInst.Variable.Kind != VariableKind.Local || !nextInst.Value.MatchLdLoc(inst.Variable))
return false;
context.Step("Inline assignment to local variable", inst);
var value = inst.Value;

Loading…
Cancel
Save