# HG changeset patch # User chrisphi # Date 1338987885 14400 # Node ID b41a43560dc844b6a33724d56a2f63e3ec83c071 # Parent 2eed594c7cdb47a1299fd9b0d600676c20a388af 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. diff -r 2eed594c7cdb -r b41a43560dc8 src/cpu/zero/vm/cppInterpreter_zero.cpp --- 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. diff -r 2eed594c7cdb -r b41a43560dc8 src/cpu/zero/vm/methodHandles_zero.cpp --- 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<