Skip to content

Commit

Permalink
8254693: Add Panama feature to pass heap segments to native code
Browse files Browse the repository at this point in the history
Reviewed-by: mcimadamore, lucy, vlivanov
  • Loading branch information
JornVernee committed Nov 14, 2023
1 parent c80e691 commit 9c98270
Show file tree
Hide file tree
Showing 73 changed files with 1,989 additions and 959 deletions.
153 changes: 76 additions & 77 deletions src/hotspot/cpu/aarch64/downcallLinker_aarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,63 +36,6 @@

#define __ _masm->

class DowncallStubGenerator : public StubCodeGenerator {
BasicType* _signature;
int _num_args;
BasicType _ret_bt;
const ABIDescriptor& _abi;

const GrowableArray<VMStorage>& _input_registers;
const GrowableArray<VMStorage>& _output_registers;

bool _needs_return_buffer;
int _captured_state_mask;
bool _needs_transition;

int _frame_complete;
int _frame_size_slots;
OopMapSet* _oop_maps;
public:
DowncallStubGenerator(CodeBuffer* buffer,
BasicType* signature,
int num_args,
BasicType ret_bt,
const ABIDescriptor& abi,
const GrowableArray<VMStorage>& input_registers,
const GrowableArray<VMStorage>& output_registers,
bool needs_return_buffer,
int captured_state_mask,
bool needs_transition)
: StubCodeGenerator(buffer, PrintMethodHandleStubs),
_signature(signature),
_num_args(num_args),
_ret_bt(ret_bt),
_abi(abi),
_input_registers(input_registers),
_output_registers(output_registers),
_needs_return_buffer(needs_return_buffer),
_captured_state_mask(captured_state_mask),
_needs_transition(needs_transition),
_frame_complete(0),
_frame_size_slots(0),
_oop_maps(nullptr) {
}

void generate();

int frame_complete() const {
return _frame_complete;
}

int framesize() const {
return (_frame_size_slots >> (LogBytesPerWord - LogBytesPerInt));
}

OopMapSet* oop_maps() const {
return _oop_maps;
}
};

static const int native_invoker_code_base_size = 256;
static const int native_invoker_size_per_arg = 8;

