Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Using GOTO in C#

DZone's Guide to

Using GOTO in C#

Read this article in order to view some interesting use cases for using GOTO in C#.

· Database Zone ·
Free Resource

RavenDB vs MongoDB: Which is Better? This White Paper compares the two leading NoSQL Document Databases on 9 features to find out which is the best solution for your next project.  

After talking about GOTO in C, I thought that I should point out some interesting use cases for using GOTO in C#. Naturally, since C# actually have proper methods for resource cleanups (IDisposable and using), the situation is quite different.

Here is one usage of GOTO in RavenDB’s codebase:

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(T item)
{
    if (_size == _items.Length)
        goto Unlikely;

    _items[_size++] = item;
    _version++;
    return;

    Unlikely:
    AddUnlikely(item, (int)_size + 1);
}

This is used for micro-optimization purposes. The idea is that we put the hot spots of this code first and only jump to the rare parts of the code if the list is full. This keeps the size of the method very small and allows us to inline it in many cases and can substantially improve performance.

Here is another example, which is a bit crazier:

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int ReadNumber(byte* value, long sizeOfValue)
{
    int returnValue = *value;
    if (sizeOfValue == sizeof(byte))
        goto Successful;

    returnValue |= *(value + 1) << 8;
    if (sizeOfValue == sizeof(short))
        goto Successful;

    returnValue |= *(short*)(value + 2) << 16;
    if (sizeOfValue == sizeof(int))
        goto Successful;

    goto Error;

    Successful:
    return returnValue;

    Error:
    return ThrowInvalidSizeForNumber(sizeOfValue);
}

private static int ThrowInvalidSizeForNumber(long sizeOfValue)
{
    throw new ArgumentException($"Unsupported size {sizeOfValue}");
}

As you can see, this is a piece of code that is full of GOTOs, and there is quite a bit of jumping around. The answer to why we are doing this is again, performance. In particular, this method is located in a very important hot spot in our code, as you can imagine. Let’s consider a common usage of this:

var val = ReadNumber(buffer, 2);

What would be the result of this call? Well, we asked the JIT to inline the method, and it is small enough that it would comply. We are also passing a constant to the method, so the JIT can simplify it further by checking the conditions. Here is the end result in assembly:

L0034: movzx edx, byte [esi]
L0037: movzx eax, byte [esi+0x1]
L003b: shl eax, 0x8
L003e: or edx, eax
L0040: mov ecx, edx

Of course, this is the best (and pretty common for us) case where we know what the size would be. If we have to send a variable, we need to include the checks, but that is still very small.

In other words, we use GOTO to direct as much as possible the actual output of the machine code, explicitly trying to be more friendly toward the machine at the expense of readability in favor of performance.

Get comfortable using NoSQL in a free, self-directed learning course provided by RavenDB. Learn to create fully-functional real-world programs on NoSQL Databases. Register today.

Topics:
database ,c# ,ravendb ,goto

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}