Beispiel #1
0
 public void Process(MethodDefinition method, bool returnVoid, ReferenceContainer references)
 {
     try
     {
         InnerProcess(method, returnVoid, references);
     }
     catch (Exception exception)
     {
         throw new Exception(string.Format("An error occurred processing '{0}'. Error: {1}", method.FullName, exception.Message));
     }
 }
Beispiel #2
0
        private void WeaveMethod(MethodDefinition methodDefinition, ReferenceContainer references)
        {
            var asyncAttribute = methodDefinition.CustomAttributes.FirstOrDefault(_ => _.AttributeType.Name == "AsyncStateMachineAttribute");

            if (asyncAttribute == null)
            {
                var returnVoid      = methodDefinition.ReturnType == ModuleDefinition.TypeSystem.Void;
                var methodProcessor = new MethodProcessor();

                methodProcessor.Process(methodDefinition, returnVoid, references);
                return;
            }
            LogError(string.Format("Could not process '{0}'. async methods are not currently supported. Feel free to do it yourself if you want this feature.", methodDefinition.FullName));
        }
Beispiel #3
0
        private Instruction InjectIlForCatch(ILProcessor processor, Instruction beforeReturn, ReferenceContainer references)
        {
            /*
             *  stloc.2
             *
             *  nop
             *  ldloc.2
             *  call void [Yalf]Yalf.Log::TraceException(class [mscorlib]System.Exception)
             *
             *  nop
             *  ldloc.0
             *  ldloc.2
             *  callvirt   instance void [Yalf]Yalf.IContext::PreserveStackTrace(class [mscorlib]System.Exception)
             *
             *  nop
             *  rethrow
             */

            var exceptionVariable = new VariableDefinition(references.ExceptionType);

            body.Variables.Add(exceptionVariable);

            var beginCatch = beforeReturn.Prepend(processor.Create(OpCodes.Stloc, exceptionVariable), processor);

            beginCatch.Append(
                processor.Create(OpCodes.Nop), processor)
            .AppendLdloc(processor, exceptionVariable.Index)
            .Append(processor.Create(OpCodes.Call, references.TraceExceptionMethod), processor)

            .Append(processor.Create(OpCodes.Nop), processor)
            .AppendLdloc(processor, contextVar.Index)
            .AppendLdloc(processor, exceptionVariable.Index)
            .Append(processor.Create(OpCodes.Callvirt, references.PreserveStackTraceMethod), processor)

            .Append(processor.Create(OpCodes.Nop), processor)
            .Append(processor.Create(OpCodes.Rethrow), processor);

            return(beginCatch);
        }
