C1: Intrinsify Class.getModifier method is relatively simple and straightforward example to intrinsify getModifier method. However, as I know very little about JIT, the patch is beyond my comprehension. Therefore, I took a blackbox approach to see its effect first before trying to understand how it is implemented.

§Simple Java Program

Here’s a trivial java program calling getModifiers.

1
2
3
4
5
6
7
8
9
10
11
12
// in hello.java
public class hello {
static int y;
static void f(Class c) {
y = int.class.getModifiers();
}

public static void main(String[] args) {
f(int.class);
// System.out.println(String.format("0x%x", y));
}
}

§Running

Normally, one can just run java <filename>, but we wanna see some additional info for our little experiment, so we use a simple shell script as the runner:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/zsh
# build jdk before & after the commit
#beforejava=...
#afterjava=...

config= "\
-XX:+UnlockExperimentalVMOptions \
-XX:+UnlockDiagnosticVMOptions \
-Xcomp \
-XX:+PrintInlining \
-XX:TieredStopAtLevel=3 \
-XX:CompileCommand='CompileOnly,*hello.f' \
-XX:CompileCommand='DontInline,*hello.f' \
-XX:PrintAssemblyOptions=intel \
-XX:CompileCommand='PrintAssembly,*hello.f' \
"

eval "$beforejava $config hello.java &> before.txt"

eval "$afterjava $config hello.java &> after.txt"

Since we are only interested in how hello.f is compiled , we disable inline (DontInline) for it, and exclude compilation (CompileOnly) for other methods. Additionally, we disable C2 (TieredStopAtLevel=3) to reduce noise in the output. Finally, we use -Xcomp to force compilation (effectively disabling the interpreter) before executing a method; otherwise, our single invocation of f in main will not trigger compilation.

§Results

The interesting part is around getModifiers:

§before.txt

1
2
3
4
5
0x00007f48fdf1520f:   call   0x00007f48fd82da80           ; ImmutableOopMap {}
;*invokevirtual getModifiers {reexecute=0 rethrow=0 return_oop=0}
; - hello::f@3 (line 12)
; {optimized virtual_call}

§after.txt

There’s no reference to getModifier in the assembly; instead, it’s just a plain mov. The 0x411 literal seems a bit magical; if we print the final result of y, we will see 0x411 as well. IOW, int.class.getModifier() is 0x411, and C1 has completely replaced the original method call with a literal.

1
2
3
0x00007f2e1104861a:   mov    DWORD PTR [rsi+0x70],0x411   ;*putstatic y {reexecute=0 rethrow=0 return_oop=0}
; - hello::f@6 (line 12)

§Summary

After seeing the end effect of this patch, we are hopefully getting a better mental picture on what this patch does. With that info in mind, we can re-read this patch without feeling overwhelmed.