RFC: Patch to enable adapter_opt_spread jsr 292 adapter code in zero

Chris Phillips ChrisPhi at redhat.com
Mon Jun 4 05:15:42 PDT 2012


Hi
This patch provides support  for jsr 292 in zero.
It is against :
   http://icedtea.classpath.org/hg/release/icedtea7-forest-2.1/hotspot
but will eventually apply to upstream also, ( after fixing other issues to
allow testing). It enables a portion of jsr 292 logic that was not functional
in the c++ Interpreter. It passes a large portion of the internal
dynamic invoke test suite (test/java/lang/invoke) although there are still
4 failing tests and 10 "NYI" (mostly involving Ricochet frames).

It has been vetted once in a slightly altered form internally but I would
appreciate a few more eyes, would like to apply so qa testing can
continue later today.

Chris


-------------- next part --------------
# HG changeset patch
# User chrisphi
# Date 1338811077 14400
# Node ID 561eb697c5db0b4eb9953b4c120db90dc4a387a0
# Parent  d1154290751107fc148173d73bc0cdef145f2230
	Enable _adapter_opt_spread* jsr 292 code, now passes
        all but 14 tests in John Rose test suite, 10 of those are NYI.
        Should fix issues seen in arm qa testing.

diff --git a/src/cpu/zero/vm/cppInterpreter_zero.cpp b/src/cpu/zero/vm/cppInterpreter_zero.cpp
--- a/src/cpu/zero/vm/cppInterpreter_zero.cpp
+++ b/src/cpu/zero/vm/cppInterpreter_zero.cpp
@@ -36,6 +36,7 @@
 #include "oops/oop.inline.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "prims/jvmtiThreadState.hpp"
+#include "prims/methodHandles.hpp"
 #include "runtime/arguments.hpp"
 #include "runtime/deoptimization.hpp"
 #include "runtime/frame.inline.hpp"
@@ -65,6 +66,14 @@
   CALL_VM_NOCHECK_NOFIX(func)                   \
   fixup_after_potential_safepoint()
 
+
+#ifdef DEBUG
+#define CPPINT_DEBUG( Z_code_ ) Z_code_
+CPPINT_DEBUG ( static const char *FFng_Zero_Flag = "CPPINT_DEBUG_ON\n"; ) 
+#else
+#define CPPINT_DEBUG( Z_code_ )
+#endif
+
 int CppInterpreter::normal_entry(methodOop method, intptr_t UNUSED, TRAPS) {
   JavaThread *thread = (JavaThread *) THREAD;
 
@@ -699,6 +708,9 @@
     method_handle = adapter;
   }
 
+  CPPINT_DEBUG( tty->print_cr( "Process method_handle sp: 0x%x unwind_sp: 0x%x result_slots: %d.", \
+			       stack->sp(), unwind_sp, result_slots ); )
+
   // Start processing
   process_method_handle(method_handle, THREAD);
   if (HAS_PENDING_EXCEPTION)
@@ -718,6 +730,8 @@
   }
 
   // Check
+  CPPINT_DEBUG( tty->print_cr( "Exiting method_handle_entry,  sp: 0x%x unwind_sp: 0x%x result_slots: %d.", \
+			       stack->sp(), unwind_sp, result_slots ); )
   assert(stack->sp() == unwind_sp - result_slots, "should be");
 
   // No deoptimized frames on the stack
