// ... /// <summary> /// Emit a global method "MibcConfig" that will contain key-value settings in the following format: /// ldstr "key1" /// ldstr "value1" /// pop /// pop /// ldstr "key2" /// ldstr "value2" /// pop /// pop /// ... /// </summary> public static void GenerateConfigData(MibcConfig config, TypeSystemMetadataEmitter emitter) { var buffer = new BlobBuilder(); var il = new InstructionEncoder(buffer); foreach (FieldInfo mibcCfgField in typeof(MibcConfig).GetFields()) { Debug.Assert(!mibcCfgField.IsStatic && mibcCfgField.FieldType == typeof(string)); il.LoadString(emitter.GetUserStringHandle(mibcCfgField.Name)); il.LoadString(emitter.GetUserStringHandle((string)mibcCfgField.GetValue(config) ?? "")); il.OpCode(ILOpCode.Pop); il.OpCode(ILOpCode.Pop); } il.OpCode(ILOpCode.Ret); emitter.AddGlobalMethod(nameof(MibcConfig), il, 8); }
static int GenerateMibcFile(TraceTypeSystemContext tsc, FileInfo outputFileName, ICollection <ProcessedMethodData> methodsToAttemptToPlaceIntoProfileData, bool validate) { TypeSystemMetadataEmitter emitter = new TypeSystemMetadataEmitter(new AssemblyName(outputFileName.Name), tsc); SortedDictionary <string, MIbcGroup> groups = new SortedDictionary <string, MIbcGroup>(); StringBuilder mibcGroupNameBuilder = new StringBuilder(); HashSet <string> assembliesAssociatedWithMethod = new HashSet <string>(); foreach (var entry in methodsToAttemptToPlaceIntoProfileData) { MethodDesc method = entry.Method; assembliesAssociatedWithMethod.Clear(); AddAssembliesAssociatedWithMethod(method, assembliesAssociatedWithMethod, out string definingAssembly); string[] assemblyNames = new string[assembliesAssociatedWithMethod.Count]; int i = 1; assemblyNames[0] = definingAssembly; foreach (string s in assembliesAssociatedWithMethod) { if (s.Equals(definingAssembly)) { continue; } assemblyNames[i++] = s; } // Always keep the defining assembly as the first name Array.Sort(assemblyNames, 1, assemblyNames.Length - 1); mibcGroupNameBuilder.Clear(); foreach (string s in assemblyNames) { mibcGroupNameBuilder.Append(s); mibcGroupNameBuilder.Append(';'); } string mibcGroupName = mibcGroupNameBuilder.ToString(); if (!groups.TryGetValue(mibcGroupName, out MIbcGroup mibcGroup)) { mibcGroup = new MIbcGroup(mibcGroupName, emitter); groups.Add(mibcGroupName, mibcGroup); } mibcGroup.AddProcessedMethodData(entry); } var buffer = new BlobBuilder(); var il = new InstructionEncoder(buffer); foreach (var entry in groups) { il.LoadString(emitter.GetUserStringHandle(entry.Key)); il.OpCode(ILOpCode.Ldtoken); il.Token(entry.Value.EmitMethod()); il.OpCode(ILOpCode.Pop); } emitter.AddGlobalMethod("AssemblyDictionary", il, 8); MemoryStream peFile = new MemoryStream(); emitter.SerializeToStream(peFile); peFile.Position = 0; if (outputFileName.Exists) { outputFileName.Delete(); } using (ZipArchive file = ZipFile.Open(outputFileName.FullName, ZipArchiveMode.Create)) { var entry = file.CreateEntry(outputFileName.Name + ".dll", CompressionLevel.Optimal); using (Stream archiveStream = entry.Open()) { peFile.CopyTo(archiveStream); } } Console.WriteLine($"Generated {outputFileName.FullName}"); if (validate) { return(ValidateMIbcData(tsc, outputFileName, peFile.ToArray(), methodsToAttemptToPlaceIntoProfileData)); } else { return(0); } }
public void AddProcessedMethodData(MethodProfileData processedMethodData) { MethodDesc method = processedMethodData.Method; // Format is // ldtoken method // variable amount of extra metadata about the method, Extension data is encoded via ldstr "id" // pop // Extensions generated by this emitter: // // ldstr "ExclusiveWeight" // Any ldc.i4 or ldc.r4 or ldc.r8 instruction to indicate the exclusive weight // // ldstr "WeightedCallData" // ldc.i4 <Count of methods called> // Repeat <Count of methods called times> // ldtoken <Method called from this method> // ldc.i4 <Weight associated with calling the <Method called from this method>> // // ldstr "InstrumentationDataStart" // Encoded ints and longs, using ldc.i4, and ldc.i8 instructions as well as ldtoken <type> instructions // ldstr "InstrumentationDataEnd" as a terminator try { EntityHandle methodHandle = _emitter.GetMethodRef(method); _il.OpCode(ILOpCode.Ldtoken); _il.Token(methodHandle); if (processedMethodData.ExclusiveWeight != 0) { _il.LoadString(_emitter.GetUserStringHandle("ExclusiveWeight")); if (((double)(int)processedMethodData.ExclusiveWeight) == processedMethodData.ExclusiveWeight) { _il.LoadConstantI4((int)processedMethodData.ExclusiveWeight); } else { _il.LoadConstantR8(processedMethodData.ExclusiveWeight); } } if ((processedMethodData.CallWeights != null) && processedMethodData.CallWeights.Count > 0) { _il.LoadString(_emitter.GetUserStringHandle("WeightedCallData")); _il.LoadConstantI4(processedMethodData.CallWeights.Count); foreach (var entry in processedMethodData.CallWeights) { EntityHandle calledMethod = _emitter.GetMethodRef(entry.Key); _il.OpCode(ILOpCode.Ldtoken); _il.Token(calledMethod); _il.LoadConstantI4(entry.Value); } } if (processedMethodData.SchemaData != null) { _il.LoadString(_emitter.GetUserStringHandle("InstrumentationDataStart")); PgoProcessor.EncodePgoData <TypeSystemEntityOrUnknown, TypeSystemEntityOrUnknown>(processedMethodData.SchemaData, this, true); } _il.OpCode(ILOpCode.Pop); } catch (Exception ex) { Program.PrintWarning($"Exception {ex} while attempting to generate method lists"); } }