2

In the process of optimizing reflection calls, I'm experimenting with using Delegate.CreateDelegate and LambdaExpression.Compile to turn my MethodInfos into faster delegates.

Based on this question, I expected LambdaExpression.Compile to perform significantly better because it would generate actual MSIL for the method call -- somewhere close to a direct method invocation.

However, after benchmarking, I noticed that both techniques have roughly the same performance.

My hypothesis is that the overhead I'm getting when calling a delegate created using LambdaExpression.Compile is due to the use of delegates itself. To confirm, I created another benchmark in which I manually created delegate directly invoking the method, and it had similar performance.

Therefore, my question is: is there any difference in the delegate object generated by LambdaExpression.Compile and Delegate.CreateDelegate?

I'm looking for a theoretical answer about the difference between the two approaches so I won't go into implementation details, but here is the jist of the implementation:

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Lazlo
  • 8,518
  • 14
  • 77
  • 116
  • To the person who voted to close; care to comment? – Lazlo Apr 06 '17 at 16:15
  • I don't understand why LambdaExpression delegate should be faster. Yes it generates msil, but Delegate.CreateDelegate creates delegate for already existing method, with already generated msil, so what's the difference? – Evk Apr 06 '17 at 19:18
  • That is precisely my question. Is there a difference, at the IL level, between calling a delegate created via `Delegate.CreateDelegate` and calling a delegate created via `LambdaExpression.Compile`? (even if this difference is small). – Lazlo Apr 06 '17 at 22:40
  • 1
    Well one is delegate (reference to function) and another is delegate. There is no difference between them. All the difference is in the functions those delegates point to. – Evk Apr 07 '17 at 09:53

1 Answers1

4

There is a difference between Delegate.CreateDelegate and LambdaExpression.Compile, Indeed the second do something more and can be more efficient in specific condition.

When you call Delegate.CreateDelegate manually you can call it with some overload with target value but in some case like static method, you don't have a target value.

In background when you don't have a target value, delegate is created with a generated method to pop useless value in stack before jump in real method. You can observe it with watcher : delegate have InPtr & InPtrAux

When IntPtrAux is assigned to a valid pointer, that means InPtr is called before to pop handle and jump to IntPtrAux. That's why a delegate to a delegate made for an instance method (handle is "this") is more efficient compared to the same for a static method.

In lambda expression compile to generated a delegate, Target is always used (for closure) and avoid the call/jump through IntPtrAux and is often efficient.

Tony THONG
  • 772
  • 5
  • 11