public static void ProfilePatch()
        {
            var patches = Harmony.GetAllPatchedMethods().ToList();

            var filteredTranspilers = patches
                                      .Where(m => Harmony.GetPatchInfo(m).Transpilers.Any(p => Utility.IsNotAnalyzerPatch(p.owner) && !TranspilerMethodUtility.PatchedMeths.Contains(m)))
                                      .ToList();

            TranspilerMethodUtility.PatchedMeths.AddRange(filteredTranspilers);

            foreach (var meth in filteredTranspilers)
            {
                try
                {
                    Modbase.Harmony.Patch(meth, transpiler: TranspilerMethodUtility.TranspilerProfiler);
                }
                catch (Exception e)
                {
#if DEBUG
                    ThreadSafeLogger.ReportException(e, $"[Analyzer] Failed to patch transpiler {Utility.GetSignature(meth, false)}");
#endif
#if NDEBUG
                    if (Settings.verboseLogging)
                    {
                        ThreadSafeLogger.ReportException(e, $"[Analyzer] Failed to patch transpiler {Utility.GetSignature(meth, false)}");
                    }
#endif
                }
            }
        }
Ejemplo n.º 2
0
        public static int AddMethod(string key, MethodInfo method)
        {
            int index = 0;

            lock (indexLock)
            {
                if (nameToKey.TryGetValue(key, out var i))
                {
                    return(i);
                }

                index = currentIndex++;

                if ((index & 0x7f) == 127)
                {
                    internalArrays.Add(new MethodInfo[0x80]);
#if DEBUG
                    ThreadSafeLogger.Message("[Analyzer] Adding new internal array to the MethodInfoCache");
#endif
                }

                nameToKey.Add(key, index);
            }

            internalArrays[index >> 7][index & 0x7f] = method;

            return(index);
        }
Ejemplo n.º 3
0
        /* CreateType creates a type at runtime which inherits from 'Entry', it creates a type with one field and two methods
         * Field: 'Active' signifying whether the entry is currently active or not
         * Ctor: Sets 'Active' to false.
         * Method: 'GetPatchMethods' given a string, finds a list of methods in a dictionary which represent the methods this type is profiling
         * they are stored in the `methods` dictionary, and added to in the CreateType method.
         */

        public static Type CreateType(string input, HashSet <MethodInfo> methods)
        {
            var name = string.Concat(input.Where(x => char.IsLetter(x) && !char.IsSymbol(x) && !char.IsWhiteSpace(x)));

#if DEBUG
            ThreadSafeLogger.Message($"[Analyzer] Converted the parameter called {input} into {name}, creating type");
#endif

            ThreadSafeLogger.Message(name);
            TypeBuilder tb = ModuleBuilder.DefineType(name, staticAtt, typeof(Entry));

            FieldBuilder active = tb.DefineField("Active", typeof(bool), FieldAttributes.Public | FieldAttributes.Static);

            DynamicTypeBuilder.methods.Add(name, methods ?? new HashSet <MethodInfo>());
            ConstructorBuilder ivCtor = tb.DefineConstructor(MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, new Type[0]);

            // default initialise active to false.
            ILGenerator ctorIL = ivCtor.GetILGenerator();
            ctorIL.Emit(OpCodes.Ldc_I4_0);
            ctorIL.Emit(OpCodes.Stsfld, active);
            ctorIL.Emit(OpCodes.Ret);

            CreateProfilePatch(name, tb);

            return(tb.CreateType());
        }
        public static void ProfilePatch()
        {
            var patches = Harmony.GetAllPatchedMethods().ToList();

            var filteredTranspilers = patches
                                      .Where(m => Harmony.GetPatchInfo(m).Transpilers.Any(p => Utility.IsNotAnalyzerPatch(p.owner) && !TranspilerMethodUtility.PatchedMeths.Contains(m)))
                                      .ToList();

            TranspilerMethodUtility.PatchedMeths.AddRange(filteredTranspilers);

            foreach (var meth in filteredTranspilers)
            {
                try
                {
                    Modbase.Harmony.Patch(meth, transpiler: TranspilerMethodUtility.TranspilerProfiler);
                }
                catch (Exception e)
                {
#if DEBUG
                    ThreadSafeLogger.Error($"[Analyzer] Failed to patch transpiler, failed with the message {e.Message}");
#endif
#if NDEBUG
                    if (Settings.verboseLogging)
                    {
                        ThreadSafeLogger.Error($"[Analyzer] Failed to patch transpiler {meth.DeclaringType.FullName + ":" + meth.Name}, failed with the message {e.Message}");
                    }
#endif
                }
            }
        }