Beispiel #4
0
        void InjectContext(ILProcessor processor, Instruction firstInstruction, MethodDefinition method, ReferenceContainer references)
        {
            /*
             * nop
             * ldstr "Namespace.Class.Method"
             * ldc.i4.1
             * newarr object
             * stloc.s CS$0$0001
             * ldloc.s CS$0$0001
             * ldc.i4.0
             * ldarg.1
             * box int32
             * stelem.ref
             * ldloc.s CS$0$0001
             * call class [Yalf]Yalf.IContext [Yalf]Yalf.Log::MethodContext(string, object[])
             * stloc.0
             */

            contextVar = new VariableDefinition(references.IContextType);
            body.Variables.Insert(0, contextVar);

            int objectParamsArrayIndex = method.AddVariable <object[]>();

            // Generate MethodContext calling method name
            var builder = new StringBuilder();

            builder.Append(string.Join(".",
                                       method.DeclaringType.Namespace,
                                       FormatType(method.DeclaringType),
                                       FormatMethod(method)));

            var current = firstInstruction
                          .Prepend(processor.Create(OpCodes.Ldstr, builder.ToString()), processor);

            // Create object[] for MethodContext
            current = current
                      .AppendLdcI4(processor, method.Parameters.Count)
                      .Append(processor.Create(OpCodes.Newarr, method.Module.ImportType <object>()), processor)
                      .AppendStloc(processor, objectParamsArrayIndex);

            var nonStaticMethodAddOne = method.IsStatic ? 0 : 1;

            // Set object[] values
            for (int i = 0; i < method.Parameters.Count; i++)
            {
                current = current
                          .AppendLdloc(processor, objectParamsArrayIndex)
                          .AppendLdcI4(processor, i);

                var paramType = method.Parameters[i].ParameterType;

                if (paramType.MetadataType == MetadataType.UIntPtr ||
                    paramType.MetadataType == MetadataType.FunctionPointer ||
                    paramType.MetadataType == MetadataType.IntPtr ||
                    paramType.MetadataType == MetadataType.Pointer)
                {
                    // don't store pointer types into object[] (we can't ToString them anyway)
                    // store type name as string instead
                    current = current.AppendLdstr(processor, paramType.FullName);
                }
                else
                {
                    current = current
                              .AppendLdarg(processor, i + nonStaticMethodAddOne)
                              .AppendBoxAndResolveRefIfNecessary(processor, paramType);
                }

                current = current.Append(processor.Create(OpCodes.Stelem_Ref), processor);
            }

            // Call Log.MethodContext
            current
            .AppendLdloc(processor, objectParamsArrayIndex)
            .Append(processor.Create(OpCodes.Call, references.MethodContextMethod), processor)
            .AppendStloc(processor, contextVar.Index);
        }
Beispiel #5
0
        private Instruction InjectIlForFinaly(ILProcessor processor, Instruction beforeReturn, ReferenceContainer references)
        {
            // wrapped in nop (for try catch handling)
            // load context then call dispose

            /*
             *  nop
             *  ldloc.0
             *  callvirt instance void [Yalf]Yalf.IContext::Dispose()
             *  nop
             *  endfinally
             */

            var beginFinally = beforeReturn.Prepend(processor.Create(OpCodes.Nop), processor);

            beginFinally.AppendLdloc(processor, contextVar.Index)
            .Append(processor.Create(OpCodes.Callvirt, references.DisposeMethod), processor)
            .Append(processor.Create(OpCodes.Nop), processor)
            .Append(processor.Create(OpCodes.Endfinally), processor);

            return(beginFinally);
        }
Beispiel #6
0
        private void InjectIlForDispose(ILProcessor processor, Instruction returnInstruction, ReferenceContainer references)
        {
            // load context then call dispose

            /*
             *  nop
             *  ldloc.0
             *  callvirt instance void [Yalf]Yalf.IContext::Dispose()
             *  return mumbo jumbo
             */

            returnInstruction.AppendLdloc(processor, contextVar.Index)
            .Append(processor.Create(OpCodes.Callvirt, references.DisposeMethod), processor);
        }
Beispiel #7
0
        private void InnerProcess(MethodDefinition method, bool returnVoid, ReferenceContainer references)
        {
            body = method.Body;
            body.SimplifyMacros();

            if (body.Instructions.Count <= 3)
                return; // nothing to do (empty method)

            HandleReturnType(method, returnVoid, references);

            var ilProcessor = body.GetILProcessor();

            var firstInstruction = FirstInstructionSkipCtor(method);

            firstInstruction = RejigFirstInstruction(ilProcessor, firstInstruction);

            InjectContext(ilProcessor, firstInstruction, method, references);
            var returnInstruction = FixReturns();

            var beforeReturn = Instruction.Create(OpCodes.Nop);
            ilProcessor.InsertBefore(returnInstruction, beforeReturn);

            // exclude try-catch from constructors (lot's of pain otherwise)
            if (!method.IsConstructor)
            {
                var beginCatch = InjectIlForCatch(ilProcessor, beforeReturn, references);
                var beginFinally = InjectIlForFinaly(ilProcessor, beforeReturn, references);

                var catchHandler = new ExceptionHandler(ExceptionHandlerType.Catch)
                    {
                        TryStart = firstInstruction,
                        TryEnd = beginCatch,
                        CatchType = references.ExceptionType,
                        HandlerStart = beginCatch,
                        HandlerEnd = beginFinally,
                    };

                body.ExceptionHandlers.Add(catchHandler);

                var finallyHandler = new ExceptionHandler(ExceptionHandlerType.Finally)
                    {
                        TryStart = firstInstruction,
                        TryEnd = beginFinally,
                        HandlerStart = beginFinally,
                        HandlerEnd = beforeReturn,
                    };

                body.ExceptionHandlers.Add(finallyHandler);
            }
            else
            {
                InjectIlForDispose(ilProcessor, returnInstruction, references);
            }

            body.InitLocals = true;
            body.OptimizeMacros();
        }
