|
|
|
@ -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; |
|
|
|
|
|
|
|
|
|
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 initialization of v:
|
|
|
|
|
int j; |
|
|
|
|
for (j = i + 1; j < block.Body.Count; j++) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
} |
|
|
|
|