# HG changeset patch # User twisti # Date 1328202878 28800 # Node ID 68657fd5d7b4132083a1469530cfe8e39e4e1c9b # Parent 0304660366153b0d8afa55933255aa002c9f7733 7141637: JSR 292: MH spread invoker crashes with NULL argument on x86_32 Reviewed-by: twisti Contributed-by: Volker Simonis diff -r 030466036615 -r 68657fd5d7b4 hotspot/src/cpu/x86/vm/methodHandles_x86.cpp --- a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp Wed Feb 01 16:57:08 2012 -0800 +++ b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp Thu Feb 02 09:14:38 2012 -0800 @@ -2364,23 +2364,19 @@ // grab another temp Register rsi_temp = rsi; - { if (rsi_temp == saved_last_sp) __ push(saved_last_sp); } - // (preceding push must be done after argslot address is taken!) -#define UNPUSH_RSI \ - { if (rsi_temp == saved_last_sp) __ pop(saved_last_sp); } // arx_argslot points both to the array and to the first output arg vmarg = Address(rax_argslot, 0); // Get the array value. - Register rsi_array = rsi_temp; + Register rdi_array = rdi_temp; Register rdx_array_klass = rdx_temp; BasicType elem_type = ek_adapter_opt_spread_type(ek); 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); - __ movptr(rsi_array, vmarg); + __ movptr(rdi_array, vmarg); Label L_array_is_empty, L_insert_arg_space, L_copy_args, L_args_done; if (length_can_be_zero) { @@ -2391,12 +2387,30 @@ __ testl(rbx_temp, rbx_temp); __ jcc(Assembler::notZero, L_skip); } - __ testptr(rsi_array, rsi_array); - __ jcc(Assembler::zero, L_array_is_empty); + __ testptr(rdi_array, rdi_array); + __ jcc(Assembler::notZero, L_skip); + + // If 'rsi' contains the 'saved_last_sp' (this is only the + // case in a 32-bit version of the VM) we have to save 'rsi' + // on the stack because later on (at 'L_array_is_empty') 'rsi' + // will be overwritten. + { if (rsi_temp == saved_last_sp) __ push(saved_last_sp); } + // Also prepare a handy macro which restores 'rsi' if required. +#define UNPUSH_RSI \ + { if (rsi_temp == saved_last_sp) __ pop(saved_last_sp); } + + __ jmp(L_array_is_empty); __ bind(L_skip); } - __ null_check(rsi_array, oopDesc::klass_offset_in_bytes()); - __ load_klass(rdx_array_klass, rsi_array); + __ null_check(rdi_array, oopDesc::klass_offset_in_bytes()); + __ load_klass(rdx_array_klass, rdi_array); + + // Save 'rsi' if required (see comment above). Do this only + // after the null check such that the exception handler which is + // called in the case of a null pointer exception will not be + // confused by the extra value on the stack (it expects the + // return pointer on top of the stack) + { if (rsi_temp == saved_last_sp) __ push(saved_last_sp); } // Check the array type. Register rbx_klass = rbx_temp; @@ -2404,18 +2418,18 @@ load_klass_from_Class(_masm, rbx_klass); Label ok_array_klass, bad_array_klass, bad_array_length; - __ check_klass_subtype(rdx_array_klass, rbx_klass, rdi_temp, ok_array_klass); + __ check_klass_subtype(rdx_array_klass, rbx_klass, rsi_temp, ok_array_klass); // If we get here, the type check failed! __ jmp(bad_array_klass); __ BIND(ok_array_klass); // Check length. if (length_constant >= 0) { - __ cmpl(Address(rsi_array, length_offset), length_constant); + __ cmpl(Address(rdi_array, length_offset), length_constant); } else { Register rbx_vminfo = rbx_temp; load_conversion_vminfo(_masm, rbx_vminfo, rcx_amh_conversion); - __ cmpl(rbx_vminfo, Address(rsi_array, length_offset)); + __ cmpl(rbx_vminfo, Address(rdi_array, length_offset)); } __ jcc(Assembler::notEqual, bad_array_length); @@ -2427,9 +2441,9 @@ __ lea(rdx_argslot_limit, Address(rax_argslot, Interpreter::stackElementSize)); // 'stack_move' is negative number of words to insert // This number already accounts for elem_slots. - Register rdi_stack_move = rdi_temp; - load_stack_move(_masm, rdi_stack_move, rcx_recv, true); - __ cmpptr(rdi_stack_move, 0); + Register rsi_stack_move = rsi_temp; + load_stack_move(_masm, rsi_stack_move, rcx_recv, true); + __ cmpptr(rsi_stack_move, 0); assert(stack_move_unit() < 0, "else change this comparison"); __ jcc(Assembler::less, L_insert_arg_space); __ jcc(Assembler::equal, L_copy_args); @@ -2440,12 +2454,12 @@ __ jmp(L_args_done); // no spreading to do __ BIND(L_insert_arg_space); // come here in the usual case, stack_move < 0 (2 or more spread arguments) - Register rsi_temp = rsi_array; // spill this - insert_arg_slots(_masm, rdi_stack_move, - rax_argslot, rbx_temp, rsi_temp); + Register rdi_temp = rdi_array; // spill this + insert_arg_slots(_masm, rsi_stack_move, + rax_argslot, rbx_temp, rdi_temp); // reload the array since rsi was killed // reload from rdx_argslot_limit since rax_argslot is now decremented - __ movptr(rsi_array, Address(rdx_argslot_limit, -Interpreter::stackElementSize)); + __ movptr(rdi_array, Address(rdx_argslot_limit, -Interpreter::stackElementSize)); } else if (length_constant >= 1) { int new_slots = (length_constant * elem_slots) - array_slots; insert_arg_slots(_masm, new_slots * stack_move_unit(), @@ -2468,16 +2482,16 @@ if (length_constant == -1) { // [rax_argslot, rdx_argslot_limit) is the area we are inserting into. // Array element [0] goes at rdx_argslot_limit[-wordSize]. - Register rsi_source = rsi_array; - __ lea(rsi_source, Address(rsi_array, elem0_offset)); + Register rdi_source = rdi_array; + __ lea(rdi_source, Address(rdi_array, elem0_offset)); Register rdx_fill_ptr = rdx_argslot_limit; Label loop; __ BIND(loop); __ addptr(rdx_fill_ptr, -Interpreter::stackElementSize * elem_slots); move_typed_arg(_masm, elem_type, true, - Address(rdx_fill_ptr, 0), Address(rsi_source, 0), - rbx_temp, rdi_temp); - __ addptr(rsi_source, type2aelembytes(elem_type)); + Address(rdx_fill_ptr, 0), Address(rdi_source, 0), + rbx_temp, rsi_temp); + __ addptr(rdi_source, type2aelembytes(elem_type)); __ cmpptr(rdx_fill_ptr, rax_argslot); __ jcc(Assembler::above, loop); } else if (length_constant == 0) { @@ -2488,8 +2502,8 @@ for (int index = 0; index < length_constant; index++) { slot_offset -= Interpreter::stackElementSize * elem_slots; // fill backward move_typed_arg(_masm, elem_type, true, - Address(rax_argslot, slot_offset), Address(rsi_array, elem_offset), - rbx_temp, rdi_temp); + Address(rax_argslot, slot_offset), Address(rdi_array, elem_offset), + rbx_temp, rsi_temp); elem_offset += type2aelembytes(elem_type); } } diff -r 030466036615 -r 68657fd5d7b4 hotspot/test/compiler/7141637/SpreadNullArg.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/7141637/SpreadNullArg.java Thu Feb 02 09:14:38 2012 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright 2011 SAP AG. 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test SpreadNullArg + * @bug 7141637 + * @summary verifies that the MethodHandle spread adapter can gracefully handle null arguments. + * @run main SpreadNullArg + * @author volker.simonis@gmail.com + */ + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +public class SpreadNullArg { + + public static void main(String args[]) { + + MethodType mt_ref_arg = MethodType.methodType(int.class, Integer.class); + MethodHandle mh_spreadInvoker = MethodHandles.spreadInvoker(mt_ref_arg, 0); + MethodHandle mh_spread_target; + int result = 42; + + try { + mh_spread_target = + MethodHandles.lookup().findStatic(SpreadNullArg.class, "target_spread_arg", mt_ref_arg); + result = (int) mh_spreadInvoker.invokeExact(mh_spread_target, (Object[]) null); + } catch(NullPointerException e) { + // Expected exception - do nothing! + } catch(Throwable e) { + throw new Error(e); + } + + if (result != 42) throw new Error("Expected NullPointerException was not thrown"); + } + + public static int target_spread_arg(Integer i1) { + return i1.intValue(); + } + +}