/// <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> /// 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> /// 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> /// 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); } }