Ejemplo n.º 5
0
        public static void ExecuteWorker(int[] LocalCalls, double[] LocalTimes, int currentLogCount)
        {
            try
            {
                // todo
                // implement a custom sorting which also keeps track of the sum.
                // this will take this from
                // o(2*nlogn + n) to o(2*nlogn)

                var stats = GatherStats(LocalCalls, LocalTimes, currentLogCount);

                lock (CurrentLogStats.sync) // Dump our current statistics into our static class which our drawing class uses
                {
                    CurrentLogStats.stats = stats;
                }
            }
            catch (Exception e)
            {
#if DEBUG
                ThreadSafeLogger.ReportException(e, $"[Analyzer] Failed while calculating stats for profiler");
#else
                if (Settings.verboseLogging)
                {
                    ThreadSafeLogger.ReportException(e, $"[Analyzer] Failed while calculating stats for profiler");
                }
#endif
            }
        }
        // Clear the caches which prevent double patching
        public static void ClearCaches()
        {
            PatchedMeths.Clear();
#if DEBUG
            ThreadSafeLogger.Message("[Analyzer] Cleaned up the transpiler methods caches");
#endif
        }
        internal static void UpdateMethod(Type type, MethodInfo meth)
        {
            if (patchedMeths.Contains(meth))
            {
                if (Settings.verboseLogging)
                {
                    ThreadSafeLogger.Warning($"[Analyzer] Already patched method {meth.DeclaringType.FullName + ":" + meth.Name}");
                }

                return;
            }

            patchedMeths.Add(meth);
            typeInfo.TryAdd(meth, type);

            Task.Factory.StartNew(delegate
            {
                try
                {
                    Modbase.Harmony.Patch(meth, transpiler: transpiler);
                }
                catch (Exception e)
                {
                    if (Settings.verboseLogging)
                    {
                        ThreadSafeLogger.Warning($"[Analyzer] Failed to patch method {meth.DeclaringType.FullName}:{meth.Name} failed with the error {e.Message}");
                    }
                }
            });
        }
        public static FileHeader ReadHeader(BinaryReader reader)
        {
            var fileHeader = new FileHeader()
            {
                MAGIC                 = reader.ReadInt32(),
                scribingVer           = reader.ReadInt32(),
                methodName            = reader.ReadString(),
                name                  = reader.ReadString(),
                entryPerCall          = reader.ReadBoolean(),
                onlyEntriesWithValues = reader.ReadBoolean(),
                entries               = reader.ReadInt32(),
                targetEntries         = reader.ReadInt32()
            };

            if (fileHeader.MAGIC == ENTRY_FILE_MAGIC)
            {
                return(fileHeader);
            }

            ThreadSafeLogger.Error($"Loaded header has an invalid MAGIC number, this indicates disk corruption");
            return(new FileHeader()
            {
                MAGIC = -1
            });                                     // magic = -1 is an error value.
        }
        public static void RegisterHarmonyId(string harmonyid, Assembly assembly)
        {
            if (harmonyIds.TryGetValue(harmonyid, out var asm))
            {
                mods.TryGetValue(asm, out var asmMod);
                mods.TryGetValue(assembly, out var assemblyMod);

                // Doesn't matter a whole lot
                if (asmMod == assemblyMod)
                {
                    return;
                }

                var blameString = $"This is a Harmony ID configuration issue with {asmMod} and {assemblyMod}. Please report that they are instantiating harmony with the same ID.";

                ThreadSafeLogger.Error($"The HarmonyID {harmonyid} has been loaded twice. It is associated with both: \n{asm.FullName} and {assembly.FullName}\n{blameString}\n\nEnable verbose logging and restart to view the associated callstack(s)");
                if (Settings.verboseLogging)
                {
                    ThreadSafeLogger.Error($"Initial Trace: {GetStackTraceString(harmonyIds_d[harmonyid], out _)}");
                    ThreadSafeLogger.Error($"Current Trace: {GetStackTraceString(new StackTrace(1, false), out _)}");
                }
            }
            else
            {
                harmonyIds.Add(harmonyid, assembly);
                if (Settings.verboseLogging)
                {
                    harmonyIds_d.Add(harmonyid, new StackTrace(1, false));
                }
            }
        }
