Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
30b7fcb
exps
rwestrel Mar 20, 2026
1e0dbf5
more
rwestrel Mar 23, 2026
7a7f904
more
rwestrel Mar 23, 2026
dfd5dad
more
rwestrel Mar 23, 2026
d64ca57
more
rwestrel Mar 23, 2026
7bf6a68
c1
rwestrel Mar 24, 2026
da96213
more
rwestrel Mar 24, 2026
a9dcfff
more
rwestrel Mar 24, 2026
eb3e313
more
rwestrel Mar 26, 2026
4901b15
more
rwestrel Mar 26, 2026
4ba6615
more
rwestrel Mar 26, 2026
e808d9f
more
rwestrel Mar 30, 2026
ce47284
more
rwestrel Mar 31, 2026
f42b582
more
rwestrel Mar 31, 2026
41cad18
more
rwestrel Apr 1, 2026
ab61fd9
more
rwestrel Apr 7, 2026
8b3e3a8
more
rwestrel Apr 23, 2026
a9ba603
more
rwestrel Apr 23, 2026
d1c073e
more
rwestrel Apr 24, 2026
8a9f78a
more
rwestrel Apr 27, 2026
aefb570
more
rwestrel Apr 29, 2026
4cadc4c
more
rwestrel Apr 29, 2026
a1e6f8c
more
rwestrel Apr 29, 2026
0b966a6
more
rwestrel Apr 30, 2026
f40ebbe
exp
rwestrel Apr 30, 2026
8074cc4
exp
rwestrel Apr 30, 2026
9bb0d12
more
rwestrel Apr 30, 2026
99cba41
more
rwestrel May 7, 2026
d3e1344
more
rwestrel May 7, 2026
82ed763
more
rwestrel May 11, 2026
3f833ee
more
rwestrel May 11, 2026
ec89477
exps
rwestrel May 12, 2026
2afa909
exps
rwestrel May 13, 2026
339f5d4
more
rwestrel May 13, 2026
f735b50
fix
rwestrel May 19, 2026
0fa586a
product build fix
rwestrel May 20, 2026
c4c0ac0
build fix
rwestrel May 20, 2026
1e09971
whitespaces
rwestrel May 20, 2026
5e046a7
profile_receiver_type_helper fixes
rwestrel May 21, 2026
54b1ec5
profile_receiver_type_helper fixes
rwestrel May 21, 2026
635504f
merge
rwestrel Jun 1, 2026
4d05db4
more
rwestrel Jun 1, 2026
8adfba0
Port changes to aarch64
galderz May 21, 2026
9f83b92
more
rwestrel Jun 3, 2026
e971135
more
rwestrel Jun 4, 2026
b5189fb
more
rwestrel Jun 4, 2026
8a60fda
more
rwestrel Jun 4, 2026
1ad7e8e
more
rwestrel Jun 5, 2026
ead41ee
more
rwestrel Jun 5, 2026
a741e69
more
rwestrel Jun 10, 2026
1bddde9
fixes
rwestrel Jun 11, 2026
5701a57
more
rwestrel Jun 11, 2026
a9bf71e
minimal build fix
rwestrel Jun 12, 2026
4b2aaa1
more
rwestrel Jun 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2969,6 +2969,48 @@ void LIR_Assembler::emit_profile_inline_type(LIR_OpProfileInlineType* op) {
__ bind(not_inline_type);
}

