# HG changeset patch # User goetz # Date 1435584655 -7200 # Node ID 427d073af86743d543a064a3462bd7e9931059e1 # Parent e0d5c4d484645eda38a9f83b1293e8a63f3f1aa3 8086069: Adapt runtime calls to recent intrinsics to pass ints as long Summary: Remove CCallingConventionRequiresIntsAsLongs from shared code and push functionality to native wrapper. Less optimal but more flexible. Reviewed-by: jrose, kvn diff -r e0d5c4d48464 -r 427d073af867 hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp --- a/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp Fri Jul 03 16:29:37 2015 +0200 +++ b/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp Mon Jun 29 15:30:55 2015 +0200 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,12 +28,6 @@ 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; - #define SUPPORTS_NATIVE_CX8 // The maximum B/BL offset range on AArch64 is 128MB. diff -r e0d5c4d48464 -r 427d073af867 hotspot/src/cpu/ppc/vm/globalDefinitions_ppc.hpp --- a/hotspot/src/cpu/ppc/vm/globalDefinitions_ppc.hpp Fri Jul 03 16:29:37 2015 +0200 +++ b/hotspot/src/cpu/ppc/vm/globalDefinitions_ppc.hpp Mon Jun 29 15:30:55 2015 +0200 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,12 +31,6 @@ 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; - #define SUPPORTS_NATIVE_CX8 // The PPC CPUs are NOT multiple-copy-atomic. diff -r e0d5c4d48464 -r 427d073af867 hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Fri Jul 03 16:29:37 2015 +0200 +++ b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Mon Jun 29 15:30:55 2015 +0200 @@ -731,23 +731,8 @@ case T_SHORT: case T_INT: // 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 against loosing that change. - assert(CCallingConventionRequiresIntsAsLongs, - "argument of type int should be promoted to type 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 " - "{T_BOOLEAN, T_CHAR, T_BYTE, T_SHORT, T_INT}"); - // Do not count halves. - regs[i].set_bad(); - --arg; - break; + // here. Thus fall through, handle as long. case T_LONG: - guarantee(sig_bt[i+1] == T_VOID || - sig_bt[i+1] == T_BOOLEAN || sig_bt[i+1] == T_CHAR || - sig_bt[i+1] == T_BYTE || sig_bt[i+1] == T_SHORT || - sig_bt[i+1] == T_INT, - "expecting type (T_LONG,half) or type (T_LONG,bt) with bt in {T_BOOLEAN, T_CHAR, T_BYTE, T_SHORT, T_INT}"); case T_OBJECT: case T_ARRAY: case T_ADDRESS: @@ -1273,7 +1258,7 @@ static void int_move(MacroAssembler*masm, VMRegPair src, VMRegPair dst, Register r_caller_sp, Register r_temp) { - assert(src.first()->is_valid() && src.second() == src.first()->next(), "incoming must be long-int"); + assert(src.first()->is_valid(), "incoming must be int"); assert(dst.first()->is_valid() && dst.second() == dst.first()->next(), "outgoing must be long"); if (src.first()->is_stack()) { @@ -1762,13 +1747,6 @@ // the jni function will expect them. To figure out where they go // we convert the java signature to a C signature by inserting // the hidden arguments as arg[0] and possibly arg[1] (static method) - // - // Additionally, on ppc64 we must convert integers to longs in the C - // signature. We do this in advance in order to have no trouble with - // indexes into the bt-arrays. - // So convert the signature and registers now, and adjust the total number - // of in-arguments accordingly. - int i2l_argcnt = convert_ints_to_longints_argcnt(total_in_args, in_sig_bt); // PPC64: pass ints as longs. // Calculate the total number of C arguments and create arrays for the // signature and the outgoing registers. @@ -1776,7 +1754,7 @@ // some floating-point arguments must be passed in registers _and_ // in stack locations. bool method_is_static = method->is_static(); - int total_c_args = i2l_argcnt; + int total_c_args = total_in_args; if (!is_critical_native) { int n_hidden_args = method_is_static ? 2 : 1; @@ -1785,7 +1763,7 @@ // No JNIEnv*, no this*, but unpacked arrays (base+length). for (int i = 0; i < total_in_args; i++) { if (in_sig_bt[i] == T_ARRAY) { - total_c_args += 2; // PPC64: T_LONG, T_INT, T_ADDRESS (see convert_ints_to_longints and c_calling_convention) + total_c_args++; } } } @@ -1803,8 +1781,6 @@ int argc = 0; if (!is_critical_native) { - convert_ints_to_longints(i2l_argcnt, total_in_args, in_sig_bt, in_regs); // PPC64: pass ints as longs. - out_sig_bt[argc++] = T_ADDRESS; if (method->is_static()) { out_sig_bt[argc++] = T_OBJECT; @@ -1815,7 +1791,7 @@ } } else { Thread* THREAD = Thread::current(); - in_elem_bt = NEW_RESOURCE_ARRAY(BasicType, i2l_argcnt); + in_elem_bt = NEW_RESOURCE_ARRAY(BasicType, total_c_args); SignatureStream ss(method->signature()); int o = 0; for (int i = 0; i < total_in_args ; i++, o++) { @@ -1839,28 +1815,16 @@ } } else { in_elem_bt[o] = T_VOID; - switch(in_sig_bt[i]) { // PPC64: pass ints as longs. - case T_BOOLEAN: - case T_CHAR: - case T_BYTE: - case T_SHORT: - case T_INT: in_elem_bt[++o] = T_VOID; break; - default: break; - } } if (in_sig_bt[i] != T_VOID) { assert(in_sig_bt[i] == ss.type(), "must match"); ss.next(); } } - assert(i2l_argcnt==o, "must match"); - - convert_ints_to_longints(i2l_argcnt, total_in_args, in_sig_bt, in_regs); // PPC64: pass ints as longs. for (int i = 0; i < total_in_args ; i++ ) { if (in_sig_bt[i] == T_ARRAY) { // Arrays are passed as int, elem* pair. - out_sig_bt[argc++] = T_LONG; // PPC64: pass ints as longs. out_sig_bt[argc++] = T_INT; out_sig_bt[argc++] = T_ADDRESS; } else { @@ -1921,7 +1885,8 @@ case T_BYTE: case T_SHORT: case T_CHAR: - case T_INT: /*single_slots++;*/ break; // PPC64: pass ints as longs. + case T_INT: + // Fall through. case T_ARRAY: case T_LONG: double_slots++; break; default: ShouldNotReachHere(); @@ -2019,7 +1984,7 @@ __ save_LR_CR(r_temp_1); __ generate_stack_overflow_check(frame_size_in_bytes); // Check before creating frame. - __ mr(r_callers_sp, R1_SP); // Remember frame pointer. + __ mr(r_callers_sp, R1_SP); // Remember frame pointer. __ push_frame(frame_size_in_bytes, r_temp_1); // Push the c2n adapter's frame. frame_done_pc = (intptr_t)__ pc(); @@ -2098,24 +2063,16 @@ case T_BYTE: case T_SHORT: case T_INT: - guarantee(in > 0 && in_sig_bt[in-1] == T_LONG, - "expecting type (T_LONG,bt) for bt in {T_BOOLEAN, T_CHAR, T_BYTE, T_SHORT, T_INT}"); + // Move int and do sign extension. + int_move(masm, in_regs[in], out_regs[out], r_callers_sp, r_temp_1); break; case T_LONG: - if (in_sig_bt[in+1] == T_VOID) { - long_move(masm, in_regs[in], out_regs[out], r_callers_sp, r_temp_1); - } else { - guarantee(in_sig_bt[in+1] == T_BOOLEAN || in_sig_bt[in+1] == T_CHAR || - in_sig_bt[in+1] == T_BYTE || in_sig_bt[in+1] == T_SHORT || - in_sig_bt[in+1] == T_INT, - "expecting type (T_LONG,bt) for bt in {T_BOOLEAN, T_CHAR, T_BYTE, T_SHORT, T_INT}"); - int_move(masm, in_regs[in], out_regs[out], r_callers_sp, r_temp_1); - } + long_move(masm, in_regs[in], out_regs[out], r_callers_sp, r_temp_1); break; case T_ARRAY: if (is_critical_native) { int body_arg = out; - out -= 2; // Point to length arg. PPC64: pass ints as longs. + out -= 1; // Point to length arg. unpack_array_argument(masm, in_regs[in], in_elem_bt[in], out_regs[body_arg], out_regs[out], r_callers_sp, r_temp_1, r_temp_2); break; @@ -2187,7 +2144,6 @@ // Make sure that thread is non-volatile; it crosses a bunch of VM calls below. assert(R16_thread->is_nonvolatile(), "thread must be in non-volatile register"); - # if 0 // DTrace method entry # endif diff -r e0d5c4d48464 -r 427d073af867 hotspot/src/cpu/sparc/vm/globalDefinitions_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/globalDefinitions_sparc.hpp Fri Jul 03 16:29:37 2015 +0200 +++ b/hotspot/src/cpu/sparc/vm/globalDefinitions_sparc.hpp Mon Jun 29 15:30:55 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,12 +30,6 @@ 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 // The expected size in bytes of a cache line, used to pad data structures. diff -r e0d5c4d48464 -r 427d073af867 hotspot/src/cpu/x86/vm/globalDefinitions_x86.hpp --- a/hotspot/src/cpu/x86/vm/globalDefinitions_x86.hpp Fri Jul 03 16:29:37 2015 +0200 +++ b/hotspot/src/cpu/x86/vm/globalDefinitions_x86.hpp Mon Jun 29 15:30:55 2015 +0200 @@ -27,12 +27,6 @@ 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 // The expected size in bytes of a cache line, used to pad data structures. diff -r e0d5c4d48464 -r 427d073af867 hotspot/src/cpu/zero/vm/globalDefinitions_zero.hpp --- a/hotspot/src/cpu/zero/vm/globalDefinitions_zero.hpp Fri Jul 03 16:29:37 2015 +0200 +++ b/hotspot/src/cpu/zero/vm/globalDefinitions_zero.hpp Mon Jun 29 15:30:55 2015 +0200 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009 Red Hat, Inc. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2009, 2015, Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,10 +28,4 @@ #include -// 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 diff -r e0d5c4d48464 -r 427d073af867 hotspot/src/share/vm/opto/generateOptoStub.cpp --- a/hotspot/src/share/vm/opto/generateOptoStub.cpp Fri Jul 03 16:29:37 2015 +0200 +++ b/hotspot/src/share/vm/opto/generateOptoStub.cpp Mon Jun 29 15:30:55 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -118,19 +118,14 @@ // 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. for (uint pcnt = cnt; pcnt < parm_cnt; pcnt++, 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] = jdomain->field_at(pcnt); } fields[cnt++] = TypeRawPtr::BOTTOM; // Thread-local storage // Also pass in the caller's PC, if asked for. - if( return_pc ) + if (return_pc) { fields[cnt++] = TypeRawPtr::BOTTOM; // Return PC + } const TypeTuple* domain = TypeTuple::make(cnt,fields); // The C routine we are about to call cannot return an oop; it can block on @@ -143,21 +138,22 @@ const Type **rfields = TypeTuple::fields(jrange->cnt() - TypeFunc::Parms); // Fixup oop returns int retval_ptr = retval->isa_oop_ptr(); - if( retval_ptr ) { + if (retval_ptr) { assert( pass_tls, "Oop must be returned thru TLS" ); // Fancy-jumps return address; others return void rfields[TypeFunc::Parms] = is_fancy_jump ? TypeRawPtr::BOTTOM : Type::TOP; - } else if( retval->isa_int() ) { // Returning any integer subtype? + } else if (retval->isa_int()) { // Returning any integer subtype? // "Fatten" byte, char & short return types to 'int' to show that // the native C code can return values with junk high order bits. // We'll sign-extend it below later. rfields[TypeFunc::Parms] = TypeInt::INT; // It's "dirty" and needs sign-ext - } else if( jrange->cnt() >= TypeFunc::Parms+1 ) { // Else copy other types + } else if (jrange->cnt() >= TypeFunc::Parms+1) { // Else copy other types rfields[TypeFunc::Parms] = jrange->field_at(TypeFunc::Parms); - if( jrange->cnt() == TypeFunc::Parms+2 ) + if (jrange->cnt() == TypeFunc::Parms+2) { rfields[TypeFunc::Parms+1] = jrange->field_at(TypeFunc::Parms+1); + } } const TypeTuple* range = TypeTuple::make(jrange->cnt(),rfields); @@ -181,14 +177,7 @@ // A little too aggressive on the parm copy; return address is not an input call->set_req(TypeFunc::ReturnAdr, top()); for (; i < parm_cnt; i++) { // Regular input arguments - // Convert ints to longs if required. - if (CCallingConventionRequiresIntsAsLongs && jdomain->field_at(i)->isa_int()) { - Node* int_as_long = _gvn.transform(new 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++, map()->in(i)); } call->init_req( cnt++, thread ); diff -r e0d5c4d48464 -r 427d073af867 hotspot/src/share/vm/opto/loopTransform.cpp --- a/hotspot/src/share/vm/opto/loopTransform.cpp Fri Jul 03 16:29:37 2015 +0200 +++ b/hotspot/src/share/vm/opto/loopTransform.cpp Mon Jun 29 15:30:55 2015 +0200 @@ -2941,13 +2941,6 @@ _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 ConvI2LNode(store_value); - _igvn.register_new_node_with_optimizer(store_value); - } - Node* mem_phi = store->in(MemNode::Memory); Node* result_ctrl; Node* result_mem; @@ -2957,9 +2950,6 @@ uint cnt = 0; 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 len = new ConvI2LNode(len); _igvn.register_new_node_with_optimizer(len); diff -r e0d5c4d48464 -r 427d073af867 hotspot/src/share/vm/opto/runtime.cpp --- a/hotspot/src/share/vm/opto/runtime.cpp Fri Jul 03 16:29:37 2015 +0200 +++ b/hotspot/src/share/vm/opto/runtime.cpp Mon Jun 29 15:30:55 2015 +0200 @@ -779,18 +779,10 @@ const TypeFunc* OptoRuntime::array_fill_Type() { const Type** fields; 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++] = TypeInt::INT; - } + fields = TypeTuple::fields(3 LP64_ONLY( + 1)); + fields[argp++] = TypePtr::NOTNULL; + fields[argp++] = TypeInt::INT; fields[argp++] = TypeX_X; // size in whatevers (size_t) LP64_ONLY(fields[argp++] = Type::HALF); // other half of long length const TypeTuple *domain = TypeTuple::make(argp, fields); diff -r e0d5c4d48464 -r 427d073af867 hotspot/src/share/vm/runtime/sharedRuntime.cpp --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp Fri Jul 03 16:29:37 2015 +0200 +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp Mon Jun 29 15:30:55 2015 +0200 @@ -2616,71 +2616,6 @@ GC_locker::unlock_critical(thread); JRT_END -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 // (what you use when Java calls Java)