Ejemplo n.º 10
0
        public static void AddEntry(string name, Category category)
        {
            Type myType = null;

            if (types.ContainsKey(name))
            {
                myType = types[name];
            }
            else
            {
                myType = DynamicTypeBuilder.CreateType(name, null);
                types.Add(name, myType);
            }

#if DEBUG
            ThreadSafeLogger.Message($"Adding entry {name} into the category {category}");
#endif
            var entry = Entry.Create(name, category, myType, true, true);

            if (Tab(category).entries.ContainsKey(entry))
            {
                ThreadSafeLogger.Error($"Attempting to re-add entry {name} into the category {category}");
            }
            else
            {
                Tab(category).entries.Add(entry, myType);
            }
        }
Ejemplo n.º 11
0
        public static void ClearCaches()
        {
            PatchedInternals.Clear();

#if DEBUG
            ThreadSafeLogger.Message("[Analyzer] Cleaned up the internal method caches");
#endif
        }
Ejemplo n.º 12
0
        private static IEnumerable <CodeInstruction> Transpiler(MethodBase __originalMethod, IEnumerable <CodeInstruction> codeInstructions)
        {
            var enumerable = codeInstructions.ToList();

            try
            {
                List <CodeInstruction> instructions = enumerable;

                for (int i = 0; i < instructions.Count; i++)
                {
                    if (!IsFunctionCall(instructions[i].opcode))
                    {
                        continue;
                    }
                    if (!(instructions[i].operand is MethodInfo meth))
                    {
                        continue;
                    }

                    // Check for constrained
                    if (i != 0 && instructions[i - 1].opcode == OpCodes.Constrained)
                    {
                        continue;
                    }
                    // Make sure it is not an analyzer profiling method
                    if (meth.DeclaringType.FullName.Contains("Analyzer.Profiling"))
                    {
                        continue;
                    }

                    var key   = Utility.GetMethodKey(meth);
                    var index = MethodInfoCache.AddMethod(key, meth);

                    var inst = MethodTransplanting.ReplaceMethodInstruction(
                        instructions[i],
                        key,
                        GUIController.types[__originalMethod.DeclaringType + ":" + __originalMethod.Name + "-int"],
                        index);

                    instructions[i] = inst;
                }

                return(instructions);
            }
            catch (Exception e)
            {
#if DEBUG
                ThreadSafeLogger.Error($"Failed to patch the internal method {__originalMethod.DeclaringType.FullName}:{__originalMethod.Name}, failed with the error " + e.Message);
#else
                if (Settings.verboseLogging)
                {
                    ThreadSafeLogger.Warning($"Failed to patch the internal method {__originalMethod.DeclaringType.FullName}:{__originalMethod.Name}, failed with the error " + e.Message);
                }
#endif

                return(enumerable);
            }
        }
