Inlining is an important optimization that allows compilers to eliminate the cost of method calls in situations where the method call overhead is more significant than the method body itself. The CLR JIT uses inlining conservatively, but features some nice tricks such as interface method call inlining – this was one of the first things I covered on this blog, almost five years ago.
The limitations on JIT inlining are not known precisely, but some criteria have been announced previously (in 2004!). Namely, the JIT won’t inline:
- Methods marked with MethodImplOptions.NoInlining
- Methods larger than 32 bytes of IL
- Virtual methods
- Methods that take a large value type as a parameter
- Methods on MarshalByRef classes
- Methods with complicated flowgraphs
- Methods meeting other, more exotic criteria
Today, however, I’d like to direct your attention towards a new flag in CLR 4.5, MethodImplOptions.AggressiveInlining. The documentation here is very brief:
The method should be inlined if possible.
Well, thanks. Interestingly, Mono introduced support for this option as well, committed on January 5th (two weeks ago!), and here’s the effect it has on deciding whether to inline a method, inside the function mono_method_check_inlining:
- if (header.code_size >= inline_limit)
+ if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
(The inline_limit parameter is configurable by an environment variable, and defaults to 20.)
So, what is the effect of AggressiveInlining on the Microsoft JIT?
From what I checked, it seems to be similar to what it does in Mono. Namely, methods that are not inlined only because of code size are inlined when this attribute is applied to them.
Here are two methods that you can try yourself:
public static int SmallMethod(int i, int j)
if (i > j)
return i + j;
return i + 2 * j – 1;
public static int LargeMethod(int i, int j)
if (i + 14 > j)
return i + j;
else if (j * 12 < i)
return 42 + i – j * 7;
return i % 14 – j;
The code size for these methods is 16 and 34, respectively. Without the AggressiveInlining attribute, the first method is inlined and the second is not inlined. With the AggressiveInlining attribute, the second method is inlined as well.
However, methods that couldn’t be inlined previously because of other criteria are still not inlined. I checked the following, and neither of these methods was inlined:
- Recursive method
- Virtual method (even if the static type of the receiver variable is sealed)
- Method with exception handling (representing a “complicated flowgraph”)
I am posting short updates and links on Twitter as well as on this blog. You can follow me: @goldshtn