Browse Source

Support fixed statement with multiple initializers.

pull/100/head
Daniel Grunwald 14 years ago
parent
commit
3ed0de81f7
  1. 20
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 8
      ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs
  3. 13
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  4. 85
      ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
  5. 9
      ICSharpCode.Decompiler/Tests/UnsafeCode.cs

20
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -178,17 +178,17 @@ namespace ICSharpCode.Decompiler.Ast @@ -178,17 +178,17 @@ namespace ICSharpCode.Decompiler.Ast
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));
foreach (ILExpression initializer in fixedNode.Initializers) {
Debug.Assert(initializer.Code == ILCode.Stloc);
ILVariable v = (ILVariable)initializer.Operand;
fixedStatement.Variables.Add(
new VariableInitializer {
Name = v.Name,
Initializer = (Expression)TransformExpression(initializer.Arguments[0])
}.WithAnnotation(v));
}
fixedStatement.Type = AstBuilder.ConvertType(((ILVariable)fixedNode.Initializers[0].Operand).Type);
fixedStatement.EmbeddedStatement = TransformBlock(fixedNode.BodyBlock);
yield return fixedStatement;
} else if (node is ILBlock) {

8
ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs

@ -55,8 +55,12 @@ namespace ICSharpCode.Decompiler.Ast @@ -55,8 +55,12 @@ namespace ICSharpCode.Decompiler.Ast
return node;
FixedStatement fixedStatement = node as FixedStatement;
if (fixedStatement != null && fixedStatement.Variables.Single().Name == name)
return null; // no need to introduce the variable here
if (fixedStatement != null) {
foreach (VariableInitializer v in fixedStatement.Variables) {
if (v.Name == name)
return null; // no need to introduce the variable here
}
}
AstNode withinCurrent = FindInsertPos(node.FirstChild, name, allowPassIntoLoops);
if (withinCurrent != null) {

13
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -519,13 +519,13 @@ namespace ICSharpCode.Decompiler.ILAst @@ -519,13 +519,13 @@ namespace ICSharpCode.Decompiler.ILAst
public class ILFixedStatement : ILNode
{
public ILExpression Initializer;
public List<ILExpression> Initializers = new List<ILExpression>();
public ILBlock BodyBlock;
public override IEnumerable<ILNode> GetChildren()
{
if (this.Initializer != null)
yield return this.Initializer;
foreach (ILExpression initializer in this.Initializers)
yield return initializer;
if (this.BodyBlock != null)
yield return this.BodyBlock;
}
@ -533,8 +533,11 @@ namespace ICSharpCode.Decompiler.ILAst @@ -533,8 +533,11 @@ namespace ICSharpCode.Decompiler.ILAst
public override void WriteTo(ITextOutput output)
{
output.Write("fixed (");
if (this.Initializer != null)
this.Initializer.WriteTo(output);
for (int i = 0; i < this.Initializers.Count; i++) {
if (i > 0)
output.Write(", ");
this.Initializers[i].WriteTo(output);
}
output.WriteLine(") {");
output.Indent();
this.BodyBlock.WriteTo(output);

85
ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -2,8 +2,10 @@ @@ -2,8 +2,10 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.NRefactory.Utils;
using Mono.Cecil;
@ -297,28 +299,42 @@ namespace ICSharpCode.Decompiler.ILAst @@ -297,28 +299,42 @@ namespace ICSharpCode.Decompiler.ILAst
#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))
int initEndPos;
if (!MatchFixedInitializer(block, i, out pinnedVar, out initValue, out initEndPos))
return;
// find initialization of v:
int j;
for (j = i + 1; j < block.Body.Count; j++) {
ILFixedStatement fixedStmt = block.Body.ElementAtOrDefault(initEndPos) as ILFixedStatement;
if (fixedStmt != null) {
ILExpression expr = fixedStmt.BodyBlock.Body.LastOrDefault() as ILExpression;
if (expr != null && expr.Code == ILCode.Stloc && expr.Operand == pinnedVar && IsNullOrZero(expr.Arguments[0])) {
// we found a second initializer for the existing fixed statement
fixedStmt.Initializers.Insert(0, initValue);
block.Body.RemoveRange(i, initEndPos - i);
fixedStmt.BodyBlock.Body.RemoveAt(fixedStmt.BodyBlock.Body.Count - 1);
if (pinnedVar.Type.IsByReference)
pinnedVar.Type = new PointerType(((ByReferenceType)pinnedVar.Type).ElementType);
return;
}
}
// find where pinnedVar is reset to 0:
for (int j = initEndPos; j < block.Body.Count; j++) {
ILVariable v2;
ILExpression storedVal;
// stloc(pinned_Var, conv.u(ldc.i4(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 = 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;
fixedStmt = new ILFixedStatement();
fixedStmt.Initializers.Add(initValue);
fixedStmt.BodyBlock = new ILBlock(block.Body.GetRange(initEndPos, j - initEndPos)); // from initEndPos to j-1 (inclusive)
block.Body.RemoveRange(i + 1, j - i); // from i+1 to j (inclusive)
block.Body[i] = fixedStmt;
if (pinnedVar.Type.IsByReference)
pinnedVar.Type = new PointerType(((ByReferenceType)pinnedVar.Type).ElementType);
HandleStringFixing(stmt);
break;
}
}
@ -332,11 +348,13 @@ namespace ICSharpCode.Decompiler.ILAst @@ -332,11 +348,13 @@ namespace ICSharpCode.Decompiler.ILAst
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)
bool MatchFixedInitializer(ILBlock block, int i, out ILVariable pinnedVar, out ILExpression initValue, out int nextPos)
{
if (block.Body[i].Match(ILCode.Stloc, out pinnedVar, out initValue)) {
if (block.Body[i].Match(ILCode.Stloc, out pinnedVar, out initValue) && pinnedVar.IsPinned) {
initValue = (ILExpression)block.Body[i];
return pinnedVar.IsPinned;
nextPos = i + 1;
HandleStringFixing(pinnedVar, block.Body, ref nextPos, ref initValue);
return true;
}
ILCondition ifStmt = block.Body[i] as ILCondition;
ILExpression arrayLoadingExpr;
@ -358,12 +376,14 @@ namespace ICSharpCode.Decompiler.ILAst @@ -358,12 +376,14 @@ namespace ICSharpCode.Decompiler.ILAst
&& IsNullOrZero(falseValue.Arguments[1]))
{
initValue = new ILExpression(ILCode.Stloc, pinnedVar, arrayLoadingExpr);
nextPos = i + 1;
return true;
}
}
}
}
initValue = null;
nextPos = -1;
return false;
}
@ -395,7 +415,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -395,7 +415,7 @@ namespace ICSharpCode.Decompiler.ILAst
return expr;
}
void HandleStringFixing(ILFixedStatement fixedStatement)
bool HandleStringFixing(ILVariable pinnedVar, List<ILNode> body, ref int pos, ref ILExpression fixedStmtInitializer)
{
// fixed (stloc(pinnedVar, ldloc(text))) {
// var1 = var2 = conv.i(ldloc(pinnedVar))
@ -405,43 +425,42 @@ namespace ICSharpCode.Decompiler.ILAst @@ -405,43 +425,42 @@ namespace ICSharpCode.Decompiler.ILAst
// stloc(ptrVar, var2)
// ...
ILVariable pinnedVar = (ILVariable)fixedStatement.Initializer.Operand;
Debug.Assert(pinnedVar.IsPinned);
var body = fixedStatement.BodyBlock.Body;
if (body.Count < 3)
return;
if (pos >= body.Count)
return false;
ILVariable var1, var2;
ILExpression varAssignment, ptrInitialization;
if (!(body[0].Match(ILCode.Stloc, out var1, out varAssignment) && varAssignment.Match(ILCode.Stloc, out var2, out ptrInitialization)))
return;
if (!(body[pos].Match(ILCode.Stloc, out var1, out varAssignment) && varAssignment.Match(ILCode.Stloc, out var2, out ptrInitialization)))
return false;
if (!(var1.IsGenerated && var2.IsGenerated))
return;
return false;
if (ptrInitialization.Code == ILCode.Conv_I || ptrInitialization.Code == ILCode.Conv_U)
ptrInitialization = ptrInitialization.Arguments[0];
if (!ptrInitialization.MatchLdloc(pinnedVar))
return;
return false;
ILCondition ifStmt = body[1] as ILCondition;
ILCondition ifStmt = body[pos + 1] as ILCondition;
if (!(ifStmt != null && ifStmt.TrueBlock != null && ifStmt.TrueBlock.Body.Count == 1 && (ifStmt.FalseBlock == null || ifStmt.FalseBlock.Body.Count == 0)))
return;
return false;
if (!UnpackDoubleNegation(ifStmt.Condition).MatchLdloc(var1))
return;
return false;
ILVariable assignedVar;
ILExpression assignedExpr;
if (!(ifStmt.TrueBlock.Body[0].Match(ILCode.Stloc, out assignedVar, out assignedExpr) && assignedVar == var2 && assignedExpr.Code == ILCode.Add))
return;
return false;
MethodReference calledMethod;
if (!(assignedExpr.Arguments[0].MatchLdloc(var1) && assignedExpr.Arguments[1].Match(ILCode.Call, out calledMethod)))
return;
return false;
if (!(calledMethod.Name == "get_OffsetToStringData" && calledMethod.DeclaringType.FullName == "System.Runtime.CompilerServices.RuntimeHelpers"))
return;
return false;
ILVariable pointerVar;
if (body[2].Match(ILCode.Stloc, out pointerVar, out assignedExpr) && assignedExpr.MatchLdloc(var2)) {
body.RemoveRange(0, 3);
fixedStatement.Initializer.Operand = pointerVar;
if (body[pos + 2].Match(ILCode.Stloc, out pointerVar, out assignedExpr) && assignedExpr.MatchLdloc(var2)) {
pos += 3;
fixedStmtInitializer.Operand = pointerVar;
return true;
}
return false;
}
#endregion
}

9
ICSharpCode.Decompiler/Tests/UnsafeCode.cs

@ -56,4 +56,13 @@ public class UnsafeCode @@ -56,4 +56,13 @@ public class UnsafeCode
{
return d->ToString();
}
public unsafe void FixMultipleStrings(string text)
{
fixed (char* c = text, d = Environment.UserName, e = text) {
*c = 'c';
*d = 'd';
*e = 'e';
}
}
}

Loading…
Cancel
Save