Beispiel #8
0
        private Instruction InjectIlForFinaly(ILProcessor processor, Instruction beforeReturn, ReferenceContainer references)
        {
            // wrapped in nop (for try catch handling)
            // load context then call dispose
            /*
                nop
                ldloc.0
                callvirt instance void [Yalf]Yalf.IContext::Dispose()
                nop
                endfinally
             */

            var beginFinally = beforeReturn.Prepend(processor.Create(OpCodes.Nop), processor);

            beginFinally.AppendLdloc(processor, contextVar.Index)
                .Append(processor.Create(OpCodes.Callvirt, references.DisposeMethod), processor)
                .Append(processor.Create(OpCodes.Nop), processor)
                .Append(processor.Create(OpCodes.Endfinally), processor);

            return beginFinally;
        }
Beispiel #9
0
        private void InjectIlForDispose(ILProcessor processor, Instruction returnInstruction, ReferenceContainer references)
        {
            // load context then call dispose
            /*
                nop
                ldloc.0
                callvirt instance void [Yalf]Yalf.IContext::Dispose()
                return mumbo jumbo
             */

            returnInstruction.AppendLdloc(processor, contextVar.Index)
                        .Append(processor.Create(OpCodes.Callvirt, references.DisposeMethod), processor);
        }
Beispiel #10
0
        private Instruction InjectIlForCatch(ILProcessor processor, Instruction beforeReturn, ReferenceContainer references)
        {
            /*
                stloc.2

                nop
                ldloc.2
                call void [Yalf]Yalf.Log::TraceException(class [mscorlib]System.Exception)

                nop
                ldloc.0
                ldloc.2
                callvirt   instance void [Yalf]Yalf.IContext::PreserveStackTrace(class [mscorlib]System.Exception)

                nop
                rethrow
             */

            var exceptionVariable = new VariableDefinition(references.ExceptionType);
            body.Variables.Add(exceptionVariable);

            var beginCatch = beforeReturn.Prepend(processor.Create(OpCodes.Stloc, exceptionVariable), processor);
            beginCatch.Append(
                           processor.Create(OpCodes.Nop), processor)
                          .AppendLdloc(processor, exceptionVariable.Index)
                          .Append(processor.Create(OpCodes.Call, references.TraceExceptionMethod), processor)

                          .Append(processor.Create(OpCodes.Nop), processor)
                          .AppendLdloc(processor, contextVar.Index)
                          .AppendLdloc(processor, exceptionVariable.Index)
                          .Append(processor.Create(OpCodes.Callvirt, references.PreserveStackTraceMethod), processor)

                          .Append(processor.Create(OpCodes.Nop), processor)
                          .Append(processor.Create(OpCodes.Rethrow), processor);

            return beginCatch;
        }
