Browse Source

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

pull/191/merge
Eusebiu Marcu 15 years ago
parent
commit
6da7e66054
  1. 8
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 15
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  3. 4
      ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs
  4. 2
      ICSharpCode.Decompiler/Ast/NameVariables.cs
  5. 31
      ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs
  6. 10
      ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs
  7. 8
      ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
  8. 9
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  9. 35
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  10. 2
      ICSharpCode.Decompiler/ILAst/ILCodes.cs
  11. 2
      ICSharpCode.Decompiler/ILAst/ILInlining.cs
  12. 103
      ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
  13. 134
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  14. 30
      ICSharpCode.Decompiler/Tests/UnsafeCode.cs
  15. 3
      ILSpy/CSharpLanguage.cs
  16. 2
      ILSpy/ILAstLanguage.cs
  17. 2
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/ComposedType.cs
  18. 4
      NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs

8
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -300,8 +300,9 @@ namespace ICSharpCode.Decompiler.Ast
if (type is Mono.Cecil.ByReferenceType) { if (type is Mono.Cecil.ByReferenceType) {
typeIndex++; typeIndex++;
// ignore by reference type (cannot be represented in C#) // by reference type cannot be represented in C#; so we'll represent it as a pointer instead
return ConvertType((type as Mono.Cecil.ByReferenceType).ElementType, typeAttributes, ref typeIndex); return ConvertType((type as Mono.Cecil.ByReferenceType).ElementType, typeAttributes, ref typeIndex)
.MakePointerType();
} else if (type is Mono.Cecil.PointerType) { } else if (type is Mono.Cecil.PointerType) {
typeIndex++; typeIndex++;
return ConvertType((type as Mono.Cecil.PointerType).ElementType, typeAttributes, ref typeIndex) return ConvertType((type as Mono.Cecil.PointerType).ElementType, typeAttributes, ref typeIndex)
@ -850,6 +851,9 @@ namespace ICSharpCode.Decompiler.Ast
if (paramDef.ParameterType is ByReferenceType) { if (paramDef.ParameterType is ByReferenceType) {
astParam.ParameterModifier = (!paramDef.IsIn && paramDef.IsOut) ? ParameterModifier.Out : ParameterModifier.Ref; astParam.ParameterModifier = (!paramDef.IsIn && paramDef.IsOut) ? ParameterModifier.Out : ParameterModifier.Ref;
ComposedType ct = astParam.Type as ComposedType;
if (ct != null && ct.PointerRank > 0)
ct.PointerRank--;
} }
if (paramDef.HasCustomAttributes) { if (paramDef.HasCustomAttributes) {
foreach (CustomAttribute ca in paramDef.CustomAttributes) { foreach (CustomAttribute ca in paramDef.CustomAttributes) {

15
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -181,6 +181,21 @@ namespace ICSharpCode.Decompiler.Ast
tryCatchStmt.CatchClauses.Add(cc); tryCatchStmt.CatchClauses.Add(cc);
} }
yield return tryCatchStmt; yield return tryCatchStmt;
} else if (node is ILFixedStatement) {
ILFixedStatement fixedNode = (ILFixedStatement)node;
ILVariable v;
ILExpression init;
if (!fixedNode.Initializer.Match(ILCode.Stloc, out v, out init))
throw new InvalidOperationException("Fixed initializer must be an assignment to a local variable");
FixedStatement fixedStatement = new FixedStatement();
fixedStatement.Type = AstBuilder.ConvertType(v.Type);
fixedStatement.Variables.Add(
new VariableInitializer {
Name = v.Name,
Initializer = (Expression)TransformExpression(init)
}.WithAnnotation(v));
fixedStatement.EmbeddedStatement = TransformBlock(fixedNode.BodyBlock);
yield return fixedStatement;
} else if (node is ILBlock) { } else if (node is ILBlock) {
yield return TransformBlock((ILBlock)node); yield return TransformBlock((ILBlock)node);
} else if (node is ILComment) { } else if (node is ILComment) {

4
ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs

@ -54,6 +54,10 @@ namespace ICSharpCode.Decompiler.Ast
if (ident != null && ident.Identifier == name && ident.TypeArguments.Count == 0) if (ident != null && ident.Identifier == name && ident.TypeArguments.Count == 0)
return node; return node;
FixedStatement fixedStatement = node as FixedStatement;
if (fixedStatement != null && fixedStatement.Variables.Single().Name == name)
return null; // no need to introduce the variable here
AstNode withinCurrent = FindInsertPos(node.FirstChild, name, allowPassIntoLoops); AstNode withinCurrent = FindInsertPos(node.FirstChild, name, allowPassIntoLoops);
if (withinCurrent != null) { if (withinCurrent != null) {
if (pos == null) { if (pos == null) {

2
ICSharpCode.Decompiler/Ast/NameVariables.cs

@ -216,7 +216,7 @@ namespace ICSharpCode.Decompiler.Ast
string name; string name;
if (type.IsArray) { if (type.IsArray) {
name = "array"; name = "array";
} else if (type.IsPointer) { } else if (type.IsPointer || type.IsByReference) {
name = "ptr"; name = "ptr";
} else if (!typeNameToVariableNameDict.TryGetValue(type.FullName, out name)) { } else if (!typeNameToVariableNameDict.TryGetValue(type.FullName, out name)) {
name = type.Name; name = type.Name;

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

@ -28,6 +28,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
public override bool VisitPointerReferenceExpression(PointerReferenceExpression pointerReferenceExpression, object data) public override bool VisitPointerReferenceExpression(PointerReferenceExpression pointerReferenceExpression, object data)
{ {
base.VisitPointerReferenceExpression(pointerReferenceExpression, data);
return true; return true;
} }
@ -41,10 +42,34 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
public override bool VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data) public override bool VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data)
{ {
if (unaryOperatorExpression.Operator == UnaryOperatorType.Dereference || unaryOperatorExpression.Operator == UnaryOperatorType.AddressOf) base.VisitUnaryOperatorExpression(unaryOperatorExpression, data);
if (unaryOperatorExpression.Operator == UnaryOperatorType.Dereference) {
BinaryOperatorExpression bop = unaryOperatorExpression.Expression as BinaryOperatorExpression;
if (bop != null && bop.Operator == BinaryOperatorType.Add) {
// TODO: transform "*(ptr + int)" to "ptr[int]"
}
return true; return true;
else } else if (unaryOperatorExpression.Operator == UnaryOperatorType.AddressOf) {
return base.VisitUnaryOperatorExpression(unaryOperatorExpression, data); return true;
} else {
return false;
}
}
public override bool VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression, object data)
{
bool result = base.VisitMemberReferenceExpression(memberReferenceExpression, data);
UnaryOperatorExpression uoe = memberReferenceExpression.Target as UnaryOperatorExpression;
if (uoe != null && uoe.Operator == UnaryOperatorType.Dereference) {
PointerReferenceExpression pre = new PointerReferenceExpression();
pre.Target = uoe.Expression.Detach();
pre.MemberName = memberReferenceExpression.MemberName;
memberReferenceExpression.TypeArguments.MoveTo(pre.TypeArguments);
pre.CopyAnnotationsFrom(uoe);
pre.CopyAnnotationsFrom(memberReferenceExpression);
memberReferenceExpression.ReplaceWith(pre);
}
return result;
} }
} }
} }

10
ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs

@ -118,7 +118,7 @@ namespace ICSharpCode.Decompiler.Disassembler
{ {
if (type is PinnedType) { if (type is PinnedType) {
writer.Write("pinned "); writer.Write("pinned ");
type.GetElementType().WriteTo(writer, onlyName, shortName); ((PinnedType)type).ElementType.WriteTo(writer, onlyName, shortName);
} else if (type is ArrayType) { } else if (type is ArrayType) {
ArrayType at = (ArrayType)type; ArrayType at = (ArrayType)type;
at.ElementType.WriteTo(writer, onlyName, shortName); at.ElementType.WriteTo(writer, onlyName, shortName);
@ -128,10 +128,10 @@ namespace ICSharpCode.Decompiler.Disassembler
} else if (type is GenericParameter) { } else if (type is GenericParameter) {
writer.WriteReference(type.Name, type); writer.WriteReference(type.Name, type);
} else if (type is ByReferenceType) { } else if (type is ByReferenceType) {
type.GetElementType().WriteTo(writer, onlyName, shortName); ((ByReferenceType)type).ElementType.WriteTo(writer, onlyName, shortName);
writer.Write('&'); writer.Write('&');
} else if (type is PointerType) { } else if (type is PointerType) {
type.GetElementType().WriteTo(writer, onlyName, shortName); ((PointerType)type).ElementType.WriteTo(writer, onlyName, shortName);
writer.Write('*'); writer.Write('*');
} else if (type is GenericInstanceType) { } else if (type is GenericInstanceType) {
type.GetElementType().WriteTo(writer, onlyName, shortName); type.GetElementType().WriteTo(writer, onlyName, shortName);
@ -147,12 +147,12 @@ namespace ICSharpCode.Decompiler.Disassembler
writer.Write("modopt("); writer.Write("modopt(");
((OptionalModifierType)type).ModifierType.WriteTo(writer, true, shortName); ((OptionalModifierType)type).ModifierType.WriteTo(writer, true, shortName);
writer.Write(") "); writer.Write(") ");
type.GetElementType().WriteTo(writer, onlyName, shortName); ((OptionalModifierType)type).ElementType.WriteTo(writer, onlyName, shortName);
} else if (type is RequiredModifierType) { } else if (type is RequiredModifierType) {
writer.Write("modreq("); writer.Write("modreq(");
((RequiredModifierType)type).ModifierType.WriteTo(writer, true, shortName); ((RequiredModifierType)type).ModifierType.WriteTo(writer, true, shortName);
writer.Write(") "); writer.Write(") ");
type.GetElementType().WriteTo(writer, onlyName, shortName); ((RequiredModifierType)type).ElementType.WriteTo(writer, onlyName, shortName);
} else { } else {
string name = PrimitiveTypeName(type); string name = PrimitiveTypeName(type);
if (name != null) { if (name != null) {

8
ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

@ -487,14 +487,16 @@ namespace ICSharpCode.Decompiler.ILAst
List<VariableInfo> newVars; List<VariableInfo> newVars;
bool isPinned = methodDef.Body.Variables[variableIndex].IsPinned;
// If the variable is pinned, use single variable.
// If any of the loads is from "all", use single variable // If any of the loads is from "all", use single variable
// If any of the loads is ldloca, fallback to single variable as well // If any of the loads is ldloca, fallback to single variable as well
if (loads.Any(b => b.VariablesBefore[variableIndex].StoredByAll || b.Code == ILCode.Ldloca)) { if (isPinned || loads.Any(b => b.VariablesBefore[variableIndex].StoredByAll || b.Code == ILCode.Ldloca)) {
newVars = new List<VariableInfo>(1) { new VariableInfo() { newVars = new List<VariableInfo>(1) { new VariableInfo() {
Variable = new ILVariable() { Variable = new ILVariable() {
Name = "var_" + variableIndex, Name = "var_" + variableIndex,
Type = varType, Type = isPinned ? ((PinnedType)varType).ElementType : varType,
OriginalVariable = methodDef.Body.Variables[variableIndex] OriginalVariable = methodDef.Body.Variables[variableIndex]
}, },
Stores = stores, Stores = stores,
Loads = loads Loads = loads

9
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -125,10 +125,7 @@ namespace ICSharpCode.Decompiler.ILAst
// open up additional inlining possibilities. // open up additional inlining possibilities.
new ILInlining(method).InlineAllVariables(); new ILInlining(method).InlineAllVariables();
foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) { TypeAnalysis.Reset(method);
expr.InferredType = null;
expr.ExpectedType = null;
}
if (abortBeforeStep == ILAstOptimizationStep.PeepholeTransforms) return; if (abortBeforeStep == ILAstOptimizationStep.PeepholeTransforms) return;
PeepholeTransforms.Run(context, method); PeepholeTransforms.Run(context, method);
@ -699,8 +696,10 @@ namespace ICSharpCode.Decompiler.ILAst
{ {
switch(expr.Code) { switch(expr.Code) {
case ILCode.Call: case ILCode.Call:
case ILCode.Calli:
case ILCode.Callvirt: case ILCode.Callvirt:
// property getters can't be expression statements, but all other method calls can be
MethodReference mr = (MethodReference)expr.Operand;
return !mr.Name.StartsWith("get_", StringComparison.Ordinal);
case ILCode.Newobj: case ILCode.Newobj:
case ILCode.Newarr: case ILCode.Newarr:
return true; return true;

35
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -202,6 +202,10 @@ namespace ICSharpCode.Decompiler.ILAst
public VariableDefinition OriginalVariable; public VariableDefinition OriginalVariable;
public ParameterDefinition OriginalParameter; public ParameterDefinition OriginalParameter;
public bool IsPinned {
get { return OriginalVariable != null && OriginalVariable.IsPinned; }
}
public bool IsParameter { public bool IsParameter {
get { return OriginalParameter != null; } get { return OriginalParameter != null; }
} }
@ -346,6 +350,11 @@ namespace ICSharpCode.Decompiler.ILAst
if (this.InferredType != null) { if (this.InferredType != null) {
output.Write(':'); output.Write(':');
this.InferredType.WriteTo(output, true, true); 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; return;
} }
@ -516,4 +525,30 @@ namespace ICSharpCode.Decompiler.ILAst
output.WriteLine("}"); output.WriteLine("}");
} }
} }
public class ILFixedStatement : ILNode
{
public ILExpression Initializer;
public ILBlock BodyBlock;
public override IEnumerable<ILNode> GetChildren()
{
if (this.Initializer != null)
yield return this.Initializer;
if (this.BodyBlock != null)
yield return this.BodyBlock;
}
public override void WriteTo(ITextOutput output)
{
output.Write("fixed (");
if (this.Initializer != null)
this.Initializer.WriteTo(output);
output.WriteLine(") {");
output.Indent();
this.BodyBlock.WriteTo(output);
output.Unindent();
output.WriteLine("}");
}
}
} }

2
ICSharpCode.Decompiler/ILAst/ILCodes.cs

@ -433,6 +433,8 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.__Stind_I2: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Int16; 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_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; case ILCode.__Stind_I8: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Int64; break;
case ILCode.__Stind_R4: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Single; break;
case ILCode.__Stind_R8: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Double; break;
} }
} }

2
ICSharpCode.Decompiler/ILAst/ILInlining.cs

@ -113,7 +113,7 @@ namespace ICSharpCode.Decompiler.ILAst
{ {
ILVariable v; ILVariable v;
ILExpression inlinedExpression; ILExpression inlinedExpression;
if (block.Body[pos].Match(ILCode.Stloc, out v, out inlinedExpression)) { if (block.Body[pos].Match(ILCode.Stloc, out v, out inlinedExpression) && !v.IsPinned) {
if (InlineIfPossible(v, inlinedExpression, block.Body.ElementAtOrDefault(pos+1), aggressive)) { if (InlineIfPossible(v, inlinedExpression, block.Body.ElementAtOrDefault(pos+1), aggressive)) {
// Assign the ranges of the stloc instruction: // Assign the ranges of the stloc instruction:
inlinedExpression.ILRanges.AddRange(((ILExpression)block.Body[pos]).ILRanges); inlinedExpression.ILRanges.AddRange(((ILExpression)block.Body[pos]).ILRanges);

103
ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -30,7 +30,8 @@ namespace ICSharpCode.Decompiler.ILAst
initializerTransforms.TransformArrayInitializers, initializerTransforms.TransformArrayInitializers,
initializerTransforms.TransformCollectionInitializers, initializerTransforms.TransformCollectionInitializers,
transforms.CachedDelegateInitialization, transforms.CachedDelegateInitialization,
transforms.MakeAssignmentExpression transforms.MakeAssignmentExpression,
transforms.IntroduceFixedStatements
}; };
Func<ILExpression, ILExpression>[] exprTransforms = { Func<ILExpression, ILExpression>[] exprTransforms = {
HandleDecimalConstants, HandleDecimalConstants,
@ -292,5 +293,105 @@ namespace ICSharpCode.Decompiler.ILAst
return false; return false;
} }
#endregion #endregion
#region IntroduceFixedStatements
void IntroduceFixedStatements(ILBlock block, ref int i)
{
// stloc(pinned_Var, conv.u(ldc.i4(0)))
ILExpression initValue;
ILVariable pinnedVar;
if (!MatchFixedInitializer(block, i, out pinnedVar, out initValue))
return;
// find initialization of v:
int j;
for (j = i + 1; j < block.Body.Count; j++) {
ILVariable v2;
ILExpression storedVal;
if (block.Body[j].Match(ILCode.Stloc, out v2, out storedVal) && v2 == pinnedVar) {
if (IsNullOrZero(storedVal)) {
// Create fixed statement from i to j
ILFixedStatement stmt = new ILFixedStatement();
stmt.Initializer = initValue;
stmt.BodyBlock = new ILBlock(block.Body.GetRange(i + 1, j - i - 1)); // from i+1 to j-1 (inclusive)
block.Body.RemoveRange(i + 1, j - i); // from j+1 to i (inclusive)
block.Body[i] = stmt;
if (pinnedVar.Type.IsByReference)
pinnedVar.Type = new PointerType(((ByReferenceType)pinnedVar.Type).ElementType);
break;
}
}
}
}
bool IsNullOrZero(ILExpression expr)
{
if (expr.Code == ILCode.Conv_U || expr.Code == ILCode.Conv_I)
expr = expr.Arguments[0];
return (expr.Code == ILCode.Ldc_I4 && (int)expr.Operand == 0) || expr.Code == ILCode.Ldnull;
}
bool MatchFixedInitializer(ILBlock block, int i, out ILVariable pinnedVar, out ILExpression initValue)
{
if (block.Body[i].Match(ILCode.Stloc, out pinnedVar, out initValue)) {
initValue = (ILExpression)block.Body[i];
return pinnedVar.IsPinned;
}
ILCondition ifStmt = block.Body[i] as ILCondition;
ILExpression arrayLoadingExpr;
if (ifStmt != null && MatchFixedArrayInitializerCondition(ifStmt.Condition, out arrayLoadingExpr)) {
ILVariable arrayVariable = (ILVariable)arrayLoadingExpr.Operand;
ILExpression trueValue;
if (ifStmt.TrueBlock != null && ifStmt.TrueBlock.Body.Count == 1
&& ifStmt.TrueBlock.Body[0].Match(ILCode.Stloc, out pinnedVar, out trueValue)
&& pinnedVar.IsPinned && IsNullOrZero(trueValue))
{
ILVariable stlocVar;
ILExpression falseValue;
if (ifStmt.FalseBlock != null && ifStmt.FalseBlock.Body.Count == 1
&& ifStmt.FalseBlock.Body[0].Match(ILCode.Stloc, out stlocVar, out falseValue) && stlocVar == pinnedVar)
{
ILVariable loadedVariable;
if (falseValue.Code == ILCode.Ldelema
&& falseValue.Arguments[0].Match(ILCode.Ldloc, out loadedVariable) && loadedVariable == arrayVariable
&& IsNullOrZero(falseValue.Arguments[1]))
{
initValue = new ILExpression(ILCode.Stloc, pinnedVar, arrayLoadingExpr);
return true;
}
}
}
}
initValue = null;
return false;
}
bool MatchFixedArrayInitializerCondition(ILExpression condition, out ILExpression initValue)
{
ILExpression logicAnd;
ILVariable arrayVar1, arrayVar2;
if (condition.Match(ILCode.LogicNot, out logicAnd) && logicAnd.Code == ILCode.LogicAnd) {
initValue = UnpackDoubleNegation(logicAnd.Arguments[0]);
if (initValue.Match(ILCode.Ldloc, out arrayVar1)) {
ILExpression arrayLength = logicAnd.Arguments[1];
if (arrayLength.Code == ILCode.Conv_I4)
arrayLength = arrayLength.Arguments[0];
if (arrayLength.Code == ILCode.Ldlen && arrayLength.Arguments[0].Match(ILCode.Ldloc, out arrayVar2)) {
return arrayVar1 == arrayVar2;
}
}
}
initValue = null;
return false;
}
ILExpression UnpackDoubleNegation(ILExpression expr)
{
ILExpression negated;
if (expr.Match(ILCode.LogicNot, out negated) && negated.Match(ILCode.LogicNot, out negated))
return negated;
else
return expr;
}
#endregion
} }
} }

134
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -45,24 +45,32 @@ namespace ICSharpCode.Decompiler.ILAst
{ {
ILCondition cond = node as ILCondition; ILCondition cond = node as ILCondition;
if (cond != null) { if (cond != null) {
InferTypeForExpression(cond.Condition, typeSystem.Boolean, false); cond.Condition.ExpectedType = typeSystem.Boolean;
} }
ILWhileLoop loop = node as ILWhileLoop; ILWhileLoop loop = node as ILWhileLoop;
if (loop != null && loop.Condition != null) { if (loop != null && loop.Condition != null) {
InferTypeForExpression(loop.Condition, typeSystem.Boolean, false); loop.Condition.ExpectedType = typeSystem.Boolean;
} }
ILExpression expr = node as ILExpression; ILExpression expr = node as ILExpression;
if (expr != null) { if (expr != null) {
ILVariable v = expr.Operand as ILVariable; foreach (ILExpression store in expr.GetSelfAndChildrenRecursive<ILExpression>(e => e.Code == ILCode.Stloc)) {
if (v != null && v.IsGenerated && v.Type == null && expr.Code == ILCode.Stloc && !inferredVariables.Contains(v) && HasSingleLoad(v)) { ILVariable v = (ILVariable)store.Operand;
// Don't deal with this node or its children yet, if (v.IsGenerated && v.Type == null && !inferredVariables.Contains(v) && HasSingleLoad(v)) {
// wait for the expected type to be inferred first. // Don't deal with this node or its children yet,
// This happens with the arg_... variables introduced by the ILAst - we skip inferring the whole statement, // wait for the expected type to be inferred first.
// and first infer the statement that reads from the arg_... variable. // This happens with the arg_... variables introduced by the ILAst - we skip inferring the whole statement,
// The ldloc inference will write the expected type to the variable, and the next InferRemainingStores() pass // and first infer the statement that reads from the arg_... variable.
// will then infer this statement with the correct expected type. // The ldloc inference will write the expected type to the variable, and the next InferRemainingStores() pass
storedToGeneratedVariables.Add(expr); // will then infer this statement with the correct expected type.
return; 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); bool anyArgumentIsMissingType = expr.Arguments.Any(a => a.InferredType == null);
if (expr.InferredType == null || anyArgumentIsMissingType) if (expr.InferredType == null || anyArgumentIsMissingType)
@ -184,6 +192,8 @@ namespace ICSharpCode.Decompiler.ILAst
Instruction constraint = expr.GetPrefix(Code.Constrained); Instruction constraint = expr.GetPrefix(Code.Constrained);
if (constraint != null) if (constraint != null)
InferTypeForExpression(expr.Arguments[i], new ByReferenceType((TypeReference)constraint.Operand)); InferTypeForExpression(expr.Arguments[i], new ByReferenceType((TypeReference)constraint.Operand));
else if (method.DeclaringType.IsValueType)
InferTypeForExpression(expr.Arguments[i], new ByReferenceType(method.DeclaringType));
else else
InferTypeForExpression(expr.Arguments[i], method.DeclaringType); InferTypeForExpression(expr.Arguments[i], method.DeclaringType);
} else { } else {
@ -247,18 +257,54 @@ namespace ICSharpCode.Decompiler.ILAst
} }
return null; return null;
case ILCode.Ldobj: case ILCode.Ldobj:
if (forceInferChildren) { {
if (InferTypeForExpression(expr.Arguments[0], new ByReferenceType((TypeReference)expr.Operand)) is PointerType) TypeReference type = (TypeReference)expr.Operand;
InferTypeForExpression(expr.Arguments[0], new PointerType((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(type)) is PointerType)
InferTypeForExpression(expr.Arguments[0], new PointerType(type));
}
return type;
} }
return (TypeReference)expr.Operand;
case ILCode.Stobj: case ILCode.Stobj:
if (forceInferChildren) { {
if (InferTypeForExpression(expr.Arguments[0], new ByReferenceType((TypeReference)expr.Operand)) is PointerType) TypeReference operandType = (TypeReference)expr.Operand;
InferTypeForExpression(expr.Arguments[0], new PointerType((TypeReference)expr.Operand)); TypeReference pointerType = InferTypeForExpression(expr.Arguments[0], new ByReferenceType(operandType));
InferTypeForExpression(expr.Arguments[1], (TypeReference)expr.Operand); 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) && IsSigned(elementType) != null && IsSigned(operandType) != null)
operandType = elementType;
}
if (forceInferChildren) {
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: case ILCode.Initobj:
return null; return null;
case ILCode.DefaultValue: case ILCode.DefaultValue:
@ -284,19 +330,19 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Or: case ILCode.Or:
case ILCode.And: case ILCode.And:
case ILCode.Xor: case ILCode.Xor:
return InferArgumentsInBinaryOperator(expr, null); return InferArgumentsInBinaryOperator(expr, null, expectedType);
case ILCode.Add_Ovf: case ILCode.Add_Ovf:
case ILCode.Sub_Ovf: case ILCode.Sub_Ovf:
case ILCode.Mul_Ovf: case ILCode.Mul_Ovf:
case ILCode.Div: case ILCode.Div:
case ILCode.Rem: case ILCode.Rem:
return InferArgumentsInBinaryOperator(expr, true); return InferArgumentsInBinaryOperator(expr, true, expectedType);
case ILCode.Add_Ovf_Un: case ILCode.Add_Ovf_Un:
case ILCode.Sub_Ovf_Un: case ILCode.Sub_Ovf_Un:
case ILCode.Mul_Ovf_Un: case ILCode.Mul_Ovf_Un:
case ILCode.Div_Un: case ILCode.Div_Un:
case ILCode.Rem_Un: case ILCode.Rem_Un:
return InferArgumentsInBinaryOperator(expr, false); return InferArgumentsInBinaryOperator(expr, false, expectedType);
case ILCode.Shl: case ILCode.Shl:
case ILCode.Shr: case ILCode.Shr:
if (forceInferChildren) if (forceInferChildren)
@ -403,31 +449,31 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Conv_I1: case ILCode.Conv_I1:
case ILCode.Conv_Ovf_I1: case ILCode.Conv_Ovf_I1:
case ILCode.Conv_Ovf_I1_Un: 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_I2:
case ILCode.Conv_Ovf_I2: case ILCode.Conv_Ovf_I2:
case ILCode.Conv_Ovf_I2_Un: 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_I4:
case ILCode.Conv_Ovf_I4: case ILCode.Conv_Ovf_I4:
case ILCode.Conv_Ovf_I4_Un: 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_I8:
case ILCode.Conv_Ovf_I8: case ILCode.Conv_Ovf_I8:
case ILCode.Conv_Ovf_I8_Un: 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_U1:
case ILCode.Conv_Ovf_U1: case ILCode.Conv_Ovf_U1:
case ILCode.Conv_Ovf_U1_Un: 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_U2:
case ILCode.Conv_Ovf_U2: case ILCode.Conv_Ovf_U2:
case ILCode.Conv_Ovf_U2_Un: 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_U4:
case ILCode.Conv_Ovf_U4: case ILCode.Conv_Ovf_U4:
case ILCode.Conv_Ovf_U4_Un: 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_U8:
case ILCode.Conv_Ovf_U8: case ILCode.Conv_Ovf_U8:
case ILCode.Conv_Ovf_U8_Un: case ILCode.Conv_Ovf_U8_Un:
@ -458,17 +504,17 @@ namespace ICSharpCode.Decompiler.ILAst
#region Comparison instructions #region Comparison instructions
case ILCode.Ceq: case ILCode.Ceq:
if (forceInferChildren) if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, null); InferArgumentsInBinaryOperator(expr, null, null);
return typeSystem.Boolean; return typeSystem.Boolean;
case ILCode.Clt: case ILCode.Clt:
case ILCode.Cgt: case ILCode.Cgt:
if (forceInferChildren) if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, true); InferArgumentsInBinaryOperator(expr, true, null);
return typeSystem.Boolean; return typeSystem.Boolean;
case ILCode.Clt_Un: case ILCode.Clt_Un:
case ILCode.Cgt_Un: case ILCode.Cgt_Un:
if (forceInferChildren) if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, false); InferArgumentsInBinaryOperator(expr, false, null);
return typeSystem.Boolean; return typeSystem.Boolean;
#endregion #endregion
#region Branch instructions #region Branch instructions
@ -613,12 +659,12 @@ namespace ICSharpCode.Decompiler.ILAst
return type; return type;
} }
TypeReference InferArgumentsInBinaryOperator(ILExpression expr, bool? isSigned) TypeReference InferArgumentsInBinaryOperator(ILExpression expr, bool? isSigned, TypeReference expectedType)
{ {
ILExpression left = expr.Arguments[0]; ILExpression left = expr.Arguments[0];
ILExpression right = expr.Arguments[1]; ILExpression right = expr.Arguments[1];
TypeReference leftPreferred = DoInferTypeForExpression(left, null); TypeReference leftPreferred = DoInferTypeForExpression(left, expectedType);
TypeReference rightPreferred = DoInferTypeForExpression(right, null); TypeReference rightPreferred = DoInferTypeForExpression(right, expectedType);
if (leftPreferred == rightPreferred) { if (leftPreferred == rightPreferred) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred; return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
} else if (rightPreferred == DoInferTypeForExpression(left, rightPreferred)) { } else if (rightPreferred == DoInferTypeForExpression(left, rightPreferred)) {
@ -768,5 +814,19 @@ namespace ICSharpCode.Decompiler.ILAst
return TypeCode.Object; 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;
}
}
} }
} }

30
ICSharpCode.Decompiler/Tests/UnsafeCode.cs

@ -26,4 +26,34 @@ public class UnsafeCode
{ {
PassRefParameterAsPointer(ref *p); PassRefParameterAsPointer(ref *p);
} }
public unsafe void FixedStringAccess(string text)
{
fixed (char* c = text) {
char* tmp = c;
while (*tmp != 0) {
*tmp = 'A';
tmp++;
}
}
}
public unsafe void PutDoubleIntoLongArray1(long[] array, int index, double val)
{
fixed (long* l = array) {
((double*)l)[index] = val;
}
}
public unsafe void PutDoubleIntoLongArray2(long[] array, int index, double val)
{
fixed (long* l = &array[index]) {
*(double*)l = val;
}
}
public unsafe string PointerReferenceExpression(double* d)
{
return d->ToString();
}
} }

3
ILSpy/CSharpLanguage.cs

@ -408,6 +408,9 @@ namespace ICSharpCode.ILSpy
w.Write("out "); w.Write("out ");
else else
w.Write("ref "); w.Write("ref ");
if (astType is ComposedType && ((ComposedType)astType).PointerRank > 0)
((ComposedType)astType).PointerRank--;
} }
astType.AcceptVisitor(new OutputVisitor(w, new CSharpFormattingPolicy()), null); astType.AcceptVisitor(new OutputVisitor(w, new CSharpFormattingPolicy()), null);

