Browse Source

Add a bunch of instructions.

pull/728/head
Daniel Grunwald 11 years ago
parent
commit
91f875169c
  1. 2
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  2. 8
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  3. 57
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  4. 3
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  5. 49
      ICSharpCode.Decompiler/IL/ILReader.cs
  6. 4
      ICSharpCode.Decompiler/IL/ILVariable.cs
  7. 1113
      ICSharpCode.Decompiler/IL/Instructions.cs
  8. 291
      ICSharpCode.Decompiler/IL/Instructions.tt
  9. 16
      ICSharpCode.Decompiler/IL/Instructions/ArrayInstructions.cs
  10. 94
      ICSharpCode.Decompiler/IL/Instructions/BinaryInstruction.cs
  11. 28
      ICSharpCode.Decompiler/IL/Instructions/BoxInstructions.cs
  12. 108
      ICSharpCode.Decompiler/IL/Instructions/FieldAccess.cs
  13. 14
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  14. 57
      ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs
  15. 253
      ICSharpCode.Decompiler/IL/Instructions/OpCode.cs
  16. 26
      ICSharpCode.Decompiler/IL/Instructions/Return.cs
  17. 113
      ICSharpCode.Decompiler/IL/Instructions/TryCatch.cs
  18. 80
      ICSharpCode.Decompiler/IL/Instructions/TryFinally.cs
  19. 49
      ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs
  20. 53
      ICSharpCode.Decompiler/IL/Instructions/VarInstructions.cs
  21. 11
      NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/TryCatchStatement.cs
  22. 10
      NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs

2
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -103,7 +103,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -103,7 +103,7 @@ namespace ICSharpCode.Decompiler.CSharp
if (methodDefinition.HasBody) {
var ilReader = new ILReader(methodDefinition.Body, CancellationToken);
var inst = ilReader.CreateBlocks(true);
var body = statementBuilder.ConvertBlockContainer(inst);
var body = statementBuilder.ConvertAsBlock(inst);
body.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true });
entityDecl.AddChild(body, Roles.Body);
}

