JIT

Fri, December 31, 2004, 06:35 AM under MobileAndEmbedded
By now, all .NET developers know that their managed code (C#, VB.NET etc) gets compiled to Intermediate Language (IL) which itself, at runtime, gets Just-In-Time (JIT) compiled to native code. Here we'll look at some of the differences of the NET Compact Framework JIT engine compared to the desktop (full framework), as well as what CF 2.0 will change.

As a historical aside, the alpha (pre-RTM) version of the CF did not have a JIT compiler and instead IL was interpreted on the device. Since RTM (for CF version info please go here), the IL is JITted to native code on the device/target. This is done on a per method basis (like on the Full Fx). When a method is called, it is detected that there is no native code for the method, so IL is compiled into native code and executed; next time the method is called the native code gets executed, which means that the JIT performance penalty is only incurred once.

The major difference on the CF is that the native code is cached in the GC heap (i.e. in RAM) and is susceptible to "pitching" if a full GC occurs (for more detail on GC phases and pitching look there). In other words, the JITted native code can be thrown away under memory pressure, so next time a recompilation has to take place for any methods that were pitched. Do not confuse pitching methods with the actual type data structures (metadata), which are never pitched once loaded.

To obtain some numbers for your CF app, you should use the perf counters. In particular focus on: Bytes Jitted, Native Bytes Jitted, Number Of Methods Jitted, Bytes Pitched and Number Of Methods Pitched

Another difference in the same area is that ngen is not supported on the NETCF. So you cannot pre-compile your assemblies to native images.

Finally, note that the JITted code has a limit of 64K (native size, not managed). You wouldn't expect to hit that limit, but very large forms can break the rule in their auto-generated InitializeComponent method. The workaround is to split the method into smaller ones (at the expense of losing designer support).

CF 1.0 comes with two JIT compilers: sJIT and iJIT. The former is for ARM devices only and the latter is for all other CPU architectures (inc. SH3, MIPS, x86). SJIT takes slightly longer to compile IL to native code, but the resulting code is faster than what IJIT can produce (there is a detailed slide "Differencies between JITs" in this ppt, for anoraks :-)

CF 2.0 comes with a unified JIT, which is more performant and optimised than what we have today. Note that VS2005 will ship with ARM CPU Emulators and not x86 like today, so the emulation experience will be enhanced from a performance perspective too.

As you recall I have read all CF books, so I can tell you that both Building Solutions with the CF and CF Kick Start include short paragprahs on JITting. The NETCF bible dedicates a few pages on the JITted Code Pool / native image cache.

Happy New Year!