United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6994093 MethodHandle.invokeGeneric needs porting to SPARC
JDK-6994093 : MethodHandle.invokeGeneric needs porting to SPARC

Details
Type:
Bug
Submit Date:
2010-10-22
Status:
Closed
Updated Date:
2011-04-23
Project Name:
JDK
Resolved Date:
2011-04-23
Component:
hotspot
OS:
generic
Sub-Component:
compiler
CPU:
generic
Priority:
P3
Resolution:
Fixed
Affected Versions:
7
Fixed Versions:
hs20 (b03)

Related Reports
Backport:
Backport:
Relates:
Relates:

Sub Tasks

Description
The implementation of invokeGeneric (added in 6939224) needs assembly code for SPARC.

                                    

Comments
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;
 }
                                     
2010-10-22
SUGGESTED FIX

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

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

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



Hardware and Software, Engineered to Work Together