Skip to content

Commit 6bf3581

Browse files
committed
8369946: Bytecode rewriting causes Java heap corruption on PPC
Reviewed-by: rrich, dbriemann
1 parent 27c83c7 commit 6bf3581

File tree

3 files changed

+32
-24
lines changed

3 files changed

+32
-24
lines changed

src/hotspot/cpu/ppc/interp_masm_ppc.hpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,13 @@ class InterpreterMacroAssembler: public MacroAssembler {
133133
void get_cache_index_at_bcp(Register Rdst, int bcp_offset, size_t index_size);
134134

135135
void load_resolved_indy_entry(Register cache, Register index);
136-
void load_field_entry(Register cache, Register index, int bcp_offset = 1);
137-
void load_method_entry(Register cache, Register index, int bcp_offset = 1);
136+
void load_field_or_method_entry(bool is_method, Register cache, Register index, int bcp_offset, bool for_fast_bytecode);
137+
void load_field_entry(Register cache, Register index, int bcp_offset = 1, bool for_fast_bytecode = false) {
138+
load_field_or_method_entry(false, cache, index, bcp_offset, for_fast_bytecode);
139+
}
140+
void load_method_entry(Register cache, Register index, int bcp_offset = 1, bool for_fast_bytecode = false) {
141+
load_field_or_method_entry(true, cache, index, bcp_offset, for_fast_bytecode);
142+
}
138143

139144
void get_u4(Register Rdst, Register Rsrc, int offset, signedOrNot is_signed);
140145

src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -468,33 +468,33 @@ void InterpreterMacroAssembler::load_resolved_indy_entry(Register cache, Registe
468468
add(cache, cache, index);
469469
}
470470

471-
void InterpreterMacroAssembler::load_field_entry(Register cache, Register index, int bcp_offset) {
471+
void InterpreterMacroAssembler::load_field_or_method_entry(bool is_method, Register cache, Register index, int bcp_offset, bool for_fast_bytecode) {
472+
const int entry_size = is_method ? sizeof(ResolvedMethodEntry) : sizeof(ResolvedFieldEntry),
473+
base_offset = is_method ? Array<ResolvedMethodEntry>::base_offset_in_bytes() : Array<ResolvedFieldEntry>::base_offset_in_bytes(),
474+
entries_offset = is_method ? in_bytes(ConstantPoolCache::method_entries_offset()) : in_bytes(ConstantPoolCache::field_entries_offset());
475+
472476
// Get index out of bytecode pointer
473477
get_cache_index_at_bcp(index, bcp_offset, sizeof(u2));
474478
// Take shortcut if the size is a power of 2
475-
if (is_power_of_2(sizeof(ResolvedFieldEntry))) {
479+
if (is_power_of_2(entry_size)) {
476480
// Scale index by power of 2
477-
sldi(index, index, log2i_exact(sizeof(ResolvedFieldEntry)));
481+
sldi(index, index, log2i_exact(entry_size));
478482
} else {
479483
// Scale the index to be the entry index * sizeof(ResolvedFieldEntry)
480-
mulli(index, index, sizeof(ResolvedFieldEntry));
484+
mulli(index, index, entry_size);
481485
}
482486
// Get address of field entries array
483-
ld_ptr(cache, in_bytes(ConstantPoolCache::field_entries_offset()), R27_constPoolCache);
484-
addi(cache, cache, Array<ResolvedFieldEntry>::base_offset_in_bytes());
487+
ld_ptr(cache, entries_offset, R27_constPoolCache);
488+
addi(cache, cache, base_offset);
485489
add(cache, cache, index);
486-
}
487490

488-
void InterpreterMacroAssembler::load_method_entry(Register cache, Register index, int bcp_offset) {
489-
// Get index out of bytecode pointer
490-
get_cache_index_at_bcp(index, bcp_offset, sizeof(u2));
491-
// Scale the index to be the entry index * sizeof(ResolvedMethodEntry)
492-
mulli(index, index, sizeof(ResolvedMethodEntry));
493-
494-
// Get address of field entries array
495-
ld_ptr(cache, ConstantPoolCache::method_entries_offset(), R27_constPoolCache);
496-
addi(cache, cache, Array<ResolvedMethodEntry>::base_offset_in_bytes());
497-
add(cache, cache, index); // method_entries + base_offset + scaled index
491+
if (for_fast_bytecode) {
492+
// Prevent speculative loading from ResolvedFieldEntry/ResolvedMethodEntry as it can miss the info written by another thread.
493+
// TemplateTable::patch_bytecode uses release-store.
494+
// We reached here via control dependency (Bytecode dispatch has used the rewritten Bytecode).
495+
// So, we can use control-isync based ordering.
496+
isync();
497+
}
498498
}
499499

500500
// Load object from cpool->resolved_references(index).

src/hotspot/cpu/ppc/templateTable_ppc_64.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,9 @@ void TemplateTable::patch_bytecode(Bytecodes::Code new_bc, Register Rnew_bc, Reg
148148
__ bind(L_fast_patch);
149149
}
150150

151-
// Patch bytecode.
151+
// Patch bytecode with release store to coordinate with ResolvedFieldEntry
152+
// and ResolvedMethodEntry loads in fast bytecode codelets.
153+
__ release();
152154
__ stb(Rnew_bc, 0, R14_bcp);
153155

154156
__ bind(L_patch_done);
@@ -312,6 +314,7 @@ void TemplateTable::fast_aldc(LdcType type) {
312314
// We are resolved if the resolved reference cache entry contains a
313315
// non-null object (CallSite, etc.)
314316
__ get_cache_index_at_bcp(R31, 1, index_size); // Load index.
317+
// Only rewritten during link time. So, no need for memory barriers for accessing resolved info.
315318
__ load_resolved_reference_at_index(R17_tos, R31, R11_scratch1, R12_scratch2, &is_null);
316319

317320
// Convert null sentinel to null
@@ -3114,7 +3117,7 @@ void TemplateTable::fast_storefield(TosState state) {
31143117
const ConditionRegister CR_is_vol = CR2; // Non-volatile condition register (survives runtime call in do_oop_store).
31153118

31163119
// Constant pool already resolved => Load flags and offset of field.
3117-
__ load_field_entry(Rcache, Rscratch);
3120+
__ load_field_entry(Rcache, Rscratch, 1, /* for_fast_bytecode */ true);
31183121
jvmti_post_field_mod(Rcache, Rscratch, false /* not static */);
31193122
load_resolved_field_entry(noreg, Rcache, noreg, Roffset, Rflags, false); // Uses R11, R12
31203123

@@ -3195,7 +3198,7 @@ void TemplateTable::fast_accessfield(TosState state) {
31953198
// R12_scratch2 used by load_field_cp_cache_entry
31963199

31973200
// Constant pool already resolved. Get the field offset.
3198-
__ load_field_entry(Rcache, Rscratch);
3201+
__ load_field_entry(Rcache, Rscratch, 1, /* for_fast_bytecode */ true);
31993202
load_resolved_field_entry(noreg, Rcache, noreg, Roffset, Rflags, false); // Uses R11, R12
32003203

32013204
// JVMTI support
@@ -3334,7 +3337,7 @@ void TemplateTable::fast_xaccess(TosState state) {
33343337
__ ld(Rclass_or_obj, 0, R18_locals);
33353338

33363339
// Constant pool already resolved. Get the field offset.
3337-
__ load_field_entry(Rcache, Rscratch, 2);
3340+
__ load_field_entry(Rcache, Rscratch, 2, /* for_fast_bytecode */ true);
33383341
load_resolved_field_entry(noreg, Rcache, noreg, Roffset, Rflags, false); // Uses R11, R12
33393342

33403343
// JVMTI support not needed, since we switch back to single bytecode as soon as debugger attaches.
@@ -3495,7 +3498,7 @@ void TemplateTable::fast_invokevfinal(int byte_no) {
34953498

34963499
assert(byte_no == f2_byte, "use this argument");
34973500
Register Rcache = R31;
3498-
__ load_method_entry(Rcache, R11_scratch1);
3501+
__ load_method_entry(Rcache, R11_scratch1, 1, /* for_fast_bytecode */ true);
34993502
invokevfinal_helper(Rcache, R11_scratch1, R12_scratch2, R22_tmp2, R23_tmp3);
35003503
}
35013504

0 commit comments

Comments
 (0)