Browse Source

Implemented 'fixed' statement for arrays.

pull/100/head
Daniel Grunwald 15 years ago
parent
commit
1b90809728
  1. 15
      ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs
  2. 86
      ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
  3. 3
      ILSpy/CSharpLanguage.cs

15
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,18 @@ 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) public override bool VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression, object data)

86
ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -299,31 +299,99 @@ namespace ICSharpCode.Decompiler.ILAst
{ {
// stloc(pinned_Var, conv.u(ldc.i4(0))) // stloc(pinned_Var, conv.u(ldc.i4(0)))
ILExpression initValue; ILExpression initValue;
ILVariable v; ILVariable pinnedVar;
if (!(block.Body[i].Match(ILCode.Stloc, out v, out initValue) && v.IsPinned)) if (!MatchFixedInitializer(block, i, out pinnedVar, out initValue))
return; return;
// find initialization of v: // find initialization of v:
int j; int j;
for (j = i + 1; j < block.Body.Count; j++) { for (j = i + 1; j < block.Body.Count; j++) {
ILVariable v2; ILVariable v2;
ILExpression storedVal; ILExpression storedVal;
if (block.Body[j].Match(ILCode.Stloc, out v2, out storedVal) && v2 == v) { if (block.Body[j].Match(ILCode.Stloc, out v2, out storedVal) && v2 == pinnedVar) {
if (storedVal.Code == ILCode.Conv_U) if (IsNullOrZero(storedVal)) {
storedVal = storedVal.Arguments[0];
if (storedVal.Code == ILCode.Ldc_I4 && (int)storedVal.Operand == 0) {
// Create fixed statement from i to j // Create fixed statement from i to j
ILFixedStatement stmt = new ILFixedStatement(); 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) 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.RemoveRange(i + 1, j - i); // from j+1 to i (inclusive)
block.Body[i] = stmt; block.Body[i] = stmt;
if (v.Type.IsByReference) if (pinnedVar.Type.IsByReference)
v.Type = new PointerType(((ByReferenceType)v.Type).ElementType); pinnedVar.Type = new PointerType(((ByReferenceType)pinnedVar.Type).ElementType);
break; 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 #endregion
} }
} }

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);

Loading…
Cancel
Save