feat(runtime): support class-9 and default Control budgets
Docs Deploy / Build and Deploy MkDocs (push) Successful in 35s

This commit is contained in:
Valentin Popov committed 2026-10-29 19:43:09 +04:00
1 parent d3a0f8c7ff
commit 1d20509b05
5 files changed
+986 -67

No files matched your search

@@ -54,6 +54,11 @@ internal static class BehaviorDistributorTickOracle {
private const int ControlResourceTag9ConstructorRva = 0x25460;
private const int ControlResourceTag15ConstructorRva = 0x22ae0;
private const int ControlResourceTag25ConstructorRva = 0x20800;
private const int ControlResourceTag9RateRva = 0x25700;
private const int ControlResourceTag9UpdateRva = 0x257b0;
private const int ControlResourceTag9AdjustRva = 0x25a90;
private const int ControlResourceDefaultRateRva = 0x21860;
private const int ControlResourceDefaultUpdateRva = 0x21890;
private const int ControlResourceTag15RateRva = 0x22b20;
private const int ControlResourceTag15UpdateRva = 0x22bb0;
private const int ControlResourceBudgetUpdateRva = 0x2d340;
@@ -119,6 +124,7 @@ internal static class BehaviorDistributorTickOracle {
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] private delegate IntPtr NativeControlResourceDeviceConstructor(IntPtr self);
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] private delegate void NativeControlResourceBudgetUpdate(IntPtr self, float deltaSeconds);
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] private delegate float NativeControlResourceDeviceRate(IntPtr self, float deltaSeconds);
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] private delegate void NativeControlResourceTag9Update(IntPtr self, float deltaSeconds, float allocation);
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] private delegate int NativeControlResourceDeviceGate(IntPtr self);
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] private delegate float NativeControlResourceAvailability(IntPtr self, byte flags);
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] private delegate IntPtr NativeControlDeviceFactory(IntPtr self, uint componentId, uint keyOffset, IntPtr record);
@@ -706,6 +712,8 @@ internal static class BehaviorDistributorTickOracle {
RunNativeControlTimedUpdateBaselineCases(controlModule);
RunNativeControlAggregateResourceCases(controlModule);
RunNativeControlResourceBudgetTag15Case(controlModule);
RunNativeControlResourceBudgetClass9Case(controlModule);
RunNativeControlGenericDefaultBudgetCase(controlModule);
RunNativeControlActivationCase(controlModule);
RunNativeBehaviorProfileMapCases(module);
RunNativeBehaviorVarSyntheticCase(module);
@@ -1790,6 +1798,198 @@ internal static class BehaviorDistributorTickOracle {
return device;
}
private static void RunNativeControlResourceBudgetClass9Case(IntPtr module) {
NativeControlOwnerConstructor constructOwner = (NativeControlOwnerConstructor)
Marshal.GetDelegateForFunctionPointer(IntPtr.Add(module, ControlOwnerConstructorRva),
typeof(NativeControlOwnerConstructor));
NativeControlResourceDeviceConstructor constructDevice = (NativeControlResourceDeviceConstructor)
Marshal.GetDelegateForFunctionPointer(IntPtr.Add(module, ControlResourceTag9ConstructorRva),
typeof(NativeControlResourceDeviceConstructor));
NativeControlProviderRowConstructor constructProvider = (NativeControlProviderRowConstructor)
Marshal.GetDelegateForFunctionPointer(IntPtr.Add(module, ControlProviderRowConstructorRva),
typeof(NativeControlProviderRowConstructor));
NativeControlResourceDeviceRate rate = (NativeControlResourceDeviceRate)
Marshal.GetDelegateForFunctionPointer(IntPtr.Add(module, ControlResourceTag9RateRva),
typeof(NativeControlResourceDeviceRate));
NativeControlResourceTag9Update update = (NativeControlResourceTag9Update)
Marshal.GetDelegateForFunctionPointer(IntPtr.Add(module, ControlResourceTag9UpdateRva),
typeof(NativeControlResourceTag9Update));
NativeControlContactRateUpdate adjust = (NativeControlContactRateUpdate)
Marshal.GetDelegateForFunctionPointer(IntPtr.Add(module, ControlResourceTag9AdjustRva),
typeof(NativeControlContactRateUpdate));
using (Fixture fixture = NewFixture()) {
IntPtr owner = fixture.Allocate(0x664);
Expect(constructOwner(owner, IntPtr.Zero, 4) == owner, "native class-9 budget owner constructor");
IntPtr ndp = fixture.Allocate(0x4c);
Marshal.WriteInt32(ndp, 4, FloatBits(100.0f));
IntPtr provider = fixture.Allocate(0x2c);
constructProvider(provider, ndp);
Marshal.WriteInt32(provider, 0x14, FloatBits(0.4f));
Marshal.WriteIntPtr(owner, 0x55c, provider);
Marshal.WriteInt32(owner, 0x560, 1);
IntPtr device = fixture.Allocate(0x120);
Expect(constructDevice(device) == device &&
Marshal.ReadIntPtr(device) == IntPtr.Add(module, ControlResourceTag9VtableRva),
"native class-9 constructor installs its original vtable");
Expect(Marshal.ReadInt32(device, 0x50) == 0x20,
"native class-9 constructor enables its budget callback");
for (int i = 0; i < 6; i++) {
Expect(Marshal.ReadInt32(device, 0x98 + i * 4) == FloatBits(1.0f) &&
Marshal.ReadInt32(device, 0xb0 + i * 4) == 0,
"native class-9 constructor initializes value/delta row " + i);
}
IntPtr descriptor = fixture.Allocate(0xb4);
Marshal.WriteInt32(descriptor, 0, 9);
Marshal.WriteInt32(descriptor, 0x20, FloatBits(0.2f));
Marshal.WriteIntPtr(device, 0x3c, owner);
Marshal.WriteIntPtr(device, 0x44, IntPtr.Add(owner, 4));
Marshal.WriteIntPtr(device, 0x48, descriptor);
Marshal.WriteInt32(device, 0x54, FloatBits(0.75f));
Marshal.WriteInt32(device, 0x58, FloatBits(0.6f));
Marshal.WriteInt32(device, 0x5c, FloatBits(2.0f));
Marshal.WriteInt32(device, 0x11c, FloatBits(1.25f));
float[] values = { 0.0f, 0.25f, 0.5f, 0.75f, 1.0f, 0.9f };
float[] deltas = { 0.1f, -0.2f, 0.0f, 0.3f, -0.4f, 0.5f };
for (int i = 0; i < 6; i++) {
Marshal.WriteInt32(device, 0x98 + i * 4, FloatBits(values[i]));
Marshal.WriteInt32(device, 0xb0 + i * 4, FloatBits(deltas[i]));
}
Expect(FloatBits(rate(device, 0.5f)) == unchecked((int)0xbeae147b),
"native class-9 rate uses six values and selector-0 scale");
update(device, 0.5f, 1.0f);
int[] expectedValues = {
unchecked((int)0x3d49a637), unchecked((int)0x3e92e795),
unchecked((int)0x3f064d32), unchecked((int)0x3f432699),
unchecked((int)0x3f800000), unchecked((int)0x3f67a90a),
};
int[] expectedDeltas = {
unchecked((int)0x3e18cff4), unchecked((int)0xbe26fda3),
unchecked((int)0x3cc9a637), unchecked((int)0x3e9fe6cc),
unchecked((int)0xbecccccd), unchecked((int)0x3f0142a4),
};
Expect(Marshal.ReadInt32(device, 0x4c) == FloatBits(1.0f),
"native class-9 update stores its allocation multiplier");
for (int i = 0; i < 6; i++) {
Expect(Marshal.ReadInt32(device, 0x98 + i * 4) == expectedValues[i] &&
Marshal.ReadInt32(device, 0xb0 + i * 4) == expectedDeltas[i],
"native class-9 exact value/delta vector row " + i);
}
Console.WriteLine("native-control-class9-budget: controlHash=" + ExpectedControlSha256 +
" rateRva=0x25700 updateRva=0x257b0 adjustRva=0x25a90 dt=0.5" +
" rate=0xbeae147b values=" + String.Join(",", Array.ConvertAll(expectedValues,
value => Hex(unchecked((uint)value)))) +
" deltas=" + String.Join(",", Array.ConvertAll(expectedDeltas,
value => Hex(unchecked((uint)value)))));
IntPtr decreasingDevice = fixture.Allocate(0x120);
Expect(constructDevice(decreasingDevice) == decreasingDevice,
"native class-9 negative-update constructor");
IntPtr decreasingDescriptor = fixture.Allocate(0xb4);
Marshal.WriteInt32(decreasingDescriptor, 0, 9);
Marshal.WriteInt32(decreasingDescriptor, 0x20, FloatBits(0.2f));
Marshal.WriteIntPtr(decreasingDevice, 0x3c, owner);
Marshal.WriteIntPtr(decreasingDevice, 0x44, IntPtr.Add(owner, 4));
Marshal.WriteIntPtr(decreasingDevice, 0x48, decreasingDescriptor);
Marshal.WriteInt32(decreasingDevice, 0x54, FloatBits(10.0f));
Marshal.WriteInt32(decreasingDevice, 0x58, FloatBits(0.6f));
Marshal.WriteInt32(decreasingDevice, 0x5c, FloatBits(2.0f));
Marshal.WriteInt32(decreasingDevice, 0x11c, FloatBits(1.0f));
Expect(FloatBits(rate(decreasingDevice, 0.5f)) == unchecked((int)0xbdcccccd),
"native class-9 negative case rate");
update(decreasingDevice, 0.5f, 0.5f);
Expect(Marshal.ReadInt32(decreasingDevice, 0x4c) == FloatBits(0.5f),
"native class-9 negative case allocation multiplier");
for (int i = 0; i < 6; i++) {
Expect(Marshal.ReadInt32(decreasingDevice, 0x98 + i * 4) == unchecked((int)0x3f7fe4b1) &&
Marshal.ReadInt32(decreasingDevice, 0xb0 + i * 4) == unchecked((int)0xb9da740e),
"native class-9 negative value/delta row " + i);
}
Console.WriteLine("native-control-class9-negative: rate=0xbdcccccd M=0x3f000000" +
" values=0x3f7fe4b1x6 deltas=0xb9da740ex6");
IntPtr averageDevice = fixture.Allocate(0x120);
Expect(constructDevice(averageDevice) == averageDevice, "native class-9 average constructor");
for (int i = 0; i < 6; i++) {
Marshal.WriteInt32(averageDevice, 0x98 + i * 4, FloatBits(i == 0 ? 0.0f : 1.0f));
Marshal.WriteInt32(averageDevice, 0xb0 + i * 4, 0);
}
adjust(averageDevice, 0.1f);
Expect(Marshal.ReadInt32(averageDevice, 0x98) == unchecked((int)0x3f19999c) &&
Marshal.ReadInt32(averageDevice, 0xb0) == unchecked((int)0x3f19999c),
"native class-9 adjustment multiplies by the stored 1/6 constant");
for (int i = 1; i < 6; i++) {
Expect(Marshal.ReadInt32(averageDevice, 0x98 + i * 4) == FloatBits(1.0f) &&
Marshal.ReadInt32(averageDevice, 0xb0 + i * 4) == 0,
"native class-9 constant-average leaves full rows unchanged");
}
Console.WriteLine("native-control-class9-average: first=0x3f19999c delta=0x3f19999c");
}
GC.KeepAlive(rate);
GC.KeepAlive(update);
GC.KeepAlive(adjust);
}
private static void RunNativeControlGenericDefaultBudgetCase(IntPtr module) {
NativeControlOwnerConstructor constructOwner = (NativeControlOwnerConstructor)
Marshal.GetDelegateForFunctionPointer(IntPtr.Add(module, ControlOwnerConstructorRva),
typeof(NativeControlOwnerConstructor));
NativeControlResourceDeviceConstructor constructDefault = (NativeControlResourceDeviceConstructor)
Marshal.GetDelegateForFunctionPointer(IntPtr.Add(module, ControlResourceTag25ConstructorRva),
typeof(NativeControlResourceDeviceConstructor));
NativeControlResourceDeviceRate rate = (NativeControlResourceDeviceRate)
Marshal.GetDelegateForFunctionPointer(IntPtr.Add(module, ControlResourceDefaultRateRva),
typeof(NativeControlResourceDeviceRate));
NativeControlResourceTag9Update update = (NativeControlResourceTag9Update)
Marshal.GetDelegateForFunctionPointer(IntPtr.Add(module, ControlResourceDefaultUpdateRva),
typeof(NativeControlResourceTag9Update));
NativeControlProviderRowConstructor constructProvider = (NativeControlProviderRowConstructor)
Marshal.GetDelegateForFunctionPointer(IntPtr.Add(module, ControlProviderRowConstructorRva),
typeof(NativeControlProviderRowConstructor));
using (Fixture fixture = NewFixture()) {
IntPtr owner = fixture.Allocate(0x664);
Expect(constructOwner(owner, IntPtr.Zero, 4) == owner,
"native generic-budget owner constructor");
IntPtr ndp = fixture.Allocate(0x4c);
Marshal.WriteInt32(ndp, 4, FloatBits(100.0f));
IntPtr provider = fixture.Allocate(0x2c);
constructProvider(provider, ndp);
Marshal.WriteInt32(provider, 0x14, FloatBits(0.4f));
Marshal.WriteIntPtr(owner, 0x55c, provider);
Marshal.WriteInt32(owner, 0x560, 1);
IntPtr device = fixture.Allocate(0xa4);
Expect(constructDefault(device) == device, "native generic default-family constructor");
IntPtr vtable = Marshal.ReadIntPtr(device);
Expect(vtable == IntPtr.Add(module, ControlResourceTag25VtableRva) &&
Marshal.ReadIntPtr(vtable, 0x14) == IntPtr.Add(module, ControlResourceDefaultRateRva) &&
Marshal.ReadIntPtr(vtable, 0x18) == IntPtr.Add(module, ControlResourceDefaultUpdateRva),
"generic default-family vtable installs native rate/update callbacks");
Expect(Marshal.ReadInt32(device, 0x50) == 5 &&
Marshal.ReadInt32(device, 0x4c) == FloatBits(1.0f),
"generic default-family constructor defaults");
IntPtr descriptor = fixture.Allocate(0xb4);
Marshal.WriteInt32(descriptor, 0, 12);
Marshal.WriteInt32(descriptor, 0x20, FloatBits(0.2f));
Marshal.WriteIntPtr(device, 0x3c, owner);
Marshal.WriteIntPtr(device, 0x44, IntPtr.Add(owner, 4));
Marshal.WriteIntPtr(device, 0x48, descriptor);
Expect(FloatBits(rate(device, 0.5f)) == FloatBits(-0.1f),
"generic native callback rate is negative descriptor rate times dt");
update(device, 0.5f, 0.375f);
Expect(Marshal.ReadInt32(device, 0x4c) == FloatBits(0.375f),
"generic native callback stores allocation multiplier");
Console.WriteLine("native-control-generic-default-budget: controlHash=" + ExpectedControlSha256 +
" constructorRva=0x20800 vtable=0x3c448 rateRva=0x21860 updateRva=0x21890" +
" descriptor=12 B=0.2 dt=0.5 rate=-0.1 allocation=0.375");
}
GC.KeepAlive(rate);
GC.KeepAlive(update);
}
private static void RunNativeControlResourceBudgetTag15Case(IntPtr module) {
RunNativeControlResourceBudgetEmptyCases(module);
NativeControlOwnerConstructor constructOwner = (NativeControlOwnerConstructor)Marshal.GetDelegateForFunctionPointer(
@@ -2533,6 +2733,10 @@ internal static class BehaviorDistributorTickOracle {
0x3cbd8, 0x29940, applyOverride);
RunNativeControlOverrideReceiverCase(module, 3, 0xa4, 0x20800,
0x3c448, ControlResourceNoOpStringPairRva, applyOverride);
RunNativeControlOverrideReceiverCase(module, 12, 0xa4, 0x20800,
0x3c448, ControlResourceNoOpStringPairRva, applyOverride);
RunNativeControlOverrideReceiverCase(module, 13, 0xa4, 0x20800,
0x3c448, ControlResourceNoOpStringPairRva, applyOverride);
GC.KeepAlive(applyOverride);
}
@@ -2546,14 +2750,21 @@ internal static class BehaviorDistributorTickOracle {
"tag-" + tag + " vtable reader resolves to its native implementation");
Expect(Marshal.ReadIntPtr(expectedVtable, 0x24) == IntPtr.Add(module, stringPairRva),
"tag-" + tag + " vtable string-pair slot matches its native callback");
if (vtableRva == 0x3c448 || vtableRva == 0x3c720 ||
vtableRva == 0x3c800 || vtableRva == 0x3c528) {
Expect(Marshal.ReadIntPtr(expectedVtable, 0x14) == IntPtr.Add(module, ControlResourceDefaultRateRva) &&
Marshal.ReadIntPtr(expectedVtable, 0x18) == IntPtr.Add(module, ControlResourceDefaultUpdateRva),
"tag-" + tag + " vtable uses the shared default budget callbacks");
}
using (Fixture fixture = NewFixture()) {
IntPtr owner = fixture.Allocate(0x5c8);
IntPtr deviceArray = fixture.Allocate(2 * IntPtr.Size);
IntPtr targetDevice = (tag == 3 || tag == 5) ? IntPtr.Zero : fixture.Allocate(objectSize);
bool defaultFactory = tag == 3 || tag == 5 || tag == 12 || tag == 13;
IntPtr targetDevice = defaultFactory ? IntPtr.Zero : fixture.Allocate(objectSize);
bool variableTail = tag == 2 || tag == 3 || tag == 4 || tag == 5 || tag == 8 || tag == 10 || tag == 21 || tag == 27;
IntPtr typedRecord = fixture.Allocate(variableTail ? 0xc0 : 0xb4);
if (tag == 3 || tag == 5) {
// Tag 3 follows the default factory; case 5 also assigns a derived vtable.
if (defaultFactory) {
// Tags 3/12/13 follow the default factory; case 5 assigns a derived vtable.
Marshal.WriteIntPtr(owner, 0x5bc, deviceArray);
Marshal.WriteInt32(owner, 0x5c4, 2);
Marshal.WriteInt32(typedRecord, 0, tag);
@@ -2573,6 +2784,10 @@ internal static class BehaviorDistributorTickOracle {
Marshal.ReadInt32(targetDevice, 0x4c) == FloatBits(1.0f),
"native extended factory constructor defaults");
}
if (tag == 12 || tag == 13)
Expect(Marshal.ReadInt32(targetDevice, 0x50) == 5 &&
Marshal.ReadInt32(targetDevice, 0x4c) == FloatBits(1.0f),
"native default-factory tag " + tag + " constructor defaults");
Marshal.WriteIntPtr(deviceArray, 0, targetDevice);
Marshal.WriteIntPtr(owner, 0x5bc, deviceArray);
Marshal.WriteInt32(owner, 0x5c0, 1);