3

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?

Johann Gerell
  • 24,991
  • 10
  • 72
  • 122
  • 1
    You're not talking about inlining, but short-circuiting the GetHashCode implementation. – sisve Sep 08 '10 at 12:53
  • 1
    @Simon: What do you mean by *short-circuiting* in this context? Please elaborate. – Johann Gerell Sep 08 '10 at 13:04
  • You want the SomeValue.GetHashCode to directly return a pre-computed (computed during the last call) value. (Creating a quicker path, short-circuiting, through SomeValue.GetHashCode.) Inlining means that the code of the HashHelpers.GetHashCode will (assuming some criterias are met) be inserted into your SomeValue.GetHashCode to speed up execution (by avoid the method call which requires stack modifications, execution jumps, etc). I am just saying that what you're describing isn't inlining. – sisve Sep 08 '10 at 13:15
  • 1
    It sounds like you want (or at least ask about) the CLR to have some kind of ability to determine if a method call is deterministic (same input => same output) and to short-circuit those calls by replacing them with the cached value from a previous execution. – sisve Sep 08 '10 at 13:18
  • @Simon: Ah, I see what you mean. I guess that taken to its extreme, that *could've* been what I meant, but I actually *did* mean inlining, as in doing the exact same calculation sequence without the function call overhead. – Johann Gerell Sep 08 '10 at 13:21
  • @Johann: But inlining has nothing to do with the readonly part. Memoization/short-circuiting does though. Inlining would work just as well regardless of whether the values could change. – recursive Sep 08 '10 at 13:42
  • @recursive: Ok, that's what my question is about. I wanted to know if inlining would be affected by readonly. If I had known the answer, then I wouldn't have to ask. I might have formulated the question too fuzzy. – Johann Gerell Sep 08 '10 at 13:51

4 Answers4

3

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
  • 11,260
  • 2
  • 29
  • 29
3

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
  • 922,412
  • 146
  • 1,693
  • 2,536
  • 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 Sep 08 '10 at 13:53
  • 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 Sep 08 '10 at 13:57
  • 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 Sep 09 '10 at 09:45
1

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
  • 263,068
  • 57
  • 365
  • 409
0

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
  • 744
  • 8
  • 22
  • 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. – Julien Roncaglia Sep 08 '10 at 13:14
  • Understood. Sorry if I misunderstood the question there. – Liggi Sep 08 '10 at 13:25