Java 空指针检查顺序
这些代码来自:Java 空指针检查顺序,java,jvm,java-memory-model,Java,Jvm,Java Memory Model,这些代码来自: 我无法理解作者用(****)突出显示的注释是什么意思。我认为他试图尽早生成NullPointerException。也就是说:如果此时h1或h2为空,则赋值h1.trap=0将抛出NPE 下面几行解释了为什么这会有帮助: 这样做可以使编译器从移动h1.a和h2.a加载中解放出来——我认为这与编译器所做的一些优化和JIT有关 最简单的方法是编写一个测试类,并在尝试访问传递的变量值时生成字节码,而在不访问时生成字节码并看到差异 或者你可以联系作者:Aleksey Shipilev(
我无法理解作者用(****)突出显示的注释是什么意思。我认为他试图尽早生成
NullPointerException
。也就是说:如果此时h1
或h2
为空,则赋值h1.trap=0
将抛出NPE
下面几行解释了为什么这会有帮助:
这样做可以使编译器从移动h1.a和h2.a加载中解放出来
——我认为这与编译器所做的一些优化和JIT有关
最简单的方法是编写一个测试类,并在尝试访问传递的变量值时生成字节码,而在不访问时生成字节码并看到差异
或者你可以联系作者:Aleksey Shipilev(shade)@Aleksey Shipilev
如果你真的想理解,我想你需要读一些关于这方面的东西:
Java规范要求在轮询实例的字段之前,即使没有显式NPE检查,也要检查实例的
h1
和h2
是否为空-此功能也称为隐式空指针检查。让我们看看汇编代码(由JIT生成):
其中,取消引用空指针将导致向进程发送SEGV信号。VM有一个SEGV处理程序可以处理这个问题,并抛出一个适当的NullPointerException(NPE)
这可以被看作是一个小编译器的障碍,它可以阻止一些优化,在这些优化中,异常应该恰好在发生异常的地方抛出。此检查保证进一步执行代码不会导致NPE,因此编译器可以移动
h1.a
和h2.a
加载,因为它不必再维护异常顺序。@aleksey shipilev,您能对此发表评论吗?
public class ReadAfterReadTest {
private final Holder h1 = new Holder();
private final Holder h2 = h1;
private static class Holder {
int a;
int trap;
}
@Actor
public void actor1() {
h1.a = 1;
}
@Actor
public void actor2(II_Result r) {
Holder h1 = this.h1;
Holder h2 = this.h2;
(*****)
// Spam null-pointer check folding: try to step on NPEs early.
// Doing this early frees compiler from moving h1.a and h2.a loads
// around, because it would not have to maintain exception order anymore.
(*****)
h1.trap = 0;
h2.trap = 0;
// Spam alias analysis: the code effectively reads the same field twice,
// but compiler does not know (h1 == h2) (i.e. does not check it, as
// this is not a profitable opt for real code), so it issues two independent
// loads.
r.r1 = h1.a;
r.r2 = h2.a;
}
}
0x00007f1fad2429f2: mov %rbx,0x18(%rsp)
0x00007f1fad2429f7: mov (%rsp),%rbx
0x00007f1fad2429fb: mov 0x10(%rsp),%rcx
0x00007f1fad242a00: mov 0x28(%rsp),%r10 ;*aload
0x00007f1fad242a05: mov 0x10(%rbx),%r11d ;*getfield h1
0x00007f1fad242a09: mov 0xc(%r11),%edx ;*getfield a
; implicit exception: dispatches to 0x00007f1fad242b37
0x00007f1fad242a0d: mov %r12d,0x10(%r11) ;*putfield trap
0x00007f1fad242a11: mov 0x14(%rbx),%r9d ;*getfield h2
0x00007f1fad242a15: mov %r12d,0x10(%r9) ;*putfield trap
; implicit exception: dispatches to 0x00007f1fad242b49
0x00007f1fad242a19: mov %r10,0x28(%rsp)
0x00007f1fad242a1e: mov %rcx,0x10(%rsp)