This software and related documentation are provided under a license agreement containing restrictions on use and disclosure and are protected by intellectual property laws. Except as expressly permitted in your license agreement or allowed by law, you may not use, copy, reproduce, translate, broadcast, modify, license, transmit, distribute, exhibit, perform, publish, or display any part, in any form, or by any means. Reverse engineering, disassembly, or decompilation of this software, unless required by law for interoperability, is prohibited.
The information contained herein is subject to change without notice and is not warranted to be error-free. If you find any errors, please report them to us in writing.
If this is software or related documentation that is delivered to the U.S. Government or anyone licensing it on behalf of the U.S. Government, the following notice is applicable:
While the JDK Mission Control client can work with many different JVMs, it is highly recommended that you use the Oracle JDK/JVM as your JVM when running the JDK Mission Control Client on the Eclipse platform. Make sure to use Oracle HotSpot JDK 7 Update 14 or later. Running on a JRE is not recommended, as this will disable the autodetection of local JVMs.
+
While the JDK Mission Control client can work with many different JVMs, it is highly recommended that you use the Oracle JDK/JVM as your JVM when running the JDK Mission Control Client on the Eclipse platform. Make sure to use Oracle HotSpot JDK 21 or later. Running on a JRE is not recommended, as this will disable the autodetection of local JVMs.
To change the JVM on which you run Eclipse:
@@ -60,9 +60,9 @@
Changing Your JVM
On the third line down (after org.eclipse.platform), add the following:
-vm <Full path JAVA_HOME/jre/bin/ folder>
The full path might look like this on Windows:
-
C:\Program Files\Java\jdk1.7.0\jre\bin\
+
C:\Program Files\Java\jdk21\jre\bin\
Or, the path might look like this on Linux and Solaris:
-
$HOME/jdk1.7.0/jre/bin/
+
$HOME/jdk21/jre/bin/
Depending upon your particular JVM implementation and the applications running on it, you can set any valid JVM command-line option.
diff --git a/application/org.openjdk.jmc.rcp.application/plugin.xml b/application/org.openjdk.jmc.rcp.application/plugin.xml
index d3ecf8db1..e577d50d4 100644
--- a/application/org.openjdk.jmc.rcp.application/plugin.xml
+++ b/application/org.openjdk.jmc.rcp.application/plugin.xml
@@ -1,6 +1,6 @@
-
+
Welcome to JDK Mission Control
diff --git a/application/org.openjdk.jmc.rcp.intro/content/console_samples_l.xhtml b/application/org.openjdk.jmc.rcp.intro/content/console_samples_l.xhtml
index 2887cfd4b..3fa957ef6 100644
--- a/application/org.openjdk.jmc.rcp.intro/content/console_samples_l.xhtml
+++ b/application/org.openjdk.jmc.rcp.intro/content/console_samples_l.xhtml
@@ -1,10 +1,10 @@
-
+
Welcome to JDK Mission Control
diff --git a/application/org.openjdk.jmc.rcp.intro/content/jfr_samples.xhtml b/application/org.openjdk.jmc.rcp.intro/content/jfr_samples.xhtml
index 0c04e5ad8..da1febfed 100644
--- a/application/org.openjdk.jmc.rcp.intro/content/jfr_samples.xhtml
+++ b/application/org.openjdk.jmc.rcp.intro/content/jfr_samples.xhtml
@@ -1,10 +1,10 @@
-
+
Welcome to JDK Mission Control
diff --git a/application/org.openjdk.jmc.rcp.intro/content/jfr_samples_l.xhtml b/application/org.openjdk.jmc.rcp.intro/content/jfr_samples_l.xhtml
index 5f24b83d5..55404d3ba 100644
--- a/application/org.openjdk.jmc.rcp.intro/content/jfr_samples_l.xhtml
+++ b/application/org.openjdk.jmc.rcp.intro/content/jfr_samples_l.xhtml
@@ -1,10 +1,10 @@
-
+
Welcome to JDK Mission Control
diff --git a/application/org.openjdk.jmc.rcp.intro/content/plugins_samples.xhtml b/application/org.openjdk.jmc.rcp.intro/content/plugins_samples.xhtml
index 69c30625b..4837d20f7 100644
--- a/application/org.openjdk.jmc.rcp.intro/content/plugins_samples.xhtml
+++ b/application/org.openjdk.jmc.rcp.intro/content/plugins_samples.xhtml
@@ -1,10 +1,10 @@
-
+
Welcome to JDK Mission Control
diff --git a/application/org.openjdk.jmc.rcp.intro/content/plugins_samples_l.xhtml b/application/org.openjdk.jmc.rcp.intro/content/plugins_samples_l.xhtml
index 883fdc076..2c578fb72 100644
--- a/application/org.openjdk.jmc.rcp.intro/content/plugins_samples_l.xhtml
+++ b/application/org.openjdk.jmc.rcp.intro/content/plugins_samples_l.xhtml
@@ -1,10 +1,10 @@
-
+
Welcome to JDK Mission Control
diff --git a/application/org.openjdk.jmc.rcp.intro/content/root.xhtml b/application/org.openjdk.jmc.rcp.intro/content/root.xhtml
index 3bd35b3a7..57fd7681c 100644
--- a/application/org.openjdk.jmc.rcp.intro/content/root.xhtml
+++ b/application/org.openjdk.jmc.rcp.intro/content/root.xhtml
@@ -1,10 +1,10 @@
-
+
Welcome to JDK Mission Control
diff --git a/application/org.openjdk.jmc.rcp.intro/content/root_l.xhtml b/application/org.openjdk.jmc.rcp.intro/content/root_l.xhtml
index 21620945c..b035fa55d 100644
--- a/application/org.openjdk.jmc.rcp.intro/content/root_l.xhtml
+++ b/application/org.openjdk.jmc.rcp.intro/content/root_l.xhtml
@@ -1,10 +1,10 @@
-
+
Welcome to JDK Mission Control
diff --git a/application/org.openjdk.jmc.rcp.intro/content/standby.xhtml b/application/org.openjdk.jmc.rcp.intro/content/standby.xhtml
index 91141b94d..f8c0982fc 100644
--- a/application/org.openjdk.jmc.rcp.intro/content/standby.xhtml
+++ b/application/org.openjdk.jmc.rcp.intro/content/standby.xhtml
@@ -1,10 +1,10 @@
-
+
Welcome to JDK Mission Control
diff --git a/application/org.openjdk.jmc.updatesite.ide/src/main/resources/index.html b/application/org.openjdk.jmc.updatesite.ide/src/main/resources/index.html
index d0a8489cb..78f8e64be 100644
--- a/application/org.openjdk.jmc.updatesite.ide/src/main/resources/index.html
+++ b/application/org.openjdk.jmc.updatesite.ide/src/main/resources/index.html
@@ -1,7 +1,7 @@
@@ -38,7 +38,7 @@
This update site provides a set of plug-ins for the Eclipse IDE designed to help develop, profile
- and diagnose applications running on the Oracle® Java HotSpot VM, and (as of JDK 11) OpenJDK.
+ and diagnose applications running on the Oracle® Java HotSpot VM, and OpenJDK.
JDK Mission Control includes tools to monitor, manage and profile your Java application without
introducing the performance overhead normally associated with tools of this type. JDK Mission Control's low performance overhead
@@ -71,9 +71,9 @@
Requirements
-
Requires Eclipse 4.31.
+
Requires Eclipse 4.34.
Requires any previously installed versions of JMC 4.x, 5.x, 6.x or 7.x to be uninstalled before installing JMC 9.
-
Note that you need to run your Eclipse on a JDK (version 11 or above) installation for all features to work. For more information on this,
+
Note that you need to run your Eclipse on a JDK (version 21 or above) installation for all features to work. For more information on this,
please see the Run Eclipse on JDK HOWTO.
@@ -108,7 +108,7 @@
Prerequisites
- JDK Mission Control is a set of plug-ins for Eclipse 4.31.
+ JDK Mission Control is a set of plug-ins for Eclipse 4.34.
diff --git a/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/JvmBrowser.java b/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/JvmBrowser.java
index 5dc501bbe..d400f3d2d 100644
--- a/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/JvmBrowser.java
+++ b/application/uitests/org.openjdk.jmc.test.jemmy/src/main/java/org/openjdk/jmc/test/jemmy/misc/wrappers/JvmBrowser.java
@@ -41,6 +41,7 @@
import java.util.List;
import java.util.stream.Collectors;
+import org.jemmy.JemmyException;
import org.jemmy.TimeoutExpiredException;
import org.junit.Assert;
@@ -365,7 +366,18 @@ public void disconnect() {
* the name of the connection
*/
public void disconnect(String ... path) {
- selectContextOption(ACTION_DISCONNECT_TEXT, path);
+ int maxRetries = 5;
+ for (int i = 0; i < maxRetries; i++) {
+ try {
+ selectContextOption(ACTION_DISCONNECT_TEXT, path);
+ break;
+ } catch (JemmyException e) {
+ if (i == maxRetries - 1) {
+ throw e;
+ }
+ sleep(1000);
+ }
+ }
MCDialog disconnectDialog = new MCDialog(ACTION_DISCONNECT_TEXT);
disconnectDialog.clickButton(MCButton.Labels.OK);
}
diff --git a/core/license/THIRD_PARTY_LICENSES.txt b/core/license/THIRD_PARTY_LICENSES.txt
index af3ffa0a0..f82cfe073 100644
--- a/core/license/THIRD_PARTY_LICENSES.txt
+++ b/core/license/THIRD_PARTY_LICENSES.txt
@@ -10,7 +10,7 @@ in this project:
===============================================================================
-## org.owasp.encoder:encoder@1.2.2 (BSD-3-Clause)
+## org.owasp.encoder:encoder@1.4.0 (BSD-3-Clause)
Copyright (c) 2015 Jeff Ichnowski
All rights reserved.
@@ -19,19 +19,19 @@ Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
-* Redistributions of source code must retain the above
-copyright notice, this list of conditions and the following
-disclaimer.
+ * Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the following
+ disclaimer.
-* Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following
-disclaimer in the documentation and/or other materials
-provided with the distribution.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials
+ provided with the distribution.
-* Neither the name of the OWASP nor the names of its
-contributors may be used to endorse or promote products
-derived from this software without specific prior written
-permission.
+ * Neither the name of the OWASP nor the names of its
+ contributors may be used to endorse or promote products
+ derived from this software without specific prior written
+ permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@@ -47,9 +47,9 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
===============================================================================
-## at.yawk.lz4:lz4-java@1.10.2 (Apache-2.0)
+## at.yawk.lz4:lz4-java@1.10.4 (Apache-2.0)
- URL for License – http://opensource.org/licenses/Apache-2.0
+URL for License – http://opensource.org/licenses/Apache-2.0
Apache License
Version 2.0, January 2004
diff --git a/core/org.openjdk.jmc.common/pom.xml b/core/org.openjdk.jmc.common/pom.xml
index 157589e1f..5a266018d 100644
--- a/core/org.openjdk.jmc.common/pom.xml
+++ b/core/org.openjdk.jmc.common/pom.xml
@@ -46,12 +46,12 @@
org.owasp.encoderencoder
- 1.2.3
+ 1.4.0at.yawk.lz4lz4-java
- 1.10.2
+ 1.10.4
diff --git a/core/org.openjdk.jmc.common/src/main/java/org/openjdk/jmc/common/IMCFrame.java b/core/org.openjdk.jmc.common/src/main/java/org/openjdk/jmc/common/IMCFrame.java
index 7e577e4ce..e2566f9dd 100644
--- a/core/org.openjdk.jmc.common/src/main/java/org/openjdk/jmc/common/IMCFrame.java
+++ b/core/org.openjdk.jmc.common/src/main/java/org/openjdk/jmc/common/IMCFrame.java
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2022, 2025, Datadog, Inc. All rights reserved.
+ * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2026, Datadog, Inc. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -89,7 +89,7 @@ final class Type {
/**
* The frame compilation type is unknown.
*/
- public static final Type UNKNOWN = new Type("UNKNONW"); //$NON-NLS-1$
+ public static final Type UNKNOWN = new Type("UNKNOWN"); //$NON-NLS-1$
private static final String MSG_PREFIX = "IMCFrame_Type_";
diff --git a/core/org.openjdk.jmc.common/src/main/java/org/openjdk/jmc/common/collection/IteratorToolkit.java b/core/org.openjdk.jmc.common/src/main/java/org/openjdk/jmc/common/collection/IteratorToolkit.java
index fb719d969..7cec4e655 100644
--- a/core/org.openjdk.jmc.common/src/main/java/org/openjdk/jmc/common/collection/IteratorToolkit.java
+++ b/core/org.openjdk.jmc.common/src/main/java/org/openjdk/jmc/common/collection/IteratorToolkit.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -33,9 +33,13 @@
package org.openjdk.jmc.common.collection;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
+import java.util.PriorityQueue;
+import java.util.Queue;
import java.util.function.Predicate;
/**
@@ -106,6 +110,41 @@ protected T findNext() {
};
}
+ /**
+ * Wrap an iterator in a new iterator that merges values from sorted iterators.
+ *
+ * @param
+ * input iterator type
+ * @param iterators
+ * input iterators
+ * @param comparator
+ * ordering rule function
+ * @return a new iterator that contains sorted elements
+ */
+ public static Iterator mergedSorting(
+ final Collection extends Iterator> iterators, final Comparator comparator) {
+ final Queue> priorityQueue = new PriorityQueue<>(
+ Comparator.comparing(PeekingIterator::peek, comparator));
+ for (Iterator iterator : iterators) {
+ if (iterator.hasNext()) {
+ priorityQueue.add(new PeekingIterator<>(iterator));
+ }
+ }
+
+ return new AbstractIterator() {
+ @Override
+ protected T findNext() {
+ if (priorityQueue.isEmpty())
+ return NO_MORE_ELEMENTS;
+ PeekingIterator minPeekingIterator = priorityQueue.poll();
+ T result = minPeekingIterator.next();
+ if (minPeekingIterator.hasNext())
+ priorityQueue.add(minPeekingIterator);
+ return result;
+ }
+ };
+ }
+
/**
* Iterator that iterates over an array. Hopefully faster than Arrays.asList(...).iterator()
* since there are no concurrency checks.
diff --git a/core/org.openjdk.jmc.common/src/main/java/org/openjdk/jmc/common/collection/PeekingIterator.java b/core/org.openjdk.jmc.common/src/main/java/org/openjdk/jmc/common/collection/PeekingIterator.java
new file mode 100644
index 000000000..0e189e33e
--- /dev/null
+++ b/core/org.openjdk.jmc.common/src/main/java/org/openjdk/jmc/common/collection/PeekingIterator.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * The contents of this file are subject to the terms of either the Universal Permissive License
+ * v 1.0 as shown at https://oss.oracle.com/licenses/upl
+ *
+ * or the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted
+ * provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other materials provided with
+ * the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors may be used to
+ * endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
+ * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.openjdk.jmc.common.collection;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * Iterator wrapper that allows peeking at the next element.
+ *
+ * @param
+ * the type of elements returned by the iterator
+ */
+public class PeekingIterator implements Iterator {
+ private final Iterator sourceIterator;
+ private T peekedElement;
+ private boolean hasPeeked;
+
+ public PeekingIterator(Iterator sourceIterator) {
+ this.sourceIterator = sourceIterator;
+ }
+
+ public T peek() {
+ if (!this.hasPeeked) {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ this.hasPeeked = true;
+ this.peekedElement = this.sourceIterator.next();
+ }
+ return this.peekedElement;
+ }
+
+ @Override
+ public T next() {
+ if (!this.hasPeeked) {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ return this.sourceIterator.next();
+ }
+ this.hasPeeked = false;
+ T result = this.peekedElement;
+ this.peekedElement = null;
+ return result;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return this.hasPeeked || this.sourceIterator.hasNext();
+ }
+}
diff --git a/core/org.openjdk.jmc.flightrecorder/src/main/java/org/openjdk/jmc/flightrecorder/stacktrace/tree/AggregatableFrame.java b/core/org.openjdk.jmc.flightrecorder/src/main/java/org/openjdk/jmc/flightrecorder/stacktrace/tree/AggregatableFrame.java
index 10dd2b890..ea5eda031 100644
--- a/core/org.openjdk.jmc.flightrecorder/src/main/java/org/openjdk/jmc/flightrecorder/stacktrace/tree/AggregatableFrame.java
+++ b/core/org.openjdk.jmc.flightrecorder/src/main/java/org/openjdk/jmc/flightrecorder/stacktrace/tree/AggregatableFrame.java
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2019, 2025, Datadog, Inc. All rights reserved.
+ * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2026, Datadog, Inc. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -37,6 +37,7 @@
import org.openjdk.jmc.common.IMCMethod;
import org.openjdk.jmc.common.util.FormatToolkit;
import org.openjdk.jmc.flightrecorder.stacktrace.FrameSeparator;
+import org.openjdk.jmc.flightrecorder.stacktrace.Messages;
/**
* Frame wrapper taking into account a frame separator for hash code and equals.
@@ -135,4 +136,19 @@ public String getHumanReadableSeparatorSensitiveString() {
public String getHumanReadableShortString() {
return FormatToolkit.getHumanReadable(getMethod(), false, false, true, false, true, false);
}
+
+ /**
+ * Returns a unique key for this frame based on the fully qualified class name and method name.
+ * This key can be used for merging frames from different stack traces.
+ *
+ * @return a key in the format "fully.qualified.ClassName::methodName", or a sentinel value for
+ * special frames (root or unclassifiable frames from truncated stacks)
+ */
+ public String getMethodKey() {
+ IMCMethod method = frame.getMethod();
+ if (method == null || method.getType() == null) {
+ return Messages.getString(Messages.STACKTRACE_UNCLASSIFIABLE_FRAME);
+ }
+ return method.getType().getFullName() + "::" + method.getMethodName();
+ }
}
diff --git a/core/org.openjdk.jmc.flightrecorder/src/main/java/org/openjdk/jmc/flightrecorder/stacktrace/tree/Node.java b/core/org.openjdk.jmc.flightrecorder/src/main/java/org/openjdk/jmc/flightrecorder/stacktrace/tree/Node.java
index 0356b2242..905979207 100644
--- a/core/org.openjdk.jmc.flightrecorder/src/main/java/org/openjdk/jmc/flightrecorder/stacktrace/tree/Node.java
+++ b/core/org.openjdk.jmc.flightrecorder/src/main/java/org/openjdk/jmc/flightrecorder/stacktrace/tree/Node.java
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2021, 2025, Datadog, Inc. All rights reserved.
+ * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2026, Datadog, Inc. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -123,6 +123,26 @@ public boolean isLeaf() {
return children.isEmpty();
}
+ public void setWeight(double weight) {
+ this.weight = weight;
+ }
+
+ public void setCumulativeWeight(double cumulativeWeight) {
+ this.cumulativeWeight = cumulativeWeight;
+ }
+
+ public void addWeight(double delta) {
+ this.weight += delta;
+ }
+
+ public void addCumulativeWeight(double delta) {
+ this.cumulativeWeight += delta;
+ }
+
+ public void addChild(Node child) {
+ this.children.add(child);
+ }
+
@Override
public int hashCode() {
// This will get a few extra collisions.
diff --git a/core/org.openjdk.jmc.flightrecorder/src/main/java/org/openjdk/jmc/flightrecorder/stacktrace/tree/StacktraceTreeModel.java b/core/org.openjdk.jmc.flightrecorder/src/main/java/org/openjdk/jmc/flightrecorder/stacktrace/tree/StacktraceTreeModel.java
index a32d6078c..d41483ef6 100644
--- a/core/org.openjdk.jmc.flightrecorder/src/main/java/org/openjdk/jmc/flightrecorder/stacktrace/tree/StacktraceTreeModel.java
+++ b/core/org.openjdk.jmc.flightrecorder/src/main/java/org/openjdk/jmc/flightrecorder/stacktrace/tree/StacktraceTreeModel.java
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2021, 2025, Datadog, Inc. All rights reserved.
+ * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2026, Datadog, Inc. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -37,6 +37,7 @@
import java.util.function.BooleanSupplier;
import org.openjdk.jmc.common.IMCFrame;
+import org.openjdk.jmc.common.IMCMethod;
import org.openjdk.jmc.common.IMCStackTrace;
import org.openjdk.jmc.common.item.IAttribute;
import org.openjdk.jmc.common.item.IItem;
@@ -272,4 +273,126 @@ private Node getOrCreateNode(Node parent, AggregatableFrame frame) {
private static IMemberAccessor getAccessor(IItemIterable iterable, IAttribute attr) {
return (attr != null) ? iterable.getType().getAccessor(attr.getKey()) : null;
}
+
+ /**
+ * Extracts a merged tree of successors (callees) for a given method. This finds all occurrences
+ * of the specified method in the tree and merges their subtrees into a single tree rooted at
+ * the method.
+ *
+ * @param typeName
+ * the fully qualified class name of the method
+ * @param methodName
+ * the method name
+ * @return a new Node representing the merged successor tree, or null if the method is not found
+ */
+ public Node extractSuccessorsFor(String typeName, String methodName) {
+ AggregatableFrame pivotFrame = findFirstMatchingFrame(root, typeName, methodName);
+ if (pivotFrame == null) {
+ return null;
+ }
+ Node result = Node.newRootNode(pivotFrame);
+ traverseForSuccessors(root, typeName, methodName, result);
+ return result.getCumulativeWeight() > 0 ? result : null;
+ }
+
+ private boolean matchesMethod(Node node, String typeName, String methodName) {
+ IMCMethod method = node.getFrame().getMethod();
+ return method != null && methodName.equals(method.getMethodName())
+ && typeName.equals(method.getType().getFullName());
+ }
+
+ private AggregatableFrame findFirstMatchingFrame(Node current, String typeName, String methodName) {
+ if (matchesMethod(current, typeName, methodName)) {
+ return current.getFrame();
+ }
+ for (Node child : current.getChildren()) {
+ AggregatableFrame found = findFirstMatchingFrame(child, typeName, methodName);
+ if (found != null) {
+ return found;
+ }
+ }
+ return null;
+ }
+
+ private void traverseForSuccessors(Node current, String typeName, String methodName, Node result) {
+ if (matchesMethod(current, typeName, methodName)) {
+ mergeSuccessorNode(result, current);
+ }
+ for (Node child : current.getChildren()) {
+ traverseForSuccessors(child, typeName, methodName, result);
+ }
+ }
+
+ private void mergeSuccessorNode(Node destNode, Node srcNode) {
+ destNode.addCumulativeWeight(srcNode.getCumulativeWeight());
+ for (Node child : srcNode.getChildren()) {
+ String key = child.getFrame().getMethodKey();
+ Node existing = findChildByKey(destNode, key);
+ if (existing == null) {
+ Node newChild = new Node(destNode, child.getFrame());
+ destNode.addChild(newChild);
+ mergeSuccessorNode(newChild, child);
+ } else {
+ mergeSuccessorNode(existing, child);
+ }
+ }
+ }
+
+ private Node findChildByKey(Node parent, String key) {
+ for (Node child : parent.getChildren()) {
+ if (child.getFrame().getMethodKey().equals(key)) {
+ return child;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Extracts a merged tree of predecessors (callers) for a given method. This finds all
+ * occurrences of the specified method in the tree and merges their ancestor chains into a
+ * single inverted tree rooted at the method.
+ *
+ * @param typeName
+ * the fully qualified class name of the method
+ * @param methodName
+ * the method name
+ * @return a new Node representing the merged predecessor tree, or null if the method is not
+ * found
+ */
+ public Node extractPredecessorsFor(String typeName, String methodName) {
+ AggregatableFrame pivotFrame = findFirstMatchingFrame(root, typeName, methodName);
+ if (pivotFrame == null) {
+ return null;
+ }
+ Node result = Node.newRootNode(pivotFrame);
+ traverseForPredecessors(root, typeName, methodName, result);
+ return result.getCumulativeWeight() > 0 ? result : null;
+ }
+
+ private void traverseForPredecessors(Node current, String typeName, String methodName, Node result) {
+ if (matchesMethod(current, typeName, methodName)) {
+ result.addCumulativeWeight(current.getCumulativeWeight());
+ mergePredecessorChain(result, current.getParent(), current.getCumulativeWeight());
+ }
+ for (Node child : current.getChildren()) {
+ traverseForPredecessors(child, typeName, methodName, result);
+ }
+ }
+
+ private void mergePredecessorChain(Node destNode, Node srcAncestor, double weight) {
+ if (srcAncestor == null || srcAncestor.isRoot()) {
+ return;
+ }
+ String key = srcAncestor.getFrame().getMethodKey();
+ Node existing = findChildByKey(destNode, key);
+ if (existing == null) {
+ Node newChild = new Node(destNode, srcAncestor.getFrame());
+ newChild.addCumulativeWeight(weight);
+ destNode.addChild(newChild);
+ mergePredecessorChain(newChild, srcAncestor.getParent(), weight);
+ } else {
+ existing.addCumulativeWeight(weight);
+ mergePredecessorChain(existing, srcAncestor.getParent(), weight);
+ }
+ }
}
diff --git a/core/pom.xml b/core/pom.xml
index 92b2d74df..f4f78f10b 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -1,6 +1,6 @@