Ejemplo n.º 13
0
        private static void ExecuteWorker(LogStats logic, int[] LocalCalls, double[] LocalTimes, int currentLogCount,
                                          uint currentIndex)
        {
            try
            {
                // todo
                // implement a custom sorting which also keeps track of the sum.
                // this will take this from
                // o(2*nlogn + n) to o(2*nlogn)

                Array.Sort(LocalCalls);
                Array.Sort(LocalTimes);


                for (var i = 0; i < Profiler.RECORDS_HELD; i++)
                {
                    logic.TotalCalls += LocalCalls[i];
                    logic.TotalTime  += LocalTimes[i];
                }

                // Mean
                logic.MeanTimePerCall         = logic.TotalTime / logic.TotalCalls;
                logic.MeanTimePerUpdateCycle  = logic.TotalTime / currentLogCount;
                logic.MeanCallsPerUpdateCycle = logic.TotalCalls / (float)currentLogCount;

                var medianOffset = Profiler.RECORDS_HELD - currentLogCount;
                var middle       = currentLogCount / 2;
                // Medians
                logic.MedianTime  = LocalTimes[medianOffset + middle];
                logic.MedianCalls = LocalCalls[medianOffset + middle];

                // Max
                logic.HighestTime  = LocalTimes[Profiler.RECORDS_HELD - 1];
                logic.HighestCalls = LocalCalls[Profiler.RECORDS_HELD - 1];

                // general
                logic.Entries = currentLogCount;

                lock (CurrentLogStats.sync
                      ) // Dump our current statistics into our static class which our drawing class uses
                {
                    CurrentLogStats.stats = logic;
                }
            }
            catch (Exception e)
            {
#if DEBUG
                ThreadSafeLogger.Error(
                    $"[Analyzer] Failed while calculating stats for profiler, errored with the message {e.Message}");
#else
                if (Settings.verboseLogging)
                {
                    ThreadSafeLogger.Error($"[Analyzer] Failed while calculating stats for profiler, errored with the message {e.Message}");
                }
#endif
            }
        }
Ejemplo n.º 14
0
        public static void ProfilePatch()
        {
            MethodInfo    jiff = AccessTools.Method(typeof(StatExtension), nameof(StatExtension.GetStatValue));
            HarmonyMethod pre  = new HarmonyMethod(typeof(H_GetStatValue), nameof(Prefix));
            HarmonyMethod post = new HarmonyMethod(typeof(H_GetStatValue), nameof(Postfix));

            Modbase.Harmony.Patch(jiff, pre, post);


            jiff = AccessTools.Method(typeof(StatExtension), nameof(StatExtension.GetStatValueAbstract), new[] { typeof(BuildableDef), typeof(StatDef), typeof(ThingDef) });
            pre  = new HarmonyMethod(typeof(H_GetStatValue), nameof(PrefixAb));
            Modbase.Harmony.Patch(jiff, pre, post);

            jiff = AccessTools.Method(typeof(StatExtension), nameof(StatExtension.GetStatValueAbstract), new[] { typeof(AbilityDef), typeof(StatDef) });
            pre  = new HarmonyMethod(typeof(H_GetStatValue), nameof(PrefixAbility));
            Modbase.Harmony.Patch(jiff, pre, post);

            jiff = AccessTools.Method(typeof(StatWorker), nameof(StatWorker.GetValue), new[] { typeof(StatRequest), typeof(bool) });
            pre  = new HarmonyMethod(typeof(H_GetStatValue), nameof(GetValueDetour));
            Modbase.Harmony.Patch(jiff, pre);


            HarmonyMethod go   = new HarmonyMethod(typeof(H_GetStatValue), nameof(PartPrefix));
            HarmonyMethod biff = new HarmonyMethod(typeof(H_GetStatValue), nameof(PartPostfix));

            foreach (Type allLeafSubclass in typeof(StatPart).AllSubclassesNonAbstract())
            {
                try
                {
                    MethodInfo mef = AccessTools.Method(allLeafSubclass, nameof(StatPart.TransformValue), new Type[] { typeof(StatRequest), typeof(float).MakeByRefType() });
                    if (mef.DeclaringType == allLeafSubclass)
                    {
                        Patches info = Harmony.GetPatchInfo(mef);
                        bool    F    = true;
                        if (info != null)
                        {
                            foreach (Patch infoPrefix in info.Prefixes)
                            {
                                if (infoPrefix.PatchMethod == go.method)
                                {
                                    F = false;
                                }
                            }
                        }

                        if (F)
                        {
                            Modbase.Harmony.Patch(mef, go, biff);
                        }
                    }
                }
                catch (Exception)
                {
                    ThreadSafeLogger.Error($"Failed to patch {allLeafSubclass} from {allLeafSubclass.Assembly.FullName} for profiling");
                }
            }
        }
 public static void ProfilePatch()
 {
     try
     {
         MethodTransplanting.PatchMethods(typeof(H_HarmonyPatches));
     }
     catch (Exception e)
     {
         ThreadSafeLogger.ReportException(e, "Failed to patch HarmonyPatches");
     }
 }