8
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using Mono.Cecil;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.TypeSystem;
@ -58,6 +59,13 @@ namespace ICSharpCode.Decompiler.CSharp @@ -58,6 +59,13 @@ namespace ICSharpCode.Decompiler.CSharp
return expr;
}
public AstType ConvertType(TypeReference type)
{
if (type == null)
return null;
return new SimpleType(type.Name);
}
ConvertedExpression ConvertArgument(ILInstruction inst)
{
var cexpr = inst.AcceptVisitor(this);

57
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -41,6 +41,12 @@ namespace ICSharpCode.Decompiler.CSharp @@ -41,6 +41,12 @@ namespace ICSharpCode.Decompiler.CSharp
return inst.AcceptVisitor(this);
}
public BlockStatement ConvertAsBlock(ILInstruction inst)
{
Statement stmt = Convert(inst);
return stmt as BlockStatement ?? new BlockStatement { stmt };
}
protected override Statement Default(ILInstruction inst)
{
return new ExpressionStatement(exprBuilder.Convert(inst));
@ -66,17 +72,58 @@ namespace ICSharpCode.Decompiler.CSharp @@ -66,17 +72,58 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override Statement VisitReturn(Return inst)
{
if (inst.Argument == null)
if (inst.ReturnValue == null)
return new ReturnStatement();
return new ReturnStatement(exprBuilder.Convert(inst.Argument));
return new ReturnStatement(exprBuilder.Convert(inst.ReturnValue));
}
protected internal override Statement VisitBlockContainer(BlockContainer inst)
TryCatchStatement MakeTryCatch(ILInstruction tryBlock)
{
var tryBlockConverted = Convert(tryBlock);
var tryCatch = tryBlockConverted as TryCatchStatement;
if (tryCatch != null && tryCatch.FinallyBlock.IsNull)
return tryCatch; // extend existing try-catch
tryCatch = new TryCatchStatement();
tryCatch.TryBlock = tryBlockConverted as BlockStatement ?? new BlockStatement { tryBlockConverted };
return tryCatch;
}
protected internal override Statement VisitTryCatch(TryCatch inst)
{
var tryCatch = new TryCatchStatement();
tryCatch.TryBlock = ConvertAsBlock(inst.TryBlock);
foreach (var handler in inst.CatchHandlers) {
var catchClause = new CatchClause();
if (handler.Variable != null) {
catchClause.Type = exprBuilder.ConvertType(handler.Variable.Type);
catchClause.VariableName = handler.Variable.Name;
}
catchClause.Condition = exprBuilder.ConvertCondition(handler.Filter);
catchClause.Body = ConvertAsBlock(handler.Body);
tryCatch.CatchClauses.Add(catchClause);
}
return tryCatch;
}
protected internal override Statement VisitTryFinally(TryFinally inst)
{
var tryCatch = MakeTryCatch(inst.TryBlock);
tryCatch.FinallyBlock = ConvertAsBlock(inst.FinallyBlock);
return tryCatch;
}
protected internal override Statement VisitTryFault(TryFault inst)
{
return ConvertBlockContainer(inst);
var tryCatch = new TryCatchStatement();
tryCatch.TryBlock = ConvertAsBlock(inst.TryBlock);
var faultBlock = ConvertAsBlock(inst.FaultBlock);
faultBlock.InsertChildAfter(null, new Comment("try-fault"), Roles.Comment);
faultBlock.Add(new ThrowStatement());
tryCatch.CatchClauses.Add(new CatchClause { Body = faultBlock });
return tryCatch;
}
public BlockStatement ConvertBlockContainer(BlockContainer container)
protected internal override Statement VisitBlockContainer(BlockContainer container)
{
BlockStatement blockStatement = new BlockStatement();
foreach (var block in container.Blocks) {

3
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -72,7 +72,6 @@ @@ -72,7 +72,6 @@
<DependentUpon>Instructions.tt</DependentUpon>
</Compile>
<Compile Include="IL\Instructions\BinaryComparisonInstruction.cs" />
<Compile Include="IL\Instructions\BinaryInstruction.cs" />
<Compile Include="IL\Instructions\BinaryNumericInstruction.cs" />
<Compile Include="IL\Instructions\Block.cs" />
<Compile Include="IL\Instructions\BlockContainer.cs" />
@ -85,6 +84,8 @@ @@ -85,6 +84,8 @@
<Compile Include="IL\Instructions\MemoryInstructions.cs" />
<Compile Include="IL\Instructions\Return.cs" />
<Compile Include="IL\Instructions\SimpleInstruction.cs" />
<Compile Include="IL\Instructions\TryCatch.cs" />
<Compile Include="IL\Instructions\TryFinally.cs" />
<Compile Include="IL\Instructions\UnaryInstruction.cs" />
<Compile Include="IL\Visitors\CountPopInstructionsVisitor.cs" />
<Compile Include="TypesHierarchyHelpers.cs" />

49
ICSharpCode.Decompiler/IL/ILReader.cs

@ -204,7 +204,7 @@ namespace ICSharpCode.Decompiler.IL @@ -204,7 +204,7 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Constrained:
return DecodeConstrainedCall();
case ILOpCode.Readonly:
throw new NotImplementedException(); // needs ldelema
return DecodeReadonly();
case ILOpCode.Tailcall:
return DecodeTailCall();
case ILOpCode.Unaligned:
@ -368,9 +368,8 @@ namespace ICSharpCode.Decompiler.IL @@ -368,9 +368,8 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Dup:
return new Peek(stack.Count > 0 ? stack.Peek() : StackType.Unknown);
case ILOpCode.Endfilter:
throw new NotImplementedException();
case ILOpCode.Endfinally:
throw new NotImplementedException();
return new EndFinally();
case ILOpCode.Initblk:
throw new NotImplementedException();
case ILOpCode.Jmp:
@ -414,7 +413,7 @@ namespace ICSharpCode.Decompiler.IL @@ -414,7 +413,7 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Ldstr:
return DecodeLdstr();
case ILOpCode.Ldftn:
throw new NotImplementedException();
return new LdFtn((MethodReference)ReadAndDecodeMetadataToken());
case ILOpCode.Ldind_I1:
return new LdObj(Pop(), typeSystem.SByte);
case ILOpCode.Ldind_I2:
@ -455,7 +454,7 @@ namespace ICSharpCode.Decompiler.IL @@ -455,7 +454,7 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Leave_S:
return DecodeUnconditionalBranch(true, isLeave: true);
case ILOpCode.Localloc:
throw new NotImplementedException();
return new LocAlloc(Pop());
case ILOpCode.Mul:
return BinaryNumeric(OpCode.Mul, OverflowMode.None);
case ILOpCode.Mul_Ovf:
@ -519,13 +518,17 @@ namespace ICSharpCode.Decompiler.IL @@ -519,13 +518,17 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Xor:
return BinaryNumeric(OpCode.BitXor);
case ILOpCode.Box:
throw new NotImplementedException();
return new Box(Pop(), (TypeReference)ReadAndDecodeMetadataToken());
case ILOpCode.Castclass:
throw new NotImplementedException();
return new CastClass(Pop(), (TypeReference)ReadAndDecodeMetadataToken());
case ILOpCode.Cpobj:
throw new NotImplementedException();
{
var type = (TypeReference)ReadAndDecodeMetadataToken();
var ld = new LdObj(Pop(), type);
return new StObj(Pop(), ld, type);
}
case ILOpCode.Initobj:
throw new NotImplementedException();
return new InitObj(Pop(), (TypeReference)ReadAndDecodeMetadataToken());
case ILOpCode.Isinst:
return new IsInst(Pop(), (TypeReference)ReadAndDecodeMetadataToken());
case ILOpCode.Ldelem:
@ -542,14 +545,13 @@ namespace ICSharpCode.Decompiler.IL @@ -542,14 +545,13 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Ldelem_Ref:
throw new NotImplementedException();
case ILOpCode.Ldelema:
throw new NotImplementedException();
return new LdElema(index: Pop(), array: Pop(), type: (TypeReference)ReadAndDecodeMetadataToken());
case ILOpCode.Ldfld:
return new LdFld(Pop(), (FieldReference)ReadAndDecodeMetadataToken());
case ILOpCode.Ldflda:
return new LdFlda(Pop(), (FieldReference)ReadAndDecodeMetadataToken());
case ILOpCode.Stfld:
throw new NotImplementedException();
//\return new Stfld(Pop(), Pop(), (FieldReference)ReadAndDecodeMetadataToken());
return new StFld(value: Pop(), target: Pop(), field: (FieldReference)ReadAndDecodeMetadataToken());
case ILOpCode.Ldlen:
return new LdLen(Pop());
case ILOpCode.Ldobj:
@ -561,9 +563,9 @@ namespace ICSharpCode.Decompiler.IL @@ -561,9 +563,9 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Stsfld:
return new StsFld(Pop(), (FieldReference)ReadAndDecodeMetadataToken());
case ILOpCode.Ldtoken:
throw new NotImplementedException();
return new LdToken((MemberReference)ReadAndDecodeMetadataToken());
case ILOpCode.Ldvirtftn:
throw new NotImplementedException();
return new LdVirtFtn(Pop(), (MethodReference)ReadAndDecodeMetadataToken());
case ILOpCode.Mkrefany:
throw new NotImplementedException();
case ILOpCode.Newarr:
@ -573,9 +575,9 @@ namespace ICSharpCode.Decompiler.IL @@ -573,9 +575,9 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Refanyval:
throw new NotImplementedException();
case ILOpCode.Rethrow:
throw new NotImplementedException();
return new Rethrow();
case ILOpCode.Sizeof:
throw new NotImplementedException();
return new SizeOf((TypeReference)ReadAndDecodeMetadataToken());
case ILOpCode.Stelem:
case ILOpCode.Stelem_I1:
case ILOpCode.Stelem_I2:
@ -587,11 +589,11 @@ namespace ICSharpCode.Decompiler.IL @@ -587,11 +589,11 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Stelem_Ref:
throw new NotImplementedException();
case ILOpCode.Stobj:
throw new NotImplementedException();
return new StObj(value: Pop(), target: Pop(), type: (TypeReference)ReadAndDecodeMetadataToken());
case ILOpCode.Throw:
return new Throw(Pop());
case ILOpCode.Unbox:
throw new NotImplementedException();
return new Unbox(Pop(), (TypeReference)ReadAndDecodeMetadataToken());
case ILOpCode.Unbox_Any:
return new UnboxAny(Pop(), (TypeReference)ReadAndDecodeMetadataToken());
default:
@ -695,6 +697,17 @@ namespace ICSharpCode.Decompiler.IL @@ -695,6 +697,17 @@ namespace ICSharpCode.Decompiler.IL
Warn("Ignored invalid 'volatile' prefix");
return inst;
}
private ILInstruction DecodeReadonly()
{
var inst = DecodeInstruction();
var ldelema = inst as LdElema;
if (ldelema != null)
ldelema.IsReadOnly = true;
else
Warn("Ignored invalid 'readonly' prefix");
return inst;
}
ILInstruction DecodeCall(OpCode opCode)
{

4
ICSharpCode.Decompiler/IL/ILVariable.cs

@ -60,6 +60,10 @@ namespace ICSharpCode.Decompiler.IL @@ -60,6 +60,10 @@ namespace ICSharpCode.Decompiler.IL
{
this.CecilObject = p;
}
public string Name {
get { return ToString(); }
}
public override string ToString()
{

1113
ICSharpCode.Decompiler/IL/Instructions.cs

File diff suppressed because it is too large Load Diff

291
ICSharpCode.Decompiler/IL/Instructions.tt

@ -23,6 +23,13 @@ @@ -23,6 +23,13 @@
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
OpCode[] baseClasses = {
new OpCode("UnaryInstruction", "Instruction with a single argument",
AbstractBaseClass, CustomArguments("argument")),
new OpCode("BinaryInstruction", "Instruction with two arguments: Left and Right",
AbstractBaseClass, CustomArguments("left", "right")),
};
OpCode[] opCodes = {
new OpCode("nop", "No operation. Takes 0 arguments and returns void.",
VoidResult, NoArguments),
@ -32,8 +39,10 @@ @@ -32,8 +39,10 @@
Peeking, NoArguments, ResultTypeParam),
new OpCode("void", "Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack.",
VoidResult, Unary),
new OpCode("BlockContainer", "A container of IL blocks.", VoidResult, CustomConstructor),
new OpCode("Block", "A block of IL instructions.", CustomConstructor),
new OpCode("BlockContainer", "A container of IL blocks.",
VoidResult, CustomConstructor, CustomVariableName("container")),
new OpCode("Block", "A block of IL instructions.",
CustomConstructor, CustomVariableName("block")),
new OpCode("logic.not", "Unary operator that expects an input of type I4. Returns 1 (of type I4) if the input value is 0. Otherwise, returns 0 (of type I4).",
ResultType("I4"), Unary),
new OpCode("add", "Adds two numbers.", BinaryNumeric),
@ -46,12 +55,35 @@ @@ -46,12 +55,35 @@
new OpCode("bit.xor", "Bitwise XOR", BinaryNumeric),
new OpCode("bit.not", "Bitwise NOT", Unary),
new OpCode("arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, ResultType("O")),
//new OpCode("ConditionalBranch", "<c>if (condition) goto target;</c>.",
// BranchInstruction, CustomConstructor, CustomComputeFlags, MayBranch, VoidResult),
new OpCode("br", "Unconditional branch. <c>goto target;</c>",
CustomClassName("Branch"), NoArguments, CustomConstructor, UnconditionalBranch, MayBranch),
// TODO: get rid of endfinally, we can represent those with a normal branch to the end of the filter/finally block instead
new OpCode("endfinally", "Marks the end of an finally, fault or exception filter block.",
CustomClassName("EndFinally"), NoArguments, UnconditionalBranch, MayBranch),
new OpCode("if", "If statement / conditional expression. <c>if (condition) trueExpr else falseExpr</c>",
CustomClassName("IfInstruction"), CustomConstructor),
CustomClassName("IfInstruction"),
CustomChildren(new []{
new ChildInfo("condition") { IsArgument = true },
new ChildInfo("trueInst"),
new ChildInfo("falseInst"),
}), CustomConstructor, CustomComputeFlags, CustomWriteTo),
new OpCode("try.catch", "Try-catch statement",
CustomConstructor, CustomComputeFlags, CustomWriteTo),
new OpCode("try.catch.handler", "Catch handler within a try-catch statement",
CustomChildren(new [] {
new ChildInfo("filter") { IsArgument = true },
new ChildInfo("body"),
}), HasVariableOperand, CustomWriteTo, ResultType("Void")),
new OpCode("try.finally", "Try-finally statement",
CustomChildren(new [] {
new ChildInfo("tryBlock"),
new ChildInfo("finallyBlock"),
}), CustomWriteTo, CustomComputeFlags),
new OpCode("try.fault", "Try-fault statement",
CustomChildren(new [] {
new ChildInfo("tryBlock"),
new ChildInfo("faultBlock"),
}), CustomWriteTo, CustomComputeFlags),
new OpCode("debug.break", "Breakpoint instruction",
NoArguments, VoidResult, SideEffect),
new OpCode("ceq", "Compare equal. Returns 1 (of type I4) if two numbers or object references are equal; 0 otherwise.",
@ -76,7 +108,7 @@ @@ -76,7 +108,7 @@
new OpCode("ldloca", "Loads the address of a local variable. (ldarga/ldloca)",
CustomClassName("LdLoca"), NoArguments, ResultType("Ref"), HasVariableOperand),
new OpCode("stloc", "Stores a value into a local variable. (starg/stloc)",
CustomClassName("StLoc"), Unary, VoidResult, HasVariableOperand),
CustomClassName("StLoc"), CustomArguments("value"), VoidResult, HasVariableOperand),
new OpCode("ldstr", "Loads a constant string.",
CustomClassName("LdStr"), LoadConstant("string"), ResultType("O")),
new OpCode("ldc.i4", "Loads a constant 32-bit integer.",
@ -87,43 +119,75 @@ @@ -87,43 +119,75 @@
LoadConstant("double"), ResultType("F")),
new OpCode("ldnull", "Loads the null reference.",
CustomClassName("LdNull"), NoArguments, ResultType("O")),
new OpCode("ldftn", "Load method pointer",
CustomClassName("LdFtn"), NoArguments, HasMethodOperand, ResultType("I")),
new OpCode("ldvirtftn", "Load method pointer",
CustomClassName("LdVirtFtn"), Unary, HasMethodOperand, MayThrow, ResultType("I")),
new OpCode("ldtoken", "Loads runtime representation of metadata token",
CustomClassName("LdToken"), NoArguments, HasTokenOperand, ResultType("O")),
new OpCode("localloc", "Allocates space in the stack frame",
CustomClassName("LocAlloc"), Unary, ResultType("I"), MayThrow),
new OpCode("ret", "Returns from the current method or lambda.",
CustomClassName("Return"), CustomConstructor, MayBranch, UnconditionalBranch),
new OpCode("shl", "Shift left", BinaryNumeric),
new OpCode("shr", "Shift right", BinaryNumeric),
new OpCode("ldfld", "Load instance field",
CustomClassName("LdFld"), Unary, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow,
CustomClassName("LdFld"), CustomArguments("target"), MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow,
HasFieldOperand, ResultType("field.FieldType.GetStackType()")),
new OpCode("ldflda", "Load address of instance field",
CustomClassName("LdFlda"), Unary, MayThrow, HasFieldOperand, ResultType("Ref")),
CustomClassName("LdFlda"), CustomArguments("target"), MayThrow, HasFieldOperand, ResultType("Ref")),
new OpCode("stfld", "Store value to instance field",
CustomClassName("StFld"), Binary, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, VoidResult, HasFieldOperand),
CustomClassName("StFld"), CustomArguments("target", "value"), MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, VoidResult, HasFieldOperand),
new OpCode("ldsfld", "Load static field",
CustomClassName("LdsFld"), NoArguments, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix,
HasFieldOperand, ResultType("field.FieldType.GetStackType()")),
new OpCode("ldsflda", "Load static field address",
CustomClassName("LdsFlda"), NoArguments, ResultType("Ref"), HasFieldOperand),
new OpCode("stsfld", "Store value to static field",
CustomClassName("StsFld"), Unary, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, VoidResult, HasFieldOperand),
CustomClassName("StsFld"), CustomArguments("value"), MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, VoidResult, HasFieldOperand),
new OpCode("castclass", "Casts an object to a class.",
CustomClassName("CastClass"), Unary, HasTypeOperand, MayThrow, ResultType("type.GetStackType()")),
new OpCode("isinst", "Test if object is instance of class or interface.",
CustomClassName("IsInst"), Unary, HasTypeOperand, ResultType("type.GetStackType()")),
new OpCode("ldobj", "Indirect load (ref/pointer dereference).",
CustomClassName("LdObj"), Unary, HasTypeOperand, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, ResultType("type.GetStackType()")),
CustomClassName("LdObj"), CustomArguments("target"), HasTypeOperand, MemoryAccess,
SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, ResultType("type.GetStackType()")),
new OpCode("stobj", "Indirect store (store to ref/pointer).",
CustomClassName("StObj"), CustomArguments("target", "value"), HasTypeOperand, MemoryAccess,
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.",
Unary, HasTypeOperand, MayThrow, ResultType("Ref")),
new OpCode("unbox.any", "Unbox a value.",
Unary, HasTypeOperand, MemoryAccess, MayThrow, ResultType("type.GetStackType()")),
new OpCode("newobj", "Creates an object instance and calls the constructor.",
CustomClassName("NewObj"), Call, ResultType("O")),
new OpCode("initobj", "Initializes the value at an address.",
CustomClassName("InitObj"), Unary, HasTypeOperand, VoidResult),
new OpCode("default.value", "Returns the default value for a type.",
NoArguments, HasTypeOperand, ResultType("type.GetStackType()")),
new OpCode("throw", "Throws an exception.",
Unary, MayThrow, UnconditionalBranch),
new OpCode("rethrow", "Rethrows the current exception.",
NoArguments, MayThrow, UnconditionalBranch),
new OpCode("sizeof", "Gets the size of a type in bytes.",
CustomClassName("SizeOf"), NoArguments, HasTypeOperand, ResultType("I4")),
new OpCode("ldlen", "Returns the length of an array as 'native unsigned int'.",
CustomClassName("LdLen"), Unary, MayThrow, ResultType("I")),
CustomClassName("LdLen"), CustomArguments("target"), MayThrow, ResultType("I")),
new OpCode("ldelema", "Load address of array element.",
CustomClassName("LdElema"), CustomArguments("array", "index"), HasTypeOperand,
MayThrow, ResultType("Ref"), SupportsReadonlyPrefix),
};
#>
using System;
using System.Collections.Generic;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.IL
@ -139,12 +203,12 @@ namespace ICSharpCode.Decompiler.IL @@ -139,12 +203,12 @@ namespace ICSharpCode.Decompiler.IL
<# } #>
}
<# foreach (OpCode opCode in opCodes) { #>
<# foreach (OpCode opCode in baseClasses.Concat(opCodes)) { #>
/// <summary><#=opCode.Description#></summary>
public sealed partial class <#=opCode.Name#> : <#=string.Join(", ", new[]{opCode.BaseClass}.Concat(opCode.Interfaces))#>
<#=opCode.ClassModifiers#> partial class <#=opCode.Name#> : <#=string.Join(", ", new[]{opCode.BaseClass}.Concat(opCode.Interfaces))#>
{
<# if (opCode.GenerateConstructor) { #>
public <#=opCode.Name#>(<#=string.Join(", ", opCode.ConstructorParameters)#>) : base(<#=string.Join(", ", opCode.BaseConstructorArguments)#>)
<#=opCode.ConstructorModifier#> <#=opCode.Name#>(<#=string.Join(", ", opCode.ConstructorParameters)#>) : base(<#=string.Join(", ", opCode.BaseConstructorArguments)#>)
{<#=Body(opCode.ConstructorBody)#>}
<# } #>
<#=string.Join(Environment.NewLine, opCode.Members.Select(m => "\t\t" + m.Replace("\n", "\n\t\t")))#>
@ -158,10 +222,12 @@ namespace ICSharpCode.Decompiler.IL @@ -158,10 +222,12 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output)
{<#=Body(opCode.WriteToBody)#>}
<# } #>
<# if (opCode.GenerateAcceptVisitor) { #>
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.Visit<#=opCode.Name#>(this);
}
<# } #>
}
<# } #>
@ -175,9 +241,9 @@ namespace ICSharpCode.Decompiler.IL @@ -175,9 +241,9 @@ namespace ICSharpCode.Decompiler.IL
protected abstract T Default(ILInstruction inst);
<# foreach (OpCode opCode in opCodes) { #>
protected internal virtual T Visit<#=opCode.Name#>(<#=opCode.Name#> inst)
protected internal virtual T Visit<#=opCode.Name#>(<#=opCode.Name#> <#=opCode.VariableName#>)
{
return Default(inst);
return Default(<#=opCode.VariableName#>);
}
<# } #>
}
@ -235,34 +301,45 @@ namespace ICSharpCode.Decompiler.IL @@ -235,34 +301,45 @@ namespace ICSharpCode.Decompiler.IL
b.Append("\t\t");
return b.ToString();
}
static string MakeName(string originalName)
{
StringBuilder name = new StringBuilder();
bool nextUpper = true;
foreach (char c in originalName) {
if (c == '.')
nextUpper = true;
else if (nextUpper) {
name.Append(char.ToUpper(c));
nextUpper = false;
} else
name.Append(c);
}
return name.ToString();
}
class OpCode {
class OpCode
{
public readonly string OriginalName;
public string Name;
public readonly string Description;
public string VariableName = "inst";
public OpCode(string originalName, string description, params Action<OpCode>[] traits)
{
this.OriginalName = originalName;
StringBuilder name = new StringBuilder();
bool nextUpper = true;
foreach (char c in originalName) {
if (c == '.')
nextUpper = true;
else if (nextUpper) {
name.Append(char.ToUpper(c));
nextUpper = false;
} else
name.Append(c);
}
this.Name = name.ToString();
this.Name = MakeName(originalName);
this.Description = description;
foreach (var trait in traits)
trait(this);
this.BaseConstructorArguments.Insert(0, "OpCode." + this.Name);
if (this.BaseConstructorArguments.FirstOrDefault() != "opCode")
this.BaseConstructorArguments.Insert(0, "OpCode." + this.Name);
}
public string ClassModifiers = "public sealed";
public bool GenerateConstructor = true;
public string ConstructorModifier = "public";
public List<string> ConstructorParameters = new List<string>();
public List<string> ConstructorBody = new List<string>();
@ -274,6 +351,8 @@ namespace ICSharpCode.Decompiler.IL @@ -274,6 +351,8 @@ namespace ICSharpCode.Decompiler.IL
public List<string> Flags = new List<string>();
public bool GenerateComputeFlags = true;
public bool GenerateAcceptVisitor = true;
public bool GenerateWriteTo = false;
public List<string> WriteOpCodePrefix = new List<string>();
public List<string> WriteOpCodeSuffix = new List<string>();
@ -298,10 +377,21 @@ namespace ICSharpCode.Decompiler.IL @@ -298,10 +377,21 @@ namespace ICSharpCode.Decompiler.IL
};
}
static Action<OpCode> CustomVariableName(string name)
{
return opCode => {
opCode.VariableName = name;
};
}
static Action<OpCode> CustomConstructor = opCode => {
opCode.GenerateConstructor = false;
};
static Action<OpCode> CustomWriteTo = opCode => {
opCode.GenerateWriteTo = false;
};
static Action<OpCode> CustomComputeFlags = opCode => {
opCode.GenerateComputeFlags = false;
};
@ -402,6 +492,116 @@ namespace ICSharpCode.Decompiler.IL @@ -402,6 +492,116 @@ namespace ICSharpCode.Decompiler.IL
opCode.WriteOpCodeSuffix.Add("output.Write(OpType);");
};
static Action<OpCode> CustomArguments(params string[] arguments)
{
return CustomChildren(arguments.Select(arg => new ChildInfo(arg) { IsArgument = true}).ToArray(), generateInline: true);
}
class ChildInfo
{
public readonly string PropertyName;
public readonly string Name;
public bool IsArgument;
public bool IsOptional;
public ChildInfo(string name)
{
this.Name = name;
this.PropertyName = MakeName(name);
}
}
static Action<OpCode> CustomChildren(ChildInfo[] children, bool generateInline = false)
{
return opCode => {
opCode.GenerateWriteTo = true;
opCode.WriteArguments.Add("output.Write('(');");
StringBuilder transformChildren = new StringBuilder();
for (int i = 0; i < children.Length; i++) {
string arg = children[i].Name;
string argProp = children[i].PropertyName;
opCode.Flags.Add(arg + ".Flags");
opCode.ConstructorParameters.Add("ILInstruction " + arg);
opCode.ConstructorBody.Add("this." + argProp + " = " + arg + ";");
if (i > 0)
opCode.WriteArguments.Add("output.Write(\", \");");
if (children[i].IsOptional)
opCode.WriteArguments.Add("if (this." + arg + " != null) this." + arg + ".WriteTo(output);");
else
opCode.WriteArguments.Add("this." + arg + ".WriteTo(output);");
opCode.Members.Add("ILInstruction " + arg + ";");
opCode.Members.Add("public ILInstruction " + argProp + " {" + Environment.NewLine
+ "\tget { return this." + arg + "; }" + Environment.NewLine
+ "\tset {" + Environment.NewLine
+ (children[i].IsOptional ? "\t\tif (value != null)" + Environment.NewLine + "\t" : "")
+ "\t\t" + (children[i].IsArgument ? "ValidateArgument" : "ValidateChild") + "(value);" + Environment.NewLine
+ "\t\tSetChildInstruction(ref this." + arg + ", value);" + Environment.NewLine
+ "\t}" + Environment.NewLine
+ "}");
}
opCode.WriteArguments.Add("output.Write(')');");
StringBuilder b = new StringBuilder();
b.AppendLine("public override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)");
b.AppendLine("{");
b.AppendLine("\tTAccumulate value = initial;");
foreach (var child in children) {
if (child.IsOptional) {
b.AppendLine("\tif (this." + child.Name + " != null)");
b.Append('\t');
}
b.AppendLine("\tvalue = func(value, this." + child.Name + ".AcceptVisitor(visitor));");
}
b.AppendLine("\treturn value;");
b.Append("}");
opCode.Members.Add(b.ToString());
b = new StringBuilder();
b.AppendLine("public override void TransformChildren(ILVisitor<ILInstruction> visitor)");
b.AppendLine("{");
foreach (var child in children) {
if (child.IsOptional) {
b.AppendLine("\tif (this." + child.Name + " != null)");
b.Append('\t');
}
b.AppendLine("\tthis." + child.PropertyName + " = this." + child.Name + ".AcceptVisitor(visitor);");
}
b.Append("}");
opCode.Members.Add(b.ToString());
if (generateInline) {
b = new StringBuilder();
b.AppendLine("internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)");
b.AppendLine("{");
for (int i = children.Length - 1; i >= 0; i--) {
string arg = children[i].Name;
if (i < children.Length - 1) {
if (children[i].IsOptional)
b.AppendLine("\tif (finished && this." + arg + " != null)");
else
b.AppendLine("\tif (finished)");
b.Append("\t");
}
b.Append("\tthis." + MakeName(arg) + " = this." + arg + ".Inline(flagsBefore");
if (i > 0) {
b.Append(" | ((");
b.Append(string.Join(" | ", children.Take(i).Select(child2 => "this." + child2.Name + ".Flags")));
b.Append(") & ~(InstructionFlags.MayPeek | InstructionFlags.MayPop))");
}
b.AppendLine(", instructionStack, out finished);");
}
b.AppendLine("\treturn this;");
b.Append("}");
opCode.Members.Add(b.ToString());
}
};
}
static Action<OpCode> AbstractBaseClass = opCode => {
opCode.GenerateAcceptVisitor = false;
opCode.ClassModifiers = "public abstract";
opCode.ConstructorModifier = "protected";
opCode.ConstructorParameters.Add("OpCode opCode");
opCode.BaseConstructorArguments.Add("opCode");
};
// SideEffect trait: the instruction has a non-local side effect
static Action<OpCode> SideEffect = HasFlag("InstructionFlags.SideEffect");
static Action<OpCode> MemoryAccess = SideEffect;
@ -446,6 +646,28 @@ namespace ICSharpCode.Decompiler.IL @@ -446,6 +646,28 @@ namespace ICSharpCode.Decompiler.IL
opCode.WriteOperand.Add("output.Write(' ');");
opCode.WriteOperand.Add("Disassembler.DisassemblerHelpers.WriteOperand(output, type);");
};
static Action<OpCode> HasMethodOperand = opCode => {
opCode.ConstructorParameters.Add("MethodReference method");
opCode.Members.Add("readonly MethodReference method;");
opCode.ConstructorBody.Add("this.method = method;");
opCode.Members.Add("/// <summary>Returns the method operand.</summary>" + Environment.NewLine
+ "public MethodReference Method { get { return method; } }");
opCode.GenerateWriteTo = true;
opCode.WriteOperand.Add("output.Write(' ');");
opCode.WriteOperand.Add("Disassembler.DisassemblerHelpers.WriteOperand(output, method);");
};
static Action<OpCode> HasTokenOperand = opCode => {
opCode.ConstructorParameters.Add("MemberReference member");
opCode.Members.Add("readonly MemberReference member;");
opCode.ConstructorBody.Add("this.member = member;");
opCode.Members.Add("/// <summary>Returns the token operand.</summary>" + Environment.NewLine
+ "public MemberReference Member { get { return member; } }");
opCode.GenerateWriteTo = true;
opCode.WriteOperand.Add("output.Write(' ');");
opCode.WriteOperand.Add("Disassembler.DisassemblerHelpers.WriteOperand(output, member);");
};
// LoadConstant trait: the instruction loads a compile-time constant. Implies NoArguments.
static Action<OpCode> LoadConstant(string operandType)
@ -476,4 +698,11 @@ namespace ICSharpCode.Decompiler.IL @@ -476,4 +698,11 @@ namespace ICSharpCode.Decompiler.IL
opCode.GenerateWriteTo = true;
opCode.WriteOpCodePrefix.Add("if (UnalignedPrefix > 0)" + Environment.NewLine + "\toutput.Write(\"unaligned(\" + UnalignedPrefix + \").\");");
};
static Action<OpCode> SupportsReadonlyPrefix = opCode => {
opCode.Members.Add("/// <summary>Gets whether the 'readonly' prefix was applied to this instruction.</summary>" + Environment.NewLine
+ "public bool IsReadOnly { get; set; }");
opCode.GenerateWriteTo = true;
opCode.WriteOpCodePrefix.Add("if (IsReadOnly)" + Environment.NewLine + "\toutput.Write(\"readonly.\");");
};
#>

