void RewriteBody(MethodDefinition method) { var reducer = new BodyReducer(method.Body, Context); // // Temporary inlines any calls which return contant expression // if (!TryInlineBodyDependencies(ref reducer)) { return; } // // This is the main step which evaluates if inlined calls can // produce folded branches. When it finds them the unreachable // branch is replaced with nops. // if (!reducer.RewriteBody()) { return; } Context.LogMessage(MessageContainer.CreateInfoMessage($"Reduced '{reducer.InstructionsReplaced}' instructions in conditional branches for [{method.DeclaringType.Module.Assembly.Name}] method {method.FullName}")); if (method.ReturnType.MetadataType == MetadataType.Void) { return; } // // Re-run the analyzer in case body change rewrote it to constant expression // var analyzer = new ConstantExpressionMethodAnalyzer(method, reducer.FoldedInstructions); if (analyzer.Analyze()) { constExprMethods[method] = analyzer.Result; } }
bool TryInlineBodyDependencies(ref BodyReducer reducer) { bool changed = false; var instructions = reducer.Body.Instructions; Instruction targetResult; for (int i = 0; i < instructions.Count; ++i) { var instr = instructions[i]; switch (instr.OpCode.Code) { case Code.Call: var target = (MethodReference)instr.Operand; var md = target.Resolve(); if (md == null) { break; } if (!md.IsStatic) { break; } if (!constExprMethods.TryGetValue(md, out targetResult)) { break; } if (md.HasParameters) { break; } reducer.Rewrite(i, targetResult); changed = true; break; case Code.Ldsfld: var ftarget = (FieldReference)instr.Operand; var field = ftarget.Resolve(); if (field == null) { break; } if (Context.Annotations.TryGetFieldUserValue(field, out object value)) { targetResult = CodeRewriterStep.CreateConstantResultInstruction(field.FieldType, value); if (targetResult == null) { break; } reducer.Rewrite(i, targetResult); changed = true; } break; case Code.Sizeof: // // sizeof (IntPtr) and sizeof (UIntPtr) are just aliases for IntPtr.Size and UIntPtr.Size // which are simple static properties commonly overwritten. Instead of forcing C# code style // we handle both via static Size property // MethodDefinition sizeOfImpl = null; var operand = (TypeReference)instr.Operand; if (operand.MetadataType == MetadataType.UIntPtr) { sizeOfImpl = UIntPtrSize ?? (UIntPtrSize = FindSizeMethod(operand.Resolve())); } if (operand.MetadataType == MetadataType.IntPtr) { sizeOfImpl = IntPtrSize ?? (IntPtrSize = FindSizeMethod(operand.Resolve())); } if (sizeOfImpl != null && constExprMethods.TryGetValue(sizeOfImpl, out targetResult)) { reducer.Rewrite(i, targetResult); changed = true; } break; } } return(changed); }