7141637: JSR 292: MH spread invoker crashes with NULL argument on x86_32

Thu, 02 Feb 2012 09:14:38 -0800

author
twisti
date
Thu, 02 Feb 2012 09:14:38 -0800
changeset 3501
392a3f07d567
parent 3500
0382d2b469b2
child 3502
379b22e03c32

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 +}

mercurial