Ejemplo n.º 16
0
 public static void ProfilePatch()
 {
     try
     {
         MethodTransplanting.PatchMethods(typeof(H_HarmonyPatches));
     }
     catch (Exception e)
     {
         ThreadSafeLogger.Error("Patching HarmonyPatches failed, errored with the message" + e.Message);
     }
 }
Ejemplo n.º 17
0
        public static void ExecutePatch(CurrentInput mode, string strinput, Category cat)
        {
            try
            {
                var entry = cat == Category.Tick ? typeof(CustomProfilersTick) : typeof(CustomProfilersUpdate);
                List <MethodInfo> methods = null;

                var temp = mode switch
                {
                    CurrentInput.Method => Utility.GetMethods(strinput),
                    CurrentInput.Type => Utility.GetTypeMethods(AccessTools.TypeByName(strinput)),
                    CurrentInput.MethodHarmony => Utility.GetMethodsPatching(strinput),
                    CurrentInput.SubClasses => Utility.SubClassImplementationsOf(AccessTools.TypeByName(strinput), m => true),
                    CurrentInput.TypeHarmony => Utility.GetMethodsPatchingType(AccessTools.TypeByName(strinput)),
                    _ => null,
                };

                if (temp is null)
                {
                    if (mode == CurrentInput.InternalMethod)
                    {
                        Utility.PatchInternalMethod(strinput, cat);
                    }
                    else
                    {
                        Utility.PatchAssembly(strinput, cat);
                    }

                    return;
                }

                methods = temp.ToList();

                if (methods.Count == 0)
                {
                    Messages.Message($"Failed to find the method(s) represented by {strinput}", MessageTypeDefOf.CautionInput, false);
                    return;
                }

                Messages.Message(methods.Count != 1 ? $"Patching {methods.Count} methods in the category {cat}" : $"Patching {Utility.GetSignature(methods[0])} in the category {cat}", MessageTypeDefOf.CautionInput, false);

                MethodTransplanting.UpdateMethods(entry, methods.ToList());
                GUIController.Tab(cat).collapsed = false;

                var entryName = (cat == Category.Tick) ? "Custom Tick" : "Custom Update";
                GUIController.SwapToEntry(entryName);
            }
            catch (Exception e)
            {
                ThreadSafeLogger.ReportException(e, $"Failed to process search bar input");
            }
        }
Ejemplo n.º 18
0
        public static void RemoveEntry(string name)
        {
            var entry = EntryByName(name);

            entry.isPatched = false;
            entry.SetActive(false);

            Tab(entry.category).entries.Remove(entry);

#if DEBUG
            ThreadSafeLogger.Message($"Removing entry {name} from the category {entry.category.ToString()}");
#endif
        }
Ejemplo n.º 19
0
        private static void ReportException(Exception e, string message)
        {
#if DEBUG
            ThreadSafeLogger.ReportException(e, $"[Analyzer] Patching error: {message}");
#endif
#if NDEBUG
            if (!displayMessages)
            {
                return;
            }
            ThreadSafeLogger.ReportException(e, message);
#endif
        }
Ejemplo n.º 20
0
        private static void Error(string message)
        {
#if DEBUG
            ThreadSafeLogger.Error($"[Analyzer] Patching error: {message}");
#endif
#if NDEBUG
            if (!displayMessages)
            {
                return;
            }
            ThreadSafeLogger.Error($"[Analyzer] Patching error: {message}");
#endif
        }
