Browse Source

Merge branch 'master' of git://github.com/icsharpcode/ILSpy into Debugger

pull/191/merge
Eusebiu Marcu 16 years ago
parent
commit
55d7852638
  1. 56
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 301
      ICSharpCode.Decompiler/Ast/Transforms/AddCheckedBlocks.cs
  3. 4
      ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs
  4. 1
      ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs
  5. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  6. 24
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  7. 23
      ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
  8. 4
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  9. 40
      ICSharpCode.Decompiler/Tests/CheckedUnchecked.cs
  10. 1
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

56
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -236,43 +236,55 @@ namespace ICSharpCode.Decompiler.Ast @@ -236,43 +236,55 @@ namespace ICSharpCode.Decompiler.Ast
Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
Ast.Expression arg3 = args.Count >= 3 ? args[2] : null;
switch(byteCode.Code) {
switch (byteCode.Code) {
#region Arithmetic
case ILCode.Add:
case ILCode.Add_Ovf:
case ILCode.Add_Ovf_Un:
{
BinaryOperatorExpression boe;
if (byteCode.InferredType is PointerType) {
if (byteCode.Arguments[0].ExpectedType is PointerType) {
arg2 = DivideBySize(arg2, ((PointerType)byteCode.InferredType).ElementType);
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2)
.WithAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation);
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
boe.AddAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation);
} else if (byteCode.Arguments[1].ExpectedType is PointerType) {
arg1 = DivideBySize(arg1, ((PointerType)byteCode.InferredType).ElementType);
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2)
.WithAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation);
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
boe.AddAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation);
} else {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
}
} else {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
}
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
boe.AddAnnotation(byteCode.Code == ILCode.Add ? AddCheckedBlocks.UncheckedAnnotation : AddCheckedBlocks.CheckedAnnotation);
return boe;
}
case ILCode.Sub:
case ILCode.Sub_Ovf:
case ILCode.Sub_Ovf_Un:
{
BinaryOperatorExpression boe;
if (byteCode.InferredType is PointerType) {
if (byteCode.Arguments[0].ExpectedType is PointerType) {
arg2 = DivideBySize(arg2, ((PointerType)byteCode.InferredType).ElementType);
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2)
.WithAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation);
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
boe.WithAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation);
} else {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
}
} else {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
}
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
boe.AddAnnotation(byteCode.Code == ILCode.Sub ? AddCheckedBlocks.UncheckedAnnotation : AddCheckedBlocks.CheckedAnnotation);
return boe;
}
case ILCode.Div: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2);
case ILCode.Div_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2);
case ILCode.Mul: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
case ILCode.Mul_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
case ILCode.Mul_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
case ILCode.Mul: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2).WithAnnotation(AddCheckedBlocks.UncheckedAnnotation);
case ILCode.Mul_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2).WithAnnotation(AddCheckedBlocks.CheckedAnnotation);
case ILCode.Mul_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2).WithAnnotation(AddCheckedBlocks.CheckedAnnotation);
case ILCode.Rem: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2);
case ILCode.Rem_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2);
case ILCode.And: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseAnd, arg2);
@ -281,7 +293,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -281,7 +293,7 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Shl: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftLeft, arg2);
case ILCode.Shr: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2);
case ILCode.Shr_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2);
case ILCode.Neg: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Minus, arg1);
case ILCode.Neg: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Minus, arg1).WithAnnotation(AddCheckedBlocks.UncheckedAnnotation);
case ILCode.Not: return new Ast.UnaryOperatorExpression(UnaryOperatorType.BitNot, arg1);
#endregion
#region Arrays
@ -372,7 +384,14 @@ namespace ICSharpCode.Decompiler.Ast @@ -372,7 +384,14 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Conv_U8:
case ILCode.Conv_I:
case ILCode.Conv_U:
return arg1; // conversion is handled by Convert() function using the info from type analysis
{
// conversion was handled by Convert() function using the info from type analysis
CastExpression cast = arg1 as CastExpression;
if (cast != null) {
cast.AddAnnotation(AddCheckedBlocks.UncheckedAnnotation);
}
return arg1;
}
case ILCode.Conv_R4: return arg1.CastTo(typeof(float));
case ILCode.Conv_R8: return arg1.CastTo(typeof(double));
case ILCode.Conv_R_Un: return arg1.CastTo(typeof(double)); // TODO
@ -392,7 +411,14 @@ namespace ICSharpCode.Decompiler.Ast @@ -392,7 +411,14 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Conv_Ovf_U2_Un:
case ILCode.Conv_Ovf_U4_Un:
case ILCode.Conv_Ovf_U8_Un:
return arg1; // conversion was handled by Convert() function using the info from type analysis
{
// conversion was handled by Convert() function using the info from type analysis
CastExpression cast = arg1 as CastExpression;
if (cast != null) {
cast.AddAnnotation(AddCheckedBlocks.CheckedAnnotation);
}
return arg1;
}
case ILCode.Conv_Ovf_I: return arg1.CastTo(typeof(IntPtr)); // TODO
case ILCode.Conv_Ovf_U: return arg1.CastTo(typeof(UIntPtr));
case ILCode.Conv_Ovf_I_Un: return arg1.CastTo(typeof(IntPtr));

