Browse Source

#1852: Rename array.to.pointer opcode to get.pinnable.reference.

pull/1857/head
Daniel Grunwald 6 years ago
parent
commit
eb2a9e6b94
  1. 17
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs
  2. 9
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  3. 14
      ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs
  4. 82
      ICSharpCode.Decompiler/IL/Instructions.cs
  5. 8
      ICSharpCode.Decompiler/IL/Instructions.tt
  6. 2
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

17
ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs

@ -65,6 +65,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -65,6 +65,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
#if CS73
public class CustomPinnable
{
public ref int GetPinnableReference()
{
throw new NotImplementedException();
}
}
#endif
public unsafe delegate void UnsafeDelegate(byte* ptr);
private UnsafeDelegate unsafeDelegate;
@ -361,6 +371,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -361,6 +371,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
UsePointer(ptr);
}
}
public unsafe void CustomPinReferenceType(CustomPinnable mem)
{
fixed (int* ptr = mem) {
UsePointer(ptr);
}
}
#endif
public unsafe string StackAlloc(int count)

9
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -819,8 +819,13 @@ namespace ICSharpCode.Decompiler.CSharp @@ -819,8 +819,13 @@ namespace ICSharpCode.Decompiler.CSharp
var fixedStmt = new FixedStatement();
fixedStmt.Type = exprBuilder.ConvertType(inst.Variable.Type);
Expression initExpr;
if (inst.Init.OpCode == OpCode.ArrayToPointer) {
initExpr = exprBuilder.Translate(((ArrayToPointer)inst.Init).Array);
if (inst.Init is GetPinnableReference gpr) {
if (gpr.Method != null) {
IType expectedType = gpr.Method.IsStatic ? gpr.Method.Parameters[0].Type : gpr.Method.DeclaringType;
initExpr = exprBuilder.Translate(gpr.Argument, typeHint: expectedType).ConvertTo(expectedType, exprBuilder);
} else {
initExpr = exprBuilder.Translate(gpr.Argument);
}
} else {
initExpr = exprBuilder.Translate(inst.Init, typeHint: inst.Variable.Type).ConvertTo(inst.Variable.Type, exprBuilder);
}

14
ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs

@ -139,11 +139,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -139,11 +139,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
bool modified = false;
for (int i = 0; i < container.Blocks.Count; i++) {
var block = container.Blocks[i];
ILVariable v, p;
Block targetBlock;
if (IsNullSafeArrayToPointerPattern(block, out v, out p, out targetBlock)) {
if (IsNullSafeArrayToPointerPattern(block, out ILVariable v, out ILVariable p, out Block targetBlock)) {
context.Step("NullSafeArrayToPointerPattern", block);
ILInstruction arrayToPointer = new ArrayToPointer(new LdLoc(v));
ILInstruction arrayToPointer = new GetPinnableReference(new LdLoc(v), null);
if (p.StackType != StackType.Ref) {
arrayToPointer = new Conv(arrayToPointer, p.StackType.ToPrimitiveType(), false, Sign.None);
}
@ -432,7 +430,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -432,7 +430,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
return; // variable access that is not LdLoc
}
}
if (!(ldloc.Parent is ArrayToPointer arrayToPointer))
if (!(ldloc.Parent is GetPinnableReference arrayToPointer))
return;
if (!(arrayToPointer.Parent is Conv conv && conv.Kind == ConversionKind.StopGCTracking))
return;
@ -446,7 +444,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -446,7 +444,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
newVar.HasGeneratedName = oldVar.HasGeneratedName;
oldVar.Function.Variables.Add(newVar);
pinnedRegion.Variable = newVar;
pinnedRegion.Init = new ArrayToPointer(pinnedRegion.Init).WithILRange(arrayToPointer);
pinnedRegion.Init = new GetPinnableReference(pinnedRegion.Init, arrayToPointer.Method).WithILRange(arrayToPointer);
conv.ReplaceWith(new LdLoc(newVar).WithILRange(conv));
}
@ -514,7 +512,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -514,7 +512,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
newVar.HasGeneratedName = pinnedRegion.Variable.HasGeneratedName;
pinnedRegion.Variable.Function.Variables.Add(newVar);
pinnedRegion.Variable = newVar;
pinnedRegion.Init = new ArrayToPointer(pinnedRegion.Init);
pinnedRegion.Init = new GetPinnableReference(pinnedRegion.Init, null);
}
return;
}
@ -542,7 +540,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -542,7 +540,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// make targetBlock the new entry point
body.Blocks.RemoveAt(targetBlock.ChildIndex);
body.Blocks.Insert(0, targetBlock);
pinnedRegion.Init = new ArrayToPointer(pinnedRegion.Init);
pinnedRegion.Init = new GetPinnableReference(pinnedRegion.Init, null);
ILVariable otherVar;
ILInstruction otherVarInit;