Ejemplo n.º 21
0
        public static void ClearCache()
        {
            lock (indexLock)
            {
                currentIndex = 0;

                internalArrays.Clear();
                nameToKey.Clear();
            }
            internalArrays.Add(new MethodInfo[0x80]);
#if DEBUG
            ThreadSafeLogger.Message("[Analyzer] Cleaned up the MethodInfoCache");
#endif
        }
        internal static void Prefix(string id)
        {
            try
            {
                if (Utility.IsNotAnalyzerPatch(id) is false)
                {
                    return;
                }

                // Can't be sure that the JIT won't inline the constructor of harmony
                // so we need to manually trawl until we find a method which doesn't belong
                // to either dpa or harmony. (this prefix, and the harmony ctor)
                var frames = new StackTrace(false).GetFrames();
                if (frames == null)
                {
                    return;
                }

                var methods = frames.Select(Harmony.GetMethodFromStackframe).Select(m => m is MethodInfo mi ? Harmony.GetOriginalMethod(mi) ?? m : m);

                // find the first non harmony/dpa method in the stack trace and assoc the asm
                // that method is from with the stack trace
                foreach (var method in methods)
                {
                    var asm = method.DeclaringType?.Assembly ?? method.ReflectedType?.Assembly;
                    if (asm == null)
                    {
                        continue;
                    }

                    if (asm.FullName.Contains("Harmony") || asm == dpaAssembly)
                    {
                        continue;
                    }

                    // we snipe this in another way
                    if (method.Name == "ApplyHarmonyPatches")
                    {
                        return;
                    }

                    StackTraceUtility.RegisterHarmonyId(id, asm);
                    return;
                }
            }
            catch (Exception e) // lets be exceedingly careful.
            {
                ThreadSafeLogger.ReportException(e, "Failed to capture Harmony ctor");
            }
        }
Ejemplo n.º 23
0
        public static void BeginUpdate()
        {
#if DEBUG
            if (Analyzer.CurrentlyPaused)
            {
                return;
            }

            if (midUpdate)
            {
                ThreadSafeLogger.Error("[Analyzer] Attempting to begin new update cycle when the previous update has not ended");
            }
            midUpdate = true;
#endif
        }
Ejemplo n.º 24
0
        public static void ClearPatchCaches()
        {
            patchedAssemblies.Clear();
            patchedTypes.Clear();
            patchedMethods.Clear();

            InternalMethodUtility.ClearCaches();
            MethodTransplanting.ClearCaches();
            TranspilerMethodUtility.ClearCaches();

            MethodInfoCache.ClearCache();

#if DEBUG
            ThreadSafeLogger.Message("[Analyzer] Cleared all caches");
#endif
        }
        // Mostly here for book keeping, optimised out of a release build.
        public static void BeginUpdate()
        {
            if (Analyzer.CurrentlyPaused)
            {
                return;
            }

            rootProf.Start();

            if (midUpdate)
            {
                ThreadSafeLogger.Error("[CRITICAL] Caught analyzer trying to begin a new update cycle before finishing the previous one.");
            }

            midUpdate = true;
        }
Ejemplo n.º 26
0
        public void RecordMeasurement()
        {
#if DEBUG
            if (stopwatch.IsRunning)
            {
                ThreadSafeLogger.Error($"[Analyzer] Profile {key} was still running when recorded");
            }
#endif

            times[currentIndex] = stopwatch.Elapsed.TotalMilliseconds;
            hits[currentIndex]  = hitCounter;

            currentIndex = (currentIndex + 1) % RECORDS_HELD; // ring buffer

            stopwatch.Reset();
            hitCounter = 0;
        }
