-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Describe the issue
Because custom marshaling behavior is built into the generated delegate types, it is necessary to compare the relevant method arguments against the generated types' marshaling behaviors. As of right now, this is done with inline new MarshalAsAttribute statements. As the number of type comparisons increase, this will create GC pressure and likely cause performance issues when creating a new INativeAction/INativeFunc instance.
Proposed solution
Rather than generating a series of inlined new MarshalAsAttribute statements, a single look-up table could be defined in the generated source files. This can be cross-referenced for any case where the custom marshaling behavior is the same. For example, the return type marshaling is kept as a separate parameter, so any instances that share the same constructor arguments for MarshalAsAttribute could reference a single static object. Similarly, the arrays used for parameters' marshaling could be cached and shared, and the individual objects in those arrays could be cached as well.
Because every use-case is known at compile-time, the number of allocations can be minimized and remove the GC pressure of constantly creating new objects at each instantiation. In the generated code, this might look something like this:
file static class MarshalInfo
{
public static readonly MarshalAsAttribute[] Attributes = { ... }; // array filled in by source generator with references to each MarshalAsAttribute
public static readonly MarshalAsAttribute?[][] ParameterAttributeArrays = { ... }; // filled in by source generator with references to each unique combination of MarshalAsAttribute[]
}Then the NativeGenericDelegateInfo object (in the generator) could simply hold a reference to the runtime object or array needed for the comparison in MarshalInfo.Equals (method call generated at the end of the NativeGenericDelegateInfo constructor), rather than creating new objects.