JDK-6994093 : MethodHandle.invokeGeneric needs porting to SPARC
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 7
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2010-10-22
  • Updated: 2011-04-23
  • Resolved: 2011-04-23
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6 JDK 7 Other
6u25Fixed 7Fixed hs20Fixed
Related Reports
Relates :  
Relates :  
Description
The implementation of invokeGeneric (added in 6939224) needs assembly code for SPARC.

Comments
EVALUATION http://hg.openjdk.java.net/jdk7/build/hotspot/rev/fff777a71346
04-12-2010

EVALUATION http://hg.openjdk.java.net/jdk7/hotspot-comp/hotspot/rev/fff777a71346 *** (#1 of 1): [ UNSAVED ] ###@###.###
10-11-2010

SUGGESTED FIX see also http://hg.openjdk.java.net/mlvm/mlvm/hotspot/file/tip/meth-ing-6994093.patch
22-10-2010

SUGGESTED FIX diff --git a/src/cpu/sparc/vm/assembler_sparc.hpp b/src/cpu/sparc/vm/assembler_sparc.hpp --- a/src/cpu/sparc/vm/assembler_sparc.hpp +++ b/src/cpu/sparc/vm/assembler_sparc.hpp @@ -1126,7 +1126,7 @@ inline void add(Register s1, int simm13a, Register d, relocInfo::relocType rtype = relocInfo::none); inline void add(Register s1, int simm13a, Register d, RelocationHolder const& rspec); inline void add(Register s1, RegisterOrConstant s2, Register d, int offset = 0); - inline void add(const Address& a, Register d, int offset = 0) { add( a.base(), a.disp() + offset, d, a.rspec(offset)); } + inline void add(const Address& a, Register d, int offset = 0); void addcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } void addcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } diff --git a/src/cpu/sparc/vm/assembler_sparc.inline.hpp b/src/cpu/sparc/vm/assembler_sparc.inline.hpp --- a/src/cpu/sparc/vm/assembler_sparc.inline.hpp +++ b/src/cpu/sparc/vm/assembler_sparc.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, 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 @@ -206,6 +206,11 @@ inline void Assembler::ldd( Register s1, RegisterOrConstant s2, Register d) { ldd( Address(s1, s2), d); } // form effective addresses this way: +inline void Assembler::add(const Address& a, Register d, int offset) { + if (a.has_index()) add(a.base(), a.index(), d); + else { add(a.base(), a.disp() + offset, d, a.rspec(offset)); offset = 0; } + if (offset != 0) add(d, offset, d); +} inline void Assembler::add(Register s1, RegisterOrConstant s2, Register d, int offset) { if (s2.is_register()) add(s1, s2.as_register(), d); else { add(s1, s2.as_constant() + offset, d); offset = 0; } diff --git a/src/cpu/sparc/vm/methodHandles_sparc.cpp b/src/cpu/sparc/vm/methodHandles_sparc.cpp --- a/src/cpu/sparc/vm/methodHandles_sparc.cpp +++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp @@ -77,10 +77,22 @@ // O0, O1: garbage temps, blown away Register O0_argslot = O0; Register O1_scratch = O1; + Register O2_scratch = O2; + Register O3_scratch = O3; + Register O4_argbase = O4; + Register O5_mtype = O5; // emit WrongMethodType path first, to enable back-branch from main path Label wrong_method_type; __ bind(wrong_method_type); + Label invoke_generic_slow_path; + assert(methodOopDesc::intrinsic_id_size_in_bytes() == sizeof(u1), "");; + __ ldub(Address(G5_method, methodOopDesc::intrinsic_id_offset_in_bytes()), O1_scratch); + __ cmp(O1_scratch, (int) vmIntrinsics::_invokeExact); + __ brx(Assembler::notEqual, false, Assembler::pt, invoke_generic_slow_path); + __ delayed()->nop(); + __ mov(O5_mtype, G5_method_type); // required by throw_WrongMethodType + // mov(G3_method_handle, G3_method_handle); // already in this register __ jump_to(AddressLiteral(Interpreter::throw_WrongMethodType_entry()), O1_scratch); __ delayed()->nop(); @@ -88,23 +100,75 @@ __ align(CodeEntryAlignment); address entry_point = __ pc(); - // fetch the MethodType from the method handle into G5_method_type + // fetch the MethodType from the method handle { Register tem = G5_method; - assert(tem == G5_method_type, "yes, it's the same register"); for (jint* pchase = methodOopDesc::method_type_offsets_chain(); (*pchase) != -1; pchase++) { - __ ld_ptr(Address(tem, *pchase), G5_method_type); + __ ld_ptr(Address(tem, *pchase), O5_mtype); + tem = O5_mtype; // in case there is another indirection } } // given the MethodType, find out where the MH argument is buried - __ load_heap_oop(Address(G5_method_type, __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, O1_scratch)), O0_argslot); - __ ldsw( Address(O0_argslot, __ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, O1_scratch)), O0_argslot); - __ ld_ptr(__ argument_address(O0_argslot), G3_method_handle); + __ load_heap_oop(Address(O5_mtype, __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, O1_scratch)), O0_argslot); + __ ldsw( Address(O0_argslot, __ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, O1_scratch)), O0_argslot); + __ add(Gargs, __ argument_offset(O0_argslot, 1), O4_argbase); + // Note: argument_address uses its input as a scratch register! + __ ld_ptr(Address(O4_argbase, -Interpreter::stackElementSize), G3_method_handle); - __ check_method_handle_type(G5_method_type, G3_method_handle, O1_scratch, wrong_method_type); + trace_method_handle(_masm, "invokeExact"); + + __ check_method_handle_type(O5_mtype, G3_method_handle, O1_scratch, wrong_method_type); __ jump_to_method_handle_entry(G3_method_handle, O1_scratch); + // for invokeGeneric (only), apply argument and result conversions on the fly + __ bind(invoke_generic_slow_path); +#ifdef ASSERT + { Label L; + __ ldub(Address(G5_method, methodOopDesc::intrinsic_id_offset_in_bytes()), O1_scratch); + __ cmp(O1_scratch, (int) vmIntrinsics::_invokeGeneric); + __ brx(Assembler::equal, false, Assembler::pt, L); + __ delayed()->nop(); + __ stop("bad methodOop::intrinsic_id"); + __ bind(L); + } +#endif //ASSERT + + // make room on the stack for another pointer: + insert_arg_slots(_masm, 2 * stack_move_unit(), _INSERT_REF_MASK, + O4_argbase, O1_scratch, O2_scratch, O3_scratch); + // load up an adapter from the calling type (Java weaves this) + Register O2_form = O2_scratch; + Register O3_adapter = O3_scratch; + __ load_heap_oop(Address(O5_mtype, __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, O1_scratch)), O2_form); + // load_heap_oop(Address(O2_form, __ delayed_value(java_dyn_MethodTypeForm::genericInvoker_offset_in_bytes, O1_scratch)), O3_adapter); + // deal with old JDK versions: + __ add( Address(O2_form, __ delayed_value(java_dyn_MethodTypeForm::genericInvoker_offset_in_bytes, O1_scratch)), O3_adapter); + __ cmp(O3_adapter, O2_form); + Label sorry_no_invoke_generic; + __ brx(Assembler::lessUnsigned, false, Assembler::pn, sorry_no_invoke_generic); + __ delayed()->nop(); + + __ load_heap_oop(Address(O3_adapter, 0), O3_adapter); + __ tst(O3_adapter); + __ brx(Assembler::zero, false, Assembler::pn, sorry_no_invoke_generic); + __ delayed()->nop(); + __ st_ptr(O3_adapter, Address(O4_argbase, 1 * Interpreter::stackElementSize)); + // As a trusted first argument, pass the type being called, so the adapter knows + // the actual types of the arguments and return values. + // (Generic invokers are shared among form-families of method-type.) + __ st_ptr(O5_mtype, Address(O4_argbase, 0 * Interpreter::stackElementSize)); + // FIXME: assert that O3_adapter is of the right method-type. + __ mov(O3_adapter, G3_method_handle); + trace_method_handle(_masm, "invokeGeneric"); + __ jump_to_method_handle_entry(G3_method_handle, O1_scratch); + + __ bind(sorry_no_invoke_generic); // no invokeGeneric implementation available! + __ mov(O5_mtype, G5_method_type); // required by throw_WrongMethodType + // mov(G3_method_handle, G3_method_handle); // already in this register + __ jump_to(AddressLiteral(Interpreter::throw_WrongMethodType_entry()), O1_scratch); + __ delayed()->nop(); + return entry_point; }
22-10-2010