16
ICSharpCode.Decompiler/IL/Instructions/ArrayInstructions.cs

@ -1,16 +0,0 @@ @@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL
{
class LdLen() : UnaryInstruction(OpCode.LdLen)
{
public override InstructionFlags Flags
{
get { return InstructionFlags.MayThrow | Operand.Flags; }
}
}
}

94
ICSharpCode.Decompiler/IL/Instructions/BinaryInstruction.cs

@ -1,94 +0,0 @@ @@ -1,94 +0,0 @@
// Copyright (c) 2014 Daniel Grunwald
//
// 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.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL
{
public abstract class BinaryInstruction : ILInstruction
{
ILInstruction left;
ILInstruction right;
protected BinaryInstruction(OpCode opCode, ILInstruction left, ILInstruction right)
: base(opCode)
{
this.Left = left;
this.Right = right;
}
public ILInstruction Left {
get { return left; }
set {
ValidateArgument(value);
SetChildInstruction(ref left, value);
}
}
public ILInstruction Right {
get { return right; }
set {
ValidateArgument(value);
SetChildInstruction(ref right, value);
}
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write('(');
Left.WriteTo(output);
output.Write(", ");
Right.WriteTo(output);
output.Write(')');
}
protected override InstructionFlags ComputeFlags()
{
return Left.Flags | Right.Flags;
}
public sealed override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)
{
TAccumulate value = initial;
value = func(value, Left.AcceptVisitor(visitor));
value = func(value, Right.AcceptVisitor(visitor));
return value;
}
public sealed override void TransformChildren(ILVisitor<ILInstruction> visitor)
{
this.Left = left.AcceptVisitor(visitor);
this.Right = right.AcceptVisitor(visitor);
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{
InstructionFlags flagsBeforeRight = flagsBefore | (Left.Flags & ~(InstructionFlags.MayPeek | InstructionFlags.MayPop));
Right = Right.Inline(flagsBeforeRight, instructionStack, out finished);
if (finished)
Left = Left.Inline(flagsBefore, instructionStack, out finished);
return this;
}
}
}

