public TraceMethod(MethodDefinition method, CustomAttribute a, bool isEmpty = true) { Method = method; IsEmpty = isEmpty; EventAttribute = a; if (a == null) { return; } Id = (int)a.ConstructorArguments[0].Value; Level = TraceMethod.GetProp <EventLevel, EventLevel?>(a, "Level", v => v); Keywords = TraceMethod.GetProp <EventKeywords, EventKeywords?>(a, "Keywords", v => v); Task = TraceMethod.GetProp <EventTask, NamedConst <int> >(a, "Task", v => NamedConst.Existing(v.ToString(), (int)v)); Opcode = TraceMethod.GetProp <EventOpcode, NamedConst <int> >(a, "Opcode", v => NamedConst.Existing(v.ToString(), (int)v)); if (Task != null) { log.Trace($"{method} {Task.Name}={Task.Value} - exists: {Task.Exists}"); } if (Opcode != null) { log.Trace($"{method} {Opcode.Name}={Opcode.Value} - exists: {Opcode.Exists}"); } }
protected void UpdateEventAttribute(MethodDefinition target, TraceMethod metadata) { var ea = metadata.EventAttribute; if (ea == null) { target.CustomAttributes.Add(ea = module.NewAttr(typeDefs.EventAttribute, metadata.Id)); } else { ea = target.CustomAttributes.Named("EventAttribute"); } if (metadata.Task != null) { if (!metadata.Task.Exists) { AddConst <int>(ensureTasks.Value, module.ImportReference(typeDefs.EventTask), metadata.Task); } ea.SetPropertyValue("Task", typeDefs.EventTask, metadata.Task.Value); } if (metadata.Opcode != null) { if (!metadata.Opcode.Exists) { AddConst <int>(ensureOpcodes.Value, module.ImportReference(typeDefs.EventOpcode), metadata.Opcode); } ea.SetPropertyValue("Opcode", typeDefs.EventOpcode, metadata.Opcode.Value); } }
protected virtual IEnumerable <TraceMethod> GetTraceMethods() { var maxId = 0; var loggers = Type.Methods.Where(IsTraceMethod); var needsId = new List <TraceMethod>(); var all = new List <TraceMethod>(); foreach (var logger in loggers) { var ea = logger.CustomAttributes.Named("EventAttribute"); var method = new TraceMethod(logger, ea, !logger.HasBody); if (ea == null) { needsId.Add(method); } else if (method.Id > maxId) { maxId = method.Id; } all.Add(method); } foreach (var method in needsId) { method.Id = ++maxId; } TryGenerateTasks(all); return(all); }
protected override MethodDefinition ImplementTraceMethod(TraceMethod metadata) { var source = metadata.Method; var newMethod = new MethodDefinition(source.Name, MethodAttributes.Public, module.ImportReference(source.ReturnType)); target.Methods.Add(newMethod); foreach (var p in source.Parameters) { newMethod.Parameters.Add(new ParameterDefinition(p.Name, p.Attributes, module.ImportReference(p.ParameterType))); } source.CopyAttrsTo(newMethod); SetTraceMethodBody(newMethod, metadata, EmitGuardedTracers); UpdateEventAttribute(newMethod, metadata); return(newMethod); }
protected void SetTraceMethodBody(MethodDefinition target, TraceMethod metadata, bool implementGuard = true) { target.CustomAttributes.Add(module.NewAttr(typeof(CompilerGeneratedAttribute))); var body = target.Body.Instructions; body.Clear(); using (var builder = new BodyBuilder(target)) { var exit = builder.DefineLabel(); if (implementGuard) { body.Add(EmitIsEnabledFallback()); body.Add(Instruction.Create(OpCodes.Brfalse, exit)); } body.Add(WriteEvent(builder, target, metadata).ToArray()); body.Add(exit); body.Add(Instruction.Create(OpCodes.Ret)); } }
public IEnumerable <Instruction> Emit(BodyBuilder builder, MethodDefinition method, TraceMethod metadata) { log.Warn($"Using WriteEventCore fallback for {method}"); var parameters = method.Parameters; var count = parameters.Count; var data = builder.DeclareLocal(typeDefs.EventDataRef.MakePointerType()); var item = builder.DeclareLocal(typeDefs.EventDataRef.MakePointerType()); ////> EventData* data = stackalloc EventData[4]; yield return(Instruction.Create(OpCodes.Ldc_I4, count)); yield return(Instruction.Create(OpCodes.Conv_U)); yield return(Instruction.Create(OpCodes.Sizeof, typeDefs.EventDataRef)); yield return(Instruction.Create(OpCodes.Mul_Ovf_Un)); yield return(Instruction.Create(OpCodes.Localloc)); yield return(Instruction.Create(OpCodes.Stloc, data)); ////> EventData* item = data yield return(Instruction.Create(OpCodes.Ldloc, data)); yield return(Instruction.Create(OpCodes.Stloc, item)); var first = true; foreach (var p in parameters) { if (first) { first = false; } else { ////> item ++; yield return(Instruction.Create(OpCodes.Ldloc, item)); yield return(Instruction.Create(OpCodes.Sizeof, typeDefs.EventDataRef)); yield return(Instruction.Create(OpCodes.Add)); yield return(Instruction.Create(OpCodes.Stloc, item)); } ////> item->DataPointer = ... ////> item->Size = ... var emitter = emitters[ResolveFullName(p)]; foreach (var i in emitter(builder, item, p)) { yield return(i); } } yield return(Instruction.Create(OpCodes.Ldarg_0)); yield return(Instruction.Create(OpCodes.Ldc_I4, metadata.Id)); yield return(Instruction.Create(OpCodes.Ldc_I4, count)); yield return(Instruction.Create(OpCodes.Ldloc, data)); yield return(Instruction.Create(OpCodes.Call, typeDefs.WriteEventCore)); }
protected abstract MethodDefinition ImplementTraceMethod(TraceMethod metadata);
private IEnumerable <Instruction> EmitWriteEventFallback(MethodDefinition method, TraceMethod metadata) { log.Warn($"Using WriteEvent fallback for {method.FullName}"); yield return(Instruction.Create(OpCodes.Ldarg_0)); yield return(Instruction.Create(OpCodes.Ldc_I4, metadata.Id)); var parameters = method.Parameters; var count = parameters.Count; yield return(Instruction.Create(OpCodes.Ldc_I4, count)); yield return(Instruction.Create(OpCodes.Newarr, module.TypeSystem.Object)); for (var i = 0; i < count; i++) { yield return(Instruction.Create(OpCodes.Dup)); yield return(Instruction.Create(OpCodes.Ldc_I4, i)); yield return(Instruction.Create(OpCodes.Ldarg, parameters[i])); if (parameters[i].ParameterType.IsValueType) { yield return(Instruction.Create(OpCodes.Box, parameters[i].ParameterType)); } yield return(Instruction.Create(OpCodes.Stelem_Ref)); } yield return(Instruction.Create(OpCodes.Call, typeDefs.WriteEventFallback)); }
private IEnumerable <Instruction> EmitSpecificWriteEvent(BodyBuilder builder, MethodDefinition method, MethodReference writeEvent, TraceMethod metadata) { yield return(Instruction.Create(OpCodes.Ldarg_0)); yield return(Instruction.Create(OpCodes.Ldc_I4, metadata.Id)); foreach (var p in method.Parameters) { yield return(Instruction.Create(OpCodes.Ldarg, p)); foreach (var i in EmitConvertCode(p.ParameterType.Resolve(), builder)) { yield return(i); } } yield return(Instruction.Create(OpCodes.Call, module.ImportReference(writeEvent))); }
private IEnumerable <Instruction> WriteEvent(BodyBuilder builder, MethodDefinition method, TraceMethod metadata) { var specificArgs = new[] { module.TypeSystem.Int32 } .Concat(method.Parameters .Select(p => ConvertToWriteEventParamType(p.ParameterType.Resolve()))); var specific = typeDefs.BaseTypeImpl.FindMethod("WriteEvent", specificArgs); return(specific != null ? EmitSpecificWriteEvent(builder, method, specific, metadata) #if ENABLE_UNSAFE : unsafeWriteEventBuilder.CanDo(method) ? unsafeWriteEventBuilder.Emit(builder, method, metadata) #endif : EmitWriteEventFallback(method, metadata)); }