82
ICSharpCode.Decompiler/IL/Instructions.cs

@ -184,9 +184,12 @@ namespace ICSharpCode.Decompiler.IL @@ -184,9 +184,12 @@ namespace ICSharpCode.Decompiler.IL
LdLen,
/// <summary>Load address of array element.</summary>
LdElema,
/// <summary>Converts an array pointer (O) to a reference to the first element, or to a null reference if the array is null or empty.
/// Also used to convert a string to a reference to the first character.</summary>
ArrayToPointer,
/// <summary>Retrieves a pinnable reference for the input object.
/// The input must be an object reference (O).
/// If the input is an array/string, evaluates to a reference to the first element/character, or to a null reference if the array is null or empty.
/// Otherwise, uses the GetPinnableReference method to get the reference, or evaluates to a null reference if the input is null.
/// </summary>
GetPinnableReference,
/// <summary>Maps a string value to an integer. This is used in switch(string).</summary>
StringToInt,
/// <summary>ILAst representation of Expression.Convert.</summary>
@ -4756,21 +4759,25 @@ namespace ICSharpCode.Decompiler.IL @@ -4756,21 +4759,25 @@ namespace ICSharpCode.Decompiler.IL
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Converts an array pointer (O) to a reference to the first element, or to a null reference if the array is null or empty.
/// Also used to convert a string to a reference to the first character.</summary>
public sealed partial class ArrayToPointer : ILInstruction
/// <summary>Retrieves a pinnable reference for the input object.
/// The input must be an object reference (O).
/// If the input is an array/string, evaluates to a reference to the first element/character, or to a null reference if the array is null or empty.
/// Otherwise, uses the GetPinnableReference method to get the reference, or evaluates to a null reference if the input is null.
/// </summary>
public sealed partial class GetPinnableReference : ILInstruction, IInstructionWithMethodOperand
{
public ArrayToPointer(ILInstruction array) : base(OpCode.ArrayToPointer)
public GetPinnableReference(ILInstruction argument, IMethod method) : base(OpCode.GetPinnableReference)
{
this.Array = array;
this.Argument = argument;
this.method = method;
}
public static readonly SlotInfo ArraySlot = new SlotInfo("Array", canInlineInto: true);
ILInstruction array;
public ILInstruction Array {
get { return this.array; }
public static readonly SlotInfo ArgumentSlot = new SlotInfo("Argument", canInlineInto: true);
ILInstruction argument;
public ILInstruction Argument {
get { return this.argument; }
set {
ValidateChild(value);
SetChildInstruction(ref this.array, value, 0);
SetChildInstruction(ref this.argument, value, 0);
}
}
protected sealed override int GetChildCount()
@ -4781,7 +4788,7 @@ namespace ICSharpCode.Decompiler.IL @@ -4781,7 +4788,7 @@ namespace ICSharpCode.Decompiler.IL
{
switch (index) {
case 0:
return this.array;
return this.argument;
default:
throw new IndexOutOfRangeException();
}
@ -4790,7 +4797,7 @@ namespace ICSharpCode.Decompiler.IL @@ -4790,7 +4797,7 @@ namespace ICSharpCode.Decompiler.IL
{
switch (index) {
case 0:
this.Array = value;
this.Argument = value;
break;
default:
throw new IndexOutOfRangeException();
@ -4800,21 +4807,24 @@ namespace ICSharpCode.Decompiler.IL @@ -4800,21 +4807,24 @@ namespace ICSharpCode.Decompiler.IL
{
switch (index) {
case 0:
return ArraySlot;
return ArgumentSlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (ArrayToPointer)ShallowClone();
clone.Array = this.array.Clone();
var clone = (GetPinnableReference)ShallowClone();
clone.Argument = this.argument.Clone();
return clone;
}
public override StackType ResultType { get { return StackType.Ref; } }
readonly IMethod method;
/// <summary>Returns the method operand.</summary>
public IMethod Method { get { return method; } }
protected override InstructionFlags ComputeFlags()
{
return array.Flags;
return argument.Flags;
}
public override InstructionFlags DirectFlags {
get {
@ -4825,31 +4835,33 @@ namespace ICSharpCode.Decompiler.IL @@ -4825,31 +4835,33 @@ namespace ICSharpCode.Decompiler.IL
{
WriteILRange(output, options);
output.Write(OpCode);
output.Write(' ');
method.WriteTo(output);
output.Write('(');
this.array.WriteTo(output, options);
this.argument.WriteTo(output, options);
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitArrayToPointer(this);
visitor.VisitGetPinnableReference(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitArrayToPointer(this);
return visitor.VisitGetPinnableReference(this);
}
public override T AcceptVisitor<C, T>(ILVisitor<C, T> visitor, C context)
{
return visitor.VisitArrayToPointer(this, context);
return visitor.VisitGetPinnableReference(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as ArrayToPointer;
return o != null && this.array.PerformMatch(o.array, ref match);
var o = other as GetPinnableReference;
return o != null && this.argument.PerformMatch(o.argument, ref match) && method.Equals(o.method);
}
internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
Debug.Assert(array.ResultType == StackType.O);
Debug.Assert(argument.ResultType == StackType.O);
}
}
}
@ -6717,7 +6729,7 @@ namespace ICSharpCode.Decompiler.IL @@ -6717,7 +6729,7 @@ namespace ICSharpCode.Decompiler.IL
{
Default(inst);
}
protected internal virtual void VisitArrayToPointer(ArrayToPointer inst)
protected internal virtual void VisitGetPinnableReference(GetPinnableReference inst)
{
Default(inst);
}
@ -7103,7 +7115,7 @@ namespace ICSharpCode.Decompiler.IL @@ -7103,7 +7115,7 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst);
}
protected internal virtual T VisitArrayToPointer(ArrayToPointer inst)
protected internal virtual T VisitGetPinnableReference(GetPinnableReference inst)
{
return Default(inst);
}
@ -7489,7 +7501,7 @@ namespace ICSharpCode.Decompiler.IL @@ -7489,7 +7501,7 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst, context);
}
protected internal virtual T VisitArrayToPointer(ArrayToPointer inst, C context)
protected internal virtual T VisitGetPinnableReference(GetPinnableReference inst, C context)
{
return Default(inst, context);
}
@ -7651,7 +7663,7 @@ namespace ICSharpCode.Decompiler.IL @@ -7651,7 +7663,7 @@ namespace ICSharpCode.Decompiler.IL
"sizeof",
"ldlen",
"ldelema",
"array.to.pointer",
"get.pinnable.reference",
"string.to.int",
"expression.tree.cast",
"user.logic.operator",
@ -8202,14 +8214,16 @@ namespace ICSharpCode.Decompiler.IL @@ -8202,14 +8214,16 @@ namespace ICSharpCode.Decompiler.IL
array = default(ILInstruction);
return false;
}
public bool MatchArrayToPointer(out ILInstruction array)
public bool MatchGetPinnableReference(out ILInstruction argument, out IMethod method)
{
var inst = this as ArrayToPointer;
var inst = this as GetPinnableReference;
if (inst != null) {
array = inst.Array;
argument = inst.Argument;
method = inst.Method;
return true;
}
array = default(ILInstruction);
argument = default(ILInstruction);
method = default(IMethod);
return false;
}
public bool MatchUserDefinedLogicOperator(out IMethod method, out ILInstruction left, out ILInstruction right)

8
ICSharpCode.Decompiler/IL/Instructions.tt

@ -279,9 +279,11 @@ @@ -279,9 +279,11 @@
new OpCode("ldelema", "Load address of array element.",
CustomClassName("LdElema"), HasTypeOperand, CustomChildren(new [] { new ArgumentInfo("array"), new ArgumentInfo("indices") { IsCollection = true } }, true),
MayThrowIfNotDelayed, ResultType("Ref"), SupportsReadonlyPrefix),
new OpCode("array.to.pointer", "Converts an array pointer (O) to a reference to the first element, or to a null reference if the array is null or empty." + Environment.NewLine
+ "Also used to convert a string to a reference to the first character.",
CustomArguments(("array", new[] { "O" })), ResultType("Ref")),
new OpCode("get.pinnable.reference", "Retrieves a pinnable reference for the input object." + Environment.NewLine
+ "The input must be an object reference (O)." + Environment.NewLine
+ "If the input is an array/string, evaluates to a reference to the first element/character, or to a null reference if the array is null or empty." + Environment.NewLine
+ "Otherwise, uses the GetPinnableReference method to get the reference, or evaluates to a null reference if the input is null." + Environment.NewLine,
CustomArguments(("argument", new[] { "O" })), ResultType("Ref"), HasMethodOperand),
new OpCode("string.to.int", "Maps a string value to an integer. This is used in switch(string).",
CustomArguments(("argument", new[] { "O" })), CustomConstructor, CustomWriteTo, ResultType("I4")),

2
ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

@ -459,7 +459,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -459,7 +459,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
break;
case OpCode.DynamicCompoundAssign:
return true;
case OpCode.ArrayToPointer:
case OpCode.GetPinnableReference:
case OpCode.LocAllocSpan:
return true; // inline size-expressions into localloc.span
case OpCode.Call:

Loading…
Cancel
Save