JIT 拆卸中的冗余存储
Redundant store in JIT disassemble
我继续探索 JIT assemble 输出,我发现了一对奇怪的 load/store 指令:
mov 0x30(%rsp),%rdx ; <---- this load
test %edi,%edi
jne 0x00007fd3d27c5032
cmp %r11d,%r10d
jae 0x00007fd3d27c4fbc
mov 0x10(%rbx,%r10,4),%edi
test %edi,%edi
je 0x00007fd3d27c5062
mov 0xc(%rbp),%esi
test %esi,%esi
je 0x00007fd3d27c4fea
mov %r8d,0x1c(%rsp)
mov %rdx,0x30(%rsp) ; <---- this store
mov %rax,0x28(%rsp)
mov %ecx,0x10(%rsp)
mov %rbp,0x20(%rsp)
mov %rbx,0x8(%rsp)
mov %r13d,%ebp
mov %r10d,0x14(%rsp)
mov %r11d,0x18(%rsp)
mov %r14d,0x40(%rsp)
mov %r9,(%rsp)
lea (%r12,%rdi,8),%rdx
shl [=10=]x3,%rsi
callq 0x00007fd3caceaf00
mov 0x20(%rsp),%r11
mov 0x10(%r11),%r10d
mov 0x8(%r12,%r10,8),%r8d
cmp [=10=]xf2c10,%r8d
jne 0x00007fd3d27c4ffa
lea (%r12,%r10,8),%r8
mov 0x10(%r8),%r10
movabs [=10=]x7fffffffffffffff,%r9
cmp %r9,%r10
je 0x00007fd3d27c5092
mov %r10,%rdx
add [=10=]x1,%rdx
test %rdx,%rdx
jle 0x00007fd3d27c50ce
mov %r10,%rax
lock cmpxchg %rdx,0x10(%r8)
sete %r11b
movzbl %r11b,%r11d
test %r11d,%r11d
je 0x00007fd3d27c5116
test %r10,%r10
jle 0x00007fd3d27c4f48
mov 0x108(%r15),%r11
mov 0x14(%rsp),%r10d
inc %r10d
mov 0x1c(%rsp),%r8d
inc %r8d
test %eax,(%r11)
mov (%rsp),%r9
mov 0x40(%rsp),%r14d
mov 0x18(%rsp),%r11d
mov %ebp,%r13d
mov 0x8(%rsp),%rbx
mov 0x20(%rsp),%rbp
mov 0x10(%rsp),%ecx
mov 0x28(%rsp),%rax
movzbl 0x18(%r9),%edi
movslq %r8d,%rsi
cmp 0x30(%rsp),%rsi
jge 0x00007fd3d27c4f17
cmp %r11d,%r10d
jl 0x00007fd3d27c4dea ; this is the end of the loop
; jump to the first instruction in this listing
为什么需要这些说明? load/store 之间没有 %rdx
的作品。是的,这是一个循环,但我不明白为什么它在下一次迭代中也可能有用。
这是一个错误还是同一种 JVM tricks as in ?
我在 this article 中发现了同样的问题,但那里没有任何解释。
您可能会看到完整的 PrintAssemble here and the original code is here
谢谢!
我已经为 ArraySubscription.slowPath
复制了 full assembly code。虽然寄存器映射与您的代码片段相比略有不同,但代码结构完全相同。
不完整的片段导致您得出错误的结论。其实%rdx
可以在load和store之间转换,因为中间有一个分支目标:L219 -> L55
看对应的Java source code:
就很好理解了
while (true) {
for (; sent < n && idx < length; sent++, idx++) {
if (canceled) {
return;
}
T element = array[idx];
if (element == null) {
subscriber.onError(new NullPointerException());
return;
}
subscriber.onNext(element);
}
Perfasm 向您展示了热内部 for
循环的编译代码。 0x30(%rsp)
中的值也缓存在 %rdx
中,保存局部变量 n
。但是,在循环之后,n
的值发生了变化:
n = requested;
外 while
继续。 corresponding compiled code 仅在寄存器中更新 n
,而不是 0x30(%rsp)
。
我继续探索 JIT assemble 输出,我发现了一对奇怪的 load/store 指令:
mov 0x30(%rsp),%rdx ; <---- this load
test %edi,%edi
jne 0x00007fd3d27c5032
cmp %r11d,%r10d
jae 0x00007fd3d27c4fbc
mov 0x10(%rbx,%r10,4),%edi
test %edi,%edi
je 0x00007fd3d27c5062
mov 0xc(%rbp),%esi
test %esi,%esi
je 0x00007fd3d27c4fea
mov %r8d,0x1c(%rsp)
mov %rdx,0x30(%rsp) ; <---- this store
mov %rax,0x28(%rsp)
mov %ecx,0x10(%rsp)
mov %rbp,0x20(%rsp)
mov %rbx,0x8(%rsp)
mov %r13d,%ebp
mov %r10d,0x14(%rsp)
mov %r11d,0x18(%rsp)
mov %r14d,0x40(%rsp)
mov %r9,(%rsp)
lea (%r12,%rdi,8),%rdx
shl [=10=]x3,%rsi
callq 0x00007fd3caceaf00
mov 0x20(%rsp),%r11
mov 0x10(%r11),%r10d
mov 0x8(%r12,%r10,8),%r8d
cmp [=10=]xf2c10,%r8d
jne 0x00007fd3d27c4ffa
lea (%r12,%r10,8),%r8
mov 0x10(%r8),%r10
movabs [=10=]x7fffffffffffffff,%r9
cmp %r9,%r10
je 0x00007fd3d27c5092
mov %r10,%rdx
add [=10=]x1,%rdx
test %rdx,%rdx
jle 0x00007fd3d27c50ce
mov %r10,%rax
lock cmpxchg %rdx,0x10(%r8)
sete %r11b
movzbl %r11b,%r11d
test %r11d,%r11d
je 0x00007fd3d27c5116
test %r10,%r10
jle 0x00007fd3d27c4f48
mov 0x108(%r15),%r11
mov 0x14(%rsp),%r10d
inc %r10d
mov 0x1c(%rsp),%r8d
inc %r8d
test %eax,(%r11)
mov (%rsp),%r9
mov 0x40(%rsp),%r14d
mov 0x18(%rsp),%r11d
mov %ebp,%r13d
mov 0x8(%rsp),%rbx
mov 0x20(%rsp),%rbp
mov 0x10(%rsp),%ecx
mov 0x28(%rsp),%rax
movzbl 0x18(%r9),%edi
movslq %r8d,%rsi
cmp 0x30(%rsp),%rsi
jge 0x00007fd3d27c4f17
cmp %r11d,%r10d
jl 0x00007fd3d27c4dea ; this is the end of the loop
; jump to the first instruction in this listing
为什么需要这些说明? load/store 之间没有 %rdx
的作品。是的,这是一个循环,但我不明白为什么它在下一次迭代中也可能有用。
这是一个错误还是同一种 JVM tricks as in
我在 this article 中发现了同样的问题,但那里没有任何解释。
您可能会看到完整的 PrintAssemble here and the original code is here
谢谢!
我已经为 ArraySubscription.slowPath
复制了 full assembly code。虽然寄存器映射与您的代码片段相比略有不同,但代码结构完全相同。
不完整的片段导致您得出错误的结论。其实%rdx
可以在load和store之间转换,因为中间有一个分支目标:L219 -> L55
看对应的Java source code:
就很好理解了 while (true) {
for (; sent < n && idx < length; sent++, idx++) {
if (canceled) {
return;
}
T element = array[idx];
if (element == null) {
subscriber.onError(new NullPointerException());
return;
}
subscriber.onNext(element);
}
Perfasm 向您展示了热内部 for
循环的编译代码。 0x30(%rsp)
中的值也缓存在 %rdx
中,保存局部变量 n
。但是,在循环之后,n
的值发生了变化:
n = requested;
外 while
继续。 corresponding compiled code 仅在寄存器中更新 n
,而不是 0x30(%rsp)
。