28
ICSharpCode.Decompiler/IL/Instructions/BoxInstructions.cs

@ -1,28 +0,0 @@ @@ -1,28 +0,0 @@
using ICSharpCode.Decompiler.Disassembler;
using Mono.Cecil;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL
{
class UnboxAny(public readonly TypeReference TypeReference) : UnaryInstruction(OpCode.UnboxAny)
{
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
TypeReference.WriteTo(output);
output.Write('(');
Operand.WriteTo(output);
output.Write(')');
}
public override InstructionFlags Flags
{
get { return Operand.Flags | InstructionFlags.MayThrow | InstructionFlags.SideEffects; }
}
}
}

108
ICSharpCode.Decompiler/IL/Instructions/FieldAccess.cs

@ -1,108 +0,0 @@ @@ -1,108 +0,0 @@
using Mono.Cecil;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL
{
class LoadStaticField(FieldReference field, OpCode opCode = OpCode.Ldsfld) : SimpleInstruction(opCode), ISupportsVolatilePrefix
{
public readonly FieldReference Field = field;
public bool IsVolatile { get; set; }
public override void WriteTo(ITextOutput output)
{
if (IsVolatile)
output.Write("volatile.");
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Field);
}
public override InstructionFlags Flags
{
get { return InstructionFlags.SideEffects; }
}
}
class StoreStaticField(FieldReference field) : UnaryInstruction(OpCode.Stsfld), ISupportsVolatilePrefix
{
public readonly FieldReference Field = field;
public bool IsVolatile { get; set; }
public override bool NoResult { get { return true; } }
public override void WriteTo(ITextOutput output)
{
if (IsVolatile)
output.Write("volatile.");
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Field);
output.Write('(');
Operand.WriteTo(output);
output.Write(')');
}
public override InstructionFlags Flags
{
get { return InstructionFlags.SideEffects | Operand.Flags; }
}
}
class LoadInstanceField(FieldReference field, OpCode opCode = OpCode.Ldfld) : UnaryInstruction(opCode), ISupportsVolatilePrefix
{
public readonly FieldReference Field = field;
public bool IsVolatile { get; set; }
public override void WriteTo(ITextOutput output)
{
if (IsVolatile)
output.Write("volatile.");
output.Write(OpCode);
output.Write(' ');
output.WriteReference(Field.Name, Field);
output.Write('(');
Operand.WriteTo(output);
output.Write(')');
}
public override InstructionFlags Flags
{
get { return InstructionFlags.SideEffects | InstructionFlags.MayThrow | Operand.Flags; }
}
}
class StoreInstanceField(FieldReference field, OpCode opCode = OpCode.Stfld) : BinaryInstruction(opCode), ISupportsVolatilePrefix
{
public readonly FieldReference Field = field;
public bool IsVolatile { get; set; }
public override bool NoResult { get { return true; } }
public override void WriteTo(ITextOutput output)
{
if (IsVolatile)
output.Write("volatile.");
output.Write(OpCode);
output.Write(' ');
output.WriteReference(Field.Name, Field);
output.Write('(');
Left.WriteTo(output);
output.Write(", ");
Right.WriteTo(output);
output.Write(')');
}
public override InstructionFlags Flags
{
get { return InstructionFlags.SideEffects | InstructionFlags.MayThrow | Left.Flags | Right.Flags; }
}
}
}

