public void Transform(ILASTTransformer tr) { ModuleDef module = tr.Method.Module; tr.Tree.TraverseTree(Transform, module); for (int i = 0; i < tr.Tree.Count; i++) { IILASTStatement st = tr.Tree[i]; ILASTExpression expr = VariableInlining.GetExpression(st); if (expr == null) { continue; } switch (expr.ILCode) { case Code.Stelem: TransformSTELEM(expr, module, (ITypeDefOrRef)expr.Operand, tr.Tree, ref i); break; case Code.Stelem_I1: TransformSTELEM(expr, module, module.CorLibTypes.SByte.ToTypeDefOrRef(), tr.Tree, ref i); break; case Code.Stelem_I2: TransformSTELEM(expr, module, module.CorLibTypes.Int16.ToTypeDefOrRef(), tr.Tree, ref i); break; case Code.Stelem_I4: TransformSTELEM(expr, module, module.CorLibTypes.Int32.ToTypeDefOrRef(), tr.Tree, ref i); break; case Code.Stelem_I8: TransformSTELEM(expr, module, module.CorLibTypes.Int64.ToTypeDefOrRef(), tr.Tree, ref i); break; case Code.Stelem_R4: TransformSTELEM(expr, module, module.CorLibTypes.Single.ToTypeDefOrRef(), tr.Tree, ref i); break; case Code.Stelem_R8: TransformSTELEM(expr, module, module.CorLibTypes.Double.ToTypeDefOrRef(), tr.Tree, ref i); break; case Code.Stelem_I: TransformSTELEM(expr, module, module.CorLibTypes.IntPtr.ToTypeDefOrRef(), tr.Tree, ref i); break; case Code.Stelem_Ref: TransformSTELEM(expr, module, module.CorLibTypes.Object.ToTypeDefOrRef(), tr.Tree, ref i); break; } } }
public static ILASTExpression GetExpression(IILASTStatement node) { if (node is ILASTExpression expr) { if (expr.ILCode == Code.Pop && expr.Arguments[0] is ILASTExpression) { expr = (ILASTExpression)expr.Arguments[0]; } return(expr); } return(node is ILASTAssignment ? ((ILASTAssignment)node).Value : null); }
public static ILASTExpression GetExpression(IILASTStatement node) { if (node is ILASTExpression) { var expr = (ILASTExpression)node; if (expr.ILCode == Code.Pop && expr.Arguments[0] is ILASTExpression) { expr = (ILASTExpression)expr.Arguments[0]; } return(expr); } else if (node is ILASTAssignment) { return(((ILASTAssignment)node).Value); } else { return(null); } }
public void Transform(ILASTTransformer tr) { var varUsage = new Dictionary <ILASTVariable, int>(); for (int i = 0; i < tr.Tree.Count; i++) { IILASTStatement st = tr.Tree[i]; ILASTExpression expr = GetExpression(st); if (expr == null) { continue; } if (st is ILASTExpression && expr.ILCode == Code.Nop) { tr.Tree.RemoveAt(i); i--; continue; } if (st is ILASTAssignment assignment) { if (Array.IndexOf(tr.Tree.StackRemains, assignment.Variable) != -1) { continue; } Debug.Assert(assignment.Variable.VariableType == ILASTVariableType.StackVar); } foreach (IILASTNode arg in expr.Arguments) { Debug.Assert(arg is ILASTVariable); var argVar = (ILASTVariable)arg; if (argVar.VariableType == ILASTVariableType.StackVar) { varUsage.Increment(argVar); } } } // If a variable is remained on stack, it cannot be inlined since it would be pushed on the stack. foreach (ILASTVariable remain in tr.Tree.StackRemains) { varUsage.Remove(remain); } var simpleVars = new HashSet <ILASTVariable>(varUsage.Where(usage => usage.Value == 1).Select(pair => pair.Key)); bool modified; do { modified = false; for (int i = 0; i < tr.Tree.Count - 1; i++) { if (!(tr.Tree[i] is ILASTAssignment assignment)) { continue; } if (!simpleVars.Contains(assignment.Variable)) { continue; } ILASTExpression expr = GetExpression(tr.Tree[i + 1]); if (expr == null || expr.ILCode.ToOpCode().Name.StartsWith("stelem")) { continue; } for (int argIndex = 0; argIndex < expr.Arguments.Length; argIndex++) { // If previous arguments are not variables (ie. expression), // there might be side-effect inlining succeeding arguments. if (!(expr.Arguments[argIndex] is ILASTVariable argVar)) { break; } if (argVar == assignment.Variable) { expr.Arguments[argIndex] = assignment.Value; tr.Tree.RemoveAt(i); i--; modified = true; break; } } // Ensure the block is processed sequentially. if (modified) { break; } } } while(modified); }