Browse Source

Add support for unsafe code. Closes #48.

pull/100/head
Daniel Grunwald 15 years ago
parent
commit
7b2c444181
  1. 2
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 49
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  3. 50
      ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs
  4. 1
      ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs
  5. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  6. 135
      ICSharpCode.Decompiler/ILAst/ILCodes.cs
  7. 72
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  8. 3
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  9. 29
      ICSharpCode.Decompiler/Tests/UnsafeCode.cs

2
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -1131,6 +1131,8 @@ namespace ICSharpCode.Decompiler.Ast @@ -1131,6 +1131,8 @@ namespace ICSharpCode.Decompiler.Ast
return new Ast.PrimitiveExpression(false);
else if (TypeAnalysis.IsBoolean(type) && val == 1)
return new Ast.PrimitiveExpression(true);
else if (val == 0 && type is PointerType)
return new Ast.NullReferenceExpression();
if (type != null)
{ // cannot rely on type.IsValueType, it's not set for typerefs (but is set for typespecs)
TypeDefinition enumDefinition = type.Resolve();

49
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -318,9 +318,9 @@ namespace ICSharpCode.Decompiler.Ast @@ -318,9 +318,9 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Conv_U2:
case ILCode.Conv_U4:
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
case ILCode.Conv_I: return arg1.CastTo(typeof(IntPtr)); // TODO
case ILCode.Conv_U: return arg1.CastTo(typeof(UIntPtr)); // TODO
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
@ -352,35 +352,18 @@ namespace ICSharpCode.Decompiler.Ast @@ -352,35 +352,18 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Unbox: return InlineAssembly(byteCode, args);
#endregion
#region Indirect
case ILCode.Ldind_I:
case ILCode.Ldind_I1:
case ILCode.Ldind_I2:
case ILCode.Ldind_I4:
case ILCode.Ldind_I8:
case ILCode.Ldind_U1:
case ILCode.Ldind_U2:
case ILCode.Ldind_U4:
case ILCode.Ldind_R4:
case ILCode.Ldind_R8:
case ILCode.Ldind_Ref:
case ILCode.Ldobj:
if (args[0] is DirectionExpression)
return ((DirectionExpression)args[0]).Expression.Detach();
if (arg1 is DirectionExpression)
return ((DirectionExpression)arg1).Expression.Detach();
else
return InlineAssembly(byteCode, args);
case ILCode.Stind_I:
case ILCode.Stind_I1:
case ILCode.Stind_I2:
case ILCode.Stind_I4:
case ILCode.Stind_I8:
case ILCode.Stind_R4:
case ILCode.Stind_R8:
return new UnaryOperatorExpression(UnaryOperatorType.Dereference, arg1);
case ILCode.Stind_Ref:
case ILCode.Stobj:
if (args[0] is DirectionExpression)
return new AssignmentExpression(((DirectionExpression)args[0]).Expression.Detach(), args[1]);
if (arg1 is DirectionExpression)
return new AssignmentExpression(((DirectionExpression)arg1).Expression.Detach(), arg2);
else
return InlineAssembly(byteCode, args);
return new AssignmentExpression(new UnaryOperatorExpression(UnaryOperatorType.Dereference, arg1), arg2);
#endregion
case ILCode.Arglist: return InlineAssembly(byteCode, args);
case ILCode.Break: return InlineAssembly(byteCode, args);
@ -769,6 +752,22 @@ namespace ICSharpCode.Decompiler.Ast @@ -769,6 +752,22 @@ namespace ICSharpCode.Decompiler.Ast
{
if (reqType == null || actualType == reqType) {
return expr;
} else if (actualType is ByReferenceType && reqType is PointerType && expr is DirectionExpression) {
return Convert(
new UnaryOperatorExpression(UnaryOperatorType.AddressOf, ((DirectionExpression)expr).Expression.Detach()),
new PointerType(((ByReferenceType)actualType).ElementType),
reqType);
} else if (actualType is PointerType && reqType is ByReferenceType) {
expr = Convert(expr, actualType, new PointerType(((ByReferenceType)reqType).ElementType));
return new DirectionExpression {
FieldDirection = FieldDirection.Ref,
Expression = new UnaryOperatorExpression(UnaryOperatorType.Dereference, expr)
};
} else if (actualType is PointerType && reqType is PointerType) {
if (actualType.FullName != reqType.FullName)
return expr.CastTo(AstBuilder.ConvertType(reqType));
else
return expr;
} else {
bool actualIsIntegerOrEnum = TypeAnalysis.IsIntegerOrEnum(actualType);
bool requiredIsIntegerOrEnum = TypeAnalysis.IsIntegerOrEnum(reqType);

50
ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
// 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 ICSharpCode.NRefactory.CSharp;
namespace ICSharpCode.Decompiler.Ast.Transforms
{
public class IntroduceUnsafeModifier : DepthFirstAstVisitor<object, bool>, IAstTransform
{
public void Run(AstNode compilationUnit)
{
compilationUnit.AcceptVisitor(this, null);
}
protected override bool VisitChildren(AstNode node, object data)
{
bool result = false;
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
result |= child.AcceptVisitor(this, data);
}
if (result && node is AttributedNode && !(node is Accessor)) {
((AttributedNode)node).Modifiers |= Modifiers.Unsafe;
return false;
}
return result;
}
public override bool VisitPointerReferenceExpression(PointerReferenceExpression pointerReferenceExpression, object data)
{
return true;
}
public override bool VisitComposedType(ComposedType composedType, object data)
{
if (composedType.PointerRank > 0)
return true;
else
return base.VisitComposedType(composedType, data);
}
public override bool VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data)
{
if (unaryOperatorExpression.Operator == UnaryOperatorType.Dereference || unaryOperatorExpression.Operator == UnaryOperatorType.AddressOf)
return true;
else
return base.VisitUnaryOperatorExpression(unaryOperatorExpression, data);
}
}
}

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 ConvertConstructorCallIntoInitializer(),
new ReplaceMethodCallsWithOperators(),
new IntroduceUnsafeModifier(),
};
}

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -60,6 +60,7 @@ @@ -60,6 +60,7 @@
<Compile Include="Ast\Transforms\ContextTrackingVisitor.cs" />
<Compile Include="Ast\Transforms\ConvertConstructorCallIntoInitializer.cs" />
<Compile Include="Ast\Transforms\DelegateConstruction.cs" />
<Compile Include="Ast\Transforms\IntroduceUnsafeModifier.cs" />
<Compile Include="Ast\Transforms\ReplaceMethodCallsWithOperators.cs" />
<Compile Include="Ast\Transforms\PushNegation.cs" />
<Compile Include="Ast\Transforms\TransformationPipeline.cs" />