14
ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs

@ -46,6 +46,12 @@ namespace ICSharpCode.Decompiler.IL @@ -46,6 +46,12 @@ namespace ICSharpCode.Decompiler.IL
throw new ArgumentException("Argument must not be of type void", "inst");
}
internal static void ValidateChild(ILInstruction inst)
{
if (inst == null)
throw new ArgumentNullException("inst");
}
[Conditional("DEBUG")]
internal void CheckInvariant()
{
@ -56,6 +62,14 @@ namespace ICSharpCode.Decompiler.IL @@ -56,6 +62,14 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
public abstract StackType ResultType { get; }
internal static StackType CommonResultType(StackType a, StackType b)
{
if (a == StackType.I || b == StackType.I)
return StackType.I;
Debug.Assert(a == b);
return a;
}
InstructionFlags flags = (InstructionFlags)(-1);
public InstructionFlags Flags {

57
ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs

@ -23,10 +23,6 @@ namespace ICSharpCode.Decompiler.IL @@ -23,10 +23,6 @@ namespace ICSharpCode.Decompiler.IL
{
partial class IfInstruction : ILInstruction
{
ILInstruction condition;
ILInstruction trueInst;
ILInstruction falseInst;
public IfInstruction(ILInstruction condition, ILInstruction trueInst, ILInstruction falseInst = null) : base(OpCode.IfInstruction)
{
this.Condition = condition;
@ -34,54 +30,12 @@ namespace ICSharpCode.Decompiler.IL @@ -34,54 +30,12 @@ namespace ICSharpCode.Decompiler.IL
this.FalseInst = falseInst ?? new Nop();
}
public ILInstruction Condition {
get { return condition; }
set {
ValidateArgument(value);
SetChildInstruction(ref condition, value);
}
}
public ILInstruction TrueInst {
get { return trueInst; }
set {
if (value == null)
throw new ArgumentNullException();
SetChildInstruction(ref trueInst, value);
}
}
public ILInstruction FalseInst {
get { return falseInst; }
set {
if (value == null)
throw new ArgumentNullException();
SetChildInstruction(ref falseInst, value);
}
}
public override StackType ResultType {
get {
return trueInst.ResultType;
return CommonResultType(trueInst.ResultType, falseInst.ResultType);
}
}
public override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)
{
TAccumulate value = initial;
value = func(value, condition.AcceptVisitor(visitor));
value = func(value, trueInst.AcceptVisitor(visitor));
value = func(value, falseInst.AcceptVisitor(visitor));
return value;
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
{
this.Condition = condition.AcceptVisitor(visitor);
this.TrueInst = trueInst.AcceptVisitor(visitor);
this.FalseInst = falseInst.AcceptVisitor(visitor);
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{
this.Condition = condition.Inline(flagsBefore, instructionStack, out finished);
@ -92,12 +46,15 @@ namespace ICSharpCode.Decompiler.IL @@ -92,12 +46,15 @@ namespace ICSharpCode.Decompiler.IL
}
protected override InstructionFlags ComputeFlags()
{
return condition.Flags | CombineFlags(trueInst.Flags, falseInst.Flags);
}
internal static InstructionFlags CombineFlags(InstructionFlags trueFlags, InstructionFlags falseFlags)
{
// the endpoint of the 'if' is only unreachable if both branches have an unreachable endpoint
const InstructionFlags combineWithAnd = InstructionFlags.EndPointUnreachable;
InstructionFlags trueFlags = trueInst.Flags;
InstructionFlags falseFlags = falseInst.Flags;
return condition.Flags | (trueFlags & falseFlags) | ((trueFlags | falseFlags) & ~combineWithAnd);
return (trueFlags & falseFlags) | ((trueFlags | falseFlags) & ~combineWithAnd);
}
public override void WriteTo(ITextOutput output)

253
ICSharpCode.Decompiler/IL/Instructions/OpCode.cs

@ -1,253 +0,0 @@ @@ -1,253 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL
{
public enum OpCode
{
/// <summary>
/// No operation. Takes 0 arguments and returns void.
/// <see cref="IL.Nop"/>
/// </summary>
Nop,
/// <summary>
/// Pops the top of the evaluation stack and returns the value.
/// Does not correspond to any IL instruction, but encodes the implicit stack use by the IL instruction.
/// <see cref="IL.Pop"/>
/// </summary>
Pop,
/// <summary>
/// Peeks at the top of the evaluation stack and returns the value.
/// Corresponds to IL 'dup'. <see cref="IL.Peek"/>
/// </summary>
Peek,
/// <summary>
/// Ignore the arguments and produce void. Used to prevent the end result of an instruction
/// from being pushed to the evaluation stack.
/// <see cref="VoidInstruction"/>
/// </summary>
Void,
/// <summary>
/// Unary operator that expects an input of type I4.
/// Return 1 (of type I4) if the input value is 0. Otherwise, return 0 (of type I4).
/// <see cref="LogicNotInstruction"/>
/// </summary>
LogicNot,
/// <summary>
/// Adds two numbers. <see cref="BinaryNumericInstruction"/>
/// </summary>
Add,
/// <summary>
/// Subtracts two numbers. <see cref="BinaryNumericInstruction"/>
/// </summary>
Sub,
/// <summary>
/// Multiplies two numbers. <see cref="BinaryNumericInstruction"/>
/// </summary>
Mul,
/// <summary>
/// Division. <see cref="BinaryNumericInstruction"/>
/// </summary>
Div,
/// <summary>
/// Division remainder. <see cref="BinaryNumericInstruction"/>
/// </summary>
Rem,
/// <summary>
/// Unary negation. <see cref="UnaryInstruction"/>
/// </summary>
Neg,
/// <summary>
/// Bitwise AND. <see cref="BinaryNumericInstruction"/>
/// </summary>
BitAnd,
/// <summary>
/// Bitwise OR. <see cref="BinaryNumericInstruction"/>
/// </summary>
BitOr,
/// <summary>
/// Bitwise XOR. <see cref="BinaryNumericInstruction"/>
/// </summary>
BitXor,
/// <summary>
/// Bitwise NOT. <see cref="UnaryNumericInstruction"/>
/// </summary>
BitNot,
/// <summary>
/// Retrieves the RuntimeArgumentHandle. <see cref="IL.Arglist"/>
/// </summary>
Arglist,
/// <summary>
/// <c>if (cond) goto target;</c>
/// <see cref="IL.ConditionalBranch"/>
/// </summary>
ConditionalBranch,
/// <summary>
/// <c>goto target;</c>
/// <see cref="IL.Branch"/>
/// </summary>
Branch,
/// <summary>
/// Breakpoint instruction.
/// </summary>
DebugBreak,
/// <summary>
/// Compare equal.
/// Returns 1 (of type I4) if two numbers or object references are equal; 0 otherwise.
/// <see cref="BinaryComparisonInstruction"/>
/// </summary>
Ceq,
/// <summary>
/// Compare greater than.
/// For integers, perform a signed comparison.
/// For floating-point numbers, return 0 for unordered numbers.
/// <see cref="BinaryComparisonInstruction"/>
/// </summary>
Cgt,
/// <summary>
/// Compare greater than (unordered/unsigned).
/// For integers, perform a signed comparison.
/// For floating-point numbers, return 1 for unordered numbers.
/// <see cref="BinaryComparisonInstruction"/>
/// </summary>
Cgt_Un,
/// <summary>
/// Compare less than.
/// For integers, perform a signed comparison.
/// For floating-point numbers, return 0 for unordered numbers.
/// <see cref="BinaryComparisonInstruction"/>
/// </summary>
Clt,
/// <summary>
/// Compare less than (unordered/unsigned).
/// For integers, perform a signed comparison.
/// For floating-point numbers, return 1 for unordered numbers.
/// <see cref="BinaryComparisonInstruction"/>
/// </summary>
Clt_Un,
/// <summary>
/// Call a method.
/// </summary>
Call,
/// <summary>
/// Call a method using virtual dispatch.
/// </summary>
CallVirt,
/// <summary>
/// Checks that the float on top of the stack is not NaN or infinite.
/// </summary>
Ckfinite,
/// <summary>
/// Numeric cast. <see cref="ConvInstruction"/>
/// </summary>
Conv,
/// <summary>
/// Loads the value of a variable. (ldarg/ldloc)
/// <see cref="IL.LdLoc"/>
/// </summary>
LdLoc,
/// <summary>
/// Loads the address of a variable. (ldarga/ldloca)
/// <see cref="IL.LdLoca"/>
/// </summary>
LdLoca,
/// <summary>
/// Stores a value into a variable. (starg/stloc)
/// <see cref="IL.StLoc"/>
/// </summary>
StLoc,
/// <summary>
/// Loads a constant string. <see cref="ConstantString"/>
/// </summary>
LdStr,
/// <summary>
/// Loads a constant 32-bit integer. <see cref="ConstantI4"/>
/// </summary>
LdcI4,
/// <summary>
/// Loads a constant 64-bit integer. <see cref="ConstantI8"/>
/// </summary>
LdcI8,
/// <summary>
/// Loads a constant floating point number. <see cref="ConstantFloat"/>
/// </summary>
LdcF,
/// <summary>
/// Loads a null reference.
/// </summary>
LdNull,
/// <summary>
/// Returns from the current method or lambda.
/// <see cref="IL.ReturnVoidInstruction"/> or <see cref="IL.ReturnInstruction"/>, depending on whether
/// the method has return type void.
/// </summary>
Ret,
/// <summary>
/// Shift left. <see cref="BinaryNumericInstruction"/>
/// </summary>
Shl,
/// <summary>
/// Shift right. <see cref="BinaryNumericInstruction"/>
/// </summary>
Shr,
/// <summary>
/// Load instance field. <see cref="LoadInstanceField"/>
/// </summary>
Ldfld,
/// <summary>
/// Load instance field address. <see cref="LoadInstanceField"/>
/// </summary>
Ldflda,
/// <summary>
/// Store to instance field. <see cref="StoreInstanceField"/>
/// </summary>
Stfld,
/// <summary>
/// Load static field. <see cref="LoadStaticField"/>
/// </summary>
Ldsfld,
/// <summary>
/// Load static field address. <see cref="LoadStaticField"/>
/// </summary>
Ldsflda,
/// <summary>
/// Store to static field. <see cref="StoreStaticField"/>
/// </summary>
Stsfld,
/// <summary>
/// Test if object is instance of class or interface. <see cref="IL.IsInst"/>
/// </summary>
IsInst,
/// <summary>
/// Indirect load (ref/pointer dereference)
/// </summary>
LdInd,
/// <summary>
/// Unbox a value.
/// </summary>
UnboxAny,
/// <summary>
/// Creates an object instance and calls the constructor. <see cref="IL.CallInstruction"/>
/// </summary>
NewObj,
/// <summary>
/// Throws an exception. <see cref="IL.ThrowInstruction"/>
/// </summary>
Throw,
/// <summary>
/// A block of IL instructions. <see cref="IL.Block"/>
/// </summary>
Block,
/// <summary>
/// A container of IL blocks. <see cref="IL.BlockContainer"/>
/// </summary>
BlockContainer,
/// <summary>
/// Returns the length of an array as 'native unsigned int'.
/// </summary>
LdLen,
}
}

26
ICSharpCode.Decompiler/IL/Instructions/Return.cs

@ -24,17 +24,17 @@ namespace ICSharpCode.Decompiler.IL @@ -24,17 +24,17 @@ namespace ICSharpCode.Decompiler.IL
{
partial class Return
{
ILInstruction argument;
ILInstruction returnValue;
/// <summary>
/// The value to return. Null if this return statement is within a void method.
/// </summary>
public ILInstruction Argument {
get { return argument; }
public ILInstruction ReturnValue {
get { return returnValue; }
set {
if (value != null)
ValidateArgument(value);
SetChildInstruction(ref argument, value);
SetChildInstruction(ref returnValue, value);
}
}
@ -44,15 +44,15 @@ namespace ICSharpCode.Decompiler.IL @@ -44,15 +44,15 @@ namespace ICSharpCode.Decompiler.IL
public Return(ILInstruction argument) : base(OpCode.Return)
{
this.Argument = argument;
this.ReturnValue = argument;
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
if (Argument != null) {
if (returnValue != null) {
output.Write('(');
Argument.WriteTo(output);
returnValue.WriteTo(output);
output.Write(')');
}
}
@ -60,21 +60,21 @@ namespace ICSharpCode.Decompiler.IL @@ -60,21 +60,21 @@ namespace ICSharpCode.Decompiler.IL
public override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)
{
TAccumulate value = initial;
if (argument != null)
value = func(value, argument.AcceptVisitor(visitor));
if (returnValue != null)
value = func(value, returnValue.AcceptVisitor(visitor));
return value;
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
{
if (argument != null)
this.Argument = argument.AcceptVisitor(visitor);
if (returnValue != null)
this.ReturnValue = returnValue.AcceptVisitor(visitor);
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{
if (argument != null)
this.Argument = argument.Inline(flagsBefore, instructionStack, out finished);
if (returnValue != null)
this.ReturnValue = returnValue.Inline(flagsBefore, instructionStack, out finished);
else
finished = true;
return this;

113
ICSharpCode.Decompiler/IL/Instructions/TryCatch.cs

@ -0,0 +1,113 @@ @@ -0,0 +1,113 @@
// Copyright (c) 2014 Daniel Grunwald
//
// 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.
using System;
using System.Collections.Generic;
namespace ICSharpCode.Decompiler.IL
{
partial class TryCatch
{
public readonly InstructionCollection<TryCatchHandler> CatchHandlers;
public TryCatch(ILInstruction tryBlock) : base(OpCode.TryCatch)
{
this.TryBlock = tryBlock;
this.CatchHandlers = new InstructionCollection<TryCatchHandler>(this);
}
ILInstruction tryBlock;
public ILInstruction TryBlock {
get { return this.tryBlock; }
set {
ValidateChild(value);
SetChildInstruction(ref this.tryBlock, value);
}
}
public override void WriteTo(ITextOutput output)
{
output.Write("try ");
tryBlock.WriteTo(output);
foreach (var handler in CatchHandlers) {
output.Write(' ');
handler.WriteTo(output);
}
}
public override StackType ResultType {
get { return StackType.Void; }
}
protected override InstructionFlags ComputeFlags()
{
var flags = tryBlock.Flags;
foreach (var handler in CatchHandlers)
flags = IfInstruction.CombineFlags(flags, handler.Flags);
return flags;
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{
finished = false;
return this;
}
public override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)
{
TAccumulate value = initial;
value = func(value, tryBlock.AcceptVisitor(visitor));
foreach (var handler in CatchHandlers)
value = func(value, handler.AcceptVisitor(visitor));
return value;
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
{
this.TryBlock = tryBlock.AcceptVisitor(visitor);
for (int i = 0; i < CatchHandlers.Count; i++) {
if (CatchHandlers[i].AcceptVisitor(visitor) != CatchHandlers[i])
throw new InvalidOperationException("Cannot transform a TryCatchHandler");
}
}
}
partial class TryCatchHandler
{
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{
finished = false;
return this;
}
public override void WriteTo(ITextOutput output)
{
output.Write(" catch ");
if (variable != null) {
output.WriteDefinition(variable.Name, variable);
output.Write(" : ");
Disassembler.DisassemblerHelpers.WriteOperand(output, variable.Type);
}
output.Write(" if (");
filter.WriteTo(output);
output.Write(')');
output.Write(' ');
body.WriteTo(output);
}
}
}

80
ICSharpCode.Decompiler/IL/Instructions/TryFinally.cs

@ -0,0 +1,80 @@ @@ -0,0 +1,80 @@
// Copyright (c) 2014 Daniel Grunwald
//
// 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.
using System;
using System.Collections.Generic;
namespace ICSharpCode.Decompiler.IL
{
partial class TryFinally
{
public override void WriteTo(ITextOutput output)
{
output.Write("try ");
tryBlock.WriteTo(output);
output.Write(" finally ");
finallyBlock.WriteTo(output);
}
public override StackType ResultType {
get {
return tryBlock.ResultType;
}
}
protected override InstructionFlags ComputeFlags()
{
// if the endpoint of either the try or the finally is unreachable, the endpoint of the try-finally will be unreachable
return tryBlock.Flags | finallyBlock.Flags;
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{
finished = false;
return this;
}
}
partial class TryFault
{
public override void WriteTo(ITextOutput output)
{
output.Write("try ");
tryBlock.WriteTo(output);
output.Write(" fault ");
faultBlock.WriteTo(output);
}
public override StackType ResultType {
get { return tryBlock.ResultType; }
}
protected override InstructionFlags ComputeFlags()
{
// The endpoint of the try-fault is unreachable only if both endpoints are unreachable
return IfInstruction.CombineFlags(tryBlock.Flags, faultBlock.Flags);
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{
finished = false;
return this;
}
}
}

49
ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs

@ -23,55 +23,6 @@ using System.Linq; @@ -23,55 +23,6 @@ using System.Linq;
namespace ICSharpCode.Decompiler.IL
{
public abstract class UnaryInstruction : ILInstruction
{
ILInstruction argument;
public ILInstruction Argument {
get { return argument; }
set {
ValidateArgument(value);
SetChildInstruction(ref argument, value);
}
}
protected UnaryInstruction(OpCode opCode, ILInstruction argument) : base(opCode)
{
this.Argument = argument;
}
//public sealed override bool IsPeeking { get { return Operand.IsPeeking; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write('(');
argument.WriteTo(output);
output.Write(')');
}
public sealed override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)
{
return func(initial, argument.AcceptVisitor(visitor));
}
public sealed override void TransformChildren(ILVisitor<ILInstruction> visitor)
{
this.Argument = argument.AcceptVisitor(visitor);
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{
Argument = argument.Inline(flagsBefore, instructionStack, out finished);
return this;
}
protected override InstructionFlags ComputeFlags()
{
return argument.Flags;
}
}
partial class BitNot
{
public override StackType ResultType {

53
ICSharpCode.Decompiler/IL/Instructions/VarInstructions.cs

@ -1,53 +0,0 @@ @@ -1,53 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL
{
class LdLoc(public readonly ILVariable Variable) : SimpleInstruction(OpCode.LdLoc)
{
public override void WriteTo(ITextOutput output)
{
Variable.WriteTo(output);
}
public override InstructionFlags Flags
{
get { return InstructionFlags.MayReadLocals; }
}
}
class LdLoca(public readonly ILVariable Variable) : SimpleInstruction(OpCode.LdLoca)
{
public override void WriteTo(ITextOutput output)
{
output.Write("ldloca ");
Variable.WriteTo(output);
}
public override InstructionFlags Flags
{
get {
// the address of a local can be considered to be a constant
return InstructionFlags.None;
}
}
}
class StLoc(public readonly ILVariable Variable) : UnaryInstruction(OpCode.StLoc)
{
public override void WriteTo(ITextOutput output)
{
Variable.WriteTo(output);
output.Write(" = ");
Operand.WriteTo(output);
}
public override InstructionFlags Flags
{
get { return InstructionFlags.MayWriteLocals | Operand.Flags; }
}
}
}

11
NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/TryCatchStatement.cs

@ -90,6 +90,8 @@ namespace ICSharpCode.NRefactory.CSharp @@ -90,6 +90,8 @@ namespace ICSharpCode.NRefactory.CSharp
public class CatchClause : AstNode
{
public static readonly TokenRole CatchKeywordRole = new TokenRole ("catch");
public static readonly TokenRole IfKeywordRole = IfElseStatement.IfKeywordRole;
public static readonly Role<Expression> ConditionRole = IfElseStatement.ConditionRole;
#region Null
public new static readonly CatchClause Null = new NullCatchClause ();
@ -212,6 +214,15 @@ namespace ICSharpCode.NRefactory.CSharp @@ -212,6 +214,15 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.RPar); }
}
public CSharpTokenNode IfToken {
get { return GetChildByRole (IfKeywordRole); }
}
public Expression Condition {
get { return GetChildByRole(ConditionRole); }
set { SetChildByRole(ConditionRole, value); }
}
public BlockStatement Body {
get { return GetChildByRole (Roles.Body); }
set { SetChildByRole (Roles.Body, value); }

10
NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs

@ -1673,6 +1673,16 @@ namespace ICSharpCode.NRefactory.CSharp @@ -1673,6 +1673,16 @@ namespace ICSharpCode.NRefactory.CSharp
Space(policy.SpacesWithinCatchParentheses);
RPar();
}
if (!catchClause.Condition.IsNull) {
Space();
WriteKeyword(CatchClause.IfKeywordRole);
Space(policy.SpaceBeforeIfParentheses);
LPar();
Space(policy.SpacesWithinIfParentheses);
catchClause.Condition.AcceptVisitor(this);
Space(policy.SpacesWithinIfParentheses);
RPar();
}
catchClause.Body.AcceptVisitor(this);
EndNode(catchClause);
}

Loading…
Cancel
Save