这些代码来自:
http://hg.openjdk.java.net/code-tools/jcstress/file/tip/tests-custom/src/main/java/org/openjdk/jcstress/tests/volatiles/ReadAfterReadTest.java
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;
}
}我不明白作者所说的突出显示(*)注释是什么意思。
发布于 2017-07-24 04:52:56
Java spec要求在轮询它们的字段之前检查h1和h2实例是否为空,即使没有显式的NPE检查-这个功能也被称为隐式空指针检查。让我们看一下汇编代码(由JIT生成):
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)其中解除对空指针的引用将导致SEGV信号到进程。VM有SEGV处理程序,它可以处理这个问题,并抛出一个适当的NullPointerException(NPE)。
这可以被认为是一个小的编译器屏障,它可以阻止一些优化,其中异常应该准确地抛出在它发生的地方。这种检查保证了代码的进一步执行不会导致NPE,因此编译器可以移动h1.a和h2.a加载,因为它不再需要维护异常顺序。
发布于 2017-07-23 06:42:31
我认为他正在尝试提早生成NullPointerException。也就是说:如果h1或h2在这一点上为空,那么分配h1.trap = 0将抛出一个NPE。
接下来的几行解释了为什么这会有帮助:
Doing this early frees compiler from moving h1.a and h2.a loads -我认为它与编译器和JIT所做的一些优化有关。
最简单的方法是编写一个测试类,并为您尝试访问传递的变量值和不访问时的情况生成字节码,并查看差异。
或者您可以联系作者: Aleksey Shipilev (shade) @aleksey shipilev
如果你真的想理解,我认为你需要读一些关于这方面的东西:
https://www.ibm.com/developerworks/ibm/library/it-haggar_bytecode/ http://www.javaworld.com/article/2076060/build-ci-sdlc/compiler-optimizations.html
https://stackoverflow.com/questions/45259702
复制相似问题