views:

133

answers:

4

Let's say we have a value type like this, where the fields are readonly and initialized during construction:

public struct SomeValue
{
    private readonly Int32 field1;
    private readonly Int32 field2;

    ...
}

Also, let's say we have a helper class that lets us implement GetHashCode() for composite types in a reusable manner:

public struct SomeValue
{
    ...

    public override Int32 GetHashCode()
    {
        return HashHelpers.GetHashCode(this.field1, this.field2);
    }
}

Now, the compiler must realize that the field values aren't ever going to change after the type is constructed, since they are readonly. Is it therefore likely that the call to HashHelpers.GetHashCode() will somehow be inlined when SomeValue.GetHashCode() is JIT-ed?

A: 

As far as I'm aware, the call to HashHelpers.GetHashCode() won't be inlined, it will just count as a normal call to that method in the CIL. I may be wrong, but I'm fairly sure that I'm not.

Liggi
I think that he is speaking of inlining at JIT time, not compile time. As far as i know the c++.net compiler is optimising it's CIL output but the C# compiler is just spiting a translation of the C# code as CIL without doing any optimisation.
VirtualBlackFox
Understood. Sorry if I misunderstood the question there.
Liggi
+3  A: 

There are some well-known rules for inlining (.NET 4 might have added more). In your case if HashHelpers.GetHashCode is simple enough, it will be inlined. I don't think that those readonly fields are of any meaning in that context.

liggett78
+1  A: 

As far as I'm aware, the fact that your fields are declared as readonly has no bearing on whether or not the jitter decides to inline the method.

Here's an article discussing some of the heuristics used by the .NET 3.5sp1 jitter. This may have changed in .NET 4, and could change again in future versions.

LukeH
+2  A: 

You didn't post the code for your HashHelper method, but since it should be small and fast, yes, it is quite likely that it will get inlined.

And, yes, the JIT optimizer is quite capable of evaluating expressions at compile time and replace the code with a simple constant value. But that is not going to happen when you use a readonly member. Because the value it has is determined by the constructor. The optimizer does not consider the code in other methods to guess if the field has a known value. It must be able to detect the value when it compiles GetHashCode.

You can get this if you use a const to initialize the readonly field. And use that same const in the GetHashCode implementation. That's pretty ugly. Given the very limited benefit you'll get from this micro-optimization, this is probably not something you should consider. The possible win is no more than a nano-second or so. But most likely zero because the optimizer would replace a xor with a mov.

Hans Passant
@Hans: The code: http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode/263416#263416 with changes to make it generic for several parameters.
Johann Gerell
Well, I'm sure your code doesn't look exactly like that. Details matter when the JIT optimizer makes inlining decisions. Nevertheless, it doesn't change my answer.
Hans Passant
@Hans: Well, I'm sure I explicitly noted that it wasn't exactly like that with the *"with changes to make it generic for several parameters"* : http://pastebin.com/Fx6HCnPL
Johann Gerell