diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotProfilingInfo.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotProfilingInfo.java index 97deccf0dcf7c..b89849fb45439 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotProfilingInfo.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotProfilingInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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 @@ -22,219 +22,25 @@ */ package jdk.vm.ci.hotspot; -import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; - -import jdk.vm.ci.meta.DeoptimizationReason; -import jdk.vm.ci.meta.JavaMethodProfile; -import jdk.vm.ci.meta.JavaTypeProfile; import jdk.vm.ci.meta.ProfilingInfo; -import jdk.vm.ci.meta.TriState; - -final class HotSpotProfilingInfo implements ProfilingInfo { - - private final HotSpotMethodData methodData; - private final HotSpotResolvedJavaMethod method; - - private boolean isMature; - private int position; - private int hintPosition; - private int hintBCI; - private HotSpotMethodDataAccessor dataAccessor; - - private boolean includeNormal; - private boolean includeOSR; - - HotSpotProfilingInfo(HotSpotMethodData methodData, HotSpotResolvedJavaMethod method, boolean includeNormal, boolean includeOSR) { - this.methodData = methodData; - this.method = method; - if (!method.getDeclaringClass().isLinked()) { - throw new IllegalArgumentException(method.format("%H.%n(%p) must be linked")); - } - this.includeNormal = includeNormal; - this.includeOSR = includeOSR; - this.isMature = methodData.isProfileMature(); - hintPosition = 0; - hintBCI = -1; - } - - @Override - public int getCodeSize() { - return method.getCodeSize(); - } - - public int getDecompileCount() { - return methodData.getDecompileCount(); - } - - public int getOverflowRecompileCount() { - return methodData.getOverflowRecompileCount(); - } - - public int getOverflowTrapCount() { - return methodData.getOverflowTrapCount(); - } - - @Override - public JavaTypeProfile getTypeProfile(int bci) { - if (!isMature) { - return null; - } - findBCI(bci); - return dataAccessor.getTypeProfile(methodData, position); - } - - @Override - public JavaMethodProfile getMethodProfile(int bci) { - if (!isMature) { - return null; - } - findBCI(bci); - return dataAccessor.getMethodProfile(methodData, position); - } - - @Override - public double getBranchTakenProbability(int bci) { - if (!isMature) { - return -1; - } - findBCI(bci); - return dataAccessor.getBranchTakenProbability(methodData, position); - } - - @Override - public double[] getSwitchProbabilities(int bci) { - if (!isMature) { - return null; - } - findBCI(bci); - return dataAccessor.getSwitchProbabilities(methodData, position); - } - - @Override - public TriState getExceptionSeen(int bci) { - if (!findBCI(bci)) { - // There might data in the extra data section but all accesses to that memory must be - // under a lock so go into VM to get the data. - int exceptionSeen = compilerToVM().methodDataExceptionSeen(methodData.methodDataPointer, bci); - if (exceptionSeen == -1) { - return TriState.UNKNOWN; - } - return TriState.get(exceptionSeen != 0); - } - return dataAccessor.getExceptionSeen(methodData, position); - } - - @Override - public TriState getNullSeen(int bci) { - findBCI(bci); - return dataAccessor.getNullSeen(methodData, position); - } - @Override - public int getExecutionCount(int bci) { - if (!isMature) { - return -1; - } - findBCI(bci); - return dataAccessor.getExecutionCount(methodData, position); - } - - @Override - public int getDeoptimizationCount(DeoptimizationReason reason) { - int count = 0; - if (includeNormal) { - count += methodData.getDeoptimizationCount(reason); - } - if (includeOSR) { - count += methodData.getOSRDeoptimizationCount(reason); - } - return count; - } - - private boolean findBCI(int targetBCI) { - assert targetBCI >= 0 : "invalid BCI"; - - if (methodData.hasNormalData()) { - int currentPosition = targetBCI < hintBCI ? 0 : hintPosition; - HotSpotMethodDataAccessor currentAccessor; - while ((currentAccessor = methodData.getNormalData(currentPosition)) != null) { - int currentBCI = currentAccessor.getBCI(methodData, currentPosition); - if (currentBCI == targetBCI) { - normalDataFound(currentAccessor, currentPosition, currentBCI); - return true; - } else if (currentBCI > targetBCI) { - break; - } - currentPosition = currentPosition + currentAccessor.getSize(methodData, currentPosition); - } - } - noDataFound(false); - return false; - } - - private void normalDataFound(HotSpotMethodDataAccessor data, int pos, int bci) { - setCurrentData(data, pos); - this.hintPosition = position; - this.hintBCI = bci; - } - - private void noDataFound(boolean exceptionPossiblyNotRecorded) { - HotSpotMethodDataAccessor accessor = HotSpotMethodData.getNoDataAccessor(exceptionPossiblyNotRecorded); - setCurrentData(accessor, -1); - } - - private void setCurrentData(HotSpotMethodDataAccessor dataAccessor, int position) { - this.dataAccessor = dataAccessor; - this.position = position; - } - - @Override - public boolean isMature() { - return isMature; - } - - public void ignoreMature() { - isMature = true; - } - - @Override - public String toString() { - return "HotSpotProfilingInfo<" + this.toString(null, "; ") + ">"; - } - - @Override - public void setMature() { - isMature = true; - } +/** + * Extends {@link ProfilingInfo} with HotSpot specific profiling info. + */ +public interface HotSpotProfilingInfo extends ProfilingInfo { /** - * {@code MethodData::_jvmci_ir_size} (currently) supports at most one JVMCI compiler IR type - * which will be determined by the first JVMCI compiler that calls - * {@link #setCompilerIRSize(Class, int)}. + * Returns {@code MethodData::_compiler_counters._nof_decompiles}. */ - private static volatile Class supportedCompilerIRType; + int getDecompileCount(); - @Override - public boolean setCompilerIRSize(Class irType, int size) { - if (supportedCompilerIRType == null) { - synchronized (HotSpotProfilingInfo.class) { - if (supportedCompilerIRType == null) { - supportedCompilerIRType = irType; - } - } - } - if (supportedCompilerIRType != irType) { - return false; - } - methodData.setCompiledIRSize(size); - return true; - } + /** + * Returns {@code MethodData::_compiler_counters._nof_overflow_recompiles}. + */ + int getOverflowRecompileCount(); - @Override - public int getCompilerIRSize(Class irType) { - if (irType == supportedCompilerIRType) { - return methodData.getCompiledIRSize(); - } - return -1; - } + /** + * Returns {@code MethodData::_compiler_counters._nof_overflow_traps}. + */ + int getOverflowTrapCount(); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotProfilingInfoImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotProfilingInfoImpl.java new file mode 100644 index 0000000000000..3dcdedef28227 --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotProfilingInfoImpl.java @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2012, 2025, 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. + * + * 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. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; + +import jdk.vm.ci.meta.DeoptimizationReason; +import jdk.vm.ci.meta.JavaMethodProfile; +import jdk.vm.ci.meta.JavaTypeProfile; +import jdk.vm.ci.meta.ProfilingInfo; +import jdk.vm.ci.meta.TriState; + +final class HotSpotProfilingInfoImpl implements HotSpotProfilingInfo { + + private final HotSpotMethodData methodData; + private final HotSpotResolvedJavaMethod method; + + private boolean isMature; + private int position; + private int hintPosition; + private int hintBCI; + private HotSpotMethodDataAccessor dataAccessor; + + private boolean includeNormal; + private boolean includeOSR; + + HotSpotProfilingInfoImpl(HotSpotMethodData methodData, HotSpotResolvedJavaMethod method, boolean includeNormal, boolean includeOSR) { + this.methodData = methodData; + this.method = method; + if (!method.getDeclaringClass().isLinked()) { + throw new IllegalArgumentException(method.format("%H.%n(%p) must be linked")); + } + this.includeNormal = includeNormal; + this.includeOSR = includeOSR; + this.isMature = methodData.isProfileMature(); + hintPosition = 0; + hintBCI = -1; + } + + @Override + public int getCodeSize() { + return method.getCodeSize(); + } + + @Override + public int getDecompileCount() { + return methodData.getDecompileCount(); + } + + @Override + public int getOverflowRecompileCount() { + return methodData.getOverflowRecompileCount(); + } + + @Override + public int getOverflowTrapCount() { + return methodData.getOverflowTrapCount(); + } + + @Override + public JavaTypeProfile getTypeProfile(int bci) { + if (!isMature) { + return null; + } + findBCI(bci); + return dataAccessor.getTypeProfile(methodData, position); + } + + @Override + public JavaMethodProfile getMethodProfile(int bci) { + if (!isMature) { + return null; + } + findBCI(bci); + return dataAccessor.getMethodProfile(methodData, position); + } + + @Override + public double getBranchTakenProbability(int bci) { + if (!isMature) { + return -1; + } + findBCI(bci); + return dataAccessor.getBranchTakenProbability(methodData, position); + } + + @Override + public double[] getSwitchProbabilities(int bci) { + if (!isMature) { + return null; + } + findBCI(bci); + return dataAccessor.getSwitchProbabilities(methodData, position); + } + + @Override + public TriState getExceptionSeen(int bci) { + if (!findBCI(bci)) { + // There might data in the extra data section but all accesses to that memory must be + // under a lock so go into VM to get the data. + int exceptionSeen = compilerToVM().methodDataExceptionSeen(methodData.methodDataPointer, bci); + if (exceptionSeen == -1) { + return TriState.UNKNOWN; + } + return TriState.get(exceptionSeen != 0); + } + return dataAccessor.getExceptionSeen(methodData, position); + } + + @Override + public TriState getNullSeen(int bci) { + findBCI(bci); + return dataAccessor.getNullSeen(methodData, position); + } + + @Override + public int getExecutionCount(int bci) { + if (!isMature) { + return -1; + } + findBCI(bci); + return dataAccessor.getExecutionCount(methodData, position); + } + + @Override + public int getDeoptimizationCount(DeoptimizationReason reason) { + int count = 0; + if (includeNormal) { + count += methodData.getDeoptimizationCount(reason); + } + if (includeOSR) { + count += methodData.getOSRDeoptimizationCount(reason); + } + return count; + } + + private boolean findBCI(int targetBCI) { + assert targetBCI >= 0 : "invalid BCI"; + + if (methodData.hasNormalData()) { + int currentPosition = targetBCI < hintBCI ? 0 : hintPosition; + HotSpotMethodDataAccessor currentAccessor; + while ((currentAccessor = methodData.getNormalData(currentPosition)) != null) { + int currentBCI = currentAccessor.getBCI(methodData, currentPosition); + if (currentBCI == targetBCI) { + normalDataFound(currentAccessor, currentPosition, currentBCI); + return true; + } else if (currentBCI > targetBCI) { + break; + } + currentPosition = currentPosition + currentAccessor.getSize(methodData, currentPosition); + } + } + noDataFound(false); + return false; + } + + private void normalDataFound(HotSpotMethodDataAccessor data, int pos, int bci) { + setCurrentData(data, pos); + this.hintPosition = position; + this.hintBCI = bci; + } + + private void noDataFound(boolean exceptionPossiblyNotRecorded) { + HotSpotMethodDataAccessor accessor = HotSpotMethodData.getNoDataAccessor(exceptionPossiblyNotRecorded); + setCurrentData(accessor, -1); + } + + private void setCurrentData(HotSpotMethodDataAccessor dataAccessor, int position) { + this.dataAccessor = dataAccessor; + this.position = position; + } + + @Override + public boolean isMature() { + return isMature; + } + + public void ignoreMature() { + isMature = true; + } + + @Override + public String toString() { + return "HotSpotProfilingInfo<" + this.toString(null, "; ") + ">"; + } + + @Override + public void setMature() { + isMature = true; + } + + /** + * {@code MethodData::_jvmci_ir_size} (currently) supports at most one JVMCI compiler IR type + * which will be determined by the first JVMCI compiler that calls + * {@link #setCompilerIRSize(Class, int)}. + */ + private static volatile Class supportedCompilerIRType; + + @Override + public boolean setCompilerIRSize(Class irType, int size) { + if (supportedCompilerIRType == null) { + synchronized (HotSpotProfilingInfoImpl.class) { + if (supportedCompilerIRType == null) { + supportedCompilerIRType = irType; + } + } + } + if (supportedCompilerIRType != irType) { + return false; + } + methodData.setCompiledIRSize(size); + return true; + } + + @Override + public int getCompilerIRSize(Class irType) { + if (irType == supportedCompilerIRType) { + return methodData.getCompiledIRSize(); + } + return -1; + } +} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index 4fbd479602437..59f5320cc5479 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -489,7 +489,7 @@ public ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR) // case of a deoptimization. info = DefaultProfilingInfo.get(TriState.FALSE); } else { - info = new HotSpotProfilingInfo(methodData, this, includeNormal, includeOSR); + info = new HotSpotProfilingInfoImpl(methodData, this, includeNormal, includeOSR); } return info; } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/DefaultProfilingInfo.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/DefaultProfilingInfo.java index a0df0a2e8096d..4fa945a896945 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/DefaultProfilingInfo.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/DefaultProfilingInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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 @@ -28,8 +28,11 @@ */ public final class DefaultProfilingInfo implements ProfilingInfo { - private static final ProfilingInfo[] NO_PROFILING_INFO = new ProfilingInfo[]{new DefaultProfilingInfo(TriState.TRUE), new DefaultProfilingInfo(TriState.FALSE), - new DefaultProfilingInfo(TriState.UNKNOWN)}; + private static final ProfilingInfo[] NO_PROFILING_INFO = { + new DefaultProfilingInfo(TriState.TRUE), + new DefaultProfilingInfo(TriState.FALSE), + new DefaultProfilingInfo(TriState.UNKNOWN) + }; private final TriState exceptionSeen; diff --git a/test/hotspot/jtreg/compiler/jvmci/meta/ProfilingInfoTest.java b/test/hotspot/jtreg/compiler/jvmci/meta/ProfilingInfoTest.java index fab61b299adce..278d52322d924 100644 --- a/test/hotspot/jtreg/compiler/jvmci/meta/ProfilingInfoTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/meta/ProfilingInfoTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, 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 @@ -32,6 +32,7 @@ * @requires vm.compMode != "Xcomp" * @requires vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel > 1 * @modules jdk.internal.vm.ci/jdk.vm.ci.meta + * jdk.internal.vm.ci/jdk.vm.ci.hotspot * jdk.internal.vm.ci/jdk.vm.ci.runtime * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler -Xbootclasspath/a:. compiler.jvmci.meta.ProfilingInfoTest */ @@ -47,6 +48,7 @@ import org.junit.Assume; import org.junit.Test; +import jdk.vm.ci.hotspot.HotSpotProfilingInfo; import jdk.vm.ci.meta.JavaTypeProfile; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ProfilingInfo; @@ -203,6 +205,15 @@ private void testTypeProfile(String testSnippet, int bci) { resetProfile(testSnippet); typeProfile = info.getTypeProfile(bci); Assert.assertNull(typeProfile); + + // Basic test that the counters are non-negative + HotSpotProfilingInfo hsInfo = (HotSpotProfilingInfo) info; + int count = hsInfo.getDecompileCount(); + Assert.assertTrue("count = " + count, count >= 0); + count = hsInfo.getOverflowRecompileCount(); + Assert.assertTrue("count = " + count, count >= 0); + count = hsInfo.getOverflowTrapCount(); + Assert.assertTrue("count = " + count, count >= 0); } public ProfilingInfoTest() {