From 61de071a175fa766b467c88039a5549b9a0419d0 Mon Sep 17 00:00:00 2001 From: Oleg Stepanischev Date: Mon, 18 Mar 2024 21:57:36 +0300 Subject: [PATCH] Better inlining codegen --- src/InlineMethod.Fody/Helper/OpCodeHelper.cs | 49 ++ .../InlineMethod.Fody.csproj | 2 +- src/InlineMethod.Fody/InlineMethodWeaver.cs | 661 ++++++++++-------- src/InlineMethod.Fody/ModuleWeaver.cs | 8 +- .../InlineMethod.InSolutionWeaver.csproj | 2 +- .../InlineMethod.Tests.csproj | 2 +- src/InlineMethod/InlineMethod.csproj | 2 +- 7 files changed, 448 insertions(+), 278 deletions(-) diff --git a/src/InlineMethod.Fody/Helper/OpCodeHelper.cs b/src/InlineMethod.Fody/Helper/OpCodeHelper.cs index f614de6..0c88e1b 100644 --- a/src/InlineMethod.Fody/Helper/OpCodeHelper.cs +++ b/src/InlineMethod.Fody/Helper/OpCodeHelper.cs @@ -255,6 +255,9 @@ public static bool IsLoadLocA(Instruction instruction) code == Code.Ldloca_S; } + public static bool IsLoadFlda(Instruction instruction) + => instruction.OpCode.Code == Code.Ldflda; + public static bool IsStoreLoc(Instruction instruction) { var code = instruction.OpCode.Code; @@ -277,6 +280,44 @@ public static bool IsLoadArg(Instruction instruction) code == Code.Ldarg_S; } + public static bool IsConv(Instruction instruction) + { + var code = instruction.OpCode.Code; + return code == Code.Conv_I || + code == Code.Conv_I1 || + code == Code.Conv_I2 || + code == Code.Conv_I4 || + code == Code.Conv_I8 || + code == Code.Conv_U || + code == Code.Conv_U1 || + code == Code.Conv_U2 || + code == Code.Conv_U4 || + code == Code.Conv_U8 || + code == Code.Conv_R4 || + code == Code.Conv_R8 || + code == Code.Conv_R_Un || + code == Code.Conv_Ovf_I1_Un || + code == Code.Conv_Ovf_I2_Un || + code == Code.Conv_Ovf_I4_Un || + code == Code.Conv_Ovf_I8_Un || + code == Code.Conv_Ovf_U1_Un || + code == Code.Conv_Ovf_U2_Un || + code == Code.Conv_Ovf_U4_Un || + code == Code.Conv_Ovf_U8_Un || + code == Code.Conv_Ovf_I_Un || + code == Code.Conv_Ovf_U_Un || + code == Code.Conv_Ovf_I1 || + code == Code.Conv_Ovf_I2 || + code == Code.Conv_Ovf_I4 || + code == Code.Conv_Ovf_I8 || + code == Code.Conv_Ovf_U1 || + code == Code.Conv_Ovf_U2 || + code == Code.Conv_Ovf_U4 || + code == Code.Conv_Ovf_U8 || + code == Code.Conv_Ovf_I || + code == Code.Conv_Ovf_U; + } + public static bool IsLoadArgA(Instruction instruction) => instruction.OpCode.Code == Code.Ldarga || instruction.OpCode.Code == Code.Ldarga_S; @@ -317,10 +358,18 @@ public static IEnumerable GetTargets(Instruction instruction) } } + public static bool HasTargets(Instruction instruction) => instruction.Operand is Instruction || instruction.Operand is Instruction[]; + public static void ReplaceInstruction(Instruction target, Instruction source) { target.OpCode = source.OpCode; target.Operand = source.Operand; } + + public static bool IsSizeOf(Instruction instruction) + => instruction.OpCode.Code == Code.Sizeof; + + public static bool IsLoadFld(Instruction instruction) + => instruction.OpCode.Code == Code.Ldfld; } } diff --git a/src/InlineMethod.Fody/InlineMethod.Fody.csproj b/src/InlineMethod.Fody/InlineMethod.Fody.csproj index d675544..82a784f 100644 --- a/src/InlineMethod.Fody/InlineMethod.Fody.csproj +++ b/src/InlineMethod.Fody/InlineMethod.Fody.csproj @@ -5,7 +5,7 @@ - + diff --git a/src/InlineMethod.Fody/InlineMethodWeaver.cs b/src/InlineMethod.Fody/InlineMethodWeaver.cs index 7744bd5..c22a3a9 100644 --- a/src/InlineMethod.Fody/InlineMethodWeaver.cs +++ b/src/InlineMethod.Fody/InlineMethodWeaver.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Fody; using InlineMethod.Fody.Extensions; using InlineMethod.Fody.Helper; using InlineMethod.Fody.Helper.Cecil; @@ -12,6 +11,14 @@ namespace InlineMethod.Fody { public class InlineMethodWeaver { + private enum ArgStrategy + { + None, + KeepOnStack, + Inline, + Variable, + } + private readonly ModuleWeaver _moduleWeaver; private readonly Instruction _callInstruction; private readonly MethodDefinition _parentMethod; @@ -19,28 +26,37 @@ public class InlineMethodWeaver private readonly ILProcessor _il; private readonly Instruction[] _pushInstructions; private readonly Arg[] _args; + private ArgStack _argStack; private readonly MethodParameters _parameters; private int _firstInnerVariableIndex; - private ArgStack _argStack; private Instruction _firstBodyInstruction; private Instruction _beforeBodyInstruction; - private readonly List _firstLoadArgs; - - private class LoadArgInfo - { - public int Index { get; } - - public LoadArgInfo(int index) - { - Index = index; - } - } private readonly Dictionary _instructionMap = new Dictionary(); private readonly TypeResolver _typeResolver; + private static bool CanInlineInstruction(Instruction instruction, int usages) + => instruction != null && + ( + OpCodeHelper.IsLoadConst(instruction) + || OpCodeHelper.IsLoadArg(instruction) + || OpCodeHelper.IsLoadArgA(instruction) + || OpCodeHelper.IsLoadLoc(instruction) + || OpCodeHelper.IsLoadLocA(instruction) + || OpCodeHelper.IsSizeOf(instruction) + // conv + const/sizeof + || (OpCodeHelper.IsConv(instruction) && (OpCodeHelper.IsLoadConst(instruction.Previous) || + OpCodeHelper.IsSizeOf(instruction.Previous))) + // load fld/flda + inline previous if one/no usage + || (usages <= 1 && (OpCodeHelper.IsLoadFlda(instruction) || OpCodeHelper.IsLoadFld(instruction)) && + CanInlineInstruction(instruction.Previous, usages)) + // convert + inline if one/no usage + || (usages <= 1 && OpCodeHelper.IsConv(instruction) && + CanInlineInstruction(instruction.Previous, usages)) + ); + public InlineMethodWeaver(ModuleWeaver moduleWeaver, Instruction callInstruction, MethodDefinition parentMethod, MethodDefinition method) { @@ -60,7 +76,6 @@ public InlineMethodWeaver(ModuleWeaver moduleWeaver, Instruction callInstruction } _args = new Arg[_pushInstructions.Length]; - _firstLoadArgs = new List(_parameters.Count); _typeResolver = _callInstruction.Operand is MethodReference methodCallReference && methodCallReference is GenericInstanceMethod genericInstanceMethod @@ -127,6 +142,11 @@ public void Consume(Arg arg) { ConsumeAt(_argStack.IndexOf(arg)); } + + public void Push(Arg arg) + { + _argStack.Add(arg); + } } private void CreateArgs() @@ -135,248 +155,12 @@ private void CreateArgs() for (var i = 0; i < _args.Length; i++) { - _args[i] = new Arg(this, i, _pushInstructions[i]); + _args[i] = new Arg(this, i, _pushInstructions[i], _args.Length); } _argStack = new ArgStack(_args); } - private void FinishArgs() - { - // try to keep some args on stack - // todo: check targets and skip - var prevIndex = -1; - foreach (var loadArg in _firstLoadArgs) - { - var loadArgIndex = loadArg.Index; - var arg = _args[loadArgIndex]; - if (!arg.IsDeferred || prevIndex >= loadArgIndex) - { - break; - } - - arg.KeepOnStack = true; - prevIndex = loadArgIndex; - } - - if (!CheckKeepStack()) - { - foreach (var arg in _args) - { - arg.KeepOnStack = false; - } - } - - for (var index = _args.Length - 1; index >= 0; index--) - { - var arg = _args[index]; - arg.Finish(); - } - } - - private bool CheckKeepStack() - { - var argStack = new ArgStack(_args); - - for (var index = _args.Length - 1; index >= 0; index--) - { - var arg = _args[index]; - - if (arg.KeepOnStack) - { - continue; - } - - if (!arg.HasPush) - { - var topArg = argStack.GetTop(); - if (topArg != arg) - { - return false; - } - } - - argStack.Consume(arg); - } - - return true; - } - - private class Arg - { - private readonly InlineMethodWeaver _inlineMethodWeaver; - private readonly int _paramIndex; - private VariableDefinition _variableDefinition; - private readonly Instruction _pushInstruction; - private int _usages; - private Instruction _deferredInstruction; - public bool KeepOnStack { get; set; } - - public bool HasPush => _pushInstruction != null; - - public bool IsDeferred => _deferredInstruction != null; - - public Arg(InlineMethodWeaver inlineMethodWeaver, int paramIndex, Instruction pushInstruction) - { - _inlineMethodWeaver = inlineMethodWeaver; - _paramIndex = paramIndex; - _pushInstruction = pushInstruction; - } - - private void InsertConsumeTopArg(Instruction instruction) - { - var topArg = _inlineMethodWeaver._argStack.GetTop(); - if (topArg != this) - { - throw new Exception($"Failed to reach argument from stack {_inlineMethodWeaver._method.Name} to {_inlineMethodWeaver._parentMethod.Name}"); - } - - _inlineMethodWeaver.InsertBeforeBody(instruction); - } - - public void Finish() - { - if (_deferredInstruction != null) - { - // keep on stack - if (KeepOnStack) - { - _inlineMethodWeaver.Remove(_deferredInstruction); - _deferredInstruction = null; - return; - } - } - - ProcessDeferred(); - if (_variableDefinition == null) - { - if (CanRemovePush) - { - _inlineMethodWeaver.Remove(_pushInstruction); - } - else - { - // neutralize push instruction - if (_pushInstruction == null) - { - InsertConsumeTopArg(Instruction.Create(OpCodes.Pop)); - } - else - { - for (var i = 0; i < _pushInstruction.GetPushCount(); i++) - { - _inlineMethodWeaver.InsertAfter(_pushInstruction, Instruction.Create(OpCodes.Pop)); - } - } - } - } - else - { - // place store loc - var storeLoc = OpCodeHelper.CreateStoreLoc(_variableDefinition); - if (_pushInstruction == null) - { - InsertConsumeTopArg(storeLoc); - } - else - { - _inlineMethodWeaver.InsertAfter(_pushInstruction, storeLoc); - } - } - - _inlineMethodWeaver._argStack.Consume(this); - } - - // no pops, can be removed safely - private bool CanRemovePush => _pushInstruction != null && _pushInstruction.OpCode.StackBehaviourPop == StackBehaviour.Pop0; - - // inline push - private bool CanInline => _pushInstruction != null && _variableDefinition == null && - (OpCodeHelper.IsLoadConst(_pushInstruction) || OpCodeHelper.IsLoadArg(_pushInstruction) || OpCodeHelper.IsLoadLoc(_pushInstruction)); - - private readonly List _inlinedInstructions = new List(); - - private VariableDefinition GetVariableDefinition() - { - if (_variableDefinition == null) - { - _variableDefinition = new VariableDefinition(_inlineMethodWeaver._parameters[_paramIndex].ParameterType); - _inlineMethodWeaver._parentMethod.Body.Variables.Add(_variableDefinition); - - // revert inline - if (_inlinedInstructions.Count > 0) - { - foreach (var inlinedInstruction in _inlinedInstructions) - { - OpCodeHelper.ReplaceInstruction(inlinedInstruction, OpCodeHelper.CreateLoadLoc(_variableDefinition)); - } - _inlinedInstructions.Clear(); - } - } - - return _variableDefinition; - } - - private void ProcessDeferred() - { - if (_deferredInstruction != null) - { - var ldArgInstruction = GetLdArgInstruction(); - OpCodeHelper.ReplaceInstruction(_deferredInstruction, ldArgInstruction); - if (_inlinedInstructions.Count > 0 && _inlinedInstructions[_inlinedInstructions.Count - 1] == ldArgInstruction) - { - _inlinedInstructions[_inlinedInstructions.Count - 1] = _deferredInstruction; - } - _deferredInstruction = null; - } - } - - private Instruction Defer() - { - _deferredInstruction = Instruction.Create(OpCodes.Nop); - return _deferredInstruction; - } - - private Instruction GetLdArgInstruction() - { - if (CanInline) - { - var ldArgInstruction = OpCodeHelper.Clone(_pushInstruction); - _inlinedInstructions.Add(ldArgInstruction); - return ldArgInstruction; - } - return OpCodeHelper.CreateLoadLoc(GetVariableDefinition()); - } - - public Instruction GetInstruction(Instruction instruction) - { - _usages++; - if (OpCodeHelper.IsLoadArg(instruction)) - { - if (_usages == 1) - { - return Defer(); - } - - ProcessDeferred(); - return GetLdArgInstruction(); - } - - ProcessDeferred(); - if (OpCodeHelper.IsLoadArgA(instruction)) - { - return OpCodeHelper.CreateLoadLocA(GetVariableDefinition()); - } - - if (OpCodeHelper.IsStoreArg(instruction)) - { - return OpCodeHelper.CreateStoreLoc(GetVariableDefinition()); - } - - throw new NotSupportedException($"Unknown arg instruction {instruction.OpCode}"); - } - } - private void CreateVars() { var variables = _parentMethod.Body.Variables; @@ -415,7 +199,7 @@ private void InsertBeforeBody(Instruction instruction) { var target = _firstBodyInstruction ?? _callInstruction; _instructionMap[target] = instruction; - _il.InsertBefore( target, instruction); + _il.InsertBefore(target, instruction); if (_beforeBodyInstruction == null) { _beforeBodyInstruction = instruction; @@ -520,9 +304,8 @@ private void CalcParentMethodOffsets() } } - private IEnumerable GetReferencedInstructions() + private IEnumerable GetReferencedInstructions(Instruction instruction) { - var instruction = _parentMethod.Body.Instructions.FirstOrDefault(); while (instruction != null) { var nextInstruction = instruction.Next; @@ -551,7 +334,7 @@ private void FindSkipArgsReferences() } int closestOffsetBeforeCall = -1; - foreach (var opInstruction in GetReferencedInstructions()) + foreach (var opInstruction in GetReferencedInstructions(_parentMethod.Body.Instructions.FirstOrDefault())) { if (opInstruction == _callInstruction) { @@ -577,17 +360,358 @@ private void FindSkipArgsReferences() } } + private class Arg + { + private readonly InlineMethodWeaver _inlineMethodWeaver; + private readonly int _paramIndex; + private readonly Instruction _pushInstruction; + private readonly int _count; + private int _usages; + private bool _onlyLoad = true; + public int Usages => _usages; + private ArgStrategy _strategy; + public ArgStrategy Strategy => _strategy; + private VariableDefinition _variableDefinition; + public Instruction PushInstruction => _pushInstruction; + private List _allPushInstructions; + + public Arg(InlineMethodWeaver inlineMethodWeaver, int paramIndex, Instruction pushInstruction, int count) + { + _inlineMethodWeaver = inlineMethodWeaver; + _paramIndex = paramIndex; + _pushInstruction = pushInstruction; + _count = count; + } + + public void TrackInstruction(Instruction instruction) + { + _usages++; + if (OpCodeHelper.IsLoadArgA(instruction) || OpCodeHelper.IsStoreArg(instruction)) + { + _onlyLoad = false; + } + } + + private void CreateVariableDefinition() + { + _variableDefinition = new VariableDefinition(_inlineMethodWeaver._parameters[_paramIndex].ParameterType); + _inlineMethodWeaver._parentMethod.Body.Variables.Add(_variableDefinition); + } + + public bool CanKeepOnStack => _onlyLoad && (_usages == 1 || (_usages > 1 && CanDup)); + + private bool IsLast => _count == _paramIndex + 1; + + private bool CanDup => (HasPush && _pushInstruction.GetPushCount() == 1) || IsLast; + + private void InsertConsumeTopArg(Instruction instruction) + { + var topArg = _inlineMethodWeaver._argStack.GetTop(); + if (topArg != this) + { + throw new Exception($"Failed to reach argument from stack {_inlineMethodWeaver._method.Name} to {_inlineMethodWeaver._parentMethod.Name}"); + } + + _inlineMethodWeaver.InsertBeforeBody(instruction); + } + + public void Finish() + { + // keep/dup arg push + if (KeepOnStack) + { + _strategy = ArgStrategy.KeepOnStack; + if (_usages > 1) + { + if (HasPush && _pushInstruction.GetPushCount() == 1) + { + _inlineMethodWeaver.InsertAfter(_pushInstruction, Instruction.Create(OpCodes.Dup)); + } + else + { + InsertConsumeTopArg(Instruction.Create(OpCodes.Dup)); + _inlineMethodWeaver._argStack.Push(this); + } + } + return; + } + + // neutralize arg push + if (CanInline || _usages == 0) + { + _strategy = _usages == 0 ? ArgStrategy.None : ArgStrategy.Inline; + _allPushInstructions = GetAllPushInstructions(); + if (CanRemovePush) + { + foreach (var instruction in _allPushInstructions) + { + _inlineMethodWeaver.Remove(instruction); + } + } + else + { + // neutralize push instruction + if (_pushInstruction == null) + { + InsertConsumeTopArg(Instruction.Create(OpCodes.Pop)); + } + else + { + for (var i = 0; i < _pushInstruction.GetPushCount(); i++) + { + _inlineMethodWeaver.InsertAfter(_pushInstruction, Instruction.Create(OpCodes.Pop)); + } + } + } + + _inlineMethodWeaver._argStack.Consume(this); + return; + } + + _strategy = ArgStrategy.Variable; + CreateVariableDefinition(); + + // place store loc + var storeLoc = OpCodeHelper.CreateStoreLoc(_variableDefinition); + if (_pushInstruction == null) + { + InsertConsumeTopArg(storeLoc); + } + else + { + _inlineMethodWeaver.InsertAfter(_pushInstruction, storeLoc); + } + + _inlineMethodWeaver._argStack.Consume(this); + } + + private List GetAllPushInstructions() + { + if (_pushInstruction == null) + { + return new List(); + } + + var instructions = new List(); + var depth = 0; + var instruction = _pushInstruction; + do + { + instructions.Insert(0, instruction); + + depth += instruction.GetPushCount(); + depth -= instruction.GetPopCount(); + + instruction = instruction.Previous; + } while (depth != 1); + + return instructions; + } + + private IEnumerable GetLdInstructions() + { + switch (_strategy) + { + case ArgStrategy.Variable: + yield return OpCodeHelper.CreateLoadLoc(_variableDefinition); + break; + case ArgStrategy.Inline: + foreach (var instruction in _allPushInstructions) + { + yield return OpCodeHelper.Clone(instruction); + } + break; + case ArgStrategy.KeepOnStack: + break; + } + } + + private bool CanRemovePush => _pushInstruction != null && (_pushInstruction.OpCode.StackBehaviourPop == StackBehaviour.Pop0 || CanInline); + + private bool CanInline => _onlyLoad && CanInlineInstruction(_pushInstruction, _usages); + + public bool HasPush => _pushInstruction != null; + public bool KeepOnStack { get; set; } + + public IEnumerable GetInstructions(Instruction instruction) + { + if (OpCodeHelper.IsLoadArg(instruction)) + { + foreach (var ldInstruction in GetLdInstructions()) + { + yield return ldInstruction; + } + } else if (OpCodeHelper.IsLoadArgA(instruction)) + { + yield return OpCodeHelper.CreateLoadLocA(_variableDefinition); + } else if (OpCodeHelper.IsStoreArg(instruction)) + { + yield return OpCodeHelper.CreateStoreLoc(_variableDefinition); + } + else + { + throw new NotSupportedException($"Unknown arg instruction {instruction.OpCode}"); + } + } + } + + private class LoadArgInfo + { + public int Index { get; } + public int StackDepth { get; } + public int Count { get; private set; } + public int Popped { get; set; } + + public int CurrentDepth => StackDepth + Count - Popped; + + public LoadArgInfo(int index, int stackDepth) + { + Index = index; + StackDepth = stackDepth; + Count++; + } + + public void Increment() + { + Count++; + } + } + + private void AnalyzeArgs() + { + var firstLoadArgs = new List(); + var references = new HashSet( + GetReferencedInstructions(_method.Body.Instructions.FirstOrDefault()) + .Select(i => i.Offset) + ); + + var isInLoadArgs = true; + var instructions = _method.Body.Instructions; + + var stackDepth = 0; + foreach (var instruction in instructions) + { + // targets / references + if (isInLoadArgs && (OpCodeHelper.HasTargets(instruction) || references.Contains(instruction.Offset))) + { + isInLoadArgs = false; + } + + var parameterDefinition = OpCodeHelper.GetArgParameterDefinition(instruction, _parameters); + if (parameterDefinition != null) + { + var index = parameterDefinition.Sequence; + var arg = _args[index]; + arg.TrackInstruction(instruction); + + if (isInLoadArgs) + { + var last = firstLoadArgs.LastOrDefault(); + + if (OpCodeHelper.IsLoadArg(instruction) && + (last?.CurrentDepth ?? 0) == stackDepth && + (last == null || index >= last.Index)) + { + // same index + if (last != null && index == last.Index) + { + last.Increment(); + } + else + { + // cannot use another index after pop + if (last != null && last.Popped > 0) + { + isInLoadArgs = false; + } + else + { + firstLoadArgs.Add(new LoadArgInfo(index, stackDepth)); + } + } + } + else + { + isInLoadArgs = false; + } + } + } + + if (instruction.OpCode.Code != Code.Ret) + { + stackDepth -= instruction.GetPopCount(); + if (isInLoadArgs && instruction.GetPopCount() > 0) + { + var last = firstLoadArgs.LastOrDefault(); + if (last != null) + { + // popped beyond last + if (stackDepth < last.StackDepth) + { + isInLoadArgs = false; + } else + { + // popped some more + var newPopped = last.StackDepth + last.Count - stackDepth; + if (stackDepth < last.StackDepth + last.Count && newPopped > last.Popped) + { + last.Popped = newPopped; + } + } + } + } + + stackDepth += instruction.GetPushCount(); + } + } + + // check keep on stack + AnalyzeKeepOnStack(firstLoadArgs); + + // finish + for (var index = _args.Length - 1; index >= 0; index--) + { + var arg = _args[index]; + arg.Finish(); + } + } + + private void AnalyzeKeepOnStack(List firstLoadArgs) + { + int currentIndex = 0; + foreach (var loadArg in firstLoadArgs) + { + var arg = _args[loadArg.Index]; + if (loadArg.Count != arg.Usages || !arg.CanKeepOnStack) + { + // cannot keep -> stop + return; + } + + for (var i = currentIndex; i < loadArg.Index; i++) + { + if (!_args[i].HasPush) + { + // cannot neutralize push on args before -> stop + return; + } + } + + arg.KeepOnStack = true; + currentIndex = loadArg.Index; + } + } + public void Process() { var callSequencePoint = _parentMethod.DebugInformation.HasSequencePoints ? _parentMethod.DebugInformation.GetSequencePoint(_callInstruction) : null; CreateVars(); CreateArgs(); + AnalyzeArgs(); var innerVariables = _method.Body.Variables; var parentVariables = _parentMethod.Body.Variables; - var isLoadArgs = true; - // inline body var instructions = _method.Body.Instructions; foreach (var instruction in instructions) @@ -600,25 +724,17 @@ public void Process() if (parameterDefinition != null) { var arg = _args[parameterDefinition.Sequence]; - newInstruction = arg.GetInstruction(instruction); - if (isLoadArgs) + bool isFirst = true; + foreach (var argInstruction in arg.GetInstructions(instruction)) { - if (OpCodeHelper.IsLoadArg(instruction) && arg.IsDeferred) - { - _firstLoadArgs.Add(new LoadArgInfo(parameterDefinition.Sequence)); - } - else + if (isFirst) { - isLoadArgs = false; + _instructionMap[instruction] = argInstruction; + isFirst = false; } + AppendToBody(argInstruction); } - } - else - { - if (isLoadArgs && instruction.OpCode != OpCodes.Nop) - { - isLoadArgs = false; - } + continue; } // loc @@ -674,7 +790,6 @@ public void Process() AppendToBody(newInstruction); } - FinishArgs(); Remove(_callInstruction); // replace call target diff --git a/src/InlineMethod.Fody/ModuleWeaver.cs b/src/InlineMethod.Fody/ModuleWeaver.cs index a2b7fe1..8b6e270 100644 --- a/src/InlineMethod.Fody/ModuleWeaver.cs +++ b/src/InlineMethod.Fody/ModuleWeaver.cs @@ -74,7 +74,13 @@ public override void Execute() var attr = GetInlineAttribute(method); if (attr != null) { - var behavior = (InlineBehavior)attr.ConstructorArguments.Single().Value; + var value = attr.ConstructorArguments.Single().Value; + if (value is bool boolValue) + { + value = boolValue ? InlineBehavior.RemovePrivate : InlineBehavior.Keep; + } + + var behavior = (InlineBehavior)value; if ((behavior == InlineBehavior.RemovePrivate && method.IsPrivate) || behavior == InlineBehavior.Remove) { diff --git a/src/InlineMethod.InSolutionWeaver/InlineMethod.InSolutionWeaver.csproj b/src/InlineMethod.InSolutionWeaver/InlineMethod.InSolutionWeaver.csproj index 2b08f6a..2b545e2 100644 --- a/src/InlineMethod.InSolutionWeaver/InlineMethod.InSolutionWeaver.csproj +++ b/src/InlineMethod.InSolutionWeaver/InlineMethod.InSolutionWeaver.csproj @@ -5,7 +5,7 @@ - + diff --git a/src/InlineMethod.Tests/InlineMethod.Tests.csproj b/src/InlineMethod.Tests/InlineMethod.Tests.csproj index 2fca6d5..ceea47c 100644 --- a/src/InlineMethod.Tests/InlineMethod.Tests.csproj +++ b/src/InlineMethod.Tests/InlineMethod.Tests.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/InlineMethod/InlineMethod.csproj b/src/InlineMethod/InlineMethod.csproj index 4432910..ccaa5ce 100644 --- a/src/InlineMethod/InlineMethod.csproj +++ b/src/InlineMethod/InlineMethod.csproj @@ -12,7 +12,7 @@ $(SolutionDir)/../nugets https://github.com/oleg-st/InlineMethod.Fody false - 0.6.2 + 0.7