From d40ecb5e0ca4ff81ddb4c72dea9a8a2be098bdbe Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Fri, 29 Sep 2017 02:25:53 +0200 Subject: [PATCH] [switch] Add StringToInt instruction --- .../ICSharpCode.Decompiler.csproj | 2 + ICSharpCode.Decompiler/IL/Instructions.cs | 96 +++++++++++++++++++ ICSharpCode.Decompiler/IL/Instructions.tt | 2 + .../IL/Instructions/LockInstruction.cs | 32 ------- .../IL/Instructions/StringToInt.cs | 45 +++++++++ .../IL/Instructions/UsingInstruction.cs | 53 ++++++++++ 6 files changed, 198 insertions(+), 32 deletions(-) create mode 100644 ICSharpCode.Decompiler/IL/Instructions/StringToInt.cs create mode 100644 ICSharpCode.Decompiler/IL/Instructions/UsingInstruction.cs diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 387d453b5..dd2bd4a91 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -271,6 +271,8 @@ + + diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs index 015b312b7..c6f361279 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.cs +++ b/ICSharpCode.Decompiler/IL/Instructions.cs @@ -158,6 +158,8 @@ namespace ICSharpCode.Decompiler.IL /// 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. ArrayToPointer, + /// Maps a string value to an integer. This is used in switch(string). + StringToInt, /// Push a typed reference of type class onto the stack. MakeRefAny, /// Push the type token stored in a typed reference. @@ -4021,6 +4023,87 @@ namespace ICSharpCode.Decompiler.IL } } namespace ICSharpCode.Decompiler.IL +{ + /// Maps a string value to an integer. This is used in switch(string). + public sealed partial class StringToInt : ILInstruction + { + 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.argument, value, 0); + } + } + protected sealed override int GetChildCount() + { + return 1; + } + protected sealed override ILInstruction GetChild(int index) + { + switch (index) { + case 0: + return this.argument; + default: + throw new IndexOutOfRangeException(); + } + } + protected sealed override void SetChild(int index, ILInstruction value) + { + switch (index) { + case 0: + this.Argument = value; + break; + default: + throw new IndexOutOfRangeException(); + } + } + protected sealed override SlotInfo GetChildSlot(int index) + { + switch (index) { + case 0: + return ArgumentSlot; + default: + throw new IndexOutOfRangeException(); + } + } + public sealed override ILInstruction Clone() + { + var clone = (StringToInt)ShallowClone(); + clone.Argument = this.argument.Clone(); + return clone; + } + public override StackType ResultType { get { return StackType.I4; } } + protected override InstructionFlags ComputeFlags() + { + return argument.Flags; + } + public override InstructionFlags DirectFlags { + get { + return InstructionFlags.None; + } + } + public override void AcceptVisitor(ILVisitor visitor) + { + visitor.VisitStringToInt(this); + } + public override T AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitStringToInt(this); + } + public override T AcceptVisitor(ILVisitor visitor, C context) + { + return visitor.VisitStringToInt(this, context); + } + protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) + { + var o = other as StringToInt; + return o != null && this.argument.PerformMatch(o.argument, ref match); + } + } +} +namespace ICSharpCode.Decompiler.IL { /// Push a typed reference of type class onto the stack. public sealed partial class MakeRefAny : UnaryInstruction @@ -4633,6 +4716,10 @@ namespace ICSharpCode.Decompiler.IL { Default(inst); } + protected internal virtual void VisitStringToInt(StringToInt inst) + { + Default(inst); + } protected internal virtual void VisitMakeRefAny(MakeRefAny inst) { Default(inst); @@ -4919,6 +5006,10 @@ namespace ICSharpCode.Decompiler.IL { return Default(inst); } + protected internal virtual T VisitStringToInt(StringToInt inst) + { + return Default(inst); + } protected internal virtual T VisitMakeRefAny(MakeRefAny inst) { return Default(inst); @@ -5205,6 +5296,10 @@ namespace ICSharpCode.Decompiler.IL { return Default(inst, context); } + protected internal virtual T VisitStringToInt(StringToInt inst, C context) + { + return Default(inst, context); + } protected internal virtual T VisitMakeRefAny(MakeRefAny inst, C context) { return Default(inst, context); @@ -5294,6 +5389,7 @@ namespace ICSharpCode.Decompiler.IL "ldlen", "ldelema", "array.to.pointer", + "string.to.int", "mkrefany", "refanytype", "refanyval", diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt index 2b28a9efe..f25e3fa0d 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.tt +++ b/ICSharpCode.Decompiler/IL/Instructions.tt @@ -220,6 +220,8 @@ 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"), ResultType("Ref")), + new OpCode("string.to.int", "Maps a string value to an integer. This is used in switch(string).", + CustomArguments("argument"), CustomConstructor, CustomWriteTo, ResultType("I4")), new OpCode("mkrefany", "Push a typed reference of type class onto the stack.", CustomClassName("MakeRefAny"), Unary, HasTypeOperand, ResultType("O")), diff --git a/ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs index f0c1b1ebc..36cd8380e 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs @@ -38,36 +38,4 @@ namespace ICSharpCode.Decompiler.IL output.Write("}"); } } - - /// - /// IL using instruction. - /// Equivalent to: - /// - /// stloc v(resourceExpression) - /// try { - /// body - /// } finally { - /// v?.Dispose(); - /// } - /// - /// - /// - /// The value of v is undefined after the end of the body block. - /// - partial class UsingInstruction - { - public override void WriteTo(ITextOutput output, ILAstWritingOptions options) - { - output.Write("using ("); - Variable.WriteTo(output); - output.Write(" = "); - ResourceExpression.WriteTo(output, options); - output.WriteLine(") {"); - output.Indent(); - Body.WriteTo(output, options); - output.Unindent(); - output.WriteLine(); - output.Write("}"); - } - } } diff --git a/ICSharpCode.Decompiler/IL/Instructions/StringToInt.cs b/ICSharpCode.Decompiler/IL/Instructions/StringToInt.cs new file mode 100644 index 000000000..f804a3928 --- /dev/null +++ b/ICSharpCode.Decompiler/IL/Instructions/StringToInt.cs @@ -0,0 +1,45 @@ +// Copyright (c) 2017 Siegfried Pammer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + + +namespace ICSharpCode.Decompiler.IL +{ + partial class StringToInt + { + public string[] Map { get; } + + public StringToInt(ILInstruction argument, string[] map) + : base(OpCode.StringToInt) + { + this.Argument = argument; + this.Map = map; + } + + public override void WriteTo(ITextOutput output, ILAstWritingOptions options) + { + output.Write("string.to.int ("); + Argument.WriteTo(output, options); + output.Write(", { "); + for (int i = 0; i < Map.Length; i++) { + if (i > 0) output.Write(", "); + output.Write($"[{i}] = \"{Map[i]}\""); + } + output.Write(" })"); + } + } +} diff --git a/ICSharpCode.Decompiler/IL/Instructions/UsingInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/UsingInstruction.cs new file mode 100644 index 000000000..795be5914 --- /dev/null +++ b/ICSharpCode.Decompiler/IL/Instructions/UsingInstruction.cs @@ -0,0 +1,53 @@ +// Copyright (c) 2017 Siegfried Pammer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + + +namespace ICSharpCode.Decompiler.IL +{ + /// + /// IL using instruction. + /// Equivalent to: + /// + /// stloc v(resourceExpression) + /// try { + /// body + /// } finally { + /// v?.Dispose(); + /// } + /// + /// + /// + /// The value of v is undefined after the end of the body block. + /// + partial class UsingInstruction + { + public override void WriteTo(ITextOutput output, ILAstWritingOptions options) + { + output.Write("using ("); + Variable.WriteTo(output); + output.Write(" = "); + ResourceExpression.WriteTo(output, options); + output.WriteLine(") {"); + output.Indent(); + Body.WriteTo(output, options); + output.Unindent(); + output.WriteLine(); + output.Write("}"); + } + } +}