Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Treat readonly fields as JIT time constants. #4287

Closed
omariom opened this issue Jun 1, 2015 · 8 comments
Closed

Treat readonly fields as JIT time constants. #4287

omariom opened this issue Jun 1, 2015 · 8 comments

Comments

@omariom
Copy link
Contributor

omariom commented Jun 1, 2015

If understand it right mutating readonly fields outside of constructors is forbidden at CLR level.

In certain conditions this could allow JIT to treat static fields of classes as JIT time constants.
And it opens interesting opportunities.
For example, there is already a JIT times constant - IntPtr.Size. In the following code JIT will get rid not only of the wrong branch but the comparison itself:

if (IntPtr.Size == 32)
{
    Console.WriteLine("It is an x86 process");
}
else
{
    Console.WriteLine("It is an x64 process");
}

JIT could do the same with "constant" static readonly fields.
Imagine such field:

private static bool etwLoggingEnabled = ReadValueFromConfig();

And this check:

if (etwLoggingEnabled)
{
    DoEtwLogging();
}

Or it could be a performance counter or other similar thing.

Another case is static readonly array fields. JIT could skip bounds checking as if it were a local variable or a parameter.

There are possibly other optimization opportunities, you guys know your JIT better ;)

@mikedn
Copy link
Contributor

mikedn commented Jun 2, 2015

"For example, there is already a JIT times constant - IntPtr.Size. In the following code JIT will get rid not only of the wrong branch but the comparison itself"

As far as I can tell RyuJIT already does that:

if (IntPtr.Size == 8)
    Console.WriteLine(IntPtr.Size);

generates this

mov         ecx,8  
call        00007FFC36ADC1B0  

If understand it right mutating readonly fields outside of constructors is forbidden at CLR level.

Yet the following code runs and prints 42:

public class Program {
    public static readonly int x = 1;

    static void Main() {
        typeof(Program).GetField("x").SetValue(null, 42);
        Console.WriteLine(typeof(Program).GetField("x").GetValue(null));
    }
}

@omariom
Copy link
Contributor Author

omariom commented Jun 2, 2015

As far as I can tell RyuJIT already does thatAs far as I can tell RyuJIT already does that

IntPtr.Size is an old trick. The idea is to extend it to static readonly fields.

Yet the following code runs and prints 42:

yeah.. that's not complete readonliness 😞

@GeirGrusom
Copy link

What about static readonly delegates? Could they be inlined or lifted?

@mikedn
Copy link
Contributor

mikedn commented Jun 2, 2015

The idea is to extend it to static readonly fields

Ah, I see. It does that too:

public class Program {
    public static readonly int x = 1;
    static void Main() {
        if (x == 1)
            Console.WriteLine(x);
    }
}

generates

sub         rsp,28h  
mov         ecx,1                            ;no if
call        00007FFC36ADC1B0  
add         rsp,28h  
ret  

What about static readonly delegates? Could they be inlined or lifted?

Nope. Delegates are never inlined by current .NET JIT compilers.

@omariom
Copy link
Contributor Author

omariom commented Jun 2, 2015

WHAAAT!?? It is already there!?

Huge thanks guys! I dreamed of this feature :)

🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉

@omariom
Copy link
Contributor Author

omariom commented Jun 2, 2015

I checked it with ProcessorCount (just to be sure)

class Program
    {
        public static readonly int procCount = Environment.ProcessorCount;

        static void Main(string[] args)
        {
            if (procCount  == 2)
                Console.WriteLine("!");
        }
    }

if is completely eliminated. As well as WriteLine if procCount != 2.

I think this RuyJIT ability deserves a separate post in JIT team blog. People should know about it.

@briansull
Copy link
Contributor

For scalar types such as int or floats the JIT compilers have optimized this kinds of readonly fields since CLR 3.5 at least. If an Object based readonly static field is initialized then it is not possible to optimize them as their values depend upon the address assigned at runtime.

@omariom
Copy link
Contributor Author

omariom commented Jun 4, 2015

I am happily closing this issue.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants