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. 10
      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 @@ -300,8 +300,9 @@ namespace ICSharpCode.Decompiler.Ast
if (type is Mono.Cecil.ByReferenceType) {
typeIndex++;
// ignore by reference type (cannot be represented in C#)
return ConvertType((type as Mono.Cecil.ByReferenceType).ElementType, typeAttributes, ref typeIndex);
// 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)
.MakePointerType();
} else if (type is Mono.Cecil.PointerType) {
typeIndex++;
return ConvertType((type as Mono.Cecil.PointerType).ElementType, typeAttributes, ref typeIndex)
@ -850,6 +851,9 @@ namespace ICSharpCode.Decompiler.Ast @@ -850,6 +851,9 @@ namespace ICSharpCode.Decompiler.Ast
if (paramDef.ParameterType is ByReferenceType) {
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) {
foreach (CustomAttribute ca in paramDef.CustomAttributes) {

15
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -181,6 +181,21 @@ namespace ICSharpCode.Decompiler.Ast @@ -181,6 +181,21 @@ namespace ICSharpCode.Decompiler.Ast
tryCatchStmt.CatchClauses.Add(cc);
}
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) {
yield return TransformBlock((ILBlock)node);
} else if (node is ILComment) {

4
ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs

@ -54,6 +54,10 @@ namespace ICSharpCode.Decompiler.Ast @@ -54,6 +54,10 @@ namespace ICSharpCode.Decompiler.Ast
if (ident != null && ident.Identifier == name && ident.TypeArguments.Count == 0)
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);
if (withinCurrent != null) {
if (pos == null) {

2
ICSharpCode.Decompiler/Ast/NameVariables.cs

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

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

@ -28,6 +28,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -28,6 +28,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
public override bool VisitPointerReferenceExpression(PointerReferenceExpression pointerReferenceExpression, object data)
{
base.VisitPointerReferenceExpression(pointerReferenceExpression, data);
return true;
}
@ -41,10 +42,34 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -41,10 +42,34 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
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;
else
return base.VisitUnaryOperatorExpression(unaryOperatorExpression, data);
} else if (unaryOperatorExpression.Operator == UnaryOperatorType.AddressOf) {
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 @@ -118,7 +118,7 @@ namespace ICSharpCode.Decompiler.Disassembler
{
if (type is PinnedType) {
writer.Write("pinned ");
type.GetElementType().WriteTo(writer, onlyName, shortName);
((PinnedType)type).ElementType.WriteTo(writer, onlyName, shortName);
} else if (type is ArrayType) {
ArrayType at = (ArrayType)type;
at.ElementType.WriteTo(writer, onlyName, shortName);
@ -128,10 +128,10 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -128,10 +128,10 @@ namespace ICSharpCode.Decompiler.Disassembler
} else if (type is GenericParameter) {
writer.WriteReference(type.Name, type);
} else if (type is ByReferenceType) {
type.GetElementType().WriteTo(writer, onlyName, shortName);
((ByReferenceType)type).ElementType.WriteTo(writer, onlyName, shortName);
writer.Write('&');
} else if (type is PointerType) {
type.GetElementType().WriteTo(writer, onlyName, shortName);
((PointerType)type).ElementType.WriteTo(writer, onlyName, shortName);
writer.Write('*');
} else if (type is GenericInstanceType) {
type.GetElementType().WriteTo(writer, onlyName, shortName);
@ -147,12 +147,12 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -147,12 +147,12 @@ namespace ICSharpCode.Decompiler.Disassembler
writer.Write("modopt(");
((OptionalModifierType)type).ModifierType.WriteTo(writer, true, shortName);
writer.Write(") ");
type.GetElementType().WriteTo(writer, onlyName, shortName);
((OptionalModifierType)type).ElementType.WriteTo(writer, onlyName, shortName);
} else if (type is RequiredModifierType) {
writer.Write("modreq(");
((RequiredModifierType)type).ModifierType.WriteTo(writer, true, shortName);
writer.Write(") ");
type.GetElementType().WriteTo(writer, onlyName, shortName);
((RequiredModifierType)type).ElementType.WriteTo(writer, onlyName, shortName);
} else {
string name = PrimitiveTypeName(type);
if (name != null) {

10
ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

@ -486,15 +486,17 @@ namespace ICSharpCode.Decompiler.ILAst @@ -486,15 +486,17 @@ namespace ICSharpCode.Decompiler.ILAst
TypeReference varType = methodDef.Body.Variables[variableIndex].VariableType;
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 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() {
Variable = new ILVariable() {
Name = "var_" + variableIndex,
Type = varType,
OriginalVariable = methodDef.Body.Variables[variableIndex]
Type = isPinned ? ((PinnedType)varType).ElementType : varType,
OriginalVariable = methodDef.Body.Variables[variableIndex]
},
Stores = stores,
Loads = loads

9
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);
@ -699,8 +696,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -699,8 +696,10 @@ namespace ICSharpCode.Decompiler.ILAst
{
switch(expr.Code) {
case ILCode.Call:
case ILCode.Calli:
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.Newarr:
return true;

35
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -202,6 +202,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -202,6 +202,10 @@ namespace ICSharpCode.Decompiler.ILAst
public VariableDefinition OriginalVariable;
public ParameterDefinition OriginalParameter;
public bool IsPinned {
get { return OriginalVariable != null && OriginalVariable.IsPinned; }
}
public bool IsParameter {
get { return OriginalParameter != null; }
}
@ -346,6 +350,11 @@ namespace ICSharpCode.Decompiler.ILAst @@ -346,6 +350,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;
}
@ -516,4 +525,30 @@ namespace ICSharpCode.Decompiler.ILAst @@ -516,4 +525,30 @@ namespace ICSharpCode.Decompiler.ILAst
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 @@ -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_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_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 @@ -113,7 +113,7 @@ namespace ICSharpCode.Decompiler.ILAst
{
ILVariable v;
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)) {
// Assign the ranges of the stloc instruction:
inlinedExpression.ILRanges.AddRange(((ILExpression)block.Body[pos]).ILRanges);

103
ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -30,7 +30,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -30,7 +30,8 @@ namespace ICSharpCode.Decompiler.ILAst
initializerTransforms.TransformArrayInitializers,
initializerTransforms.TransformCollectionInitializers,
transforms.CachedDelegateInitialization,
transforms.MakeAssignmentExpression
transforms.MakeAssignmentExpression,
transforms.IntroduceFixedStatements
};
Func<ILExpression, ILExpression>[] exprTransforms = {
HandleDecimalConstants,
@ -292,5 +293,105 @@ namespace ICSharpCode.Decompiler.ILAst @@ -292,5 +293,105 @@ namespace ICSharpCode.Decompiler.ILAst
return false;
}
#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 @@ -45,24 +45,32 @@ 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)) {
// 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,
// and first infer the statement that reads from the arg_... variable.
// 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);
return;
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,
// and first infer the statement that reads from the arg_... variable.
// 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)
@ -184,6 +192,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -184,6 +192,8 @@ namespace ICSharpCode.Decompiler.ILAst
Instruction constraint = expr.GetPrefix(Code.Constrained);
if (constraint != null)
InferTypeForExpression(expr.Arguments[i], new ByReferenceType((TypeReference)constraint.Operand));
else if (method.DeclaringType.IsValueType)
InferTypeForExpression(expr.Arguments[i], new ByReferenceType(method.DeclaringType));
else
InferTypeForExpression(expr.Arguments[i], method.DeclaringType);
} else {
@ -247,18 +257,54 @@ namespace ICSharpCode.Decompiler.ILAst @@ -247,18 +257,54 @@ 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));
{
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(type)) is PointerType)
InferTypeForExpression(expr.Arguments[0], new PointerType(type));
}
return type;
}
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);
{
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) && 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:
return null;
case ILCode.DefaultValue:
@ -284,19 +330,19 @@ namespace ICSharpCode.Decompiler.ILAst @@ -284,19 +330,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 +449,31 @@ namespace ICSharpCode.Decompiler.ILAst @@ -403,31 +449,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 +504,17 @@ namespace ICSharpCode.Decompiler.ILAst @@ -458,17 +504,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 +659,12 @@ namespace ICSharpCode.Decompiler.ILAst @@ -613,12 +659,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 +814,19 @@ namespace ICSharpCode.Decompiler.ILAst @@ -768,5 +814,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;
}
}
}
}

30
ICSharpCode.Decompiler/Tests/UnsafeCode.cs

@ -26,4 +26,34 @@ public class UnsafeCode @@ -26,4 +26,34 @@ 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++;
}
}
}
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 @@ -408,6 +408,9 @@ namespace ICSharpCode.ILSpy
w.Write("out ");
else
w.Write("ref ");
if (astType is ComposedType && ((ComposedType)astType).PointerRank > 0)
((ComposedType)astType).PointerRank--;
}
astType.AcceptVisitor(new OutputVisitor(w, new CSharpFormattingPolicy()), null);

2
ILSpy/ILAstLanguage.cs

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

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

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

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

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

Loading…
Cancel
Save