[Tools] Fix ShaderDump reflection invoke against new optional parameters (#166)

TryCompileVertexShader gained an optional scalarRegisterBufferIndex
parameter (#156), and reflection Invoke does not apply C# default
parameter values, so ShaderDump crashed with
TargetParameterCountException. Pad trailing optional parameters with
Type.Missing under BindingFlags.OptionalParamBinding so the declared
defaults are used; only a new required parameter now needs a tool
update, and that fails with a named error instead of a crash.

Verified: all five programs behave as expected (exit 0), all eight
emitted blobs pass spirv-val --target-env vulkan1.3.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Deeptanshu Lal
2026-07-15 04:04:08 +05:30
committed by GitHub
parent de13735972
commit 3fb9d4db1c
+35 -4
View File
@@ -201,8 +201,8 @@ foreach (var (name, expectTranslate, words) in testPrograms)
null, null,
null)!; null)!;
object?[] compileArgs = [state, evaluation, null, null, 0, -1, 0]; var compileArgs = PadWithDefaults(tryCompile, [state, evaluation, null, null]);
if ((bool)tryCompile.Invoke(null, compileArgs)!) if ((bool)tryCompile.Invoke(null, BindingFlags.OptionalParamBinding, null, compileArgs, null)!)
{ {
var shader = compileArgs[2]!; var shader = compileArgs[2]!;
var spirv = (byte[])shader.GetType().GetProperty("Spirv")!.GetValue(shader)!; var spirv = (byte[])shader.GetType().GetProperty("Spirv")!.GetValue(shader)!;
@@ -216,8 +216,8 @@ foreach (var (name, expectTranslate, words) in testPrograms)
Console.WriteLine($"[{name}] emit: FAILED ({compileArgs[3]})"); Console.WriteLine($"[{name}] emit: FAILED ({compileArgs[3]})");
} }
object?[] computeArgs = [state, evaluation, 1u, 1u, 1u, null, null]; var computeArgs = PadWithDefaults(tryCompileCompute, [state, evaluation, 1u, 1u, 1u, null, null]);
if ((bool)tryCompileCompute.Invoke(null, computeArgs)!) if ((bool)tryCompileCompute.Invoke(null, BindingFlags.OptionalParamBinding, null, computeArgs, null)!)
{ {
var shader = computeArgs[5]!; var shader = computeArgs[5]!;
var spirv = (byte[])shader.GetType().GetProperty("Spirv")!.GetValue(shader)!; var spirv = (byte[])shader.GetType().GetProperty("Spirv")!.GetValue(shader)!;
@@ -237,6 +237,37 @@ Console.WriteLine(failures == 0
: $"RESULT: {failures} unexpected outcome(s)"); : $"RESULT: {failures} unexpected outcome(s)");
Environment.ExitCode = failures == 0 ? 0 : 1; Environment.ExitCode = failures == 0 ? 0 : 1;
// Reflection Invoke does not apply C# default parameter values, so a newly
// added optional parameter on a translator entry point would otherwise throw
// TargetParameterCountException. Type.Missing + OptionalParamBinding lets the
// runtime substitute the declared defaults; only a new *required* parameter
// should force a tool update.
static object?[] PadWithDefaults(MethodInfo method, object?[] arguments)
{
var parameters = method.GetParameters();
if (arguments.Length > parameters.Length)
{
throw new InvalidOperationException(
$"{method.DeclaringType?.Name}.{method.Name} takes fewer parameters than the tool supplies");
}
var padded = new object?[parameters.Length];
arguments.CopyTo(padded, 0);
for (var i = arguments.Length; i < padded.Length; i++)
{
if (!parameters[i].IsOptional)
{
throw new InvalidOperationException(
$"{method.DeclaringType?.Name}.{method.Name} gained a required parameter " +
$"'{parameters[i].Name}' — the tool needs updating");
}
padded[i] = Type.Missing;
}
return padded;
}
internal sealed class FakeMemory : ICpuMemory internal sealed class FakeMemory : ICpuMemory
{ {
private readonly List<(ulong Base, byte[] Data)> _regions = []; private readonly List<(ulong Base, byte[] Data)> _regions = [];