提交 05fa054c 编写于 作者: G goetz

8024342: PPC64 (part 111): Support for C calling conventions that require 64-bit ints.

Summary: Some platforms, as ppc and s390x/zArch require that 32-bit ints are passed as 64-bit values to C functions. This change adds support to adapt the signature and to issue proper casts to c2-compiled stubs. The functions are used in generate_native_wrapper(). Adapt signature used by the compiler as in PhaseIdealLoop::intrinsify_fill().
Reviewed-by: kvn
上级 cb6ef5af
...@@ -31,4 +31,10 @@ const int BytesPerInstWord = 4; ...@@ -31,4 +31,10 @@ const int BytesPerInstWord = 4;
const int StackAlignmentInBytes = 16; const int StackAlignmentInBytes = 16;
// Indicates whether the C calling conventions require that
// 32-bit integer argument values are properly extended to 64 bits.
// If set, SharedRuntime::c_calling_convention() must adapt
// signatures accordingly.
const bool CCallingConventionRequiresIntsAsLongs = true;
#endif // CPU_PPC_VM_GLOBALDEFINITIONS_PPC_HPP #endif // CPU_PPC_VM_GLOBALDEFINITIONS_PPC_HPP
...@@ -734,11 +734,8 @@ int SharedRuntime::c_calling_convention(const BasicType *sig_bt, ...@@ -734,11 +734,8 @@ int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
// We must cast ints to longs and use full 64 bit stack slots // We must cast ints to longs and use full 64 bit stack slots
// here. We do the cast in GraphKit::gen_stub() and just guard // here. We do the cast in GraphKit::gen_stub() and just guard
// here against loosing that change. // here against loosing that change.
Unimplemented(); // TODO: PPC port assert(CCallingConventionRequiresIntsAsLongs,
/*
assert(SharedRuntime::c_calling_convention_requires_ints_as_longs(),
"argument of type int should be promoted to type long"); "argument of type int should be promoted to type long");
*/
guarantee(i > 0 && sig_bt[i-1] == T_LONG, guarantee(i > 0 && sig_bt[i-1] == T_LONG,
"argument of type (bt) should have been promoted to type (T_LONG,bt) for bt in " "argument of type (bt) should have been promoted to type (T_LONG,bt) for bt in "
"{T_BOOLEAN, T_CHAR, T_BYTE, T_SHORT, T_INT}"); "{T_BOOLEAN, T_CHAR, T_BYTE, T_SHORT, T_INT}");
...@@ -856,7 +853,6 @@ static address gen_c2i_adapter(MacroAssembler *masm, ...@@ -856,7 +853,6 @@ static address gen_c2i_adapter(MacroAssembler *masm,
const int adapter_size = frame::top_ijava_frame_abi_size + const int adapter_size = frame::top_ijava_frame_abi_size +
round_to(total_args_passed * wordSize, frame::alignment_in_bytes); round_to(total_args_passed * wordSize, frame::alignment_in_bytes);
// regular (verified) c2i entry point // regular (verified) c2i entry point
c2i_entrypoint = __ pc(); c2i_entrypoint = __ pc();
......
...@@ -30,6 +30,12 @@ const int BytesPerInstWord = 4; ...@@ -30,6 +30,12 @@ const int BytesPerInstWord = 4;
const int StackAlignmentInBytes = (2*wordSize); const int StackAlignmentInBytes = (2*wordSize);
// Indicates whether the C calling conventions require that
// 32-bit integer argument values are properly extended to 64 bits.
// If set, SharedRuntime::c_calling_convention() must adapt
// signatures accordingly.
const bool CCallingConventionRequiresIntsAsLongs = false;
#define SUPPORTS_NATIVE_CX8 #define SUPPORTS_NATIVE_CX8
#endif // CPU_SPARC_VM_GLOBALDEFINITIONS_SPARC_HPP #endif // CPU_SPARC_VM_GLOBALDEFINITIONS_SPARC_HPP
...@@ -27,6 +27,12 @@ ...@@ -27,6 +27,12 @@
const int StackAlignmentInBytes = 16; const int StackAlignmentInBytes = 16;
// Indicates whether the C calling conventions require that
// 32-bit integer argument values are properly extended to 64 bits.
// If set, SharedRuntime::c_calling_convention() must adapt
// signatures accordingly.
const bool CCallingConventionRequiresIntsAsLongs = false;
#define SUPPORTS_NATIVE_CX8 #define SUPPORTS_NATIVE_CX8
#endif // CPU_X86_VM_GLOBALDEFINITIONS_X86_HPP #endif // CPU_X86_VM_GLOBALDEFINITIONS_X86_HPP
...@@ -28,4 +28,10 @@ ...@@ -28,4 +28,10 @@
#include <ffi.h> #include <ffi.h>
// Indicates whether the C calling conventions require that
// 32-bit integer argument values are properly extended to 64 bits.
// If set, SharedRuntime::c_calling_convention() must adapt
// signatures accordingly.
const bool CCallingConventionRequiresIntsAsLongs = false;
#endif // CPU_ZERO_VM_GLOBALDEFINITIONS_ZERO_HPP #endif // CPU_ZERO_VM_GLOBALDEFINITIONS_ZERO_HPP
...@@ -117,8 +117,16 @@ void GraphKit::gen_stub(address C_function, ...@@ -117,8 +117,16 @@ void GraphKit::gen_stub(address C_function,
uint cnt = TypeFunc::Parms; uint cnt = TypeFunc::Parms;
// The C routines gets the base of thread-local storage passed in as an // The C routines gets the base of thread-local storage passed in as an
// extra argument. Not all calls need it, but its cheap to add here. // extra argument. Not all calls need it, but its cheap to add here.
for( ; cnt<parm_cnt; cnt++ ) for (uint pcnt = cnt; pcnt < parm_cnt; pcnt++, cnt++) {
fields[cnt] = jdomain->field_at(cnt); // Convert ints to longs if required.
if (CCallingConventionRequiresIntsAsLongs && jdomain->field_at(pcnt)->isa_int()) {
fields[cnt++] = TypeLong::LONG;
fields[cnt] = Type::HALF; // must add an additional half for a long
} else {
fields[cnt] = jdomain->field_at(pcnt);
}
}
fields[cnt++] = TypeRawPtr::BOTTOM; // Thread-local storage fields[cnt++] = TypeRawPtr::BOTTOM; // Thread-local storage
// Also pass in the caller's PC, if asked for. // Also pass in the caller's PC, if asked for.
if( return_pc ) if( return_pc )
...@@ -169,12 +177,20 @@ void GraphKit::gen_stub(address C_function, ...@@ -169,12 +177,20 @@ void GraphKit::gen_stub(address C_function,
// Set fixed predefined input arguments // Set fixed predefined input arguments
cnt = 0; cnt = 0;
for( i=0; i<TypeFunc::Parms; i++ ) for (i = 0; i < TypeFunc::Parms; i++)
call->init_req( cnt++, map()->in(i) ); call->init_req(cnt++, map()->in(i));
// A little too aggressive on the parm copy; return address is not an input // A little too aggressive on the parm copy; return address is not an input
call->set_req(TypeFunc::ReturnAdr, top()); call->set_req(TypeFunc::ReturnAdr, top());
for( ; i<parm_cnt; i++ ) // Regular input arguments for (; i < parm_cnt; i++) { // Regular input arguments
call->init_req( cnt++, map()->in(i) ); // Convert ints to longs if required.
if (CCallingConventionRequiresIntsAsLongs && jdomain->field_at(i)->isa_int()) {
Node* int_as_long = _gvn.transform(new (C) ConvI2LNode(map()->in(i)));
call->init_req(cnt++, int_as_long); // long
call->init_req(cnt++, top()); // half
} else {
call->init_req(cnt++, map()->in(i));
}
}
call->init_req( cnt++, thread ); call->init_req( cnt++, thread );
if( return_pc ) // Return PC, if asked for if( return_pc ) // Return PC, if asked for
......
...@@ -2692,27 +2692,38 @@ bool PhaseIdealLoop::intrinsify_fill(IdealLoopTree* lpt) { ...@@ -2692,27 +2692,38 @@ bool PhaseIdealLoop::intrinsify_fill(IdealLoopTree* lpt) {
_igvn.register_new_node_with_optimizer(store_value); _igvn.register_new_node_with_optimizer(store_value);
} }
if (CCallingConventionRequiresIntsAsLongs &&
// See StubRoutines::select_fill_function for types. FLOAT has been converted to INT.
(t == T_FLOAT || t == T_INT || is_subword_type(t))) {
store_value = new (C) ConvI2LNode(store_value);
_igvn.register_new_node_with_optimizer(store_value);
}
Node* mem_phi = store->in(MemNode::Memory); Node* mem_phi = store->in(MemNode::Memory);
Node* result_ctrl; Node* result_ctrl;
Node* result_mem; Node* result_mem;
const TypeFunc* call_type = OptoRuntime::array_fill_Type(); const TypeFunc* call_type = OptoRuntime::array_fill_Type();
CallLeafNode *call = new (C) CallLeafNoFPNode(call_type, fill, CallLeafNode *call = new (C) CallLeafNoFPNode(call_type, fill,
fill_name, TypeAryPtr::get_array_body_type(t)); fill_name, TypeAryPtr::get_array_body_type(t));
call->init_req(TypeFunc::Parms+0, from); uint cnt = 0;
call->init_req(TypeFunc::Parms+1, store_value); call->init_req(TypeFunc::Parms + cnt++, from);
call->init_req(TypeFunc::Parms + cnt++, store_value);
if (CCallingConventionRequiresIntsAsLongs) {
call->init_req(TypeFunc::Parms + cnt++, C->top());
}
#ifdef _LP64 #ifdef _LP64
len = new (C) ConvI2LNode(len); len = new (C) ConvI2LNode(len);
_igvn.register_new_node_with_optimizer(len); _igvn.register_new_node_with_optimizer(len);
#endif #endif
call->init_req(TypeFunc::Parms+2, len); call->init_req(TypeFunc::Parms + cnt++, len);
#ifdef _LP64 #ifdef _LP64
call->init_req(TypeFunc::Parms+3, C->top()); call->init_req(TypeFunc::Parms + cnt++, C->top());
#endif #endif
call->init_req( TypeFunc::Control, head->init_control()); call->init_req(TypeFunc::Control, head->init_control());
call->init_req( TypeFunc::I_O , C->top() ) ; // does no i/o call->init_req(TypeFunc::I_O, C->top()); // Does no I/O.
call->init_req( TypeFunc::Memory , mem_phi->in(LoopNode::EntryControl) ); call->init_req(TypeFunc::Memory, mem_phi->in(LoopNode::EntryControl));
call->init_req( TypeFunc::ReturnAdr, C->start()->proj_out(TypeFunc::ReturnAdr) ); call->init_req(TypeFunc::ReturnAdr, C->start()->proj_out(TypeFunc::ReturnAdr));
call->init_req( TypeFunc::FramePtr, C->start()->proj_out(TypeFunc::FramePtr) ); call->init_req(TypeFunc::FramePtr, C->start()->proj_out(TypeFunc::FramePtr));
_igvn.register_new_node_with_optimizer(call); _igvn.register_new_node_with_optimizer(call);
result_ctrl = new (C) ProjNode(call,TypeFunc::Control); result_ctrl = new (C) ProjNode(call,TypeFunc::Control);
_igvn.register_new_node_with_optimizer(result_ctrl); _igvn.register_new_node_with_optimizer(result_ctrl);
......
...@@ -795,11 +795,20 @@ const TypeFunc* OptoRuntime::generic_arraycopy_Type() { ...@@ -795,11 +795,20 @@ const TypeFunc* OptoRuntime::generic_arraycopy_Type() {
const TypeFunc* OptoRuntime::array_fill_Type() { const TypeFunc* OptoRuntime::array_fill_Type() {
// create input type (domain): pointer, int, size_t const Type** fields;
const Type** fields = TypeTuple::fields(3 LP64_ONLY( + 1));
int argp = TypeFunc::Parms; int argp = TypeFunc::Parms;
if (CCallingConventionRequiresIntsAsLongs) {
// create input type (domain): pointer, int, size_t
fields = TypeTuple::fields(3 LP64_ONLY( + 2));
fields[argp++] = TypePtr::NOTNULL;
fields[argp++] = TypeLong::LONG;
fields[argp++] = Type::HALF;
} else {
// create input type (domain): pointer, int, size_t
fields = TypeTuple::fields(3 LP64_ONLY( + 1));
fields[argp++] = TypePtr::NOTNULL; fields[argp++] = TypePtr::NOTNULL;
fields[argp++] = TypeInt::INT; fields[argp++] = TypeInt::INT;
}
fields[argp++] = TypeX_X; // size in whatevers (size_t) fields[argp++] = TypeX_X; // size in whatevers (size_t)
LP64_ONLY(fields[argp++] = Type::HALF); // other half of long length LP64_ONLY(fields[argp++] = Type::HALF); // other half of long length
const TypeTuple *domain = TypeTuple::make(argp, fields); const TypeTuple *domain = TypeTuple::make(argp, fields);
......
...@@ -2714,6 +2714,71 @@ void SharedRuntime::get_utf(oopDesc* src, address dst) { ...@@ -2714,6 +2714,71 @@ void SharedRuntime::get_utf(oopDesc* src, address dst) {
} }
#endif // ndef HAVE_DTRACE_H #endif // ndef HAVE_DTRACE_H
int SharedRuntime::convert_ints_to_longints_argcnt(int in_args_count, BasicType* in_sig_bt) {
int argcnt = in_args_count;
if (CCallingConventionRequiresIntsAsLongs) {
for (int in = 0; in < in_args_count; in++) {
BasicType bt = in_sig_bt[in];
switch (bt) {
case T_BOOLEAN:
case T_CHAR:
case T_BYTE:
case T_SHORT:
case T_INT:
argcnt++;
break;
default:
break;
}
}
} else {
assert(0, "This should not be needed on this platform");
}
return argcnt;
}
void SharedRuntime::convert_ints_to_longints(int i2l_argcnt, int& in_args_count,
BasicType*& in_sig_bt, VMRegPair*& in_regs) {
if (CCallingConventionRequiresIntsAsLongs) {
VMRegPair *new_in_regs = NEW_RESOURCE_ARRAY(VMRegPair, i2l_argcnt);
BasicType *new_in_sig_bt = NEW_RESOURCE_ARRAY(BasicType, i2l_argcnt);
int argcnt = 0;
for (int in = 0; in < in_args_count; in++, argcnt++) {
BasicType bt = in_sig_bt[in];
VMRegPair reg = in_regs[in];
switch (bt) {
case T_BOOLEAN:
case T_CHAR:
case T_BYTE:
case T_SHORT:
case T_INT:
// Convert (bt) to (T_LONG,bt).
new_in_sig_bt[argcnt ] = T_LONG;
new_in_sig_bt[argcnt+1] = bt;
assert(reg.first()->is_valid() && !reg.second()->is_valid(), "");
new_in_regs[argcnt ].set2(reg.first());
new_in_regs[argcnt+1].set_bad();
argcnt++;
break;
default:
// No conversion needed.
new_in_sig_bt[argcnt] = bt;
new_in_regs[argcnt] = reg;
break;
}
}
assert(argcnt == i2l_argcnt, "must match");
in_regs = new_in_regs;
in_sig_bt = new_in_sig_bt;
in_args_count = i2l_argcnt;
} else {
assert(0, "This should not be needed on this platform");
}
}
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Java-Java calling convention // Java-Java calling convention
// (what you use when Java calls Java) // (what you use when Java calls Java)
......
...@@ -366,6 +366,16 @@ class SharedRuntime: AllStatic { ...@@ -366,6 +366,16 @@ class SharedRuntime: AllStatic {
static int c_calling_convention(const BasicType *sig_bt, VMRegPair *regs, VMRegPair *regs2, static int c_calling_convention(const BasicType *sig_bt, VMRegPair *regs, VMRegPair *regs2,
int total_args_passed); int total_args_passed);
// Compute the new number of arguments in the signature if 32 bit ints
// must be converted to longs. Needed if CCallingConventionRequiresIntsAsLongs
// is true.
static int convert_ints_to_longints_argcnt(int in_args_count, BasicType* in_sig_bt);
// Adapt a method's signature if it contains 32 bit integers that must
// be converted to longs. Needed if CCallingConventionRequiresIntsAsLongs
// is true.
static void convert_ints_to_longints(int i2l_argcnt, int& in_args_count,
BasicType*& in_sig_bt, VMRegPair*& in_regs);
// Generate I2C and C2I adapters. These adapters are simple argument marshalling // Generate I2C and C2I adapters. These adapters are simple argument marshalling
// blobs. Unlike adapters in the tiger and earlier releases the code in these // blobs. Unlike adapters in the tiger and earlier releases the code in these
// blobs does not create a new frame and are therefore virtually invisible // blobs does not create a new frame and are therefore virtually invisible
...@@ -378,7 +388,7 @@ class SharedRuntime: AllStatic { ...@@ -378,7 +388,7 @@ class SharedRuntime: AllStatic {
// location for the interpreter to record. This is used by the frame code // location for the interpreter to record. This is used by the frame code
// to correct the sender code to match up with the stack pointer when the // to correct the sender code to match up with the stack pointer when the
// thread left the compiled code. In addition it allows the interpreter // thread left the compiled code. In addition it allows the interpreter
// to remove the space the c2i adapter allocated to do it argument conversion. // to remove the space the c2i adapter allocated to do its argument conversion.
// Although a c2i blob will always run interpreted even if compiled code is // Although a c2i blob will always run interpreted even if compiled code is
// present if we see that compiled code is present the compiled call site // present if we see that compiled code is present the compiled call site
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册