301
ICSharpCode.Decompiler/Ast/Transforms/AddCheckedBlocks.cs

@ -0,0 +1,301 @@ @@ -0,0 +1,301 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Linq;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory.CSharp;
namespace ICSharpCode.Decompiler.Ast.Transforms
{
/// <summary>
/// Add checked/unchecked blocks.
/// </summary>
public class AddCheckedBlocks : IAstTransform
{
#region Annotation
sealed class CheckedUncheckedAnnotation {
/// <summary>
/// true=checked, false=unchecked
/// </summary>
public bool IsChecked;
}
public static readonly object CheckedAnnotation = new CheckedUncheckedAnnotation { IsChecked = true };
public static readonly object UncheckedAnnotation = new CheckedUncheckedAnnotation { IsChecked = false };
#endregion
/*
We treat placing checked/unchecked blocks as an optimization problem, with the following goals:
1. Use minimum number of checked blocks+expressions
2. Prefer checked expressions over checked blocks
3. Make the scope of checked expressions as small as possible
4. Make the scope of checked blocks as large as possible
(where goal 1 has the highest priority)
*/
#region struct Cost
struct Cost
{
// highest possible cost so that the Blocks+Expressions addition doesn't overflow
public static readonly Cost Infinite = new Cost(0x3fffffff, 0x3fffffff);
public readonly int Blocks;
public readonly int Expressions;
public Cost(int blocks, int expressions)
{
this.Blocks = blocks;
this.Expressions = expressions;
}
public static bool operator <(Cost a, Cost b)
{
return a.Blocks + a.Expressions < b.Blocks + b.Expressions
|| a.Blocks + a.Expressions == b.Blocks + b.Expressions && a.Blocks < b.Blocks;
}
public static bool operator >(Cost a, Cost b)
{
return a.Blocks + a.Expressions > b.Blocks + b.Expressions
|| a.Blocks + a.Expressions == b.Blocks + b.Expressions && a.Blocks > b.Blocks;
}
public static bool operator <=(Cost a, Cost b)
{
return a.Blocks + a.Expressions < b.Blocks + b.Expressions
|| a.Blocks + a.Expressions == b.Blocks + b.Expressions && a.Blocks <= b.Blocks;
}
public static bool operator >=(Cost a, Cost b)
{
return a.Blocks + a.Expressions > b.Blocks + b.Expressions
|| a.Blocks + a.Expressions == b.Blocks + b.Expressions && a.Blocks >= b.Blocks;
}
public static Cost operator +(Cost a, Cost b)
{
return new Cost(a.Blocks + b.Blocks, a.Expressions + b.Expressions);
}
public override string ToString()
{
return string.Format("[{0} + {1}]", Blocks, Expressions);
}
}
#endregion
#region class InsertedNode
/// <summary>
/// Holds the blocks and expressions that should be inserted
/// </summary>
abstract class InsertedNode
{
public static InsertedNode operator +(InsertedNode a, InsertedNode b)
{
if (a == null)
return b;
if (b == null)
return a;
return new InsertedNodeList(a, b);
}
public abstract void Insert();
}
class InsertedNodeList : InsertedNode
{
readonly InsertedNode child1, child2;
public InsertedNodeList(AddCheckedBlocks.InsertedNode child1, AddCheckedBlocks.InsertedNode child2)
{
this.child1 = child1;
this.child2 = child2;
}
public override void Insert()
{
child1.Insert();
child2.Insert();
}
}
class InsertedExpression : InsertedNode
{
readonly Expression expression;
readonly bool isChecked;
public InsertedExpression(Expression expression, bool isChecked)
{
this.expression = expression;
this.isChecked = isChecked;
}
public override void Insert()
{
if (isChecked)
expression.ReplaceWith(e => new CheckedExpression { Expression = e });
else
expression.ReplaceWith(e => new UncheckedExpression { Expression = e });
}
}
class InsertedBlock : InsertedNode
{
readonly Statement firstStatement; // inclusive
readonly Statement lastStatement; // exclusive
readonly bool isChecked;
public InsertedBlock(Statement firstStatement, Statement lastStatement, bool isChecked)
{
this.firstStatement = firstStatement;
this.lastStatement = lastStatement;
this.isChecked = isChecked;
}
public override void Insert()
{
BlockStatement newBlock = new BlockStatement();
// Move all statements except for the first
Statement next;
for (Statement stmt = firstStatement.NextStatement; stmt != lastStatement; stmt = next) {
next = stmt.NextStatement;
newBlock.Add(stmt.Detach());
}
// Replace the first statement with the new (un)checked block
if (isChecked)
firstStatement.ReplaceWith(new CheckedStatement { Body = newBlock });
else
firstStatement.ReplaceWith(new UncheckedStatement { Body = newBlock });
// now also move the first node into the new block
newBlock.Statements.InsertAfter(null, firstStatement);
}
}
#endregion
#region class Result
/// <summary>
/// Holds the result of an insertion operation.
/// </summary>
class Result
{
public Cost CostInCheckedContext;
public InsertedNode NodesToInsertInCheckedContext;
public Cost CostInUncheckedContext;
public InsertedNode NodesToInsertInUncheckedContext;
}
#endregion
public void Run(AstNode node)
{
BlockStatement block = node as BlockStatement;
if (block == null) {
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
Run(child);
}
} else {
Result r = GetResultFromBlock(block);
if (r.NodesToInsertInUncheckedContext != null)
r.NodesToInsertInUncheckedContext.Insert();
}
}
Result GetResultFromBlock(BlockStatement block)
{
// For a block, we are tracking 4 possibilities:
// a) context is checked, no unchecked block open
Cost costCheckedContext = new Cost(0, 0);
InsertedNode nodesCheckedContext = null;
// b) context is checked, an unchecked block is open
Cost costCheckedContextUncheckedBlockOpen = Cost.Infinite;
InsertedNode nodesCheckedContextUncheckedBlockOpen = null;
Statement uncheckedBlockStart = null;
// c) context is unchecked, no checked block open
Cost costUncheckedContext = new Cost(0, 0);
InsertedNode nodesUncheckedContext = null;
// d) context is unchecked, a checked block is open
Cost costUncheckedContextCheckedBlockOpen = Cost.Infinite;
InsertedNode nodesUncheckedContextCheckedBlockOpen = null;
Statement checkedBlockStart = null;
Statement statement = block.Statements.FirstOrDefault();
while (true) {
// Blocks can be closed 'for free'. We use '<=' so that blocks are closed as late as possible (goal 4)
if (costCheckedContextUncheckedBlockOpen <= costCheckedContext) {
costCheckedContext = costCheckedContextUncheckedBlockOpen;
nodesCheckedContext = nodesCheckedContextUncheckedBlockOpen + new InsertedBlock(uncheckedBlockStart, statement, false);
}
if (costUncheckedContextCheckedBlockOpen <= costUncheckedContext) {
costUncheckedContext = costUncheckedContextCheckedBlockOpen;
nodesUncheckedContext = nodesUncheckedContextCheckedBlockOpen + new InsertedBlock(checkedBlockStart, statement, true);
}
if (statement == null)
break;
// Now try opening blocks. We use '<' so that blocks are opened as early as possible. (goal 4)
if (costCheckedContext + new Cost(1, 0) < costCheckedContextUncheckedBlockOpen) {
costCheckedContextUncheckedBlockOpen = costCheckedContext + new Cost(1, 0);
nodesCheckedContextUncheckedBlockOpen = nodesCheckedContext;
uncheckedBlockStart = statement;
}
if (costUncheckedContext + new Cost(1, 0) < costUncheckedContextCheckedBlockOpen) {
costUncheckedContextCheckedBlockOpen = costUncheckedContext + new Cost(1, 0);
nodesUncheckedContextCheckedBlockOpen = nodesUncheckedContext;
checkedBlockStart = statement;
}
// Now handle the statement
Result stmtResult = GetResult(statement);
costCheckedContext += stmtResult.CostInCheckedContext;
nodesCheckedContext += stmtResult.NodesToInsertInCheckedContext;
costCheckedContextUncheckedBlockOpen += stmtResult.CostInUncheckedContext;
nodesCheckedContextUncheckedBlockOpen += stmtResult.NodesToInsertInUncheckedContext;
costUncheckedContext += stmtResult.CostInUncheckedContext;
nodesUncheckedContext += stmtResult.NodesToInsertInUncheckedContext;
costUncheckedContextCheckedBlockOpen += stmtResult.CostInCheckedContext;
nodesUncheckedContextCheckedBlockOpen += stmtResult.NodesToInsertInCheckedContext;
statement = statement.NextStatement;
}
return new Result {
CostInCheckedContext = costCheckedContext, NodesToInsertInCheckedContext = nodesCheckedContext,
CostInUncheckedContext = costUncheckedContext, NodesToInsertInUncheckedContext = nodesUncheckedContext
};
}
Result GetResult(AstNode node)
{
if (node is BlockStatement)
return GetResultFromBlock((BlockStatement)node);
Result result = new Result();
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
Result childResult = GetResult(child);
result.CostInCheckedContext += childResult.CostInCheckedContext;
result.NodesToInsertInCheckedContext += childResult.NodesToInsertInCheckedContext;
result.CostInUncheckedContext += childResult.CostInUncheckedContext;
result.NodesToInsertInUncheckedContext += childResult.NodesToInsertInUncheckedContext;
}
Expression expr = node as Expression;
if (expr != null) {
CheckedUncheckedAnnotation annotation = expr.Annotation<CheckedUncheckedAnnotation>();
if (annotation != null) {
// If the annotation requires this node to be in a specific context, set the cost of the other context to infinite.
if (annotation.IsChecked)
result.CostInUncheckedContext = Cost.Infinite;
else
result.CostInCheckedContext = Cost.Infinite;
}
// Embed this node in an checked/unchecked expression:
// We use '<' so that expressions are introduced on the deepest level possible (goal 3)
if (result.CostInCheckedContext + new Cost(0, 1) < result.CostInUncheckedContext) {
result.CostInUncheckedContext = result.CostInCheckedContext + new Cost(0, 1);
result.NodesToInsertInUncheckedContext = result.NodesToInsertInCheckedContext + new InsertedExpression(expr, true);
} else if (result.CostInUncheckedContext + new Cost(0, 1) < result.CostInCheckedContext) {
result.CostInCheckedContext = result.CostInUncheckedContext + new Cost(0, 1);
result.NodesToInsertInCheckedContext = result.NodesToInsertInUncheckedContext + new InsertedExpression(expr, false);
}
}
return result;
}
}
}

