# Thursday, December 07, 2006
« Getting the list of loaded assemblies | Main | Getting the list of loaded assemblies fr... »

A guy from a well-known company mailed me asking how to avoid deploying statically referenced assemblies that he knows will not be loaded at runtime. The issue is that the assembly is being loaded, but he doesn’t believe that it is being actually used. His current workaround is to deploy the assembly to avoid FileNotFound exceptions, which nobody likes.

I have two questions for the guy:

1.      Why are you so certain that the assembly will not be needed?

2.      Is the assembly used in other scenarios, just not this one? There must be a reason that it is statically referenced by your app in the first place.

 

As you can guess, this whole exercise is a bit of a dangerous situation. You can spend a lot of time ensuring that certain code paths will never be called, and then your users do something unexpected and low-and-behold, that darned FileNotFound exception is thrown. Ouch.

Why is this a problem?

Anyway, the core of the problem is at the level of the JIT (just-in-time compiler). The JIT jits code (MSIL) at a method-level basis.  The following is how things work at a high-level:

1.      The app calls a method

2.      The method cannot be executed because it hasn’t yet been jitted to machine code

3.      The JIT compiles the method (MSIL) into x86 (or X64 or IA64) code

4.      For every method call that the JIT sees, it must fully understand the signature of that method, specifically the return type and the arguments/parameters. This requirement may cause an assembly load.

5.      The method can now be called. The method will not need to be jitted again (at least in this app domain).

 

For example, the return type might be a value type, requiring the JIT to know how large that type is. To get that information, the JIT must load the type, and must request that the assembly (in which the type is contained) be loaded if it is not already loaded. This is still the case even if the method call is within an if statement, and might not actually be called.

Code that exposes the problem

As already suggested, you are going to run into this problem anytime you have a direct cross-assembly method call anywhere in a method you know that you will call, and hence JIT. This is even true under an if statement where the condition will not be true in this scenario.

        static void Method1()

        {

            if (condition)

            {

                //directly calling method from ClassLibrary2

                Class2.Multiply(100, 200);

            }

        }

 

Code that avoids this problem

It is pretty easy to avoid this problem. Write the following code instead.

        static void Method1()

        {

            if (condition)

            {

                //indirectly calling method from ClassLibrary2

                Method2();

            }

        }

        static void Method2()

        {

                //directly calling method from ClassLibrary2

                Class2.Multiply(100, 200);

        }

As you can see, the call to Class2.Multiply() is now an indirect call and does not require the JIT to know anything about the Class2 or require ClassLibrary2 to be loaded (the symptom to be avoided), unless of course the condition is met and Method2() is called. This trick is a little awkward sometimes, but it is a great option to at least defer and even completely avoid assembly loads.

Gotcha

Unfortunately, there is a gotcha. The JIT does optimize code by inlining methods. When this happens, you lose your indirect call, and you are now in the same bad boat you were in before. I don’t know much about the JIT inlining policy, so cannot provide a list of where this happens. This is merely a caveat that my workaround doesn’t work in all cases.  If folks are interested, I can talk to the folks on the JIT and perf teams to learn more about this gotcha.