135
ICSharpCode.Decompiler/ILAst/ILCodes.cs

@ -102,24 +102,24 @@ namespace ICSharpCode.Decompiler.ILAst @@ -102,24 +102,24 @@ namespace ICSharpCode.Decompiler.ILAst
__Ble_Un,
__Blt_Un,
Switch,
Ldind_I1,
Ldind_U1,
Ldind_I2,
Ldind_U2,
Ldind_I4,
Ldind_U4,
Ldind_I8,
Ldind_I,
Ldind_R4,
Ldind_R8,
__Ldind_I1,
__Ldind_U1,
__Ldind_I2,
__Ldind_U2,
__Ldind_I4,
__Ldind_U4,
__Ldind_I8,
__Ldind_I,
__Ldind_R4,
__Ldind_R8,
Ldind_Ref,
Stind_Ref,
Stind_I1,
Stind_I2,
Stind_I4,
Stind_I8,
Stind_R4,
Stind_R8,
__Stind_I1,
__Stind_I2,
__Stind_I4,
__Stind_I8,
__Stind_R4,
__Stind_R8,
Add,
Sub,
Mul,
@ -222,7 +222,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -222,7 +222,7 @@ namespace ICSharpCode.Decompiler.ILAst
Endfinally,
Leave,
__Leave_S,
Stind_I,
__Stind_I,
Conv_U,
Arglist,
Ceq,
@ -375,49 +375,64 @@ namespace ICSharpCode.Decompiler.ILAst @@ -375,49 +375,64 @@ namespace ICSharpCode.Decompiler.ILAst
public static void ExpandMacro(ref ILCode code, ref object operand, MethodBody methodBody)
{
switch (code) {
case ILCode.__Ldarg_0: code = ILCode.__Ldarg; operand = methodBody.GetParameter(0); break;
case ILCode.__Ldarg_1: code = ILCode.__Ldarg; operand = methodBody.GetParameter(1); break;
case ILCode.__Ldarg_2: code = ILCode.__Ldarg; operand = methodBody.GetParameter(2); break;
case ILCode.__Ldarg_3: code = ILCode.__Ldarg; operand = methodBody.GetParameter(3); break;
case ILCode.__Ldloc_0: code = ILCode.Ldloc; operand = methodBody.Variables[0]; break;
case ILCode.__Ldloc_1: code = ILCode.Ldloc; operand = methodBody.Variables[1]; break;
case ILCode.__Ldloc_2: code = ILCode.Ldloc; operand = methodBody.Variables[2]; break;
case ILCode.__Ldloc_3: code = ILCode.Ldloc; operand = methodBody.Variables[3]; break;
case ILCode.__Stloc_0: code = ILCode.Stloc; operand = methodBody.Variables[0]; break;
case ILCode.__Stloc_1: code = ILCode.Stloc; operand = methodBody.Variables[1]; break;
case ILCode.__Stloc_2: code = ILCode.Stloc; operand = methodBody.Variables[2]; break;
case ILCode.__Stloc_3: code = ILCode.Stloc; operand = methodBody.Variables[3]; break;
case ILCode.__Ldarg_S: code = ILCode.__Ldarg; break;
case ILCode.__Ldarga_S: code = ILCode.__Ldarga; break;
case ILCode.__Starg_S: code = ILCode.__Starg; break;
case ILCode.__Ldloc_S: code = ILCode.Ldloc; break;
case ILCode.__Ldloca_S: code = ILCode.Ldloca; break;
case ILCode.__Stloc_S: code = ILCode.Stloc; break;
case ILCode.__Ldc_I4_M1: code = ILCode.Ldc_I4; operand = -1; break;
case ILCode.__Ldc_I4_0: code = ILCode.Ldc_I4; operand = 0; break;
case ILCode.__Ldc_I4_1: code = ILCode.Ldc_I4; operand = 1; break;
case ILCode.__Ldc_I4_2: code = ILCode.Ldc_I4; operand = 2; break;
case ILCode.__Ldc_I4_3: code = ILCode.Ldc_I4; operand = 3; break;
case ILCode.__Ldc_I4_4: code = ILCode.Ldc_I4; operand = 4; break;
case ILCode.__Ldc_I4_5: code = ILCode.Ldc_I4; operand = 5; break;
case ILCode.__Ldc_I4_6: code = ILCode.Ldc_I4; operand = 6; break;
case ILCode.__Ldc_I4_7: code = ILCode.Ldc_I4; operand = 7; break;
case ILCode.__Ldc_I4_8: code = ILCode.Ldc_I4; operand = 8; break;
case ILCode.__Ldc_I4_S: code = ILCode.Ldc_I4; operand = (int) (sbyte) operand; break;
case ILCode.__Br_S: code = ILCode.Br; break;
case ILCode.__Brfalse_S: code = ILCode.__Brfalse; break;
case ILCode.__Brtrue_S: code = ILCode.Brtrue; break;
case ILCode.__Beq_S: code = ILCode.__Beq; break;
case ILCode.__Bge_S: code = ILCode.__Bge; break;
case ILCode.__Bgt_S: code = ILCode.__Bgt; break;
case ILCode.__Ble_S: code = ILCode.__Ble; break;
case ILCode.__Blt_S: code = ILCode.__Blt; break;
case ILCode.__Bne_Un_S: code = ILCode.__Bne_Un; break;
case ILCode.__Bge_Un_S: code = ILCode.__Bge_Un; break;
case ILCode.__Bgt_Un_S: code = ILCode.__Bgt_Un; break;
case ILCode.__Ble_Un_S: code = ILCode.__Ble_Un; break;
case ILCode.__Blt_Un_S: code = ILCode.__Blt_Un; break;
case ILCode.__Leave_S: code = ILCode.Leave; break;
case ILCode.__Ldarg_0: code = ILCode.__Ldarg; operand = methodBody.GetParameter(0); break;
case ILCode.__Ldarg_1: code = ILCode.__Ldarg; operand = methodBody.GetParameter(1); break;
case ILCode.__Ldarg_2: code = ILCode.__Ldarg; operand = methodBody.GetParameter(2); break;
case ILCode.__Ldarg_3: code = ILCode.__Ldarg; operand = methodBody.GetParameter(3); break;
case ILCode.__Ldloc_0: code = ILCode.Ldloc; operand = methodBody.Variables[0]; break;
case ILCode.__Ldloc_1: code = ILCode.Ldloc; operand = methodBody.Variables[1]; break;
case ILCode.__Ldloc_2: code = ILCode.Ldloc; operand = methodBody.Variables[2]; break;
case ILCode.__Ldloc_3: code = ILCode.Ldloc; operand = methodBody.Variables[3]; break;
case ILCode.__Stloc_0: code = ILCode.Stloc; operand = methodBody.Variables[0]; break;
case ILCode.__Stloc_1: code = ILCode.Stloc; operand = methodBody.Variables[1]; break;
case ILCode.__Stloc_2: code = ILCode.Stloc; operand = methodBody.Variables[2]; break;
case ILCode.__Stloc_3: code = ILCode.Stloc; operand = methodBody.Variables[3]; break;
case ILCode.__Ldarg_S: code = ILCode.__Ldarg; break;
case ILCode.__Ldarga_S: code = ILCode.__Ldarga; break;
case ILCode.__Starg_S: code = ILCode.__Starg; break;
case ILCode.__Ldloc_S: code = ILCode.Ldloc; break;
case ILCode.__Ldloca_S: code = ILCode.Ldloca; break;
case ILCode.__Stloc_S: code = ILCode.Stloc; break;
case ILCode.__Ldc_I4_M1: code = ILCode.Ldc_I4; operand = -1; break;
case ILCode.__Ldc_I4_0: code = ILCode.Ldc_I4; operand = 0; break;
case ILCode.__Ldc_I4_1: code = ILCode.Ldc_I4; operand = 1; break;
case ILCode.__Ldc_I4_2: code = ILCode.Ldc_I4; operand = 2; break;
case ILCode.__Ldc_I4_3: code = ILCode.Ldc_I4; operand = 3; break;
case ILCode.__Ldc_I4_4: code = ILCode.Ldc_I4; operand = 4; break;
case ILCode.__Ldc_I4_5: code = ILCode.Ldc_I4; operand = 5; break;
case ILCode.__Ldc_I4_6: code = ILCode.Ldc_I4; operand = 6; break;
case ILCode.__Ldc_I4_7: code = ILCode.Ldc_I4; operand = 7; break;
case ILCode.__Ldc_I4_8: code = ILCode.Ldc_I4; operand = 8; break;
case ILCode.__Ldc_I4_S: code = ILCode.Ldc_I4; operand = (int) (sbyte) operand; break;
case ILCode.__Br_S: code = ILCode.Br; break;
case ILCode.__Brfalse_S: code = ILCode.__Brfalse; break;
case ILCode.__Brtrue_S: code = ILCode.Brtrue; break;
case ILCode.__Beq_S: code = ILCode.__Beq; break;
case ILCode.__Bge_S: code = ILCode.__Bge; break;
case ILCode.__Bgt_S: code = ILCode.__Bgt; break;
case ILCode.__Ble_S: code = ILCode.__Ble; break;
case ILCode.__Blt_S: code = ILCode.__Blt; break;
case ILCode.__Bne_Un_S: code = ILCode.__Bne_Un; break;
case ILCode.__Bge_Un_S: code = ILCode.__Bge_Un; break;
case ILCode.__Bgt_Un_S: code = ILCode.__Bgt_Un; break;
case ILCode.__Ble_Un_S: code = ILCode.__Ble_Un; break;
case ILCode.__Blt_Un_S: code = ILCode.__Blt_Un; break;
case ILCode.__Leave_S: code = ILCode.Leave; break;
case ILCode.__Ldind_I: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.IntPtr; break;
case ILCode.__Ldind_I1: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.SByte; break;
case ILCode.__Ldind_I2: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Int16; break;
case ILCode.__Ldind_I4: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Int32; break;
case ILCode.__Ldind_I8: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Int64; break;
case ILCode.__Ldind_U1: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Byte; break;
case ILCode.__Ldind_U2: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.UInt16; break;
case ILCode.__Ldind_U4: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.UInt32; break;
case ILCode.__Ldind_R4: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Single; break;
case ILCode.__Ldind_R8: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Double; break;
case ILCode.__Stind_I: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.IntPtr; break;
case ILCode.__Stind_I1: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Byte; break;
case ILCode.__Stind_I2: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Int16; break;
case ILCode.__Stind_I4: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Int32; break;
case ILCode.__Stind_I8: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Int64; break;
}
}

