8025260: Methodhandles/JSR292: NullPointerException (NPE) thrown instead of AbstractMethodError (AME)

Fri, 27 Sep 2013 13:36:25 -0400

author
drchase
date
Fri, 27 Sep 2013 13:36:25 -0400
changeset 5800
dc261f466b6d
parent 5799
d8d059e90ec1
child 5801
cacc4c6bfc80

8025260: Methodhandles/JSR292: NullPointerException (NPE) thrown instead of AbstractMethodError (AME)
Summary: Copied null-checks from templateInterpreter_CPU into methodHandles_CPU
Reviewed-by: jrose, twisti

src/cpu/sparc/vm/methodHandles_sparc.cpp file | annotate | diff | comparison | revisions
src/cpu/x86/vm/methodHandles_x86.cpp file | annotate | diff | comparison | revisions
test/compiler/jsr292/methodHandleExceptions/ByteClassLoader.java file | annotate | diff | comparison | revisions
test/compiler/jsr292/methodHandleExceptions/C.java file | annotate | diff | comparison | revisions
test/compiler/jsr292/methodHandleExceptions/I.java file | annotate | diff | comparison | revisions
test/compiler/jsr292/methodHandleExceptions/TestAMEnotNPE.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/cpu/sparc/vm/methodHandles_sparc.cpp	Mon Sep 30 15:42:39 2013 -0700
     1.2 +++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp	Fri Sep 27 13:36:25 2013 -0400
     1.3 @@ -1,5 +1,5 @@
     1.4  /*
     1.5 - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
     1.6 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
     1.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.8   *
     1.9   * This code is free software; you can redistribute it and/or modify it
    1.10 @@ -121,6 +121,7 @@
    1.11  
    1.12  void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register target, Register temp,
    1.13                                              bool for_compiler_entry) {
    1.14 +  Label L_no_such_method;
    1.15    assert(method == G5_method, "interpreter calling convention");
    1.16    assert_different_registers(method, target, temp);
    1.17  
    1.18 @@ -133,6 +134,9 @@
    1.19      const Address interp_only(G2_thread, JavaThread::interp_only_mode_offset());
    1.20      __ ld(interp_only, temp);
    1.21      __ cmp_and_br_short(temp, 0, Assembler::zero, Assembler::pt, run_compiled_code);
    1.22 +    // Null method test is replicated below in compiled case,
    1.23 +    // it might be able to address across the verify_thread()
    1.24 +    __ br_null_short(G5_method, Assembler::pn, L_no_such_method);
    1.25      __ ld_ptr(G5_method, in_bytes(Method::interpreter_entry_offset()), target);
    1.26      __ jmp(target, 0);
    1.27      __ delayed()->nop();
    1.28 @@ -141,11 +145,19 @@
    1.29      // it doesn't matter, since this is interpreter code.
    1.30    }
    1.31  
    1.32 +  // Compiled case, either static or fall-through from runtime conditional
    1.33 +  __ br_null_short(G5_method, Assembler::pn, L_no_such_method);
    1.34 +
    1.35    const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_offset() :
    1.36                                                       Method::from_interpreted_offset();
    1.37    __ ld_ptr(G5_method, in_bytes(entry_offset), target);
    1.38    __ jmp(target, 0);
    1.39    __ delayed()->nop();
    1.40 +
    1.41 +  __ bind(L_no_such_method);
    1.42 +  AddressLiteral ame(StubRoutines::throw_AbstractMethodError_entry());
    1.43 +  __ jump_to(ame, temp);
    1.44 +  __ delayed()->nop();
    1.45  }
    1.46  
    1.47  void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm,
     2.1 --- a/src/cpu/x86/vm/methodHandles_x86.cpp	Mon Sep 30 15:42:39 2013 -0700
     2.2 +++ b/src/cpu/x86/vm/methodHandles_x86.cpp	Fri Sep 27 13:36:25 2013 -0400
     2.3 @@ -1,5 +1,5 @@
     2.4  /*
     2.5 - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
     2.6 + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
     2.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     2.8   *
     2.9   * This code is free software; you can redistribute it and/or modify it
    2.10 @@ -114,6 +114,11 @@
    2.11  void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp,
    2.12                                              bool for_compiler_entry) {
    2.13    assert(method == rbx, "interpreter calling convention");
    2.14 +
    2.15 +   Label L_no_such_method;
    2.16 +   __ testptr(rbx, rbx);
    2.17 +   __ jcc(Assembler::zero, L_no_such_method);
    2.18 +
    2.19    __ verify_method_ptr(method);
    2.20  
    2.21    if (!for_compiler_entry && JvmtiExport::can_post_interpreter_events()) {
    2.22 @@ -138,6 +143,9 @@
    2.23    const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_offset() :
    2.24                                                       Method::from_interpreted_offset();
    2.25    __ jmp(Address(method, entry_offset));
    2.26 +
    2.27 +  __ bind(L_no_such_method);
    2.28 +  __ jump(RuntimeAddress(StubRoutines::throw_AbstractMethodError_entry()));
    2.29  }
    2.30  
    2.31  void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm,
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/test/compiler/jsr292/methodHandleExceptions/ByteClassLoader.java	Fri Sep 27 13:36:25 2013 -0400
     3.3 @@ -0,0 +1,44 @@
     3.4 +/*
     3.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
     3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3.7 + *
     3.8 + * This code is free software; you can redistribute it and/or modify it
     3.9 + * under the terms of the GNU General Public License version 2 only, as
    3.10 + * published by the Free Software Foundation.
    3.11 + *
    3.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    3.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    3.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    3.15 + * version 2 for more details (a copy is included in the LICENSE file that
    3.16 + * accompanied this code).
    3.17 + *
    3.18 + * You should have received a copy of the GNU General Public License version
    3.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    3.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    3.21 + *
    3.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    3.23 + * or visit www.oracle.com if you need additional information or have any
    3.24 + * questions.
    3.25 + *
    3.26 + */
    3.27 +
    3.28 +/**
    3.29 + * A minimal classloader for loading bytecodes that could not result from
    3.30 + * properly compiled Java.
    3.31 + *
    3.32 + * @author dr2chase
    3.33 + */
    3.34 +public class ByteClassLoader extends ClassLoader {
    3.35 +    /**
    3.36 +     * (pre)load class name using classData for the definition.
    3.37 +     *
    3.38 +     * @param name
    3.39 +     * @param classData
    3.40 +     * @return
    3.41 +     */
    3.42 +    public Class<?> loadBytes(String name, byte[] classData) {
    3.43 +         Class<?> clazz = defineClass(name, classData, 0, classData.length);
    3.44 +                     resolveClass(clazz);
    3.45 +         return clazz;
    3.46 +    }
    3.47 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/test/compiler/jsr292/methodHandleExceptions/C.java	Fri Sep 27 13:36:25 2013 -0400
     4.3 @@ -0,0 +1,33 @@
     4.4 +/*
     4.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
     4.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4.7 + *
     4.8 + * This code is free software; you can redistribute it and/or modify it
     4.9 + * under the terms of the GNU General Public License version 2 only, as
    4.10 + * published by the Free Software Foundation.
    4.11 + *
    4.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    4.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    4.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    4.15 + * version 2 for more details (a copy is included in the LICENSE file that
    4.16 + * accompanied this code).
    4.17 + *
    4.18 + * You should have received a copy of the GNU General Public License version
    4.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    4.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    4.21 + *
    4.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    4.23 + * or visit www.oracle.com if you need additional information or have any
    4.24 + * questions.
    4.25 + *
    4.26 + */
    4.27 +
    4.28 +/**
    4.29 + * Test class -- implements I, which provides default for m, but this class
    4.30 + * declares it abstract which (should) hide the interface default, and throw
    4.31 + * an abstract method error if it is called (calling it requires bytecode hacking
    4.32 + * or inconsistent compilation).
    4.33 + */
    4.34 +public abstract class C implements I {
    4.35 +       public abstract int m();
    4.36 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/test/compiler/jsr292/methodHandleExceptions/I.java	Fri Sep 27 13:36:25 2013 -0400
     5.3 @@ -0,0 +1,27 @@
     5.4 +/*
     5.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
     5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     5.7 + *
     5.8 + * This code is free software; you can redistribute it and/or modify it
     5.9 + * under the terms of the GNU General Public License version 2 only, as
    5.10 + * published by the Free Software Foundation.
    5.11 + *
    5.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    5.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    5.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    5.15 + * version 2 for more details (a copy is included in the LICENSE file that
    5.16 + * accompanied this code).
    5.17 + *
    5.18 + * You should have received a copy of the GNU General Public License version
    5.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    5.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    5.21 + *
    5.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    5.23 + * or visit www.oracle.com if you need additional information or have any
    5.24 + * questions.
    5.25 + *
    5.26 + */
    5.27 +
    5.28 +public interface I {
    5.29 +    default public int m() { return 1; }
    5.30 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/test/compiler/jsr292/methodHandleExceptions/TestAMEnotNPE.java	Fri Sep 27 13:36:25 2013 -0400
     6.3 @@ -0,0 +1,143 @@
     6.4 +/*
     6.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
     6.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     6.7 + *
     6.8 + * This code is free software; you can redistribute it and/or modify it
     6.9 + * under the terms of the GNU General Public License version 2 only, as
    6.10 + * published by the Free Software Foundation.
    6.11 + *
    6.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    6.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    6.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    6.15 + * version 2 for more details (a copy is included in the LICENSE file that
    6.16 + * accompanied this code).
    6.17 + *
    6.18 + * You should have received a copy of the GNU General Public License version
    6.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    6.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    6.21 + *
    6.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    6.23 + * or visit www.oracle.com if you need additional information or have any
    6.24 + * questions.
    6.25 + *
    6.26 + */
    6.27 +
    6.28 +import java.lang.reflect.InvocationTargetException;
    6.29 +import jdk.internal.org.objectweb.asm.ClassWriter;
    6.30 +import jdk.internal.org.objectweb.asm.Handle;
    6.31 +import jdk.internal.org.objectweb.asm.MethodVisitor;
    6.32 +import jdk.internal.org.objectweb.asm.Opcodes;
    6.33 +
    6.34 +/**
    6.35 + * @test
    6.36 + * @bug 8025260
    6.37 + * @summary Ensure that AbstractMethodError is thrown, not NullPointerException, through MethodHandles::jump_from_method_handle code path
    6.38 + *
    6.39 + * @compile -XDignore.symbol.file ByteClassLoader.java I.java C.java TestAMEnotNPE.java
    6.40 + * @run main/othervm TestAMEnotNPE
    6.41 + */
    6.42 +
    6.43 +public class TestAMEnotNPE implements Opcodes {
    6.44 +
    6.45 +    /**
    6.46 +     * The bytes for D, a NOT abstract class extending abstract class C
    6.47 +     * without supplying an implementation for abstract method m.
    6.48 +     * There is a default method in the interface I, but it should lose to
    6.49 +     * the abstract class.
    6.50 +
    6.51 +     class D extends C {
    6.52 +        D() { super(); }
    6.53 +        // does not define m
    6.54 +     }
    6.55 +
    6.56 +     * @return
    6.57 +     * @throws Exception
    6.58 +     */
    6.59 +    public static byte[] bytesForD() throws Exception {
    6.60 +
    6.61 +        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS);
    6.62 +        MethodVisitor mv;
    6.63 +
    6.64 +        cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "D", null, "C", null);
    6.65 +
    6.66 +        {
    6.67 +            mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
    6.68 +            mv.visitCode();
    6.69 +            mv.visitVarInsn(ALOAD, 0);
    6.70 +            mv.visitMethodInsn(INVOKESPECIAL, "C", "<init>", "()V");
    6.71 +            mv.visitInsn(RETURN);
    6.72 +            mv.visitMaxs(0, 0);
    6.73 +            mv.visitEnd();
    6.74 +        }
    6.75 +        cw.visitEnd();
    6.76 +
    6.77 +        return cw.toByteArray();
    6.78 +    }
    6.79 +
    6.80 +
    6.81 +    /**
    6.82 +     * The bytecodes for an invokeExact of a particular methodHandle, I.m, invoked on a D
    6.83 +
    6.84 +        class T {
    6.85 +           T() { super(); } // boring constructor
    6.86 +           int test() {
    6.87 +              MethodHandle mh = `I.m():int`;
    6.88 +              D d = new D();
    6.89 +              return mh.invokeExact(d); // Should explode here, AbstractMethodError
    6.90 +           }
    6.91 +        }
    6.92 +
    6.93 +     * @return
    6.94 +     * @throws Exception
    6.95 +     */
    6.96 +    public static byte[] bytesForT() throws Exception {
    6.97 +
    6.98 +        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS);
    6.99 +        MethodVisitor mv;
   6.100 +
   6.101 +        cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "T", null, "java/lang/Object", null);
   6.102 +        {
   6.103 +            mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
   6.104 +            mv.visitCode();
   6.105 +            mv.visitVarInsn(ALOAD, 0);
   6.106 +            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
   6.107 +            mv.visitInsn(RETURN);
   6.108 +            mv.visitMaxs(0,0);
   6.109 +            mv.visitEnd();
   6.110 +        }
   6.111 +        {
   6.112 +            mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "test", "()I", null, null);
   6.113 +            mv.visitCode();
   6.114 +            mv.visitLdcInsn(new Handle(Opcodes.H_INVOKEINTERFACE, "I", "m", "()I"));
   6.115 +            mv.visitTypeInsn(NEW, "D");
   6.116 +            mv.visitInsn(DUP);
   6.117 +            mv.visitMethodInsn(INVOKESPECIAL, "D", "<init>", "()V");
   6.118 +            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invokeExact", "(LI;)I");
   6.119 +            mv.visitInsn(IRETURN);
   6.120 +            mv.visitMaxs(0,0);
   6.121 +            mv.visitEnd();
   6.122 +        }
   6.123 +        cw.visitEnd();
   6.124 +        return cw.toByteArray();
   6.125 +    }
   6.126 +
   6.127 +    public static void main(String args[] ) throws Throwable {
   6.128 +        ByteClassLoader bcl = new ByteClassLoader();
   6.129 +        Class<?> d = bcl.loadBytes("D", bytesForD());
   6.130 +        Class<?> t = bcl.loadBytes("T", bytesForT());
   6.131 +        try {
   6.132 +          Object result = t.getMethod("test").invoke(null);
   6.133 +          System.out.println("Expected AbstractMethodError wrapped in InvocationTargetException, saw no exception");
   6.134 +          throw new Error("Missing expected exception");
   6.135 +        } catch (InvocationTargetException e) {
   6.136 +            Throwable th = e.getCause();
   6.137 +            if (th instanceof AbstractMethodError) {
   6.138 +                th.printStackTrace(System.out);
   6.139 +                System.out.println("PASS, saw expected exception (AbstractMethodError, wrapped in InvocationTargetException).");
   6.140 +            } else {
   6.141 +                System.out.println("Expected AbstractMethodError wrapped in InvocationTargetException, saw " + th);
   6.142 +                throw th;
   6.143 +            }
   6.144 +        }
   6.145 +    }
   6.146 +}

mercurial