XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
using Mono.Cecil;
using Mono.Cecil.Cil;

/// <summary>Leaf reads of the pinned collector's completed-GC snapshot.</summary>
internal static class GcMemoryRuntimePatch
{
    private const string Prefix = "XfeLastGcMetricV1_";
    private static readonly string[] Fields = ["HeapSizeBytes", "FragmentedBytes", "TotalCommittedBytes", "CollectionIndex"];
    private static readonly string[] Exports = ["XfeRuntimeLastGcHeapSpanBytes", "XfeRuntimeLastGcFragmentedBytes", "XfeRuntimeLastGcCommittedBytes", "XfeRuntimeLastGcCollectionIndex"];

    public static bool Apply(AssemblyDefinition assembly)
    {
        var module = assembly.MainModule;
        var gc = module.Types.Single(type => type.FullName == "Cosmos.Kernel.Core.Memory.GarbageCollector.GarbageCollector");
        var snapshot = gc.Fields.Single(field => field.Name == "s_lastGCMemoryInfo");
        var info = snapshot.FieldType.Resolve();
        if (!snapshot.IsStatic || !info.IsValueType || Fields.Where((name, index) =>
                info.Fields.Single(field => field.Name == name).FieldType.MetadataType != (index == 3 ? MetadataType.Int32 : MetadataType.UInt64)).Any())
            throw new InvalidOperationException("The pinned completed-GC snapshot layout changed.");

        var existing = gc.Methods.Where(method => method.Name.StartsWith(Prefix, StringComparison.Ordinal)).ToArray();
        if (existing.Length != 0)
        {
            if (existing.Length != Fields.Length) throw new InvalidOperationException("Incomplete GC snapshot exports.");
            Verify();
            return true;
        }
        for (int index = 0; index < Fields.Length; index++)
        {
            var field = info.Fields.Single(candidate => candidate.Name == Fields[index]);
            var method = new MethodDefinition(Prefix + Fields[index], MethodAttributes.Assembly | MethodAttributes.Static | MethodAttributes.HideBySig, module.TypeSystem.UInt64);
            var export = new CustomAttribute(module.ImportReference(typeof(System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute).GetConstructor(Type.EmptyTypes)!));
            export.Fields.Add(new("EntryPoint", new CustomAttributeArgument(module.TypeSystem.String, Exports[index])));
            method.CustomAttributes.Add(export);
            gc.Methods.Add(method);
            var il = method.Body.GetILProcessor();
            il.Append(il.Create(OpCodes.Ldsflda, snapshot));
            il.Append(il.Create(OpCodes.Ldfld, field));
            if (index == 3) il.Append(il.Create(OpCodes.Conv_U8));
            il.Append(il.Create(OpCodes.Ret));
            method.Body.MaxStackSize = 1;
        }
        var handleManager = gc.Fields.Single(field => field.Name == "s_gCHandleManager");
        var dependentStore = handleManager.FieldType.Resolve().Fields.Single(field => field.Name == "DependentHandleStore");
        var count = dependentStore.FieldType.Resolve().Methods.Single(method => method.Name == "get_Count");
        var countExport = new MethodDefinition("XfeDependentHandleCountV1", MethodAttributes.Assembly | MethodAttributes.Static | MethodAttributes.HideBySig, module.TypeSystem.UInt64);
        var countAttribute = new CustomAttribute(module.ImportReference(typeof(System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute).GetConstructor(Type.EmptyTypes)!));
        countAttribute.Fields.Add(new("EntryPoint", new CustomAttributeArgument(module.TypeSystem.String, "XfeRuntimeDependentHandleCount")));
        countExport.CustomAttributes.Add(countAttribute); gc.Methods.Add(countExport);
        var countIl = countExport.Body.GetILProcessor();
        countIl.Append(countIl.Create(OpCodes.Ldsflda, handleManager));
        countIl.Append(countIl.Create(OpCodes.Ldflda, dependentStore));
        countIl.Append(countIl.Create(OpCodes.Call, count));
        countIl.Append(countIl.Create(OpCodes.Ret)); countExport.Body.MaxStackSize = 1;
        Verify();
        return false;

        void Verify()
        {
            var count = gc.Methods.SingleOrDefault(method => method.Name == "XfeDependentHandleCountV1");
            if (count is null || count.Parameters.Count != 0 || count.ReturnType.MetadataType != MetadataType.UInt64 || count.Body.Instructions.Count != 4 ||
                count.Body.Instructions[0].OpCode != OpCodes.Ldsflda || count.Body.Instructions[0].Operand is not FieldReference manager || manager.Name != "s_gCHandleManager" ||
                count.Body.Instructions[1].OpCode != OpCodes.Ldflda || count.Body.Instructions[1].Operand is not FieldReference store || store.Name != "DependentHandleStore" ||
                count.Body.Instructions[2].OpCode != OpCodes.Call || count.Body.Instructions[2].Operand is not MethodReference getter || getter.Name != "get_Count" ||
                getter.DeclaringType.FullName != "Cosmos.Kernel.Core.Memory.GarbageCollector.GCHandleSegmentStore" || count.Body.Instructions[3].OpCode != OpCodes.Ret)
                throw new InvalidOperationException("The dependent-handle count export is not read-only.");
            for (int index = 0; index < Fields.Length; index++)
            {
                var method = gc.Methods.Single(candidate => candidate.Name == Prefix + Fields[index]);
                var il = method.Body.Instructions;
                if (method.Parameters.Count != 0 || method.ReturnType.MetadataType != MetadataType.UInt64 || method.Body.ExceptionHandlers.Count != 0 ||
                    il.Count != (index == 3 ? 4 : 3) || il[0].OpCode != OpCodes.Ldsflda || il[0].Operand is not FieldReference source || source.FullName != snapshot.FullName ||
                    il[1].OpCode != OpCodes.Ldfld || il[1].Operand is not FieldReference value || value.FullName != info.Fields.Single(field => field.Name == Fields[index]).FullName ||
                    index == 3 && il[2].OpCode != OpCodes.Conv_U8 || il[^1].OpCode != OpCodes.Ret ||
                    !method.CustomAttributes.Any(attribute => attribute.AttributeType.Name == "UnmanagedCallersOnlyAttribute" && attribute.Fields.Any(field =>
                        field.Name == "EntryPoint" && Equals(field.Argument.Value, Exports[index]))))
                    throw new InvalidOperationException("A GC snapshot export is not a read-only leaf.");
            }
        }
    }
}