Browse Source

Fix type analysis bugs.

pull/100/head
Daniel Grunwald 15 years ago
parent
commit
b41ee3ca88
  1. 5
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  2. 5
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  3. 112
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  4. 11
      ICSharpCode.Decompiler/Tests/UnsafeCode.cs

5
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -125,10 +125,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -125,10 +125,7 @@ namespace ICSharpCode.Decompiler.ILAst
// open up additional inlining possibilities.
new ILInlining(method).InlineAllVariables();
foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
expr.InferredType = null;
expr.ExpectedType = null;
}
TypeAnalysis.Reset(method);
if (abortBeforeStep == ILAstOptimizationStep.PeepholeTransforms) return;
PeepholeTransforms.Run(context, method);

5
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -341,6 +341,11 @@ namespace ICSharpCode.Decompiler.ILAst @@ -341,6 +341,11 @@ namespace ICSharpCode.Decompiler.ILAst
if (this.InferredType != null) {
output.Write(':');
this.InferredType.WriteTo(output, true, true);
if (this.ExpectedType != null && this.ExpectedType.FullName != this.InferredType.FullName) {
output.Write("[exp:");
this.ExpectedType.WriteTo(output, true, true);
output.Write(']');
}
}
return;
}

112
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -45,16 +45,17 @@ namespace ICSharpCode.Decompiler.ILAst @@ -45,16 +45,17 @@ namespace ICSharpCode.Decompiler.ILAst
{
ILCondition cond = node as ILCondition;
if (cond != null) {
InferTypeForExpression(cond.Condition, typeSystem.Boolean, false);
cond.Condition.ExpectedType = typeSystem.Boolean;
}
ILWhileLoop loop = node as ILWhileLoop;
if (loop != null && loop.Condition != null) {
InferTypeForExpression(loop.Condition, typeSystem.Boolean, false);
loop.Condition.ExpectedType = typeSystem.Boolean;
}
ILExpression expr = node as ILExpression;
if (expr != null) {
ILVariable v = expr.Operand as ILVariable;
if (v != null && v.IsGenerated && v.Type == null && expr.Code == ILCode.Stloc && !inferredVariables.Contains(v) && HasSingleLoad(v)) {
foreach (ILExpression store in expr.GetSelfAndChildrenRecursive<ILExpression>(e => e.Code == ILCode.Stloc)) {
ILVariable v = (ILVariable)store.Operand;
if (v.IsGenerated && v.Type == null && !inferredVariables.Contains(v) && HasSingleLoad(v)) {
// Don't deal with this node or its children yet,
// wait for the expected type to be inferred first.
// This happens with the arg_... variables introduced by the ILAst - we skip inferring the whole statement,
@ -62,8 +63,15 @@ namespace ICSharpCode.Decompiler.ILAst @@ -62,8 +63,15 @@ namespace ICSharpCode.Decompiler.ILAst
// The ldloc inference will write the expected type to the variable, and the next InferRemainingStores() pass
// will then infer this statement with the correct expected type.
storedToGeneratedVariables.Add(expr);
// However, it is possible that this statement both writes to and reads from the variable (think inlined assignments).
if (expr.GetSelfAndChildrenRecursive<ILExpression>(e => e.Code == ILCode.Ldlen && e.Operand == v).Any()) {
// In this case, we analyze it now anyways, and will re-evaluate it later
break;
} else {
return;
}
}
}
bool anyArgumentIsMissingType = expr.Arguments.Any(a => a.InferredType == null);
if (expr.InferredType == null || anyArgumentIsMissingType)
expr.InferredType = InferTypeForExpression(expr, expr.ExpectedType, forceInferChildren: anyArgumentIsMissingType);
@ -247,18 +255,54 @@ namespace ICSharpCode.Decompiler.ILAst @@ -247,18 +255,54 @@ namespace ICSharpCode.Decompiler.ILAst
}
return null;
case ILCode.Ldobj:
{
TypeReference type = (TypeReference)expr.Operand;
if (expectedType != null) {
int infoAmount = GetInformationAmount(expectedType);
if (infoAmount == 1 && GetInformationAmount(type) == 8) {
// A bool can be loaded from both bytes and sbytes.
type = expectedType;
}
if (infoAmount >= 8 && infoAmount <= 64 && infoAmount == GetInformationAmount(type)) {
// An integer can be loaded as another integer of the same size.
// For integers smaller than 32 bit, the signs must match (as loading performs sign extension)
if (infoAmount >= 32 || IsSigned(expectedType) == IsSigned(type))
type = expectedType;
}
}
if (forceInferChildren) {
if (InferTypeForExpression(expr.Arguments[0], new ByReferenceType((TypeReference)expr.Operand)) is PointerType)
InferTypeForExpression(expr.Arguments[0], new PointerType((TypeReference)expr.Operand));
if (InferTypeForExpression(expr.Arguments[0], new ByReferenceType(type)) is PointerType)
InferTypeForExpression(expr.Arguments[0], new PointerType(type));
}
return type;
}
return (TypeReference)expr.Operand;
case ILCode.Stobj:
{
TypeReference operandType = (TypeReference)expr.Operand;
TypeReference pointerType = InferTypeForExpression(expr.Arguments[0], new ByReferenceType(operandType));
TypeReference elementType;
if (pointerType is PointerType)
elementType = ((PointerType)pointerType).ElementType;
else if (pointerType is ByReferenceType)
elementType = ((ByReferenceType)pointerType).ElementType;
else
elementType = null;
if (elementType != null) {
// An integer can be stored in any other integer of the same size.
int infoAmount = GetInformationAmount(elementType);
if (infoAmount == 1) infoAmount = 8;
if (infoAmount == GetInformationAmount(operandType))
operandType = elementType;
}
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);
if (pointerType is PointerType)
InferTypeForExpression(expr.Arguments[0], new PointerType(operandType));
else if (operandType != expr.Operand)
InferTypeForExpression(expr.Arguments[0], new ByReferenceType(operandType));
InferTypeForExpression(expr.Arguments[1], operandType);
}
return operandType;
}
return (TypeReference)expr.Operand;
case ILCode.Initobj:
return null;
case ILCode.DefaultValue:
@ -284,19 +328,19 @@ namespace ICSharpCode.Decompiler.ILAst @@ -284,19 +328,19 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Or:
case ILCode.And:
case ILCode.Xor:
return InferArgumentsInBinaryOperator(expr, null);
return InferArgumentsInBinaryOperator(expr, null, expectedType);
case ILCode.Add_Ovf:
case ILCode.Sub_Ovf:
case ILCode.Mul_Ovf:
case ILCode.Div:
case ILCode.Rem:
return InferArgumentsInBinaryOperator(expr, true);
return InferArgumentsInBinaryOperator(expr, true, expectedType);
case ILCode.Add_Ovf_Un:
case ILCode.Sub_Ovf_Un:
case ILCode.Mul_Ovf_Un:
case ILCode.Div_Un:
case ILCode.Rem_Un:
return InferArgumentsInBinaryOperator(expr, false);
return InferArgumentsInBinaryOperator(expr, false, expectedType);
case ILCode.Shl:
case ILCode.Shr:
if (forceInferChildren)
@ -403,31 +447,31 @@ namespace ICSharpCode.Decompiler.ILAst @@ -403,31 +447,31 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Conv_I1:
case ILCode.Conv_Ovf_I1:
case ILCode.Conv_Ovf_I1_Un:
return HandleConversion(8, true, expr.Arguments[0], expectedType, typeSystem.Byte);
return HandleConversion(8, true, expr.Arguments[0], expectedType, typeSystem.SByte);
case ILCode.Conv_I2:
case ILCode.Conv_Ovf_I2:
case ILCode.Conv_Ovf_I2_Un:
return HandleConversion(16, true, expr.Arguments[0], expectedType, typeSystem.UInt16);
return HandleConversion(16, true, expr.Arguments[0], expectedType, typeSystem.Int16);
case ILCode.Conv_I4:
case ILCode.Conv_Ovf_I4:
case ILCode.Conv_Ovf_I4_Un:
return HandleConversion(32, true, expr.Arguments[0], expectedType, typeSystem.UInt32);
return HandleConversion(32, true, expr.Arguments[0], expectedType, typeSystem.Int32);
case ILCode.Conv_I8:
case ILCode.Conv_Ovf_I8:
case ILCode.Conv_Ovf_I8_Un:
return HandleConversion(64, true, expr.Arguments[0], expectedType, typeSystem.UInt64);
return HandleConversion(64, true, expr.Arguments[0], expectedType, typeSystem.Int64);
case ILCode.Conv_U1:
case ILCode.Conv_Ovf_U1:
case ILCode.Conv_Ovf_U1_Un:
return HandleConversion(8, false, expr.Arguments[0], expectedType, typeSystem.SByte);
return HandleConversion(8, false, expr.Arguments[0], expectedType, typeSystem.Byte);
case ILCode.Conv_U2:
case ILCode.Conv_Ovf_U2:
case ILCode.Conv_Ovf_U2_Un:
return HandleConversion(16, false, expr.Arguments[0], expectedType, typeSystem.Int16);
return HandleConversion(16, false, expr.Arguments[0], expectedType, typeSystem.UInt16);
case ILCode.Conv_U4:
case ILCode.Conv_Ovf_U4:
case ILCode.Conv_Ovf_U4_Un:
return HandleConversion(32, false, expr.Arguments[0], expectedType, typeSystem.Int32);
return HandleConversion(32, false, expr.Arguments[0], expectedType, typeSystem.UInt32);
case ILCode.Conv_U8:
case ILCode.Conv_Ovf_U8:
case ILCode.Conv_Ovf_U8_Un:
@ -458,17 +502,17 @@ namespace ICSharpCode.Decompiler.ILAst @@ -458,17 +502,17 @@ namespace ICSharpCode.Decompiler.ILAst
#region Comparison instructions
case ILCode.Ceq:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, null);
InferArgumentsInBinaryOperator(expr, null, null);
return typeSystem.Boolean;
case ILCode.Clt:
case ILCode.Cgt:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, true);
InferArgumentsInBinaryOperator(expr, true, null);
return typeSystem.Boolean;
case ILCode.Clt_Un:
case ILCode.Cgt_Un:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, false);
InferArgumentsInBinaryOperator(expr, false, null);
return typeSystem.Boolean;
#endregion
#region Branch instructions
@ -613,12 +657,12 @@ namespace ICSharpCode.Decompiler.ILAst @@ -613,12 +657,12 @@ namespace ICSharpCode.Decompiler.ILAst
return type;
}
TypeReference InferArgumentsInBinaryOperator(ILExpression expr, bool? isSigned)
TypeReference InferArgumentsInBinaryOperator(ILExpression expr, bool? isSigned, TypeReference expectedType)
{
ILExpression left = expr.Arguments[0];
ILExpression right = expr.Arguments[1];
TypeReference leftPreferred = DoInferTypeForExpression(left, null);
TypeReference rightPreferred = DoInferTypeForExpression(right, null);
TypeReference leftPreferred = DoInferTypeForExpression(left, expectedType);
TypeReference rightPreferred = DoInferTypeForExpression(right, expectedType);
if (leftPreferred == rightPreferred) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
} else if (rightPreferred == DoInferTypeForExpression(left, rightPreferred)) {
@ -768,5 +812,19 @@ namespace ICSharpCode.Decompiler.ILAst @@ -768,5 +812,19 @@ namespace ICSharpCode.Decompiler.ILAst
return TypeCode.Object;
}
}
/// <summary>
/// Clears the type inference data on the method.
/// </summary>
public static void Reset(ILBlock method)
{
foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
expr.InferredType = null;
expr.ExpectedType = null;
ILVariable v = expr.Operand as ILVariable;
if (v != null && v.IsGenerated)
v.Type = null;
}
}
}
}

11
ICSharpCode.Decompiler/Tests/UnsafeCode.cs

@ -26,4 +26,15 @@ public class UnsafeCode @@ -26,4 +26,15 @@ public class UnsafeCode
{
PassRefParameterAsPointer(ref *p);
}
public unsafe void FixedStringAccess(string text)
{
fixed (char* c = text) {
char* tmp = c;
while (*tmp != 0) {
*tmp = 'A';
tmp++;
}
}
}
}

Loading…
Cancel
Save