Expand All @@ -108,10 +51,10 @@ RuntimeStub* DowncallLinker::make_downcall_stub(BasicType* signature,
int code_size = native_invoker_code_base_size + (num_args * native_invoker_size_per_arg);
int locs_size = 1; // must be non-zero
CodeBuffer code("nep_invoker_blob", code_size, locs_size);
DowncallStubGenerator g(&code, signature, num_args, ret_bt, abi,
input_registers, output_registers,
needs_return_buffer, captured_state_mask,
needs_transition);
StubGenerator g(&code, signature, num_args, ret_bt, abi,
input_registers, output_registers,
needs_return_buffer, captured_state_mask,
needs_transition);
g.generate();
code.log_section_sizes("nep_invoker_blob");

Expand All @@ -134,7 +77,39 @@ RuntimeStub* DowncallLinker::make_downcall_stub(BasicType* signature,
return stub;
}

void DowncallStubGenerator::generate() {
static constexpr int RFP_BIAS = 16; // skip old rbp and return address

void DowncallLinker::StubGenerator::pd_add_offset_to_oop(VMStorage reg_oop, VMStorage reg_offset, VMStorage tmp1, VMStorage tmp2) const {
Register r_tmp1 = as_Register(tmp1);
Register r_tmp2 = as_Register(tmp2);
if (reg_oop.is_reg()) {
assert(reg_oop.type() == StorageType::INTEGER, "expected");
Register reg_oop_reg = as_Register(reg_oop);
if (reg_offset.is_reg()) {
assert(reg_offset.type() == StorageType::INTEGER, "expected");
__ add(reg_oop_reg, reg_oop_reg, as_Register(reg_offset));
} else {
assert(reg_offset.is_stack(), "expected");
assert(reg_offset.stack_size() == 8, "expected long");
Address offset_addr(rfp, RFP_BIAS + reg_offset.offset());
__ ldr (r_tmp1, offset_addr);
__ add(reg_oop_reg, reg_oop_reg, r_tmp1);
}
} else {
assert(reg_oop.is_stack(), "expected");
assert(reg_oop.stack_size() == 8, "expected long");
assert(reg_offset.is_stack(), "expected");
assert(reg_offset.stack_size() == 8, "expected long");
Address offset_addr(rfp, RFP_BIAS + reg_offset.offset());
Address oop_addr(rfp, RFP_BIAS + reg_oop.offset());
__ ldr(r_tmp1, offset_addr);
__ ldr(r_tmp2, oop_addr);
__ add(r_tmp1, r_tmp1, r_tmp2);
__ str(r_tmp1, oop_addr);
}
}

void DowncallLinker::StubGenerator::generate() {
enum layout {
rfp_off,
rfp_off2,
Expand All @@ -150,23 +125,16 @@ void DowncallStubGenerator::generate() {
Register tmp1 = r9;
Register tmp2 = r10;

VMStorage shuffle_reg = as_VMStorage(r19);
JavaCallingConvention in_conv;
NativeCallingConvention out_conv(_input_registers);
ArgumentShuffle arg_shuffle(_signature, _num_args, _signature, _num_args, &in_conv, &out_conv, shuffle_reg);

#ifndef PRODUCT
LogTarget(Trace, foreign, downcall) lt;
if (lt.is_enabled()) {
ResourceMark rm;
LogStream ls(lt);
arg_shuffle.print_on(&ls);
}
#endif
GrowableArray<VMStorage> java_regs;
ForeignGlobals::java_calling_convention(_signature, _num_args, java_regs);
bool has_objects = false;
GrowableArray<VMStorage> filtered_java_regs = ForeignGlobals::downcall_filter_offset_regs(java_regs, _signature,
_num_args, has_objects);
assert(!(_needs_transition && has_objects), "can not pass objects when doing transition");

int allocated_frame_size = 0;
assert(_abi._shadow_space_bytes == 0, "not expecting shadow space on AArch64");
allocated_frame_size += arg_shuffle.out_arg_bytes();
allocated_frame_size += ForeignGlobals::compute_out_arg_bytes(_input_registers);

bool should_save_return_value = !_needs_return_buffer;
RegSpiller out_reg_spiller(_output_registers);
Expand All @@ -193,6 +161,33 @@ void DowncallStubGenerator::generate() {
allocated_frame_size += BytesPerWord;
}

// The space we have allocated will look like:
//
// FP-> | |
// |---------------------| = frame_bottom_offset = frame_size
// | (optional) |
// | capture state buf |
// |---------------------| = StubLocations::CAPTURED_STATE_BUFFER
// | (optional) |
// | return buffer |
// |---------------------| = StubLocations::RETURN_BUFFER
// SP-> | out/stack args | or | out_reg_spiller area |
//
// Note how the last chunk can be shared, since the 3 uses occur at different times.

VMStorage shuffle_reg = as_VMStorage(r19);
GrowableArray<VMStorage> out_regs = ForeignGlobals::replace_place_holders(_input_registers, locs);
ArgumentShuffle arg_shuffle(filtered_java_regs, out_regs, shuffle_reg);

#ifndef PRODUCT
LogTarget(Trace, foreign, downcall) lt;
if (lt.is_enabled()) {
ResourceMark rm;
LogStream ls(lt);
arg_shuffle.print_on(&ls);
}
#endif

_frame_size_slots = align_up(framesize + (allocated_frame_size >> LogBytesPerInt), 4);
assert(is_even(_frame_size_slots/2), "sp not 16-byte aligned");

Expand All @@ -218,8 +213,12 @@ void DowncallStubGenerator::generate() {
__ stlrw(tmp1, tmp2);
}

if (has_objects) {
add_offsets_to_oops(java_regs, as_VMStorage(tmp1), as_VMStorage(tmp2));
}

__ block_comment("{ argument shuffle");
arg_shuffle.generate(_masm, shuffle_reg, 0, _abi._shadow_space_bytes, locs);
arg_shuffle.generate(_masm, shuffle_reg, 0, _abi._shadow_space_bytes);
__ block_comment("} argument shuffle");

__ blr(as_Register(locs.get(StubLocations::TARGET_ADDRESS)));
Expand Down
10 changes: 1 addition & 9 deletions src/hotspot/cpu/aarch64/foreignGlobals_aarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,21 +200,13 @@ static void move_v128(MacroAssembler* masm, int out_stk_bias,
}
}

void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMStorage tmp, int in_stk_bias, int out_stk_bias, const StubLocations& locs) const {
void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMStorage tmp, int in_stk_bias, int out_stk_bias) const {
Register tmp_reg = as_Register(tmp);
for (int i = 0; i < _moves.length(); i++) {
Move move = _moves.at(i);
VMStorage from_reg = move.from;
VMStorage to_reg = move.to;

// replace any placeholders
if (from_reg.type() == StorageType::PLACEHOLDER) {
from_reg = locs.get(from_reg);
}
if (to_reg.type() == StorageType::PLACEHOLDER) {
to_reg = locs.get(to_reg);
}

switch (from_reg.type()) {
case StorageType::INTEGER:
assert(from_reg.segment_mask() == REG64_MASK, "only 64-bit register supported");
Expand Down
44 changes: 23 additions & 21 deletions src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,48 +118,36 @@ static const int upcall_stub_code_base_size = 1024;
static const int upcall_stub_size_per_arg = 16;

address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
BasicType* in_sig_bt, int total_in_args,
BasicType* out_sig_bt, int total_out_args,
BasicType ret_type,
jobject jabi, jobject jconv,
bool needs_return_buffer, int ret_buf_size) {
ResourceMark rm;
const ABIDescriptor abi = ForeignGlobals::parse_abi_descriptor(jabi);
const CallRegs call_regs = ForeignGlobals::parse_call_regs(jconv);
int code_size = upcall_stub_code_base_size + (total_in_args * upcall_stub_size_per_arg);
int code_size = upcall_stub_code_base_size + (total_out_args * upcall_stub_size_per_arg);
CodeBuffer buffer("upcall_stub", code_size, /* locs_size = */ 1);

Register shuffle_reg = r19;
JavaCallingConvention out_conv;
NativeCallingConvention in_conv(call_regs._arg_regs);
ArgumentShuffle arg_shuffle(in_sig_bt, total_in_args, out_sig_bt, total_out_args, &in_conv, &out_conv, as_VMStorage(shuffle_reg));
GrowableArray<VMStorage> unfiltered_out_regs;
int out_arg_bytes = ForeignGlobals::java_calling_convention(out_sig_bt, total_out_args, unfiltered_out_regs);
int preserved_bytes = SharedRuntime::out_preserve_stack_slots() * VMRegImpl::stack_slot_size;
int stack_bytes = preserved_bytes + arg_shuffle.out_arg_bytes();
int stack_bytes = preserved_bytes + out_arg_bytes;
int out_arg_area = align_up(stack_bytes , StackAlignmentInBytes);

#ifndef PRODUCT
LogTarget(Trace, foreign, upcall) lt;
if (lt.is_enabled()) {
ResourceMark rm;
LogStream ls(lt);
arg_shuffle.print_on(&ls);
}
#endif

// out_arg_area (for stack arguments) doubles as shadow space for native calls.
// make sure it is big enough.
if (out_arg_area < frame::arg_reg_save_area_bytes) {
out_arg_area = frame::arg_reg_save_area_bytes;
}

int reg_save_area_size = compute_reg_save_area_size(abi);
RegSpiller arg_spilller(call_regs._arg_regs);
RegSpiller arg_spiller(call_regs._arg_regs);
RegSpiller result_spiller(call_regs._ret_regs);

int shuffle_area_offset = 0;
int res_save_area_offset = shuffle_area_offset + out_arg_area;
int arg_save_area_offset = res_save_area_offset + result_spiller.spill_size_bytes();
int reg_save_area_offset = arg_save_area_offset + arg_spilller.spill_size_bytes();
int reg_save_area_offset = arg_save_area_offset + arg_spiller.spill_size_bytes();
int frame_data_offset = reg_save_area_offset + reg_save_area_size;
int frame_bottom_offset = frame_data_offset + sizeof(UpcallStub::FrameData);

Expand All @@ -173,6 +161,20 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
locs.set(StubLocations::RETURN_BUFFER, abi._scratch1);
}

Register shuffle_reg = r19;
GrowableArray<VMStorage> in_regs = ForeignGlobals::replace_place_holders(call_regs._arg_regs, locs);
GrowableArray<VMStorage> filtered_out_regs = ForeignGlobals::upcall_filter_receiver_reg(unfiltered_out_regs);
ArgumentShuffle arg_shuffle(in_regs, filtered_out_regs, as_VMStorage(shuffle_reg));

#ifndef PRODUCT
LogTarget(Trace, foreign, upcall) lt;
if (lt.is_enabled()) {
ResourceMark rm;
LogStream ls(lt);
arg_shuffle.print_on(&ls);
}
#endif

int frame_size = frame_bottom_offset;
frame_size = align_up(frame_size, StackAlignmentInBytes);

Expand Down Expand Up @@ -212,7 +214,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,

// we have to always spill args since we need to do a call to get the thread
// (and maybe attach it).
arg_spilller.generate_spill(_masm, arg_save_area_offset);
arg_spiller.generate_spill(_masm, arg_save_area_offset);
preserve_callee_saved_registers(_masm, abi, reg_save_area_offset);

__ block_comment("{ on_entry");
Expand All @@ -225,12 +227,12 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
__ block_comment("} on_entry");

__ block_comment("{ argument shuffle");
arg_spilller.generate_fill(_masm, arg_save_area_offset);
arg_spiller.generate_fill(_masm, arg_save_area_offset);
if (needs_return_buffer) {
assert(ret_buf_offset != -1, "no return buffer allocated");
__ lea(as_Register(locs.get(StubLocations::RETURN_BUFFER)), Address(sp, ret_buf_offset));
}
arg_shuffle.generate(_masm, as_VMStorage(shuffle_reg), abi._shadow_space_bytes, 0, locs);
arg_shuffle.generate(_masm, as_VMStorage(shuffle_reg), abi._shadow_space_bytes, 0);
__ block_comment("} argument shuffle");

__ block_comment("{ receiver ");
Expand Down
5 changes: 5 additions & 0 deletions src/hotspot/cpu/arm/downcallLinker_arm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,8 @@ RuntimeStub* DowncallLinker::make_downcall_stub(BasicType* signature,
Unimplemented();
return nullptr;
}

void DowncallLinker::StubGenerator::pd_add_offset_to_oop(VMStorage reg_oop, VMStorage reg_offset,
VMStorage tmp1, VMStorage tmp2) const {
Unimplemented();
}
2 changes: 1 addition & 1 deletion src/hotspot/cpu/arm/foreignGlobals_arm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,6 @@ void RegSpiller::pd_load_reg(MacroAssembler* masm, int offset, VMStorage reg) {
Unimplemented();
}

void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMStorage tmp, int in_stk_bias, int out_stk_bias, const StubLocations& locs) const {
void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMStorage tmp, int in_stk_bias, int out_stk_bias) const {
Unimplemented();
}
1 change: 0 additions & 1 deletion src/hotspot/cpu/arm/upcallLinker_arm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
#include "utilities/debug.hpp"

address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
BasicType* in_sig_bt, int total_in_args,
BasicType* out_sig_bt, int total_out_args,
BasicType ret_type,
jobject jabi, jobject jconv,
Expand Down

1 comment on commit 9c98270

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.