Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8080451 | 9 | Max Ockner | P4 | Resolved | Fixed | b67 |
JDK-8082788 | emb-9 | Max Ockner | P4 | Resolved | Fixed | team |
Bug found via code inspection during port.
The error is in the file src/cpu/x86/vm/assembler_x86_32.cpp, around line 4836.
Here's a snippit:
if (need_tmp_reg) {
pushl(tmp_reg);
}
get_thread(tmp_reg);
movl(swap_reg, klass_addr);
orl(tmp_reg, Address(swap_reg, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes()));
movl(swap_reg, saved_mark_addr);
if (os::is_MP()) {
lock();
}
cmpxchg(tmp_reg, Address(obj_reg, 0));
if (need_tmp_reg) {
popl(tmp_reg);
}n
Basically the problem is that "tmp_reg" in some cases is actually "lock_reg" (see the top of the function),
and the "need_tmp_reg" conditional code is used to push/pop "tmp_reg" to allow us to re-use it.
However, that means that we can never reference "lock_reg" in the middle of the push/pop sequence.
And "saved_mark_addr" is an address defined with "lock_reg" as the base.
So we're using the value we just stuffed into "tmp_reg" as the address when we do:
movl(swap_reg, saved_mark_addr);
Note that this just happens in the cases when a valid "tmp_reg" isn't being passed into biased_locking_enter(),
so depending on the usage case it will sometimes work correctly. Also it's in a chunk of code that doesn't get
hit as often. (epoch expiration for bias holder)
That probably explains why this hasn't been caught yet.
The bug only exists in the 32-bit version. The 64-bit always supplies tmp_reg and doesn't have the push/pop logic.
Likewise, the Sparc doesn't have this problem since it also avoids the register re-use.
The error is in the file src/cpu/x86/vm/assembler_x86_32.cpp, around line 4836.
Here's a snippit:
if (need_tmp_reg) {
pushl(tmp_reg);
}
get_thread(tmp_reg);
movl(swap_reg, klass_addr);
orl(tmp_reg, Address(swap_reg, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes()));
movl(swap_reg, saved_mark_addr);
if (os::is_MP()) {
lock();
}
cmpxchg(tmp_reg, Address(obj_reg, 0));
if (need_tmp_reg) {
popl(tmp_reg);
}n
Basically the problem is that "tmp_reg" in some cases is actually "lock_reg" (see the top of the function),
and the "need_tmp_reg" conditional code is used to push/pop "tmp_reg" to allow us to re-use it.
However, that means that we can never reference "lock_reg" in the middle of the push/pop sequence.
And "saved_mark_addr" is an address defined with "lock_reg" as the base.
So we're using the value we just stuffed into "tmp_reg" as the address when we do:
movl(swap_reg, saved_mark_addr);
Note that this just happens in the cases when a valid "tmp_reg" isn't being passed into biased_locking_enter(),
so depending on the usage case it will sometimes work correctly. Also it's in a chunk of code that doesn't get
hit as often. (epoch expiration for bias holder)
That probably explains why this hasn't been caught yet.
The bug only exists in the 32-bit version. The 64-bit always supplies tmp_reg and doesn't have the push/pop logic.
Likewise, the Sparc doesn't have this problem since it also avoids the register re-use.
- backported by
-
JDK-8080451 x86 biasedlocking epoch expired rare bug
-
- Resolved
-
-
JDK-8082788 x86 biasedlocking epoch expired rare bug
-
- Resolved
-