Ejemplo n.º 27
0
        // Iterates through each child element in the document and attempts to extract method(s) from the strings inside the children
        private static void Parse(XmlDocument doc)
        {
            foreach (XmlNode node in doc.DocumentElement.ChildNodes) // entries should be
            {
                var meths = new HashSet <MethodInfo>();
                foreach (XmlNode child in node.ChildNodes)
                {
                    switch (child.Name.ToLower())
                    {
                    case "methods":
                    case "method":
                        foreach (XmlNode method in child.ChildNodes)
                        {
                            meths.Add(ParseMethod(method.InnerText));
                        }
                        break;

                    case "types":
                    case "type":
                        foreach (XmlNode type in child.ChildNodes)
                        {
                            meths.AddRange(ParseTypeMethods(type.InnerText));
                        }
                        break;

                    case "nestedtype":
                    case "nestedtypes":
                        foreach (XmlNode type in child.ChildNodes)
                        {
                            meths.AddRange(ParseSubTypeTypeMethods(type.InnerText));
                        }
                        break;

                    default:
                        ThreadSafeLogger.Error($"[Analyzer] Attempting to read unknown value from an Analyzer.xml, the given input was {child.Name}, it should have been either '(M/m)ethods', '(T/t)ypes' '(N/n)estedTypes");
                        break;
                    }
                }

                Type myType = DynamicTypeBuilder.CreateType(node.Name, meths);

                GUIController.Tab(Category.Modder).entries.Add(Entry.Create(myType.Name, Category.Modder, myType, false, true), myType);
            }
        }
        public static EntryFile ReadFile(FileInfo file)
        {
            var entryFile = new EntryFile();

            try
            {
                using (var reader = new BinaryReader(file.OpenRead()))
                {
                    entryFile.header = ReadHeader(reader);
                    if (entryFile.header.MAGIC == -1)
                    {
                        return(null);
                    }

                    entryFile.times = new double[entryFile.header.entries];
                    entryFile.calls = new int[entryFile.header.entries];
                    if (entryFile.header.entryPerCall)
                    {
                        Array.Fill(entryFile.calls, 1);
                    }

                    for (int i = 0; i < entryFile.header.entries; i++)
                    {
                        entryFile.times[i] = reader.ReadDouble();
                        if (!entryFile.header.entryPerCall)
                        {
                            entryFile.calls[i] = reader.ReadInt32();
                        }
                    }

                    reader.Close();
                    reader.Dispose();
                }
            }
            catch (Exception e)
            {
                ThreadSafeLogger.ReportException(e, "Failed while reading entry file from disk.");
            }

            return(entryFile);
        }
        private static IEnumerable <CodeInstruction> Transpiler(MethodBase __originalMethod, IEnumerable <CodeInstruction> codeInstructions)
        {
            try
            {
                var instructions = codeInstructions.ToList();

                for (int i = 0; i < instructions.Count; i++)
                {
                    if (!Utility.ValidCallInstruction(instructions[i], i == 0 ? null : instructions[i - 1], out var meth, out var key))
                    {
                        continue;
                    }

                    var index = MethodInfoCache.AddMethod(key, meth);

                    var inst = MethodTransplanting.ReplaceMethodInstruction(
                        instructions[i],
                        key,
                        GUIController.types[__originalMethod.DeclaringType + ":" + __originalMethod.Name + "-int"],
                        index);

                    instructions[i] = inst;
                }

                return(instructions);
            }
            catch (Exception e)
            {
#if DEBUG
                ThreadSafeLogger.ReportException(e, $"Failed to patch the methods inside {Utility.GetSignature(__originalMethod, false)}");
#else
                if (Settings.verboseLogging)
                {
                    ThreadSafeLogger.ReportException(e, $"Failed to patch the methods inside {Utility.GetSignature(__originalMethod, false)}");
                }
#endif

                return(codeInstructions);
            }
        }
        public static void WriteFile(EntryFile file)
        {
            var fileName = FinalFileNameFor(file.header.methodName);

            try
            {
                using (var writer = new BinaryWriter(File.Open(fileName, FileMode.Create)))
                {
                    writer.Write(file.header.MAGIC);
                    writer.Write(file.header.scribingVer);
                    writer.Write(file.header.methodName);
                    writer.Write(file.header.name);
                    writer.Write(file.header.entryPerCall);
                    writer.Write(file.header.onlyEntriesWithValues);
                    writer.Write(file.header.entries);
                    writer.Write(file.header.targetEntries);

                    // interleaved is faster by profiling, (even if less cache-efficient)
                    for (var i = 0; i < file.header.entries; i++)
                    {
                        writer.Write(file.times[i]);
                        if (!file.header.entryPerCall)
                        {
                            writer.Write(file.calls[i]);
                        }
                    }

                    writer.Close();
                    writer.Dispose();
                }
            }
            catch (Exception e)
            {
                ThreadSafeLogger.ReportException(e, $"Caught an exception when writing file to disk, if the file exists on disk, it should be deleted at {fileName}");
            }


            changed = true;
        }