void LIR_Assembler::emit_profile_multiple_array_types(LIR_OpProfileMultipleArrayTypes* op) {
Register array = op->array()->as_pointer_register();
Register tmp1 = op->tmp1()->as_pointer_register();
Register tmp2 = op->tmp2()->as_pointer_register();
ciMethodData* md = op->md();

Label not_flat, done;
__ test_non_flat_array_oop (array, tmp1, not_flat);

Register klass = tmp1;
__ load_klass(klass, array);

Register mdo = tmp2;
__ mov_metadata(mdo, md->constant_encoding());

int mdp_offset = md->byte_offset_of_slot(op->load(), in_ByteSize(0));
__ profile_array_type_at_load(tmp1, mdo, mdp_offset);

__ b(done);
__ bind(not_flat);
__ mov_metadata(mdo, md->constant_encoding());

Label null_free;

__ test_null_free_array_oop(array, tmp1, null_free);

{
Address counter_addr(mdo, md->byte_offset_of_slot(op->load(), ArrayLoadData::not_flat_nullable_count_offset()));
__ addptr(counter_addr, DataLayout::counter_increment);
}

__ b(done);
__ bind(null_free);

{
Address counter_addr(mdo, md->byte_offset_of_slot(op->load(), ArrayLoadData::not_flat_null_free_count_offset()));
__ addptr(counter_addr, DataLayout::counter_increment);
}

__ bind(done);
}

void LIR_Assembler::align_backward_branch_target() {
}

Expand Down
52 changes: 39 additions & 13 deletions src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1202,44 +1202,70 @@ void InterpreterMacroAssembler::profile_switch_case(Register index,
}
}

