Esempio n. 1
0
        public override MethodDefinition BeforeMethod(MethodDefinition method)
        {
            if (!method.HasBody)
            {
                return(method);
            }

            var calls = new List <(Instruction instruction, FieldDefinition instanceField)>();

            foreach (var i in method.Body.Instructions)
            {
                if (i.OpCode != OpCodes.Call)
                {
                    continue;
                }

                var key = i.TargetMethod().DeclaringType.FullName;
                if (instanceMap.TryGetValue(key, out var field))
                {
                    calls.Add((i, field));
                }
            }

            if (calls.Count == 0)
            {
                return(method);
            }

            using (var builder = new BodyBuilder(method.Body))
            {
                foreach (var call in calls)
                {
                    var instruction = call.instruction;
                    builder.InsertBefore(instruction, Instruction.Create(OpCodes.Ldsfld, call.instanceField));

                    instruction.OpCode  = OpCodes.Callvirt;
                    instruction.Operand = logMap[instruction.TargetMethod().FullName];
                }
            }

            return(method);
        }
Esempio n. 2
0
        public override MethodDefinition BeforeMethod(MethodDefinition method)
        {
            if (!method.HasBody)
            {
                return(method);
            }

            TryDeclareExceptionsForLoggers(method);
            var calls = callCollector.Collect(method, logDefinitionFactory.IsLogger);

            if (calls.Length == 0)
            {
                return(method);
            }

            var collapsed = calls.SplitToSequences(new SameMethodComparer()).ToList();

            if (collapsed.Count == 0)
            {
                return(method);
            }

            log.Info($"Rewriting {method.FullName}");

            using (var builder = new BodyBuilder(method))
            {
                foreach (var callGroup in collapsed)
                {
                    var theCall = callGroup.First();
                    if (!logDefinitionFactory.TryGet(theCall.Call.TargetMethod().DeclaringType.Resolve(), out var info))
                    {
                        throw new InvalidOperationException("Log info should have been cached");
                    }

                    var start = theCall.StartsAt;                           // where the arguments start
                    var label = builder.DefineLabel();                      // jump target
                    var end   = callGroup.Last().Call;                      // the last call/callvirt in the sequence
                    var field = info.DeclareLoggerIn(method.DeclaringType); // the static field containing the logger instance
                    var guard = info.TryFindGuard(end);                     // the IsXXXEnabled method  (optional)

                    if (guard == null)
                    {
                        log.Warn($"There is no IsXXXEnabled defined for {end.TargetMethod()}, no check will be emitted");
                    }
                    else
                    {
                        builder.InsertBefore(start, Instruction.Create(OpCodes.Ldsfld, field));
                        builder.InsertBefore(start, Instruction.Create(OpCodes.Callvirt, guard));
                        builder.InsertBefore(start, Instruction.Create(OpCodes.Brfalse, label));
                    }

                    var logMethod = info.MapToILog(end);

                    foreach (var call in callGroup)
                    {
                        builder.InsertBefore(call.StartsAt, Instruction.Create(OpCodes.Ldsfld, field));

                        call.Call.OpCode  = OpCodes.Callvirt;
                        call.Call.Operand = logMethod;
                    }

                    if (guard != null)
                    {
                        builder.InsertAfter(end, label);
                    }
                }
            }

            return(method);
        }