/// <summary>
        /// Returns an EventAttribute for the Completed or Faulted events for a call context.
        /// </summary>
        /// <param name="baseAttribute">The EventAttribute for the method call that should be copied.</param>
        /// <param name="context">The context of the call.</param>
        /// <param name="nextEventId">The next event ID to use if not specified by some other mechanism.</param>
        /// <returns>The EventAttribute for the call context.</returns>
        public virtual EventAttribute CopyEventAttribute(EventAttribute baseAttribute, InvocationContext context, int nextEventId)
        {
            if (baseAttribute == null) throw new ArgumentNullException("baseAttribute");
            if (context == null) throw new ArgumentNullException("context");

            return new EventAttribute(nextEventId)
            {
                Keywords = baseAttribute.Keywords,
                Level = GetEventLevelForContext(context, baseAttribute),
                Message = GetEventMessage(context),
                Opcode = baseAttribute.Opcode,
                Task = baseAttribute.Task,
                Version = baseAttribute.Version
            };
        }
        /// <summary>
        /// Determines whether the given invocation context requires context to be provided.
        /// </summary>
        /// <param name="context">The context of the invocation.</param>
        /// <returns>True if EventSourceProxy should ask for context, false to skip context generation.</returns>
        public virtual bool ShouldProvideContext(InvocationContext context)
        {
            if (context == null) throw new ArgumentNullException("context");

            // NOTE: this method is called at proxy generation time and is not called at runtime
            // so we don't need to cache anything here
            // if this returns false, then ProvideContext will never be called for the given context

            // check the method first
            var attribute = context.MethodInfo.GetCustomAttribute<TraceContextAttribute>();
            if (attribute != null)
                return attribute.EnabledFor.HasFlag(context.ContextType);

            // now check the class
            attribute = context.MethodInfo.DeclaringType.GetCustomAttribute<TraceContextAttribute>();
            if (attribute != null)
                return attribute.EnabledFor.HasFlag(context.ContextType);

            // it's enabled by default
            return true;
        }
 /// <summary>
 /// Emits a _Faulted version of a given event that logs the result of an operation.
 /// The _Completed event is used by TracingProxy to signal an exception in a method call.
 /// </summary>
 /// <param name="invocationContext">The InvocationContext for this call.</param>
 /// <param name="beginMethod">The begin method for this interface call.</param>
 /// <param name="eventId">The next available event ID.</param>
 /// <param name="autoKeyword">The auto-keyword to use if enabled.</param>
 /// <returns>The MethodBuilder for the method.</returns>
 private MethodBuilder EmitMethodFaultedImpl(InvocationContext invocationContext, MethodInfo beginMethod, ref int eventId, EventKeywords autoKeyword)
 {
     return EmitMethodComplementImpl(invocationContext.SpecifyType(InvocationContextTypes.MethodFaulted), FaultedSuffix, typeof(Exception), beginMethod, ref eventId, autoKeyword, null);
 }
 /// <summary>
 /// Emits a _Completed version of a given event that logs the result of an operation.
 /// The _Completed event is used by TracingProxy to signal the end of a method call.
 /// </summary>
 /// <param name="invocationContext">The InvocationContext for this call.</param>
 /// <param name="beginMethod">The begin method for this interface call.</param>
 /// <param name="eventId">The next available event ID.</param>
 /// <param name="autoKeyword">The auto-keyword to use if enabled.</param>
 /// <param name="faultedMethod">A faulted method to call or null if no other faulted method is available.</param>
 /// <returns>The MethodBuilder for the method.</returns>
 private MethodBuilder EmitMethodCompletedImpl(InvocationContext invocationContext, MethodInfo beginMethod, ref int eventId, EventKeywords autoKeyword, MethodBuilder faultedMethod)
 {
     return EmitMethodComplementImpl(invocationContext.SpecifyType(InvocationContextTypes.MethodCompletion), CompletedSuffix, invocationContext.MethodInfo.ReturnType, beginMethod, ref eventId, autoKeyword, faultedMethod);
 }
        /// <summary>
        /// Emits a method to complement an interface method. The complement method will have a suffix such as _Completed,
        /// and will take one parameter.
        /// </summary>
        /// <param name="invocationContext">The InvocationContext for this call.</param>
        /// <param name="suffix">The suffix to use on the method.</param>
        /// <param name="parameterType">The type of the parameter of the method.</param>
        /// <param name="beginMethod">The begin method for this interface call.</param>
        /// <param name="eventId">The next available event ID.</param>
        /// <param name="autoKeyword">The auto-keyword to use if enabled.</param>
        /// <param name="faultedMethod">A faulted method to call or null if no other faulted method is available.</param>
        /// <returns>The MethodBuilder for the method.</returns>
        private MethodBuilder EmitMethodComplementImpl(InvocationContext invocationContext, string suffix, Type parameterType, MethodInfo beginMethod, ref int eventId, EventKeywords autoKeyword, MethodBuilder faultedMethod)
        {
            var interfaceMethod = invocationContext.MethodInfo;

            // if there is a NonEvent attribute, then no need to emit this method
            if (interfaceMethod.GetCustomAttribute<NonEventAttribute>() != null)
                return null;

            // if the method ends in _Completed, then don't emit another one
            if (interfaceMethod.Name.EndsWith(suffix, StringComparison.OrdinalIgnoreCase))
                return null;

            var methodName = beginMethod.Name + suffix;

            // if the interface already has a _Completed method, don't emit a new one
            var parameterTypes = parameterType == typeof(void) ? Type.EmptyTypes : new Type[] { parameterType };
            if (interfaceMethod.DeclaringType.GetMethod(methodName, parameterTypes) != null)
                return null;

            var targetParameterType = GetTypeSupportedByEventSource(parameterType);
            var targetParameters = parameterTypes.Select(t => TypeIsSupportedByEventSource(t) ? t : typeof(string)).ToList();
            bool supportsContext = SupportsContext(invocationContext);
            if (supportsContext)
                targetParameters.Add(typeof(string));
            var targetParameterTypes = targetParameters.ToArray();

            // determine if this is a non-event or an event
            // if an event, but there is no event attribute, just add one to the last event id
            EventAttribute startEventAttribute = interfaceMethod.GetCustomAttribute<EventAttribute>() ?? new EventAttribute(eventId);
            EventAttribute eventAttribute = _eventAttributeProvider.CopyEventAttribute(startEventAttribute, invocationContext, eventId);
            eventId = Math.Max(eventId, eventAttribute.EventId + 1);
            if (eventAttribute.Keywords == EventKeywords.None)
                eventAttribute.Keywords = autoKeyword;

            // if we have a return type, then we need to implement two methods
            if (parameterTypes.Length == 1)
            {
                // emit the internal method
                MethodBuilder m = _typeBuilder.DefineMethod(methodName, MethodAttributes.Public, typeof(void), targetParameterTypes);
                m.SetCustomAttribute(EventAttributeHelper.ConvertEventAttributeToAttributeBuilder(eventAttribute));
                EmitCallWriteEvent(invocationContext, m, eventAttribute, targetParameterTypes, targetParameterTypes);

                // emit an overloaded wrapper method that calls the method when it's enabled
                // note this is a non-event so EventSource doesn't try to log it
                MethodBuilder im = _typeBuilder.DefineMethod(methodName, MethodAttributes.Public);
                ProxyHelper.CopyGenericSignature(interfaceMethod, im);
                im.SetReturnType(parameterTypes[0]);
                im.SetParameters(parameterTypes);

                // mark the method as a non-event
                im.SetCustomAttribute(EventAttributeHelper.CreateNonEventAttribute());

                // put the return value on the stack so we can return the value as a passthrough
                im.GetILGenerator().Emit(OpCodes.Ldarg_1);

                if (EmitIsEnabled(im, eventAttribute))
                {
                    EmitTaskCompletion(im, parameterType, faultedMethod);
                    EmitDirectProxy(invocationContext, im, m, parameterTypes, targetParameterTypes);
                }

                return im;
            }
            else
            {
                // the method does not have a return value
                // so create the internal method that calls WriteEvent
                MethodBuilder m = _typeBuilder.DefineMethod(methodName, MethodAttributes.Public, typeof(void), targetParameterTypes);
                m.SetCustomAttribute(EventAttributeHelper.ConvertEventAttributeToAttributeBuilder(eventAttribute));
                ProxyHelper.EmitDefaultValue(m.GetILGenerator(), m.ReturnType);
                if (EmitIsEnabled(m, eventAttribute))
                    EmitCallWriteEvent(invocationContext, m, eventAttribute, targetParameterTypes, targetParameterTypes);

                return m;
            }
        }
        /// <summary>
        /// Emits a proxy to a method that just calls the base method.
        /// </summary>
        /// <param name="invocationContext">The current invocation context.</param>
        /// <param name="methodBuilder">The method to implement.</param>
        /// <param name="baseMethod">The base method.</param>
        /// <param name="sourceParameterTypes">The types of the parameters on the source method.</param>
        /// <param name="targetParameterTypes">The types of the parameters on the target method.</param>
        private void EmitDirectProxy(InvocationContext invocationContext, MethodBuilder methodBuilder, MethodInfo baseMethod, Type[] sourceParameterTypes, Type[] targetParameterTypes)
        {
            /*
             * This method assume that a default return value has been pushed on the stack.
             *
             *		base(params);
             *		return (top of stack);
             */

            ILGenerator mIL = methodBuilder.GetILGenerator();

            // copy the parameters to the stack
            // arg.0 = this
            // so we go to length+1
            mIL.Emit(OpCodes.Ldarg_0);
            for (int i = 0; i < sourceParameterTypes.Length; i++)
            {
                ProxyHelper.EmitSerializeValue(
                    methodBuilder,
                    invocationContext,
                    _invocationContexts,
                    _invocationContextsField,
                    i,
                    sourceParameterTypes[i],
                    targetParameterTypes[i],
                    _serializationProvider,
                    _serializationProviderField);
            }

            // if this method supports context, then add a context parameter
            // note that we pass null in here and then build the context from within EmitCallWriteEvent
            if (SupportsContext(invocationContext))
                mIL.Emit(OpCodes.Ldnull);

            // now that all of the parameters have been loaded, call the base method
            mIL.Emit(OpCodes.Call, baseMethod);

            mIL.Emit(OpCodes.Ret);
        }
        /// <summary>
        /// Emits an implementation of a given method.
        /// </summary>
        /// <param name="invocationContext">The InvocationContext for this call.</param>
        /// <param name="eventId">The next eventID to use.</param>
        /// <param name="autoKeyword">The auto-keyword to use if enabled.</param>
        /// <returns>The method that is implemented.</returns>
        private MethodBuilder EmitMethodImpl(InvocationContext invocationContext, ref int eventId, EventKeywords autoKeyword)
        {
            // get the method we are implementing and the parameter mapping
            var interfaceMethod = invocationContext.MethodInfo;
            var parameterMapping = _traceParameterProvider.ProvideParameterMapping(invocationContext.MethodInfo).Where(p => p.HasSource).ToList();

            // if we are implementing an interface, then add an string context parameter
            if (SupportsContext(invocationContext))
                parameterMapping.Add(new ParameterMapping(Context));

            // calculate the method name
            // if there is more than one method with the given name, then append an ID to it
            var methodName = interfaceMethod.Name;
            var matchingMethods = interfaceMethod.DeclaringType.GetMethods().AsEnumerable().Where(im => String.Compare(im.Name, methodName, StringComparison.OrdinalIgnoreCase) == 0).ToArray();
            if (matchingMethods.Length > 1)
                methodName += "_" + Array.IndexOf(matchingMethods, interfaceMethod).ToString(CultureInfo.InvariantCulture);

            // determine if this is a non-event or an event
            // if an event, but there is no event attribute, just add one to the last event id
            EventAttribute eventAttribute = null;
            if (interfaceMethod.GetCustomAttribute<NonEventAttribute>() == null)
            {
                eventAttribute = _eventAttributeProvider.GetEventAttribute(invocationContext, eventId);
                eventId = Math.Max(eventId, eventAttribute.EventId + 1);
            }

            // if auto-keywords are enabled, use them
            if (eventAttribute != null && eventAttribute.Keywords == EventKeywords.None)
                eventAttribute.Keywords = autoKeyword;

            // create the internal method that calls WriteEvent
            // this cannot be virtual or static, or the manifest builder will skip it
            // it also cannot return a value
            MethodBuilder m = _typeBuilder.DefineMethod(methodName, MethodAttributes.Public, typeof(void), parameterMapping.Select(p => p.CleanTargetType).ToArray());

            // copy the Event or NonEvent attribute from the interface
            if (eventAttribute != null)
                m.SetCustomAttribute(EventAttributeHelper.ConvertEventAttributeToAttributeBuilder(eventAttribute));
            else
                m.SetCustomAttribute(EventAttributeHelper.CreateNonEventAttribute());

            // add the parameter names
            for (int i = 0; i < parameterMapping.Count; i++)
            {
                var parameter = parameterMapping[i];
                m.DefineParameter(i + 1, ParameterAttributes.In, parameter.Name);
            }

            if (interfaceMethod.IsAbstract || !interfaceMethod.DeclaringType.IsSubclassOf(typeof(EventSource)))
            {
                // for interface methods, implement a call to write event
                ProxyHelper.EmitDefaultValue(m.GetILGenerator(), m.ReturnType);
                if (EmitIsEnabled(m, eventAttribute))
                    EmitCallWriteEvent(invocationContext, m, eventAttribute, parameterMapping);

                // since EventSource only accepts non-virtual methods, and we need a virtual method to implement the abstract method
                // we need to implement a wrapper method on the interface that calls into the base method
                // and handles the bundling/unbundling of parameters
                MethodBuilder im = _typeBuilder.DefineMethod("_" + methodName, MethodAttributes.Public | MethodAttributes.Virtual);
                ProxyHelper.CopyMethodSignature(interfaceMethod, im);
                ProxyHelper.EmitDefaultValue(im.GetILGenerator(), im.ReturnType);
                if (EmitIsEnabled(im, eventAttribute))
                    EmitDirectProxy(invocationContext, im, m, parameterMapping);

                // if this is an interface, then tell the system to map our method to the interface implementation
                if (interfaceMethod.IsAbstract)
                    _typeBuilder.DefineMethodOverride(im, interfaceMethod);
            }
            else
            {
                // we are implementing a non-abstract method in event source, then
                // all we can do is call the base implementation
                EmitDirectProxy(invocationContext, m, interfaceMethod, parameterMapping);
            }

            return m;
        }
        /// <summary>
        /// Emits the code needed to properly push an object on the stack,
        /// serializing the value if necessary.
        /// </summary>
        /// <param name="typeBuilder">The TypeBuilder for the method being built.</param>
        /// <param name="methodBuilder">The method currently being built.</param>
        /// <param name="invocationContext">The invocation context for this call.</param>
        /// <param name="invocationContexts">A list of invocation contexts that will be appended to.</param>
        /// <param name="invocationContextsField">The static field containing the array of invocation contexts at runtime.</param>
        /// <param name="i">The index of the current parameter being pushed.</param>
        /// <param name="sourceType">The type that the parameter is being converted from.</param>
        /// <param name="targetType">The type that the parameter is being converted to.</param>
        /// <param name="converter">An optional converter to apply to the source type.</param>
        /// <param name="serializationProvider">The serialization provider for the current interface.</param>
        /// <param name="serializationProviderField">
        /// The field on the current object that contains the serialization provider at runtime.
        /// This method assume the current object is stored in arg.0.
        /// </param>
        internal static void EmitSerializeValue(
			TypeBuilder typeBuilder,
			MethodBuilder methodBuilder,
			InvocationContext invocationContext,
			List<InvocationContext> invocationContexts,
			FieldBuilder invocationContextsField,
			int i,
			Type sourceType,
			Type targetType,
			LambdaExpression converter,
			TraceSerializationProvider serializationProvider,
			FieldBuilder serializationProviderField)
        {
            ILGenerator mIL = methodBuilder.GetILGenerator();

            // if the source is a parameter, then load the parameter onto the stack
            if (i >= 0)
                mIL.Emit(OpCodes.Ldarg, i + 1);

            // if a converter is passed in, then define a static method and use it to convert
            if (converter != null)
            {
                MethodBuilder mb = typeBuilder.DefineMethod(Guid.NewGuid().ToString(), MethodAttributes.Static | MethodAttributes.Public, converter.ReturnType, converter.Parameters.Select(p => p.Type).ToArray());
                converter.CompileToMethod(mb);
                mIL.Emit(OpCodes.Call, mb);

                // the object on the stack is now the return type. we may need to convert it further
                sourceType = converter.ReturnType;
            }

            // if the source type is a reference to the target type, we have to dereference it
            if (sourceType.IsByRef && sourceType.GetElementType() == targetType)
            {
                sourceType = sourceType.GetElementType();
                mIL.Emit(OpCodes.Ldobj, sourceType);
                return;
            }

            // if the types match, just put the argument on the stack
            if (sourceType == targetType)
                return;

            // this is not a match, so convert using the serializer.
            // verify that the target type is a string
            if (targetType != typeof(string))
                throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Cannot convert type {0} to a type compatible with EventSource", targetType.FullName));

            // for fundamental types, just convert them with ToString and be done with it
            var underlyingType = Nullable.GetUnderlyingType(sourceType) ?? sourceType;
            if (!sourceType.IsGenericParameter && (underlyingType.IsEnum || (underlyingType.IsValueType && underlyingType.Assembly == typeof(string).Assembly)))
            {
                // convert the argument to a string with ToString
                LocalBuilder lb = mIL.DeclareLocal(sourceType);
                mIL.Emit(OpCodes.Stloc, lb.LocalIndex);
                mIL.Emit(OpCodes.Ldloca, lb.LocalIndex);
                mIL.Emit(OpCodes.Call, sourceType.GetMethod("ToString", Type.EmptyTypes));
                return;
            }

            // non-fundamental types use the object serializer
            var context = new TraceSerializationContext(invocationContext, i);
            context.EventLevel = serializationProvider.GetEventLevelForContext(context);
            if (context.EventLevel != null)
            {
                LocalBuilder lb = mIL.DeclareLocal(sourceType);
                mIL.Emit(OpCodes.Stloc, lb.LocalIndex);

                // get the object serializer from the this pointer
                mIL.Emit(OpCodes.Ldsfld, serializationProviderField);
                mIL.Emit(OpCodes.Ldloc, lb.LocalIndex);

                // if the source type is a reference to the target type, we have to dereference it
                if (sourceType.IsByRef)
                {
                    sourceType = sourceType.GetElementType();
                    mIL.Emit(OpCodes.Ldobj, sourceType);
                }

                // if it's a value type, we have to box it to log it
                if (sourceType.IsGenericParameter || sourceType.IsValueType)
                    mIL.Emit(OpCodes.Box, sourceType);

                // get the invocation context from the array on the provider
                mIL.Emit(OpCodes.Ldsfld, invocationContextsField);
                mIL.Emit(OpCodes.Ldc_I4, invocationContexts.Count);
                mIL.Emit(OpCodes.Ldelem, typeof(TraceSerializationContext));
                invocationContexts.Add(context);

                mIL.Emit(OpCodes.Callvirt, typeof(TraceSerializationProvider).GetMethod("ProvideSerialization", BindingFlags.Instance | BindingFlags.Public));
            }
            else
            {
                mIL.Emit(OpCodes.Pop);
                mIL.Emit(OpCodes.Ldnull);
            }
        }
 /// <summary>
 /// Determines whether the given invocation supports a context provider.
 /// </summary>
 /// <param name="invocationContext">The current InvocationContext.</param>
 /// <returns>True if the context provider should be invoked for the context.</returns>
 private bool SupportsContext(InvocationContext invocationContext)
 {
     return _contextProvider != null && _contextProvider.ShouldProvideContext(invocationContext);
 }
        /// <summary>
        /// Returns an EventAttribute for the given call context.
        /// </summary>
        /// <param name="context">The context of the call.</param>
        /// <param name="nextEventId">The next event ID to use if not specified by some other mechanism.</param>
        /// <returns>The EventAttribute for the call context.</returns>
        public virtual EventAttribute GetEventAttribute(InvocationContext context, int nextEventId)
        {
            if (context == null) throw new ArgumentNullException("context");

            EventAttribute eventAttribute = context.MethodInfo.GetCustomAttribute<EventAttribute>();
            if (eventAttribute != null)
                return eventAttribute;

            return new EventAttribute(nextEventId)
            {
                Level = GetEventLevelForContext(context, null),
                Message = GetEventMessage(context)
            };
        }
        /// <summary>
        /// Gets the message for an event.
        /// </summary>
        /// <param name="context">The context of the call.</param>
        /// <returns>The message for the event.</returns>
        protected virtual string GetEventMessage(InvocationContext context)
        {
            if (context == null) throw new ArgumentNullException("context");

            switch (context.ContextType)
            {
                case InvocationContextTypes.MethodCall:
                    return String.Join(" ", Enumerable.Range(0, context.MethodInfo.GetParameters().Length).Select(i => String.Format(CultureInfo.InvariantCulture, "{{{0}}}", i)));

                case InvocationContextTypes.MethodFaulted:
                    return "{0}";

                case InvocationContextTypes.MethodCompletion:
                    if (context.MethodInfo.ReturnType != typeof(void))
                        return "{0}";
                    else
                        return String.Empty;
            }

            return String.Empty;
        }
        /// <summary>
        /// Gets the appropriate EventLevel for the call context.
        /// </summary>
        /// <param name="context">The context of the call.</param>
        /// <param name="baseAttribute">The base attribute to copy if there are no additional attributes.</param>
        /// <returns>The EventLevel for the call context.</returns>
        protected virtual EventLevel GetEventLevelForContext(InvocationContext context, EventAttribute baseAttribute)
        {
            if (context == null) throw new ArgumentNullException("context");

            // for faulted methods, allow the EventExceptionAttribute to override the event level
            if (context.ContextType == InvocationContextTypes.MethodFaulted)
            {
                var attribute = context.MethodInfo.GetCustomAttribute<EventExceptionAttribute>();
                if (attribute != null)
                    return attribute.Level;

                attribute = context.MethodInfo.DeclaringType.GetCustomAttribute<EventExceptionAttribute>();
                if (attribute != null)
                    return attribute.Level;

                return ExceptionEventLevel;
            }

            // check for an attribute on the type
            var implementationAttribute = context.MethodInfo.DeclaringType.GetCustomAttribute<EventSourceImplementationAttribute>();
            if (implementationAttribute != null && implementationAttribute.Level.HasValue)
                return implementationAttribute.Level.Value;

            if (baseAttribute != null)
                return baseAttribute.Level;

            return EventLevel;
        }
        /// <summary>
        /// Emits the code needed to properly push an object on the stack,
        /// serializing the value if necessary.
        /// </summary>
        /// <param name="methodBuilder">The method currently being built.</param>
        /// <param name="invocationContext">The invocation context for this call.</param>
        /// <param name="invocationContexts">A list of invocation contexts that will be appended to.</param>
        /// <param name="invocationContextsField">The static field containing the array of invocation contexts at runtime.</param>
        /// <param name="i">The index of the current parameter being pushed.</param>
        /// <param name="sourceType">The type that the parameter is being converted from.</param>
        /// <param name="targetType">The type that the parameter is being converted to.</param>
        /// <param name="serializationProvider">The serialization provider for the current interface.</param>
        /// <param name="serializationProviderField">
        /// The field on the current object that contains the serialization provider at runtime.
        /// This method assume the current object is stored in arg.0.
        /// </param>
        internal static void EmitSerializeValue(
			MethodBuilder methodBuilder,
			InvocationContext invocationContext,
			List<InvocationContext> invocationContexts,
			FieldBuilder invocationContextsField,
			int i,
			Type sourceType,
			Type targetType,
			TraceSerializationProvider serializationProvider,
			FieldBuilder serializationProviderField)
        {
            ILGenerator mIL = methodBuilder.GetILGenerator();

            // if the source type is a reference to the target type, we have to dereference it
            if (sourceType.IsByRef && sourceType.GetElementType() == targetType)
            {
                mIL.Emit(OpCodes.Ldarg, (int)i + 1);
                sourceType = sourceType.GetElementType();
                mIL.Emit(OpCodes.Ldobj, sourceType);
                return;
            }

            // if the types match, just put the argument on the stack
            if (sourceType == targetType)
            {
                mIL.Emit(OpCodes.Ldarg, (int)i + 1);
                return;
            }

            // this is not a match, so convert using the serializer.
            // verify that the target type is a string
            if (targetType != typeof(string))
                throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Cannot convert type {0} to a type compatible with EventSource", targetType.FullName));

            // for fundamental types, just convert them with ToString and be done with it
            var underlyingType = Nullable.GetUnderlyingType(sourceType) ?? sourceType;
            if (!sourceType.IsGenericParameter && (underlyingType.IsEnum || (underlyingType.IsValueType && underlyingType.Assembly == typeof(string).Assembly)))
            {
                // convert the argument to a string with ToString
                mIL.Emit(OpCodes.Ldarga_S, i + 1);
                mIL.Emit(OpCodes.Call, sourceType.GetMethod("ToString", Type.EmptyTypes));
                return;
            }

            // non-fundamental types use the object serializer
            var context = new TraceSerializationContext(invocationContext, i);
            context.EventLevel = serializationProvider.GetEventLevelForContext(context);
            if (context.EventLevel != null)
            {
                // get the object serializer from the this pointer
                mIL.Emit(OpCodes.Ldsfld, serializationProviderField);

                // load the value
                mIL.Emit(OpCodes.Ldarg, (int)i + 1);

                // if the source type is a reference to the target type, we have to dereference it
                if (sourceType.IsByRef)
                {
                    sourceType = sourceType.GetElementType();
                    mIL.Emit(OpCodes.Ldobj, sourceType);
                }

                // if it's a value type, we have to box it to log it
                if (sourceType.IsGenericParameter || sourceType.IsValueType)
                    mIL.Emit(OpCodes.Box, sourceType);

                // get the invocation context from the array on the provider
                mIL.Emit(OpCodes.Ldsfld, invocationContextsField);
                mIL.Emit(OpCodes.Ldc_I4, invocationContexts.Count);
                mIL.Emit(OpCodes.Ldelem, typeof(TraceSerializationContext));
                invocationContexts.Add(context);

                mIL.Emit(OpCodes.Callvirt, typeof(TraceSerializationProvider).GetMethod("ProvideSerialization", BindingFlags.Instance | BindingFlags.Public));
            }
            else
                mIL.Emit(OpCodes.Ldnull);
        }
 /// <summary>
 /// Provides context information, such as security context, for a trace session.
 /// </summary>
 /// <param name="context">The context of the current invocation.</param>
 /// <returns>A string representing the current context.</returns>
 public abstract string ProvideContext(InvocationContext context);
        /// <summary>
        /// Emits an implementation of a given method.
        /// </summary>
        /// <param name="invocationContext">The InvocationContext for this call.</param>
        /// <param name="eventId">The next eventID to use.</param>
        /// <param name="autoKeyword">The auto-keyword to use if enabled.</param>
        /// <returns>The method that is implemented.</returns>
        private MethodBuilder EmitMethodImpl(InvocationContext invocationContext, ref int eventId, EventKeywords autoKeyword)
        {
            var interfaceMethod = invocationContext.MethodInfo;

            // look at the parameters on the interface
            var parameters = interfaceMethod.GetParameters();
            var parameterTypes = parameters.Select(p => p.ParameterType).ToArray();

            // some types aren't supported in event source. we will convert them to strings
            var targetParameters = parameterTypes.Select(t => GetTypeSupportedByEventSource(t)).ToList();

            // if we are implementing an interface, then add an string context parameter
            bool supportsContext = SupportsContext(invocationContext);
            if (supportsContext)
                targetParameters.Add(typeof(string));
            var targetParameterTypes = targetParameters.ToArray();

            // calculate the method name
            // if there is more than one method with the given name, then append an ID to it
            var methodName = interfaceMethod.Name;
            var matchingMethods = interfaceMethod.DeclaringType.GetMethods().AsEnumerable().Where(im => String.Compare(im.Name, methodName, StringComparison.OrdinalIgnoreCase) == 0).ToArray();
            if (matchingMethods.Length > 1)
                methodName += "_" + Array.IndexOf(matchingMethods, interfaceMethod).ToString(CultureInfo.InvariantCulture);

            // determine if this is a non-event or an event
            // if an event, but there is no event attribute, just add one to the last event id
            EventAttribute eventAttribute = null;
            if (interfaceMethod.GetCustomAttribute<NonEventAttribute>() == null)
            {
                eventAttribute = _eventAttributeProvider.GetEventAttribute(invocationContext, eventId);
                eventId = Math.Max(eventId, eventAttribute.EventId + 1);
            }

            // if auto-keywords are enabled, use them
            if (eventAttribute != null && eventAttribute.Keywords == EventKeywords.None)
                eventAttribute.Keywords = autoKeyword;

            // create the internal method that calls WriteEvent
            // this cannot be virtual or static, or the manifest builder will skip it
            // it also cannot return a value
            MethodBuilder m = _typeBuilder.DefineMethod(methodName, MethodAttributes.Public, typeof(void), targetParameterTypes);

            // copy the Event or NonEvent attribute from the interface
            if (eventAttribute != null)
                m.SetCustomAttribute(EventAttributeHelper.ConvertEventAttributeToAttributeBuilder(eventAttribute));
            else
                m.SetCustomAttribute(EventAttributeHelper.CreateNonEventAttribute());

            // add the parameter names
            for (int i = 0; i < parameters.Length; i++)
            {
                var parameter = parameters[i];
                m.DefineParameter(i + 1, parameter.Attributes, parameter.Name);
            }

            // add the context parameter
            if (supportsContext)
                m.DefineParameter(parameters.Length + 1, ParameterAttributes.In, Context);

            if (interfaceMethod.IsAbstract)
            {
                // for interface methods, implement a call to write event
                EmitCallWriteEvent(invocationContext, m, eventAttribute, parameterTypes, targetParameterTypes);

                // since EventSource only accepts non-virtual methods, and we need a virtual method to implement the abstract method
                // we need to implement a wrapper method on the interface that calls into the base method
                MethodBuilder im = _typeBuilder.DefineMethod("_" + methodName, MethodAttributes.Public | MethodAttributes.Virtual);
                ProxyHelper.CopyMethodSignature(interfaceMethod, im);
                ProxyHelper.EmitDefaultValue(im.GetILGenerator(), im.ReturnType);
                if (EmitIsEnabled(im, eventAttribute))
                    EmitDirectProxy(invocationContext, im, m, parameterTypes, targetParameterTypes);

                // map our method to the interface implementation
                _typeBuilder.DefineMethodOverride(im, interfaceMethod);
            }
            else if (interfaceMethod.DeclaringType.IsSubclassOf(typeof(EventSource)))
            {
                // if we are implementing an event source, then
                // for non-abstract methods we just proxy the base implementation
                EmitDirectProxy(invocationContext, m, interfaceMethod, parameterTypes, targetParameterTypes);
            }
            else
            {
                // the base class is not an event source, so we are creating an eventsource-derived class
                // that just logs the event
                // so we need to call write event
                // call IsEnabled with the given event level and keywords to check whether we should log
                ProxyHelper.EmitDefaultValue(m.GetILGenerator(), m.ReturnType);
                if (EmitIsEnabled(m, eventAttribute))
                    EmitCallWriteEvent(invocationContext, m, eventAttribute, parameterTypes, targetParameterTypes);
            }

            return m;
        }
        /// <summary>
        /// Emits a call to the base method by pushing all of the arguments.
        /// </summary>
        /// <param name="m">The method to append to.</param>
        /// <param name="invocationContext">The invocation context for this call.</param>
        /// <param name="field">The field containing the interface to call.</param>
        /// <param name="originalMethod">The the original method signature.</param>
        /// <param name="baseMethod">The method to call.</param>
        private void EmitBaseMethodCall(MethodBuilder m, InvocationContext invocationContext, FieldInfo field, MethodInfo originalMethod, MethodInfo baseMethod)
        {
            // if this is a generic method, we have to instantiate our type of method
            if (baseMethod.IsGenericMethodDefinition)
                baseMethod = baseMethod.MakeGenericMethod(baseMethod.GetGenericArguments());

            var sourceParameters = originalMethod.GetParameters();
            var targetParameters = baseMethod.GetParameters();

            // load the pointer from the field, push the parameters and call the method
            // this is an instance method, so arg.0 is the this pointer
            ILGenerator mIL = m.GetILGenerator();
            mIL.Emit(OpCodes.Ldarg_0);
            mIL.Emit(OpCodes.Ldfld, field);

            // go through and serialize the parameters
            for (int i = 0; i < targetParameters.Length; i++)
            {
                ProxyHelper.EmitSerializeValue(
                    m,
                    invocationContext,
                    _invocationContexts,
                    _invocationContextsField,
                    i,
                    sourceParameters[i].ParameterType,
                    targetParameters[i].ParameterType,
                    _serializationProvider,
                    _serializerField);
            }

            // call the method
            mIL.Emit(OpCodes.Callvirt, baseMethod);
        }
        /// <summary>
        /// Implement the type.
        /// </summary>
        private void ImplementType()
        {
            // create a new assembly
            AssemblyName an = Assembly.GetExecutingAssembly().GetName();
            an.Name = ProxyHelper.AssemblyName;
            AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
            ModuleBuilder mb = ab.DefineDynamicModule(an.Name);

            // create a type based on EventSource and call the default constructor
            if (_interfaceType.IsSubclassOf(typeof(EventSource)))
                _typeBuilder = mb.DefineType(_interfaceType.FullName + "_Implemented", TypeAttributes.Class | TypeAttributes.Public, _interfaceType);
            else if (_interfaceType.IsInterface)
                _typeBuilder = mb.DefineType(_interfaceType.FullName + "_Implemented", TypeAttributes.Class | TypeAttributes.Public, typeof(EventSource), new Type[] { _interfaceType });
            else
                _typeBuilder = mb.DefineType(_interfaceType.FullName + "_Implemented", TypeAttributes.Class | TypeAttributes.Public, typeof(EventSource));

            // assign an EventSource attribute to the type so it gets the original name and guid
            _typeBuilder.SetCustomAttribute(EventSourceAttributeHelper.GetEventSourceAttributeBuilder(_interfaceType));

            // implement the fields and constructor
            EmitFields();

            // find all of the methods that need to be implemented
            var interfaceMethods = ProxyHelper.DiscoverMethods(_interfaceType);
            var implementationAttribute = _interfaceType.GetCustomAttribute<EventSourceImplementationAttribute>() ?? new EventSourceImplementationAttribute();

            // find the first free event id, in case we need to assign some ourselves
            int eventId = interfaceMethods
                .Select(m => m.GetCustomAttribute<EventAttribute>())
                .Where(a => a != null)
                .Select(a => a.EventId)
                .DefaultIfEmpty(0)
                .Max() + 1;

            // if there isn't a keyword class, then auto-generate the keywords
            bool hasKeywords = (implementationAttribute.Keywords != null) || (FindNestedType(_interfaceType, "Keywords") != null);
            ulong autoKeyword = hasKeywords ? (ulong)0 : 1;

            // for each method on the interface, try to implement it with a call to eventsource
            Dictionary<string, ulong> autoKeywords = new Dictionary<string, ulong>();
            foreach (MethodInfo interfaceMethod in interfaceMethods)
            {
                var invocationContext = new InvocationContext(interfaceMethod, InvocationContextTypes.MethodCall);

                var beginMethod = EmitMethodImpl(invocationContext, ref eventId, (EventKeywords)autoKeyword);
                var faultedMethod = EmitMethodFaultedImpl(invocationContext, beginMethod, ref eventId, (EventKeywords)autoKeyword);
                EmitMethodCompletedImpl(invocationContext, beginMethod, ref eventId, (EventKeywords)autoKeyword, faultedMethod);

                // shift to the next keyword
                autoKeywords.Add(beginMethod.Name, autoKeyword);
                autoKeyword <<= 1;
            }

            // create the type
            Type t = _typeBuilder.CreateType();

            // define the internal enum classes if they are defined
            if (hasKeywords)
                EmitEnumImplementation(implementationAttribute.Keywords, Keywords, typeof(EventKeywords));
            else
                EmitKeywordImpl(autoKeywords);
            EmitEnumImplementation(implementationAttribute.OpCodes, Opcodes, typeof(EventOpcode));
            EmitEnumImplementation(implementationAttribute.Tasks, Tasks, typeof(EventTask));

            // initialize the static fields
            t.GetField(_invocationContextsField.Name, BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, _invocationContexts.ToArray());
            t.GetField(_serializationProviderField.Name, BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, _serializationProvider);
            t.GetField(_contextProviderField.Name, BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, _contextProvider);

            // instantiate the singleton
            EventSource = (EventSource)t.GetConstructor(Type.EmptyTypes).Invoke(null);

            // fill in the event source for all of the invocation contexts
            foreach (var context in _invocationContexts)
                context.EventSource = EventSource;
        }
        /// <summary>
        /// Emits the implementation of a given interface method.
        /// </summary>
        /// <param name="executeMethod">The execute method to implement.</param>
        private void EmitMethodImpl(MethodInfo executeMethod)
        {
            /*
             * public TReturn Method (params)
             * {
             *		var scope = new EventActivityScope(true);
             *		try
             *		{
             *			_log.Method(params);
             *			object value = _execute.Method(params);
             *			_log.Method_Completed(value);
             *		}
             *		catch (Exception e)
             *		{
             *			_log.Method_Faulted(e);
             *			throw;
             *		}
             *		finally
             *		{
             *			scope.Dispose();
             *		}
             * }
             */

            var invocationContext = new InvocationContext(executeMethod, InvocationContextTypes.MethodCall);

            // start building the interface
            MethodBuilder m = _typeBuilder.DefineMethod(executeMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual);
            ProxyHelper.CopyMethodSignature(executeMethod, m);
            var parameterTypes = executeMethod.GetParameters().Select(p => p.ParameterType).ToArray();

            ILGenerator mIL = m.GetILGenerator();

            // set up a place to hold the return value
            LocalBuilder returnValue = null;
            if (m.ReturnType != typeof(void))
                returnValue = mIL.DeclareLocal(m.ReturnType);

            // set up the activity scope
            LocalBuilder scope = null;
            if (_callWithActivityScope)
            {
                scope = mIL.DeclareLocal(typeof(EventActivityScope));
                mIL.Emit(OpCodes.Ldc_I4_1);
                mIL.Emit(OpCodes.Newobj, typeof(EventSourceProxy.EventActivityScope).GetConstructor(new Type[] { typeof(bool) }));
                mIL.Emit(OpCodes.Stloc, scope);
            }

            // start the try block
            mIL.BeginExceptionBlock();

            // call the method on the log that matches the execute method
            var targetParameterTypes = parameterTypes.Select(p => p.IsGenericParameter ? TypeImplementer.GetTypeSupportedByEventSource(p) : p).ToArray();
            var logMethod = DiscoverMethod(_logField.FieldType, executeMethod.Name, String.Empty, targetParameterTypes);
            if (logMethod != null)
            {
                // call the log method and throw away the result if there is one
                EmitBaseMethodCall(m, invocationContext, _logField, executeMethod, logMethod);
                if (logMethod.ReturnType != typeof(void))
                    mIL.Emit(OpCodes.Pop);
            }

            // call execute
            EmitBaseMethodCall(m, invocationContext, _executeField, executeMethod, executeMethod);
            if (executeMethod.ReturnType != typeof(void))
                mIL.Emit(OpCodes.Stloc, returnValue);

            // if there is a completed method, then call that
            var completedParameterTypes = (executeMethod.ReturnType == typeof(void)) ? Type.EmptyTypes : new Type[] { executeMethod.ReturnType };
            var completedMethod = DiscoverMethod(_logField.FieldType, executeMethod.Name, TypeImplementer.CompletedSuffix, completedParameterTypes);
            if (completedMethod != null)
            {
                // load this._log
                mIL.Emit(OpCodes.Ldarg_0);
                mIL.Emit(OpCodes.Ldfld, _logField);

                // load the value from the local variable
                if (executeMethod.ReturnType != typeof(void))
                    mIL.Emit(OpCodes.Ldloc, returnValue);

                mIL.Emit(OpCodes.Call, completedMethod);
                if (completedMethod.ReturnType != typeof(void))
                    mIL.Emit(OpCodes.Pop);
            }

            // handle exceptions by logging them and rethrowing
            mIL.BeginCatchBlock(typeof(Exception));
            var faultedMethod = DiscoverMethod(_logField.FieldType, executeMethod.Name, TypeImplementer.FaultedSuffix, new Type[] { typeof(Exception) });
            if (faultedMethod != null)
            {
                // save the exception
                var exception = mIL.DeclareLocal(typeof(Exception));
                mIL.Emit(OpCodes.Stloc, exception);

                // load this._log
                mIL.Emit(OpCodes.Ldarg_0);
                mIL.Emit(OpCodes.Ldfld, _logField);

                // load the exception
                mIL.Emit(OpCodes.Ldloc, exception);

                // call the fault handler
                mIL.Emit(OpCodes.Call, faultedMethod);
                if (faultedMethod.ReturnType != typeof(void))
                    mIL.Emit(OpCodes.Pop);
            }

            mIL.Emit(OpCodes.Rethrow);

            // clean up the activity scope
            if (_callWithActivityScope)
            {
                mIL.BeginFinallyBlock();
                mIL.Emit(OpCodes.Ldloc, scope);
                mIL.Emit(OpCodes.Callvirt, typeof(EventActivityScope).GetMethod("Dispose"));
            }

            mIL.EndExceptionBlock();

            // return the result
            if (executeMethod.ReturnType != typeof(void))
                mIL.Emit(OpCodes.Ldloc, returnValue);
            mIL.Emit(OpCodes.Ret);
        }
        /// <summary>
        /// Emits the code needed to properly push an object on the stack,
        /// serializing the value if necessary.
        /// </summary>
        /// <param name="typeBuilder">The TypeBuilder for the method being built.</param>
        /// <param name="methodBuilder">The method currently being built.</param>
        /// <param name="invocationContext">The invocation context for this call.</param>
        /// <param name="invocationContexts">A list of invocation contexts that will be appended to.</param>
        /// <param name="invocationContextsField">The static field containing the array of invocation contexts at runtime.</param>
        /// <param name="parameterMapping">The mapping of source parameters to destination parameters.</param>
        /// <param name="serializationProvider">The serialization provider for the current interface.</param>
        /// <param name="serializationProviderField">
        /// The field on the current object that contains the serialization provider at runtime.
        /// This method assume the current object is stored in arg.0.
        /// </param>
        internal static void EmitSerializeValue(
			TypeBuilder typeBuilder,
			MethodBuilder methodBuilder,
			InvocationContext invocationContext,
			List<InvocationContext> invocationContexts,
			FieldBuilder invocationContextsField,
			ParameterMapping parameterMapping,
			TraceSerializationProvider serializationProvider,
			FieldBuilder serializationProviderField)
        {
            var sourceCount = parameterMapping.Sources.Count();
            if (sourceCount == 0)
                return;

            if (sourceCount == 1)
            {
                var parameter = parameterMapping.Sources.First();

                EmitSerializeValue(
                    typeBuilder,
                    methodBuilder,
                    invocationContext,
                    invocationContexts,
                    invocationContextsField,
                    parameter.Position,
                    parameter.SourceType,
                    parameterMapping.CleanTargetType,
                    parameter.Converter,
                    serializationProvider,
                    serializationProviderField);
                return;
            }

            var il = methodBuilder.GetILGenerator();

            // use the serializer to serialize the objects
            var context = new TraceSerializationContext(invocationContext.SpecifyType(InvocationContextTypes.BundleParameters), -1);
            context.EventLevel = serializationProvider.GetEventLevelForContext(context);

            if (context.EventLevel != null)
            {
                // get the object serializer from the this pointer
                il.Emit(OpCodes.Ldsfld, serializationProviderField);

                // create a new dictionary strings and values
                il.Emit(OpCodes.Newobj, typeof(Dictionary<string, string>).GetConstructor(Type.EmptyTypes));

                foreach (var parameter in parameterMapping.Sources)
                {
                    il.Emit(OpCodes.Dup);
                    il.Emit(OpCodes.Ldstr, parameter.Alias);

                    EmitSerializeValue(
                        typeBuilder,
                        methodBuilder,
                        invocationContext,
                        invocationContexts,
                        invocationContextsField,
                        parameter.Position,
                        parameter.SourceType,
                        parameterMapping.CleanTargetType,
                        parameter.Converter,
                        serializationProvider,
                        serializationProviderField);

                    var method = typeof(Dictionary<string, string>).GetMethod("Add");
                    il.Emit(OpCodes.Call, method);
                }

                // get the invocation context from the array on the provider
                il.Emit(OpCodes.Ldsfld, invocationContextsField);
                il.Emit(OpCodes.Ldc_I4, invocationContexts.Count);
                il.Emit(OpCodes.Ldelem, typeof(TraceSerializationContext));
                invocationContexts.Add(context);

                il.Emit(OpCodes.Callvirt, typeof(TraceSerializationProvider).GetMethod("ProvideSerialization", BindingFlags.Instance | BindingFlags.Public));
            }
            else
                il.Emit(OpCodes.Ldnull);
        }
        /// <summary>
        /// Emit a call to WriteEvent(param object[]).
        /// </summary>
        /// <param name="invocationContext">The InvocationContext for this call.</param>
        /// <param name="methodBuilder">The MethodBuilder to append to.</param>
        /// <param name="eventAttribute">The EventAttribute to use as values in the method.</param>
        /// <param name="sourceParameterTypes">The types of parameters on the source method.</param>
        /// <param name="targetParameterTypes">The types of the parameters on the target method.</param>
        private void EmitCallWriteEvent(InvocationContext invocationContext, MethodBuilder methodBuilder, EventAttribute eventAttribute, Type[] sourceParameterTypes, Type[] targetParameterTypes)
        {
            ILGenerator mIL = methodBuilder.GetILGenerator();

            // if there is no event attribute, then this is a non-event, so just return silently
            if (eventAttribute == null)
            {
                ProxyHelper.EmitDefaultValue(mIL, methodBuilder.ReturnType);
                mIL.Emit(OpCodes.Ret);
                return;
            }

            // call write event with the parameters in an object array
            mIL.Emit(OpCodes.Ldarg_0);
            mIL.Emit(OpCodes.Ldc_I4, eventAttribute.EventId);

            // create a new array of the proper length to pass the values in
            mIL.Emit(OpCodes.Ldc_I4, targetParameterTypes.Length);
            mIL.Emit(OpCodes.Newarr, typeof(object));
            for (int i = 0; i < sourceParameterTypes.Length; i++)
            {
                mIL.Emit(OpCodes.Dup);
                mIL.Emit(OpCodes.Ldc_I4, (int)i);

                // load the argument and box it
                mIL.Emit(OpCodes.Ldarg, (int)i + 1);

                // if the target is a value type, then we can box the source type
                // and the CLR will apply conversions for us
                // at this point, all invalid types have been converted to strings in EmitDirectProxy
                // and references have been dereferenced
                if (targetParameterTypes[i].IsValueType)
                {
                    var sourceType = sourceParameterTypes[i];
                    if (sourceType.IsByRef)
                        sourceType = sourceType.GetElementType();
                    mIL.Emit(OpCodes.Box, sourceType);
                }

                mIL.Emit(OpCodes.Stelem, typeof(object));
            }

            // if there is a context, call the context provider and add the context parameter
            if (SupportsContext(invocationContext))
            {
                // load the array and index onto the stack
                mIL.Emit(OpCodes.Dup);
                mIL.Emit(OpCodes.Ldc_I4, (int)targetParameterTypes.Length - 1);

                // load the context provider
                mIL.Emit(OpCodes.Ldsfld, _contextProviderField);

                // get the invocation context from the array on the provider
                mIL.Emit(OpCodes.Ldsfld, _invocationContextsField);
                mIL.Emit(OpCodes.Ldc_I4, _invocationContexts.Count);
                mIL.Emit(OpCodes.Ldelem, typeof(InvocationContext));
                mIL.Emit(OpCodes.Callvirt, typeof(TraceContextProvider).GetMethod("ProvideContext"));
                _invocationContexts.Add(invocationContext);

                // put the result into the array
                mIL.Emit(OpCodes.Stelem, typeof(object));
            }

            // prepare for write event by setting the ETW activity ID
            mIL.Emit(OpCodes.Call, typeof(EventActivityScope).GetMethod("PrepareForWriteEvent"));

            // call writeevent
            mIL.Emit(OpCodes.Call, _writeEvent);
            mIL.Emit(OpCodes.Ret);
        }
 /// <summary>
 /// Initializes a new instance of the TraceSerializationContext class.
 /// </summary>
 /// <param name="invocationContext">The InvocationContext this is based on.</param>
 /// <param name="parameterIndex">The index of the parameter being serialized.</param>
 internal TraceSerializationContext(InvocationContext invocationContext, int parameterIndex)
     : base(invocationContext.MethodInfo, invocationContext.ContextType)
 {
     ParameterIndex = parameterIndex;
 }
        /// <summary>
        /// Emits a proxy to a method that just calls the base method.
        /// </summary>
        /// <param name="invocationContext">The current invocation context.</param>
        /// <param name="methodBuilder">The method to implement.</param>
        /// <param name="baseMethod">The base method.</param>
        /// <param name="parameterMapping">The mapping of the parameters.</param>
        private void EmitDirectProxy(InvocationContext invocationContext, MethodBuilder methodBuilder, MethodInfo baseMethod, List<ParameterMapping> parameterMapping)
        {
            /*
             * This method assume that a default return value has been pushed on the stack.
             *
             *		base(params);
             *		return (top of stack);
             */

            ILGenerator mIL = methodBuilder.GetILGenerator();

            // copy the parameters to the stack
            // arg.0 = this
            // so we go to length+1
            mIL.Emit(OpCodes.Ldarg_0);
            for (int i = 0; i < parameterMapping.Count; i++)
            {
                var parameter = parameterMapping[i];

                if (parameter.HasSource)
                {
                    ProxyHelper.EmitSerializeValue(
                        _typeBuilder,
                        methodBuilder,
                        invocationContext,
                        _invocationContexts,
                        _invocationContextsField,
                        parameter,
                        _serializationProvider,
                        _serializationProviderField);
                }
                else
                {
                    // if this method supports context, then add a context parameter
                    // note that we pass null in here and then build the context from within EmitCallWriteEvent
                    mIL.Emit(OpCodes.Ldnull);
                }
            }

            // now that all of the parameters have been loaded, call the base method
            mIL.Emit(OpCodes.Call, baseMethod);

            mIL.Emit(OpCodes.Ret);
        }