4
ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs

@ -24,10 +24,6 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -24,10 +24,6 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
public void Run(AstNode compilationUnit)
{
// Don't show using when decompiling a single method or nested types:
if (context.CurrentMethod != null || (context.CurrentType != null && context.CurrentType.DeclaringType != null))
return;
// First determine all the namespaces that need to be imported:
compilationUnit.AcceptVisitor(this, null);

1
ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs

@ -22,6 +22,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -22,6 +22,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
new PatternStatementTransform(context),
new ReplaceMethodCallsWithOperators(),
new IntroduceUnsafeModifier(),
new AddCheckedBlocks(),
new DeclareVariables(context), // should run after most transforms that modify statements
new ConvertConstructorCallIntoInitializer(), // must run after DeclareVariables
new IntroduceUsingDeclarations(context)

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -58,6 +58,7 @@ @@ -58,6 +58,7 @@
<Compile Include="Ast\NameVariables.cs" />
<Compile Include="Ast\NRefactoryExtensions.cs" />
<Compile Include="Ast\TextOutputFormatter.cs" />
<Compile Include="Ast\Transforms\AddCheckedBlocks.cs" />
<Compile Include="Ast\Transforms\ContextTrackingVisitor.cs" />
<Compile Include="Ast\Transforms\ConvertConstructorCallIntoInitializer.cs" />
<Compile Include="Ast\Transforms\DeclareVariables.cs" />

24
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -38,6 +38,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -38,6 +38,7 @@ namespace ICSharpCode.Decompiler.ILAst
InlineVariables3,
CachedDelegateInitialization,
IntroduceFixedStatements,
RecombineVariables,
TypeInference2,
RemoveRedundantCode3,
None
@ -106,6 +107,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -106,6 +107,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (abortBeforeStep == ILAstOptimizationStep.TransformDecimalCtorToConstant) return;
modified |= block.RunOptimization(TransformDecimalCtorToConstant);
modified |= block.RunOptimization(SimplifyLdcI4ConvI8);
if (abortBeforeStep == ILAstOptimizationStep.SimplifyLdObjAndStObj) return;
modified |= block.RunOptimization(SimplifyLdObjAndStObj);
@ -180,6 +182,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -180,6 +182,9 @@ namespace ICSharpCode.Decompiler.ILAst
}
}
if (abortBeforeStep == ILAstOptimizationStep.RecombineVariables) return;
RecombineVariables(method);
if (abortBeforeStep == ILAstOptimizationStep.TypeInference2) return;
TypeAnalysis.Reset(method);
TypeAnalysis.Run(context, method);
@ -458,6 +463,25 @@ namespace ICSharpCode.Decompiler.ILAst @@ -458,6 +463,25 @@ namespace ICSharpCode.Decompiler.ILAst
}
}
void RecombineVariables(ILBlock method)
{
// Recombine variables that were split when the ILAst was created
// This ensures that a single IL variable is a single C# variable (gets assigned only one name)
// The DeclareVariables transformation might then split up the C# variable again if it is used indendently in two separate scopes.
Dictionary<VariableDefinition, ILVariable> dict = new Dictionary<VariableDefinition, ILVariable>();
foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
ILVariable v = expr.Operand as ILVariable;
if (v != null && v.OriginalVariable != null) {
ILVariable combinedVariable;
if (!dict.TryGetValue(v.OriginalVariable, out combinedVariable)) {
dict.Add(v.OriginalVariable, v);
combinedVariable = v;
}
expr.Operand = combinedVariable;
}
}
}
void ReportUnassignedILRanges(ILBlock method)
{
var unassigned = ILRange.Invert(method.GetSelfAndChildrenRecursive<ILExpression>().SelectMany(e => e.ILRanges), context.CurrentMethod.Body.CodeSize).ToList();

23
ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -13,6 +13,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -13,6 +13,7 @@ namespace ICSharpCode.Decompiler.ILAst
{
public partial class ILAstOptimizer
{
#region TransformDecimalCtorToConstant
static bool TransformDecimalCtorToConstant(List<ILNode> body, ILExpression expr, int pos)
{
MethodReference r;
@ -52,7 +53,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -52,7 +53,9 @@ namespace ICSharpCode.Decompiler.ILAst
}
return modified;
}
#endregion
#region SimplifyLdObjAndStObj
static bool SimplifyLdObjAndStObj(List<ILNode> body, ILExpression expr, int pos)
{
bool modified = false;
@ -89,6 +92,26 @@ namespace ICSharpCode.Decompiler.ILAst @@ -89,6 +92,26 @@ namespace ICSharpCode.Decompiler.ILAst
}
return modified;
}
#endregion
#region SimplifyLdcI4ConvI8
static bool SimplifyLdcI4ConvI8(List<ILNode> body, ILExpression expr, int pos)
{
ILExpression ldc;
int val;
if (expr.Match(ILCode.Conv_I8, out ldc) && ldc.Match(ILCode.Ldc_I4, out val)) {
expr.Code = ILCode.Ldc_I8;
expr.Operand = (long)val;
expr.Arguments.Clear();
return true;
}
bool modified = false;
foreach(ILExpression arg in expr.Arguments) {
modified |= SimplifyLdcI4ConvI8(null, arg, -1);
}
return modified;
}
#endregion
#region CachedDelegateInitialization
void CachedDelegateInitialization(ILBlock block, ref int i)

4
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -689,7 +689,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -689,7 +689,9 @@ namespace ICSharpCode.Decompiler.ILAst
} else if (targetBitSize >= NativeInt && argType is PointerType) {
return argType;
}
return (GetInformationAmount(expectedType) == targetBitSize && IsSigned(expectedType) == targetSigned) ? expectedType : targetType;
TypeReference resultType = (GetInformationAmount(expectedType) == targetBitSize && IsSigned(expectedType) == targetSigned) ? expectedType : targetType;
arg.ExpectedType = resultType; // store the expected type in the argument so that AstMethodBodyBuilder will insert a cast
return resultType;
}
static TypeReference GetFieldType(FieldReference fieldReference)

40
ICSharpCode.Decompiler/Tests/CheckedUnchecked.cs

@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
public class CheckedUnchecked
{
public void Operators(int a, int b)
{
int c1 = checked(a + b);
int u1 = unchecked(a + b);
int c2 = checked(a - b);
int u2 = unchecked(a - b);
int c3 = checked(a * b);
int u3 = unchecked(a * b);
int c4 = checked(a / b);
int u4 = unchecked(a / b);
int c5 = checked(a % b);
int u5 = unchecked(a % b);
}
public void Cast(int a)
{
short c1 = checked((short)a);
short u1 = unchecked((short)a);
byte c2 = checked((byte)a);
byte u2 = unchecked((byte)a);
}
public void ForWithCheckedIteratorAndUncheckedBody(int n)
{
checked {
for (int i = n + 1; i < n + 1; i++) {
unchecked {
n = i * i;
}
}
}
}
}

1
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -53,6 +53,7 @@ @@ -53,6 +53,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="CheckedUnchecked.cs" />
<Compile Include="Switch.cs" />
<Compile Include="UnsafeCode.cs" />
<Compile Include="YieldReturn.cs" />

Loading…
Cancel
Save