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

Wed, 18 Sep 2013 14:34:56 -0700

author
goetz
date
Wed, 18 Sep 2013 14:34:56 -0700
changeset 6468
cfd05ec74089
parent 6467
f3806614494a
child 6469
7373e44fa207

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

src/cpu/ppc/vm/globalDefinitions_ppc.hpp file | annotate | diff | comparison | revisions
src/cpu/ppc/vm/sharedRuntime_ppc.cpp file | annotate | diff | comparison | revisions
src/cpu/sparc/vm/globalDefinitions_sparc.hpp file | annotate | diff | comparison | revisions
src/cpu/x86/vm/globalDefinitions_x86.hpp file | annotate | diff | comparison | revisions
src/cpu/zero/vm/globalDefinitions_zero.hpp file | annotate | diff | comparison | revisions
src/share/vm/opto/generateOptoStub.cpp file | annotate | diff | comparison | revisions
src/share/vm/opto/loopTransform.cpp file | annotate | diff | comparison | revisions
src/share/vm/opto/runtime.cpp file | annotate | diff | comparison | revisions
src/share/vm/runtime/sharedRuntime.cpp file | annotate | diff | comparison | revisions
src/share/vm/runtime/sharedRuntime.hpp file | annotate | diff | comparison | revisions
     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

mercurial