test: replace runtime root source freezes

This commit is contained in:
Erik 2026-08-18 16:02:15 +02:00
parent 80c7b44457
commit 3c492aedc2
4 changed files with 248 additions and 220 deletions

View file

@ -5,6 +5,10 @@ namespace AcDream.App.Tests.Architecture;
internal readonly record struct CompiledCall(int Offset, MethodBase Target);
internal readonly record struct CompiledInstruction(int Offset, OpCode OpCode);
internal readonly record struct CompiledFieldReference(
int Offset,
OpCode OpCode,
FieldInfo Field);
/// <summary>
/// Reads compiled call/new-object edges from a method body. Architecture tests
@ -96,6 +100,52 @@ internal static class CompiledCallGraph
return instructions;
}
/// <summary>
/// Reads compiled field loads and stores with their instruction offsets.
/// This supports lifetime/state-order checks whose observable contract is
/// a latch edge rather than a source spelling.
/// </summary>
public static IReadOnlyList<CompiledFieldReference> ReadFieldReferences(
MethodBase method)
{
ArgumentNullException.ThrowIfNull(method);
byte[] il = method.GetMethodBody()?.GetILAsByteArray()
?? throw new InvalidOperationException(
$"{method.DeclaringType?.FullName}.{method.Name} has no compiled body.");
Type[]? declaringArguments = method.DeclaringType?.IsGenericType == true
? method.DeclaringType.GetGenericArguments()
: null;
Type[]? methodArguments = method.IsGenericMethod
? method.GetGenericArguments()
: null;
var references = new List<CompiledFieldReference>();
for (int cursor = 0; cursor < il.Length;)
{
int instructionOffset = cursor;
OpCode opCode = ReadOpCode(il, ref cursor);
if (opCode.OperandType == OperandType.InlineField)
{
int token = BitConverter.ToInt32(il, cursor);
FieldInfo? field = method.Module.ResolveField(
token,
declaringArguments,
methodArguments);
if (field is not null)
{
references.Add(new CompiledFieldReference(
instructionOffset,
opCode,
field));
}
}
cursor += OperandSize(opCode.OperandType, il, cursor);
}
return references;
}
/// <summary>
/// Reads types named by compiled type operands such as casts, boxing, and
/// <c>isinst</c>. This lets tests retain an exact type boundary without