Beispiel #11
0
        void InjectContext(ILProcessor processor, Instruction firstInstruction, MethodDefinition method, ReferenceContainer references)
        {
            /*
            nop
            ldstr "Namespace.Class.Method"
            ldc.i4.1
            newarr object
            stloc.s CS$0$0001
            ldloc.s CS$0$0001
            ldc.i4.0
            ldarg.1
            box int32
            stelem.ref
            ldloc.s CS$0$0001
            call class [Yalf]Yalf.IContext [Yalf]Yalf.Log::MethodContext(string, object[])
            stloc.0
            */

            contextVar = new VariableDefinition(references.IContextType);
            body.Variables.Insert(0, contextVar);

            int objectParamsArrayIndex = method.AddVariable<object[]>();

            // Generate MethodContext calling method name
            var builder = new StringBuilder();

            builder.Append(string.Join(".",
                method.DeclaringType.Namespace,
                FormatType(method.DeclaringType),
                FormatMethod(method)));

            var current = firstInstruction
                .Prepend(processor.Create(OpCodes.Ldstr, builder.ToString()), processor);

            // Create object[] for MethodContext
            current = current
                .AppendLdcI4(processor, method.Parameters.Count)
                .Append(processor.Create(OpCodes.Newarr, method.Module.ImportType<object>()), processor)
                .AppendStloc(processor, objectParamsArrayIndex);

            var nonStaticMethodAddOne = method.IsStatic ? 0 : 1;

            // Set object[] values
            for (int i = 0; i < method.Parameters.Count; i++)
            {
                current = current
                    .AppendLdloc(processor, objectParamsArrayIndex)
                    .AppendLdcI4(processor, i);

                var paramType = method.Parameters[i].ParameterType;

                if (paramType.MetadataType == MetadataType.UIntPtr ||
                    paramType.MetadataType == MetadataType.FunctionPointer ||
                    paramType.MetadataType == MetadataType.IntPtr ||
                    paramType.MetadataType == MetadataType.Pointer)
                {
                    // don't store pointer types into object[] (we can't ToString them anyway)
                    // store type name as string instead
                    current = current.AppendLdstr(processor, paramType.FullName);
                }
                else
                {
                    current = current
                        .AppendLdarg(processor, i + nonStaticMethodAddOne)
                        .AppendBoxAndResolveRefIfNecessary(processor, paramType);
                }

                current = current.Append(processor.Create(OpCodes.Stelem_Ref), processor);
            }

            // Call Log.MethodContext
            current
                .AppendLdloc(processor, objectParamsArrayIndex)
                .Append(processor.Create(OpCodes.Call, references.MethodContextMethod), processor)
                .AppendStloc(processor, contextVar.Index);
        }
Beispiel #12
0
 private void HandleReturnType(MethodDefinition method, bool returnVoid, ReferenceContainer references)
 {
     _returnType = null;
     if (!returnVoid)
     {
         _returnType = method.ReturnType;
         _recordReturnMethod = references.CreateRecordReturnMethod(_returnType);
     }
 }
Beispiel #13
0
        public void Execute()
        {
            IsDebugBuild = DefineConstants.Any(x => x.ToLower() == "debug");

            var references = new ReferenceContainer(ModuleDefinition, AssemblyResolver);

            WeaveMethods(references);
        }
Beispiel #14
0
        private void WeaveMethods(ReferenceContainer references)
        {
            var methodDefinitions = SelectMethods(ModuleDefinition, NoLogAttributeName);

            foreach (var methodDefinition in methodDefinitions)
            {
                WeaveMethod(methodDefinition, references);
            }
        }
Beispiel #15
0
        private void WeaveMethod(MethodDefinition methodDefinition, ReferenceContainer references)
        {
            var asyncAttribute = methodDefinition.CustomAttributes.FirstOrDefault(_ => _.AttributeType.Name == "AsyncStateMachineAttribute");
            if (asyncAttribute == null)
            {
                var returnVoid = methodDefinition.ReturnType == ModuleDefinition.TypeSystem.Void;
                var methodProcessor = new MethodProcessor();

                methodProcessor.Process(methodDefinition, returnVoid, references);
                return;
            }
            LogError(string.Format("Could not process '{0}'. async methods are not currently supported. Feel free to do it yourself if you want this feature.", methodDefinition.FullName));
        }