As of @ k5_, it seems like there is a threshold to determine whether to embed a function. And if the JIT compiler decided to embed it, it would take a lot of work and time to do this, since -XX:+PrintCompilation shows:
task-id 158 32 3 so_test.StrangeBehaviour::functionB (326 bytes) made not entrant 159 35 3 java.lang.String::<init> (82 bytes) 160 36 s 1 java.util.Vector::size (5 bytes) 1878 37 % 3 so_test.StrangeBehaviour::main @ 6 (65 bytes) 1898 38 3 so_test.StrangeBehaviour::main (65 bytes) 2665 39 3 java.util.regex.Pattern::has (15 bytes) 2667 40 3 sun.misc.FDBigInteger::mult (64 bytes) 2668 41 3 sun.misc.FDBigInteger::<init> (30 bytes) 2668 42 3 sun.misc.FDBigInteger::trimLeadingZeros (57 bytes) 2.51 seconds elapsed.
The top is non-comment information, followed by a comment that reduces the size of the method from 326 bytes to 318 bytes. And you may notice that the task ID in column 1 of the output is much larger in the latter, which causes more time.
task-id 126 35 4 so_test.StrangeBehaviour::functionA (12 bytes) 130 33 3 so_test.StrangeBehaviour::functionA (12 bytes) made not entrant 131 36 s 1 java.util.Vector::size (5 bytes) 14078 37 % 3 so_test.StrangeBehaviour::main @ 6 (65 bytes) 14296 38 3 so_test.StrangeBehaviour::main (65 bytes) 14296 39 % 4 so_test.StrangeBehaviour::functionB @ 2 (318 bytes) 14300 40 4 so_test.StrangeBehaviour::functionB (318 bytes) 14304 34 3 so_test.StrangeBehaviour::functionB (318 bytes) made not entrant 14628 41 3 java.util.regex.Pattern::has (15 bytes) 14631 42 3 sun.misc.FDBigInteger::mult (64 bytes) 14632 43 3 sun.misc.FDBigInteger::<init> (30 bytes) 14632 44 3 sun.misc.FDBigInteger::trimLeadingZeros (57 bytes) 14.50 seconds elapsed.
And if you change the code to the following (add two lines and copy the print line), you will see that the code size is changed to 326 bytes and it runs faster:
if (StrangeBehaviour.recursionFlag) { int a = 1; int b = 1; if (recursionSwitch == 0) { if (functionA(recursionDepth - 1, 1 - recursionSwitch)) return true; } else { if (!functionA(recursionDepth - 1, 1 - recursionSwitch)) return false; } } else { // This block is never entered into. // Yet commenting out one of the lines below makes the program run slower! System.out.println("..."); System.out.println("..."); System.out.println("..."); //System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); System.out.println("..."); }
New time and JIT compiler info:
140 34 3 so_test.StrangeBehaviour::functionB (326 bytes) made not entrant 145 36 3 java.lang.String::<init> (82 bytes) 148 37 s 1 java.util.Vector::size (5 bytes) 162 38 4 so_test.StrangeBehaviour::functionA (12 bytes) 163 33 3 so_test.StrangeBehaviour::functionA (12 bytes) made not entrant 1916 39 % 3 so_test.StrangeBehaviour::main @ 6 (65 bytes) 1936 40 3 so_test.StrangeBehaviour::main (65 bytes) 2686 41 3 java.util.regex.Pattern::has (15 bytes) 2689 42 3 sun.misc.FDBigInteger::mult (64 bytes) 2690 43 3 sun.misc.FDBigInteger::<init> (30 bytes) 2690 44 3 sun.misc.FDBigInteger::trimLeadingZeros (57 bytes) 2.55 seconds elapsed.
In conclusion :
- When the method size exceeds some restrictions, JIT will not inline this function.
- And if we comment out a line that shrinks to a size below the threshold, JIT decides to embed it;
- Embedding this function leads to many JIT tasks that slow down the program.
Update
Confirming my last test , the answer to this question is not so simple:
As my code example shows, the usual inline optimization will be
- speeds up the program
- and it doesn't cost much compiler work (in my test, it even costs less work when inline happens).
But in this problem, the code causes a lot of JIT work and slows down the program, which seems like a JIT error. And it is still unclear why this causes so much JIT work.