Path: blob/master/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java
41153 views
/*1* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test NullCheckDroppingsTest25* @bug 805449226* @summary Casting can result in redundant null checks in generated code27* @requires vm.hasJFR28* @requires vm.flavor == "server" & !vm.emulatedClient & !vm.graal.enabled29* @library /test/lib30* @modules java.base/jdk.internal.misc31* java.management32*33* @build sun.hotspot.WhiteBox34* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox35* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI36* -Xmixed -XX:-BackgroundCompilation -XX:-TieredCompilation -XX:CompileThreshold=100037* -XX:CompileCommand=exclude,compiler.intrinsics.klass.CastNullCheckDroppingsTest::runTest38* compiler.intrinsics.klass.CastNullCheckDroppingsTest39*/4041package compiler.intrinsics.klass;4243import jdk.jfr.Recording;44import jdk.jfr.consumer.RecordedEvent;45import jdk.test.lib.Platform;46import jdk.test.lib.jfr.EventNames;47import jdk.test.lib.jfr.Events;48import sun.hotspot.WhiteBox;49import sun.hotspot.code.NMethod;5051import java.io.IOException;52import java.lang.invoke.MethodHandle;53import java.lang.invoke.MethodHandles;54import java.lang.invoke.MethodType;55import java.lang.reflect.Method;56import java.util.List;57import java.util.function.BiFunction;5859public class CastNullCheckDroppingsTest {6061private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();6263static final BiFunction<Class, Object, Object> fCast = (c, o) -> c.cast(o);6465static final MethodHandle SET_SSINK;66static final MethodHandle MH_CAST;6768static {69try {70SET_SSINK = MethodHandles.lookup().findSetter(CastNullCheckDroppingsTest.class, "ssink", String.class);71MH_CAST = MethodHandles.lookup().findVirtual(Class.class,72"cast",73MethodType.methodType(Object.class, Object.class));74}75catch (Exception e) {76throw new Error(e);77}78}7980static volatile String svalue = "A";81static volatile Object onull = null;82static volatile Integer iobj = new Integer(0);83static volatile int[] arr = new int[2];84static volatile Class objClass = String.class;85static volatile Class nullClass = null;8687String ssink;88Integer isink;89int[] asink;9091public static void main(String[] args) throws Exception {92if (!Platform.isServer() || Platform.isEmulatedClient()) {93throw new Error("TESTBUG: Not server mode");94}95// Make sure background compilation is disabled96if (WHITE_BOX.getBooleanVMFlag("BackgroundCompilation")) {97throw new Error("TESTBUG: Background compilation enabled");98}99// Make sure Tiered compilation is disabled100if (WHITE_BOX.getBooleanVMFlag("TieredCompilation")) {101throw new Error("TESTBUG: Tiered compilation enabled");102}103104Method methodClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCast", String.class);105Method methodMHCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testMHCast", String.class);106Method methodMHSetter = CastNullCheckDroppingsTest.class.getDeclaredMethod("testMHSetter", String.class);107Method methodFunction = CastNullCheckDroppingsTest.class.getDeclaredMethod("testFunction", String.class);108109CastNullCheckDroppingsTest t = new CastNullCheckDroppingsTest();110t.runTest(methodClassCast, false, svalue);111t.runTest(methodMHCast, false, svalue);112t.runTest(methodMHSetter, false, svalue);113t.runTest(methodFunction, false, svalue);114115// Edge cases116Method methodClassCastNull = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCastNull", String.class);117Method methodNullClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testNullClassCast", String.class);118Method methodClassCastObj = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCastObj", Object.class);119Method methodObjClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testObjClassCast", String.class);120Method methodClassCastInt = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCastInt", Object.class);121Method methodIntClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testIntClassCast", Object.class);122Method methodClassCastint = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCastint", Object.class);123Method methodintClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testintClassCast", Object.class);124Method methodClassCastPrim = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCastPrim", Object.class);125Method methodPrimClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testPrimClassCast", Object.class);126Method methodVarClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testVarClassCast", Class.class);127128t.runTest(methodClassCastNull, false, svalue);129t.runTest(methodNullClassCast, false, svalue);130t.runTest(methodClassCastObj, false, svalue);131t.runTest(methodObjClassCast, true, svalue);132t.runTest(methodClassCastInt, false, svalue);133t.runTest(methodIntClassCast, true, svalue);134t.runTest(methodClassCastint, false, svalue);135t.runTest(methodintClassCast, false, svalue);136t.runTest(methodClassCastPrim, false, svalue);137t.runTest(methodPrimClassCast, true, svalue);138t.runTest(methodVarClassCast, true, objClass);139}140141void testClassCast(String s) {142try {143ssink = String.class.cast(s);144} catch (Throwable t) {145throw new Error(t);146}147}148149void testClassCastNull(String s) {150try {151ssink = String.class.cast(null);152} catch (Throwable t) {153throw new Error(t);154}155}156157void testNullClassCast(String s) {158try {159ssink = (String)nullClass.cast(s);160throw new AssertionError("NullPointerException is not thrown");161} catch (NullPointerException t) {162// Ignore NullPointerException163} catch (Throwable t) {164throw new Error(t);165}166}167168void testClassCastObj(Object s) {169try {170ssink = String.class.cast(s);171} catch (Throwable t) {172throw new Error(t);173}174}175176void testObjClassCast(String s) {177try {178ssink = (String)objClass.cast(s);179} catch (Throwable t) {180throw new Error(t);181}182}183184void testVarClassCast(Class cl) {185try {186ssink = (String)cl.cast(svalue);187if (cl == null) {188throw new AssertionError("NullPointerException is not thrown");189}190} catch (NullPointerException t) {191// Ignore NullPointerException192} catch (Throwable t) {193throw new Error(t);194}195}196197void testClassCastInt(Object s) {198try {199ssink = String.class.cast(iobj);200throw new AssertionError("ClassCastException is not thrown");201} catch (ClassCastException t) {202// Ignore ClassCastException: Cannot cast java.lang.Integer to java.lang.String203} catch (Throwable t) {204throw new Error(t);205}206}207208void testIntClassCast(Object s) {209try {210isink = Integer.class.cast(s);211if (s != null) {212throw new AssertionError("ClassCastException is not thrown");213}214} catch (ClassCastException t) {215// Ignore ClassCastException: Cannot cast java.lang.String to java.lang.Integer216} catch (Throwable t) {217throw new Error(t);218}219}220221void testClassCastint(Object s) {222try {223ssink = String.class.cast(45);224throw new AssertionError("ClassCastException is not thrown");225} catch (ClassCastException t) {226// Ignore ClassCastException: Cannot cast java.lang.Integer to java.lang.String227} catch (Throwable t) {228throw new Error(t);229}230}231232void testintClassCast(Object s) {233try {234isink = int.class.cast(s);235if (s != null) {236throw new AssertionError("ClassCastException is not thrown");237}238} catch (ClassCastException t) {239// Ignore ClassCastException: Cannot cast java.lang.String to java.lang.Integer240} catch (Throwable t) {241throw new Error(t);242}243}244245void testClassCastPrim(Object s) {246try {247ssink = String.class.cast(arr);248throw new AssertionError("ClassCastException is not thrown");249} catch (ClassCastException t) {250// Ignore ClassCastException: Cannot cast [I to java.lang.String251} catch (Throwable t) {252throw new Error(t);253}254}255256void testPrimClassCast(Object s) {257try {258asink = int[].class.cast(s);259if (s != null) {260throw new AssertionError("ClassCastException is not thrown");261}262} catch (ClassCastException t) {263// Ignore ClassCastException: Cannot cast java.lang.String to [I264} catch (Throwable t) {265throw new Error(t);266}267}268269void testMHCast(String s) {270try {271ssink = (String) (Object) MH_CAST.invokeExact(String.class, (Object) s);272} catch (Throwable t) {273throw new Error(t);274}275}276277void testMHSetter(String s) {278try {279SET_SSINK.invokeExact(this, s);280} catch (Throwable t) {281throw new Error(t);282}283}284285void testFunction(String s) {286try {287ssink = (String) fCast.apply(String.class, s);288} catch (Throwable t) {289throw new Error(t);290}291}292293void runTest(Method method, boolean deopt, Object value) {294if (method == null) {295throw new AssertionError("method was not found");296}297// Ensure method is compiled298WHITE_BOX.testSetDontInlineMethod(method, true);299Recording recording = new Recording();300recording.enable(EventNames.Deoptimization);301recording.start();302303for (int i = 0; i < 3000; i++) {304try {305method.invoke(this, value);306} catch (Exception e) {307throw new Error("Unexpected exception: ", e);308}309}310NMethod nm = getNMethod(method);311312// Passing null should cause a de-optimization313// if method is compiled with a null-check.314try {315method.invoke(this, onull);316} catch (Exception e) {317throw new Error("Unexpected exception: ", e);318}319recording.stop();320List<RecordedEvent> events;321try {322events = Events.fromRecording(recording);323} catch (IOException e) {324throw new Error("failed to read jfr events", e);325}326327checkDeoptimization(events, nm.compile_id, deopt);328329if (!deopt) {330checkNoRecompilation(method, nm);331}332}333334static NMethod getNMethod(Method test) {335// Because background compilation is disabled, method should now be compiled336if (!WHITE_BOX.isMethodCompiled(test)) {337throw new AssertionError(test + " not compiled");338}339340NMethod nm = NMethod.get(test, false); // not OSR nmethod341if (nm == null) {342throw new AssertionError(test + " missing nmethod?");343}344if (nm.comp_level != 4) {345throw new AssertionError(test + " compiled by not C2: " + nm);346}347return nm;348}349350static void checkDeoptimization(List<RecordedEvent> events, int compilerId, boolean mustExist) {351boolean exist = events.stream()352.filter(e -> e.getEventType().getName().equals(EventNames.Deoptimization))353.anyMatch(e -> compilerId == Events.assertField(e, "compileId").<Integer>getValue());354355if (exist != mustExist) {356System.err.println("events:");357System.err.println(events);358throw new AssertionError("compilation must " + (mustExist ? "" : " not ") + " got deoptimized");359}360361if (mustExist && events.stream()362.filter(e -> e.getEventType().getName().equals(EventNames.Deoptimization))363.filter(e -> compilerId == Events.assertField(e, "compileId").<Integer>getValue())364.noneMatch(e -> "null_check".equals(Events.assertField(e, "reason").getValue()))) {365System.err.println("events:");366System.err.println(events);367throw new AssertionError("no deoptimizations due to null_check found");368}369370}371372static void checkNoRecompilation(Method method, NMethod nmOrig) {373NMethod nm = NMethod.get(method, false); // not OSR nmethod374if (nm == null) {375throw new AssertionError(method + " missing nmethod?");376}377if (nm.comp_level != 4) {378throw new AssertionError(method + " compiled by not C2: " + nm);379}380if (nm.compile_id != nmOrig.compile_id) {381throw new AssertionError(method + " was recompiled: old nmethod=" + nmOrig + ", new nmethod=" + nm);382}383}384}385386387