72
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -108,7 +108,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -108,7 +108,10 @@ namespace ICSharpCode.Decompiler.ILAst
/// <returns>The inferred type</returns>
TypeReference InferTypeForExpression(ILExpression expr, TypeReference expectedType, bool forceInferChildren = false)
{
expr.ExpectedType = expectedType;
if (expectedType != null && expr.ExpectedType != expectedType) {
expr.ExpectedType = expectedType;
forceInferChildren = true;
}
if (forceInferChildren || expr.InferredType == null)
expr.InferredType = DoInferTypeForExpression(expr, expectedType, forceInferChildren);
return expr.InferredType;
@ -235,25 +238,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -235,25 +238,8 @@ namespace ICSharpCode.Decompiler.ILAst
return GetFieldType((FieldReference)expr.Operand);
#endregion
#region Reference/Pointer instructions
case ILCode.Ldind_I:
case ILCode.Ldind_I1:
case ILCode.Ldind_I2:
case ILCode.Ldind_I4:
case ILCode.Ldind_I8:
case ILCode.Ldind_U1:
case ILCode.Ldind_U2:
case ILCode.Ldind_U4:
case ILCode.Ldind_R4:
case ILCode.Ldind_R8:
case ILCode.Ldind_Ref:
return UnpackPointer(InferTypeForExpression(expr.Arguments[0], null));
case ILCode.Stind_I1:
case ILCode.Stind_I2:
case ILCode.Stind_I4:
case ILCode.Stind_I8:
case ILCode.Stind_R4:
case ILCode.Stind_R8:
case ILCode.Stind_I:
case ILCode.Stind_Ref:
if (forceInferChildren) {
TypeReference elementType = UnpackPointer(InferTypeForExpression(expr.Arguments[0], null));
@ -261,12 +247,18 @@ namespace ICSharpCode.Decompiler.ILAst @@ -261,12 +247,18 @@ namespace ICSharpCode.Decompiler.ILAst
}
return null;
case ILCode.Ldobj:
if (forceInferChildren) {
if (InferTypeForExpression(expr.Arguments[0], new ByReferenceType((TypeReference)expr.Operand)) is PointerType)
InferTypeForExpression(expr.Arguments[0], new PointerType((TypeReference)expr.Operand));
}
return (TypeReference)expr.Operand;
case ILCode.Stobj:
if (forceInferChildren) {
if (InferTypeForExpression(expr.Arguments[0], new ByReferenceType((TypeReference)expr.Operand)) is PointerType)
InferTypeForExpression(expr.Arguments[0], new PointerType((TypeReference)expr.Operand));
InferTypeForExpression(expr.Arguments[1], (TypeReference)expr.Operand);
}
return null;
return (TypeReference)expr.Operand;
case ILCode.Initobj:
return null;
case ILCode.DefaultValue:
@ -326,9 +318,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -326,9 +318,9 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Ldc_I4:
if (IsBoolean(expectedType) && ((int)expr.Operand == 0 || (int)expr.Operand == 1))
return typeSystem.Boolean;
return IsIntegerOrEnum(expectedType) ? expectedType : typeSystem.Int32;
return (IsIntegerOrEnum(expectedType) || expectedType is PointerType) ? expectedType : typeSystem.Int32;
case ILCode.Ldc_I8:
return (IsIntegerOrEnum(expectedType)) ? expectedType : typeSystem.Int64;
return (IsIntegerOrEnum(expectedType) || expectedType is PointerType) ? expectedType : typeSystem.Int64;
case ILCode.Ldc_R4:
return typeSystem.Single;
case ILCode.Ldc_R8:
@ -411,43 +403,43 @@ namespace ICSharpCode.Decompiler.ILAst @@ -411,43 +403,43 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Conv_I1:
case ILCode.Conv_Ovf_I1:
case ILCode.Conv_Ovf_I1_Un:
return (GetInformationAmount(expectedType) == 8 && IsSigned(expectedType) == true) ? expectedType : typeSystem.SByte;
return HandleConversion(8, true, expr.Arguments[0], expectedType, typeSystem.Byte);
case ILCode.Conv_I2:
case ILCode.Conv_Ovf_I2:
case ILCode.Conv_Ovf_I2_Un:
return (GetInformationAmount(expectedType) == 16 && IsSigned(expectedType) == true) ? expectedType : typeSystem.Int16;
return HandleConversion(16, true, expr.Arguments[0], expectedType, typeSystem.UInt16);
case ILCode.Conv_I4:
case ILCode.Conv_Ovf_I4:
case ILCode.Conv_Ovf_I4_Un:
return (GetInformationAmount(expectedType) == 32 && IsSigned(expectedType) == true) ? expectedType : typeSystem.Int32;
return HandleConversion(32, true, expr.Arguments[0], expectedType, typeSystem.UInt32);
case ILCode.Conv_I8:
case ILCode.Conv_Ovf_I8:
case ILCode.Conv_Ovf_I8_Un:
return (GetInformationAmount(expectedType) == 64 && IsSigned(expectedType) == true) ? expectedType : typeSystem.Int64;
return HandleConversion(64, true, expr.Arguments[0], expectedType, typeSystem.UInt64);
case ILCode.Conv_U1:
case ILCode.Conv_Ovf_U1:
case ILCode.Conv_Ovf_U1_Un:
return (GetInformationAmount(expectedType) == 8 && IsSigned(expectedType) == false) ? expectedType : typeSystem.Byte;
return HandleConversion(8, false, expr.Arguments[0], expectedType, typeSystem.SByte);
case ILCode.Conv_U2:
case ILCode.Conv_Ovf_U2:
case ILCode.Conv_Ovf_U2_Un:
return (GetInformationAmount(expectedType) == 16 && IsSigned(expectedType) == false) ? expectedType : typeSystem.UInt16;
return HandleConversion(16, false, expr.Arguments[0], expectedType, typeSystem.Int16);
case ILCode.Conv_U4:
case ILCode.Conv_Ovf_U4:
case ILCode.Conv_Ovf_U4_Un:
return (GetInformationAmount(expectedType) == 32 && IsSigned(expectedType) == false) ? expectedType : typeSystem.UInt32;
return HandleConversion(32, false, expr.Arguments[0], expectedType, typeSystem.Int32);
case ILCode.Conv_U8:
case ILCode.Conv_Ovf_U8:
case ILCode.Conv_Ovf_U8_Un:
return (GetInformationAmount(expectedType) == 64 && IsSigned(expectedType) == false) ? expectedType : typeSystem.UInt64;
return HandleConversion(64, false, expr.Arguments[0], expectedType, typeSystem.UInt64);
case ILCode.Conv_I:
case ILCode.Conv_Ovf_I:
case ILCode.Conv_Ovf_I_Un:
return (GetInformationAmount(expectedType) == nativeInt && IsSigned(expectedType) == true) ? expectedType : typeSystem.IntPtr;
return HandleConversion(nativeInt, true, expr.Arguments[0], expectedType, typeSystem.IntPtr);
case ILCode.Conv_U:
case ILCode.Conv_Ovf_U:
case ILCode.Conv_Ovf_U_Un:
return (GetInformationAmount(expectedType) == nativeInt && IsSigned(expectedType) == false) ? expectedType : typeSystem.UIntPtr;
return HandleConversion(nativeInt, false, expr.Arguments[0], expectedType, typeSystem.UIntPtr);
case ILCode.Conv_R4:
return typeSystem.Single;
case ILCode.Conv_R8:
@ -519,6 +511,24 @@ namespace ICSharpCode.Decompiler.ILAst @@ -519,6 +511,24 @@ namespace ICSharpCode.Decompiler.ILAst
}
}
TypeReference HandleConversion(int targetBitSize, bool targetSigned, ILExpression arg, TypeReference expectedType, TypeReference targetType)
{
if (targetBitSize >= nativeInt && expectedType is PointerType) {
InferTypeForExpression(arg, expectedType);
return expectedType;
}
TypeReference argType = InferTypeForExpression(arg, null);
if (targetBitSize >= nativeInt && argType is ByReferenceType) {
// conv instructions on managed references mean that the GC should stop tracking them, so they become pointers:
PointerType ptrType = new PointerType(((ByReferenceType)argType).ElementType);
InferTypeForExpression(arg, ptrType);
return ptrType;
} else if (targetBitSize >= nativeInt && argType is PointerType) {
return argType;
}
return (GetInformationAmount(expectedType) == targetBitSize && IsSigned(expectedType) == targetSigned) ? expectedType : targetType;
}
static TypeReference GetFieldType(FieldReference fieldReference)
{
return SubstituteTypeArgs(UnpackModifiers(fieldReference.FieldType), fieldReference);

3
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
<AssemblyName>ICSharpCode.Decompiler.Tests</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<AppDesignerFolder>Properties</AppDesignerFolder>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<NoStdLib>False</NoStdLib>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
@ -54,6 +54,7 @@ @@ -54,6 +54,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Switch.cs" />
<Compile Include="UnsafeCode.cs" />
<Compile Include="YieldReturn.cs" />
<None Include="Types\S_EnumSamples.cs" />
<None Include="CustomAttributes\S_AssemblyCustomAttribute.cs" />

29
ICSharpCode.Decompiler/Tests/UnsafeCode.cs

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
// 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 UnsafeCode
{
public unsafe long ConvertDoubleToLong(double d)
{
return *(long*)&d;
}
public unsafe int* NullPointer {
get {
return null;
}
}
public unsafe void PassRefParameterAsPointer(ref int p)
{
fixed (int* ptr = &p)
PassPointerAsRefParameter(ptr);
}
public unsafe void PassPointerAsRefParameter(int* p)
{
PassRefParameterAsPointer(ref *p);
}
}
Loading…
Cancel
Save