JIT中的冗余存储区将分解

时间:2019-01-22 21:13:46

标签: assembly jvm reverse-engineering jit jvm-hotspot

我继续探索JIT汇编输出,发现了一对奇怪的加载/存储指令:

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    $0x3,%rsi
callq  0x00007fd3caceaf00



mov    0x20(%rsp),%r11
mov    0x10(%r11),%r10d


mov    0x8(%r12,%r10,8),%r8d
cmp    $0xf2c10,%r8d
jne    0x00007fd3d27c4ffa

lea    (%r12,%r10,8),%r8

mov    0x10(%r8),%r10
movabs $0x7fffffffffffffff,%r9
cmp    %r9,%r10
je     0x00007fd3d27c5092

mov    %r10,%rdx
add    $0x1,%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 

为什么需要这些说明?在加载/存储之间无法使用%rdx。是的,这是一个循环,但是我不明白为什么它在下一次迭代中可能也不有用。

是错误还是与JVM tricks中的my previous question相同?

我在this article中发现了相同的问题,但是那里没有解释。

完整的PrintAssemble您可能会看到here,原始代码为here

谢谢!

1 个答案:

答案 0 :(得分:4)

我为ArraySubscription.slowPath复制了full assembly code。尽管与您的代码段相比,寄存器映射略有不同,但代码结构却完全相同。

不完整的片段使您得出错误的结论。实际上%rdx 可以在加载和存储之间进行更改,因为中间有一个分支目标: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)中更新。