Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does .NET optimize methods that return a Structure value?

Tags:

.net

vb.net

Consider a method that returns a Structure, like this:

Public Function DoWork() As MyStructure

    Return New MyStructure(1.5, 1.7, 1.1, 55.9)

End Function

In this case, does .NET create and initialize a MyStructure value once, or twice?

EDIT: My hunch is that a call to DoWork must involve .NET pushing the return value on the stack right from the outset. Otherwise, how would Return get anything back to the calling code? So that's the first initialization I'm talking about.

The second initialization would be at the Return statement, where arguments 1.5, 1.7, 1.1, 55.9 initialize a new MyStructure value. On Return, .NET would then overwrite the existing value on the Stack with the new return value.

The thing is, I know very little about how .NET works under the hood. My conception of how Stacks work is based on vague recollections of trying to code in Pascal, under DOS, in the early 90s. I have no idea how .NET/Windows does things these days!

like image 978
misha256 Avatar asked Jun 18 '15 00:06

misha256


1 Answers

Just have a look at the generated machine code to see what happens. You first need to change an option to ensure the optimizer is enabled, Tools > Options > Debugging > General > untick the "Suppress JIT optimization" checkbox. Switch to the Release build. Set a breakpoint on the DoWork call and when it hits use Debug > Windows > Disassembly to see the generated machine code.

I'll noodle a little bit about what you see. Your instinct is correct, only returning simple scalar values is efficient, they fit in a CPU register. Not this structure, the caller method must reserve space on its stack frame so the callee can store the structure there. It passes a pointer to that reserved space. In other words, there's no real difference if you had declared this method as Public Sub DoWork(ByRef retval As MyStructure).

Only other way this code can be optimized is by inlining the Function. The x86 jitter does not do that, it is picky about methods returning structs. The x64 jitter does in fact inline the method, but then does an absolutely horrible job with it. It still reserves the space for the return value and then generates lots and lots of needless initialization and value moving code. Quite atrocious. This jitter was rewritten for VS2015 (project name RyuJIT), I don't have it installed yet to see if it does a better job at it.

Basic conclusion to draw: this code isn't optimized. Structures work well when you pass them ByVal. Don't let this cramp your style, we're talking nanoseconds here.

like image 179
Hans Passant Avatar answered Nov 09 '22 00:11

Hans Passant