/// <summary> /// Optimize expressions /// </summary> public static void Convert(DecompilerContext context, AstBlock ast, AssemblyCompiler compiler) { // Convert stobj/stind_ref foreach (var node in ast.GetExpressions(x => (x.Arguments.Count == 2) && ((x.Code == AstCode.Stobj) || (x.Code == AstCode.Stind_Ref)))) { var addrNode = node.Arguments[0]; var valueNode = node.Arguments[1]; AstVariable variable; if ((addrNode.GetResultType().IsByReference) && addrNode.Match(AstCode.Ldloc, out variable)) { if (variable.IsThis && valueNode.Match(AstCode.DefaultValue)) { // Struct init : this() node.CopyFrom(new AstExpression(node.SourceLocation, AstCode.Nop, null)); } else if (!variable.IsThis) { // Convert byref type to array type var addrType = (XByReferenceType)addrNode.GetResultType(); var arrayType = new XArrayType(addrType.ElementType); addrNode.ExpectedType = arrayType; addrNode.InferredType = arrayType; // Convert to stelem array, index, value var int32Type = compiler.Module.TypeSystem.Int; node.Arguments.Insert(1, new AstExpression(node.SourceLocation, AstCode.Ldc_I4, 0).SetType(int32Type)); node.Code = arrayType.ElementType.GetStElemCode(); } else { // Convert to stloc } } } // Convert ldobj var resetTypes = false; var processed = new HashSet <AstExpression>(); foreach (var pair in ast.GetExpressionPairs()) { var node = pair.Expression; if ((node.Arguments.Count == 1) && ((node.Code == AstCode.Ldobj) || (node.Code == AstCode.Ldind_Ref))) { var parent = pair.Parent; var useAsValue = true; var isCallArgument = (parent != null) && (parent.Code.IsCall()); var isBoxArgument = (parent != null) && (parent.Match(AstCode.Box)); if (isCallArgument && (node.Code == AstCode.Ldobj)) { if (IsArgByRefOrOut(node, parent)) { useAsValue = false; } } if (isBoxArgument) { var boxType = (XTypeReference)parent.Operand; if (!boxType.IsGenericParameter) { useAsValue = false; } } var ldlocNode = node.Arguments[0]; processed.Add(ldlocNode); var addrNodeType = ldlocNode.GetResultType(); if (ldlocNode.MatchThis()) { useAsValue = false; } if (useAsValue) { if ((addrNodeType.IsByReference) && (ldlocNode.Code == AstCode.Ldloc)) { // Convert byref type to array type var addrType = (XByReferenceType)ldlocNode.GetResultType(); var arrayType = new XArrayType(addrType.ElementType); ldlocNode.ExpectedType = arrayType; ldlocNode.InferredType = arrayType; // Convert to ldelem array, index, value var int32Type = compiler.Module.TypeSystem.Int; node.Arguments.Insert(1, new AstExpression(node.SourceLocation, AstCode.Ldc_I4, 0).SetType(int32Type)); node.Code = arrayType.ElementType.GetLdElemCode(); node.SetType(arrayType.ElementType); resetTypes = true; } } else if (isCallArgument && (ldlocNode.Code == AstCode.Ldloc)) { var typeRef = (XTypeReference)node.Operand; XTypeDefinition typeDef; if ((typeRef != null) && typeRef.TryResolve(out typeDef) && typeDef.IsValueType && !typeDef.IsPrimitive) { // Replace by ldloc node.Code = AstCode.Ldloc; node.Operand = ldlocNode.Operand; node.Arguments.Clear(); } } } else if ((node.Code == AstCode.Ldloc) && ((AstVariable)node.Operand).IsParameter && (node.GetResultType().IsByReference)) { var parent = pair.Parent; if ((parent != null) && (parent.Code == AstCode.Ldobj)) { continue; } var useAsValue = true; var isCallArgument = (parent != null) && (parent.Code.IsCall()); var isBoxArgument = (parent != null) && (parent.Match(AstCode.Box)); if (isCallArgument) { if (IsArgByRefOrOut(node, parent)) { useAsValue = false; } } if (isBoxArgument) { useAsValue = false; } if (node.MatchThis()) { useAsValue = false; } if (useAsValue) { // Convert byref type to array type var addrType = (XByReferenceType)node.GetResultType(); var arrayType = new XArrayType(addrType.ElementType); var clone = new AstExpression(node).SetType(arrayType); // Convert to ldelem array, index, value var int32Type = compiler.Module.TypeSystem.Int; node.SetArguments(clone, new AstExpression(node.SourceLocation, AstCode.Ldc_I4, 0).SetType(int32Type)); node.Code = arrayType.ElementType.GetLdElemCode(); node.SetType(arrayType.ElementType); resetTypes = true; } } } if (resetTypes) { TypeAnalysis.Run(context, ast); } }
public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizationStep abortBeforeStep = ILAstOptimizationStep.None) { this.context = context; this.typeSystem = context.CurrentMethod.Module.TypeSystem; this.method = method; if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode) { return; } RemoveRedundantCode(method); if (abortBeforeStep == ILAstOptimizationStep.ReduceBranchInstructionSet) { return; } foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>()) { ReduceBranchInstructionSet(block); } // ReduceBranchInstructionSet runs before inlining because the non-aggressive inlining heuristic // looks at which type of instruction consumes the inlined variable. if (abortBeforeStep == ILAstOptimizationStep.InlineVariables) { return; } // Works better after simple goto removal because of the following debug pattern: stloc X; br Next; Next:; ldloc X ILInlining inlining1 = new ILInlining(method); inlining1.InlineAllVariables(); if (abortBeforeStep == ILAstOptimizationStep.CopyPropagation) { return; } inlining1.CopyPropagation(); if (abortBeforeStep == ILAstOptimizationStep.YieldReturn) { return; } YieldReturnDecompiler.Run(context, method); if (abortBeforeStep == ILAstOptimizationStep.PropertyAccessInstructions) { return; } IntroducePropertyAccessInstructions(method); if (abortBeforeStep == ILAstOptimizationStep.SplitToMovableBlocks) { return; } foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>()) { SplitToBasicBlocks(block); } if (abortBeforeStep == ILAstOptimizationStep.TypeInference) { return; } // Types are needed for the ternary operator optimization TypeAnalysis.Run(context, method); foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>()) { bool modified; do { modified = false; if (abortBeforeStep == ILAstOptimizationStep.SimplifyShortCircuit) { return; } modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyShortCircuit); if (abortBeforeStep == ILAstOptimizationStep.SimplifyTernaryOperator) { return; } modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyTernaryOperator); if (abortBeforeStep == ILAstOptimizationStep.SimplifyNullCoalescing) { return; } modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyNullCoalescing); if (abortBeforeStep == ILAstOptimizationStep.JoinBasicBlocks) { return; } modified |= block.RunOptimization(new SimpleControlFlow(context, method).JoinBasicBlocks); if (abortBeforeStep == ILAstOptimizationStep.TransformDecimalCtorToConstant) { return; } modified |= block.RunOptimization(TransformDecimalCtorToConstant); modified |= block.RunOptimization(SimplifyLdcI4ConvI8); if (abortBeforeStep == ILAstOptimizationStep.SimplifyLdObjAndStObj) { return; } modified |= block.RunOptimization(SimplifyLdObjAndStObj); if (abortBeforeStep == ILAstOptimizationStep.TransformArrayInitializers) { return; } modified |= block.RunOptimization(TransformArrayInitializers); if (abortBeforeStep == ILAstOptimizationStep.TransformObjectInitializers) { return; } modified |= block.RunOptimization(TransformObjectInitializers); if (abortBeforeStep == ILAstOptimizationStep.MakeAssignmentExpression) { return; } modified |= block.RunOptimization(MakeAssignmentExpression); modified |= block.RunOptimization(MakeCompoundAssignments); if (abortBeforeStep == ILAstOptimizationStep.IntroducePostIncrement) { return; } modified |= block.RunOptimization(IntroducePostIncrement); if (abortBeforeStep == ILAstOptimizationStep.InlineVariables2) { return; } modified |= new ILInlining(method).InlineAllInBlock(block); new ILInlining(method).CopyPropagation(); } while(modified); } if (abortBeforeStep == ILAstOptimizationStep.FindLoops) { return; } foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>()) { new LoopsAndConditions(context).FindLoops(block); } if (abortBeforeStep == ILAstOptimizationStep.FindConditions) { return; } foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>()) { new LoopsAndConditions(context).FindConditions(block); } if (abortBeforeStep == ILAstOptimizationStep.FlattenNestedMovableBlocks) { return; } FlattenBasicBlocks(method); if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode2) { return; } RemoveRedundantCode(method); if (abortBeforeStep == ILAstOptimizationStep.GotoRemoval) { return; } new GotoRemoval().RemoveGotos(method); if (abortBeforeStep == ILAstOptimizationStep.DuplicateReturns) { return; } DuplicateReturnStatements(method); if (abortBeforeStep == ILAstOptimizationStep.ReduceIfNesting) { return; } ReduceIfNesting(method); if (abortBeforeStep == ILAstOptimizationStep.InlineVariables3) { return; } // The 2nd inlining pass is necessary because DuplicateReturns and the introduction of ternary operators // open up additional inlining possibilities. new ILInlining(method).InlineAllVariables(); if (abortBeforeStep == ILAstOptimizationStep.CachedDelegateInitialization) { return; } foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>()) { for (int i = 0; i < block.Body.Count; i++) { // TODO: Move before loops CachedDelegateInitializationWithField(block, ref i); CachedDelegateInitializationWithLocal(block, ref i); } } if (abortBeforeStep == ILAstOptimizationStep.IntroduceFixedStatements) { return; } // we need post-order traversal, not pre-order, for "fixed" to work correctly foreach (ILBlock block in TreeTraversal.PostOrder <ILNode>(method, n => n.GetChildren()).OfType <ILBlock>()) { for (int i = block.Body.Count - 1; i >= 0; i--) { // TODO: Move before loops if (i < block.Body.Count) { IntroduceFixedStatements(block.Body, i); } } } if (abortBeforeStep == ILAstOptimizationStep.RecombineVariables) { return; } RecombineVariables(method); if (abortBeforeStep == ILAstOptimizationStep.TypeInference2) { return; } TypeAnalysis.Reset(method); TypeAnalysis.Run(context, method); if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode3) { return; } GotoRemoval.RemoveRedundantCode(method); // ReportUnassignedILRanges(method); }
public void Optimize(AstOptimizationStep abortBeforeStep = AstOptimizationStep.None) { if (abortBeforeStep == AstOptimizationStep.RemoveRedundantCode) { return; } RemoveRedundantCode(method); if (abortBeforeStep == AstOptimizationStep.ReduceBranchInstructionSet) { return; } foreach (AstBlock block in method.GetSelfAndChildrenRecursive <AstBlock>()) { ReduceBranchInstructionSet(block); } // ReduceBranchInstructionSet runs before inlining because the non-aggressive inlining heuristic // looks at which type of instruction consumes the inlined variable. if (abortBeforeStep == AstOptimizationStep.InlineVariables) { return; } // Works better after simple goto removal because of the following debug pattern: stloc X; br Next; Next:; ldloc X var inlining1 = new AstInlining(method); inlining1.InlineAllVariables(); if (abortBeforeStep == AstOptimizationStep.CopyPropagation) { return; } inlining1.CopyPropagation(); if (abortBeforeStep == AstOptimizationStep.SplitToMovableBlocks) { return; } foreach (var block in method.GetSelfAndChildrenRecursive <AstBlock>()) { SplitToBasicBlocks(block); } if (abortBeforeStep == AstOptimizationStep.TypeInference) { return; } // Types are needed for the ternary operator optimization TypeAnalysis.Run(context, method); foreach (AstBlock block in method.GetSelfAndChildrenRecursive <AstBlock>()) { bool modified; do { modified = false; if (abortBeforeStep == AstOptimizationStep.SimplifyNullCoalescing) { return; } modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyNullCoalescing); if (abortBeforeStep == AstOptimizationStep.JoinBasicBlocks) { return; } modified |= block.RunOptimization(new SimpleControlFlow(context, method).JoinBasicBlocks); if (abortBeforeStep == AstOptimizationStep.SimplifyShiftOperators) { return; } modified |= block.RunOptimization(SimplifyShiftOperators); if (abortBeforeStep == AstOptimizationStep.TransformDecimalCtorToConstant) { return; } modified |= block.RunOptimization(TransformDecimalCtorToConstant); modified |= block.RunOptimization(SimplifyLdcI4ConvI8); if (abortBeforeStep == AstOptimizationStep.SimplifyLdObjAndStObj) { return; } modified |= block.RunOptimization(SimplifyLdObjAndStObj); if (abortBeforeStep == AstOptimizationStep.TransformArrayInitializers) { return; } modified |= block.RunOptimization(TransformArrayInitializers); if (abortBeforeStep == AstOptimizationStep.TransformMultidimensionalArrayInitializers) { return; } modified |= block.RunOptimization(TransformMultidimensionalArrayInitializers); if (abortBeforeStep == AstOptimizationStep.MakeAssignmentExpression) { return; } modified |= block.RunOptimization(MakeAssignmentExpression); #if COMPOUNDASSIGNMENT modified |= block.RunOptimization(MakeCompoundAssignments); #endif #if POSTINCREMENT if (abortBeforeStep == AstOptimizationStep.IntroducePostIncrement) { return; } modified |= block.RunOptimization(IntroducePostIncrement); #endif if (abortBeforeStep == AstOptimizationStep.InlineExpressionTreeParameterDeclarations) { return; } if (context.Settings.ExpressionTrees) { modified |= block.RunOptimization(InlineExpressionTreeParameterDeclarations); } if (abortBeforeStep == AstOptimizationStep.InlineVariables2) { return; } modified |= new AstInlining(method).InlineAllInBlock(block); new AstInlining(method).CopyPropagation(); } while (modified); } /*if (abortBeforeStep == AstOptimizationStep.FindLoops) return; * foreach (AstBlock block in method.GetSelfAndChildrenRecursive<AstBlock>()) * { * new LoopsAndConditions(context).FindLoops(block); * } */ /*if (abortBeforeStep == AstOptimizationStep.FindConditions) return; * foreach (AstBlock block in method.GetSelfAndChildrenRecursive<AstBlock>()) * { * new LoopsAndConditions(context).FindConditions(block); * }*/ if (abortBeforeStep == AstOptimizationStep.FlattenNestedMovableBlocks) { return; } FlattenBasicBlocks(method); if (abortBeforeStep == AstOptimizationStep.RemoveEndFinally) { return; } RemoveEndFinally(method); if (abortBeforeStep == AstOptimizationStep.RemoveRedundantCode2) { return; } RemoveRedundantCode(method); if (abortBeforeStep == AstOptimizationStep.GotoRemoval) { return; } new GotoRemoval().RemoveGotos(method); if (abortBeforeStep == AstOptimizationStep.DuplicateReturns) { return; } DuplicateReturnStatements(method); if (abortBeforeStep == AstOptimizationStep.GotoRemoval2) { return; } new GotoRemoval().RemoveGotos(method); if (abortBeforeStep == AstOptimizationStep.InlineVariables3) { return; } // The 2nd inlining pass is necessary because DuplicateReturns and the introduction of ternary operators // open up additional inlining possibilities. new AstInlining(method).InlineAllVariables(); if (abortBeforeStep == AstOptimizationStep.RecombineVariables) { return; } //RecombineVariables(method); // We do not recombine variables because the RL code depends on it. if (abortBeforeStep == AstOptimizationStep.TypeInference2) { return; } TypeAnalysis.Reset(method); TypeAnalysis.Run(context, method); if (abortBeforeStep == AstOptimizationStep.RemoveRedundantCode3) { return; } GotoRemoval.RemoveRedundantCode(method); // ReportUnassignedILRanges(method); }