Wed, 18 Sep 2013 14:34:56 -0700
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
1.1 --- a/src/cpu/ppc/vm/globalDefinitions_ppc.hpp Fri Sep 13 22:50:47 2013 +0200 1.2 +++ b/src/cpu/ppc/vm/globalDefinitions_ppc.hpp Wed Sep 18 14:34:56 2013 -0700 1.3 @@ -29,6 +29,12 @@ 1.4 // Size of PPC Instructions 1.5 const int BytesPerInstWord = 4; 1.6 1.7 -const int StackAlignmentInBytes = 16; 1.8 +const int StackAlignmentInBytes = 16; 1.9 + 1.10 +// Indicates whether the C calling conventions require that 1.11 +// 32-bit integer argument values are properly extended to 64 bits. 1.12 +// If set, SharedRuntime::c_calling_convention() must adapt 1.13 +// signatures accordingly. 1.14 +const bool CCallingConventionRequiresIntsAsLongs = true; 1.15 1.16 #endif // CPU_PPC_VM_GLOBALDEFINITIONS_PPC_HPP
2.1 --- a/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Fri Sep 13 22:50:47 2013 +0200 2.2 +++ b/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Wed Sep 18 14:34:56 2013 -0700 2.3 @@ -734,11 +734,8 @@ 2.4 // We must cast ints to longs and use full 64 bit stack slots 2.5 // here. We do the cast in GraphKit::gen_stub() and just guard 2.6 // here against loosing that change. 2.7 - Unimplemented(); // TODO: PPC port 2.8 - /* 2.9 - assert(SharedRuntime::c_calling_convention_requires_ints_as_longs(), 2.10 + assert(CCallingConventionRequiresIntsAsLongs, 2.11 "argument of type int should be promoted to type long"); 2.12 - */ 2.13 guarantee(i > 0 && sig_bt[i-1] == T_LONG, 2.14 "argument of type (bt) should have been promoted to type (T_LONG,bt) for bt in " 2.15 "{T_BOOLEAN, T_CHAR, T_BYTE, T_SHORT, T_INT}"); 2.16 @@ -856,7 +853,6 @@ 2.17 const int adapter_size = frame::top_ijava_frame_abi_size + 2.18 round_to(total_args_passed * wordSize, frame::alignment_in_bytes); 2.19 2.20 - 2.21 // regular (verified) c2i entry point 2.22 c2i_entrypoint = __ pc(); 2.23
3.1 --- a/src/cpu/sparc/vm/globalDefinitions_sparc.hpp Fri Sep 13 22:50:47 2013 +0200 3.2 +++ b/src/cpu/sparc/vm/globalDefinitions_sparc.hpp Wed Sep 18 14:34:56 2013 -0700 3.3 @@ -30,6 +30,12 @@ 3.4 3.5 const int StackAlignmentInBytes = (2*wordSize); 3.6 3.7 +// Indicates whether the C calling conventions require that 3.8 +// 32-bit integer argument values are properly extended to 64 bits. 3.9 +// If set, SharedRuntime::c_calling_convention() must adapt 3.10 +// signatures accordingly. 3.11 +const bool CCallingConventionRequiresIntsAsLongs = false; 3.12 + 3.13 #define SUPPORTS_NATIVE_CX8 3.14 3.15 #endif // CPU_SPARC_VM_GLOBALDEFINITIONS_SPARC_HPP
4.1 --- a/src/cpu/x86/vm/globalDefinitions_x86.hpp Fri Sep 13 22:50:47 2013 +0200 4.2 +++ b/src/cpu/x86/vm/globalDefinitions_x86.hpp Wed Sep 18 14:34:56 2013 -0700 4.3 @@ -27,6 +27,12 @@ 4.4 4.5 const int StackAlignmentInBytes = 16; 4.6 4.7 +// Indicates whether the C calling conventions require that 4.8 +// 32-bit integer argument values are properly extended to 64 bits. 4.9 +// If set, SharedRuntime::c_calling_convention() must adapt 4.10 +// signatures accordingly. 4.11 +const bool CCallingConventionRequiresIntsAsLongs = false; 4.12 + 4.13 #define SUPPORTS_NATIVE_CX8 4.14 4.15 #endif // CPU_X86_VM_GLOBALDEFINITIONS_X86_HPP
5.1 --- a/src/cpu/zero/vm/globalDefinitions_zero.hpp Fri Sep 13 22:50:47 2013 +0200 5.2 +++ b/src/cpu/zero/vm/globalDefinitions_zero.hpp Wed Sep 18 14:34:56 2013 -0700 5.3 @@ -28,4 +28,10 @@ 5.4 5.5 #include <ffi.h> 5.6 5.7 +// Indicates whether the C calling conventions require that 5.8 +// 32-bit integer argument values are properly extended to 64 bits. 5.9 +// If set, SharedRuntime::c_calling_convention() must adapt 5.10 +// signatures accordingly. 5.11 +const bool CCallingConventionRequiresIntsAsLongs = false; 5.12 + 5.13 #endif // CPU_ZERO_VM_GLOBALDEFINITIONS_ZERO_HPP
6.1 --- a/src/share/vm/opto/generateOptoStub.cpp Fri Sep 13 22:50:47 2013 +0200 6.2 +++ b/src/share/vm/opto/generateOptoStub.cpp Wed Sep 18 14:34:56 2013 -0700 6.3 @@ -117,8 +117,16 @@ 6.4 uint cnt = TypeFunc::Parms; 6.5 // The C routines gets the base of thread-local storage passed in as an 6.6 // extra argument. Not all calls need it, but its cheap to add here. 6.7 - for( ; cnt<parm_cnt; cnt++ ) 6.8 - fields[cnt] = jdomain->field_at(cnt); 6.9 + for (uint pcnt = cnt; pcnt < parm_cnt; pcnt++, cnt++) { 6.10 + // Convert ints to longs if required. 6.11 + if (CCallingConventionRequiresIntsAsLongs && jdomain->field_at(pcnt)->isa_int()) { 6.12 + fields[cnt++] = TypeLong::LONG; 6.13 + fields[cnt] = Type::HALF; // must add an additional half for a long 6.14 + } else { 6.15 + fields[cnt] = jdomain->field_at(pcnt); 6.16 + } 6.17 + } 6.18 + 6.19 fields[cnt++] = TypeRawPtr::BOTTOM; // Thread-local storage 6.20 // Also pass in the caller's PC, if asked for. 6.21 if( return_pc ) 6.22 @@ -169,12 +177,20 @@ 6.23 6.24 // Set fixed predefined input arguments 6.25 cnt = 0; 6.26 - for( i=0; i<TypeFunc::Parms; i++ ) 6.27 - call->init_req( cnt++, map()->in(i) ); 6.28 + for (i = 0; i < TypeFunc::Parms; i++) 6.29 + call->init_req(cnt++, map()->in(i)); 6.30 // A little too aggressive on the parm copy; return address is not an input 6.31 call->set_req(TypeFunc::ReturnAdr, top()); 6.32 - for( ; i<parm_cnt; i++ ) // Regular input arguments 6.33 - call->init_req( cnt++, map()->in(i) ); 6.34 + for (; i < parm_cnt; i++) { // Regular input arguments 6.35 + // Convert ints to longs if required. 6.36 + if (CCallingConventionRequiresIntsAsLongs && jdomain->field_at(i)->isa_int()) { 6.37 + Node* int_as_long = _gvn.transform(new (C) ConvI2LNode(map()->in(i))); 6.38 + call->init_req(cnt++, int_as_long); // long 6.39 + call->init_req(cnt++, top()); // half 6.40 + } else { 6.41 + call->init_req(cnt++, map()->in(i)); 6.42 + } 6.43 + } 6.44 6.45 call->init_req( cnt++, thread ); 6.46 if( return_pc ) // Return PC, if asked for
7.1 --- a/src/share/vm/opto/loopTransform.cpp Fri Sep 13 22:50:47 2013 +0200 7.2 +++ b/src/share/vm/opto/loopTransform.cpp Wed Sep 18 14:34:56 2013 -0700 7.3 @@ -2692,27 +2692,38 @@ 7.4 _igvn.register_new_node_with_optimizer(store_value); 7.5 } 7.6 7.7 + if (CCallingConventionRequiresIntsAsLongs && 7.8 + // See StubRoutines::select_fill_function for types. FLOAT has been converted to INT. 7.9 + (t == T_FLOAT || t == T_INT || is_subword_type(t))) { 7.10 + store_value = new (C) ConvI2LNode(store_value); 7.11 + _igvn.register_new_node_with_optimizer(store_value); 7.12 + } 7.13 + 7.14 Node* mem_phi = store->in(MemNode::Memory); 7.15 Node* result_ctrl; 7.16 Node* result_mem; 7.17 const TypeFunc* call_type = OptoRuntime::array_fill_Type(); 7.18 CallLeafNode *call = new (C) CallLeafNoFPNode(call_type, fill, 7.19 fill_name, TypeAryPtr::get_array_body_type(t)); 7.20 - call->init_req(TypeFunc::Parms+0, from); 7.21 - call->init_req(TypeFunc::Parms+1, store_value); 7.22 + uint cnt = 0; 7.23 + call->init_req(TypeFunc::Parms + cnt++, from); 7.24 + call->init_req(TypeFunc::Parms + cnt++, store_value); 7.25 + if (CCallingConventionRequiresIntsAsLongs) { 7.26 + call->init_req(TypeFunc::Parms + cnt++, C->top()); 7.27 + } 7.28 #ifdef _LP64 7.29 len = new (C) ConvI2LNode(len); 7.30 _igvn.register_new_node_with_optimizer(len); 7.31 #endif 7.32 - call->init_req(TypeFunc::Parms+2, len); 7.33 + call->init_req(TypeFunc::Parms + cnt++, len); 7.34 #ifdef _LP64 7.35 - call->init_req(TypeFunc::Parms+3, C->top()); 7.36 + call->init_req(TypeFunc::Parms + cnt++, C->top()); 7.37 #endif 7.38 - call->init_req( TypeFunc::Control, head->init_control()); 7.39 - call->init_req( TypeFunc::I_O , C->top() ) ; // does no i/o 7.40 - call->init_req( TypeFunc::Memory , mem_phi->in(LoopNode::EntryControl) ); 7.41 - call->init_req( TypeFunc::ReturnAdr, C->start()->proj_out(TypeFunc::ReturnAdr) ); 7.42 - call->init_req( TypeFunc::FramePtr, C->start()->proj_out(TypeFunc::FramePtr) ); 7.43 + call->init_req(TypeFunc::Control, head->init_control()); 7.44 + call->init_req(TypeFunc::I_O, C->top()); // Does no I/O. 7.45 + call->init_req(TypeFunc::Memory, mem_phi->in(LoopNode::EntryControl)); 7.46 + call->init_req(TypeFunc::ReturnAdr, C->start()->proj_out(TypeFunc::ReturnAdr)); 7.47 + call->init_req(TypeFunc::FramePtr, C->start()->proj_out(TypeFunc::FramePtr)); 7.48 _igvn.register_new_node_with_optimizer(call); 7.49 result_ctrl = new (C) ProjNode(call,TypeFunc::Control); 7.50 _igvn.register_new_node_with_optimizer(result_ctrl);
8.1 --- a/src/share/vm/opto/runtime.cpp Fri Sep 13 22:50:47 2013 +0200 8.2 +++ b/src/share/vm/opto/runtime.cpp Wed Sep 18 14:34:56 2013 -0700 8.3 @@ -795,11 +795,20 @@ 8.4 8.5 8.6 const TypeFunc* OptoRuntime::array_fill_Type() { 8.7 + const Type** fields; 8.8 + int argp = TypeFunc::Parms; 8.9 + if (CCallingConventionRequiresIntsAsLongs) { 8.10 // create input type (domain): pointer, int, size_t 8.11 - const Type** fields = TypeTuple::fields(3 LP64_ONLY( + 1)); 8.12 - int argp = TypeFunc::Parms; 8.13 - fields[argp++] = TypePtr::NOTNULL; 8.14 - fields[argp++] = TypeInt::INT; 8.15 + fields = TypeTuple::fields(3 LP64_ONLY( + 2)); 8.16 + fields[argp++] = TypePtr::NOTNULL; 8.17 + fields[argp++] = TypeLong::LONG; 8.18 + fields[argp++] = Type::HALF; 8.19 + } else { 8.20 + // create input type (domain): pointer, int, size_t 8.21 + fields = TypeTuple::fields(3 LP64_ONLY( + 1)); 8.22 + fields[argp++] = TypePtr::NOTNULL; 8.23 + fields[argp++] = TypeInt::INT; 8.24 + } 8.25 fields[argp++] = TypeX_X; // size in whatevers (size_t) 8.26 LP64_ONLY(fields[argp++] = Type::HALF); // other half of long length 8.27 const TypeTuple *domain = TypeTuple::make(argp, fields);
9.1 --- a/src/share/vm/runtime/sharedRuntime.cpp Fri Sep 13 22:50:47 2013 +0200 9.2 +++ b/src/share/vm/runtime/sharedRuntime.cpp Wed Sep 18 14:34:56 2013 -0700 9.3 @@ -2714,6 +2714,71 @@ 9.4 } 9.5 #endif // ndef HAVE_DTRACE_H 9.6 9.7 +int SharedRuntime::convert_ints_to_longints_argcnt(int in_args_count, BasicType* in_sig_bt) { 9.8 + int argcnt = in_args_count; 9.9 + if (CCallingConventionRequiresIntsAsLongs) { 9.10 + for (int in = 0; in < in_args_count; in++) { 9.11 + BasicType bt = in_sig_bt[in]; 9.12 + switch (bt) { 9.13 + case T_BOOLEAN: 9.14 + case T_CHAR: 9.15 + case T_BYTE: 9.16 + case T_SHORT: 9.17 + case T_INT: 9.18 + argcnt++; 9.19 + break; 9.20 + default: 9.21 + break; 9.22 + } 9.23 + } 9.24 + } else { 9.25 + assert(0, "This should not be needed on this platform"); 9.26 + } 9.27 + 9.28 + return argcnt; 9.29 +} 9.30 + 9.31 +void SharedRuntime::convert_ints_to_longints(int i2l_argcnt, int& in_args_count, 9.32 + BasicType*& in_sig_bt, VMRegPair*& in_regs) { 9.33 + if (CCallingConventionRequiresIntsAsLongs) { 9.34 + VMRegPair *new_in_regs = NEW_RESOURCE_ARRAY(VMRegPair, i2l_argcnt); 9.35 + BasicType *new_in_sig_bt = NEW_RESOURCE_ARRAY(BasicType, i2l_argcnt); 9.36 + 9.37 + int argcnt = 0; 9.38 + for (int in = 0; in < in_args_count; in++, argcnt++) { 9.39 + BasicType bt = in_sig_bt[in]; 9.40 + VMRegPair reg = in_regs[in]; 9.41 + switch (bt) { 9.42 + case T_BOOLEAN: 9.43 + case T_CHAR: 9.44 + case T_BYTE: 9.45 + case T_SHORT: 9.46 + case T_INT: 9.47 + // Convert (bt) to (T_LONG,bt). 9.48 + new_in_sig_bt[argcnt ] = T_LONG; 9.49 + new_in_sig_bt[argcnt+1] = bt; 9.50 + assert(reg.first()->is_valid() && !reg.second()->is_valid(), ""); 9.51 + new_in_regs[argcnt ].set2(reg.first()); 9.52 + new_in_regs[argcnt+1].set_bad(); 9.53 + argcnt++; 9.54 + break; 9.55 + default: 9.56 + // No conversion needed. 9.57 + new_in_sig_bt[argcnt] = bt; 9.58 + new_in_regs[argcnt] = reg; 9.59 + break; 9.60 + } 9.61 + } 9.62 + assert(argcnt == i2l_argcnt, "must match"); 9.63 + 9.64 + in_regs = new_in_regs; 9.65 + in_sig_bt = new_in_sig_bt; 9.66 + in_args_count = i2l_argcnt; 9.67 + } else { 9.68 + assert(0, "This should not be needed on this platform"); 9.69 + } 9.70 +} 9.71 + 9.72 // ------------------------------------------------------------------------- 9.73 // Java-Java calling convention 9.74 // (what you use when Java calls Java)
10.1 --- a/src/share/vm/runtime/sharedRuntime.hpp Fri Sep 13 22:50:47 2013 +0200 10.2 +++ b/src/share/vm/runtime/sharedRuntime.hpp Wed Sep 18 14:34:56 2013 -0700 10.3 @@ -366,6 +366,16 @@ 10.4 static int c_calling_convention(const BasicType *sig_bt, VMRegPair *regs, VMRegPair *regs2, 10.5 int total_args_passed); 10.6 10.7 + // Compute the new number of arguments in the signature if 32 bit ints 10.8 + // must be converted to longs. Needed if CCallingConventionRequiresIntsAsLongs 10.9 + // is true. 10.10 + static int convert_ints_to_longints_argcnt(int in_args_count, BasicType* in_sig_bt); 10.11 + // Adapt a method's signature if it contains 32 bit integers that must 10.12 + // be converted to longs. Needed if CCallingConventionRequiresIntsAsLongs 10.13 + // is true. 10.14 + static void convert_ints_to_longints(int i2l_argcnt, int& in_args_count, 10.15 + BasicType*& in_sig_bt, VMRegPair*& in_regs); 10.16 + 10.17 // Generate I2C and C2I adapters. These adapters are simple argument marshalling 10.18 // blobs. Unlike adapters in the tiger and earlier releases the code in these 10.19 // blobs does not create a new frame and are therefore virtually invisible 10.20 @@ -378,7 +388,7 @@ 10.21 // location for the interpreter to record. This is used by the frame code 10.22 // to correct the sender code to match up with the stack pointer when the 10.23 // thread left the compiled code. In addition it allows the interpreter 10.24 - // to remove the space the c2i adapter allocated to do it argument conversion. 10.25 + // to remove the space the c2i adapter allocated to do its argument conversion. 10.26 10.27 // Although a c2i blob will always run interpreted even if compiled code is 10.28 // present if we see that compiled code is present the compiled call site