2
ILSpy/ILAstLanguage.cs

@ -66,6 +66,8 @@ namespace ICSharpCode.ILSpy
output.WriteDefinition(v.Name, v); output.WriteDefinition(v.Name, v);
if (v.Type != null) { if (v.Type != null) {
output.Write(" : "); output.Write(" : ");
if (v.IsPinned)
output.Write("pinned ");
v.Type.WriteTo(output, true, true); v.Type.WriteTo(output, true, true);
} }
output.WriteLine(); output.WriteLine();

2
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/ComposedType.cs

@ -55,6 +55,8 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildrenByRole(PointerRole).Count(); return GetChildrenByRole(PointerRole).Count();
} }
set { set {
if (value < 0)
throw new ArgumentOutOfRangeException();
int d = this.PointerRank; int d = this.PointerRank;
while (d > value) { while (d > value) {
GetChildByRole(PointerRole).Remove(); GetChildByRole(PointerRole).Remove();

4
NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs

@ -1387,9 +1387,13 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
StartNode(fixedStatement); StartNode(fixedStatement);
WriteKeyword("fixed"); WriteKeyword("fixed");
Space(policy.UsingParentheses);
LPar(); LPar();
Space(policy.WithinUsingParentheses);
fixedStatement.Type.AcceptVisitor(this, data); fixedStatement.Type.AcceptVisitor(this, data);
Space();
WriteCommaSeparatedList(fixedStatement.Variables); WriteCommaSeparatedList(fixedStatement.Variables);
Space(policy.WithinUsingParentheses);
RPar(); RPar();
WriteEmbeddedStatement(fixedStatement.EmbeddedStatement); WriteEmbeddedStatement(fixedStatement.EmbeddedStatement);
return EndNode(fixedStatement); return EndNode(fixedStatement);

Loading…
Cancel
Save