changeset 2971:b41a43560dc8

Enable _adapter_opt_spread* jsr 292 code, now passes all but 13 tests in John Rose test suite, 10 of those are NYI. Should fix issues seen in arm qa testing.
author chrisphi
date Wed, 06 Jun 2012 09:04:45 -0400
parents 2eed594c7cdb
children 47a867dd3005
files src/cpu/zero/vm/cppInterpreter_zero.cpp src/cpu/zero/vm/methodHandles_zero.cpp
diffstat 2 files changed, 318 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/cpu/zero/vm/cppInterpreter_zero.cpp	Tue Jun 12 23:50:11 2012 +0100
+++ b/src/cpu/zero/vm/cppInterpreter_zero.cpp	Wed Jun 06 09:04:45 2012 -0400
@@ -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,309 @@
     }
     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 != T_OBJECT) && (elem_type != element_type)) {
+          CPPINT_DEBUG( tty->print_cr( \
+            "CLASS CAST ERROR #3 invalid type %s != %s in _adapter_opt_spread.", \
+            type2name(elem_type), type2name(element_type)  ); )
+          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 ((((ulong)(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(element_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 +1451,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.
--- a/src/cpu/zero/vm/methodHandles_zero.cpp	Tue Jun 12 23:50:11 2012 +0100
+++ b/src/cpu/zero/vm/methodHandles_zero.cpp	Wed Jun 06 09:04:45 2012 -0400
@@ -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,