mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-15 16:44:36 +02:00
7141637: JSR 292: MH spread invoker crashes with NULL argument on x86_32
Reviewed-by: twisti
This commit is contained in:
parent
9599296d97
commit
b9fbc2faab
2 changed files with 103 additions and 27 deletions
|
@ -2364,23 +2364,19 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||||
|
|
||||||
// grab another temp
|
// grab another temp
|
||||||
Register rsi_temp = rsi;
|
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
|
// arx_argslot points both to the array and to the first output arg
|
||||||
vmarg = Address(rax_argslot, 0);
|
vmarg = Address(rax_argslot, 0);
|
||||||
|
|
||||||
// Get the array value.
|
// Get the array value.
|
||||||
Register rsi_array = rsi_temp;
|
Register rdi_array = rdi_temp;
|
||||||
Register rdx_array_klass = rdx_temp;
|
Register rdx_array_klass = rdx_temp;
|
||||||
BasicType elem_type = ek_adapter_opt_spread_type(ek);
|
BasicType elem_type = ek_adapter_opt_spread_type(ek);
|
||||||
int elem_slots = type2size[elem_type]; // 1 or 2
|
int elem_slots = type2size[elem_type]; // 1 or 2
|
||||||
int array_slots = 1; // array is always a T_OBJECT
|
int array_slots = 1; // array is always a T_OBJECT
|
||||||
int length_offset = arrayOopDesc::length_offset_in_bytes();
|
int length_offset = arrayOopDesc::length_offset_in_bytes();
|
||||||
int elem0_offset = arrayOopDesc::base_offset_in_bytes(elem_type);
|
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;
|
Label L_array_is_empty, L_insert_arg_space, L_copy_args, L_args_done;
|
||||||
if (length_can_be_zero) {
|
if (length_can_be_zero) {
|
||||||
|
@ -2391,12 +2387,30 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||||
__ testl(rbx_temp, rbx_temp);
|
__ testl(rbx_temp, rbx_temp);
|
||||||
__ jcc(Assembler::notZero, L_skip);
|
__ jcc(Assembler::notZero, L_skip);
|
||||||
}
|
}
|
||||||
__ testptr(rsi_array, rsi_array);
|
__ testptr(rdi_array, rdi_array);
|
||||||
__ jcc(Assembler::zero, L_array_is_empty);
|
__ 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);
|
__ bind(L_skip);
|
||||||
}
|
}
|
||||||
__ null_check(rsi_array, oopDesc::klass_offset_in_bytes());
|
__ null_check(rdi_array, oopDesc::klass_offset_in_bytes());
|
||||||
__ load_klass(rdx_array_klass, rsi_array);
|
__ 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.
|
// Check the array type.
|
||||||
Register rbx_klass = rbx_temp;
|
Register rbx_klass = rbx_temp;
|
||||||
|
@ -2404,18 +2418,18 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||||
load_klass_from_Class(_masm, rbx_klass);
|
load_klass_from_Class(_masm, rbx_klass);
|
||||||
|
|
||||||
Label ok_array_klass, bad_array_klass, bad_array_length;
|
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!
|
// If we get here, the type check failed!
|
||||||
__ jmp(bad_array_klass);
|
__ jmp(bad_array_klass);
|
||||||
__ BIND(ok_array_klass);
|
__ BIND(ok_array_klass);
|
||||||
|
|
||||||
// Check length.
|
// Check length.
|
||||||
if (length_constant >= 0) {
|
if (length_constant >= 0) {
|
||||||
__ cmpl(Address(rsi_array, length_offset), length_constant);
|
__ cmpl(Address(rdi_array, length_offset), length_constant);
|
||||||
} else {
|
} else {
|
||||||
Register rbx_vminfo = rbx_temp;
|
Register rbx_vminfo = rbx_temp;
|
||||||
load_conversion_vminfo(_masm, rbx_vminfo, rcx_amh_conversion);
|
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);
|
__ jcc(Assembler::notEqual, bad_array_length);
|
||||||
|
|
||||||
|
@ -2427,9 +2441,9 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||||
__ lea(rdx_argslot_limit, Address(rax_argslot, Interpreter::stackElementSize));
|
__ lea(rdx_argslot_limit, Address(rax_argslot, Interpreter::stackElementSize));
|
||||||
// 'stack_move' is negative number of words to insert
|
// 'stack_move' is negative number of words to insert
|
||||||
// This number already accounts for elem_slots.
|
// This number already accounts for elem_slots.
|
||||||
Register rdi_stack_move = rdi_temp;
|
Register rsi_stack_move = rsi_temp;
|
||||||
load_stack_move(_masm, rdi_stack_move, rcx_recv, true);
|
load_stack_move(_masm, rsi_stack_move, rcx_recv, true);
|
||||||
__ cmpptr(rdi_stack_move, 0);
|
__ cmpptr(rsi_stack_move, 0);
|
||||||
assert(stack_move_unit() < 0, "else change this comparison");
|
assert(stack_move_unit() < 0, "else change this comparison");
|
||||||
__ jcc(Assembler::less, L_insert_arg_space);
|
__ jcc(Assembler::less, L_insert_arg_space);
|
||||||
__ jcc(Assembler::equal, L_copy_args);
|
__ jcc(Assembler::equal, L_copy_args);
|
||||||
|
@ -2440,12 +2454,12 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||||
__ jmp(L_args_done); // no spreading to do
|
__ jmp(L_args_done); // no spreading to do
|
||||||
__ BIND(L_insert_arg_space);
|
__ BIND(L_insert_arg_space);
|
||||||
// come here in the usual case, stack_move < 0 (2 or more spread arguments)
|
// come here in the usual case, stack_move < 0 (2 or more spread arguments)
|
||||||
Register rsi_temp = rsi_array; // spill this
|
Register rdi_temp = rdi_array; // spill this
|
||||||
insert_arg_slots(_masm, rdi_stack_move,
|
insert_arg_slots(_masm, rsi_stack_move,
|
||||||
rax_argslot, rbx_temp, rsi_temp);
|
rax_argslot, rbx_temp, rdi_temp);
|
||||||
// reload the array since rsi was killed
|
// reload the array since rsi was killed
|
||||||
// reload from rdx_argslot_limit since rax_argslot is now decremented
|
// 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) {
|
} else if (length_constant >= 1) {
|
||||||
int new_slots = (length_constant * elem_slots) - array_slots;
|
int new_slots = (length_constant * elem_slots) - array_slots;
|
||||||
insert_arg_slots(_masm, new_slots * stack_move_unit(),
|
insert_arg_slots(_masm, new_slots * stack_move_unit(),
|
||||||
|
@ -2468,16 +2482,16 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||||
if (length_constant == -1) {
|
if (length_constant == -1) {
|
||||||
// [rax_argslot, rdx_argslot_limit) is the area we are inserting into.
|
// [rax_argslot, rdx_argslot_limit) is the area we are inserting into.
|
||||||
// Array element [0] goes at rdx_argslot_limit[-wordSize].
|
// Array element [0] goes at rdx_argslot_limit[-wordSize].
|
||||||
Register rsi_source = rsi_array;
|
Register rdi_source = rdi_array;
|
||||||
__ lea(rsi_source, Address(rsi_array, elem0_offset));
|
__ lea(rdi_source, Address(rdi_array, elem0_offset));
|
||||||
Register rdx_fill_ptr = rdx_argslot_limit;
|
Register rdx_fill_ptr = rdx_argslot_limit;
|
||||||
Label loop;
|
Label loop;
|
||||||
__ BIND(loop);
|
__ BIND(loop);
|
||||||
__ addptr(rdx_fill_ptr, -Interpreter::stackElementSize * elem_slots);
|
__ addptr(rdx_fill_ptr, -Interpreter::stackElementSize * elem_slots);
|
||||||
move_typed_arg(_masm, elem_type, true,
|
move_typed_arg(_masm, elem_type, true,
|
||||||
Address(rdx_fill_ptr, 0), Address(rsi_source, 0),
|
Address(rdx_fill_ptr, 0), Address(rdi_source, 0),
|
||||||
rbx_temp, rdi_temp);
|
rbx_temp, rsi_temp);
|
||||||
__ addptr(rsi_source, type2aelembytes(elem_type));
|
__ addptr(rdi_source, type2aelembytes(elem_type));
|
||||||
__ cmpptr(rdx_fill_ptr, rax_argslot);
|
__ cmpptr(rdx_fill_ptr, rax_argslot);
|
||||||
__ jcc(Assembler::above, loop);
|
__ jcc(Assembler::above, loop);
|
||||||
} else if (length_constant == 0) {
|
} else if (length_constant == 0) {
|
||||||
|
@ -2488,8 +2502,8 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||||
for (int index = 0; index < length_constant; index++) {
|
for (int index = 0; index < length_constant; index++) {
|
||||||
slot_offset -= Interpreter::stackElementSize * elem_slots; // fill backward
|
slot_offset -= Interpreter::stackElementSize * elem_slots; // fill backward
|
||||||
move_typed_arg(_masm, elem_type, true,
|
move_typed_arg(_masm, elem_type, true,
|
||||||
Address(rax_argslot, slot_offset), Address(rsi_array, elem_offset),
|
Address(rax_argslot, slot_offset), Address(rdi_array, elem_offset),
|
||||||
rbx_temp, rdi_temp);
|
rbx_temp, rsi_temp);
|
||||||
elem_offset += type2aelembytes(elem_type);
|
elem_offset += type2aelembytes(elem_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
62
hotspot/test/compiler/7141637/SpreadNullArg.java
Normal file
62
hotspot/test/compiler/7141637/SpreadNullArg.java
Normal file
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue