Does the JVM do runtime constant folding?

621 views Asked by At

If I have two constants known at compile time, the Java compiler will fold them.

final static int foo = 2;
final static int bar = 17;
int myVariable;

int myFunction(){
    return foo*bar + myVariable;
}

At runtime, myFunction will return 34 + myVariable, and won't need to calculate 2*17 as that was done at compile time.

My question is: would it do the same if the constants aren't known until runtime? I believe this is called runtime code specialization.

final int foo;
final int bar;
int myVariable;

int myFunction(){
    return foo*bar + myVariable;
}

If foo and bar were initialised as 2 and 17 in the object's constructor, would myFunction be specialised to return 34 + myVariable, or would it still calculate foo*bar every time the function was called, even though foo*bar would never change?

*Edit: I'm referring to the newest version of the JVM, 1.7.0_45.

3

There are 3 answers

1
flaviut On BEST ANSWER

Hotspot Compiled Assembler

mov r10d,DWORD PTR [rsi+0x8]
shl    r10,0x3
cmp    rax,r10
jne    0x00007fb509045b60        ;   {runtime_call}
data32 xchg ax,ax
nop    WORD PTR [rax+rax*1+0x0]
nop    WORD PTR [rax+rax*1+0x0]
[Verified Entry Point]
sub    rsp,0x18
mov    QWORD PTR [rsp+0x10],rbp  ;*synchronization entry
                                 ;- Main$TestClass::myFunction@-1 (line 25)

mov    eax,DWORD PTR [rsi+0x10]
imul   eax,DWORD PTR [rsi+0xc]
add    eax,DWORD PTR [rsi+0x14]  ;*iadd 
                                 ;- Main$TestClass::myFunction@13 (line 25)
add    rsp,0x10
pop    rbp
test   DWORD PTR [rip+0x15f7a8bf],eax        # 0x00007fb51f087000 
                                 ;{poll_return}
ret

Java Code

public class Main {
    public static void main(String... args) {
        int accm = 0;
        TestClass t = new TestClass(542,452);
        while(true){
            t.myVariable = accm;
            accm += t.myFunction();
            if(false) break;
        }
        System.out.println(accm);
    }

    public static class TestClass{
        final int foo;
        final int bar;
        public int myVariable = 2;

        public TestClass(int foo, int bar){
            this.foo = foo;
            this.bar = bar;
        }


        int myFunction(){
            return foo*bar + myVariable;
        }
    }
}

Java Version

java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b124)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b66, mixed mode)

Conclusions

No, it can't.

While I do not understand most of what is going on there, it appears that the function has been inlined into the loop at [Verified Entry Point], but that the constants are not folded because there is a multiplication is still occurring at imul eax,DWORD PTR [rsi+0xc].

2
Tim B On

Foo and Bar would never change in that instance they could well be different in different instances though and the system doesn't compile the code separately for every instance of every object. The overhead from doing so would be terrible.

It's possible that the system may detect this but its unlikely, and you certainly couldn't expect all or even most environments to do so. Your best bet will be to store foobar = foo*bar yourself and use that if you think the multiplication is going to have a significant performance impact. (Which is unlikely).

1
Evgeniy Dorofeev On

I have JDK 1.7.0_45 and I compiled this code

class X {
    final int foo;
    final int bar;

    X() {
        foo = 2;
        bar = 17;
    }

    int myVariable;

    int myFunction() {
        return foo * bar + myVariable;
    }

and got this bytecote for myFunction

myFunction()I
   L0
    LINENUMBER 22 L0
    ALOAD 0
    GETFIELD test/X.foo : I         <-- load 2
    ALOAD 0
    GETFIELD test/X.bar : I         <-- load 17
    IMUL                            <-- 2 x 17
    ALOAD 0
    GETFIELD test/X.myVariable : I
    IADD
    IRETURN

so answer to "would it calculate foo*bar every time the function was called?" is yes (unless JVM optimizes it)