@@ -725,6 +739,7 @@
 }
 
 void CppInterpreter::process_method_handle(oop method_handle, TRAPS) {
+
   JavaThread *thread = (JavaThread *) THREAD;
   ZeroStack *stack = thread->zero_stack();
   intptr_t *vmslots = stack->sp();
@@ -739,6 +754,7 @@
     (MethodHandles::EntryKind) (((intptr_t) entry) & 0xffffffff);
 
   methodOop method = NULL;
+  CPPINT_DEBUG( tty->print_cr( "\nEntering %s 0x%x.",MethodHandles::entry_name(entry_kind), (char *)vmslots ); )
   switch (entry_kind) {
   case MethodHandles::_invokestatic_mh:
     direct_to_method = true;
@@ -1080,12 +1096,308 @@
     }
     break;
 
-  default:
-    tty->print_cr("unhandled entry_kind %s",
+  case MethodHandles::_adapter_opt_spread_0:
+  case MethodHandles::_adapter_opt_spread_1_ref:
+  case MethodHandles::_adapter_opt_spread_2_ref:
+  case MethodHandles::_adapter_opt_spread_3_ref:
+  case MethodHandles::_adapter_opt_spread_4_ref:
+  case MethodHandles::_adapter_opt_spread_5_ref:
+  case MethodHandles::_adapter_opt_spread_ref:
+  case MethodHandles::_adapter_opt_spread_byte:
+  case MethodHandles::_adapter_opt_spread_char:
+  case MethodHandles::_adapter_opt_spread_short:
+  case MethodHandles::_adapter_opt_spread_int:
+  case MethodHandles::_adapter_opt_spread_long:
+  case MethodHandles::_adapter_opt_spread_float:
+  case MethodHandles::_adapter_opt_spread_double:
+    {
+
+      // spread an array out into a group of arguments
+
+      int arg_slot =
+        java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle);
+      // Fetch the argument, which we will cast to the required array type.
+      oop arg = VMSLOTS_OBJECT(arg_slot);
+
+      BasicType elem_type      =
+        MethodHandles::ek_adapter_opt_spread_type(entry_kind);
+      int       elem_slots     = 
+        type2size[elem_type];  // 1 or 2
+      int       array_slots    = 
+        1;  // array is always a T_OBJECT
+      int       length_offset  = 
+        arrayOopDesc::length_offset_in_bytes();
+      int       elem0_offset   = 
+        arrayOopDesc::base_offset_in_bytes(elem_type);
+      int       length_constant = 
+        MethodHandles::ek_adapter_opt_spread_count(entry_kind);
+      int       array_length = 0;
+      void      *array_elem0 = NULL;       
+
+      CPPINT_DEBUG( tty->print_cr( \
+        "ENTERING _adapter_opt_spread: %s %d %d 0x%x 0x%x", \
+        type2name(elem_type), arg_slot, length_constant, (char *)arg, stack->sp() ); )
+
+      // If the spread count is -1, the length is "variable" ie controlled
+      // by the array length.
+      // See ek_adapter_opt_spread_count in methodHandles.hpp
+      // If array lenth is 0 or spread count is 0 , we will remove the argslot.
+
+      bool length_can_be_zero = (length_constant == 0);
+      if (length_constant < 0) {
+        // some adapters with variable length must handle the zero case
+        if (!OptimizeMethodHandles ||
+            elem_type != T_OBJECT)
+          length_can_be_zero = true;
+      }
+
+      if (arg == NULL) {
+        CPPINT_DEBUG( tty->print_cr( \
+          "arg NULL implies Array_length == 0, remove slot." ); )
+        // remove arg slot
+        remove_vmslots(arg_slot, 1, THREAD); // doesn't trap
+        vmslots = stack->sp(); // unused, but let the compiler figure that out
+        CPPINT_DEBUG( tty->print_cr( \
+          " >> Would LEAVE _adapter_opt_spread with NPE." ); )
+#ifdef _NOT_DEF_
+	// queue a nullpointer exception for the caller
+        stack->set_sp(calculate_unwind_sp(stack, method_handle));
+        CALL_VM_NOCHECK_NOFIX(
+          throw_exception(
+            thread,
+            vmSymbols::java_lang_NullPointerException()));
+        // NB all oops trashed!
+        assert(HAS_PENDING_EXCEPTION, "should do");
+        return;
+#endif
+      } else {    //  (arg != NULL) 
+        klassOop objKlassOop = arg->klass();
+        klassOop klassOf = java_lang_Class::as_klassOop(
+          java_lang_invoke_AdapterMethodHandle::argument(method_handle));
+
+        if (objKlassOop != klassOf &&
+            !objKlassOop->klass_part()->is_subtype_of(klassOf)) {
+          CPPINT_DEBUG( tty->print_cr( \
+            "CLASS CAST ERROR #1 in _adapter_opt_spread." ); )
+          ResourceMark rm(THREAD);
+          const char* objName = Klass::cast(objKlassOop)->external_name();
+          const char* klassName = Klass::cast(klassOf)->external_name();
+          char* message = SharedRuntime::generate_class_cast_message(
+            objName, klassName);
+
+          stack->set_sp(calculate_unwind_sp(stack, method_handle));
+          CALL_VM_NOCHECK_NOFIX(
+            throw_exception(
+              thread,
+              vmSymbols::java_lang_ClassCastException(), message));
+          // NB all oops trashed!
+          assert(HAS_PENDING_EXCEPTION, "should do");
+          return;
+        }
+
+        // Check the array type.
+
+        klassOop array_klass_oop = NULL;
+        BasicType array_type = java_lang_Class::as_BasicType(
+          java_lang_invoke_AdapterMethodHandle::argument(method_handle),
+            &array_klass_oop);
+        arrayKlassHandle array_klass(THREAD, array_klass_oop);
+
+        assert(array_type == T_OBJECT, "");
+        assert(Klass::cast(array_klass_oop)->oop_is_array(), "");
+        if (!(array_type == T_OBJECT) || 
+            !(Klass::cast(array_klass_oop)->oop_is_array())) {
+          CPPINT_DEBUG( tty->print_cr( \
+            "CLASS CAST ERROR #2 not an array in _adapter_opt_spread." ); )
+          ResourceMark rm(THREAD);
+          const char* objName = Klass::cast(objKlassOop)->external_name();
+          const char* klassName = Klass::cast(klassOf)->external_name();
+          char* message = SharedRuntime::generate_class_cast_message(
+            objName, klassName);
+          stack->set_sp(calculate_unwind_sp(stack, method_handle));
+          CALL_VM_NOCHECK_NOFIX(
+            throw_exception(
+              thread,
+              vmSymbols::java_lang_ClassCastException(), message));
+          // NB all oops trashed!
+          assert(HAS_PENDING_EXCEPTION, "should do");
+          return;
+        }
+
+        klassOop element_klass_oop = NULL;
+        BasicType element_type = 
+          java_lang_Class::as_BasicType(array_klass->component_mirror(),
+            &element_klass_oop);
+        KlassHandle element_klass(THREAD, element_klass_oop);
+        if (elem_type != element_type) {
+          CPPINT_DEBUG( tty->print_cr( \
+            "CLASS CAST ERROR #3 invalid type in _adapter_opt_spread." ); )
+          ResourceMark rm(THREAD);
+          const char* objName = Klass::cast(objKlassOop)->external_name();
+          const char* klassName = Klass::cast(klassOf)->external_name();
+          char* message = SharedRuntime::generate_class_cast_message(
+            objName, klassName);
+          stack->set_sp(calculate_unwind_sp(stack, method_handle));
+          CALL_VM_NOCHECK_NOFIX(
+            throw_exception(
+              thread,
+              vmSymbols::java_lang_ClassCastException(), message));
+          // NB all oops trashed!
+          assert(HAS_PENDING_EXCEPTION, "should do");
+          return;
+        }
+
+        array_length = arrayOop(arg)->length();
+
+        // Check the required length.
+        if (length_constant > 0) { // must match ?
+          if ( array_length != length_constant ) {
+            CPPINT_DEBUG( tty->print_cr( \
+              "ARRY INDEX ERROR #4 invalid array length in _adapter_opt_spread." ); )
+            //fixme  ArrayIndexOutOfBoundsException ?
+            ResourceMark rm(THREAD);
+            const char* objName = Klass::cast(objKlassOop)->external_name();
+            const char* klassName = Klass::cast(klassOf)->external_name();
+            char* message = SharedRuntime::generate_class_cast_message(
+              objName, klassName);
+
+            stack->set_sp(calculate_unwind_sp(stack, method_handle));
+            CALL_VM_NOCHECK_NOFIX(
+              throw_exception(
+                thread,
+                vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), message));
+            // NB all oops trashed!
+            assert(HAS_PENDING_EXCEPTION, "should do");
+            return;
+          }
+        // use array_length ?
+        } else { // length_constant == [ -1 or 0 ] 
+          if ( (array_length > 0) || length_can_be_zero ) {
+            // use array_length.
+          } else { // array_length 0 and not length_can_be_zero
+            CPPINT_DEBUG( tty->print_cr( \
+              "ARRY INDEX ERROR #5 arry length 0 in _adapter_opt_spread." ); )
+            //fixme   ArrayIndexOutOfBoundsException ?
+            ResourceMark rm(THREAD);
+            const char* objName = Klass::cast(objKlassOop)->external_name();
+            const char* klassName = Klass::cast(klassOf)->external_name();
+            char* message = SharedRuntime::generate_class_cast_message(
+              objName, klassName);
+
+            stack->set_sp(calculate_unwind_sp(stack, method_handle));
+            CALL_VM_NOCHECK_NOFIX(
+              throw_exception(
+                thread,
+                vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), message));
+            // NB all oops trashed!
+            assert(HAS_PENDING_EXCEPTION, "should do");
+            return;
+          }
+        }
+
+        // Array length checked out.  Now insert any required arg slots.
+        // array_length - 1 more slots if array_length > 0
+        // otherwise  if array_length == 0 remove arg_slot.
+
+        if ( array_length > 0 ) {
+          int slots = (array_length * elem_slots) - 1;
+          CPPINT_DEBUG( tty->print_cr( \
+            "array_length %d %d slots needed in _adapter_opt_spread.",\
+              array_length, slots); )
+          debug_only(if (elem_slots == 2) \
+            assert ((slots % 2 == 1)," bad slots calc"));
+          if ( slots > 0 ) {
+            intptr_t *unwind_sp = 
+            calculate_unwind_sp(stack, method_handle);
+            insert_vmslots(arg_slot, slots, THREAD);
+            if (HAS_PENDING_EXCEPTION) {
+              // all oops trashed
+              stack->set_sp(unwind_sp);
+              return;
+            }
+          }
+          vmslots = stack->sp();
+          arg_slot += slots;
+
+          array_elem0 = arrayOop(arg)->base(elem_type);
+
+          // Copy from the array to the new arg slots.
+          // [from native : Beware:  Arguments that are shallow 
+          // on the stack are deep in the array,
+          // and vice versa.  So a downward-growing stack (the usual) 
+          // has to be copied elementwise in reverse order 
+          // from the source array.]
+
+          void * array_elem = array_elem0;
+          int top_slot = arg_slot;
+
+          debug_only(if (elem_slots == 2) \
+            assert ((((u_int)(char *)&vmslots[top_slot]) % \
+              (u_int)type2aelembytes(elem_type) == 0), \
+                " bad arg alignment"));
+
+          CPPINT_DEBUG( tty->print_cr( \
+            "BEGIN ARRY LOOP %d %d 0x%x 0x%x _adapter_opt_spread.",\
+              array_length, top_slot, &vmslots[top_slot], array_elem  ); )
+
+          for (int index = 0; index < array_length; index++) {
+            switch (elem_type) {
+            case T_BYTE:
+              SET_VMSLOTS_INT(*(jint*)array_elem, top_slot);
+              break;
+            case T_CHAR:
+              SET_VMSLOTS_INT(*(jint*)array_elem, top_slot);
+              break;
+            case T_SHORT:
+              SET_VMSLOTS_INT(*(jint*)array_elem, top_slot);
+              break;
+            case T_INT:
+              SET_VMSLOTS_INT(*(jint*)array_elem, top_slot);
+              break;
+            case T_FLOAT:
+              SET_VMSLOTS_FLOAT(*(jfloat*)array_elem,top_slot);
+              break;
+            case T_LONG:
+              SET_VMSLOTS_LONG(*(jlong*)array_elem, top_slot);
+              break;
+            case T_DOUBLE:
+              SET_VMSLOTS_DOUBLE(*(jdouble*)array_elem, top_slot);
+              break;
+            case T_OBJECT:
+              SET_VMSLOTS_OBJECT(*(oopDesc**)array_elem, top_slot);
+              break;
+            default:
+              tty->print_cr("unhandled type %s", type2name(elem_type));
+              ShouldNotReachHere();
+            }
+            array_elem = (void*)((char *)array_elem +
+              type2aelembytes(elem_type));
+            top_slot -= elem_slots;
+          }
+          arg_slot++;
+        }
+      }
+      if ((array_length == 0) && (arg != NULL)) {
+        CPPINT_DEBUG( tty->print_cr( \
+          "Array_length == 0, will remove slot." ); )
+        // remove arg slot
+        remove_vmslots(arg_slot, 1, THREAD); // doesn't trap
+         // unused, but let the compiler figure that out
+        vmslots = stack->sp();
+        //
+      }
+      CPPINT_DEBUG( tty->print_cr( \
+        "LEAVING _adapter_opt_spread: %s 0x%x 0x%x \n", \
+          type2name(elem_type), (char *)arg, (char *)stack->sp() ); )
+    }
+        break;
+    default:
+      tty->print_cr("unhandled entry_kind %s",
                   MethodHandles::entry_name(entry_kind));
