views:

165

answers:

1

The problem:

  • a .Net 2.0 class with a few thousand delegate fields generated by a code generator

    1. varying signatures
    2. delegates may or may not return values
    3. no generics
  • these delegates much be initialized quickly at runtime

    1. initializing a delegate is simple but expensive
    2. initializing the whole lot costs ~300ms right now - acceptable, but not perfect
    3. the user will likely use less than 10% of those delegates - it would be much faster if we could load only those delegates lazily! (don't pay for what you don't use)

The question:

Is it possible to use reflection to initialize a delegate field lazily? In pseudo-code:

class Delegates
{
    int FooDelegate(IntPtr p1, float* p2);
    public static FooDelegate Foo;
    // Several thousand more    
    ...

    static Delegate LoadDelegate(string name, Type signature)
    {
        // complex and expensive p/invokes
    }

    static void SetupStubs()
    {
        // Create loader stubs (using reflection because
        // JIT times are prohibitive when done inline)
        foreach (FieldInfo f in typeof(Delegates)
            .GetFields(BindingFlags.Static | BindingFlags.NonPublic))
        {
            // We need to generate a compatible delegate, which:
            // (a) calls LoadDelegate("Foo", typeof(FooDelegate)), and
            // (b) assigns its result to the Foo field (replacing the stub),
            // (c) executes Foo(p1, p2) and returns the result, where 
            // p1 and p2 are the original parameters specified by the user.
            Delegate stub = ...;
            f.SetValue(null, stub);
        }
    }
}

I have a feeling that it is possible to create a stub that performs (a), (b) and (c), but I haven't managed to divine how.

Ideally, the code should run .Net 2.0 and Mono 2.0 and should not use System.Reflection.Emit. However I'd also be interested in solutions using .Net 3.5 or DynamicMethod.

Any ideas? :)

+1  A: 

Yes, it is possible to dynamically generate stubs at runtime, but it is very likely that it will takes more that 300 ms -- we are talking about generating thousands of stubs. And btw, it would requires DynamicMethods or maybe 3.5 Expressions.

The best approach would be to generate stubs before compilation. Ideally, the code generator which generates fields should also generate stubs. If you can't modify the existing code generator, you may want to use a template engine, like T4.

Romain Verdier
Initial tests showed that reflection is significantly faster than the JIT in initializing the delegates: ~300ms for reflection vs ~2500ms for the JIT code. (Obviously the tables turn once the code is JITted, but we are concerned only for the initial startup time). Both tests used the same LoadDelegate() method.If I were to use DynamicMethods or expressions, what would these stubs look like? How would I capture the original parameters and execute the method inside the stub itself?
BlackStar