Skip to content

Commit

Permalink
8129092: compiler/intrinsics/classcast/NullCheckDroppingsTest.java te…
Browse files Browse the repository at this point in the history
…stVarClassCast() can fail

Reviewed-by: kvn
  • Loading branch information
iignatev committed Dec 4, 2019
1 parent b1c42a1 commit 503a960
Showing 1 changed file with 69 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2019, 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
Expand All @@ -25,6 +25,7 @@
* @test NullCheckDroppingsTest
* @bug 8054492
* @summary Casting can result in redundant null checks in generated code
* @requires vm.hasJFR
* @requires vm.flavor == "server" & !vm.emulatedClient & !vm.graal.enabled
* @library /test/lib
* @modules java.base/jdk.internal.misc
Expand All @@ -41,14 +42,20 @@

package compiler.intrinsics.klass;

import jdk.jfr.Recording;
import jdk.jfr.consumer.RecordedEvent;
import jdk.test.lib.Platform;
import jdk.test.lib.jfr.EventNames;
import jdk.test.lib.jfr.Events;
import sun.hotspot.WhiteBox;
import sun.hotspot.code.NMethod;

import java.io.IOException;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.List;
import java.util.function.BiFunction;

public class CastNullCheckDroppingsTest {
Expand All @@ -73,7 +80,7 @@ public class CastNullCheckDroppingsTest {
}

static volatile String svalue = "A";
static volatile String snull = null;
static volatile Object onull = null;
static volatile Integer iobj = new Integer(0);
static volatile int[] arr = new int[2];
static volatile Class objClass = String.class;
Expand Down Expand Up @@ -102,35 +109,35 @@ public static void main(String[] args) throws Exception {
Method methodFunction = CastNullCheckDroppingsTest.class.getDeclaredMethod("testFunction", String.class);

CastNullCheckDroppingsTest t = new CastNullCheckDroppingsTest();
t.runTest(methodClassCast, false);
t.runTest(methodMHCast, false);
t.runTest(methodMHSetter, false);
t.runTest(methodFunction, false);
t.runTest(methodClassCast, false, svalue);
t.runTest(methodMHCast, false, svalue);
t.runTest(methodMHSetter, false, svalue);
t.runTest(methodFunction, false, svalue);

// Edge cases
Method methodClassCastNull = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCastNull", String.class);
Method methodNullClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testNullClassCast", String.class);
Method methodClassCastObj = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCastObj", Object.class);
Method methodObjClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testObjClassCast", String.class);
Method methodVarClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testVarClassCast", String.class);
Method methodClassCastInt = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCastInt", Object.class);
Method methodIntClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testIntClassCast", Object.class);
Method methodClassCastint = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCastint", Object.class);
Method methodintClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testintClassCast", Object.class);
Method methodClassCastPrim = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCastPrim", Object.class);
Method methodPrimClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testPrimClassCast", Object.class);

t.runTest(methodClassCastNull, false);
t.runTest(methodNullClassCast, false);
t.runTest(methodClassCastObj, false);
t.runTest(methodObjClassCast, true);
t.runTest(methodVarClassCast, true);
t.runTest(methodClassCastInt, false);
t.runTest(methodIntClassCast, true);
t.runTest(methodClassCastint, false);
t.runTest(methodintClassCast, false);
t.runTest(methodClassCastPrim, false);
t.runTest(methodPrimClassCast, true);
Method methodVarClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testVarClassCast", Class.class);

t.runTest(methodClassCastNull, false, svalue);
t.runTest(methodNullClassCast, false, svalue);
t.runTest(methodClassCastObj, false, svalue);
t.runTest(methodObjClassCast, true, svalue);
t.runTest(methodClassCastInt, false, svalue);
t.runTest(methodIntClassCast, true, svalue);
t.runTest(methodClassCastint, false, svalue);
t.runTest(methodintClassCast, false, svalue);
t.runTest(methodClassCastPrim, false, svalue);
t.runTest(methodPrimClassCast, true, svalue);
t.runTest(methodVarClassCast, true, objClass);
}

void testClassCast(String s) {
Expand Down Expand Up @@ -176,11 +183,10 @@ void testObjClassCast(String s) {
}
}

void testVarClassCast(String s) {
Class cl = (s == null) ? null : String.class;
void testVarClassCast(Class cl) {
try {
ssink = (String)cl.cast(svalue);
if (s == null) {
if (cl == null) {
throw new AssertionError("NullPointerException is not thrown");
}
} catch (NullPointerException t) {
Expand Down Expand Up @@ -286,15 +292,19 @@ void testFunction(String s) {
}
}

void runTest(Method method, boolean deopt) {
void runTest(Method method, boolean deopt, Object value) {
if (method == null) {
throw new AssertionError("method was not found");
}
// Ensure method is compiled
WHITE_BOX.testSetDontInlineMethod(method, true);
Recording recording = new Recording();
recording.enable(EventNames.Deoptimization);
recording.start();

for (int i = 0; i < 3000; i++) {
try {
method.invoke(this, svalue);
method.invoke(this, value);
} catch (Exception e) {
throw new Error("Unexpected exception: ", e);
}
Expand All @@ -304,11 +314,23 @@ void runTest(Method method, boolean deopt) {
// Passing null should cause a de-optimization
// if method is compiled with a null-check.
try {
method.invoke(this, snull);
method.invoke(this, onull);
} catch (Exception e) {
throw new Error("Unexpected exception: ", e);
}
checkDeoptimization(method, nm, deopt);
recording.stop();
List<RecordedEvent> events;
try {
events = Events.fromRecording(recording);
} catch (IOException e) {
throw new Error("failed to read jfr events", e);
}

checkDeoptimization(events, nm.compile_id, deopt);

if (!deopt) {
checkNoRecompilation(method, nm);
}
}

static NMethod getNMethod(Method test) {
Expand All @@ -327,15 +349,29 @@ static NMethod getNMethod(Method test) {
return nm;
}

static void checkDeoptimization(Method method, NMethod nmOrig, boolean deopt) {
// Check deoptimization event (intrinsic Class.cast() works).
if (WHITE_BOX.isMethodCompiled(method) == deopt) {
throw new AssertionError(method + " was" + (deopt ? " not" : "") + " deoptimized");
static void checkDeoptimization(List<RecordedEvent> events, int compilerId, boolean mustExist) {
boolean exist = events.stream()
.filter(e -> e.getEventType().getName().equals(EventNames.Deoptimization))
.anyMatch(e -> compilerId == Events.assertField(e, "compileId").<Integer>getValue());

if (exist != mustExist) {
System.err.println("events:");
System.err.println(events);
throw new AssertionError("compilation must " + (mustExist ? "" : " not ") + " got deoptimized");
}
if (deopt) {
return;

if (mustExist && events.stream()
.filter(e -> e.getEventType().getName().equals(EventNames.Deoptimization))
.filter(e -> compilerId == Events.assertField(e, "compileId").<Integer>getValue())
.noneMatch(e -> "null_check".equals(Events.assertField(e, "reason").getValue()))) {
System.err.println("events:");
System.err.println(events);
throw new AssertionError("no deoptimizations due to null_check found");
}
// Ensure no recompilation when no deoptimization is expected.

}

static void checkNoRecompilation(Method method, NMethod nmOrig) {
NMethod nm = NMethod.get(method, false); // not OSR nmethod
if (nm == null) {
throw new AssertionError(method + " missing nmethod?");
Expand Down

0 comments on commit 503a960

Please sign in to comment.