-    ShouldNotReachHere();
+      ShouldNotReachHere();
   }
 
+
   // Continue along the chain
   if (direct_to_method) {
     if (method == NULL) {
@@ -1138,6 +1450,7 @@
     tty->print_cr("dst_rtype = %s", type2name(dst_rtype));
     ShouldNotReachHere();
   }
+  CPPINT_DEBUG( tty->print_cr( "LEAVING %s\n",MethodHandles::entry_name(entry_kind) ); )
 }
 
 // The new slots will be inserted before slot insert_before.
diff --git a/src/cpu/zero/vm/methodHandles_zero.cpp b/src/cpu/zero/vm/methodHandles_zero.cpp
--- a/src/cpu/zero/vm/methodHandles_zero.cpp
+++ b/src/cpu/zero/vm/methodHandles_zero.cpp
@@ -38,9 +38,8 @@
          |(1<<java_lang_invoke_AdapterMethodHandle::OP_ROT_ARGS)
          |(1<<java_lang_invoke_AdapterMethodHandle::OP_DUP_ARGS)
          |(1<<java_lang_invoke_AdapterMethodHandle::OP_DROP_ARGS)
-         //|(1<<java_lang_invoke_AdapterMethodHandle::OP_SPREAD_ARGS) //BUG!
+         |(1<<java_lang_invoke_AdapterMethodHandle::OP_SPREAD_ARGS)
          );
-  // FIXME: MethodHandlesTest gets a crash if we enable OP_SPREAD_ARGS.
 }
 
 void MethodHandles::generate_method_handle_stub(MacroAssembler*          masm,


More information about the distro-pkg-dev mailing list