From a3c241dac642fe7cad3c7525975abcf5f86baeb8 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Tue, 15 Mar 2011 03:32:25 +0100 Subject: [PATCH] Improve handling of pinned variables. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 8 ++++++-- ICSharpCode.Decompiler/Ast/NameVariables.cs | 2 +- .../Disassembler/DisassemblerHelpers.cs | 10 +++++----- ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs | 10 ++++++---- ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs | 4 +++- ICSharpCode.Decompiler/ILAst/ILAstTypes.cs | 4 ++++ ICSharpCode.Decompiler/ILAst/ILCodes.cs | 2 ++ ICSharpCode.Decompiler/ILAst/ILInlining.cs | 2 +- 8 files changed, 28 insertions(+), 14 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index ff308e32e..f0cbdcdcb 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -292,8 +292,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) @@ -799,6 +800,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) { diff --git a/ICSharpCode.Decompiler/Ast/NameVariables.cs b/ICSharpCode.Decompiler/Ast/NameVariables.cs index aabeec440..8feaf16f0 100644 --- a/ICSharpCode.Decompiler/Ast/NameVariables.cs +++ b/ICSharpCode.Decompiler/Ast/NameVariables.cs @@ -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; diff --git a/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs b/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs index 7cbbb7d3b..1b4f680d6 100644 --- a/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs +++ b/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs @@ -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 } 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 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) { diff --git a/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs b/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs index 3109d81e1..552d60a67 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs @@ -479,15 +479,17 @@ namespace ICSharpCode.Decompiler.ILAst TypeReference varType = methodDef.Body.Variables[variableIndex].VariableType; List 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(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 diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs index 45d7731c0..c96e81e4a 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs @@ -699,8 +699,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; diff --git a/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs index 5fbd2e385..3667b529f 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs @@ -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; } } diff --git a/ICSharpCode.Decompiler/ILAst/ILCodes.cs b/ICSharpCode.Decompiler/ILAst/ILCodes.cs index 7d5daed98..ea0569582 100644 --- a/ICSharpCode.Decompiler/ILAst/ILCodes.cs +++ b/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_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; } } diff --git a/ICSharpCode.Decompiler/ILAst/ILInlining.cs b/ICSharpCode.Decompiler/ILAst/ILInlining.cs index b2de137fa..b79287bd6 100644 --- a/ICSharpCode.Decompiler/ILAst/ILInlining.cs +++ b/ICSharpCode.Decompiler/ILAst/ILInlining.cs @@ -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);