0

I'm trying to produce some "Hello World" size C# code snippet that would incur JIT inlining. So far I have this:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine( GetAssembly().FullName );
        Console.ReadLine();
    }

    static Assembly GetAssembly()
    {
        return System.Reflection.Assembly.GetCallingAssembly();
    }
}

which I compile as "Release"-"Any CPU" and "Run without debugging" from Visual Studio. It displays the name of my sample program assembly so clearly GetAssembly() is not inlined into Main(), otherwise it would display mscorlib assembly name.

How do I compose some C# code snippet that would incur JIT inlining?

sharptooth
  • 167,383
  • 100
  • 513
  • 979

2 Answers2

6

Sure, here's an example:

using System;

class Test
{
    static void Main()
    {
        CallThrow();
    }

    static void CallThrow()
    {
        Throw();
    }

    static void Throw()
    {
        // Add a condition to try to disuade the JIT
        // compiler from inlining *this* method. Could
        // do this with attributes...
        if (DateTime.Today.Year > 1000)
        {
            throw new Exception();
        }
    }
}

Compile in a release-like mode:

csc /o+ /debug- Test.cs

Run:

c:\Users\Jon\Test>test

Unhandled Exception: System.Exception: Exception of type 'System.Exception' was
thrown.
   at Test.Throw()
   at Test.Main()

Note the stack trace - it looks as if Throw was called directly by Main, because the code for CallThrow was inlined.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
1

Your understanding of inlining seems incorrect: If GetAssembly was inlined, it would still show the name of your program.

Inlining means: "Use the body of the function at the place of the function call". Inlining GetAssembly would lead to code equivalent to this:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(System.Reflection.Assembly.GetCallingAssembly()
                                                    .FullName);
        Console.ReadLine();
    }
}
Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • I think his point was that `GetAssembly` would be invoked by `Main`, but `Main` is invoked by something in `mscorlib`. – Rawling Oct 02 '12 at 08:32
  • @Rawling: That's not what he is saying in his question: "clearly `GetAssembly()` is not inlined into `Main()`" – Daniel Hilgarth Oct 02 '12 at 08:35
  • `System.Reflection.Assembly.GetCallingAssembly()` returns something different if called directly in `main` as it does if called in a function that is called by `main`. Your code produces a different result than the original code. Thus if inlining occurred turning his code into your code, the output _would_ be different. – Rawling Oct 02 '12 at 08:37
  • @Rawling: That's not correct. You are free to test it yourself. – Daniel Hilgarth Oct 02 '12 at 09:37
  • If I combine your code and the question code - e.g. one `WriteLine` with `System.Reflection.Assembly.GetCallingAssembly()`, one with `GetAssembly()` - I get two different outputs. – Rawling Oct 02 '12 at 09:40
  • @Rawling: [I don't](http://i.stack.imgur.com/tEM6H.png). I get the same output in Release and Debug and if I start it from within VS or directly from disk. – Daniel Hilgarth Oct 02 '12 at 13:12
  • ... Oh, that's bizarre. I get `Microsoft.VisualStudio.HostingProcess.Utilities ...` for the call in `Main` and `MyProject ...` for the call in `GetAssembly`. (Edit: When running from VS. When running standalone, I get `MyProject ...` for both, so I owe you an apology for that.) – Rawling Oct 02 '12 at 13:15
  • I assume you start it with debugging (F5)? Try starting without debugging (Ctrl + F5) – Daniel Hilgarth Oct 02 '12 at 13:17
  • Aaaand I've just noticed the comment in the question about going "Run without debugging", which also gives me two identical line. I'm just going to go away now. – Rawling Oct 02 '12 at 13:18