Search code examples
c#.netcilil

Are void methods at their most basic faster/less of an overhead than methods that return a value?


I cannot find a similar question/answer either here on SO or on the internet, and as useless as this question maybe it is a question that came to my mind whilst doing some reading on MSIL. I am very curious to understand how IL operation execution works in my scenario, even if this is not a practical question I have no one else to ask.

Premise:

Bearing in mind that the execution of both MSIL commands and functions is done in three steps:

  1. Push command operands or function parameters onto the stack.
  2. Execute the MSIL command or call function. The command or function pops their operands (parameters) from the stack and pushes onto the stack result (return value).
  3. Read result from the stack.

Steps 1 and 3 are optional. For example, the void function doesn't push a return value to the stack.

I understand that it is what a method does that determines how much 'processing-power' is required, but for the sake of my curiosity lets consider these two very basic methods:

First method:

void Method1()
{
  var result = 1+1;
}

Second method:

int Method2()
{
  var result = 1+1;
  return result;
}

Question:

Because the void method doesn't push a return value (or is there an implicit return) does this mean that it requires less overhead when executing as opposed to the second method?


Solution

  • Remember, though, that MSIL is not executed or even interpreted. MSIL is an expression of the compiled code as it would be executed on the virtual machine. But the JIT compiler converts MSIL to machine code (x86, etc.). The x86 is fundamentally different from the stack-based virtual machine.

    At the most basic level, functions return values in registers. Assuming that the registers are large enough. Let's stick with 64-bit values (references, long integers, doubles, and smaller value types). Those can be returned in the RAX register. In your trivial example, there would be no difference in the generated machine code for the two functions. That is, Method1 would be:

    mov rax, 1
    inc rax
    ret
    

    (And, yes, I know that a smart compiler would collapse 1+1 to 2. Let's assume that there was a memory access there, okay?)

    Method2 would be identical because the value to be returned is already in the RAX register.

    So when you're working with 64 bit or smaller quantities, the difference between a method that returns a value and a method that doesn't return a value will most often differ, if at all, only in whatever instruction it takes to load the return value into the proper register. This is typically a single mov instruction. It's going to depend on the order in which things are done, and also on how well the compiler and JITer optimize things.