From 1b90809728fbbdf7d3dc3b384d01e35f96f0b29e Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Tue, 15 Mar 2011 16:32:01 +0100 Subject: [PATCH] Implemented 'fixed' statement for arrays. --- .../Ast/Transforms/IntroduceUnsafeModifier.cs | 15 +++- .../ILAst/PeepholeTransform.cs | 86 +++++++++++++++++-- ILSpy/CSharpLanguage.cs | 3 + 3 files changed, 92 insertions(+), 12 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs b/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs index b221dada6..fd716eb00 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs @@ -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,18 @@ 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) diff --git a/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs b/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs index 0dc72db93..8fbd47c4d 100644 --- a/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs +++ b/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs @@ -299,31 +299,99 @@ namespace ICSharpCode.Decompiler.ILAst { // stloc(pinned_Var, conv.u(ldc.i4(0))) ILExpression initValue; - ILVariable v; - if (!(block.Body[i].Match(ILCode.Stloc, out v, out initValue) && v.IsPinned)) + 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 == v) { - if (storedVal.Code == ILCode.Conv_U) - storedVal = storedVal.Arguments[0]; - if (storedVal.Code == ILCode.Ldc_I4 && (int)storedVal.Operand == 0) { + 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 = (ILExpression)block.Body[i]; + 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 (v.Type.IsByReference) - v.Type = new PointerType(((ByReferenceType)v.Type).ElementType); + 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 } } diff --git a/ILSpy/CSharpLanguage.cs b/ILSpy/CSharpLanguage.cs index 1234c90be..11bc1b3dc 100644 --- a/ILSpy/CSharpLanguage.cs +++ b/ILSpy/CSharpLanguage.cs @@ -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);