Thu, 02 Feb 2012 09:14:38 -0800
7141637: JSR 292: MH spread invoker crashes with NULL argument on x86_32
Reviewed-by: twisti
Contributed-by: Volker Simonis <volker.simonis@gmail.com>
src/cpu/x86/vm/methodHandles_x86.cpp | file | annotate | diff | comparison | revisions | |
test/compiler/7141637/SpreadNullArg.java | file | annotate | diff | comparison | revisions |
1.1 --- a/src/cpu/x86/vm/methodHandles_x86.cpp Wed Feb 01 16:57:08 2012 -0800 1.2 +++ b/src/cpu/x86/vm/methodHandles_x86.cpp Thu Feb 02 09:14:38 2012 -0800 1.3 @@ -2364,23 +2364,19 @@ 1.4 1.5 // grab another temp 1.6 Register rsi_temp = rsi; 1.7 - { if (rsi_temp == saved_last_sp) __ push(saved_last_sp); } 1.8 - // (preceding push must be done after argslot address is taken!) 1.9 -#define UNPUSH_RSI \ 1.10 - { if (rsi_temp == saved_last_sp) __ pop(saved_last_sp); } 1.11 1.12 // arx_argslot points both to the array and to the first output arg 1.13 vmarg = Address(rax_argslot, 0); 1.14 1.15 // Get the array value. 1.16 - Register rsi_array = rsi_temp; 1.17 + Register rdi_array = rdi_temp; 1.18 Register rdx_array_klass = rdx_temp; 1.19 BasicType elem_type = ek_adapter_opt_spread_type(ek); 1.20 int elem_slots = type2size[elem_type]; // 1 or 2 1.21 int array_slots = 1; // array is always a T_OBJECT 1.22 int length_offset = arrayOopDesc::length_offset_in_bytes(); 1.23 int elem0_offset = arrayOopDesc::base_offset_in_bytes(elem_type); 1.24 - __ movptr(rsi_array, vmarg); 1.25 + __ movptr(rdi_array, vmarg); 1.26 1.27 Label L_array_is_empty, L_insert_arg_space, L_copy_args, L_args_done; 1.28 if (length_can_be_zero) { 1.29 @@ -2391,12 +2387,30 @@ 1.30 __ testl(rbx_temp, rbx_temp); 1.31 __ jcc(Assembler::notZero, L_skip); 1.32 } 1.33 - __ testptr(rsi_array, rsi_array); 1.34 - __ jcc(Assembler::zero, L_array_is_empty); 1.35 + __ testptr(rdi_array, rdi_array); 1.36 + __ jcc(Assembler::notZero, L_skip); 1.37 + 1.38 + // If 'rsi' contains the 'saved_last_sp' (this is only the 1.39 + // case in a 32-bit version of the VM) we have to save 'rsi' 1.40 + // on the stack because later on (at 'L_array_is_empty') 'rsi' 1.41 + // will be overwritten. 1.42 + { if (rsi_temp == saved_last_sp) __ push(saved_last_sp); } 1.43 + // Also prepare a handy macro which restores 'rsi' if required. 1.44 +#define UNPUSH_RSI \ 1.45 + { if (rsi_temp == saved_last_sp) __ pop(saved_last_sp); } 1.46 + 1.47 + __ jmp(L_array_is_empty); 1.48 __ bind(L_skip); 1.49 } 1.50 - __ null_check(rsi_array, oopDesc::klass_offset_in_bytes()); 1.51 - __ load_klass(rdx_array_klass, rsi_array); 1.52 + __ null_check(rdi_array, oopDesc::klass_offset_in_bytes()); 1.53 + __ load_klass(rdx_array_klass, rdi_array); 1.54 + 1.55 + // Save 'rsi' if required (see comment above). Do this only 1.56 + // after the null check such that the exception handler which is 1.57 + // called in the case of a null pointer exception will not be 1.58 + // confused by the extra value on the stack (it expects the 1.59 + // return pointer on top of the stack) 1.60 + { if (rsi_temp == saved_last_sp) __ push(saved_last_sp); } 1.61 1.62 // Check the array type. 1.63 Register rbx_klass = rbx_temp; 1.64 @@ -2404,18 +2418,18 @@ 1.65 load_klass_from_Class(_masm, rbx_klass); 1.66 1.67 Label ok_array_klass, bad_array_klass, bad_array_length; 1.68 - __ check_klass_subtype(rdx_array_klass, rbx_klass, rdi_temp, ok_array_klass); 1.69 + __ check_klass_subtype(rdx_array_klass, rbx_klass, rsi_temp, ok_array_klass); 1.70 // If we get here, the type check failed! 1.71 __ jmp(bad_array_klass); 1.72 __ BIND(ok_array_klass); 1.73 1.74 // Check length. 1.75 if (length_constant >= 0) { 1.76 - __ cmpl(Address(rsi_array, length_offset), length_constant); 1.77 + __ cmpl(Address(rdi_array, length_offset), length_constant); 1.78 } else { 1.79 Register rbx_vminfo = rbx_temp; 1.80 load_conversion_vminfo(_masm, rbx_vminfo, rcx_amh_conversion); 1.81 - __ cmpl(rbx_vminfo, Address(rsi_array, length_offset)); 1.82 + __ cmpl(rbx_vminfo, Address(rdi_array, length_offset)); 1.83 } 1.84 __ jcc(Assembler::notEqual, bad_array_length); 1.85 1.86 @@ -2427,9 +2441,9 @@ 1.87 __ lea(rdx_argslot_limit, Address(rax_argslot, Interpreter::stackElementSize)); 1.88 // 'stack_move' is negative number of words to insert 1.89 // This number already accounts for elem_slots. 1.90 - Register rdi_stack_move = rdi_temp; 1.91 - load_stack_move(_masm, rdi_stack_move, rcx_recv, true); 1.92 - __ cmpptr(rdi_stack_move, 0); 1.93 + Register rsi_stack_move = rsi_temp; 1.94 + load_stack_move(_masm, rsi_stack_move, rcx_recv, true); 1.95 + __ cmpptr(rsi_stack_move, 0); 1.96 assert(stack_move_unit() < 0, "else change this comparison"); 1.97 __ jcc(Assembler::less, L_insert_arg_space); 1.98 __ jcc(Assembler::equal, L_copy_args); 1.99 @@ -2440,12 +2454,12 @@ 1.100 __ jmp(L_args_done); // no spreading to do 1.101 __ BIND(L_insert_arg_space); 1.102 // come here in the usual case, stack_move < 0 (2 or more spread arguments) 1.103 - Register rsi_temp = rsi_array; // spill this 1.104 - insert_arg_slots(_masm, rdi_stack_move, 1.105 - rax_argslot, rbx_temp, rsi_temp); 1.106 + Register rdi_temp = rdi_array; // spill this 1.107 + insert_arg_slots(_masm, rsi_stack_move, 1.108 + rax_argslot, rbx_temp, rdi_temp); 1.109 // reload the array since rsi was killed 1.110 // reload from rdx_argslot_limit since rax_argslot is now decremented 1.111 - __ movptr(rsi_array, Address(rdx_argslot_limit, -Interpreter::stackElementSize)); 1.112 + __ movptr(rdi_array, Address(rdx_argslot_limit, -Interpreter::stackElementSize)); 1.113 } else if (length_constant >= 1) { 1.114 int new_slots = (length_constant * elem_slots) - array_slots; 1.115 insert_arg_slots(_masm, new_slots * stack_move_unit(), 1.116 @@ -2468,16 +2482,16 @@ 1.117 if (length_constant == -1) { 1.118 // [rax_argslot, rdx_argslot_limit) is the area we are inserting into. 1.119 // Array element [0] goes at rdx_argslot_limit[-wordSize]. 1.120 - Register rsi_source = rsi_array; 1.121 - __ lea(rsi_source, Address(rsi_array, elem0_offset)); 1.122 + Register rdi_source = rdi_array; 1.123 + __ lea(rdi_source, Address(rdi_array, elem0_offset)); 1.124 Register rdx_fill_ptr = rdx_argslot_limit; 1.125 Label loop; 1.126 __ BIND(loop); 1.127 __ addptr(rdx_fill_ptr, -Interpreter::stackElementSize * elem_slots); 1.128 move_typed_arg(_masm, elem_type, true, 1.129 - Address(rdx_fill_ptr, 0), Address(rsi_source, 0), 1.130 - rbx_temp, rdi_temp); 1.131 - __ addptr(rsi_source, type2aelembytes(elem_type)); 1.132 + Address(rdx_fill_ptr, 0), Address(rdi_source, 0), 1.133 + rbx_temp, rsi_temp); 1.134 + __ addptr(rdi_source, type2aelembytes(elem_type)); 1.135 __ cmpptr(rdx_fill_ptr, rax_argslot); 1.136 __ jcc(Assembler::above, loop); 1.137 } else if (length_constant == 0) { 1.138 @@ -2488,8 +2502,8 @@ 1.139 for (int index = 0; index < length_constant; index++) { 1.140 slot_offset -= Interpreter::stackElementSize * elem_slots; // fill backward 1.141 move_typed_arg(_masm, elem_type, true, 1.142 - Address(rax_argslot, slot_offset), Address(rsi_array, elem_offset), 1.143 - rbx_temp, rdi_temp); 1.144 + Address(rax_argslot, slot_offset), Address(rdi_array, elem_offset), 1.145 + rbx_temp, rsi_temp); 1.146 elem_offset += type2aelembytes(elem_type); 1.147 } 1.148 }
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/test/compiler/7141637/SpreadNullArg.java Thu Feb 02 09:14:38 2012 -0800 2.3 @@ -0,0 +1,62 @@ 2.4 +/* 2.5 + * Copyright 2011 SAP AG. All Rights Reserved. 2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.7 + * 2.8 + * This code is free software; you can redistribute it and/or modify it 2.9 + * under the terms of the GNU General Public License version 2 only, as 2.10 + * published by the Free Software Foundation. 2.11 + * 2.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 2.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 2.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 2.15 + * version 2 for more details (a copy is included in the LICENSE file that 2.16 + * accompanied this code). 2.17 + * 2.18 + * You should have received a copy of the GNU General Public License version 2.19 + * 2 along with this work; if not, write to the Free Software Foundation, 2.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2.21 + * 2.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2.23 + * or visit www.oracle.com if you need additional information or have any 2.24 + * questions. 2.25 + */ 2.26 + 2.27 +/* 2.28 + * @test SpreadNullArg 2.29 + * @bug 7141637 2.30 + * @summary verifies that the MethodHandle spread adapter can gracefully handle null arguments. 2.31 + * @run main SpreadNullArg 2.32 + * @author volker.simonis@gmail.com 2.33 + */ 2.34 + 2.35 +import java.lang.invoke.MethodHandle; 2.36 +import java.lang.invoke.MethodHandles; 2.37 +import java.lang.invoke.MethodType; 2.38 + 2.39 +public class SpreadNullArg { 2.40 + 2.41 + public static void main(String args[]) { 2.42 + 2.43 + MethodType mt_ref_arg = MethodType.methodType(int.class, Integer.class); 2.44 + MethodHandle mh_spreadInvoker = MethodHandles.spreadInvoker(mt_ref_arg, 0); 2.45 + MethodHandle mh_spread_target; 2.46 + int result = 42; 2.47 + 2.48 + try { 2.49 + mh_spread_target = 2.50 + MethodHandles.lookup().findStatic(SpreadNullArg.class, "target_spread_arg", mt_ref_arg); 2.51 + result = (int) mh_spreadInvoker.invokeExact(mh_spread_target, (Object[]) null); 2.52 + } catch(NullPointerException e) { 2.53 + // Expected exception - do nothing! 2.54 + } catch(Throwable e) { 2.55 + throw new Error(e); 2.56 + } 2.57 + 2.58 + if (result != 42) throw new Error("Expected NullPointerException was not thrown"); 2.59 + } 2.60 + 2.61 + public static int target_spread_arg(Integer i1) { 2.62 + return i1.intValue(); 2.63 + } 2.64 + 2.65 +}