8073432: Object.getClass() throws stackless NPE, due to C2 intrinsic

Javac should generate NPE checks using Objects.requireNonNull if -target >= 7

Reviewed-by: jlahoda
This commit is contained in:
Aleksey Shipilev 2015-03-05 15:03:07 +00:00 committed by Maurizio Cimadamore
parent 1114c26925
commit 89cc77c8cb
5 changed files with 85 additions and 2 deletions

View File

@ -147,6 +147,7 @@ public class Symtab {
/** Predefined types.
*/
public final Type objectType;
public final Type objectsType;
public final Type classType;
public final Type classLoaderType;
public final Type stringType;
@ -408,6 +409,7 @@ public class Symtab {
// Enter predefined classes.
objectType = enterClass("java.lang.Object");
objectsType = enterClass("java.util.Objects");
classType = enterClass("java.lang.Class");
stringType = enterClass("java.lang.String");
stringBufferType = enterClass("java.lang.StringBuffer");

View File

@ -124,6 +124,7 @@ public class Gen extends JCTree.Visitor {
genCrt = options.isSet(XJCOV);
debugCode = options.isSet("debugcode");
allowInvokedynamic = target.hasInvokedynamic() || options.isSet("invokedynamic");
allowBetterNullChecks = target.hasObjects();
pool = new Pool(types);
// ignore cldc because we cannot have both stackmap formats
@ -150,6 +151,7 @@ public class Gen extends JCTree.Visitor {
private final boolean genCrt;
private final boolean debugCode;
private final boolean allowInvokedynamic;
private final boolean allowBetterNullChecks;
/** Default limit of (approximate) size of finalizer to inline.
* Zero means always use jsr. 100 or greater means never use
@ -1983,8 +1985,13 @@ public class Gen extends JCTree.Visitor {
/** Generate a null check from the object value at stack top. */
private void genNullCheck(DiagnosticPosition pos) {
callMethod(pos, syms.objectType, names.getClass,
List.<Type>nil(), false);
if (allowBetterNullChecks) {
callMethod(pos, syms.objectsType, names.requireNonNull,
List.of(syms.objectType), true);
} else {
callMethod(pos, syms.objectType, names.getClass,
List.<Type>nil(), false);
}
code.emitop0(pop);
}

View File

@ -121,6 +121,12 @@ public enum Target {
return compareTo(JDK1_7) >= 0;
}
/** Does the target JDK contains the java.util.Objects class?
*/
public boolean hasObjects() {
return compareTo(JDK1_7) >= 0;
}
/** Does the VM support polymorphic method handle invocation?
* Affects the linkage information output to the classfile.
* An alias for {@code hasInvokedynamic}, since all the JSR 292 features appear together.

View File

@ -171,6 +171,7 @@ public class Names {
public final Name deprecated;
public final Name ex;
public final Name package_info;
public final Name requireNonNull;
//lambda-related
public final Name lambda;
@ -307,6 +308,7 @@ public class Names {
deprecated = fromString("deprecated");
ex = fromString("ex");
package_info = fromString("package-info");
requireNonNull = fromString("requireNonNull");
//lambda-related
lambda = fromString("lambda$");

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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
* @bug 8074306
* @summary NULLCHK is emitted as Object.getClass
* @compile -source 6 -target 6 TestSyntheticNullChecks.java
* @run main TestSyntheticNullChecks 6
* @clean TestSyntheticNullChecks*
* @compile -source 7 -target 7 TestSyntheticNullChecks.java
* @run main TestSyntheticNullChecks 7
* @clean TestSyntheticNullChecks*
* @compile TestSyntheticNullChecks.java
* @run main TestSyntheticNullChecks 9
*/
public class TestSyntheticNullChecks {
class Inner { }
static void generateSyntheticNPE(TestSyntheticNullChecks outer) {
outer.new Inner(); //javac will generate a synthetic NPE check for 'outer'
}
public static void main(String[] args) {
int version = Integer.valueOf(args[0]);
boolean useObjects = version >= 7;
try {
generateSyntheticNPE(null);
} catch (NullPointerException npe) {
boolean hasRequireNotNull = false;
for (StackTraceElement e : npe.getStackTrace()) {
if (e.getClassName().equals("java.util.Objects") &&
e.getMethodName().equals("requireNonNull")) {
hasRequireNotNull = true;
break;
}
}
if (hasRequireNotNull != useObjects) {
throw new AssertionError();
}
}
}
}