template <class ArrayData> void InterpreterMacroAssembler::profile_array_type(Register mdp,
Register array,
Register tmp) {
void InterpreterMacroAssembler::profile_array_type(Register mdp,
Register array,
Register tmp) {
if (ProfileInterpreter) {
Label profile_continue;

// If no method data exists, go to profile_continue.
test_method_data_pointer(mdp, profile_continue);

mov(tmp, array);
profile_obj_type(tmp, Address(mdp, in_bytes(ArrayData::array_offset())));
profile_obj_type(tmp, Address(mdp, in_bytes(ArrayStoreData::array_offset())));

Label not_flat;
test_non_flat_array_oop(array, tmp, not_flat);

set_mdp_flag_at(mdp, ArrayData::flat_array_byte_constant());
set_mdp_flag_at(mdp, ArrayStoreData::flat_array_byte_constant());

bind(not_flat);

Label not_null_free;
test_non_null_free_array_oop(array, tmp, not_null_free);

set_mdp_flag_at(mdp, ArrayData::null_free_array_byte_constant());
set_mdp_flag_at(mdp, ArrayStoreData::null_free_array_byte_constant());

bind(not_null_free);

bind(profile_continue);
}
}

template void InterpreterMacroAssembler::profile_array_type<ArrayLoadData>(Register mdp,
Register array,
Register tmp);
template void InterpreterMacroAssembler::profile_array_type<ArrayStoreData>(Register mdp,
Register array,
Register tmp);
void InterpreterMacroAssembler::profile_multiple_array_types(Register mdp,
Register array,
Register tmp) {
if (ProfileInterpreter) {
Label profile_continue;

// If no method data exists, go to profile_continue.
test_method_data_pointer(mdp, profile_continue);

Label not_flat;
test_non_flat_array_oop(array, tmp, not_flat);

load_klass(tmp, array);
profile_array_type_at_load(tmp, mdp, 0);

b(profile_continue);
bind(not_flat);

Label not_null_free;
test_non_null_free_array_oop(array, tmp, not_null_free);

increment_mdp_data_at(mdp, in_bytes(ArrayLoadData::not_flat_null_free_count_offset()));

b(profile_continue);

bind(not_null_free);

increment_mdp_data_at(mdp, in_bytes(ArrayLoadData::not_flat_nullable_count_offset()));

bind(profile_continue);
}
}

void InterpreterMacroAssembler::profile_multiple_element_types(Register mdp, Register element, Register tmp, const Register tmp2) {
void InterpreterMacroAssembler::profile_multiple_element_types(Register mdp, Register element, Register tmp) {
if (ProfileInterpreter) {
Label profile_continue;

Expand Down
5 changes: 3 additions & 2 deletions src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,8 +303,9 @@ class InterpreterMacroAssembler: public MacroAssembler {
void profile_switch_default(Register mdp);
void profile_switch_case(Register index_in_scratch, Register mdp,
Register scratch2);
template <class ArrayData> void profile_array_type(Register mdp, Register array, Register tmp);
void profile_multiple_element_types(Register mdp, Register element, Register tmp, Register tmp2);
void profile_array_type(Register mdp, Register array, Register tmp);
void profile_multiple_array_types(Register mdp, Register array, Register tmp);
void profile_multiple_element_types(Register mdp, Register element, Register tmp);
void profile_element_type(Register mdp, Register element, Register tmp);
void profile_acmp(Register mdp, Register left, Register right, Register tmp);

Expand Down
167 changes: 122 additions & 45 deletions src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2112,56 +2112,32 @@ Address MacroAssembler::argument_address(RegisterOrConstant arg_slot,
}
}

// Handle the receiver type profile update given the "recv" klass.
//
// Normally updates the ReceiverData (RD) that starts at "mdp" + "mdp_offset".
// If there are no matching or claimable receiver entries in RD, updates
// the polymorphic counter.
//
// This code expected to run by either the interpreter or JIT-ed code, without
// extra synchronization. For safety, receiver cells are claimed atomically, which
// avoids grossly misrepresenting the profiles under concurrent updates. For speed,
// counter updates are not atomic.
//
void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_offset) {
assert_different_registers(recv, mdp, rscratch1, rscratch2);

int base_receiver_offset = in_bytes(ReceiverTypeData::receiver_offset(0));
int end_receiver_offset = in_bytes(ReceiverTypeData::receiver_offset(ReceiverTypeData::row_limit()));
int poly_count_offset = in_bytes(CounterData::count_offset());
int receiver_step = in_bytes(ReceiverTypeData::receiver_offset(1)) - base_receiver_offset;
int receiver_to_count_step = in_bytes(ReceiverTypeData::receiver_count_offset(0)) - base_receiver_offset;
void MacroAssembler::profile_receiver_type_helper(Register recv, Register mdp, Label &L_found_recv, int mdp_offset, int base, uint row_limit) {
int base_receiver_offset = in_bytes(MegamorphicTypeData::receiver_offset(base, 0));
int end_receiver_offset = in_bytes(MegamorphicTypeData::receiver_offset(base, row_limit));
int receiver_step = in_bytes(MegamorphicTypeData::receiver_offset(base, 1)) - base_receiver_offset;
int receiver_to_count_step = in_bytes(MegamorphicTypeData::receiver_count_offset(base, 0)) - base_receiver_offset;

// Adjust for MDP offsets.
base_receiver_offset += mdp_offset;
end_receiver_offset += mdp_offset;
poly_count_offset += mdp_offset;

#ifdef ASSERT
// We are about to walk the MDO slots without asking for offsets.
// Check that our math hits all the right spots.
for (uint c = 0; c < ReceiverTypeData::row_limit(); c++) {
int real_recv_offset = mdp_offset + in_bytes(ReceiverTypeData::receiver_offset(c));
int real_count_offset = mdp_offset + in_bytes(ReceiverTypeData::receiver_count_offset(c));
int real_recv_offset = mdp_offset + in_bytes(MegamorphicTypeData::receiver_offset(base, c));
int real_count_offset = mdp_offset + in_bytes(MegamorphicTypeData::receiver_count_offset(base, c));
int offset = base_receiver_offset + receiver_step*c;
int count_offset = offset + receiver_to_count_step;
assert(offset == real_recv_offset, "receiver slot math");
assert(offset== real_recv_offset, "receiver slot math");
assert(count_offset == real_count_offset, "receiver count math");
}
int real_poly_count_offset = mdp_offset + in_bytes(CounterData::count_offset());
assert(poly_count_offset == real_poly_count_offset, "poly counter math");
#endif

// Corner case: no profile table. Increment poly counter and exit.
if (ReceiverTypeData::row_limit() == 0) {
increment(Address(mdp, poly_count_offset), DataLayout::counter_increment);
return;
}

Register offset = rscratch2;

Label L_loop_search_receiver, L_loop_search_empty;
Label L_restart, L_found_recv, L_found_empty, L_count_update;
Label L_restart, L_found_empty, L_polymorphic;

// The code here recognizes three major cases:
// A. Fastest: receiver found in the table
Expand Down Expand Up @@ -2214,28 +2190,24 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_
// Fastest: receiver is already installed
mov(offset, base_receiver_offset);
bind(L_loop_search_receiver);
ldr(rscratch1, Address(mdp, offset));
cmp(rscratch1, recv);
br(Assembler::EQ, L_found_recv);
ldr(rscratch1, Address(mdp, offset));
cmp(rscratch1, recv);
br(Assembler::EQ, L_found_recv);
add(offset, offset, receiver_step);
sub(rscratch1, offset, end_receiver_offset);
cbnz(rscratch1, L_loop_search_receiver);

// Fast: no receiver, but profile is not full
mov(offset, base_receiver_offset);
bind(L_loop_search_empty);
ldr(rscratch1, Address(mdp, offset));
cbz(rscratch1, L_found_empty);
ldr(rscratch1, Address(mdp, offset));
cbz(rscratch1, L_found_empty);
add(offset, offset, receiver_step);
sub(rscratch1, offset, end_receiver_offset);
cbnz(rscratch1, L_loop_search_empty);
b(L_polymorphic);

// Slow: Receiver is not found and table is full.
// Increment polymorphic counter instead of receiver slot.
mov(offset, poly_count_offset);
b(L_count_update);

// Slowest: try to install receiver
// Slow: try to install receiver
bind(L_found_empty);

// Atomically swing receiver slot: null -> recv.
Expand All @@ -2254,15 +2226,120 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_
// and just restart the search from the beginning.
b(L_restart);

// Counter updates:

// Increment polymorphic counter instead of receiver slot.
bind(L_polymorphic);
}

// Handle the receiver type profile update given the "recv" klass.
//
// Normally updates the ReceiverData (RD) that starts at "mdp" + "mdp_offset".
// If there are no matching or claimable receiver entries in RD, updates
// the polymorphic counter.
//
// This code expected to run by either the interpreter or JIT-ed code, without
// extra synchronization. For safety, receiver cells are claimed atomically, which
// avoids grossly misrepresenting the profiles under concurrent updates. For speed,
// counter updates are not atomic.
//
void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_offset) {
assert_different_registers(recv, mdp, rscratch1, rscratch2);

int poly_count_offset = in_bytes(ReceiverTypeData::count_offset());
int base_receiver_offset = in_bytes(ReceiverTypeData::receiver_offset(0));
int receiver_to_count_step = in_bytes(ReceiverTypeData::receiver_count_offset(0)) - base_receiver_offset;

// Adjust for MDP offsets.
poly_count_offset += mdp_offset;

#ifdef ASSERT
int real_poly_count_offset = mdp_offset + in_bytes(ReceiverTypeData::count_offset());
assert(poly_count_offset == real_poly_count_offset, "poly counter math");
#endif

// Corner case: no profile table. Increment poly counter and exit.
if (ReceiverTypeData::row_limit() == 0) {
increment(Address(mdp, poly_count_offset), DataLayout::counter_increment);
return;
}

Label L_found_recv;
profile_receiver_type_helper(recv, mdp, L_found_recv, mdp_offset, ReceiverTypeData::base_of_megamorphic_type_data(), ReceiverTypeData::row_limit());
// Increment polymorphic counter instead of receiver slot.
Register offset = rscratch2;
mov(offset, poly_count_offset);
Label L_count_update;
b(L_count_update);

// Found a receiver, convert its slot offset to corresponding count offset.
bind(L_found_recv);
add(offset, offset, receiver_to_count_step);

// Finally, update the counter
bind(L_count_update);
increment(Address(mdp, offset), DataLayout::counter_increment);
}

void MacroAssembler::profile_array_type_at_load(Register recv, Register mdp, int mdp_offset) {
int base_receiver_offset = in_bytes(ArrayLoadData::receiver_offset(0));
int receiver_to_count_step = in_bytes(ArrayLoadData::receiver_count_offset(0)) - base_receiver_offset;
int flat_nullable_count_offset = in_bytes(ArrayLoadData::flat_nullable_count_offset());
int flat_nullfree_atomic_count_offset = in_bytes(ArrayLoadData::flat_nullfree_atomic_count_offset());
int flat_nullfree_not_atomic_count_offset = in_bytes(ArrayLoadData::flat_nullfree_not_atomic_count_offset());

// Adjust for MDP offsets. Slots are pointer-sized, so is the global offset.
flat_nullable_count_offset += mdp_offset;
flat_nullfree_atomic_count_offset += mdp_offset;
flat_nullfree_not_atomic_count_offset += mdp_offset;

#ifdef ASSERT
int real_flat_nullable_count_offset = mdp_offset + in_bytes(ArrayLoadData::flat_nullable_count_offset());
assert(flat_nullable_count_offset == real_flat_nullable_count_offset, "poly counter math");
int real_flat_nullfree_atomic_count_offset = mdp_offset + in_bytes(ArrayLoadData::flat_nullfree_atomic_count_offset());
assert(flat_nullfree_atomic_count_offset == real_flat_nullfree_atomic_count_offset, "poly counter math");
int real_flat_nullfree_not_atomic_count_offset = mdp_offset + in_bytes(ArrayLoadData::flat_nullfree_not_atomic_count_offset());
assert(flat_nullfree_not_atomic_count_offset == real_flat_nullfree_not_atomic_count_offset, "poly counter math");
#endif

Label L_found_recv;
// Corner case: no profile table. Increment poly counter and exit.
if (ReceiverTypeData::row_limit() != 0) {
profile_receiver_type_helper(recv, mdp, L_found_recv, mdp_offset, ArrayLoadData::base_of_megamorphic_type_data(), ArrayLoadData::row_limit());
}

Register offset = rscratch2;
int layout_kind_offset = in_bytes(FlatArrayKlass::layout_kind_offset());
Label null_free_non_atomic, null_free_atomic, nullable_atomic_flat, failure, L_count_update;
ldrw(rscratch1, Address(recv, layout_kind_offset));
cmpw(rscratch1, (int)LayoutKind::NULL_FREE_ATOMIC_FLAT);
br(NE, null_free_non_atomic);
mov(offset, flat_nullfree_atomic_count_offset);

b(L_count_update);
bind(null_free_non_atomic);
ldrw(rscratch1, Address(recv, layout_kind_offset));
cmpw(rscratch1, (int)LayoutKind::NULL_FREE_NON_ATOMIC_FLAT);
br(NE, nullable_atomic_flat);
mov(offset, flat_nullfree_not_atomic_count_offset);

b(L_count_update);
bind(nullable_atomic_flat);
ldrw(rscratch1, Address(recv, layout_kind_offset));
cmpw(rscratch1, (int)LayoutKind::NULLABLE_ATOMIC_FLAT);
br(NE, failure);
mov(offset, flat_nullable_count_offset);

b(L_count_update);
bind(failure);
stop("unexpected flat array");

// Found a receiver, convert its slot offset to corresponding count offset.
bind(L_found_recv);
add(offset, offset, receiver_to_count_step);

bind(L_count_update);
increment(Address(mdp, offset), DataLayout::counter_increment);
}

void MacroAssembler::call_VM_leaf_base(address entry_point,
int number_of_arguments,
Expand Down
4 changes: 4 additions & 0 deletions src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1177,7 +1177,11 @@ class MacroAssembler: public Assembler {

Address argument_address(RegisterOrConstant arg_slot, int extra_slot_offset = 0);

void profile_receiver_type_helper(Register recv, Register mdp,
Label &L_found_recv, int mdp_offset, int base, uint row_limit);

void profile_receiver_type(Register recv, Register mdp, int mdp_offset);
void profile_array_type_at_load(Register recv, Register mdp, int mdp_offset);

void verify_sve_vector_length(Register tmp = rscratch1);
void reinitialize_ptrue() {
Expand Down
Loading