env = getAttrContext(path.getTreePath());
- Type t = attr.attribType(dcReference.qualifierExpression, env);
- if (t != null && !t.isErroneous()) {
- return t;
+ JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile);
+ try {
+ Type t = attr.attribType(dcReference.qualifierExpression, env);
+ if (t != null && !t.isErroneous()) {
+ return t;
+ }
+ } finally {
+ log.useSource(prevSource);
}
} catch (Abort e) { // may be thrown by Check.completionError in case of bad class file
return null;
@@ -388,6 +393,7 @@ public class JavacTrees extends DocTrees {
return null;
}
Log.DeferredDiagnosticHandler deferredDiagnosticHandler = log.new DeferredDiagnosticHandler();
+ JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile);
try {
final TypeSymbol tsym;
final Name memberName;
@@ -509,6 +515,7 @@ public class JavacTrees extends DocTrees {
} catch (Abort e) { // may be thrown by Check.completionError in case of bad class file
return null;
} finally {
+ log.useSource(prevSource);
log.popDiagnosticHandler(deferredDiagnosticHandler);
}
}
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/DeferredLintHandler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/DeferredLintHandler.java
deleted file mode 100644
index 11544b92b7f..00000000000
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/DeferredLintHandler.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (c) 2011, 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. 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.
- */
-
-package com.sun.tools.javac.code;
-
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Optional;
-import java.util.function.Consumer;
-
-import com.sun.tools.javac.tree.JCTree;
-import com.sun.tools.javac.tree.JCTree.Tag;
-import com.sun.tools.javac.util.Assert;
-import com.sun.tools.javac.util.Context;
-
-/**
- * Holds pending {@link Lint} warnings until the {@lint Lint} instance associated with the containing
- * module, package, class, method, or variable declaration is known so that {@link @SupressWarnings}
- * suppressions may be applied.
- *
- *
- * Warnings are regsistered at any time prior to attribution via {@link #report}. The warning will be
- * associated with the declaration placed in context by the most recent invocation of {@link #push push()}
- * not yet {@link #pop}'d. Warnings are actually emitted later, during attribution, via {@link #flush}.
- *
- *
- * There is also an "immediate" mode, where warnings are emitted synchronously; see {@link #pushImmediate}.
- *
- *
- * Deferred warnings are grouped by the innermost containing module, package, class, method, or variable
- * declaration (represented by {@link JCTree} nodes), so that the corresponding {@link Lint} configuration
- * can be applied when the warning is eventually generated.
- *
- *
This is NOT part of any supported API.
- * If you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.
- */
-public class DeferredLintHandler {
-
- protected static final Context.Key deferredLintHandlerKey = new Context.Key<>();
-
- public static DeferredLintHandler instance(Context context) {
- DeferredLintHandler instance = context.get(deferredLintHandlerKey);
- if (instance == null)
- instance = new DeferredLintHandler(context);
- return instance;
- }
-
- /**
- * Registered {@link LintLogger}s grouped by the innermost containing module, package, class,
- * method, or variable declaration.
- */
- private final HashMap> deferralMap = new HashMap<>();
-
- /**
- * The current "reporter" stack, reflecting calls to {@link #push} and {@link #pop}.
- *
- *
- * The top of the stack determines how calls to {@link #report} are handled.
- */
- private final ArrayDeque> reporterStack = new ArrayDeque<>();
-
- @SuppressWarnings("this-escape")
- protected DeferredLintHandler(Context context) {
- context.put(deferredLintHandlerKey, this);
- Lint rootLint = Lint.instance(context);
- pushImmediate(rootLint); // default to "immediate" mode
- }
-
-// LintLogger
-
- /**An interface for deferred lint reporting - loggers passed to
- * {@link #report(LintLogger) } will be called when
- * {@link #flush(DiagnosticPosition) } is invoked.
- */
- public interface LintLogger {
-
- /**
- * Generate a warning if appropriate.
- *
- * @param lint the applicable lint configuration
- */
- void report(Lint lint);
- }
-
-// Reporter Stack
-
- /**
- * Defer {@link #report}ed warnings until the given declaration is flushed.
- *
- * @param decl module, package, class, method, or variable declaration
- * @see #pop
- */
- public void push(JCTree decl) {
- Assert.check(decl.getTag() == Tag.MODULEDEF
- || decl.getTag() == Tag.PACKAGEDEF
- || decl.getTag() == Tag.CLASSDEF
- || decl.getTag() == Tag.METHODDEF
- || decl.getTag() == Tag.VARDEF);
- reporterStack.push(logger -> deferralMap
- .computeIfAbsent(decl, s -> new ArrayList<>())
- .add(logger));
- }
-
- /**
- * Enter "immediate" mode so that {@link #report}ed warnings are emitted synchonously.
- *
- * @param lint lint configuration to use for reported warnings
- */
- public void pushImmediate(Lint lint) {
- reporterStack.push(logger -> logger.report(lint));
- }
-
- /**
- * Revert to the previous configuration in effect prior to the most recent invocation
- * of {@link #push} or {@link #pushImmediate}.
- *
- * @see #pop
- */
- public void pop() {
- Assert.check(reporterStack.size() > 1); // the bottom stack entry should never be popped
- reporterStack.pop();
- }
-
- /**
- * Report a warning.
- *
- *
- * In immediate mode, the warning is emitted synchronously. Otherwise, the warning is emitted later
- * when the current declaration is flushed.
- */
- public void report(LintLogger logger) {
- Assert.check(!reporterStack.isEmpty());
- reporterStack.peek().accept(logger);
- }
-
-// Warning Flush
-
- /**
- * Emit deferred warnings encompassed by the given declaration.
- *
- * @param decl module, package, class, method, or variable declaration
- * @param lint lint configuration corresponding to {@code decl}
- */
- public void flush(JCTree decl, Lint lint) {
- Optional.of(decl)
- .map(deferralMap::remove)
- .stream()
- .flatMap(ArrayList::stream)
- .forEach(logger -> logger.report(lint));
- }
-}
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java
index 6d83f95fce4..8eab238f82a 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java
@@ -374,11 +374,8 @@ public class Lint {
/**
* Warn about issues relating to use of text blocks
- *
- *
- * This category is not supported by {@code @SuppressWarnings} (yet - see JDK-8224228).
*/
- TEXT_BLOCKS("text-blocks", false),
+ TEXT_BLOCKS("text-blocks"),
/**
* Warn about possible 'this' escapes before subclass instance is fully initialized.
@@ -476,27 +473,6 @@ public class Lint {
return suppressedValues.contains(lc);
}
- /**
- * Helper method. Log a lint warning if its lint category is enabled.
- *
- * @param warning key for the localized warning message
- */
- public void logIfEnabled(LintWarning warning) {
- logIfEnabled(null, warning);
- }
-
- /**
- * Helper method. Log a lint warning if its lint category is enabled.
- *
- * @param pos source position at which to report the warning
- * @param warning key for the localized warning message
- */
- public void logIfEnabled(DiagnosticPosition pos, LintWarning warning) {
- if (isEnabled(warning.getLintCategory())) {
- log.warning(pos, warning);
- }
- }
-
/**
* Obtain the set of recognized lint warning categories suppressed at the given symbol's declaration.
*
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java
new file mode 100644
index 00000000000..b15ddae02e1
--- /dev/null
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 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. 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.
+ */
+
+package com.sun.tools.javac.code;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+import javax.tools.DiagnosticListener;
+import javax.tools.JavaFileObject;
+
+import com.sun.tools.javac.tree.EndPosTable;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.tree.TreeInfo;
+import com.sun.tools.javac.tree.TreeScanner;
+import com.sun.tools.javac.util.Assert;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+
+/**
+ * Maps source code positions to the applicable {@link Lint} instance.
+ *
+ *
+ * Because {@code @SuppressWarnings} is a Java symbol, in general this mapping can't be
+ * calculated until after attribution. As each top-level declaration (class, package, or module)
+ * is attributed, this singleton is notified and the {@link Lint}s that apply to every source
+ * position within that top-level declaration are calculated.
+ *
+ *
+ * The method {@link #lintAt} returns the {@link Lint} instance applicable to source position;
+ * if it can't be determined yet, an empty {@link Optional} is returned.
+ *
+ *
This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.
+ */
+public class LintMapper {
+
+ // The key for the context singleton
+ private static final Context.Key CONTEXT_KEY = new Context.Key<>();
+
+ // Per-source file information. Note: during the parsing of a file, an entry exists but the FileInfo value is null
+ private final Map fileInfoMap = new HashMap<>();
+
+ // Compiler context
+ private final Context context;
+
+ // These are initialized lazily; see initializeIfNeeded()
+ private Lint rootLint;
+
+ /**
+ * Obtain the {@link LintMapper} context singleton.
+ */
+ public static LintMapper instance(Context context) {
+ LintMapper instance = context.get(CONTEXT_KEY);
+ if (instance == null)
+ instance = new LintMapper(context);
+ return instance;
+ }
+
+ /**
+ * Constructor.
+ */
+ @SuppressWarnings("this-escape")
+ protected LintMapper(Context context) {
+ context.put(CONTEXT_KEY, this);
+ this.context = context;
+ }
+
+ // Lazy initialization to avoid dependency loops
+ private void initializeIfNeeded() {
+ if (rootLint == null)
+ rootLint = Lint.instance(context);
+ }
+
+// Lint Operations
+
+ /**
+ * Determine if the given file is known to this instance.
+ *
+ * @param sourceFile source file
+ * @return true if file is recognized
+ */
+ public boolean isKnown(JavaFileObject sourceFile) {
+ return fileInfoMap.containsKey(sourceFile);
+ }
+
+ /**
+ * Obtain the {@link Lint} configuration that applies at the given position, if known.
+ *
+ * @param sourceFile source file
+ * @param pos source position
+ * @return the applicable {@link Lint}, if known, otherwise empty
+ */
+ public Optional lintAt(JavaFileObject sourceFile, DiagnosticPosition pos) {
+ initializeIfNeeded();
+ return Optional.of(sourceFile)
+ .map(fileInfoMap::get)
+ .flatMap(fileInfo -> fileInfo.lintAt(pos));
+ }
+
+ /**
+ * Calculate {@lint Lint} configurations for all positions within the given top-level declaration.
+ *
+ * @param sourceFile source file
+ * @param tree top-level declaration (class, package, or module)
+ */
+ public void calculateLints(JavaFileObject sourceFile, JCTree tree, EndPosTable endPositions) {
+ Assert.check(rootLint != null);
+ fileInfoMap.get(sourceFile).afterAttr(tree, endPositions);
+ }
+
+ /**
+ * Reset this instance.
+ */
+ public void clear() {
+ fileInfoMap.clear();
+ }
+
+// Parsing Notifications
+
+ /**
+ * Invoked when file parsing starts to create an entry for the new file (but with a null value).
+ */
+ public void startParsingFile(JavaFileObject sourceFile) {
+ initializeIfNeeded();
+ fileInfoMap.put(sourceFile, null);
+ }
+
+ /**
+ * Invoked when file parsing completes to put in place a corresponding {@link FileInfo}.
+ */
+ public void finishParsingFile(JCCompilationUnit tree) {
+ Assert.check(rootLint != null);
+ fileInfoMap.put(tree.sourcefile, new FileInfo(rootLint, tree));
+ }
+
+// FileInfo
+
+ /**
+ * Holds {@link Lint} information for a fully parsed source file.
+ *
+ *
+ * Initially (immediately after parsing), "unmappedDecls" contains a {@link Span} corresponding to each
+ * top-level declaration in the source file. As each top-level declaration is attributed, the corresponding
+ * {@link Span} is removed and the corresponding {@link LintRange} subtree is populated under "rootRange".
+ */
+ private static class FileInfo {
+
+ final LintRange rootRange; // the root LintRange (covering the entire source file)
+ final List unmappedDecls = new ArrayList<>(); // unmapped top-level declarations awaiting attribution
+
+ // After parsing: Add top-level declarations to our "unmappedDecls" list
+ FileInfo(Lint rootLint, JCCompilationUnit tree) {
+ rootRange = new LintRange(rootLint);
+ tree.defs.stream()
+ .filter(this::isTopLevelDecl)
+ .map(decl -> new Span(decl, tree.endPositions))
+ .forEach(unmappedDecls::add);
+ }
+
+ // After attribution: Discard the span from "unmappedDecls" and populate the declaration's subtree under "rootRange"
+ void afterAttr(JCTree tree, EndPosTable endPositions) {
+ for (Iterator i = unmappedDecls.iterator(); i.hasNext(); ) {
+ if (i.next().contains(tree.pos())) {
+ rootRange.populateSubtree(tree, endPositions);
+ i.remove();
+ return;
+ }
+ }
+ throw new AssertionError("top-level declaration not found");
+ }
+
+ // Find the most specific Lint configuration applying to the given position, unless the position has not been mapped yet
+ Optional lintAt(DiagnosticPosition pos) {
+ boolean mapped = unmappedDecls.stream().noneMatch(span -> span.contains(pos));
+ return mapped ? Optional.of(rootRange.bestMatch(pos).lint) : Optional.empty();
+ }
+
+ boolean isTopLevelDecl(JCTree tree) {
+ return tree.getTag() == Tag.MODULEDEF
+ || tree.getTag() == Tag.PACKAGEDEF
+ || tree.getTag() == Tag.CLASSDEF;
+ }
+ }
+
+// Span
+
+ /**
+ * A lexical range.
+ */
+ private record Span(int startPos, int endPos) {
+
+ static final Span MAXIMAL = new Span(Integer.MIN_VALUE, Integer.MAX_VALUE);
+
+ Span(JCTree tree, EndPosTable endPositions) {
+ this(TreeInfo.getStartPos(tree), TreeInfo.getEndPos(tree, endPositions));
+ }
+
+ boolean contains(DiagnosticPosition pos) {
+ int offset = pos.getLintPosition();
+ return offset == startPos || (offset > startPos && offset < endPos);
+ }
+
+ boolean contains(Span that) {
+ return this.startPos <= that.startPos && this.endPos >= that.endPos;
+ }
+ }
+
+// LintRange
+
+ /**
+ * A tree of nested lexical ranges and the {@link Lint} configurations that apply therein.
+ */
+ private record LintRange(
+ Span span, // declaration's lexical range
+ Lint lint, // the Lint configuration that applies at this declaration
+ List children // the nested declarations one level below this node
+ ) {
+
+ // Create a node representing the entire file, using the root lint configuration
+ LintRange(Lint rootLint) {
+ this(Span.MAXIMAL, rootLint, new ArrayList<>());
+ }
+
+ // Create a node representing the given declaration and its corresponding Lint configuration
+ LintRange(JCTree tree, EndPosTable endPositions, Lint lint) {
+ this(new Span(tree, endPositions), lint, new ArrayList<>());
+ }
+
+ // Find the most specific node in this tree (including me) that contains the given position, if any
+ LintRange bestMatch(DiagnosticPosition pos) {
+ return children.stream()
+ .map(child -> child.bestMatch(pos))
+ .filter(Objects::nonNull)
+ .reduce((a, b) -> a.span.contains(b.span) ? b : a)
+ .orElseGet(() -> span.contains(pos) ? this : null);
+ }
+
+ // Populate a sparse subtree corresponding to the given nested declaration.
+ // Only when the Lint configuration differs from the parent is a node added.
+ void populateSubtree(JCTree tree, EndPosTable endPositions) {
+ new TreeScanner() {
+
+ private LintRange currentNode = LintRange.this;
+
+ @Override
+ public void visitModuleDef(JCModuleDecl tree) {
+ scanDecl(tree, tree.sym, super::visitModuleDef);
+ }
+ @Override
+ public void visitPackageDef(JCPackageDecl tree) {
+ scanDecl(tree, tree.packge, super::visitPackageDef);
+ }
+ @Override
+ public void visitClassDef(JCClassDecl tree) {
+ scanDecl(tree, tree.sym, super::visitClassDef);
+ }
+ @Override
+ public void visitMethodDef(JCMethodDecl tree) {
+ scanDecl(tree, tree.sym, super::visitMethodDef);
+ }
+ @Override
+ public void visitVarDef(JCVariableDecl tree) {
+ scanDecl(tree, tree.sym, super::visitVarDef);
+ }
+
+ private void scanDecl(T tree, Symbol symbol, Consumer super T> recursor) {
+
+ // The "symbol" can be null if there were earlier errors; skip this declaration if so
+ if (symbol == null) {
+ recursor.accept(tree);
+ return;
+ }
+
+ // Update the Lint using the declaration; if there's no change, then we don't need a new node here
+ Lint newLint = currentNode.lint.augment(symbol);
+ if (newLint == currentNode.lint) { // note: lint.augment() returns the same instance if there's no change
+ recursor.accept(tree);
+ return;
+ }
+
+ // Add a new node here and proceed
+ final LintRange previousNode = currentNode;
+ currentNode = new LintRange(tree, endPositions, newLint);
+ previousNode.children.add(currentNode);
+ try {
+ recursor.accept(tree);
+ } finally {
+ currentNode = previousNode;
+ }
+ }
+ }.scan(tree);
+ }
+ }
+}
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java
index e11a9c6754e..1c93c37698a 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java
@@ -67,9 +67,6 @@ public class Preview {
/** flag: are preview features enabled */
private final boolean enabled;
- /** flag: is the "preview" lint category enabled? */
- private final boolean verbose;
-
/** test flag: should all features be considered as preview features? */
private final boolean forcePreview;
@@ -100,7 +97,6 @@ public class Preview {
enabled = options.isSet(PREVIEW);
log = Log.instance(context);
source = Source.instance(context);
- verbose = Lint.instance(context).isEnabled(LintCategory.PREVIEW);
forcePreview = options.isSet("forcePreview");
majorVersionToSource = initMajorVersionToSourceMap();
}
@@ -184,9 +180,7 @@ public class Preview {
*/
public void warnPreview(JavaFileObject classfile, int majorVersion) {
Assert.check(isEnabled());
- if (verbose) {
- log.warning(LintWarnings.PreviewFeatureUseClassfile(classfile, majorVersionToSource.get(majorVersion).name));
- }
+ log.warning(LintWarnings.PreviewFeatureUseClassfile(classfile, majorVersionToSource.get(majorVersion).name));
}
/**
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java
index 3da83248436..9f56bec4cca 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java
@@ -89,9 +89,7 @@ public class Annotate {
private final Attr attr;
private final Check chk;
private final ConstFold cfolder;
- private final DeferredLintHandler deferredLintHandler;
private final Enter enter;
- private final Lint lint;
private final Log log;
private final Names names;
private final Resolve resolve;
@@ -110,10 +108,8 @@ public class Annotate {
attr = Attr.instance(context);
chk = Check.instance(context);
cfolder = ConstFold.instance(context);
- deferredLintHandler = DeferredLintHandler.instance(context);
enter = Enter.instance(context);
log = Log.instance(context);
- lint = Lint.instance(context);
make = TreeMaker.instance(context);
names = Names.instance(context);
resolve = Resolve.instance(context);
@@ -235,10 +231,8 @@ public class Annotate {
* @param annotations the list of JCAnnotations to attribute and enter
* @param localEnv the enclosing env
* @param s the Symbol on which to enter the annotations
- * @param deferDecl enclosing declaration for DeferredLintHandler, or null for no deferral
*/
- public void annotateLater(List annotations, Env localEnv,
- Symbol s, JCTree deferDecl)
+ public void annotateLater(List annotations, Env localEnv, Symbol s)
{
if (annotations.isEmpty()) {
return;
@@ -256,8 +250,6 @@ public class Annotate {
// been handled, meaning that the set of annotations pending completion is now empty.
Assert.check(s.kind == PCK || s.annotationsPendingCompletion());
JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
- Assert.check(deferDecl != null);
- deferredLintHandler.push(deferDecl);
try {
if (s.hasAnnotations() && annotations.nonEmpty())
log.error(annotations.head.pos, Errors.AlreadyAnnotated(Kinds.kindName(s), s));
@@ -268,7 +260,6 @@ public class Annotate {
// never called for a type parameter
annotateNow(s, annotations, localEnv, false, false);
} finally {
- deferredLintHandler.pop();
log.useSource(prev);
}
});
@@ -285,16 +276,13 @@ public class Annotate {
/** Queue processing of an attribute default value. */
- public void annotateDefaultValueLater(JCExpression defaultValue, Env localEnv,
- MethodSymbol m, JCTree deferDecl)
+ public void annotateDefaultValueLater(JCExpression defaultValue, Env localEnv, MethodSymbol m)
{
normal(() -> {
JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
- deferredLintHandler.push(deferDecl);
try {
enterDefaultValue(defaultValue, localEnv, m);
} finally {
- deferredLintHandler.pop();
log.useSource(prev);
}
});
@@ -682,7 +670,7 @@ public class Annotate {
// Scan the annotation element value and then attribute nested annotations if present
if (tree.type != null && tree.type.tsym != null) {
- queueScanTreeAndTypeAnnotate(tree, env, tree.type.tsym, null);
+ queueScanTreeAndTypeAnnotate(tree, env, tree.type.tsym);
}
result = cfolder.coerce(result, expectedElementType);
@@ -1034,20 +1022,14 @@ public class Annotate {
/**
* Attribute the list of annotations and enter them onto s.
*/
- public void enterTypeAnnotations(List annotations, Env env,
- Symbol s, JCTree deferDecl, boolean isTypeParam)
+ public void enterTypeAnnotations(List annotations, Env env, Symbol s, boolean isTypeParam)
{
Assert.checkNonNull(s, "Symbol argument to actualEnterTypeAnnotations is nul/");
JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
- if (deferDecl != null) {
- deferredLintHandler.push(deferDecl);
- }
try {
annotateNow(s, annotations, env, true, isTypeParam);
} finally {
- if (deferDecl != null)
- deferredLintHandler.pop();
log.useSource(prev);
}
}
@@ -1055,10 +1037,10 @@ public class Annotate {
/**
* Enqueue tree for scanning of type annotations, attaching to the Symbol sym.
*/
- public void queueScanTreeAndTypeAnnotate(JCTree tree, Env env, Symbol sym, JCTree deferDecl)
+ public void queueScanTreeAndTypeAnnotate(JCTree tree, Env env, Symbol sym)
{
Assert.checkNonNull(sym);
- normal(() -> tree.accept(new TypeAnnotate(env, sym, deferDecl)));
+ normal(() -> tree.accept(new TypeAnnotate(env, sym)));
}
/**
@@ -1093,32 +1075,30 @@ public class Annotate {
private class TypeAnnotate extends TreeScanner {
private final Env env;
private final Symbol sym;
- private JCTree deferDecl;
- public TypeAnnotate(Env env, Symbol sym, JCTree deferDecl) {
+ public TypeAnnotate(Env env, Symbol sym) {
this.env = env;
this.sym = sym;
- this.deferDecl = deferDecl;
}
@Override
public void visitAnnotatedType(JCAnnotatedType tree) {
- enterTypeAnnotations(tree.annotations, env, sym, deferDecl, false);
+ enterTypeAnnotations(tree.annotations, env, sym, false);
scan(tree.underlyingType);
}
@Override
public void visitTypeParameter(JCTypeParameter tree) {
- enterTypeAnnotations(tree.annotations, env, sym, deferDecl, true);
+ enterTypeAnnotations(tree.annotations, env, sym, true);
scan(tree.bounds);
}
@Override
public void visitNewArray(JCNewArray tree) {
- enterTypeAnnotations(tree.annotations, env, sym, deferDecl, false);
+ enterTypeAnnotations(tree.annotations, env, sym, false);
for (List dimAnnos : tree.dimAnnotations)
- enterTypeAnnotations(dimAnnos, env, sym, deferDecl, false);
+ enterTypeAnnotations(dimAnnos, env, sym, false);
scan(tree.elemtype);
scan(tree.elems);
}
@@ -1137,19 +1117,13 @@ public class Annotate {
@Override
public void visitVarDef(JCVariableDecl tree) {
- JCTree prevDecl = deferDecl;
- deferDecl = tree;
- try {
- if (sym != null && sym.kind == VAR) {
- // Don't visit a parameter once when the sym is the method
- // and once when the sym is the parameter.
- scan(tree.mods);
- scan(tree.vartype);
- }
- scan(tree.init);
- } finally {
- deferDecl = prevDecl;
+ if (sym != null && sym.kind == VAR) {
+ // Don't visit a parameter once when the sym is the method
+ // and once when the sym is the parameter.
+ scan(tree.mods);
+ scan(tree.vartype);
}
+ scan(tree.init);
}
@Override
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
index ea3b08e0338..45ece909ad7 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
@@ -41,6 +41,7 @@ import com.sun.source.tree.TreeVisitor;
import com.sun.source.util.SimpleTreeVisitor;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Lint.LintCategory;
+import com.sun.tools.javac.code.LintMapper;
import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.code.Source.Feature;
import com.sun.tools.javac.code.Symbol.*;
@@ -98,6 +99,7 @@ public class Attr extends JCTree.Visitor {
final Names names;
final Log log;
+ final LintMapper lintMapper;
final Symtab syms;
final Resolve rs;
final Operators operators;
@@ -116,7 +118,6 @@ public class Attr extends JCTree.Visitor {
final Preview preview;
final JCDiagnostic.Factory diags;
final TypeAnnotations typeAnnotations;
- final DeferredLintHandler deferredLintHandler;
final TypeEnvs typeEnvs;
final Dependencies dependencies;
final Annotate annotate;
@@ -137,6 +138,7 @@ public class Attr extends JCTree.Visitor {
names = Names.instance(context);
log = Log.instance(context);
+ lintMapper = LintMapper.instance(context);
syms = Symtab.instance(context);
rs = Resolve.instance(context);
operators = Operators.instance(context);
@@ -156,7 +158,6 @@ public class Attr extends JCTree.Visitor {
diags = JCDiagnostic.Factory.instance(context);
annotate = Annotate.instance(context);
typeAnnotations = TypeAnnotations.instance(context);
- deferredLintHandler = DeferredLintHandler.instance(context);
typeEnvs = TypeEnvs.instance(context);
dependencies = Dependencies.instance(context);
argumentAttr = ArgumentAttr.instance(context);
@@ -853,7 +854,6 @@ public class Attr extends JCTree.Visitor {
Env enclosingEnv,
JCVariableDecl variable,
Type type) {
- deferredLintHandler.push(variable);
final JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile);
try {
doQueueScanTreeAndTypeAnnotateForVarInit(variable, enclosingEnv);
@@ -869,7 +869,6 @@ public class Attr extends JCTree.Visitor {
}
} finally {
log.useSource(prevSource);
- deferredLintHandler.pop();
}
}
@@ -998,7 +997,6 @@ public class Attr extends JCTree.Visitor {
Assert.check(!env.info.ctorPrologue);
MethodSymbol prevMethod = chk.setMethod(m);
try {
- deferredLintHandler.flush(tree, lint);
chk.checkDeprecatedAnnotation(tree.pos(), m);
@@ -1233,7 +1231,7 @@ public class Attr extends JCTree.Visitor {
}
// Attribute all type annotations in the body
- annotate.queueScanTreeAndTypeAnnotate(tree.body, localEnv, m, null);
+ annotate.queueScanTreeAndTypeAnnotate(tree.body, localEnv, m);
annotate.flush();
// Start of constructor prologue (if not in java.lang.Object constructor)
@@ -1297,7 +1295,6 @@ public class Attr extends JCTree.Visitor {
try {
v.getConstValue(); // ensure compile-time constant initializer is evaluated
- deferredLintHandler.flush(tree, lint);
chk.checkDeprecatedAnnotation(tree.pos(), v);
if (tree.init != null) {
@@ -1342,7 +1339,7 @@ public class Attr extends JCTree.Visitor {
env.info.scope.owner.kind != MTH && env.info.scope.owner.kind != VAR) {
tree.mods.flags |= Flags.FIELD_INIT_TYPE_ANNOTATIONS_QUEUED;
// Field initializer expression need to be entered.
- annotate.queueScanTreeAndTypeAnnotate(tree.init, env, tree.sym, tree);
+ annotate.queueScanTreeAndTypeAnnotate(tree.init, env, tree.sym);
annotate.flush();
}
}
@@ -1439,7 +1436,7 @@ public class Attr extends JCTree.Visitor {
if ((tree.flags & STATIC) != 0) localEnv.info.staticLevel++;
// Attribute all type annotations in the block
- annotate.queueScanTreeAndTypeAnnotate(tree, localEnv, localEnv.info.scope.owner, null);
+ annotate.queueScanTreeAndTypeAnnotate(tree, localEnv, localEnv.info.scope.owner);
annotate.flush();
attribStats(tree.stats, localEnv);
@@ -1952,7 +1949,7 @@ public class Attr extends JCTree.Visitor {
public void visitSynchronized(JCSynchronized tree) {
chk.checkRefType(tree.pos(), attribExpr(tree.lock, env));
if (tree.lock.type != null && tree.lock.type.isValueBased()) {
- env.info.lint.logIfEnabled(tree.pos(), LintWarnings.AttemptToSynchronizeOnInstanceOfValueBasedClass);
+ log.warning(tree.pos(), LintWarnings.AttemptToSynchronizeOnInstanceOfValueBasedClass);
}
attribStat(tree.body, env);
result = null;
@@ -2054,7 +2051,7 @@ public class Attr extends JCTree.Visitor {
if (close.kind == MTH &&
close.overrides(syms.autoCloseableClose, resource.tsym, types, true) &&
chk.isHandled(syms.interruptedExceptionType, types.memberType(resource, close).getThrownTypes())) {
- env.info.lint.logIfEnabled(pos, LintWarnings.TryResourceThrowsInterruptedExc(resource));
+ log.warning(pos, LintWarnings.TryResourceThrowsInterruptedExc(resource));
}
}
}
@@ -4226,9 +4223,9 @@ public class Attr extends JCTree.Visitor {
setSyntheticVariableType(tree.var, type == Type.noType ? syms.errType
: type);
}
- annotate.annotateLater(tree.var.mods.annotations, env, v, tree.var);
+ annotate.annotateLater(tree.var.mods.annotations, env, v);
if (!tree.var.isImplicitlyTyped()) {
- annotate.queueScanTreeAndTypeAnnotate(tree.var.vartype, env, v, tree.var);
+ annotate.queueScanTreeAndTypeAnnotate(tree.var.vartype, env, v);
}
annotate.flush();
result = tree.type;
@@ -4466,7 +4463,7 @@ public class Attr extends JCTree.Visitor {
sym.kind == MTH &&
sym.name.equals(names.close) &&
sym.overrides(syms.autoCloseableClose, sitesym.type.tsym, types, true)) {
- env.info.lint.logIfEnabled(tree, LintWarnings.TryExplicitCloseCall);
+ log.warning(tree, LintWarnings.TryExplicitCloseCall);
}
// Disallow selecting a type from an expression
@@ -4493,9 +4490,9 @@ public class Attr extends JCTree.Visitor {
// If the qualified item is not a type and the selected item is static, report
// a warning. Make allowance for the class of an array type e.g. Object[].class)
if (!sym.owner.isAnonymous()) {
- chk.lint.logIfEnabled(tree, LintWarnings.StaticNotQualifiedByType(sym.kind.kindName(), sym.owner));
+ log.warning(tree, LintWarnings.StaticNotQualifiedByType(sym.kind.kindName(), sym.owner));
} else {
- chk.lint.logIfEnabled(tree, LintWarnings.StaticNotQualifiedByType2(sym.kind.kindName()));
+ log.warning(tree, LintWarnings.StaticNotQualifiedByType2(sym.kind.kindName()));
}
}
@@ -5297,6 +5294,9 @@ public class Attr extends JCTree.Visitor {
}
annotate.flush();
+
+ // Now that this tree is attributed, we can calculate the Lint configuration everywhere within it
+ lintMapper.calculateLints(env.toplevel.sourcefile, env.tree, env.toplevel.endPositions);
}
public void attribPackage(DiagnosticPosition pos, PackageSymbol p) {
@@ -5339,7 +5339,6 @@ public class Attr extends JCTree.Visitor {
JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
try {
- deferredLintHandler.flush(env.tree, lint);
attrib.accept(env);
} finally {
log.useSource(prev);
@@ -5523,7 +5522,6 @@ public class Attr extends JCTree.Visitor {
}
}
- deferredLintHandler.flush(env.tree, env.info.lint);
env.info.returnResult = null;
// java.lang.Enum may not be subclassed by a non-enum
if (st.tsym == syms.enumSym &&
@@ -5569,11 +5567,9 @@ public class Attr extends JCTree.Visitor {
ModuleSymbol msym = tree.sym;
Lint lint = env.outer.info.lint = env.outer.info.lint.augment(msym);
Lint prevLint = chk.setLint(lint);
- chk.checkModuleName(tree);
- chk.checkDeprecatedAnnotation(tree, msym);
-
try {
- deferredLintHandler.flush(tree, lint);
+ chk.checkModuleName(tree);
+ chk.checkDeprecatedAnnotation(tree, msym);
} finally {
chk.setLint(prevLint);
}
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
index ec328f391f9..3d9eff107da 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
@@ -121,7 +121,7 @@ public class Check {
// The set of lint options currently in effect. It is initialized
// from the context, and then is set/reset as needed by Attr as it
// visits all the various parts of the trees during attribution.
- Lint lint;
+ private Lint lint;
// The method being analyzed in Attr - it is set/reset as needed by
// Attr as it visits new method declarations.
@@ -164,8 +164,6 @@ public class Check {
profile = Profile.instance(context);
preview = Preview.instance(context);
- deferredLintHandler = DeferredLintHandler.instance(context);
-
allowModules = Feature.MODULES.allowedInSource(source);
allowRecords = Feature.RECORDS.allowedInSource(source);
allowSealed = Feature.SEALED_CLASSES.allowedInSource(source);
@@ -180,10 +178,6 @@ public class Check {
*/
private Map,ClassSymbol> compiled = new HashMap<>();
- /** A handler for deferred lint warnings.
- */
- private DeferredLintHandler deferredLintHandler;
-
/** Are modules allowed
*/
private final boolean allowModules;
@@ -229,24 +223,15 @@ public class Check {
* @param sym The deprecated symbol.
*/
void warnDeprecated(DiagnosticPosition pos, Symbol sym) {
- LintWarning warningKey = null;
- if (sym.isDeprecatedForRemoval()) {
- if (!lint.isSuppressed(LintCategory.REMOVAL)) {
- if (sym.kind == MDL) {
- warningKey = LintWarnings.HasBeenDeprecatedForRemovalModule(sym);
- } else {
- warningKey = LintWarnings.HasBeenDeprecatedForRemoval(sym, sym.location());
- }
- }
- } else if (!lint.isSuppressed(LintCategory.DEPRECATION)) {
- if (sym.kind == MDL) {
- warningKey = LintWarnings.HasBeenDeprecatedModule(sym);
- } else {
- warningKey = LintWarnings.HasBeenDeprecated(sym, sym.location());
- }
- }
- if (warningKey != null)
- log.warning(pos, warningKey);
+ Assert.check(!importSuppression);
+ LintWarning warningKey = sym.isDeprecatedForRemoval() ?
+ (sym.kind == MDL ?
+ LintWarnings.HasBeenDeprecatedForRemovalModule(sym) :
+ LintWarnings.HasBeenDeprecatedForRemoval(sym, sym.location())) :
+ (sym.kind == MDL ?
+ LintWarnings.HasBeenDeprecatedModule(sym) :
+ LintWarnings.HasBeenDeprecated(sym, sym.location()));
+ log.warning(pos, warningKey);
}
/** Log a preview warning.
@@ -254,25 +239,16 @@ public class Check {
* @param msg A Warning describing the problem.
*/
public void warnPreviewAPI(DiagnosticPosition pos, LintWarning warnKey) {
- if (!importSuppression && !lint.isSuppressed(LintCategory.PREVIEW))
+ if (!importSuppression)
log.warning(pos, warnKey);
}
- /** Log a preview warning.
- * @param pos Position to be used for error reporting.
- * @param msg A Warning describing the problem.
- */
- public void warnRestrictedAPI(DiagnosticPosition pos, Symbol sym) {
- lint.logIfEnabled(pos, LintWarnings.RestrictedMethod(sym.enclClass(), sym));
- }
-
/** Warn about unchecked operation.
* @param pos Position to be used for error reporting.
* @param msg A string describing the problem.
*/
public void warnUnchecked(DiagnosticPosition pos, LintWarning warnKey) {
- if (!lint.isSuppressed(LintCategory.UNCHECKED))
- log.warning(pos, warnKey);
+ log.warning(pos, warnKey);
}
/** Report a failure to complete a class.
@@ -608,9 +584,7 @@ public class Check {
&& types.isSameType(tree.expr.type, tree.clazz.type)
&& !(ignoreAnnotatedCasts && TreeInfo.containsTypeAnnotation(tree.clazz))
&& !is292targetTypeCast(tree)) {
- deferredLintHandler.report(_l -> {
- lint.logIfEnabled(tree.pos(), LintWarnings.RedundantCast(tree.clazz.type));
- });
+ log.warning(tree.pos(), LintWarnings.RedundantCast(tree.clazz.type));
}
}
//where
@@ -914,7 +888,7 @@ public class Check {
}
} else if (hasTrustMeAnno && varargElemType != null &&
types.isReifiable(varargElemType)) {
- lint.logIfEnabled(tree, LintWarnings.VarargsRedundantTrustmeAnno(
+ log.warning(tree.pos(), LintWarnings.VarargsRedundantTrustmeAnno(
syms.trustMeType.tsym,
diags.fragment(Fragments.VarargsTrustmeOnReifiableVarargs(varargElemType))));
}
@@ -1173,7 +1147,7 @@ public class Check {
mask = MethodFlags;
}
if ((flags & STRICTFP) != 0) {
- warnOnExplicitStrictfp(tree);
+ log.warning(tree.pos(), LintWarnings.Strictfp);
}
// Imply STRICTFP if owner has STRICTFP set.
if (((flags|implicit) & Flags.ABSTRACT) == 0 ||
@@ -1217,7 +1191,7 @@ public class Check {
implicit |= FINAL;
}
if ((flags & STRICTFP) != 0) {
- warnOnExplicitStrictfp(tree);
+ log.warning(tree.pos(), LintWarnings.Strictfp);
}
// Imply STRICTFP if owner has STRICTFP set.
implicit |= sym.owner.flags_field & STRICTFP;
@@ -1281,16 +1255,6 @@ public class Check {
return flags & (mask | ~ExtendedStandardFlags) | implicit;
}
- private void warnOnExplicitStrictfp(JCTree tree) {
- deferredLintHandler.push(tree);
- try {
- deferredLintHandler.report(_ -> lint.logIfEnabled(tree.pos(), LintWarnings.Strictfp));
- } finally {
- deferredLintHandler.pop();
- }
- }
-
-
/** Determine if this enum should be implicitly final.
*
* If the enum has no specialized enum constants, it is final.
@@ -1503,7 +1467,7 @@ public class Check {
!TreeInfo.isDiamond(tree) &&
!withinAnonConstr(env) &&
tree.type.isRaw()) {
- lint.logIfEnabled(tree.pos(), LintWarnings.RawClassUse(tree.type, tree.type.tsym.type));
+ log.warning(tree.pos(), LintWarnings.RawClassUse(tree.type, tree.type.tsym.type));
}
}
//where
@@ -1827,7 +1791,7 @@ public class Check {
// Optional warning if varargs don't agree
if ((((m.flags() ^ other.flags()) & Flags.VARARGS) != 0)) {
- lint.logIfEnabled(TreeInfo.diagnosticPositionFor(m, tree),
+ log.warning(TreeInfo.diagnosticPositionFor(m, tree),
((m.flags() & Flags.VARARGS) != 0)
? LintWarnings.OverrideVarargsMissing(varargsOverrides(m, other))
: LintWarnings.OverrideVarargsExtra(varargsOverrides(m, other)));
@@ -1841,12 +1805,7 @@ public class Check {
// Warn if a deprecated method overridden by a non-deprecated one.
if (!isDeprecatedOverrideIgnorable(other, origin)) {
- Lint prevLint = setLint(lint.augment(m));
- try {
- checkDeprecated(() -> TreeInfo.diagnosticPositionFor(m, tree), m, other);
- } finally {
- setLint(prevLint);
- }
+ checkDeprecated(() -> TreeInfo.diagnosticPositionFor(m, tree), m, other);
}
}
// where
@@ -2915,42 +2874,33 @@ public class Check {
// Apply special flag "-XDwarnOnAccessToMembers" which turns on just this particular warning for all types of access
void checkAccessFromSerializableElement(final JCTree tree, boolean isLambda) {
- final Lint prevLint = setLint(warnOnAnyAccessToMembers ? lint.enable(LintCategory.SERIAL) : lint);
- try {
- if (warnOnAnyAccessToMembers || isLambda)
- checkAccessFromSerializableElementInner(tree, isLambda);
- } finally {
- setLint(prevLint);
- }
+ if (warnOnAnyAccessToMembers || isLambda)
+ checkAccessFromSerializableElementInner(tree, isLambda);
}
private void checkAccessFromSerializableElementInner(final JCTree tree, boolean isLambda) {
- if (lint.isEnabled(LintCategory.SERIAL)) {
- Symbol sym = TreeInfo.symbol(tree);
- if (!sym.kind.matches(KindSelector.VAL_MTH)) {
+ Symbol sym = TreeInfo.symbol(tree);
+ if (!sym.kind.matches(KindSelector.VAL_MTH)) {
+ return;
+ }
+
+ if (sym.kind == VAR) {
+ if ((sym.flags() & PARAMETER) != 0 ||
+ sym.isDirectlyOrIndirectlyLocal() ||
+ sym.name == names._this ||
+ sym.name == names._super) {
return;
}
+ }
- if (sym.kind == VAR) {
- if ((sym.flags() & PARAMETER) != 0 ||
- sym.isDirectlyOrIndirectlyLocal() ||
- sym.name == names._this ||
- sym.name == names._super) {
- return;
- }
- }
-
- if (!types.isSubtype(sym.owner.type, syms.serializableType) &&
- isEffectivelyNonPublic(sym)) {
- if (isLambda) {
- if (belongsToRestrictedPackage(sym)) {
- log.warning(tree.pos(),
- LintWarnings.AccessToMemberFromSerializableLambda(sym));
- }
- } else {
- log.warning(tree.pos(),
- LintWarnings.AccessToMemberFromSerializableElement(sym));
+ if (!types.isSubtype(sym.owner.type, syms.serializableType) && isEffectivelyNonPublic(sym)) {
+ DiagnosticFlag flag = warnOnAnyAccessToMembers ? DiagnosticFlag.DEFAULT_ENABLED : null;
+ if (isLambda) {
+ if (belongsToRestrictedPackage(sym)) {
+ log.warning(flag, tree.pos(), LintWarnings.AccessToMemberFromSerializableLambda(sym));
}
+ } else {
+ log.warning(flag, tree.pos(), LintWarnings.AccessToMemberFromSerializableElement(sym));
}
}
}
@@ -3737,8 +3687,7 @@ public class Check {
// Note: @Deprecated has no effect on local variables, parameters and package decls.
if (lint.isEnabled(LintCategory.DEPRECATION) && !s.isDeprecatableViaAnnotation()) {
if (!syms.deprecatedType.isErroneous() && s.attribute(syms.deprecatedType.tsym) != null) {
- log.warning(pos,
- LintWarnings.DeprecatedAnnotationHasNoEffect(Kinds.kindName(s)));
+ log.warning(pos, LintWarnings.DeprecatedAnnotationHasNoEffect(Kinds.kindName(s)));
}
}
}
@@ -3752,15 +3701,13 @@ public class Check {
&& (s.isDeprecatedForRemoval() || s.isDeprecated() && !other.isDeprecated())
&& (s.outermostClass() != other.outermostClass() || s.outermostClass() == null)
&& s.kind != Kind.PCK) {
- deferredLintHandler.report(_l -> warnDeprecated(pos.get(), s));
+ warnDeprecated(pos.get(), s);
}
}
void checkSunAPI(final DiagnosticPosition pos, final Symbol s) {
if ((s.flags() & PROPRIETARY) != 0) {
- deferredLintHandler.report(_l -> {
- log.warning(pos, Warnings.SunProprietary(s));
- });
+ log.warning(pos, Warnings.SunProprietary(s));
}
}
@@ -3817,7 +3764,7 @@ public class Check {
void checkRestricted(DiagnosticPosition pos, Symbol s) {
if (s.kind == MTH && (s.flags() & RESTRICTED) != 0) {
- deferredLintHandler.report(_l -> warnRestrictedAPI(pos, s));
+ log.warning(pos, LintWarnings.RestrictedMethod(s.enclClass(), s));
}
}
@@ -4089,7 +4036,7 @@ public class Check {
int opc = ((OperatorSymbol)operator).opcode;
if (opc == ByteCodes.idiv || opc == ByteCodes.imod
|| opc == ByteCodes.ldiv || opc == ByteCodes.lmod) {
- deferredLintHandler.report(_ -> lint.logIfEnabled(pos, LintWarnings.DivZero));
+ log.warning(pos, LintWarnings.DivZero);
}
}
}
@@ -4102,8 +4049,7 @@ public class Check {
*/
void checkLossOfPrecision(final DiagnosticPosition pos, Type found, Type req) {
if (found.isNumeric() && req.isNumeric() && !types.isAssignable(found, req)) {
- deferredLintHandler.report(_ ->
- lint.logIfEnabled(pos, LintWarnings.PossibleLossOfPrecision(found, req)));
+ log.warning(pos, LintWarnings.PossibleLossOfPrecision(found, req));
}
}
@@ -4112,7 +4058,7 @@ public class Check {
*/
void checkEmptyIf(JCIf tree) {
if (tree.thenpart.hasTag(SKIP) && tree.elsepart == null) {
- lint.logIfEnabled(tree.thenpart.pos(), LintWarnings.EmptyIf);
+ log.warning(tree.thenpart.pos(), LintWarnings.EmptyIf);
}
}
@@ -4259,8 +4205,7 @@ public class Check {
rs.isAccessible(env, c) &&
!fileManager.isSameFile(c.sourcefile, env.toplevel.sourcefile))
{
- lint.logIfEnabled(pos,
- LintWarnings.AuxiliaryClassAccessedFromOutsideOfItsSourceFile(c, c.sourcefile));
+ log.warning(pos, LintWarnings.AuxiliaryClassAccessedFromOutsideOfItsSourceFile(c, c.sourcefile));
}
}
@@ -4302,8 +4247,7 @@ public class Check {
// Warning may be suppressed by
// annotations; check again for being
// enabled in the deferred context.
- deferredLintHandler.report(_ ->
- lint.logIfEnabled(pos, LintWarnings.MissingExplicitCtor(c, pkg, modle)));
+ log.warning(pos, LintWarnings.MissingExplicitCtor(c, pkg, modle));
} else {
return;
}
@@ -4339,7 +4283,7 @@ public class Check {
method.attribute(syms.trustMeType.tsym) != null &&
isTrustMeAllowedOnMethod(method) &&
!types.isReifiable(method.type.getParameterTypes().last())) {
- Check.this.lint.logIfEnabled(pos(), LintWarnings.VarargsUnsafeUseVarargsParam(method.params.last()));
+ log.warning(pos(), LintWarnings.VarargsUnsafeUseVarargsParam(method.params.last()));
}
break;
default:
@@ -4637,28 +4581,24 @@ public class Check {
void checkModuleExists(final DiagnosticPosition pos, ModuleSymbol msym) {
if (msym.kind != MDL) {
- deferredLintHandler.report(_ ->
- lint.logIfEnabled(pos, LintWarnings.ModuleNotFound(msym)));
+ log.warning(pos, LintWarnings.ModuleNotFound(msym));
}
}
void checkPackageExistsForOpens(final DiagnosticPosition pos, PackageSymbol packge) {
if (packge.members().isEmpty() &&
((packge.flags() & Flags.HAS_RESOURCE) == 0)) {
- deferredLintHandler.report(_ ->
- lint.logIfEnabled(pos, LintWarnings.PackageEmptyOrNotFound(packge)));
+ log.warning(pos, LintWarnings.PackageEmptyOrNotFound(packge));
}
}
void checkModuleRequires(final DiagnosticPosition pos, final RequiresDirective rd) {
if ((rd.module.flags() & Flags.AUTOMATIC_MODULE) != 0) {
- deferredLintHandler.report(_ -> {
- if (rd.isTransitive() && lint.isEnabled(LintCategory.REQUIRES_TRANSITIVE_AUTOMATIC)) {
- log.warning(pos, LintWarnings.RequiresTransitiveAutomatic);
- } else {
- lint.logIfEnabled(pos, LintWarnings.RequiresAutomatic);
- }
- });
+ if (rd.isTransitive()) { // see comment in Log.applyLint() for special logic that applies
+ log.warning(pos, LintWarnings.RequiresTransitiveAutomatic);
+ } else {
+ log.warning(pos, LintWarnings.RequiresAutomatic);
+ }
}
}
@@ -5693,14 +5633,14 @@ public class Check {
VarSymbol lastParam = ms.params.head;
for (VarSymbol param: ms.params) {
if ((param.flags_field & REQUIRES_IDENTITY) != 0 && argExps.head.type.isValueBased()) {
- lint.logIfEnabled(argExps.head.pos(), LintWarnings.AttemptToUseValueBasedWhereIdentityExpected);
+ log.warning(argExps.head.pos(), LintWarnings.AttemptToUseValueBasedWhereIdentityExpected);
}
lastParam = param;
argExps = argExps.tail;
}
while (argExps != null && !argExps.isEmpty() && lastParam != null) {
if ((lastParam.flags_field & REQUIRES_IDENTITY) != 0 && argExps.head.type.isValueBased()) {
- lint.logIfEnabled(argExps.head.pos(), LintWarnings.AttemptToUseValueBasedWhereIdentityExpected);
+ log.warning(argExps.head.pos(), LintWarnings.AttemptToUseValueBasedWhereIdentityExpected);
}
argExps = argExps.tail;
}
@@ -5727,7 +5667,7 @@ public class Check {
// we need to avoid recursion due to self referencing type vars or captures, this is why we need a set
requiresIdentityVisitor.visit(t, new HashSet<>());
if (requiresIdentityVisitor.requiresWarning) {
- lint.logIfEnabled(pos, LintWarnings.AttemptToUseValueBasedWhereIdentityExpected);
+ log.warning(pos, LintWarnings.AttemptToUseValueBasedWhereIdentityExpected);
return true;
}
}
@@ -5804,7 +5744,7 @@ public class Check {
.filter(ta -> isRequiresIdentityAnnotation(ta.type.tsym) &&
typeParamTrees.get(ta.position.parameter_index).type != null &&
typeParamTrees.get(ta.position.parameter_index).type.isValueBased())
- .forEach(ta -> lint.logIfEnabled(typeParamTrees.get(ta.position.parameter_index).pos(),
+ .forEach(ta -> log.warning(typeParamTrees.get(ta.position.parameter_index).pos(),
CompilerProperties.LintWarnings.AttemptToUseValueBasedWhereIdentityExpected));
}
}
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
index e685f139b68..3bbd007c66a 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
@@ -214,7 +214,6 @@ public class Flow {
private final Resolve rs;
private final JCDiagnostic.Factory diags;
private Env attrEnv;
- private Lint lint;
private final Infer infer;
public static Flow instance(Context context) {
@@ -337,7 +336,6 @@ public class Flow {
syms = Symtab.instance(context);
types = Types.instance(context);
chk = Check.instance(context);
- lint = Lint.instance(context);
infer = Infer.instance(context);
rs = Resolve.instance(context);
diags = JCDiagnostic.Factory.instance(context);
@@ -562,10 +560,8 @@ public class Flow {
if (tree.sym == null) return;
Liveness alivePrev = alive;
ListBuffer pendingExitsPrev = pendingExits;
- Lint lintPrev = lint;
pendingExits = new ListBuffer<>();
- lint = lint.augment(tree.sym);
try {
// process all the nested classes
@@ -596,30 +592,22 @@ public class Flow {
} finally {
pendingExits = pendingExitsPrev;
alive = alivePrev;
- lint = lintPrev;
}
}
public void visitMethodDef(JCMethodDecl tree) {
if (tree.body == null) return;
- Lint lintPrev = lint;
-
- lint = lint.augment(tree.sym);
Assert.check(pendingExits.isEmpty());
- try {
- alive = Liveness.ALIVE;
- scanStat(tree.body);
- tree.completesNormally = alive != Liveness.DEAD;
+ alive = Liveness.ALIVE;
+ scanStat(tree.body);
+ tree.completesNormally = alive != Liveness.DEAD;
- if (alive == Liveness.ALIVE && !tree.sym.type.getReturnType().hasTag(VOID))
- log.error(TreeInfo.diagEndPos(tree.body), Errors.MissingRetStmt);
+ if (alive == Liveness.ALIVE && !tree.sym.type.getReturnType().hasTag(VOID))
+ log.error(TreeInfo.diagEndPos(tree.body), Errors.MissingRetStmt);
- clearPendingExits(true);
- } finally {
- lint = lintPrev;
- }
+ clearPendingExits(true);
}
private void clearPendingExits(boolean inMethod) {
@@ -634,15 +622,7 @@ public class Flow {
}
public void visitVarDef(JCVariableDecl tree) {
- if (tree.init != null) {
- Lint lintPrev = lint;
- lint = lint.augment(tree.sym);
- try{
- scan(tree.init);
- } finally {
- lint = lintPrev;
- }
- }
+ scan(tree.init);
}
public void visitBlock(JCBlock tree) {
@@ -724,8 +704,7 @@ public class Flow {
// Warn about fall-through if lint switch fallthrough enabled.
if (alive == Liveness.ALIVE &&
c.stats.nonEmpty() && l.tail.nonEmpty())
- lint.logIfEnabled(l.tail.head.pos(),
- LintWarnings.PossibleFallThroughIntoCase);
+ log.warning(l.tail.head.pos(), LintWarnings.PossibleFallThroughIntoCase);
}
tree.isExhaustive = tree.hasUnconditionalPattern ||
TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases);
@@ -1232,7 +1211,7 @@ public class Flow {
scanStat(tree.finalizer);
tree.finallyCanCompleteNormally = alive != Liveness.DEAD;
if (alive == Liveness.DEAD) {
- lint.logIfEnabled(TreeInfo.diagEndPos(tree.finalizer),
+ log.warning(TreeInfo.diagEndPos(tree.finalizer),
LintWarnings.FinallyCannotComplete);
} else {
while (exits.nonEmpty()) {
@@ -1453,7 +1432,6 @@ public class Flow {
List thrownPrev = thrown;
List caughtPrev = caught;
ListBuffer pendingExitsPrev = pendingExits;
- Lint lintPrev = lint;
boolean anonymousClass = tree.name == names.empty;
pendingExits = new ListBuffer<>();
if (!anonymousClass) {
@@ -1461,7 +1439,6 @@ public class Flow {
}
classDef = tree;
thrown = List.nil();
- lint = lint.augment(tree.sym);
try {
// process all the nested classes
@@ -1510,7 +1487,6 @@ public class Flow {
pendingExits = pendingExitsPrev;
caught = caughtPrev;
classDef = classDefPrev;
- lint = lintPrev;
}
}
@@ -1519,9 +1495,6 @@ public class Flow {
List caughtPrev = caught;
List mthrown = tree.sym.type.getThrownTypes();
- Lint lintPrev = lint;
-
- lint = lint.augment(tree.sym);
Assert.check(pendingExits.isEmpty());
@@ -1554,20 +1527,11 @@ public class Flow {
}
} finally {
caught = caughtPrev;
- lint = lintPrev;
}
}
public void visitVarDef(JCVariableDecl tree) {
- if (tree.init != null) {
- Lint lintPrev = lint;
- lint = lint.augment(tree.sym);
- try{
- scan(tree.init);
- } finally {
- lint = lintPrev;
- }
- }
+ scan(tree.init);
}
public void visitBlock(JCBlock tree) {
@@ -2387,82 +2351,76 @@ public class Flow {
return;
}
- Lint lintPrev = lint;
- lint = lint.augment(tree.sym);
+ JCClassDecl classDefPrev = classDef;
+ int firstadrPrev = firstadr;
+ int nextadrPrev = nextadr;
+ ListBuffer pendingExitsPrev = pendingExits;
+
+ pendingExits = new ListBuffer<>();
+ if (tree.name != names.empty) {
+ firstadr = nextadr;
+ }
+ classDef = tree;
try {
- JCClassDecl classDefPrev = classDef;
- int firstadrPrev = firstadr;
- int nextadrPrev = nextadr;
- ListBuffer pendingExitsPrev = pendingExits;
-
- pendingExits = new ListBuffer<>();
- if (tree.name != names.empty) {
- firstadr = nextadr;
+ // define all the static fields
+ for (List l = tree.defs; l.nonEmpty(); l = l.tail) {
+ if (l.head.hasTag(VARDEF)) {
+ JCVariableDecl def = (JCVariableDecl)l.head;
+ if ((def.mods.flags & STATIC) != 0) {
+ VarSymbol sym = def.sym;
+ if (trackable(sym)) {
+ newVar(def);
+ }
+ }
+ }
}
- classDef = tree;
- try {
- // define all the static fields
- for (List l = tree.defs; l.nonEmpty(); l = l.tail) {
- if (l.head.hasTag(VARDEF)) {
- JCVariableDecl def = (JCVariableDecl)l.head;
- if ((def.mods.flags & STATIC) != 0) {
- VarSymbol sym = def.sym;
- if (trackable(sym)) {
- newVar(def);
- }
+
+ // process all the static initializers
+ forEachInitializer(tree, true, def -> {
+ scan(def);
+ clearPendingExits(false);
+ });
+
+ // verify all static final fields got initialized
+ for (int i = firstadr; i < nextadr; i++) {
+ JCVariableDecl vardecl = vardecls[i];
+ VarSymbol var = vardecl.sym;
+ if (var.owner == classDef.sym && var.isStatic()) {
+ checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
+ }
+ }
+
+ // define all the instance fields
+ for (List l = tree.defs; l.nonEmpty(); l = l.tail) {
+ if (l.head.hasTag(VARDEF)) {
+ JCVariableDecl def = (JCVariableDecl)l.head;
+ if ((def.mods.flags & STATIC) == 0) {
+ VarSymbol sym = def.sym;
+ if (trackable(sym)) {
+ newVar(def);
}
}
}
+ }
- // process all the static initializers
- forEachInitializer(tree, true, def -> {
- scan(def);
- clearPendingExits(false);
- });
-
- // verify all static final fields got initialized
- for (int i = firstadr; i < nextadr; i++) {
- JCVariableDecl vardecl = vardecls[i];
- VarSymbol var = vardecl.sym;
- if (var.owner == classDef.sym && var.isStatic()) {
- checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
- }
+ // process all the methods
+ for (List l = tree.defs; l.nonEmpty(); l = l.tail) {
+ if (l.head.hasTag(METHODDEF)) {
+ scan(l.head);
}
+ }
- // define all the instance fields
- for (List l = tree.defs; l.nonEmpty(); l = l.tail) {
- if (l.head.hasTag(VARDEF)) {
- JCVariableDecl def = (JCVariableDecl)l.head;
- if ((def.mods.flags & STATIC) == 0) {
- VarSymbol sym = def.sym;
- if (trackable(sym)) {
- newVar(def);
- }
- }
- }
+ // process all the nested classes
+ for (List l = tree.defs; l.nonEmpty(); l = l.tail) {
+ if (l.head.hasTag(CLASSDEF)) {
+ scan(l.head);
}
-
- // process all the methods
- for (List l = tree.defs; l.nonEmpty(); l = l.tail) {
- if (l.head.hasTag(METHODDEF)) {
- scan(l.head);
- }
- }
-
- // process all the nested classes
- for (List l = tree.defs; l.nonEmpty(); l = l.tail) {
- if (l.head.hasTag(CLASSDEF)) {
- scan(l.head);
- }
- }
- } finally {
- pendingExits = pendingExitsPrev;
- nextadr = nextadrPrev;
- firstadr = firstadrPrev;
- classDef = classDefPrev;
}
} finally {
- lint = lintPrev;
+ pendingExits = pendingExitsPrev;
+ nextadr = nextadrPrev;
+ firstadr = firstadrPrev;
+ classDef = classDefPrev;
}
}
@@ -2477,87 +2435,81 @@ public class Flow {
return;
}
- Lint lintPrev = lint;
- lint = lint.augment(tree.sym);
+ final Bits initsPrev = new Bits(inits);
+ final Bits uninitsPrev = new Bits(uninits);
+ int nextadrPrev = nextadr;
+ int firstadrPrev = firstadr;
+ int returnadrPrev = returnadr;
+
+ Assert.check(pendingExits.isEmpty());
+ boolean isConstructorPrev = isConstructor;
try {
- final Bits initsPrev = new Bits(inits);
- final Bits uninitsPrev = new Bits(uninits);
- int nextadrPrev = nextadr;
- int firstadrPrev = firstadr;
- int returnadrPrev = returnadr;
+ isConstructor = TreeInfo.isConstructor(tree);
- Assert.check(pendingExits.isEmpty());
- boolean isConstructorPrev = isConstructor;
- try {
- isConstructor = TreeInfo.isConstructor(tree);
+ // We only track field initialization inside constructors
+ if (!isConstructor) {
+ firstadr = nextadr;
+ }
- // We only track field initialization inside constructors
- if (!isConstructor) {
- firstadr = nextadr;
- }
+ // Mark all method parameters as DA
+ for (List l = tree.params; l.nonEmpty(); l = l.tail) {
+ JCVariableDecl def = l.head;
+ scan(def);
+ Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
+ /* If we are executing the code from Gen, then there can be
+ * synthetic or mandated variables, ignore them.
+ */
+ initParam(def);
+ }
+ // else we are in an instance initializer block;
+ // leave caught unchanged.
+ scan(tree.body);
- // Mark all method parameters as DA
- for (List l = tree.params; l.nonEmpty(); l = l.tail) {
- JCVariableDecl def = l.head;
- scan(def);
- Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
- /* If we are executing the code from Gen, then there can be
- * synthetic or mandated variables, ignore them.
- */
- initParam(def);
- }
- // else we are in an instance initializer block;
- // leave caught unchanged.
- scan(tree.body);
-
- boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
- (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
- if (isConstructor) {
- boolean isSynthesized = (tree.sym.flags() &
- GENERATEDCONSTR) != 0;
- for (int i = firstadr; i < nextadr; i++) {
- JCVariableDecl vardecl = vardecls[i];
- VarSymbol var = vardecl.sym;
- if (var.owner == classDef.sym && !var.isStatic()) {
- // choose the diagnostic position based on whether
- // the ctor is default(synthesized) or not
- if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
- checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
- var, Errors.VarNotInitializedInDefaultConstructor(var));
- } else if (isCompactOrGeneratedRecordConstructor) {
- boolean isInstanceRecordField = var.enclClass().isRecord() &&
- (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
- var.owner.kind == TYP;
- if (isInstanceRecordField) {
- boolean notInitialized = !inits.isMember(var.adr);
- if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
- /* this way we indicate Lower that it should generate an initialization for this field
- * in the compact constructor
- */
- var.flags_field |= UNINITIALIZED_FIELD;
- } else {
- checkInit(TreeInfo.diagEndPos(tree.body), var);
- }
+ boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
+ (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
+ if (isConstructor) {
+ boolean isSynthesized = (tree.sym.flags() &
+ GENERATEDCONSTR) != 0;
+ for (int i = firstadr; i < nextadr; i++) {
+ JCVariableDecl vardecl = vardecls[i];
+ VarSymbol var = vardecl.sym;
+ if (var.owner == classDef.sym && !var.isStatic()) {
+ // choose the diagnostic position based on whether
+ // the ctor is default(synthesized) or not
+ if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
+ checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
+ var, Errors.VarNotInitializedInDefaultConstructor(var));
+ } else if (isCompactOrGeneratedRecordConstructor) {
+ boolean isInstanceRecordField = var.enclClass().isRecord() &&
+ (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
+ var.owner.kind == TYP;
+ if (isInstanceRecordField) {
+ boolean notInitialized = !inits.isMember(var.adr);
+ if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
+ /* this way we indicate Lower that it should generate an initialization for this field
+ * in the compact constructor
+ */
+ var.flags_field |= UNINITIALIZED_FIELD;
} else {
- checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
+ checkInit(TreeInfo.diagEndPos(tree.body), var);
}
} else {
- checkInit(TreeInfo.diagEndPos(tree.body), var);
+ checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
}
+ } else {
+ checkInit(TreeInfo.diagEndPos(tree.body), var);
}
}
}
- clearPendingExits(true);
- } finally {
- inits.assign(initsPrev);
- uninits.assign(uninitsPrev);
- nextadr = nextadrPrev;
- firstadr = firstadrPrev;
- returnadr = returnadrPrev;
- isConstructor = isConstructorPrev;
}
+ clearPendingExits(true);
} finally {
- lint = lintPrev;
+ inits.assign(initsPrev);
+ uninits.assign(uninitsPrev);
+ nextadr = nextadrPrev;
+ firstadr = firstadrPrev;
+ returnadr = returnadrPrev;
+ isConstructor = isConstructorPrev;
}
}
@@ -2585,21 +2537,15 @@ public class Flow {
}
public void visitVarDef(JCVariableDecl tree) {
- Lint lintPrev = lint;
- lint = lint.augment(tree.sym);
- try{
- boolean track = trackable(tree.sym);
- if (track && (tree.sym.owner.kind == MTH || tree.sym.owner.kind == VAR)) {
- newVar(tree);
+ boolean track = trackable(tree.sym);
+ if (track && (tree.sym.owner.kind == MTH || tree.sym.owner.kind == VAR)) {
+ newVar(tree);
+ }
+ if (tree.init != null) {
+ scanExpr(tree.init);
+ if (track) {
+ letInit(tree.pos(), tree.sym);
}
- if (tree.init != null) {
- scanExpr(tree.init);
- if (track) {
- letInit(tree.pos(), tree.sym);
- }
- }
- } finally {
- lint = lintPrev;
}
}
@@ -2851,8 +2797,7 @@ public class Flow {
final Bits uninitsEnd = new Bits(uninits);
int nextadrCatch = nextadr;
- if (!resourceVarDecls.isEmpty() &&
- lint.isEnabled(Lint.LintCategory.TRY)) {
+ if (!resourceVarDecls.isEmpty()) {
for (JCVariableDecl resVar : resourceVarDecls) {
if (unrefdResources.includes(resVar.sym) && !resVar.sym.isUnnamedVariable()) {
log.warning(resVar.pos(),
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java
index b726cc7a61d..d63ba1677d6 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java
@@ -66,7 +66,6 @@ public class MemberEnter extends JCTree.Visitor {
private final Annotate annotate;
private final Types types;
private final Names names;
- private final DeferredLintHandler deferredLintHandler;
public static MemberEnter instance(Context context) {
MemberEnter instance = context.get(memberEnterKey);
@@ -87,7 +86,6 @@ public class MemberEnter extends JCTree.Visitor {
types = Types.instance(context);
source = Source.instance(context);
names = Names.instance(context);
- deferredLintHandler = DeferredLintHandler.instance(context);
}
/** Construct method type from method signature.
@@ -194,16 +192,11 @@ public class MemberEnter extends JCTree.Visitor {
}
Env localEnv = methodEnv(tree, env);
- deferredLintHandler.push(tree);
- try {
- // Compute the method type
- m.type = signature(m, tree.typarams, tree.params,
- tree.restype, tree.recvparam,
- tree.thrown,
- localEnv);
- } finally {
- deferredLintHandler.pop();
- }
+ // Compute the method type
+ m.type = signature(m, tree.typarams, tree.params,
+ tree.restype, tree.recvparam,
+ tree.thrown,
+ localEnv);
if (types.isSignaturePolymorphic(m)) {
m.flags_field |= SIGNATURE_POLYMORPHIC;
@@ -227,14 +220,14 @@ public class MemberEnter extends JCTree.Visitor {
enclScope.enter(m);
}
- annotate.annotateLater(tree.mods.annotations, localEnv, m, tree);
+ annotate.annotateLater(tree.mods.annotations, localEnv, m);
// Visit the signature of the method. Note that
// TypeAnnotate doesn't descend into the body.
- annotate.queueScanTreeAndTypeAnnotate(tree, localEnv, m, tree);
+ annotate.queueScanTreeAndTypeAnnotate(tree, localEnv, m);
if (tree.defaultValue != null) {
m.defaultValue = annotate.unfinishedDefaultValue(); // set it to temporary sentinel for now
- annotate.annotateDefaultValueLater(tree.defaultValue, localEnv, m, tree);
+ annotate.annotateDefaultValueLater(tree.defaultValue, localEnv, m);
}
}
@@ -263,18 +256,13 @@ public class MemberEnter extends JCTree.Visitor {
localEnv = env.dup(tree, env.info.dup());
localEnv.info.staticLevel++;
}
- deferredLintHandler.push(tree);
- try {
- if (TreeInfo.isEnumInit(tree)) {
- attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype);
- } else if (!tree.isImplicitlyTyped()) {
- attr.attribType(tree.vartype, localEnv);
- if (TreeInfo.isReceiverParam(tree))
- checkReceiver(tree, localEnv);
- }
- } finally {
- deferredLintHandler.pop();
+ if (TreeInfo.isEnumInit(tree)) {
+ attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype);
+ } else if (!tree.isImplicitlyTyped()) {
+ attr.attribType(tree.vartype, localEnv);
+ if (TreeInfo.isReceiverParam(tree))
+ checkReceiver(tree, localEnv);
}
if ((tree.mods.flags & VARARGS) != 0) {
@@ -315,9 +303,9 @@ public class MemberEnter extends JCTree.Visitor {
}
}
- annotate.annotateLater(tree.mods.annotations, localEnv, v, tree);
+ annotate.annotateLater(tree.mods.annotations, localEnv, v);
if (!tree.isImplicitlyTyped()) {
- annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree);
+ annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v);
}
v.pos = tree.pos;
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java
index 4d0af014d83..0cef9cc6602 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java
@@ -52,7 +52,6 @@ import javax.tools.JavaFileObject.Kind;
import javax.tools.StandardLocation;
import com.sun.source.tree.ModuleTree.ModuleKind;
-import com.sun.tools.javac.code.DeferredLintHandler;
import com.sun.tools.javac.code.Directive;
import com.sun.tools.javac.code.Directive.ExportsDirective;
import com.sun.tools.javac.code.Directive.ExportsFlag;
@@ -141,7 +140,6 @@ public class Modules extends JCTree.Visitor {
private final Attr attr;
private final Check chk;
private final Preview preview;
- private final DeferredLintHandler deferredLintHandler;
private final TypeEnvs typeEnvs;
private final Types types;
private final JavaFileManager fileManager;
@@ -169,8 +167,6 @@ public class Modules extends JCTree.Visitor {
private final String moduleVersionOpt;
private final boolean sourceLauncher;
- private final boolean lintOptions;
-
private Set rootModules = null;
private final Set warnedMissing = new HashSet<>();
@@ -193,7 +189,6 @@ public class Modules extends JCTree.Visitor {
attr = Attr.instance(context);
chk = Check.instance(context);
preview = Preview.instance(context);
- deferredLintHandler = DeferredLintHandler.instance(context);
typeEnvs = TypeEnvs.instance(context);
moduleFinder = ModuleFinder.instance(context);
types = Types.instance(context);
@@ -205,8 +200,6 @@ public class Modules extends JCTree.Visitor {
allowAccessIntoSystem = options.isUnset(Option.RELEASE);
- lintOptions = !options.isLintDisabled(LintCategory.OPTIONS);
-
multiModuleMode = fileManager.hasLocation(StandardLocation.MODULE_SOURCE_PATH);
ClassWriter classWriter = ClassWriter.instance(context);
classWriter.multiModuleMode = multiModuleMode;
@@ -746,7 +739,6 @@ public class Modules extends JCTree.Visitor {
ModuleVisitor v = new ModuleVisitor();
JavaFileObject prev = log.useSource(tree.sourcefile);
JCModuleDecl moduleDecl = tree.getModuleDecl();
- deferredLintHandler.push(moduleDecl);
try {
moduleDecl.accept(v);
@@ -754,7 +746,6 @@ public class Modules extends JCTree.Visitor {
checkCyclicDependencies(moduleDecl);
} finally {
log.useSource(prev);
- deferredLintHandler.pop();
msym.flags_field &= ~UNATTRIBUTED;
}
}
@@ -991,13 +982,11 @@ public class Modules extends JCTree.Visitor {
UsesProvidesVisitor v = new UsesProvidesVisitor(msym, env);
JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
JCModuleDecl decl = env.toplevel.getModuleDecl();
- deferredLintHandler.push(decl);
try {
decl.accept(v);
} finally {
log.useSource(prev);
- deferredLintHandler.pop();
}
};
}
@@ -1263,12 +1252,9 @@ public class Modules extends JCTree.Visitor {
}
observable = computeTransitiveClosure(limitMods, rootModules, null);
observable.addAll(rootModules);
- if (lintOptions) {
- for (ModuleSymbol msym : limitMods) {
- if (!observable.contains(msym)) {
- log.warning(
- LintWarnings.ModuleForOptionNotFound(Option.LIMIT_MODULES, msym));
- }
+ for (ModuleSymbol msym : limitMods) {
+ if (!observable.contains(msym)) {
+ log.warning(LintWarnings.ModuleForOptionNotFound(Option.LIMIT_MODULES, msym));
}
}
}
@@ -1721,10 +1707,7 @@ public class Modules extends JCTree.Visitor {
}
if (!unknownModules.contains(msym)) {
- if (lintOptions) {
- log.warning(
- LintWarnings.ModuleForOptionNotFound(Option.ADD_EXPORTS, msym));
- }
+ log.warning(LintWarnings.ModuleForOptionNotFound(Option.ADD_EXPORTS, msym));
unknownModules.add(msym);
}
return false;
@@ -1760,9 +1743,7 @@ public class Modules extends JCTree.Visitor {
ModuleSymbol msym = syms.enterModule(names.fromString(sourceName));
if (!allModules.contains(msym)) {
- if (lintOptions) {
- log.warning(LintWarnings.ModuleForOptionNotFound(Option.ADD_READS, msym));
- }
+ log.warning(LintWarnings.ModuleForOptionNotFound(Option.ADD_READS, msym));
continue;
}
@@ -1780,9 +1761,7 @@ public class Modules extends JCTree.Visitor {
continue;
targetModule = syms.enterModule(names.fromString(targetName));
if (!allModules.contains(targetModule)) {
- if (lintOptions) {
- log.warning(LintWarnings.ModuleForOptionNotFound(Option.ADD_READS, targetModule));
- }
+ log.warning(LintWarnings.ModuleForOptionNotFound(Option.ADD_READS, targetModule));
continue;
}
}
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java
index 9119278660f..6fb1feed08d 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java
@@ -45,6 +45,7 @@ import java.util.stream.Stream;
import com.sun.tools.javac.code.Directive;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Lint;
+import com.sun.tools.javac.code.LintMapper;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Symtab;
@@ -57,6 +58,7 @@ import com.sun.tools.javac.tree.TreeInfo;
import com.sun.tools.javac.tree.TreeScanner;
import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.JCDiagnostic.LintWarning;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Log;
@@ -67,6 +69,7 @@ import static com.sun.tools.javac.code.Kinds.Kind.*;
import static com.sun.tools.javac.code.Lint.LintCategory.THIS_ESCAPE;
import static com.sun.tools.javac.code.TypeTag.*;
import static com.sun.tools.javac.tree.JCTree.Tag.*;
+import static com.sun.tools.javac.util.Position.NOPOS;
/**
* Looks for possible 'this' escapes and generates corresponding warnings.
@@ -156,7 +159,7 @@ public class ThisEscapeAnalyzer extends TreeScanner {
private final Types types;
private final Resolve rs;
private final Log log;
- private Lint lint;
+ private final LintMapper lintMapper;
// These fields are scoped to the entire compilation unit
@@ -168,10 +171,6 @@ public class ThisEscapeAnalyzer extends TreeScanner {
*/
private final Map methodMap = new LinkedHashMap<>();
- /** Contains symbols of fields and constructors that have warnings suppressed.
- */
- private final Set suppressed = new HashSet<>();
-
/** Contains classes whose outer instance (if any) is non-public.
*/
private final Set nonPublicOuters = new HashSet<>();
@@ -231,7 +230,7 @@ public class ThisEscapeAnalyzer extends TreeScanner {
syms = Symtab.instance(context);
types = Types.instance(context);
rs = Resolve.instance(context);
- lint = Lint.instance(context);
+ lintMapper = LintMapper.instance(context);
}
//
@@ -262,8 +261,8 @@ public class ThisEscapeAnalyzer extends TreeScanner {
Assert.check(checkInvariants(false, false));
Assert.check(methodMap.isEmpty()); // we are not prepared to be used more than once
- // Short circuit if warnings are totally disabled
- if (!lint.isEnabled(THIS_ESCAPE))
+ // Short circuit if this calculation is unnecessary
+ if (!lintMapper.lintAt(env.toplevel.sourcefile, env.tree.pos()).get().isEnabled(THIS_ESCAPE))
return;
// Determine which packages are exported by the containing module, if any.
@@ -278,11 +277,9 @@ public class ThisEscapeAnalyzer extends TreeScanner {
// Build a mapping from symbols of methods to their declarations.
// Classify all ctors and methods as analyzable and/or invokable.
- // Track which constructors and fields have warnings suppressed.
// Record classes whose outer instance (if any) is non-public.
new TreeScanner() {
- private Lint lint = ThisEscapeAnalyzer.this.lint;
private JCClassDecl currentClass;
private boolean nonPublicOuter;
@@ -290,8 +287,6 @@ public class ThisEscapeAnalyzer extends TreeScanner {
public void visitClassDef(JCClassDecl tree) {
JCClassDecl currentClassPrev = currentClass;
boolean nonPublicOuterPrev = nonPublicOuter;
- Lint lintPrev = lint;
- lint = lint.augment(tree.sym);
try {
currentClass = tree;
@@ -306,57 +301,29 @@ public class ThisEscapeAnalyzer extends TreeScanner {
} finally {
currentClass = currentClassPrev;
nonPublicOuter = nonPublicOuterPrev;
- lint = lintPrev;
- }
- }
-
- @Override
- public void visitVarDef(JCVariableDecl tree) {
- Lint lintPrev = lint;
- lint = lint.augment(tree.sym);
- try {
-
- // Track warning suppression of fields
- if (tree.sym.owner.kind == TYP && !lint.isEnabled(THIS_ESCAPE))
- suppressed.add(tree.sym);
-
- // Recurse
- super.visitVarDef(tree);
- } finally {
- lint = lintPrev;
}
}
@Override
public void visitMethodDef(JCMethodDecl tree) {
- Lint lintPrev = lint;
- lint = lint.augment(tree.sym);
- try {
- // Track warning suppression of constructors
- if (TreeInfo.isConstructor(tree) && !lint.isEnabled(THIS_ESCAPE))
- suppressed.add(tree.sym);
+ // Gather some useful info
+ boolean constructor = TreeInfo.isConstructor(tree);
+ boolean extendableClass = currentClassIsExternallyExtendable();
+ boolean nonPrivate = (tree.sym.flags() & (Flags.PUBLIC | Flags.PROTECTED)) != 0;
+ boolean finalish = (tree.mods.flags & (Flags.STATIC | Flags.PRIVATE | Flags.FINAL)) != 0;
- // Gather some useful info
- boolean constructor = TreeInfo.isConstructor(tree);
- boolean extendableClass = currentClassIsExternallyExtendable();
- boolean nonPrivate = (tree.sym.flags() & (Flags.PUBLIC | Flags.PROTECTED)) != 0;
- boolean finalish = (tree.mods.flags & (Flags.STATIC | Flags.PRIVATE | Flags.FINAL)) != 0;
+ // Determine if this is a constructor we should analyze
+ boolean analyzable = extendableClass && constructor && nonPrivate;
- // Determine if this is a constructor we should analyze
- boolean analyzable = extendableClass && constructor && nonPrivate;
+ // Determine if it's safe to "invoke" the method in an analysis (i.e., it can't be overridden)
+ boolean invokable = !extendableClass || constructor || finalish;
- // Determine if it's safe to "invoke" the method in an analysis (i.e., it can't be overridden)
- boolean invokable = !extendableClass || constructor || finalish;
+ // Add this method or constructor to our map
+ methodMap.put(tree.sym, new MethodInfo(currentClass, tree, constructor, analyzable, invokable));
- // Add this method or constructor to our map
- methodMap.put(tree.sym, new MethodInfo(currentClass, tree, constructor, analyzable, invokable));
-
- // Recurse
- super.visitMethodDef(tree);
- } finally {
- lint = lintPrev;
- }
+ // Recurse
+ super.visitMethodDef(tree);
}
// Determines if the current class could be extended in some other package/module
@@ -401,7 +368,7 @@ public class ThisEscapeAnalyzer extends TreeScanner {
for (Warning warning : warningList) {
LintWarning key = LintWarnings.PossibleThisEscape;
for (StackFrame frame : warning.stack) {
- log.warning(frame.site.pos(), key);
+ log.warning(frame.warningPos(), key);
key = LintWarnings.PossibleThisEscapeLocation;
}
}
@@ -1746,9 +1713,16 @@ public class ThisEscapeAnalyzer extends TreeScanner {
this.suppressible = initializer != null || (method.constructor && method.declaringClass == targetClass);
}
+ DiagnosticPosition warningPos() {
+ return site.pos().withLintPosition(NOPOS); // disable normal Lint suppression
+ }
+
+ Lint lint() {
+ return lintMapper.lintAt(topLevelEnv.toplevel.sourcefile, site.pos()).get();
+ }
+
boolean isSuppressed() {
- return suppressible &&
- suppressed.contains(initializer instanceof JCVariableDecl v ? v.sym : method.declaration.sym);
+ return suppressible && !lint().isEnabled(THIS_ESCAPE);
}
int comparePos(StackFrame that) {
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java
index eb4ab96dfd2..8648b929a04 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java
@@ -34,7 +34,6 @@ import javax.tools.JavaFileObject;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Directive.ExportsDirective;
import com.sun.tools.javac.code.Directive.RequiresDirective;
-import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Scope.ImportFilter;
import com.sun.tools.javac.code.Scope.NamedImportScope;
import com.sun.tools.javac.code.Scope.StarImportScope;
@@ -108,8 +107,6 @@ public class TypeEnter implements Completer {
private final Annotate annotate;
private final TypeAnnotations typeAnnotations;
private final Types types;
- private final DeferredLintHandler deferredLintHandler;
- private final Lint lint;
private final TypeEnvs typeEnvs;
private final Dependencies dependencies;
@@ -135,8 +132,6 @@ public class TypeEnter implements Completer {
annotate = Annotate.instance(context);
typeAnnotations = TypeAnnotations.instance(context);
types = Types.instance(context);
- deferredLintHandler = DeferredLintHandler.instance(context);
- lint = Lint.instance(context);
typeEnvs = TypeEnvs.instance(context);
dependencies = Dependencies.instance(context);
Source source = Source.instance(context);
@@ -274,7 +269,6 @@ public class TypeEnter implements Completer {
queue.add(env);
JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
- deferredLintHandler.push(tree);
try {
dependencies.push(env.enclClass.sym, phaseName);
runPhase(env);
@@ -282,7 +276,6 @@ public class TypeEnter implements Completer {
chk.completionError(tree.pos(), ex);
} finally {
dependencies.pop();
- deferredLintHandler.pop();
log.useSource(prev);
}
}
@@ -351,8 +344,6 @@ public class TypeEnter implements Completer {
ImportFilter prevStaticImportFilter = staticImportFilter;
ImportFilter prevTypeImportFilter = typeImportFilter;
- deferredLintHandler.pushImmediate(lint);
- Lint prevLint = chk.setLint(lint);
Env prevEnv = this.env;
try {
this.env = env;
@@ -376,20 +367,13 @@ public class TypeEnter implements Completer {
handleImports(tree.getImports());
if (decl != null) {
- deferredLintHandler.push(decl);
- try {
- //check @Deprecated:
- markDeprecated(decl.sym, decl.mods.annotations, env);
- } finally {
- deferredLintHandler.pop();
- }
+ //check for @Deprecated annotations
+ markDeprecated(decl.sym, decl.mods.annotations, env);
// process module annotations
- annotate.annotateLater(decl.mods.annotations, env, env.toplevel.modle, decl);
+ annotate.annotateLater(decl.mods.annotations, env, env.toplevel.modle);
}
} finally {
this.env = prevEnv;
- chk.setLint(prevLint);
- deferredLintHandler.pop();
this.staticImportFilter = prevStaticImportFilter;
this.typeImportFilter = prevTypeImportFilter;
}
@@ -422,7 +406,7 @@ public class TypeEnter implements Completer {
}
}
// process package annotations
- annotate.annotateLater(tree.annotations, env, env.toplevel.packge, tree);
+ annotate.annotateLater(tree.annotations, env, env.toplevel.packge);
}
private void doImport(JCImport tree, boolean fromModuleImport) {
@@ -914,9 +898,9 @@ public class TypeEnter implements Completer {
Env baseEnv = baseEnv(tree, env);
if (tree.extending != null)
- annotate.queueScanTreeAndTypeAnnotate(tree.extending, baseEnv, sym, tree);
+ annotate.queueScanTreeAndTypeAnnotate(tree.extending, baseEnv, sym);
for (JCExpression impl : tree.implementing)
- annotate.queueScanTreeAndTypeAnnotate(impl, baseEnv, sym, tree);
+ annotate.queueScanTreeAndTypeAnnotate(impl, baseEnv, sym);
annotate.flush();
attribSuperTypes(env, baseEnv);
@@ -931,11 +915,11 @@ public class TypeEnter implements Completer {
chk.checkNotRepeated(iface.pos(), types.erasure(it), interfaceSet);
}
- annotate.annotateLater(tree.mods.annotations, baseEnv, sym, tree);
+ annotate.annotateLater(tree.mods.annotations, baseEnv, sym);
attr.attribTypeVariables(tree.typarams, baseEnv, false);
for (JCTypeParameter tp : tree.typarams)
- annotate.queueScanTreeAndTypeAnnotate(tp, baseEnv, sym, tree);
+ annotate.queueScanTreeAndTypeAnnotate(tp, baseEnv, sym);
// check that no package exists with same fully qualified name,
// but admit classes in the unnamed package which have the same
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java
index 73f86239713..5964c16c151 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java
@@ -92,7 +92,7 @@ public abstract class BaseFileManager implements JavaFileManager {
options = Options.instance(context);
// Initialize locations
- locations.update(log, lint, FSInfo.instance(context));
+ locations.update(log, FSInfo.instance(context));
// Apply options
options.whenReady(this::applyOptions);
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java
index ff02de705fb..c4573b9a364 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java
@@ -77,12 +77,11 @@ import javax.tools.StandardJavaFileManager;
import javax.tools.StandardJavaFileManager.PathFactory;
import javax.tools.StandardLocation;
-import com.sun.tools.javac.code.Lint;
-import com.sun.tools.javac.resources.CompilerProperties.LintWarnings;
import jdk.internal.jmod.JmodFile;
import com.sun.tools.javac.main.Option;
import com.sun.tools.javac.resources.CompilerProperties.Errors;
+import com.sun.tools.javac.resources.CompilerProperties.LintWarnings;
import com.sun.tools.javac.util.DefinedBy;
import com.sun.tools.javac.util.DefinedBy.Api;
import com.sun.tools.javac.util.ListBuffer;
@@ -123,11 +122,6 @@ public class Locations {
*/
private FSInfo fsInfo;
- /**
- * The root {@link Lint} instance.
- */
- private Lint lint;
-
private ModuleNameReader moduleNameReader;
private PathFactory pathFactory = Paths::get;
@@ -168,9 +162,8 @@ public class Locations {
}
}
- void update(Log log, Lint lint, FSInfo fsInfo) {
+ void update(Log log, FSInfo fsInfo) {
this.log = log;
- this.lint = lint;
this.fsInfo = fsInfo;
}
@@ -221,7 +214,7 @@ public class Locations {
try {
entries.add(getPath(s));
} catch (IllegalArgumentException e) {
- lint.logIfEnabled(LintWarnings.InvalidPath(s));
+ log.warning(LintWarnings.InvalidPath(s));
}
}
}
@@ -316,7 +309,7 @@ public class Locations {
private void addDirectory(Path dir, boolean warn) {
if (!Files.isDirectory(dir)) {
if (warn) {
- lint.logIfEnabled(LintWarnings.DirPathElementNotFound(dir));
+ log.warning(LintWarnings.DirPathElementNotFound(dir));
}
return;
}
@@ -361,7 +354,7 @@ public class Locations {
if (!fsInfo.exists(file)) {
/* No such file or directory exists */
if (warn) {
- lint.logIfEnabled(LintWarnings.PathElementNotFound(file));
+ log.warning(LintWarnings.PathElementNotFound(file));
}
super.add(file);
return;
@@ -383,12 +376,12 @@ public class Locations {
try {
FileSystems.newFileSystem(file, (ClassLoader)null).close();
if (warn) {
- lint.logIfEnabled(LintWarnings.UnexpectedArchiveFile(file));
+ log.warning(LintWarnings.UnexpectedArchiveFile(file));
}
} catch (IOException | ProviderNotFoundException e) {
// FIXME: include e.getLocalizedMessage in warning
if (warn) {
- lint.logIfEnabled(LintWarnings.InvalidArchiveFile(file));
+ log.warning(LintWarnings.InvalidArchiveFile(file));
}
return;
}
@@ -1651,7 +1644,7 @@ public class Locations {
void add(Map> map, Path prefix, Path suffix) {
if (!Files.isDirectory(prefix)) {
- lint.logIfEnabled(Files.exists(prefix) ?
+ log.warning(Files.exists(prefix) ?
LintWarnings.DirPathElementNotDirectory(prefix) :
LintWarnings.DirPathElementNotFound(prefix));
return;
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java
index cf751ff6b30..6f1ad28586d 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java
@@ -51,7 +51,6 @@ import com.sun.tools.javac.comp.Annotate;
import com.sun.tools.javac.comp.Annotate.AnnotationTypeCompleter;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Directive.*;
-import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Symtab;
@@ -139,9 +138,6 @@ public class ClassReader {
/** The symbol table. */
Symtab syms;
- /** The root Lint config. */
- Lint lint;
-
Types types;
/** The name table. */
@@ -303,8 +299,6 @@ public class ClassReader {
typevars = WriteableScope.create(syms.noSymbol);
- lint = Lint.instance(context);
-
initAttributeReaders();
}
@@ -854,8 +848,7 @@ public class ClassReader {
if (!warnedAttrs.contains(name)) {
JavaFileObject prev = log.useSource(currentClassFile);
try {
- lint.logIfEnabled(
- LintWarnings.FutureAttr(name, version.major, version.minor, majorVersion, minorVersion));
+ log.warning(LintWarnings.FutureAttr(name, version.major, version.minor, majorVersion, minorVersion));
} finally {
log.useSource(prev);
}
@@ -1609,7 +1602,7 @@ public class ClassReader {
} else if (parameterAnnotations.length != numParameters) {
//the RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations
//provide annotations for a different number of parameters, ignore:
- lint.logIfEnabled(LintWarnings.RuntimeVisibleInvisibleParamAnnotationsMismatch(currentClassFile));
+ log.warning(LintWarnings.RuntimeVisibleInvisibleParamAnnotationsMismatch(currentClassFile));
for (int pnum = 0; pnum < numParameters; pnum++) {
readAnnotations();
}
@@ -2075,9 +2068,9 @@ public class ClassReader {
JavaFileObject prevSource = log.useSource(requestingOwner.classfile);
try {
if (failure == null) {
- lint.logIfEnabled(LintWarnings.AnnotationMethodNotFound(container, name));
+ log.warning(LintWarnings.AnnotationMethodNotFound(container, name));
} else {
- lint.logIfEnabled(LintWarnings.AnnotationMethodNotFoundReason(container,
+ log.warning(LintWarnings.AnnotationMethodNotFoundReason(container,
name,
failure.getDetailValue()));//diagnostic, if present
}
@@ -2954,7 +2947,7 @@ public class ClassReader {
private void dropParameterAnnotations() {
parameterAnnotations = null;
- lint.logIfEnabled(LintWarnings.RuntimeInvisibleParameterAnnotations(currentClassFile));
+ log.warning(LintWarnings.RuntimeInvisibleParameterAnnotations(currentClassFile));
}
/**
* Creates the parameter at the position {@code mpIndex} in the parameter list of the owning method.
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java
index 7aa1cc473b5..58beee78af2 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java
@@ -52,7 +52,6 @@ import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import com.sun.tools.doclint.DocLint;
-import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.file.BaseFileManager;
import com.sun.tools.javac.file.JavacFileManager;
@@ -503,12 +502,9 @@ public class Arguments {
}
} else {
// single-module or legacy mode
- boolean lintPaths = !options.isLintDisabled(LintCategory.PATH);
- if (lintPaths) {
- Path outDirParent = outDir.getParent();
- if (outDirParent != null && Files.exists(outDirParent.resolve("module-info.class"))) {
- log.warning(LintWarnings.OutdirIsInExplodedModule(outDir));
- }
+ Path outDirParent = outDir.getParent();
+ if (outDirParent != null && Files.exists(outDirParent.resolve("module-info.class"))) {
+ log.warning(LintWarnings.OutdirIsInExplodedModule(outDir));
}
}
}
@@ -576,15 +572,14 @@ public class Arguments {
reportDiag(Errors.SourcepathModulesourcepathConflict);
}
- boolean lintOptions = !options.isLintDisabled(LintCategory.OPTIONS);
- if (lintOptions && source.compareTo(Source.DEFAULT) < 0 && !options.isSet(Option.RELEASE)) {
+ if (source.compareTo(Source.DEFAULT) < 0 && !options.isSet(Option.RELEASE)) {
if (fm instanceof BaseFileManager baseFileManager) {
if (source.compareTo(Source.JDK8) <= 0) {
- if (baseFileManager.isDefaultBootClassPath())
+ if (baseFileManager.isDefaultBootClassPath()) {
log.warning(LintWarnings.SourceNoBootclasspath(source.name, releaseNote(source, targetString)));
- } else {
- if (baseFileManager.isDefaultSystemModulesPath())
- log.warning(LintWarnings.SourceNoSystemModulesPath(source.name, releaseNote(source, targetString)));
+ }
+ } else if (baseFileManager.isDefaultSystemModulesPath()) {
+ log.warning(LintWarnings.SourceNoSystemModulesPath(source.name, releaseNote(source, targetString)));
}
}
}
@@ -593,14 +588,14 @@ public class Arguments {
if (source.compareTo(Source.MIN) < 0) {
log.error(Errors.OptionRemovedSource(source.name, Source.MIN.name));
- } else if (source == Source.MIN && lintOptions) {
+ } else if (source == Source.MIN) {
log.warning(LintWarnings.OptionObsoleteSource(source.name));
obsoleteOptionFound = true;
}
if (target.compareTo(Target.MIN) < 0) {
log.error(Errors.OptionRemovedTarget(target, Target.MIN));
- } else if (target == Target.MIN && lintOptions) {
+ } else if (target == Target.MIN) {
log.warning(LintWarnings.OptionObsoleteTarget(target));
obsoleteOptionFound = true;
}
@@ -634,7 +629,7 @@ public class Arguments {
log.error(Errors.ProcessorpathNoProcessormodulepath);
}
- if (obsoleteOptionFound && lintOptions) {
+ if (obsoleteOptionFound) {
log.warning(LintWarnings.OptionObsoleteSuppression);
}
@@ -645,7 +640,7 @@ public class Arguments {
validateLimitModules(sv);
validateDefaultModuleForCreatedFiles(sv);
- if (lintOptions && options.isSet(Option.ADD_OPENS)) {
+ if (options.isSet(Option.ADD_OPENS)) {
log.warning(LintWarnings.AddopensIgnored);
}
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java
index 83106ff2278..ee11304dce9 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java
@@ -258,6 +258,10 @@ public class JavaCompiler {
*/
protected JNIWriter jniWriter;
+ /** The Lint mapper.
+ */
+ protected LintMapper lintMapper;
+
/** The module for the symbol table entry phases.
*/
protected Enter enter;
@@ -384,6 +388,7 @@ public class JavaCompiler {
names = Names.instance(context);
log = Log.instance(context);
+ lintMapper = LintMapper.instance(context);
diagFactory = JCDiagnostic.Factory.instance(context);
finder = ClassFinder.instance(context);
reader = ClassReader.instance(context);
@@ -575,6 +580,7 @@ public class JavaCompiler {
/** The number of errors reported so far.
*/
public int errorCount() {
+ log.reportOutstandingWarnings();
if (werror && log.nerrors == 0 && log.nwarnings > 0) {
log.error(Errors.WarningsAndWerror);
}
@@ -625,6 +631,7 @@ public class JavaCompiler {
private JCCompilationUnit parse(JavaFileObject filename, CharSequence content, boolean silent) {
long msec = now();
JCCompilationUnit tree = make.TopLevel(List.nil());
+ lintMapper.startParsingFile(filename);
if (content != null) {
if (verbose) {
log.printVerbose("parsing.started", filename);
@@ -644,6 +651,7 @@ public class JavaCompiler {
}
tree.sourcefile = filename;
+ lintMapper.finishParsingFile(tree);
if (content != null && !taskListener.isEmpty() && !silent) {
TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, tree);
@@ -1843,6 +1851,7 @@ public class JavaCompiler {
else
log.warning(Warnings.ProcUseProcOrImplicit);
}
+ log.reportOutstandingWarnings();
log.reportOutstandingNotes();
if (log.compressedOutput) {
log.note(Notes.CompressedDiags);
@@ -1916,6 +1925,7 @@ public class JavaCompiler {
attr = null;
chk = null;
gen = null;
+ lintMapper = null;
flow = null;
transTypes = null;
lower = null;
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java
index f3d0837398c..f40cb0fb6b7 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java
@@ -25,8 +25,6 @@
package com.sun.tools.javac.parser;
-import com.sun.tools.javac.code.Lint;
-import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Preview;
import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.code.Source.Feature;
@@ -83,7 +81,7 @@ public class JavaTokenizer extends UnicodeReader {
/**
* The log to be used for error reporting. Copied from scanner factory.
*/
- private final Log log;
+ protected final Log log;
/**
* The token factory. Copied from scanner factory.
@@ -135,13 +133,6 @@ public class JavaTokenizer extends UnicodeReader {
*/
protected boolean hasEscapeSequences;
- /**
- * The set of lint options currently in effect. It is initialized
- * from the context, and then is set/reset as needed by Attr as it
- * visits all the various parts of the trees during attribution.
- */
- protected final Lint lint;
-
/**
* Construct a Java token scanner from the input character buffer.
*
@@ -168,7 +159,6 @@ public class JavaTokenizer extends UnicodeReader {
this.source = fac.source;
this.preview = fac.preview;
this.enableLineDocComments = fac.enableLineDocComments;
- this.lint = fac.lint;
this.sb = new StringBuilder(256);
}
@@ -205,17 +195,6 @@ public class JavaTokenizer extends UnicodeReader {
errPos = pos;
}
- /**
- * Report a warning at the given position using the provided arguments.
- *
- * @param pos position in input buffer.
- * @param key error key to report.
- */
- protected void lexWarning(int pos, JCDiagnostic.LintWarning key) {
- DiagnosticPosition dp = new SimpleDiagnosticPosition(pos) ;
- log.warning(dp, key);
- }
-
/**
* Add a character to the literal buffer.
*
@@ -1060,17 +1039,12 @@ public class JavaTokenizer extends UnicodeReader {
// If a text block.
if (isTextBlock) {
// Verify that the incidental indentation is consistent.
- if (lint.isEnabled(LintCategory.TEXT_BLOCKS)) {
- Set checks =
- TextBlockSupport.checkWhitespace(string);
- if (checks.contains(TextBlockSupport.WhitespaceChecks.INCONSISTENT)) {
- lexWarning(pos,
- LintWarnings.InconsistentWhiteSpaceIndentation);
- }
- if (checks.contains(TextBlockSupport.WhitespaceChecks.TRAILING)) {
- lexWarning(pos,
- LintWarnings.TrailingWhiteSpaceWillBeRemoved);
- }
+ Set checks = TextBlockSupport.checkWhitespace(string);
+ if (checks.contains(TextBlockSupport.WhitespaceChecks.INCONSISTENT)) {
+ log.warning(pos, LintWarnings.InconsistentWhiteSpaceIndentation);
+ }
+ if (checks.contains(TextBlockSupport.WhitespaceChecks.TRAILING)) {
+ log.warning(pos, LintWarnings.TrailingWhiteSpaceWillBeRemoved);
}
// Remove incidental indentation.
try {
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
index b63374d9c6d..4a990701315 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
@@ -116,8 +116,6 @@ public class JavacParser implements Parser {
/** A map associating "other nearby documentation comments"
* with the preferred documentation comment for a declaration. */
protected Map> danglingComments = new HashMap<>();
- /** Handler for deferred diagnostics. */
- protected final DeferredLintHandler deferredLintHandler;
// Because of javac's limited lookahead, some contexts are ambiguous in
// the presence of type annotations even though they are not ambiguous
@@ -190,7 +188,6 @@ public class JavacParser implements Parser {
this.names = fac.names;
this.source = fac.source;
this.preview = fac.preview;
- this.deferredLintHandler = fac.deferredLintHandler;
this.allowStringFolding = fac.options.getBoolean("allowStringFolding", true);
this.keepDocComments = keepDocComments;
this.parseModuleInfo = parseModuleInfo;
@@ -216,7 +213,6 @@ public class JavacParser implements Parser {
this.names = parser.names;
this.source = parser.source;
this.preview = parser.preview;
- this.deferredLintHandler = parser.deferredLintHandler;
this.allowStringFolding = parser.allowStringFolding;
this.keepDocComments = parser.keepDocComments;
this.parseModuleInfo = false;
@@ -591,8 +587,7 @@ public class JavacParser implements Parser {
* 4. When the tree node for the declaration is finally
* available, and the primary comment, if any,
* is "attached", (in {@link #attach}) any related
- * dangling comments are also attached to the tree node
- * by registering them using the {@link #deferredLintHandler}.
+ * dangling comments are reported to the log as warnings.
* 5. (Later) Warnings may be generated for the dangling
* comments, subject to the {@code -Xlint} and
* {@code @SuppressWarnings}.
@@ -653,32 +648,22 @@ public class JavacParser implements Parser {
void reportDanglingComments(JCTree tree, Comment dc) {
var list = danglingComments.remove(dc);
if (list != null) {
- deferredLintHandler.push(tree);
- try {
- list.forEach(this::reportDanglingDocComment);
- } finally {
- deferredLintHandler.pop();
- }
+ list.forEach(c -> reportDanglingDocComment(tree, c));
}
}
/**
- * Reports an individual dangling comment using the {@link #deferredLintHandler}.
+ * Reports an individual dangling comment as a warning to the log.
* The comment may or not may generate an actual diagnostic, depending on
* the settings for {@code -Xlint} and/or {@code @SuppressWarnings}.
*
* @param c the comment
*/
- void reportDanglingDocComment(Comment c) {
+ void reportDanglingDocComment(JCTree tree, Comment c) {
var pos = c.getPos();
- if (pos != null) {
- deferredLintHandler.report(lint -> {
- if (lint.isEnabled(Lint.LintCategory.DANGLING_DOC_COMMENTS) &&
- !shebang(c, pos)) {
- log.warning(
- pos, LintWarnings.DanglingDocComment);
- }
- });
+ if (pos != null && !shebang(c, pos)) {
+ pos = pos.withLintPosition(tree.getStartPosition());
+ S.lintWarning(pos, LintWarnings.DanglingDocComment);
}
}
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Lexer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Lexer.java
index bff4e027db7..1d1e08194f7 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Lexer.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Lexer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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,6 +28,8 @@ package com.sun.tools.javac.parser;
import java.util.Queue;
import com.sun.tools.javac.parser.Tokens.*;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+import com.sun.tools.javac.util.JCDiagnostic.LintWarning;
import com.sun.tools.javac.util.Position.LineMap;
/**
@@ -103,4 +105,12 @@ public interface Lexer {
* token.
*/
Queue getDocComments();
+
+ /**
+ * Report a warning that is subject to possible suppression by {@code @SuppressWarnings}.
+ *
+ * @param pos the lexical position at which the warning occurs
+ * @param key the warning to report
+ */
+ void lintWarning(DiagnosticPosition pos, LintWarning key);
}
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ParserFactory.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ParserFactory.java
index c873c6f31b7..f9e187315ba 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ParserFactory.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ParserFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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,7 +28,6 @@ package com.sun.tools.javac.parser;
import java.util.Locale;
import com.sun.tools.javac.api.JavacTrees;
-import com.sun.tools.javac.code.DeferredLintHandler;
import com.sun.tools.javac.code.Lint;
import com.sun.tools.javac.code.Preview;
import com.sun.tools.javac.code.Source;
@@ -70,7 +69,6 @@ public class ParserFactory {
final Options options;
final ScannerFactory scannerFactory;
final Locale locale;
- final DeferredLintHandler deferredLintHandler;
private final JavacTrees trees;
@@ -88,7 +86,6 @@ public class ParserFactory {
this.options = Options.instance(context);
this.scannerFactory = ScannerFactory.instance(context);
this.locale = context.get(Locale.class);
- this.deferredLintHandler = DeferredLintHandler.instance(context);
this.trees = JavacTrees.instance(context);
}
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Scanner.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Scanner.java
index a24e73a4141..7fcb87eac7a 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Scanner.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Scanner.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -31,6 +31,8 @@ import java.util.List;
import java.util.ArrayList;
import java.util.Queue;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+import com.sun.tools.javac.util.JCDiagnostic.LintWarning;
import com.sun.tools.javac.util.Position.LineMap;
import static com.sun.tools.javac.parser.Tokens.*;
@@ -150,6 +152,11 @@ public class Scanner implements Lexer {
return docComments;
}
+ @Override
+ public void lintWarning(DiagnosticPosition pos, LintWarning key) {
+ tokenizer.log.warning(pos, key);
+ }
+
public int errPos() {
return tokenizer.errPos();
}
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ScannerFactory.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ScannerFactory.java
index 188fe838b18..66f2b66fabf 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ScannerFactory.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ScannerFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -27,7 +27,6 @@ package com.sun.tools.javac.parser;
import java.nio.CharBuffer;
-import com.sun.tools.javac.code.Lint;
import com.sun.tools.javac.code.Preview;
import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.main.Option;
@@ -62,7 +61,6 @@ public class ScannerFactory {
final Source source;
final Preview preview;
final Tokens tokens;
- final Lint lint;
final boolean enableLineDocComments;
/** Create a new scanner factory. */
@@ -74,7 +72,6 @@ public class ScannerFactory {
this.source = Source.instance(context);
this.preview = Preview.instance(context);
this.tokens = Tokens.instance(context);
- this.lint = Lint.instance(context);
var options = Options.instance(context);
this.enableLineDocComments = !options.isSet(Option.DISABLE_LINE_DOC_COMMENTS);
}
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/VirtualParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/VirtualParser.java
index ec3a373ab4e..2a819152eed 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/VirtualParser.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/VirtualParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 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
@@ -30,6 +30,7 @@ import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCErroneous;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.JCDiagnostic.Error;
+import com.sun.tools.javac.util.JCDiagnostic.LintWarning;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Position.LineMap;
@@ -167,10 +168,9 @@ public class VirtualParser extends JavacParser {
return S.getLineMap();
}
- public void commit() {
- for (int i = 0 ; i < offset ; i++) {
- S.nextToken(); // advance underlying lexer until position matches
- }
+ @Override
+ public void lintWarning(DiagnosticPosition pos, LintWarning key) {
+ // ignore
}
}
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacFiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacFiler.java
index 012ac628ecd..dc25de30b36 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacFiler.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacFiler.java
@@ -51,7 +51,6 @@ import javax.tools.JavaFileManager.Location;
import static javax.tools.StandardLocation.SOURCE_OUTPUT;
import static javax.tools.StandardLocation.CLASS_OUTPUT;
-import com.sun.tools.javac.code.Lint;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.ModuleSymbol;
import com.sun.tools.javac.code.Symtab;
@@ -62,7 +61,6 @@ import com.sun.tools.javac.resources.CompilerProperties.Warnings;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.DefinedBy.Api;
-import static com.sun.tools.javac.code.Lint.LintCategory.PROCESSING;
import com.sun.tools.javac.code.Symbol.PackageSymbol;
import com.sun.tools.javac.main.Option;
@@ -338,7 +336,6 @@ public class JavacFiler implements Filer, Closeable {
JavaFileManager fileManager;
JavacElements elementUtils;
Log log;
- Lint lint;
Modules modules;
Names names;
Symtab syms;
@@ -421,8 +418,6 @@ public class JavacFiler implements Filer, Closeable {
aggregateGeneratedClassNames = new LinkedHashSet<>();
initialClassNames = new LinkedHashSet<>();
- lint = Lint.instance(context);
-
Options options = Options.instance(context);
defaultTargetModule = options.get(Option.DEFAULT_MODULE_FOR_CREATED_FILES);
@@ -486,14 +481,12 @@ public class JavacFiler implements Filer, Closeable {
private JavaFileObject createSourceOrClassFile(ModuleSymbol mod, boolean isSourceFile, String name, Element... originatingElements) throws IOException {
Assert.checkNonNull(mod);
- if (lint.isEnabled(PROCESSING)) {
- int periodIndex = name.lastIndexOf(".");
- if (periodIndex != -1) {
- String base = name.substring(periodIndex);
- String extn = (isSourceFile ? ".java" : ".class");
- if (base.equals(extn))
- log.warning(LintWarnings.ProcSuspiciousClassName(name, extn));
- }
+ int periodIndex = name.lastIndexOf(".");
+ if (periodIndex != -1) {
+ String base = name.substring(periodIndex);
+ String extn = (isSourceFile ? ".java" : ".class");
+ if (base.equals(extn))
+ log.warning(LintWarnings.ProcSuspiciousClassName(name, extn));
}
checkNameAndExistence(mod, name, isSourceFile);
Location loc = (isSourceFile ? SOURCE_OUTPUT : CLASS_OUTPUT);
@@ -707,7 +700,7 @@ public class JavacFiler implements Filer, Closeable {
private void checkName(String name, boolean allowUnnamedPackageInfo) throws FilerException {
if (!SourceVersion.isName(name) && !isPackageInfo(name, allowUnnamedPackageInfo)) {
- lint.logIfEnabled(LintWarnings.ProcIllegalFileName(name));
+ log.warning(LintWarnings.ProcIllegalFileName(name));
throw new FilerException("Illegal name " + name);
}
}
@@ -735,11 +728,11 @@ public class JavacFiler implements Filer, Closeable {
initialClassNames.contains(typename) ||
containedInInitialInputs(typename);
if (alreadySeen) {
- lint.logIfEnabled(LintWarnings.ProcTypeRecreate(typename));
+ log.warning(LintWarnings.ProcTypeRecreate(typename));
throw new FilerException("Attempt to recreate a file for type " + typename);
}
if (existing != null) {
- lint.logIfEnabled(LintWarnings.ProcTypeAlreadyExists(typename));
+ log.warning(LintWarnings.ProcTypeAlreadyExists(typename));
}
if (!mod.isUnnamed() && !typename.contains(".")) {
throw new FilerException("Attempt to create a type in unnamed package of a named module: " + typename);
@@ -768,7 +761,7 @@ public class JavacFiler implements Filer, Closeable {
*/
private void checkFileReopening(FileObject fileObject, boolean forWriting) throws FilerException {
if (isInFileObjectHistory(fileObject, forWriting)) {
- lint.logIfEnabled(LintWarnings.ProcFileReopening(fileObject.getName()));
+ log.warning(LintWarnings.ProcFileReopening(fileObject.getName()));
throw new FilerException("Attempt to reopen a file for path " + fileObject.getName());
}
if (forWriting)
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java
index 7bc538a1d1e..b28f19bd3af 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java
@@ -123,7 +123,6 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
private final Modules modules;
private final Types types;
private final Annotate annotate;
- private final Lint lint;
/**
* Holds relevant state history of which processors have been
@@ -206,7 +205,6 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
printProcessorInfo = options.isSet(Option.XPRINTPROCESSORINFO);
printRounds = options.isSet(Option.XPRINTROUNDS);
verbose = options.isSet(Option.VERBOSE);
- lint = Lint.instance(context);
compiler = JavaCompiler.instance(context);
if (options.isSet(Option.PROC, "only") || options.isSet(Option.XPRINT)) {
compiler.shouldStopPolicyIfNoError = CompileState.PROCESS;
@@ -626,7 +624,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
private Set supportedOptionNames;
ProcessorState(Processor p, Log log, Source source, DeferredCompletionFailureHandler dcfh,
- boolean allowModules, ProcessingEnvironment env, Lint lint) {
+ boolean allowModules, ProcessingEnvironment env) {
processor = p;
contributed = false;
@@ -647,10 +645,9 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
boolean patternAdded = supportedAnnotationStrings.add(annotationPattern);
supportedAnnotationPatterns.
- add(importStringToPattern(allowModules, annotationPattern,
- processor, log, lint));
+ add(importStringToPattern(allowModules, annotationPattern, processor, log));
if (!patternAdded) {
- lint.logIfEnabled(LintWarnings.ProcDuplicateSupportedAnnotation(annotationPattern,
+ log.warning(LintWarnings.ProcDuplicateSupportedAnnotation(annotationPattern,
p.getClass().getName()));
}
}
@@ -663,7 +660,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
// and "foo.bar.*".
if (supportedAnnotationPatterns.contains(MatchingUtils.validImportStringToPattern("*")) &&
supportedAnnotationPatterns.size() > 1) {
- lint.logIfEnabled(LintWarnings.ProcRedundantTypesWithWildcard(p.getClass().getName()));
+ log.warning(LintWarnings.ProcRedundantTypesWithWildcard(p.getClass().getName()));
}
supportedOptionNames = new LinkedHashSet<>();
@@ -671,8 +668,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
if (checkOptionName(optionName, log)) {
boolean optionAdded = supportedOptionNames.add(optionName);
if (!optionAdded) {
- lint.logIfEnabled(LintWarnings.ProcDuplicateOptionName(optionName,
- p.getClass().getName()));
+ log.warning(LintWarnings.ProcDuplicateOptionName(optionName, p.getClass().getName()));
}
}
}
@@ -759,8 +755,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
ProcessorState ps = new ProcessorState(psi.processorIterator.next(),
log, source, dcfh,
Feature.MODULES.allowedInSource(source),
- JavacProcessingEnvironment.this,
- lint);
+ JavacProcessingEnvironment.this);
psi.procStateList.add(ps);
return ps;
} else
@@ -888,7 +883,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
}
unmatchedAnnotations.remove("");
- if (lint.isEnabled(PROCESSING) && unmatchedAnnotations.size() > 0) {
+ if (unmatchedAnnotations.size() > 0) {
// Remove annotations processed by javac
unmatchedAnnotations.keySet().removeAll(platformAnnotations);
if (unmatchedAnnotations.size() > 0) {
@@ -1649,7 +1644,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
* regex matching that string. If the string is not a valid
* import-style string, return a regex that won't match anything.
*/
- private static Pattern importStringToPattern(boolean allowModules, String s, Processor p, Log log, Lint lint) {
+ private static Pattern importStringToPattern(boolean allowModules, String s, Processor p, Log log) {
String module;
String pkg;
int slash = s.indexOf('/');
@@ -1662,7 +1657,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
} else {
String moduleName = s.substring(0, slash);
if (!SourceVersion.isName(moduleName)) {
- return warnAndNoMatches(s, p, log, lint);
+ return warnAndNoMatches(s, p, log);
}
module = Pattern.quote(moduleName + "/");
// And warn if module is specified if modules aren't supported, conditional on -Xlint:proc?
@@ -1671,12 +1666,12 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
if (MatchingUtils.isValidImportString(pkg)) {
return Pattern.compile(module + MatchingUtils.validImportStringToPatternString(pkg));
} else {
- return warnAndNoMatches(s, p, log, lint);
+ return warnAndNoMatches(s, p, log);
}
}
- private static Pattern warnAndNoMatches(String s, Processor p, Log log, Lint lint) {
- lint.logIfEnabled(LintWarnings.ProcMalformedSupportedString(s, p.getClass().getName()));
+ private static Pattern warnAndNoMatches(String s, Processor p, Log log) {
+ log.warning(LintWarnings.ProcMalformedSupportedString(s, p.getClass().getName()));
return noMatches; // won't match any valid identifier
}
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
index 7dde6cc963f..a226b2f5960 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
@@ -1600,6 +1600,7 @@ compiler.err.multi-module.outdir.cannot.be.exploded.module=\
# 0: path
# lint: path
+# flags: default-enabled
compiler.warn.outdir.is.in.exploded.module=\
the output directory is within an exploded module: {0}
@@ -1924,19 +1925,19 @@ compiler.warn.incubating.modules=\
# 0: symbol, 1: symbol
# lint: deprecation
-# flags: aggregate, mandatory
+# flags: aggregate, mandatory, default-enabled
compiler.warn.has.been.deprecated=\
{0} in {1} has been deprecated
# 0: symbol, 1: symbol
# lint: removal
-# flags: aggregate, mandatory
+# flags: aggregate, mandatory, default-enabled
compiler.warn.has.been.deprecated.for.removal=\
{0} in {1} has been deprecated and marked for removal
# 0: symbol
# lint: preview
-# flags: aggregate, mandatory
+# flags: aggregate, mandatory, default-enabled
compiler.warn.is.preview=\
{0} is a preview API and may be removed in a future release.
@@ -1947,7 +1948,7 @@ compiler.err.is.preview=\
# 0: symbol
# lint: preview
-# flags: aggregate, mandatory
+# flags: aggregate, mandatory, default-enabled
compiler.warn.is.preview.reflective=\
{0} is a reflective preview API and may be removed in a future release.
@@ -1959,13 +1960,13 @@ compiler.warn.restricted.method=\
# 0: symbol
# lint: deprecation
-# flags: aggregate, mandatory
+# flags: aggregate, mandatory, default-enabled
compiler.warn.has.been.deprecated.module=\
module {0} has been deprecated
# 0: symbol
# lint: removal
-# flags: aggregate, mandatory
+# flags: aggregate, mandatory, default-enabled
compiler.warn.has.been.deprecated.for.removal.module=\
module {0} has been deprecated and marked for removal
@@ -2194,11 +2195,13 @@ compiler.warn.static.not.qualified.by.type2=\
# 0: string, 1: fragment
# lint: options
+# flags: default-enabled
compiler.warn.source.no.bootclasspath=\
bootstrap class path is not set in conjunction with -source {0}\n{1}
# 0: string, 1: fragment
# lint: options
+# flags: default-enabled
compiler.warn.source.no.system.modules.path=\
location of system modules is not set in conjunction with -source {0}\n{1}
@@ -2224,11 +2227,13 @@ compiler.misc.source.no.system.modules.path.with.target=\
# 0: string
# lint: options
+# flags: default-enabled
compiler.warn.option.obsolete.source=\
source value {0} is obsolete and will be removed in a future release
# 0: target
# lint: options
+# flags: default-enabled
compiler.warn.option.obsolete.target=\
target value {0} is obsolete and will be removed in a future release
@@ -2241,6 +2246,7 @@ compiler.err.option.removed.target=\
Target option {0} is no longer supported. Use {1} or later.
# lint: options
+# flags: default-enabled
compiler.warn.option.obsolete.suppression=\
To suppress warnings about obsolete options, use -Xlint:-options.
@@ -2365,13 +2371,13 @@ compiler.warn.unchecked.assign=\
# 0: symbol, 1: type
# lint: unchecked
-# flags: aggregate, mandatory
+# flags: aggregate, mandatory, default-enabled
compiler.warn.unchecked.assign.to.var=\
unchecked assignment to variable {0} as member of raw type {1}
# 0: symbol, 1: type
# lint: unchecked
-# flags: aggregate, mandatory
+# flags: aggregate, mandatory, default-enabled
compiler.warn.unchecked.call.mbr.of.raw.type=\
unchecked call to {0} as a member of the raw type {1}
@@ -2381,7 +2387,7 @@ compiler.warn.unchecked.cast.to.type=\
# 0: kind name, 1: name, 2: object, 3: object, 4: kind name, 5: symbol
# lint: unchecked
-# flags: aggregate, mandatory
+# flags: aggregate, mandatory, default-enabled
compiler.warn.unchecked.meth.invocation.applied=\
unchecked method invocation: {0} {1} in {4} {5} is applied to given types\n\
required: {2}\n\
@@ -2389,13 +2395,13 @@ compiler.warn.unchecked.meth.invocation.applied=\
# 0: type
# lint: unchecked
-# flags: aggregate, mandatory
+# flags: aggregate, mandatory, default-enabled
compiler.warn.unchecked.generic.array.creation=\
unchecked generic array creation for varargs parameter of type {0}
# 0: type
# lint: unchecked
-# flags: aggregate, mandatory
+# flags: aggregate, mandatory, default-enabled
compiler.warn.unchecked.varargs.non.reifiable.type=\
Possible heap pollution from parameterized vararg type {0}
@@ -2794,7 +2800,7 @@ compiler.misc.prob.found.req=\
# 0: message segment, 1: type, 2: type
# lint: unchecked
-# flags: aggregate, mandatory
+# flags: aggregate, mandatory, default-enabled
compiler.warn.prob.found.req=\
{0}\n\
required: {2}\n\
@@ -3191,14 +3197,14 @@ compiler.err.override.incompatible.ret=\
# 0: message segment, 1: type, 2: type
# lint: unchecked
-# flags: aggregate, mandatory
+# flags: aggregate, mandatory, default-enabled
compiler.warn.override.unchecked.ret=\
{0}\n\
return type requires unchecked conversion from {1} to {2}
# 0: message segment, 1: type
# lint: unchecked
-# flags: aggregate, mandatory
+# flags: aggregate, mandatory, default-enabled
compiler.warn.override.unchecked.thrown=\
{0}\n\
overridden method does not throw {1}
@@ -3302,13 +3308,13 @@ compiler.err.preview.feature.disabled.classfile=\
# 0: message segment (feature)
# lint: preview
-# flags: aggregate, mandatory
+# flags: aggregate, mandatory, default-enabled
compiler.warn.preview.feature.use=\
{0} is a preview feature and may be removed in a future release.
# 0: message segment (feature)
# lint: preview
-# flags: aggregate, mandatory
+# flags: aggregate, mandatory, default-enabled
compiler.warn.preview.feature.use.plural=\
{0} are a preview feature and may be removed in a future release.
@@ -3879,6 +3885,7 @@ compiler.err.bad.name.for.option=\
# 0: option name, 1: symbol
# lint: options
+# flags: default-enabled
compiler.warn.module.for.option.not.found=\
module name in {0} option not found: {1}
@@ -3895,6 +3902,7 @@ compiler.err.add.reads.with.release=\
adding read edges for system module {0} is not allowed with --release
# lint: options
+# flags: default-enabled
compiler.warn.addopens.ignored=\
--add-opens has no effect at compile time
@@ -4272,7 +4280,7 @@ compiler.err.incorrect.number.of.nested.patterns=\
# 0: kind name, 1: symbol
# lint: preview
-# flags: aggregate, mandatory
+# flags: aggregate, mandatory, default-enabled
compiler.warn.declared.using.preview=\
{0} {1} is declared using a preview feature, which may be removed in a future release.
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java
index 06a1d9fc7a3..c9f529eae55 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java
@@ -368,6 +368,36 @@ public class JCDiagnostic implements Diagnostic {
* the end position of the tree node. Otherwise, just returns the
* same as getPreferredPosition(). */
int getEndPosition(EndPosTable endPosTable);
+ /** Get the position that determines which Lint configuration applies. */
+ default int getLintPosition() {
+ return getStartPosition();
+ }
+ /** Create a new instance from this instance and the given lint position. */
+ default DiagnosticPosition withLintPosition(int lintPos) {
+ DiagnosticPosition orig = this;
+ return new DiagnosticPosition() {
+ @Override
+ public JCTree getTree() {
+ return orig.getTree();
+ }
+ @Override
+ public int getStartPosition() {
+ return orig.getStartPosition();
+ }
+ @Override
+ public int getPreferredPosition() {
+ return orig.getPreferredPosition();
+ }
+ @Override
+ public int getEndPosition(EndPosTable endPosTable) {
+ return orig.getEndPosition(endPosTable);
+ }
+ @Override
+ public int getLintPosition() {
+ return lintPos;
+ }
+ };
+ }
}
/**
@@ -405,6 +435,10 @@ public class JCDiagnostic implements Diagnostic {
RECOVERABLE,
NON_DEFERRABLE,
COMPRESSED,
+ /** Flag for lint diagnostics that should be emitted even when their category
+ * is not explicitly enabled, as long as it is not explicitly suppressed.
+ */
+ DEFAULT_ENABLED,
/** Flags mandatory warnings that should pass through a mandatory warning aggregator.
*/
AGGREGATE,
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java
index 576344a3d2a..95458f339a1 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java
@@ -32,29 +32,45 @@ import java.util.Comparator;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import javax.tools.DiagnosticListener;
import javax.tools.JavaFileObject;
import com.sun.tools.javac.api.DiagnosticFormatter;
+import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Lint;
import com.sun.tools.javac.code.Lint.LintCategory;
+import com.sun.tools.javac.code.LintMapper;
import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.comp.AttrContext;
+import com.sun.tools.javac.comp.Env;
import com.sun.tools.javac.main.Main;
import com.sun.tools.javac.main.Option;
import com.sun.tools.javac.tree.EndPosTable;
-import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.tree.TreeInfo;
+import com.sun.tools.javac.tree.TreeScanner;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticInfo;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
+import com.sun.tools.javac.util.JCDiagnostic.LintWarning;
import static com.sun.tools.javac.main.Option.*;
import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*;
+import static com.sun.tools.javac.code.Lint.LintCategory.*;
+import static com.sun.tools.javac.resources.CompilerProperties.LintWarnings.RequiresAutomatic;
+import static com.sun.tools.javac.resources.CompilerProperties.LintWarnings.RequiresTransitiveAutomatic;
+import static com.sun.tools.javac.tree.JCTree.Tag.*;
/** A class for error logs. Reports errors and warnings, and
* keeps track of error numbers and positions.
@@ -103,6 +119,11 @@ public class Log extends AbstractLog {
*/
protected final DiagnosticHandler prev;
+ /**
+ * Diagnostics waiting for an applicable {@link Lint} instance.
+ */
+ protected Map> lintWaitersMap = new LinkedHashMap<>();
+
/**
* Install this diagnostic handler as the current one,
* recording the previous one.
@@ -113,9 +134,92 @@ public class Log extends AbstractLog {
}
/**
- * Handle a diagnostic.
+ * Step 1: Handle a diagnostic for which the applicable Lint instance (if any) may not be known yet.
*/
- public abstract void report(JCDiagnostic diag);
+ public final void report(JCDiagnostic diag) {
+ Lint lint = null;
+ LintCategory category = diag.getLintCategory();
+ if (category != null) { // this is a lint warning; find the applicable Lint
+ DiagnosticPosition pos = diag.getDiagnosticPosition();
+ if (pos != null && category.annotationSuppression) { // we should apply the Lint from the warning's position
+ if ((lint = lintFor(diag)) == null) {
+ addLintWaiter(currentSourceFile(), diag); // ...but we don't know it yet, so defer
+ return;
+ }
+ } else // we should apply the root Lint
+ lint = rootLint();
+ }
+ reportWithLint(diag, lint);
+ }
+
+ /**
+ * Step 2: Handle a diagnostic for which the applicable Lint instance (if any) is known and provided.
+ */
+ public final void reportWithLint(JCDiagnostic diag, Lint lint) {
+
+ // Apply hackery for REQUIRES_TRANSITIVE_AUTOMATIC (see also Check.checkModuleRequires())
+ if (diag.getCode().equals(RequiresTransitiveAutomatic.key()) && !lint.isEnabled(REQUIRES_TRANSITIVE_AUTOMATIC)) {
+ reportWithLint(
+ diags.warning(null, diag.getDiagnosticSource(), diag.getDiagnosticPosition(), RequiresAutomatic), lint);
+ return;
+ }
+
+ // Apply the lint configuration (if any) and discard the warning if it gets filtered out
+ if (lint != null) {
+ LintCategory category = diag.getLintCategory();
+ boolean emit = !diag.isFlagSet(DEFAULT_ENABLED) ? // is the warning not enabled by default?
+ lint.isEnabled(category) : // then emit if the category is enabled
+ category.annotationSuppression ? // else emit if the category is not suppressed, where
+ !lint.isSuppressed(category) : // ...suppression happens via @SuppressWarnings
+ !options.isLintDisabled(category); // ...suppression happens via -Xlint:-category
+ if (!emit)
+ return;
+ }
+
+ // Proceed
+ reportReady(diag);
+ }
+
+ /**
+ * Step 3: Handle a diagnostic to which the applicable Lint instance (if any) has been applied.
+ */
+ protected abstract void reportReady(JCDiagnostic diag);
+
+ protected void addLintWaiter(JavaFileObject sourceFile, JCDiagnostic diagnostic) {
+ lintWaitersMap.computeIfAbsent(sourceFile, s -> new LinkedList<>()).add(diagnostic);
+ }
+
+ /**
+ * Flush any lint waiters whose {@link Lint} configurations are now known.
+ */
+ public void flushLintWaiters() {
+ lintWaitersMap.entrySet().removeIf(entry -> {
+
+ // Is the source file no longer recognized? If so, discard warnings (e.g., this can happen with JShell)
+ JavaFileObject sourceFile = entry.getKey();
+ if (!lintMapper.isKnown(sourceFile))
+ return true;
+
+ // Flush those diagnostics for which we now know the applicable Lint
+ List diagnosticList = entry.getValue();
+ JavaFileObject prevSourceFile = useSource(sourceFile);
+ try {
+ diagnosticList.removeIf(diag -> {
+ Lint lint = lintFor(diag);
+ if (lint != null) {
+ reportWithLint(diag, lint);
+ return true;
+ }
+ return false;
+ });
+ } finally {
+ useSource(prevSourceFile);
+ }
+
+ // Discard list if empty
+ return diagnosticList.isEmpty();
+ });
+ }
}
/**
@@ -124,7 +228,10 @@ public class Log extends AbstractLog {
public class DiscardDiagnosticHandler extends DiagnosticHandler {
@Override
- public void report(JCDiagnostic diag) { }
+ protected void addLintWaiter(JavaFileObject sourceFile, JCDiagnostic diagnostic) { }
+
+ @Override
+ protected void reportReady(JCDiagnostic diag) { }
}
/**
@@ -157,11 +264,20 @@ public class Log extends AbstractLog {
}
@Override
- public void report(JCDiagnostic diag) {
+ protected void reportReady(JCDiagnostic diag) {
if (deferrable(diag)) {
deferred.add(diag);
} else {
- prev.report(diag);
+ prev.reportReady(diag);
+ }
+ }
+
+ @Override
+ protected void addLintWaiter(JavaFileObject sourceFile, JCDiagnostic diag) {
+ if (deferrable(diag)) {
+ super.addLintWaiter(sourceFile, diag);
+ } else {
+ prev.addLintWaiter(sourceFile, diag);
}
}
@@ -182,6 +298,13 @@ public class Log extends AbstractLog {
.filter(accepter)
.forEach(prev::report);
deferred = null; // prevent accidental ongoing use
+
+ // Flush matching Lint waiters to the previous handler
+ lintWaitersMap.forEach(
+ (sourceFile, diagnostics) -> diagnostics.stream()
+ .filter(accepter)
+ .forEach(diagnostic -> prev.addLintWaiter(sourceFile, diagnostic)));
+ lintWaitersMap = null; // prevent accidental ongoing use
}
/** Report all deferred diagnostics in the specified order. */
@@ -247,6 +370,16 @@ public class Log extends AbstractLog {
*/
private final Context context;
+ /**
+ * The {@link Options} singleton.
+ */
+ private final Options options;
+
+ /**
+ * The lint positions table.
+ */
+ private final LintMapper lintMapper;
+
/**
* The root {@link Lint} singleton.
*/
@@ -350,6 +483,8 @@ public class Log extends AbstractLog {
super(JCDiagnostic.Factory.instance(context));
context.put(logKey, this);
this.context = context;
+ this.options = Options.instance(context);
+ this.lintMapper = LintMapper.instance(context);
this.writers = writers;
@SuppressWarnings("unchecked") // FIXME
@@ -369,7 +504,6 @@ public class Log extends AbstractLog {
this.diagFormatter = new BasicDiagnosticFormatter(messages);
// Once Options is ready, complete the initialization
- final Options options = Options.instance(context);
options.whenReady(this::initOptions);
}
// where
@@ -689,6 +823,21 @@ public class Log extends AbstractLog {
diagnosticHandler.report(diagnostic);
}
+// Deferred Lint Calculation
+
+ /**
+ * Report unreported lint warnings for which the applicable {@link Lint} configuration is now known.
+ */
+ public void reportOutstandingWarnings() {
+ diagnosticHandler.flushLintWaiters();
+ }
+
+ // Get the Lint config for the given warning (if known)
+ private Lint lintFor(JCDiagnostic diag) {
+ Assert.check(diag.getLintCategory() != null);
+ return lintMapper.lintAt(diag.getSource(), diag.getDiagnosticPosition()).orElse(null);
+ }
+
// Obtain root Lint singleton lazily to avoid init loops
private Lint rootLint() {
if (rootLint == null)
@@ -756,7 +905,7 @@ public class Log extends AbstractLog {
private class DefaultDiagnosticHandler extends DiagnosticHandler {
@Override
- public void report(JCDiagnostic diagnostic) {
+ protected void reportReady(JCDiagnostic diagnostic) {
if (expectDiagKeys != null)
expectDiagKeys.remove(diagnostic.getCode());
@@ -783,13 +932,13 @@ public class Log extends AbstractLog {
// Apply the appropriate mandatory warning aggregator, if needed
if (diagnostic.isFlagSet(AGGREGATE)) {
LintCategory category = diagnostic.getLintCategory();
- boolean verbose = rootLint().isEnabled(category);
+ boolean verbose = lintFor(diagnostic).isEnabled(category);
if (!aggregatorFor(category).aggregate(diagnostic, verbose))
return;
}
// Strict warnings are always emitted
- if (diagnostic.isFlagSet(DiagnosticFlag.STRICT)) {
+ if (diagnostic.isFlagSet(STRICT)) {
writeDiagnostic(diagnostic);
nwarnings++;
return;
diff --git a/test/langtools/tools/javac/6304921/TestLog.java b/test/langtools/tools/javac/6304921/TestLog.java
index 41695554a88..8f00a14b9e2 100644
--- a/test/langtools/tools/javac/6304921/TestLog.java
+++ b/test/langtools/tools/javac/6304921/TestLog.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -41,7 +41,7 @@ import javax.tools.SimpleJavaFileObject;
import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.parser.Parser;
import com.sun.tools.javac.parser.ParserFactory;
-import com.sun.tools.javac.resources.CompilerProperties.LintWarnings;
+import com.sun.tools.javac.resources.CompilerProperties.Warnings;
import com.sun.tools.javac.tree.EndPosTable;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeScanner;
@@ -130,10 +130,11 @@ public class TestLog
log.error(tree.pos(), Errors.NotStmt);
log.error(nil, Errors.NotStmt);
- log.warning(LintWarnings.DivZero);
- log.warning(tree.pos, LintWarnings.DivZero);
- log.warning(tree.pos(), LintWarnings.DivZero);
- log.warning(nil, LintWarnings.DivZero);
+ // some warnings that will be emitted during parsing
+ log.warning(Warnings.ExtraneousSemicolon);
+ log.warning(tree.pos, Warnings.ExtraneousSemicolon);
+ log.warning(tree.pos(), Warnings.ExtraneousSemicolon);
+ log.warning(nil, Warnings.ExtraneousSemicolon);
}
private Log log;
diff --git a/test/langtools/tools/javac/ImportModule.java b/test/langtools/tools/javac/ImportModule.java
index f088dbef658..d26b73c0289 100644
--- a/test/langtools/tools/javac/ImportModule.java
+++ b/test/langtools/tools/javac/ImportModule.java
@@ -730,8 +730,8 @@ public class ImportModule extends TestRunner {
.getOutputLines(Task.OutputKind.DIRECT);
List expectedErrors = List.of(
- "module-info.java:3:18: compiler.warn.module.not.found: M1",
"module-info.java:6:9: compiler.err.cant.resolve: kindname.class, A, , ",
+ "module-info.java:3:18: compiler.warn.module.not.found: M1",
"1 error",
"1 warning"
);
diff --git a/test/langtools/tools/javac/OverrideChecks/6400189/T6400189a.out b/test/langtools/tools/javac/OverrideChecks/6400189/T6400189a.out
index 2a12111fe40..23dcddc1e93 100644
--- a/test/langtools/tools/javac/OverrideChecks/6400189/T6400189a.out
+++ b/test/langtools/tools/javac/OverrideChecks/6400189/T6400189a.out
@@ -1,4 +1,4 @@
-T6400189a.java:14:35: compiler.warn.unchecked.call.mbr.of.raw.type: getAnnotation(java.lang.Class), java.lang.reflect.Constructor
T6400189a.java:14:35: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.annotation.Annotation, java.lang.annotation.Documented)
+T6400189a.java:14:35: compiler.warn.unchecked.call.mbr.of.raw.type: getAnnotation(java.lang.Class), java.lang.reflect.Constructor
1 error
1 warning
diff --git a/test/langtools/tools/javac/OverrideChecks/6400189/T6400189b.out b/test/langtools/tools/javac/OverrideChecks/6400189/T6400189b.out
index 904cd3e677f..91e34b5beca 100644
--- a/test/langtools/tools/javac/OverrideChecks/6400189/T6400189b.out
+++ b/test/langtools/tools/javac/OverrideChecks/6400189/T6400189b.out
@@ -1,4 +1,4 @@
-T6400189b.java:24:24: compiler.warn.unchecked.call.mbr.of.raw.type: m(T6400189b), T6400189b.B
T6400189b.java:24:24: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Object, java.lang.Integer)
+T6400189b.java:24:24: compiler.warn.unchecked.call.mbr.of.raw.type: m(T6400189b), T6400189b.B
1 error
1 warning
diff --git a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass.enabled.out b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass.enabled.out
index 78285aa45d9..b2dde3ff0ef 100644
--- a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass.enabled.out
+++ b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass.enabled.out
@@ -1,7 +1,7 @@
+DanglingDocCommentsClass.java:15:5: compiler.warn.dangling.doc.comment
+DanglingDocCommentsClass.java:19:5: compiler.warn.dangling.doc.comment
DanglingDocCommentsClass.java:10:1: compiler.warn.dangling.doc.comment
DanglingDocCommentsClass.java:13:1: compiler.warn.dangling.doc.comment
DanglingDocCommentsClass.java:14:8: compiler.warn.dangling.doc.comment
DanglingDocCommentsClass.java:14:69: compiler.warn.dangling.doc.comment
-DanglingDocCommentsClass.java:15:5: compiler.warn.dangling.doc.comment
-DanglingDocCommentsClass.java:19:5: compiler.warn.dangling.doc.comment
6 warnings
diff --git a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Line.enabled.out b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Line.enabled.out
index 3ed89c5f5bc..e97bd630ad8 100644
--- a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Line.enabled.out
+++ b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Line.enabled.out
@@ -1,7 +1,7 @@
+DanglingDocCommentsClass_Line.java:21:5: compiler.warn.dangling.doc.comment
+DanglingDocCommentsClass_Line.java:26:5: compiler.warn.dangling.doc.comment
DanglingDocCommentsClass_Line.java:11:1: compiler.warn.dangling.doc.comment
DanglingDocCommentsClass_Line.java:15:1: compiler.warn.dangling.doc.comment
DanglingDocCommentsClass_Line.java:17:5: compiler.warn.dangling.doc.comment
DanglingDocCommentsClass_Line.java:19:9: compiler.warn.dangling.doc.comment
-DanglingDocCommentsClass_Line.java:21:5: compiler.warn.dangling.doc.comment
-DanglingDocCommentsClass_Line.java:26:5: compiler.warn.dangling.doc.comment
6 warnings
diff --git a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Mixed.enabled.out b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Mixed.enabled.out
index 1eda729da19..13e15493579 100644
--- a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Mixed.enabled.out
+++ b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Mixed.enabled.out
@@ -1,4 +1,4 @@
-DanglingDocCommentsClass_Mixed.java:13:1: compiler.warn.dangling.doc.comment
DanglingDocCommentsClass_Mixed.java:17:5: compiler.warn.dangling.doc.comment
DanglingDocCommentsClass_Mixed.java:21:5: compiler.warn.dangling.doc.comment
+DanglingDocCommentsClass_Mixed.java:13:1: compiler.warn.dangling.doc.comment
3 warnings
diff --git a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsEnum.enabled.out b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsEnum.enabled.out
index ddf1b2964de..33938e86078 100644
--- a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsEnum.enabled.out
+++ b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsEnum.enabled.out
@@ -1,8 +1,8 @@
+DanglingDocCommentsEnum.java:16:5: compiler.warn.dangling.doc.comment
+DanglingDocCommentsEnum.java:22:5: compiler.warn.dangling.doc.comment
+DanglingDocCommentsEnum.java:28:5: compiler.warn.dangling.doc.comment
DanglingDocCommentsEnum.java:10:1: compiler.warn.dangling.doc.comment
DanglingDocCommentsEnum.java:13:1: compiler.warn.dangling.doc.comment
DanglingDocCommentsEnum.java:14:8: compiler.warn.dangling.doc.comment
DanglingDocCommentsEnum.java:14:67: compiler.warn.dangling.doc.comment
-DanglingDocCommentsEnum.java:16:5: compiler.warn.dangling.doc.comment
-DanglingDocCommentsEnum.java:22:5: compiler.warn.dangling.doc.comment
-DanglingDocCommentsEnum.java:28:5: compiler.warn.dangling.doc.comment
7 warnings
diff --git a/test/langtools/tools/javac/generics/diamond/7188968/T7188968.out b/test/langtools/tools/javac/generics/diamond/7188968/T7188968.out
index efceb84c8c7..3c93e1711d6 100644
--- a/test/langtools/tools/javac/generics/diamond/7188968/T7188968.out
+++ b/test/langtools/tools/javac/generics/diamond/7188968/T7188968.out
@@ -1,11 +1,11 @@
T7188968.java:20:20: compiler.err.cant.resolve.location: kindname.variable, unknown, , , (compiler.misc.location: kindname.class, T7188968, null)
-T7188968.java:20:9: compiler.warn.unchecked.call.mbr.of.raw.type: T7188968.Foo(java.util.List,java.lang.Object), T7188968.Foo
T7188968.java:21:20: compiler.err.cant.resolve.location: kindname.variable, unknown, , , (compiler.misc.location: kindname.class, T7188968, null)
-T7188968.java:21:29: compiler.warn.unchecked.call.mbr.of.raw.type: T7188968.Foo(java.util.List,java.lang.Object), T7188968.Foo
T7188968.java:22:22: compiler.err.cant.resolve.location: kindname.variable, unknown, , , (compiler.misc.location: kindname.class, T7188968, null)
+T7188968.java:23:24: compiler.err.cant.resolve.location: kindname.variable, unknown, , , (compiler.misc.location: kindname.class, T7188968, null)
+T7188968.java:20:9: compiler.warn.unchecked.call.mbr.of.raw.type: T7188968.Foo(java.util.List,java.lang.Object), T7188968.Foo
+T7188968.java:21:29: compiler.warn.unchecked.call.mbr.of.raw.type: T7188968.Foo(java.util.List,java.lang.Object), T7188968.Foo
T7188968.java:22:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, , java.util.List,java.lang.Object, java.util.List,unknown, kindname.class, T7188968.Foo
T7188968.java:22:19: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.util.List, java.util.List
-T7188968.java:23:24: compiler.err.cant.resolve.location: kindname.variable, unknown, , , (compiler.misc.location: kindname.class, T7188968, null)
T7188968.java:23:20: compiler.warn.unchecked.meth.invocation.applied: kindname.method, makeFoo, java.util.List,java.lang.Object, java.util.List,unknown, kindname.class, T7188968.Foo
T7188968.java:23:21: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.util.List, java.util.List
4 errors
diff --git a/test/langtools/tools/javac/lambda/TargetType22.out b/test/langtools/tools/javac/lambda/TargetType22.out
index d94b2cc60b3..c19aef2411f 100644
--- a/test/langtools/tools/javac/lambda/TargetType22.out
+++ b/test/langtools/tools/javac/lambda/TargetType22.out
@@ -1,4 +1,4 @@
-TargetType22.java:29:21: compiler.warn.unchecked.varargs.non.reifiable.type: A
TargetType22.java:40:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType22.Sam1), TargetType22, kindname.method, call(TargetType22.SamX), TargetType22
+TargetType22.java:29:21: compiler.warn.unchecked.varargs.non.reifiable.type: A
1 error
1 warning
diff --git a/test/langtools/tools/javac/lint/LexicalLintNesting.java b/test/langtools/tools/javac/lint/LexicalLintNesting.java
new file mode 100644
index 00000000000..f167921df81
--- /dev/null
+++ b/test/langtools/tools/javac/lint/LexicalLintNesting.java
@@ -0,0 +1,170 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8224228
+ * @summary Verify lexical lint warnings handle nested declarations with SuppressWarnings correctly
+ * @compile/fail/ref=LexicalLintNesting.out -XDrawDiagnostics -Xlint:text-blocks -Werror LexicalLintNesting.java
+ */
+
+//@SuppressWarnings("text-blocks")
+public class LexicalLintNesting {
+
+ //@SuppressWarnings("text-blocks")
+ /* WARNING HERE */ String s1 = """
+ trailing space here:\u0020
+ """;
+
+ @SuppressWarnings("text-blocks")
+ String s2 = """
+ trailing space here:\u0020
+ """;
+
+ //@SuppressWarnings("text-blocks")
+ public static class Nested1 {
+
+ @SuppressWarnings("text-blocks")
+ String s3 = """
+ trailing space here:\u0020
+ """;
+
+ //@SuppressWarnings("text-blocks")
+ /* WARNING HERE */ String s4 = """
+ trailing space here:\u0020
+ """;
+
+ @SuppressWarnings("text-blocks")
+ public static class Nested1A {
+
+ //@SuppressWarnings("text-blocks")
+ String s5 = """
+ trailing space here:\u0020
+ """;
+
+ @SuppressWarnings("text-blocks")
+ String s6 = """
+ trailing space here:\u0020
+ """;
+
+ }
+
+ @SuppressWarnings("text-blocks")
+ String s7 = """
+ trailing space here:\u0020
+ """;
+
+ //@SuppressWarnings("text-blocks")
+ /* WARNING HERE */ String s8 = """
+ trailing space here:\u0020
+ """;
+
+ //@SuppressWarnings("text-blocks")
+ public static class Nested1B {
+
+ @SuppressWarnings("text-blocks")
+ String s9 = """
+ trailing space here:\u0020
+ """;
+
+ //@SuppressWarnings("text-blocks")
+ /* WARNING HERE */ String s10 = """
+ trailing space here:\u0020
+ """;
+
+ }
+
+ @SuppressWarnings("text-blocks")
+ String s11 = """
+ trailing space here:\u0020
+ """;
+
+ //@SuppressWarnings("text-blocks")
+ /* WARNING HERE */ String s12 = """
+ trailing space here:\u0020
+ """;
+
+ }
+
+ @SuppressWarnings("text-blocks")
+ String s13 = """
+ trailing space here:\u0020
+ """;
+
+ //@SuppressWarnings("text-blocks")
+ /* WARNING HERE */ String s14 = """
+ trailing space here:\u0020
+ """;
+
+ @SuppressWarnings("text-blocks")
+ public static class Nested2 {
+
+ @SuppressWarnings("text-blocks")
+ String s15 = """
+ trailing space here:\u0020
+ """;
+
+ //@SuppressWarnings("text-blocks")
+ String s16 = """
+ trailing space here:\u0020
+ """;
+
+ @SuppressWarnings("text-blocks")
+ public static class Nested2A {
+
+ //@SuppressWarnings("text-blocks")
+ String s17 = """
+ trailing space here:\u0020
+ """;
+
+ @SuppressWarnings("text-blocks")
+ String s18 = """
+ trailing space here:\u0020
+ """; // SHOULD NOT get a warning here
+
+ }
+
+ @SuppressWarnings("text-blocks")
+ String s19 = """
+ trailing space here:\u0020
+ """;
+
+ //@SuppressWarnings("text-blocks")
+ String s20 = """
+ trailing space here:\u0020
+ """;
+
+ //@SuppressWarnings("text-blocks")
+ public static class Nested2B {
+
+ @SuppressWarnings("text-blocks")
+ String s21 = """
+ trailing space here:\u0020
+ """;
+
+ //@SuppressWarnings("text-blocks")
+ String s22 = """
+ trailing space here:\u0020
+ """;
+
+ }
+
+ @SuppressWarnings("text-blocks")
+ String s23 = """
+ trailing space here:\u0020
+ """;
+
+ //@SuppressWarnings("text-blocks")
+ String s24 = """
+ trailing space here:\u0020
+ """;
+
+ }
+
+ //@SuppressWarnings("text-blocks")
+ /* WARNING HERE */ String s25 = """
+ trailing space here:\u0020
+ """;
+
+ @SuppressWarnings("text-blocks")
+ String s26 = """
+ trailing space here:\u0020
+ """;
+}
diff --git a/test/langtools/tools/javac/lint/LexicalLintNesting.out b/test/langtools/tools/javac/lint/LexicalLintNesting.out
new file mode 100644
index 00000000000..b16db47cf52
--- /dev/null
+++ b/test/langtools/tools/javac/lint/LexicalLintNesting.out
@@ -0,0 +1,10 @@
+LexicalLintNesting.java:12:36: compiler.warn.trailing.white.space.will.be.removed
+LexicalLintNesting.java:30:40: compiler.warn.trailing.white.space.will.be.removed
+LexicalLintNesting.java:55:40: compiler.warn.trailing.white.space.will.be.removed
+LexicalLintNesting.java:68:45: compiler.warn.trailing.white.space.will.be.removed
+LexicalLintNesting.java:80:41: compiler.warn.trailing.white.space.will.be.removed
+LexicalLintNesting.java:92:37: compiler.warn.trailing.white.space.will.be.removed
+LexicalLintNesting.java:162:37: compiler.warn.trailing.white.space.will.be.removed
+- compiler.err.warnings.and.werror
+1 error
+7 warnings
diff --git a/test/langtools/tools/javac/lint/TextBlockSuppress.java b/test/langtools/tools/javac/lint/TextBlockSuppress.java
new file mode 100644
index 00000000000..05019be6bc2
--- /dev/null
+++ b/test/langtools/tools/javac/lint/TextBlockSuppress.java
@@ -0,0 +1,61 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8224228
+ * @summary Verify SuppressWarnings works for LintCategore.TEXT_BLOCKS
+ * @compile/fail/ref=TextBlockSuppress.out -XDrawDiagnostics -Xlint:text-blocks -Werror TextBlockSuppress.java
+ */
+
+public class TextBlockSuppress {
+
+ public static class Example1 {
+ public void method() {
+ String s = """
+ trailing space here:\u0020
+ """; // SHOULD get a warning here
+ }
+ }
+
+ @SuppressWarnings("text-blocks")
+ public static class Example2 {
+ public void method() {
+ String s = """
+ trailing space here:\u0020
+ """; // SHOULD NOT get a warning here
+ }
+ }
+
+ public static class Example3 {
+ @SuppressWarnings("text-blocks")
+ public void method() {
+ String s = """
+ trailing space here:\u0020
+ """; // SHOULD NOT get a warning here
+ }
+ }
+
+ public static class Example4 {
+ {
+ String s = """
+ trailing space here:\u0020
+ """; // SHOULD get a warning here
+ }
+ }
+
+ @SuppressWarnings("text-blocks")
+ public static class Example5 {
+ {
+ String s = """
+ trailing space here:\u0020
+ """; // SHOULD NOT get a warning here
+ }
+ }
+
+ public static class Example6 {
+ public void method() {
+ @SuppressWarnings("text-blocks")
+ String s = """
+ trailing space here:\u0020
+ """; // SHOULD NOT get a warning here
+ }
+ }
+}
diff --git a/test/langtools/tools/javac/lint/TextBlockSuppress.out b/test/langtools/tools/javac/lint/TextBlockSuppress.out
new file mode 100644
index 00000000000..d16f080a133
--- /dev/null
+++ b/test/langtools/tools/javac/lint/TextBlockSuppress.out
@@ -0,0 +1,5 @@
+TextBlockSuppress.java:12:24: compiler.warn.trailing.white.space.will.be.removed
+TextBlockSuppress.java:38:24: compiler.warn.trailing.white.space.will.be.removed
+- compiler.err.warnings.and.werror
+1 error
+2 warnings
diff --git a/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5.out b/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5.out
index 6fe57b8979d..1656d8eeff5 100644
--- a/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5.out
+++ b/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5.out
@@ -1,4 +1,4 @@
-Q.java:7:10: compiler.warn.has.been.deprecated: bar(), Q2
P.java:10:18: compiler.warn.has.been.deprecated: foo(), Q
+Q.java:7:10: compiler.warn.has.been.deprecated: bar(), Q2
Q.java:17:25: compiler.warn.has.been.deprecated: foo(), Q
3 warnings
diff --git a/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5b.out b/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5b.out
index fe4a91e2584..5dee9c1414c 100644
--- a/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5b.out
+++ b/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5b.out
@@ -1,4 +1,4 @@
-Q.java:7:10: compiler.warn.has.been.deprecated: bar(), Q2
P.java:10:18: compiler.warn.has.been.deprecated: foo(), Q
+Q.java:7:10: compiler.warn.has.been.deprecated: bar(), Q2
- compiler.note.deprecated.filename.additional: Q.java
2 warnings
diff --git a/test/langtools/tools/javac/modules/AnnotationsOnModules.java b/test/langtools/tools/javac/modules/AnnotationsOnModules.java
index 6d9bfaad406..f9858a105eb 100644
--- a/test/langtools/tools/javac/modules/AnnotationsOnModules.java
+++ b/test/langtools/tools/javac/modules/AnnotationsOnModules.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -599,8 +599,8 @@ public class AnnotationsOnModules extends ModuleTestBase {
"1 warning");
} else if (suppress.equals(DEPRECATED_JAVADOC)) {
expected = Arrays.asList(
- "module-info.java:1:19: compiler.warn.missing.deprecated.annotation",
"module-info.java:2:14: compiler.warn.has.been.deprecated.module: m1x",
+ "module-info.java:1:19: compiler.warn.missing.deprecated.annotation",
"2 warnings");
} else {
expected = Arrays.asList("");
diff --git a/test/langtools/tools/javac/preview/PreviewErrors.java b/test/langtools/tools/javac/preview/PreviewErrors.java
index eab5b2af9bf..db17aabbd42 100644
--- a/test/langtools/tools/javac/preview/PreviewErrors.java
+++ b/test/langtools/tools/javac/preview/PreviewErrors.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 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
@@ -324,7 +324,9 @@ public class PreviewErrors extends ComboInstance {
ok = true;
switch (elementType) {
case LANGUAGE -> {
- if (lint == Lint.ENABLE_PREVIEW) {
+ if (suppress == Suppress.YES) {
+ expected = Set.of();
+ } else if (lint == Lint.ENABLE_PREVIEW) {
expected = Set.of("5:41:compiler.warn.preview.feature.use");
} else {
expected = Set.of("-1:-1:compiler.note.preview.filename",
diff --git a/test/langtools/tools/javac/preview/PreviewTest.java b/test/langtools/tools/javac/preview/PreviewTest.java
index 36f1e70acd0..e681f3f837e 100644
--- a/test/langtools/tools/javac/preview/PreviewTest.java
+++ b/test/langtools/tools/javac/preview/PreviewTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 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
@@ -587,12 +587,12 @@ public class PreviewTest extends TestRunner {
"Test.java:19:11: compiler.err.is.preview: test()",
"Test.java:20:11: compiler.err.is.preview: test()",
"Test.java:21:11: compiler.err.is.preview: test()",
- "Test.java:24:11: compiler.warn.is.preview.reflective: test()",
"Test.java:29:16: compiler.err.is.preview: preview.api.Preview",
"Test.java:32:21: compiler.err.is.preview: test()",
"Test.java:36:21: compiler.err.is.preview: test()",
"Test.java:40:13: compiler.err.is.preview: test()",
"Test.java:41:21: compiler.err.is.preview: FIELD",
+ "Test.java:24:11: compiler.warn.is.preview.reflective: test()",
"17 errors",
"1 warning");
@@ -792,6 +792,99 @@ public class PreviewTest extends TestRunner {
throw new Exception("expected output not found" + log);
}
+ @Test //JDK-8224228:
+ public void testSuppressWarnings(Path base) throws Exception {
+ Path apiSrc = base.resolve("api-src");
+ tb.writeJavaFiles(apiSrc,
+ """
+ package preview.api;
+ @jdk.internal.javac.PreviewFeature(feature=jdk.internal.javac.PreviewFeature.Feature.TEST)
+ public class Preview {
+ public static int test() {
+ return 0;
+ }
+ }
+ """);
+ Path apiClasses = base.resolve("api-classes");
+
+ new JavacTask(tb, Task.Mode.CMDLINE)
+ .outdir(apiClasses)
+ .options("--patch-module", "java.base=" + apiSrc.toString(),
+ "-Werror")
+ .files(tb.findJavaFiles(apiSrc))
+ .run()
+ .writeAll()
+ .getOutputLines(Task.OutputKind.DIRECT);
+
+ Path testSrc = base.resolve("test-src");
+ tb.writeJavaFiles(testSrc,
+ """
+ package test;
+ import preview.api.Preview;
+ public class Test {
+
+ public static class Example1 {
+ public void method() {
+ Preview.test(); // SHOULD get a warning here
+ }
+ }
+
+ @SuppressWarnings("preview")
+ public static class Example2 {
+ public void method() {
+ Preview.test(); // SHOULD NOT get a warning here
+ }
+ }
+
+ public static class Example3 {
+ @SuppressWarnings("preview")
+ public void method() {
+ Preview.test(); // SHOULD NOT get a warning here
+ }
+ }
+
+ public static class Example4 {
+ {
+ Preview.test(); // SHOULD get a warning here
+ }
+ }
+
+ @SuppressWarnings("preview")
+ public static class Example5 {
+ {
+ Preview.test(); // SHOULD NOT get a warning here
+ }
+ }
+
+ public static class Example6 {
+ @SuppressWarnings("preview")
+ int x = Preview.test(); // SHOULD NOT get a warning here
+ }
+ }
+ """);
+ Path testClasses = base.resolve("test-classes");
+ List log = new JavacTask(tb, Task.Mode.CMDLINE)
+ .outdir(testClasses)
+ .options("--patch-module", "java.base=" + apiClasses.toString(),
+ "--add-exports", "java.base/preview.api=ALL-UNNAMED",
+ "--enable-preview",
+ "-Xlint:preview",
+ "-source", String.valueOf(Runtime.version().feature()),
+ "-XDrawDiagnostics")
+ .files(tb.findJavaFiles(testSrc))
+ .run(Task.Expect.SUCCESS)
+ .writeAll()
+ .getOutputLines(Task.OutputKind.DIRECT);
+
+ List expected =
+ List.of("Test.java:7:11: compiler.warn.is.preview: preview.api.Preview",
+ "Test.java:27:11: compiler.warn.is.preview: preview.api.Preview",
+ "2 warnings");
+
+ if (!log.equals(expected))
+ throw new Exception("expected output not found: " + log);
+ }
+
@Test //JDK-8343540:
public void nonPreviewImplementsPreview5(Path base) throws Exception {
Path apiSrc = base.resolve("api-src");
diff --git a/test/langtools/tools/javac/varargs/7097436/T7097436.out b/test/langtools/tools/javac/varargs/7097436/T7097436.out
index 5e35910d2fa..392869f3b9f 100644
--- a/test/langtools/tools/javac/varargs/7097436/T7097436.out
+++ b/test/langtools/tools/javac/varargs/7097436/T7097436.out
@@ -1,6 +1,6 @@
-T7097436.java:13:20: compiler.warn.varargs.unsafe.use.varargs.param: ls
-T7097436.java:14:25: compiler.warn.varargs.unsafe.use.varargs.param: ls
T7097436.java:15:20: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.util.List[], java.lang.String)
T7097436.java:16:26: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.util.List[], java.lang.Integer[])
+T7097436.java:13:20: compiler.warn.varargs.unsafe.use.varargs.param: ls
+T7097436.java:14:25: compiler.warn.varargs.unsafe.use.varargs.param: ls
2 errors
2 warnings
diff --git a/test/langtools/tools/javac/warnings/6594914/T6594914a.out b/test/langtools/tools/javac/warnings/6594914/T6594914a.out
index 62f99072a7a..d3d759ca044 100644
--- a/test/langtools/tools/javac/warnings/6594914/T6594914a.out
+++ b/test/langtools/tools/javac/warnings/6594914/T6594914a.out
@@ -1,7 +1,7 @@
T6594914a.java:11:5: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
T6594914a.java:16:16: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
+T6594914a.java:16:52: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
T6594914a.java:16:33: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
T6594914a.java:17:20: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
-T6594914a.java:16:52: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
T6594914a.java:24:9: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
6 warnings
diff --git a/test/langtools/tools/javac/warnings/7090499/T7090499.out b/test/langtools/tools/javac/warnings/7090499/T7090499.out
index 1ff9e164e48..2241c0a04bb 100644
--- a/test/langtools/tools/javac/warnings/7090499/T7090499.out
+++ b/test/langtools/tools/javac/warnings/7090499/T7090499.out
@@ -1,14 +1,14 @@
+T7090499.java:26:10: compiler.err.improperly.formed.type.inner.raw.param
+T7090499.java:27:10: compiler.err.improperly.formed.type.inner.raw.param
+T7090499.java:28:17: compiler.err.improperly.formed.type.inner.raw.param
+T7090499.java:28:10: compiler.err.improperly.formed.type.inner.raw.param
T7090499.java:18:5: compiler.warn.raw.class.use: T7090499, T7090499
T7090499.java:18:22: compiler.warn.raw.class.use: T7090499, T7090499
T7090499.java:20:10: compiler.warn.raw.class.use: T7090499.A.X, T7090499.A.X
T7090499.java:21:10: compiler.warn.raw.class.use: T7090499.A.Z, T7090499.A.Z
T7090499.java:24:17: compiler.warn.raw.class.use: T7090499.B, T7090499.B
-T7090499.java:26:10: compiler.err.improperly.formed.type.inner.raw.param
-T7090499.java:27:10: compiler.err.improperly.formed.type.inner.raw.param
T7090499.java:28:18: compiler.warn.raw.class.use: T7090499.B, T7090499.B
-T7090499.java:28:17: compiler.err.improperly.formed.type.inner.raw.param
T7090499.java:28:11: compiler.warn.raw.class.use: T7090499.B, T7090499.B
-T7090499.java:28:10: compiler.err.improperly.formed.type.inner.raw.param
T7090499.java:30:32: compiler.warn.raw.class.use: T7090499.B, T7090499.B
T7090499.java:33:13: compiler.warn.raw.class.use: T7090499.A, T7090499.A
T7090499.java:33:24: compiler.warn.raw.class.use: T7090499.A, T7090499.A
diff --git a/test/langtools/tools/javac/warnings/UnneededStrictfpWarningToolBox.java b/test/langtools/tools/javac/warnings/UnneededStrictfpWarningToolBox.java
index b5062a9b63f..a9101b47e42 100644
--- a/test/langtools/tools/javac/warnings/UnneededStrictfpWarningToolBox.java
+++ b/test/langtools/tools/javac/warnings/UnneededStrictfpWarningToolBox.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 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
@@ -116,8 +116,8 @@ public class UnneededStrictfpWarningToolBox extends TestRunner {
var expected = List.of("UnneededStrictfpWarning1.java:1:17: compiler.warn.strictfp",
"UnneededStrictfpWarning1.java:10:10: compiler.warn.strictfp",
"UnneededStrictfpWarning1.java:12:29: compiler.warn.strictfp",
- "UnneededStrictfpWarning1.java:16:28: compiler.warn.strictfp",
"UnneededStrictfpWarning1.java:18:21: compiler.warn.strictfp",
+ "UnneededStrictfpWarning1.java:16:28: compiler.warn.strictfp",
"5 warnings");
checkLog(log, expected);
}
diff --git a/test/langtools/tools/javac/warnings/suppress/T6480588.out b/test/langtools/tools/javac/warnings/suppress/T6480588.out
index 630ba55523d..267ef32c964 100644
--- a/test/langtools/tools/javac/warnings/suppress/T6480588.out
+++ b/test/langtools/tools/javac/warnings/suppress/T6480588.out
@@ -1,19 +1,19 @@
T6480588.java:16:24: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
T6480588.java:16:51: compiler.warn.has.been.deprecated: DeprecatedInterface, compiler.misc.unnamed.package
T6480588.java:15:2: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package
+T6480588.java:18:35: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
T6480588.java:18:12: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
T6480588.java:18:65: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
+T6480588.java:30:5: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
+T6480588.java:33:25: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
+T6480588.java:33:52: compiler.warn.has.been.deprecated: DeprecatedInterface, compiler.misc.unnamed.package
+T6480588.java:32:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package
T6480588.java:17:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package
-T6480588.java:18:35: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
+T6480588.java:29:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package
T6480588.java:19:9: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
T6480588.java:19:34: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
T6480588.java:21:9: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
T6480588.java:21:25: compiler.warn.deprecated.annotation.has.no.effect: kindname.variable
T6480588.java:21:35: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
-T6480588.java:30:5: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
-T6480588.java:29:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package
T6480588.java:30:33: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
-T6480588.java:33:25: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
-T6480588.java:33:52: compiler.warn.has.been.deprecated: DeprecatedInterface, compiler.misc.unnamed.package
-T6480588.java:32:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package
18 warnings
From 9041f4c47f3c9b90abe825f652f572351060c96a Mon Sep 17 00:00:00 2001
From: Chris Plummer
Date: Wed, 20 Aug 2025 15:32:17 +0000
Subject: [PATCH 06/54] 8309400: JDI spec needs to clarify when
OpaqueFrameException and NativeMethodException are thrown
Reviewed-by: sspitsyn, alanb, amenkov
---
.../classes/com/sun/jdi/ThreadReference.java | 10 ++---
.../com/sun/tools/jdi/StackFrameImpl.java | 39 ++++++++-----------
.../sun/tools/jdi/ThreadReferenceImpl.java | 6 +--
3 files changed, 25 insertions(+), 30 deletions(-)
diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java b/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java
index bccdf4cc8bf..67b8e391bf3 100644
--- a/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java
+++ b/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -402,8 +402,8 @@ public interface ThreadReference extends ObjectReference {
* @throws java.lang.IllegalArgumentException if frame
* is not on this thread's call stack.
*
- * @throws OpaqueFrameException if this thread is a suspended virtual thread and the
- * target VM was unable to pop the frames.
+ * @throws OpaqueFrameException if the target VM is unable to pop this frame
+ * (e.g. a virtual thread is suspended, but not at an event).
*
* @throws NativeMethodException if one of the frames that would be
* popped is that of a native method or if the frame previous to
@@ -484,8 +484,8 @@ public interface ThreadReference extends ObjectReference {
* @throws IncompatibleThreadStateException if this
* thread is not suspended.
*
- * @throws OpaqueFrameException if this thread is a suspended virtual thread and the
- * target VM is unable to force the method to return.
+ * @throws OpaqueFrameException if the target VM is unable to force the method to return
+ * (e.g. a virtual thread is suspended, but not at an event).
*
* @throws NativeMethodException if the frame to be returned from
* is that of a native method.
diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/StackFrameImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/StackFrameImpl.java
index e242bd7313b..a36e5695f69 100644
--- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/StackFrameImpl.java
+++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/StackFrameImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -395,29 +395,24 @@ public class StackFrameImpl extends MirrorImpl
} catch (JDWPException exc) {
switch (exc.errorCode()) {
case JDWP.Error.OPAQUE_FRAME:
- if (thread.isVirtual()) {
- // We first need to find out if the current frame is native, or if the
- // previous frame is native, in which case we throw NativeMethodException
- for (int i = 0; i < 2; i++) {
- StackFrameImpl sf;
- try {
- sf = (StackFrameImpl)thread.frame(i);
- } catch (IndexOutOfBoundsException e) {
- // This should never happen, but we need to check for it.
- break;
- }
- sf.validateStackFrame();
- MethodImpl meth = (MethodImpl)sf.location().method();
- if (meth.isNative()) {
- throw new NativeMethodException();
- }
+ // We first need to find out if the current frame is native, or if the
+ // previous frame is native, in which case we throw NativeMethodException
+ for (int i = 0; i < 2; i++) {
+ StackFrame sf;
+ try {
+ sf = thread.frame(i);
+ } catch (IndexOutOfBoundsException e) {
+ // This should never happen, but we need to check for it.
+ break;
+ }
+ Method meth = sf.location().method();
+ if (meth.isNative()) {
+ throw new NativeMethodException();
}
- // No native frames involved. Must have been due to thread
- // not being mounted.
- throw new OpaqueFrameException();
- } else {
- throw new NativeMethodException();
}
+ // No native frames involved. Must have been due to virtual thread
+ // not being mounted or some other reason such as failure to deopt.
+ throw new OpaqueFrameException();
case JDWP.Error.THREAD_NOT_SUSPENDED:
throw new IncompatibleThreadStateException(
"Thread not current or suspended");
diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java
index 0f99fe99871..e5dce0718f4 100644
--- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java
+++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java
@@ -597,10 +597,10 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl
} catch (JDWPException exc) {
switch (exc.errorCode()) {
case JDWP.Error.OPAQUE_FRAME:
- if (isVirtual() && !meth.isNative()) {
- throw new OpaqueFrameException();
- } else {
+ if (meth.isNative()) {
throw new NativeMethodException();
+ } else {
+ throw new OpaqueFrameException();
}
case JDWP.Error.THREAD_NOT_SUSPENDED:
throw new IncompatibleThreadStateException(
From be6c15ecb490e86bafc15b5cd552784f7aa3ee69 Mon Sep 17 00:00:00 2001
From: Alan Bateman
Date: Wed, 20 Aug 2025 16:07:38 +0000
Subject: [PATCH 07/54] 8365671: Typo in Joiner.allUntil example
Reviewed-by: liach
---
.../classes/java/util/concurrent/StructuredTaskScope.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java b/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java
index fb16e0a615e..0088e486d4a 100644
--- a/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java
+++ b/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java
@@ -700,12 +700,12 @@ public sealed interface StructuredTaskScope
* }
* }
*
- * var joiner = Joiner.all(new CancelAfterTwoFailures());
+ * var joiner = Joiner.allUntil(new CancelAfterTwoFailures());
* }
*
* The following example uses {@code allUntil} to wait for all subtasks to
* complete without any cancellation. This is similar to {@link #awaitAll()}
- * except that it yields a stream of the completed subtasks.
+ * except that it yields a list of the completed subtasks.
* {@snippet lang=java :
* List> invokeAll(Collection> tasks) throws InterruptedException {
* try (var scope = StructuredTaskScope.open(Joiner.allUntil(_ -> false))) {
From ed7d5fe840fed853b8a7db3347d6400f142ad154 Mon Sep 17 00:00:00 2001
From: Francesco Andreuzzi
Date: Wed, 20 Aug 2025 17:16:38 +0000
Subject: [PATCH 08/54] 8360304: Redundant condition in
LibraryCallKit::inline_vector_nary_operation
Reviewed-by: shade, vlivanov
---
src/hotspot/share/opto/vectorIntrinsics.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/hotspot/share/opto/vectorIntrinsics.cpp b/src/hotspot/share/opto/vectorIntrinsics.cpp
index 10430a09e72..43ca51fca67 100644
--- a/src/hotspot/share/opto/vectorIntrinsics.cpp
+++ b/src/hotspot/share/opto/vectorIntrinsics.cpp
@@ -383,7 +383,7 @@ bool LibraryCallKit::inline_vector_nary_operation(int n) {
// When using mask, mask use type needs to be VecMaskUseLoad.
VectorMaskUseType mask_use_type = is_vector_mask(vbox_klass) ? VecMaskUseAll
: is_masked_op ? VecMaskUseLoad : VecMaskNotUsed;
- if ((sopc != 0) && !arch_supports_vector(sopc, num_elem, elem_bt, mask_use_type)) {
+ if (!arch_supports_vector(sopc, num_elem, elem_bt, mask_use_type)) {
log_if_needed(" ** not supported: arity=%d opc=%d vlen=%d etype=%s ismask=%d is_masked_op=%d",
n, sopc, num_elem, type2name(elem_bt),
is_vector_mask(vbox_klass) ? 1 : 0, is_masked_op ? 1 : 0);
@@ -391,7 +391,7 @@ bool LibraryCallKit::inline_vector_nary_operation(int n) {
}
// Return true if current platform has implemented the masked operation with predicate feature.
- bool use_predicate = is_masked_op && sopc != 0 && arch_supports_vector(sopc, num_elem, elem_bt, VecMaskUsePred);
+ bool use_predicate = is_masked_op && arch_supports_vector(sopc, num_elem, elem_bt, VecMaskUsePred);
if (is_masked_op && !use_predicate && !arch_supports_vector(Op_VectorBlend, num_elem, elem_bt, VecMaskUseLoad)) {
log_if_needed(" ** not supported: arity=%d opc=%d vlen=%d etype=%s ismask=0 is_masked_op=1",
n, sopc, num_elem, type2name(elem_bt));
From ecab52c09b078201ebeb8d45c0982b0481e15dc3 Mon Sep 17 00:00:00 2001
From: Francesco Andreuzzi
Date: Wed, 20 Aug 2025 17:21:22 +0000
Subject: [PATCH 09/54] 8365610: Sort share/jfr includes
Reviewed-by: shade, mgronlun
---
src/hotspot/share/jfr/dcmd/jfrDcmds.cpp | 2 +-
.../instrumentation/jfrClassTransformer.cpp | 2 +-
src/hotspot/share/jfr/jfr.cpp | 6 ++----
src/hotspot/share/jfr/jni/jfrJavaSupport.cpp | 5 ++---
src/hotspot/share/jfr/jni/jfrJniMethod.cpp | 20 +++++++++----------
.../jfr/leakprofiler/chains/bfsClosure.cpp | 2 +-
.../jfr/leakprofiler/chains/edgeQueue.hpp | 2 +-
.../chains/pathToGcRootsOperation.cpp | 6 ++----
.../leakprofiler/checkpoint/eventEmitter.hpp | 2 +-
.../checkpoint/objectSampleCheckpoint.cpp | 2 +-
.../checkpoint/objectSampleCheckpoint.hpp | 2 +-
.../checkpoint/objectSampleWriter.cpp | 2 +-
.../leakprofiler/checkpoint/rootResolver.cpp | 4 ++--
.../share/jfr/leakprofiler/leakProfiler.cpp | 4 ++--
.../leakprofiler/sampling/objectSampler.cpp | 4 ++--
.../share/jfr/metadata/jfrSerializer.hpp | 2 +-
.../jfr/periodic/jfrNetworkUtilization.cpp | 2 +-
.../share/jfr/periodic/jfrPeriodic.cpp | 6 +++---
.../jfr/periodic/jfrThreadCPULoadEvent.cpp | 4 ++--
.../sampling/jfrCPUTimeThreadSampler.cpp | 5 ++---
.../periodic/sampling/jfrThreadSampler.cpp | 4 ++--
.../recorder/checkpoint/jfrMetadataEvent.cpp | 2 +-
.../checkpoint/types/jfrThreadState.cpp | 2 +-
.../types/traceid/jfrTraceId.inline.hpp | 2 +-
.../types/traceid/jfrTraceIdLoadBarrier.cpp | 2 +-
.../share/jfr/recorder/jfrEventSetting.hpp | 2 +-
.../share/jfr/recorder/jfrRecorder.cpp | 6 +++---
.../recorder/service/jfrEventThrottler.hpp | 2 +-
.../recorder/service/jfrRecorderService.cpp | 8 ++++----
.../recorder/service/jfrRecorderThread.cpp | 2 +-
.../service/jfrRecorderThreadLoop.cpp | 1 -
.../stacktrace/jfrStackFilterRegistry.hpp | 2 +-
.../share/jfr/recorder/storage/jfrStorage.cpp | 2 +-
.../jfr/recorder/storage/jfrStorageUtils.hpp | 2 +-
.../jfr/recorder/stringpool/jfrStringPool.cpp | 2 +-
.../stringpool/jfrStringPoolWriter.hpp | 2 +-
.../share/jfr/support/jfrAdaptiveSampler.cpp | 1 +
.../support/jfrAnnotationElementIterator.hpp | 2 +-
.../jfr/support/jfrDeprecationEventWriter.cpp | 2 +-
.../jfr/support/jfrDeprecationEventWriter.hpp | 2 +-
.../jfr/support/jfrDeprecationManager.cpp | 7 +++----
.../jfr/support/jfrDeprecationManager.hpp | 2 +-
src/hotspot/share/jfr/support/jfrFlush.cpp | 2 +-
.../share/jfr/support/jfrResolution.cpp | 3 +--
.../share/jfr/support/jfrStackTraceMark.hpp | 4 ++--
.../methodtracer/jfrClassFilterClosure.hpp | 4 ++--
.../jfr/support/methodtracer/jfrFilter.hpp | 2 +-
.../support/methodtracer/jfrFilterManager.hpp | 2 +-
.../support/methodtracer/jfrMethodTracer.hpp | 2 +-
.../jfr/utilities/jfrEpochQueue.inline.hpp | 1 +
src/hotspot/share/jfr/utilities/jfrSet.hpp | 2 +-
.../share/jfr/utilities/jfrTimeConverter.cpp | 2 +-
.../share/jfr/utilities/jfrTryLock.hpp | 2 +-
.../writers/jfrStreamWriterHost.inline.hpp | 3 ++-
.../jtreg/sources/TestIncludesAreSorted.java | 1 +
55 files changed, 84 insertions(+), 89 deletions(-)
diff --git a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp
index e7ba0e8f7ca..d18136e1570 100644
--- a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp
+++ b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp
@@ -24,8 +24,8 @@
#include "classfile/javaClasses.inline.hpp"
#include "classfile/vmSymbols.hpp"
-#include "jfr/jfr.hpp"
#include "jfr/dcmd/jfrDcmds.hpp"
+#include "jfr/jfr.hpp"
#include "jfr/jni/jfrJavaSupport.hpp"
#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/service/jfrOptionSet.hpp"
diff --git a/src/hotspot/share/jfr/instrumentation/jfrClassTransformer.cpp b/src/hotspot/share/jfr/instrumentation/jfrClassTransformer.cpp
index b9bedff0f9d..aa3b14e32f1 100644
--- a/src/hotspot/share/jfr/instrumentation/jfrClassTransformer.cpp
+++ b/src/hotspot/share/jfr/instrumentation/jfrClassTransformer.cpp
@@ -28,8 +28,8 @@
#include "classfile/javaClasses.inline.hpp"
#include "classfile/symbolTable.hpp"
#include "jfr/instrumentation/jfrClassTransformer.hpp"
-#include "jfr/recorder/service/jfrOptionSet.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
+#include "jfr/recorder/service/jfrOptionSet.hpp"
#include "logging/log.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
diff --git a/src/hotspot/share/jfr/jfr.cpp b/src/hotspot/share/jfr/jfr.cpp
index a273df61922..7abf5c89945 100644
--- a/src/hotspot/share/jfr/jfr.cpp
+++ b/src/hotspot/share/jfr/jfr.cpp
@@ -26,18 +26,16 @@
#include "jfr/jfr.hpp"
#include "jfr/jni/jfrJavaSupport.hpp"
#include "jfr/leakprofiler/leakProfiler.hpp"
-#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/repository/jfrEmergencyDump.hpp"
-#include "jfr/recorder/service/jfrOptionSet.hpp"
-#include "jfr/recorder/service/jfrOptionSet.hpp"
#include "jfr/recorder/repository/jfrRepository.hpp"
+#include "jfr/recorder/service/jfrOptionSet.hpp"
#include "jfr/support/jfrKlassExtension.hpp"
#include "jfr/support/jfrResolution.hpp"
#include "jfr/support/jfrThreadLocal.hpp"
#include "jfr/support/methodtracer/jfrMethodTracer.hpp"
#include "jfr/support/methodtracer/jfrTraceTagging.hpp"
-#include "oops/instanceKlass.hpp"
#include "oops/instanceKlass.inline.hpp"
#include "oops/klass.hpp"
#include "runtime/java.hpp"
diff --git a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp
index 3b566868f07..59a9d8a9090 100644
--- a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp
+++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp
@@ -39,11 +39,11 @@
#include "memory/resourceArea.hpp"
#include "oops/instanceOop.hpp"
#include "oops/klass.inline.hpp"
-#include "oops/oop.inline.hpp"
#include "oops/objArrayKlass.hpp"
#include "oops/objArrayOop.inline.hpp"
-#include "runtime/handles.inline.hpp"
+#include "oops/oop.inline.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
+#include "runtime/handles.inline.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/javaThread.hpp"
@@ -52,7 +52,6 @@
#include "runtime/synchronizer.hpp"
#include "runtime/threadSMR.hpp"
#include "utilities/growableArray.hpp"
-#include "classfile/vmSymbols.hpp"
#ifdef ASSERT
static void check_java_thread_state(JavaThread* t, JavaThreadState state) {
diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp
index a09da529b1b..1d1f3a62866 100644
--- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp
+++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp
@@ -22,19 +22,24 @@
*
*/
+#include "jfr/instrumentation/jfrEventClassTransformer.hpp"
+#include "jfr/instrumentation/jfrJvmtiAgent.hpp"
#include "jfr/jfr.hpp"
#include "jfr/jfrEvents.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
+#include "jfr/jni/jfrJniMethodRegistration.hpp"
+#include "jfr/leakprofiler/leakProfiler.hpp"
#include "jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp"
#include "jfr/periodic/sampling/jfrThreadSampler.hpp"
-#include "jfr/recorder/jfrEventSetting.hpp"
-#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/checkpoint/jfrMetadataEvent.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
+#include "jfr/recorder/jfrEventSetting.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/repository/jfrChunk.hpp"
-#include "jfr/recorder/repository/jfrRepository.hpp"
#include "jfr/recorder/repository/jfrChunkRotation.hpp"
#include "jfr/recorder/repository/jfrChunkWriter.hpp"
#include "jfr/recorder/repository/jfrEmergencyDump.hpp"
+#include "jfr/recorder/repository/jfrRepository.hpp"
#include "jfr/recorder/service/jfrEventThrottler.hpp"
#include "jfr/recorder/service/jfrOptionSet.hpp"
#include "jfr/recorder/service/jfrRecorderService.hpp"
@@ -42,18 +47,13 @@
#include "jfr/recorder/stacktrace/jfrStackFilterRegistry.hpp"
#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
#include "jfr/recorder/stringpool/jfrStringPool.hpp"
-#include "jfr/jni/jfrJavaSupport.hpp"
-#include "jfr/jni/jfrJniMethodRegistration.hpp"
-#include "jfr/instrumentation/jfrEventClassTransformer.hpp"
-#include "jfr/instrumentation/jfrJvmtiAgent.hpp"
-#include "jfr/leakprofiler/leakProfiler.hpp"
#include "jfr/support/jfrDeprecationManager.hpp"
#include "jfr/support/jfrJdkJfrEvent.hpp"
#include "jfr/support/jfrKlassUnloading.hpp"
#include "jfr/support/methodtracer/jfrMethodTracer.hpp"
#include "jfr/utilities/jfrJavaLog.hpp"
-#include "jfr/utilities/jfrTimeConverter.hpp"
#include "jfr/utilities/jfrTime.hpp"
+#include "jfr/utilities/jfrTimeConverter.hpp"
#include "jfr/writers/jfrJavaEventWriter.hpp"
#include "jfrfiles/jfrPeriodic.hpp"
#include "jfrfiles/jfrTypes.hpp"
@@ -67,8 +67,8 @@
#include "runtime/os.hpp"
#include "utilities/debug.hpp"
#ifdef LINUX
-#include "osContainer_linux.hpp"
#include "os_linux.hpp"
+#include "osContainer_linux.hpp"
#endif
#define NO_TRANSITION(result_type, header) extern "C" { result_type JNICALL header {
diff --git a/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp b/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp
index 45fd4a7dc57..5bdddc4fd68 100644
--- a/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp
+++ b/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp
@@ -24,8 +24,8 @@
#include "jfr/leakprofiler/chains/bfsClosure.hpp"
#include "jfr/leakprofiler/chains/dfsClosure.hpp"
#include "jfr/leakprofiler/chains/edge.hpp"
-#include "jfr/leakprofiler/chains/edgeStore.hpp"
#include "jfr/leakprofiler/chains/edgeQueue.hpp"
+#include "jfr/leakprofiler/chains/edgeStore.hpp"
#include "jfr/leakprofiler/chains/jfrbitset.hpp"
#include "jfr/leakprofiler/utilities/granularTimer.hpp"
#include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp"
diff --git a/src/hotspot/share/jfr/leakprofiler/chains/edgeQueue.hpp b/src/hotspot/share/jfr/leakprofiler/chains/edgeQueue.hpp
index 774bd10d353..18cee5de7f2 100644
--- a/src/hotspot/share/jfr/leakprofiler/chains/edgeQueue.hpp
+++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeQueue.hpp
@@ -25,9 +25,9 @@
#ifndef SHARE_JFR_LEAKPROFILER_CHAINS_EDGEQUEUE_HPP
#define SHARE_JFR_LEAKPROFILER_CHAINS_EDGEQUEUE_HPP
-#include "memory/allocation.hpp"
#include "jfr/leakprofiler/chains/edge.hpp"
#include "jfr/leakprofiler/utilities/unifiedOopRef.hpp"
+#include "memory/allocation.hpp"
class JfrVirtualMemory;
diff --git a/src/hotspot/share/jfr/leakprofiler/chains/pathToGcRootsOperation.cpp b/src/hotspot/share/jfr/leakprofiler/chains/pathToGcRootsOperation.cpp
index ca7650d6876..83dc71f3827 100644
--- a/src/hotspot/share/jfr/leakprofiler/chains/pathToGcRootsOperation.cpp
+++ b/src/hotspot/share/jfr/leakprofiler/chains/pathToGcRootsOperation.cpp
@@ -24,7 +24,6 @@
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/gc_globals.hpp"
-#include "jfr/leakprofiler/leakProfiler.hpp"
#include "jfr/leakprofiler/chains/bfsClosure.hpp"
#include "jfr/leakprofiler/chains/dfsClosure.hpp"
#include "jfr/leakprofiler/chains/edge.hpp"
@@ -32,12 +31,11 @@
#include "jfr/leakprofiler/chains/edgeStore.hpp"
#include "jfr/leakprofiler/chains/jfrbitset.hpp"
#include "jfr/leakprofiler/chains/objectSampleMarker.hpp"
-#include "jfr/leakprofiler/chains/rootSetClosure.hpp"
-#include "jfr/leakprofiler/chains/edgeStore.hpp"
-#include "jfr/leakprofiler/chains/objectSampleMarker.hpp"
#include "jfr/leakprofiler/chains/pathToGcRootsOperation.hpp"
+#include "jfr/leakprofiler/chains/rootSetClosure.hpp"
#include "jfr/leakprofiler/checkpoint/eventEmitter.hpp"
#include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
+#include "jfr/leakprofiler/leakProfiler.hpp"
#include "jfr/leakprofiler/sampling/objectSample.hpp"
#include "jfr/leakprofiler/sampling/objectSampler.hpp"
#include "jfr/leakprofiler/utilities/granularTimer.hpp"
diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/eventEmitter.hpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/eventEmitter.hpp
index 1d40c001c43..3965d0c0ff7 100644
--- a/src/hotspot/share/jfr/leakprofiler/checkpoint/eventEmitter.hpp
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/eventEmitter.hpp
@@ -25,8 +25,8 @@
#ifndef SHARE_JFR_LEAKPROFILER_CHECKPOINT_EVENTEMITTER_HPP
#define SHARE_JFR_LEAKPROFILER_CHECKPOINT_EVENTEMITTER_HPP
-#include "memory/allocation.hpp"
#include "jfr/utilities/jfrTime.hpp"
+#include "memory/allocation.hpp"
typedef u8 traceid;
diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp
index 300786daf05..d8834e65b60 100644
--- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp
@@ -39,8 +39,8 @@
#include "jfr/support/jfrKlassUnloading.hpp"
#include "jfr/support/jfrMethodLookup.hpp"
#include "jfr/utilities/jfrHashtable.hpp"
-#include "jfr/utilities/jfrSet.hpp"
#include "jfr/utilities/jfrRelation.hpp"
+#include "jfr/utilities/jfrSet.hpp"
#include "memory/resourceArea.inline.hpp"
#include "oops/instanceKlass.inline.hpp"
#include "runtime/interfaceSupport.inline.hpp"
diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp
index 2ab2e12302f..63e251d3b67 100644
--- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp
@@ -25,8 +25,8 @@
#ifndef SHARE_JFR_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLECHECKPOINT_HPP
#define SHARE_JFR_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLECHECKPOINT_HPP
-#include "memory/allStatic.hpp"
#include "jfr/utilities/jfrTypes.hpp"
+#include "memory/allStatic.hpp"
class EdgeStore;
class InstanceKlass;
diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp
index ff1f9efd017..5b7ee3ddb3d 100644
--- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp
@@ -22,7 +22,6 @@
*
*/
-#include "jfrfiles/jfrTypes.hpp"
#include "jfr/leakprofiler/chains/edge.hpp"
#include "jfr/leakprofiler/chains/edgeStore.hpp"
#include "jfr/leakprofiler/chains/edgeUtils.hpp"
@@ -34,6 +33,7 @@
#include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp"
#include "jfr/metadata/jfrSerializer.hpp"
#include "jfr/writers/jfrTypeWriterHost.hpp"
+#include "jfrfiles/jfrTypes.hpp"
#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "utilities/growableArray.hpp"
diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp
index cf94293f0a3..4d7ccba5262 100644
--- a/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp
@@ -27,13 +27,13 @@
#include "gc/shared/oopStorage.inline.hpp"
#include "gc/shared/oopStorageSet.hpp"
#include "gc/shared/strongRootsScope.hpp"
-#include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp"
#include "jfr/leakprofiler/checkpoint/rootResolver.hpp"
+#include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp"
#include "jfr/utilities/jfrThreadIterator.hpp"
#include "memory/iterator.hpp"
-#include "prims/jvmtiDeferredUpdates.hpp"
#include "oops/klass.hpp"
#include "oops/oop.hpp"
+#include "prims/jvmtiDeferredUpdates.hpp"
#include "prims/jvmtiThreadState.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/jniHandles.hpp"
diff --git a/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp b/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp
index a5b4babb2b1..e8ad79783c0 100644
--- a/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp
+++ b/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp
@@ -22,11 +22,11 @@
*
*/
+#include "jfr/leakprofiler/checkpoint/eventEmitter.hpp"
#include "jfr/leakprofiler/leakProfiler.hpp"
+#include "jfr/leakprofiler/sampling/objectSampler.hpp"
#include "jfr/leakprofiler/startOperation.hpp"
#include "jfr/leakprofiler/stopOperation.hpp"
-#include "jfr/leakprofiler/checkpoint/eventEmitter.hpp"
-#include "jfr/leakprofiler/sampling/objectSampler.hpp"
#include "jfr/recorder/service/jfrOptionSet.hpp"
#include "logging/log.hpp"
#include "memory/iterator.hpp"
diff --git a/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp b/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp
index 86b8712698b..83873e2e500 100644
--- a/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp
+++ b/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp
@@ -31,11 +31,11 @@
#include "jfr/leakprofiler/sampling/objectSampler.hpp"
#include "jfr/leakprofiler/sampling/sampleList.hpp"
#include "jfr/leakprofiler/sampling/samplePriorityQueue.hpp"
-#include "jfr/recorder/jfrEventSetting.inline.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
+#include "jfr/recorder/jfrEventSetting.inline.hpp"
#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
-#include "jfr/utilities/jfrSignal.hpp"
#include "jfr/support/jfrThreadLocal.hpp"
+#include "jfr/utilities/jfrSignal.hpp"
#include "jfr/utilities/jfrTime.hpp"
#include "jfr/utilities/jfrTryLock.hpp"
#include "logging/log.hpp"
diff --git a/src/hotspot/share/jfr/metadata/jfrSerializer.hpp b/src/hotspot/share/jfr/metadata/jfrSerializer.hpp
index 57ae3554b0d..34ea94acbe8 100644
--- a/src/hotspot/share/jfr/metadata/jfrSerializer.hpp
+++ b/src/hotspot/share/jfr/metadata/jfrSerializer.hpp
@@ -25,9 +25,9 @@
#ifndef SHARE_JFR_METADATA_JFRSERIALIZER_HPP
#define SHARE_JFR_METADATA_JFRSERIALIZER_HPP
-#include "memory/allocation.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
#include "jfrfiles/jfrTypes.hpp"
+#include "memory/allocation.hpp"
/*
* A "type" in Jfr is a binary relation defined by enumerating a set of ordered pairs:
diff --git a/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp b/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp
index c18248e1056..11e211f6505 100644
--- a/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp
+++ b/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp
@@ -22,13 +22,13 @@
*
*/
-#include "logging/log.hpp"
#include "jfr/jfrEvents.hpp"
#include "jfr/metadata/jfrSerializer.hpp"
#include "jfr/periodic/jfrNetworkUtilization.hpp"
#include "jfr/periodic/jfrOSInterface.hpp"
#include "jfr/utilities/jfrTime.hpp"
#include "jfr/utilities/jfrTypes.hpp"
+#include "logging/log.hpp"
#include "runtime/os_perf.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/growableArray.hpp"
diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp
index 0be1c32728c..49669d1675d 100644
--- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp
+++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp
@@ -38,11 +38,11 @@
#include "jfr/periodic/jfrCompilerQueueUtilization.hpp"
#include "jfr/periodic/jfrFinalizerStatisticsEvent.hpp"
#include "jfr/periodic/jfrModuleEvent.hpp"
+#include "jfr/periodic/jfrNativeMemoryEvent.hpp"
+#include "jfr/periodic/jfrNetworkUtilization.hpp"
#include "jfr/periodic/jfrOSInterface.hpp"
#include "jfr/periodic/jfrThreadCPULoadEvent.hpp"
#include "jfr/periodic/jfrThreadDumpEvent.hpp"
-#include "jfr/periodic/jfrNativeMemoryEvent.hpp"
-#include "jfr/periodic/jfrNetworkUtilization.hpp"
#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/utilities/jfrThreadIterator.hpp"
#include "jfr/utilities/jfrTime.hpp"
@@ -61,8 +61,8 @@
#include "runtime/os_perf.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threads.hpp"
-#include "runtime/vmThread.hpp"
#include "runtime/vm_version.hpp"
+#include "runtime/vmThread.hpp"
#include "services/classLoadingService.hpp"
#include "services/management.hpp"
#include "services/memoryPool.hpp"
diff --git a/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp b/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp
index 1863b1af800..e2c92af2fb3 100644
--- a/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp
+++ b/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp
@@ -22,14 +22,14 @@
*
*/
-#include "logging/log.hpp"
#include "jfr/jfrEvents.hpp"
#include "jfr/periodic/jfrThreadCPULoadEvent.hpp"
#include "jfr/utilities/jfrThreadIterator.hpp"
#include "jfr/utilities/jfrTime.hpp"
-#include "utilities/globalDefinitions.hpp"
+#include "logging/log.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/os.hpp"
+#include "utilities/globalDefinitions.hpp"
jlong JfrThreadCPULoadEvent::get_wallclock_time() {
return os::javaTimeNanos();
diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp
index 2793a1fb984..db3ca758cc1 100644
--- a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp
+++ b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp
@@ -29,8 +29,8 @@
#if defined(LINUX)
#include "jfr/periodic/sampling/jfrThreadSampling.hpp"
#include "jfr/support/jfrThreadLocal.hpp"
-#include "jfr/utilities/jfrTime.hpp"
#include "jfr/utilities/jfrThreadIterator.hpp"
+#include "jfr/utilities/jfrTime.hpp"
#include "jfr/utilities/jfrTypes.hpp"
#include "jfrfiles/jfrEventClasses.hpp"
#include "memory/resourceArea.hpp"
@@ -41,9 +41,8 @@
#include "runtime/threadSMR.hpp"
#include "runtime/vmOperation.hpp"
#include "runtime/vmThread.hpp"
-#include "utilities/ticks.hpp"
-
#include "signals_posix.hpp"
+#include "utilities/ticks.hpp"
static const int64_t RECOMPUTE_INTERVAL_MS = 100;
diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp
index 4c44c43772d..6347abd654f 100644
--- a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp
+++ b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp
@@ -23,11 +23,11 @@
*/
#include "jfr/metadata/jfrSerializer.hpp"
-#include "jfr/recorder/service/jfrOptionSet.hpp"
#include "jfr/periodic/sampling/jfrSampleMonitor.hpp"
#include "jfr/periodic/sampling/jfrSampleRequest.hpp"
-#include "jfr/periodic/sampling/jfrThreadSampling.hpp"
#include "jfr/periodic/sampling/jfrThreadSampler.hpp"
+#include "jfr/periodic/sampling/jfrThreadSampling.hpp"
+#include "jfr/recorder/service/jfrOptionSet.hpp"
#include "jfr/utilities/jfrTime.hpp"
#include "jfr/utilities/jfrTryLock.hpp"
#include "jfr/utilities/jfrTypes.hpp"
diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp
index 20e9c1e6798..937a0ca58c7 100644
--- a/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp
@@ -25,8 +25,8 @@
#include "jfr/jni/jfrJavaSupport.hpp"
#include "jfr/jni/jfrUpcalls.hpp"
#include "jfr/recorder/checkpoint/jfrMetadataEvent.hpp"
-#include "jfr/recorder/repository/jfrChunkWriter.hpp"
#include "jfr/recorder/jfrEventSetting.inline.hpp"
+#include "jfr/recorder/repository/jfrChunkWriter.hpp"
#include "oops/klass.inline.hpp"
#include "oops/oop.inline.hpp"
#include "oops/typeArrayOop.inline.hpp"
diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadState.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadState.cpp
index cdd7adebe4f..ed7e7d8195e 100644
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadState.cpp
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadState.cpp
@@ -23,8 +23,8 @@
*/
#include "classfile/javaClasses.inline.hpp"
-#include "jfr/recorder/checkpoint/types/jfrThreadState.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
+#include "jfr/recorder/checkpoint/types/jfrThreadState.hpp"
#include "jfr/support/jfrThreadLocal.hpp"
#include "jvmtifiles/jvmti.h"
#include "runtime/javaThread.hpp"
diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp
index 03647bdeae2..2af1080820f 100644
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp
@@ -27,9 +27,9 @@
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp"
-#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp"
#include "jfr/support/jfrKlassExtension.hpp"
#include "oops/instanceKlass.hpp"
diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.cpp
index 8f600431333..12a73fd76c5 100644
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.cpp
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.cpp
@@ -22,8 +22,8 @@
*
*/
-#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdKlassQueue.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp"
#include "jfr/recorder/service/jfrOptionSet.hpp"
#include "jfr/support/jfrThreadLocal.hpp"
#include "jfr/utilities/jfrEpochQueue.inline.hpp"
diff --git a/src/hotspot/share/jfr/recorder/jfrEventSetting.hpp b/src/hotspot/share/jfr/recorder/jfrEventSetting.hpp
index e935dff3b27..3b2888bf505 100644
--- a/src/hotspot/share/jfr/recorder/jfrEventSetting.hpp
+++ b/src/hotspot/share/jfr/recorder/jfrEventSetting.hpp
@@ -25,9 +25,9 @@
#ifndef SHARE_JFR_RECORDER_JFREVENTSETTING_HPP
#define SHARE_JFR_RECORDER_JFREVENTSETTING_HPP
-#include "jni.h"
#include "jfr/utilities/jfrAllocation.hpp"
#include "jfrfiles/jfrEventControl.hpp"
+#include "jni.h"
//
// Native event settings as an associative array using the event id as key.
diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp
index 4ef278ab522..f5214ff7942 100644
--- a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp
+++ b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp
@@ -31,17 +31,17 @@
#include "jfr/periodic/jfrOSInterface.hpp"
#include "jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp"
#include "jfr/periodic/sampling/jfrThreadSampler.hpp"
-#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
#include "jfr/recorder/checkpoint/types/jfrThreadGroupManager.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/repository/jfrRepository.hpp"
#include "jfr/recorder/service/jfrEventThrottler.hpp"
#include "jfr/recorder/service/jfrOptionSet.hpp"
#include "jfr/recorder/service/jfrPostBox.hpp"
#include "jfr/recorder/service/jfrRecorderService.hpp"
#include "jfr/recorder/service/jfrRecorderThread.hpp"
-#include "jfr/recorder/storage/jfrStorage.hpp"
#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
+#include "jfr/recorder/storage/jfrStorage.hpp"
#include "jfr/recorder/stringpool/jfrStringPool.hpp"
#include "jfr/support/jfrThreadLocal.hpp"
#include "jfr/utilities/jfrTime.hpp"
@@ -49,8 +49,8 @@
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/resourceArea.inline.hpp"
-#include "runtime/handles.inline.hpp"
#include "runtime/globals_extension.hpp"
+#include "runtime/handles.inline.hpp"
#include "utilities/growableArray.hpp"
#ifdef ASSERT
#include "prims/jvmtiEnvBase.hpp"
diff --git a/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.hpp b/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.hpp
index b3c56183630..be6f8127205 100644
--- a/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.hpp
+++ b/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.hpp
@@ -26,8 +26,8 @@
#ifndef SHARE_JFR_RECORDER_SERVICE_JFREVENTTHROTTLER_HPP
#define SHARE_JFR_RECORDER_SERVICE_JFREVENTTHROTTLER_HPP
-#include "jfrfiles/jfrEventIds.hpp"
#include "jfr/support/jfrAdaptiveSampler.hpp"
+#include "jfrfiles/jfrEventIds.hpp"
class JfrEventThrottler : public JfrAdaptiveSampler {
friend class JfrRecorder;
diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp
index 7784148aee5..e8a3ea935de 100644
--- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp
+++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp
@@ -22,14 +22,13 @@
*
*/
-#include "jfrfiles/jfrEventClasses.hpp"
#include "jfr/jni/jfrJavaSupport.hpp"
-#include "jfr/leakprofiler/leakProfiler.hpp"
#include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
+#include "jfr/leakprofiler/leakProfiler.hpp"
#include "jfr/leakprofiler/sampling/objectSampler.hpp"
-#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
#include "jfr/recorder/checkpoint/jfrMetadataEvent.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/repository/jfrChunkRotation.hpp"
#include "jfr/recorder/repository/jfrChunkWriter.hpp"
#include "jfr/recorder/repository/jfrRepository.hpp"
@@ -43,8 +42,9 @@
#include "jfr/utilities/jfrAllocation.hpp"
#include "jfr/utilities/jfrThreadIterator.hpp"
#include "jfr/utilities/jfrTime.hpp"
-#include "jfr/writers/jfrJavaEventWriter.hpp"
#include "jfr/utilities/jfrTypes.hpp"
+#include "jfr/writers/jfrJavaEventWriter.hpp"
+#include "jfrfiles/jfrEventClasses.hpp"
#include "logging/log.hpp"
#include "runtime/atomic.hpp"
#include "runtime/interfaceSupport.inline.hpp"
diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderThread.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderThread.cpp
index aa594ea6d1f..a63a55386a0 100644
--- a/src/hotspot/share/jfr/recorder/service/jfrRecorderThread.cpp
+++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderThread.cpp
@@ -33,8 +33,8 @@
#include "memory/universe.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/javaThread.hpp"
-#include "utilities/preserveException.hpp"
#include "utilities/macros.hpp"
+#include "utilities/preserveException.hpp"
static Thread* start_thread(instanceHandle thread_oop, ThreadFunction proc, TRAPS) {
assert(thread_oop.not_null(), "invariant");
diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp
index 8aeb745b35e..de015e9a502 100644
--- a/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp
+++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp
@@ -27,7 +27,6 @@
#include "jfr/recorder/service/jfrPostBox.hpp"
#include "jfr/recorder/service/jfrRecorderService.hpp"
#include "jfr/recorder/service/jfrRecorderThread.hpp"
-#include "jfr/recorder/jfrRecorder.hpp"
#include "logging/log.hpp"
#include "runtime/handles.hpp"
#include "runtime/interfaceSupport.inline.hpp"
diff --git a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilterRegistry.hpp b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilterRegistry.hpp
index e35fb90938f..a3564506924 100644
--- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilterRegistry.hpp
+++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilterRegistry.hpp
@@ -25,8 +25,8 @@
#ifndef SHARE_JFR_RECORDER_STACKTRACE_JFRSTCKFILTERREGISTRY_HPP
#define SHARE_JFR_RECORDER_STACKTRACE_JFRSTCKFILTERREGISTRY_HPP
-#include "jni.h"
#include "jfr/utilities/jfrAllocation.hpp"
+#include "jni.h"
class JavaThread;
class JfrStackFilter;
diff --git a/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp b/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp
index ca54b297b38..934d2ba9d28 100644
--- a/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp
+++ b/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp
@@ -24,8 +24,8 @@
#include "jfr/jfrEvents.hpp"
#include "jfr/jni/jfrJavaSupport.hpp"
-#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/repository/jfrChunkWriter.hpp"
#include "jfr/recorder/service/jfrOptionSet.hpp"
#include "jfr/recorder/service/jfrPostBox.hpp"
diff --git a/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp b/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp
index fdfd32d1f90..690a5730804 100644
--- a/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp
+++ b/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp
@@ -25,8 +25,8 @@
#ifndef SHARE_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_HPP
#define SHARE_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_HPP
-#include "jfr/recorder/storage/jfrBuffer.hpp"
#include "jfr/recorder/repository/jfrChunkWriter.hpp"
+#include "jfr/recorder/storage/jfrBuffer.hpp"
#include "jfr/utilities/jfrAllocation.hpp"
#include "jfr/utilities/jfrTypes.hpp"
#include "runtime/javaThread.hpp"
diff --git a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp
index dc28818b0f9..e1733b0ed5a 100644
--- a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp
+++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp
@@ -27,9 +27,9 @@
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp"
+#include "jfr/recorder/repository/jfrChunkWriter.hpp"
#include "jfr/recorder/service/jfrOptionSet.hpp"
#include "jfr/recorder/storage/jfrMemorySpace.inline.hpp"
-#include "jfr/recorder/repository/jfrChunkWriter.hpp"
#include "jfr/recorder/storage/jfrStorageUtils.inline.hpp"
#include "jfr/recorder/stringpool/jfrStringPool.hpp"
#include "jfr/recorder/stringpool/jfrStringPoolWriter.hpp"
diff --git a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolWriter.hpp b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolWriter.hpp
index c91b6e585ce..5fc41550b66 100644
--- a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolWriter.hpp
+++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolWriter.hpp
@@ -25,11 +25,11 @@
#ifndef SHARE_JFR_RECORDER_STRINGPOOL_JFRSTRINGPOOLWRITER_HPP
#define SHARE_JFR_RECORDER_STRINGPOOL_JFRSTRINGPOOLWRITER_HPP
-#include "memory/allocation.hpp"
#include "jfr/recorder/stringpool/jfrStringPoolBuffer.hpp"
#include "jfr/writers/jfrEventWriterHost.hpp"
#include "jfr/writers/jfrMemoryWriterHost.hpp"
#include "jfr/writers/jfrStorageAdapter.hpp"
+#include "memory/allocation.hpp"
class Thread;
diff --git a/src/hotspot/share/jfr/support/jfrAdaptiveSampler.cpp b/src/hotspot/share/jfr/support/jfrAdaptiveSampler.cpp
index aa351a81ff3..769a6b4a3e8 100644
--- a/src/hotspot/share/jfr/support/jfrAdaptiveSampler.cpp
+++ b/src/hotspot/share/jfr/support/jfrAdaptiveSampler.cpp
@@ -32,6 +32,7 @@
#include "logging/log.hpp"
#include "runtime/atomic.hpp"
#include "utilities/globalDefinitions.hpp"
+
#include
JfrSamplerWindow::JfrSamplerWindow() :
diff --git a/src/hotspot/share/jfr/support/jfrAnnotationElementIterator.hpp b/src/hotspot/share/jfr/support/jfrAnnotationElementIterator.hpp
index 9d8b35080fb..289f0ead2fe 100644
--- a/src/hotspot/share/jfr/support/jfrAnnotationElementIterator.hpp
+++ b/src/hotspot/share/jfr/support/jfrAnnotationElementIterator.hpp
@@ -26,8 +26,8 @@
#define SHARE_JFR_SUPPORT_JFRANNOTATIONELEMENTITERATOR_HPP
#include "jni.h"
-#include "utilities/globalDefinitions.hpp"
#include "memory/allocation.hpp"
+#include "utilities/globalDefinitions.hpp"
class InstanceKlass;
class Symbol;
diff --git a/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.cpp b/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.cpp
index 49b5e20e49a..7225dd60182 100644
--- a/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.cpp
+++ b/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.cpp
@@ -22,13 +22,13 @@
*
*/
-#include "jfrfiles/jfrEventIds.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
#include "jfr/recorder/jfrEventSetting.inline.hpp"
#include "jfr/recorder/repository/jfrChunkWriter.hpp"
#include "jfr/support/jfrDeprecationEventWriter.hpp"
#include "jfr/support/jfrDeprecationManager.hpp"
#include "jfr/utilities/jfrTypes.hpp"
+#include "jfrfiles/jfrEventIds.hpp"
#include "runtime/thread.inline.hpp"
// This dual state machine for the level setting is because when multiple recordings are running,
diff --git a/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.hpp b/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.hpp
index 1d73d4dc3a3..85a7ba51732 100644
--- a/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.hpp
+++ b/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.hpp
@@ -25,9 +25,9 @@
#ifndef SHARE_JFR_SUPPORT_JFRDEPRECATIONEVENTWRITER_HPP
#define SHARE_JFR_SUPPORT_JFRDEPRECATIONEVENTWRITER_HPP
-#include "memory/allocation.hpp"
#include "jfr/utilities/jfrBlob.hpp"
#include "jfr/utilities/jfrTime.hpp"
+#include "memory/allocation.hpp"
class JfrCheckpointWriter;
class JfrChunkWriter;
diff --git a/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp b/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp
index 8fc35ca8dc1..5d2e180cae9 100644
--- a/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp
+++ b/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp
@@ -24,12 +24,11 @@
#include "classfile/moduleEntry.hpp"
#include "interpreter/bytecodes.hpp"
-#include "jfrfiles/jfrEventIds.hpp"
#include "jfr/jni/jfrJavaSupport.hpp"
-#include "jfr/recorder/jfrRecorder.hpp"
-#include "jfr/recorder/jfrEventSetting.inline.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
+#include "jfr/recorder/jfrEventSetting.inline.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/repository/jfrChunkWriter.hpp"
#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
#include "jfr/recorder/storage/jfrReferenceCountedStorage.hpp"
@@ -41,6 +40,7 @@
#include "jfr/utilities/jfrBlob.hpp"
#include "jfr/utilities/jfrLinkedList.inline.hpp"
#include "jfr/utilities/jfrTime.hpp"
+#include "jfrfiles/jfrEventIds.hpp"
#include "logging/log.hpp"
#include "memory/resourceArea.inline.hpp"
#include "oops/instanceKlass.inline.hpp"
@@ -49,7 +49,6 @@
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/thread.inline.hpp"
-// for strstr
#include
static bool _enqueue_klasses = false;
diff --git a/src/hotspot/share/jfr/support/jfrDeprecationManager.hpp b/src/hotspot/share/jfr/support/jfrDeprecationManager.hpp
index d156679521a..86fe3cd35df 100644
--- a/src/hotspot/share/jfr/support/jfrDeprecationManager.hpp
+++ b/src/hotspot/share/jfr/support/jfrDeprecationManager.hpp
@@ -25,9 +25,9 @@
#ifndef SHARE_JFR_SUPPORT_JFRDEPRECATIONMANAGER_HPP
#define SHARE_JFR_SUPPORT_JFRDEPRECATIONMANAGER_HPP
-#include "memory/allocation.hpp"
#include "jfr/utilities/jfrBlob.hpp"
#include "jfr/utilities/jfrTypes.hpp"
+#include "memory/allocation.hpp"
class JavaThread;
class JfrCheckpointWriter;
diff --git a/src/hotspot/share/jfr/support/jfrFlush.cpp b/src/hotspot/share/jfr/support/jfrFlush.cpp
index 0179cde3d4a..a8ad2f531fd 100644
--- a/src/hotspot/share/jfr/support/jfrFlush.cpp
+++ b/src/hotspot/share/jfr/support/jfrFlush.cpp
@@ -23,8 +23,8 @@
*/
#include "jfr/recorder/jfrEventSetting.inline.hpp"
-#include "jfr/recorder/storage/jfrStorage.hpp"
#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
+#include "jfr/recorder/storage/jfrStorage.hpp"
#include "jfr/support/jfrFlush.hpp"
#include "jfr/support/jfrThreadLocal.hpp"
#include "runtime/javaThread.hpp"
diff --git a/src/hotspot/share/jfr/support/jfrResolution.cpp b/src/hotspot/share/jfr/support/jfrResolution.cpp
index 4027de2fb3d..3a00d24d455 100644
--- a/src/hotspot/share/jfr/support/jfrResolution.cpp
+++ b/src/hotspot/share/jfr/support/jfrResolution.cpp
@@ -26,8 +26,8 @@
#include "ci/ciMethod.hpp"
#include "classfile/vmSymbols.hpp"
#include "interpreter/linkResolver.hpp"
-#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/stacktrace/jfrStackTrace.hpp"
#include "jfr/support/jfrDeprecationManager.hpp"
#include "jfr/support/jfrResolution.hpp"
@@ -42,7 +42,6 @@
#include "opto/parse.hpp"
#endif
- // for strstr
#include
// The following packages are internal implmentation details used by reflection.
diff --git a/src/hotspot/share/jfr/support/jfrStackTraceMark.hpp b/src/hotspot/share/jfr/support/jfrStackTraceMark.hpp
index e56dc64e400..1429c48a278 100644
--- a/src/hotspot/share/jfr/support/jfrStackTraceMark.hpp
+++ b/src/hotspot/share/jfr/support/jfrStackTraceMark.hpp
@@ -25,9 +25,9 @@
#ifndef SHARE_JFR_SUPPORT_JFRSTACKTRACEMARK_HPP
#define SHARE_JFR_SUPPORT_JFRSTACKTRACEMARK_HPP
-#include "memory/allocation.hpp"
-#include "jfrfiles/jfrEventIds.hpp"
#include "jfr/utilities/jfrTypes.hpp"
+#include "jfrfiles/jfrEventIds.hpp"
+#include "memory/allocation.hpp"
class Thread;
diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.hpp b/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.hpp
index 6cf1b321f1e..2febb43ce3a 100644
--- a/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.hpp
+++ b/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.hpp
@@ -25,11 +25,11 @@
#ifndef SHARE_JFR_SUPPORT_METHODTRACER_JFRFILTERCLASSCLOSURE_HPP
#define SHARE_JFR_SUPPORT_METHODTRACER_JFRFILTERCLASSCLOSURE_HPP
-#include "jni.h"
-#include "memory/iterator.hpp"
#include "jfr/support/methodtracer/jfrInstrumentedClass.hpp"
#include "jfr/utilities/jfrRelation.hpp"
#include "jfr/utilities/jfrTypes.hpp"
+#include "jni.h"
+#include "memory/iterator.hpp"
class JavaThread;
class JfrFilter;
diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrFilter.hpp b/src/hotspot/share/jfr/support/methodtracer/jfrFilter.hpp
index 665a2cafad3..d4c2414fa84 100644
--- a/src/hotspot/share/jfr/support/methodtracer/jfrFilter.hpp
+++ b/src/hotspot/share/jfr/support/methodtracer/jfrFilter.hpp
@@ -25,8 +25,8 @@
#ifndef SHARE_JFR_SUPPORT_METHODTRACER_JFRFILTER_HPP
#define SHARE_JFR_SUPPORT_METHODTRACER_JFRFILTER_HPP
-#include "jni.h"
#include "jfr/utilities/jfrAllocation.hpp"
+#include "jni.h"
#include "oops/annotations.hpp"
class InstanceKlass;
diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrFilterManager.hpp b/src/hotspot/share/jfr/support/methodtracer/jfrFilterManager.hpp
index 904c8447a2e..687e2d700bc 100644
--- a/src/hotspot/share/jfr/support/methodtracer/jfrFilterManager.hpp
+++ b/src/hotspot/share/jfr/support/methodtracer/jfrFilterManager.hpp
@@ -25,8 +25,8 @@
#ifndef SHARE_JFR_SUPPORT_METHODTRACER_JFRFILTERMANAGER_HPP
#define SHARE_JFR_SUPPORT_METHODTRACER_JFRFILTERMANAGER_HPP
-#include "jni.h"
#include "jfr/utilities/jfrAllocation.hpp"
+#include "jni.h"
class JfrFilter;
class JavaThread;
diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrMethodTracer.hpp b/src/hotspot/share/jfr/support/methodtracer/jfrMethodTracer.hpp
index d67de9daa59..8a214ab675b 100644
--- a/src/hotspot/share/jfr/support/methodtracer/jfrMethodTracer.hpp
+++ b/src/hotspot/share/jfr/support/methodtracer/jfrMethodTracer.hpp
@@ -25,10 +25,10 @@
#ifndef SHARE_JFR_SUPPORT_METHODTRACER_JFRMETHODTRACER_HPP
#define SHARE_JFR_SUPPORT_METHODTRACER_JFRMETHODTRACER_HPP
-#include "jni.h"
#include "jfr/support/methodtracer/jfrInstrumentedClass.hpp"
#include "jfr/support/methodtracer/jfrTracedMethod.hpp"
#include "jfr/utilities/jfrTypes.hpp"
+#include "jni.h"
#include "memory/allocation.hpp"
class ClassFileParser;
diff --git a/src/hotspot/share/jfr/utilities/jfrEpochQueue.inline.hpp b/src/hotspot/share/jfr/utilities/jfrEpochQueue.inline.hpp
index cc2274408ec..553d61582c0 100644
--- a/src/hotspot/share/jfr/utilities/jfrEpochQueue.inline.hpp
+++ b/src/hotspot/share/jfr/utilities/jfrEpochQueue.inline.hpp
@@ -26,6 +26,7 @@
#define SHARE_JFR_UTILITIES_JFREPOCHQUEUE_INLINE_HPP
#include "jfr/utilities/jfrEpochQueue.hpp"
+
#include "jfr/recorder/storage/jfrEpochStorage.inline.hpp"
#include "jfr/recorder/storage/jfrStorageUtils.inline.hpp"
#include "runtime/javaThread.hpp"
diff --git a/src/hotspot/share/jfr/utilities/jfrSet.hpp b/src/hotspot/share/jfr/utilities/jfrSet.hpp
index b6458d3f9a4..1432d40e4b2 100644
--- a/src/hotspot/share/jfr/utilities/jfrSet.hpp
+++ b/src/hotspot/share/jfr/utilities/jfrSet.hpp
@@ -25,8 +25,8 @@
#ifndef SHARE_JFR_UTILITIES_JFRSET_HPP
#define SHARE_JFR_UTILITIES_JFRSET_HPP
-#include "memory/allocation.hpp"
#include "jfr/utilities/jfrTypes.hpp"
+#include "memory/allocation.hpp"
template
class JfrSetConfig : public AllStatic {
diff --git a/src/hotspot/share/jfr/utilities/jfrTimeConverter.cpp b/src/hotspot/share/jfr/utilities/jfrTimeConverter.cpp
index 2ea0fd383d6..d03a15b31b5 100644
--- a/src/hotspot/share/jfr/utilities/jfrTimeConverter.cpp
+++ b/src/hotspot/share/jfr/utilities/jfrTimeConverter.cpp
@@ -22,8 +22,8 @@
*
*/
-#include "jfr/utilities/jfrTimeConverter.hpp"
#include "jfr/utilities/jfrTime.hpp"
+#include "jfr/utilities/jfrTimeConverter.hpp"
#include "runtime/os.inline.hpp"
static double ft_counter_to_nanos_factor = .0;
diff --git a/src/hotspot/share/jfr/utilities/jfrTryLock.hpp b/src/hotspot/share/jfr/utilities/jfrTryLock.hpp
index 5c76fa66321..513e550348b 100644
--- a/src/hotspot/share/jfr/utilities/jfrTryLock.hpp
+++ b/src/hotspot/share/jfr/utilities/jfrTryLock.hpp
@@ -26,8 +26,8 @@
#define SHARE_JFR_UTILITIES_JFRTRYLOCK_HPP
#include "runtime/atomic.hpp"
-#include "runtime/orderAccess.hpp"
#include "runtime/mutexLocker.hpp"
+#include "runtime/orderAccess.hpp"
#include "utilities/debug.hpp"
class JfrTryLock {
diff --git a/src/hotspot/share/jfr/writers/jfrStreamWriterHost.inline.hpp b/src/hotspot/share/jfr/writers/jfrStreamWriterHost.inline.hpp
index 72fd3485aa3..83451148c70 100644
--- a/src/hotspot/share/jfr/writers/jfrStreamWriterHost.inline.hpp
+++ b/src/hotspot/share/jfr/writers/jfrStreamWriterHost.inline.hpp
@@ -25,8 +25,9 @@
#ifndef SHARE_JFR_WRITERS_JFRSTREAMWRITERHOST_INLINE_HPP
#define SHARE_JFR_WRITERS_JFRSTREAMWRITERHOST_INLINE_HPP
-#include "jfr/jni/jfrJavaSupport.hpp"
#include "jfr/writers/jfrStreamWriterHost.hpp"
+
+#include "jfr/jni/jfrJavaSupport.hpp"
#include "runtime/os.hpp"
template
diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java
index 7460a160ee6..5d8c60e23e0 100644
--- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java
+++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java
@@ -51,6 +51,7 @@ public class TestIncludesAreSorted {
"share/code",
"share/compiler",
"share/interpreter",
+ "share/jfr",
"share/jvmci",
"share/libadt",
"share/metaprogramming",
From 2e06a917659d76fa1b4c63f38894564679209625 Mon Sep 17 00:00:00 2001
From: Dingli Zhang
Date: Thu, 21 Aug 2025 01:20:16 +0000
Subject: [PATCH 10/54] 8365841: RISC-V: Several IR verification tests fail
after JDK-8350960 without Zvfh
Reviewed-by: fyang, fjiang, mli
---
src/hotspot/cpu/riscv/riscv_v.ad | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad
index 8b5759ce11c..f2845ee2a6c 100644
--- a/src/hotspot/cpu/riscv/riscv_v.ad
+++ b/src/hotspot/cpu/riscv/riscv_v.ad
@@ -110,6 +110,7 @@ source %{
if (vlen < 4) {
return false;
}
+ break;
case Op_VectorCastHF2F:
case Op_VectorCastF2HF:
case Op_AddVHF:
From 78d50c02152d3d02953cc468d50c7c40c43c1527 Mon Sep 17 00:00:00 2001
From: Amit Kumar
Date: Thu, 21 Aug 2025 03:53:30 +0000
Subject: [PATCH 11/54] 8358756: [s390x] Test StartupOutput.java crash due to
CodeCache size
Reviewed-by: lucy, dfenacci
---
test/hotspot/jtreg/compiler/startup/StartupOutput.java | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/test/hotspot/jtreg/compiler/startup/StartupOutput.java b/test/hotspot/jtreg/compiler/startup/StartupOutput.java
index 22f2887a266..14897f7ab87 100644
--- a/test/hotspot/jtreg/compiler/startup/StartupOutput.java
+++ b/test/hotspot/jtreg/compiler/startup/StartupOutput.java
@@ -36,6 +36,7 @@
package compiler.startup;
+import jdk.test.lib.Platform;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.Utils;
@@ -60,8 +61,11 @@ public class StartupOutput {
throw new Exception("VM crashed with exit code " + exitCode);
}
+ // On s390x, generated code is ~6x larger in fastdebug and ~1.4x in release builds vs. other archs,
+ // hence we require slightly more minimum space.
+ int minInitialSize = 800 + (Platform.isS390x() ? 800 : 0);
for (int i = 0; i < 200; i++) {
- int initialCodeCacheSizeInKb = 800 + rand.nextInt(400);
+ int initialCodeCacheSizeInKb = minInitialSize + rand.nextInt(400);
int reservedCodeCacheSizeInKb = initialCodeCacheSizeInKb + rand.nextInt(200);
pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:InitialCodeCacheSize=" + initialCodeCacheSizeInKb + "K", "-XX:ReservedCodeCacheSize=" + reservedCodeCacheSizeInKb + "k", "-version");
out = new OutputAnalyzer(pb.start());
From c74c60fb8b8aa5c917fc4e1c157cc8083f5797a0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20H=C3=A4ssig?=
Date: Thu, 21 Aug 2025 07:09:25 +0000
Subject: [PATCH 12/54] 8308094: Add a compilation timeout flag to catch long
running compilations
Co-authored-by: Dean Long
Reviewed-by: dlong, chagedorn
---
.../os/linux/compilerThreadTimeout_linux.cpp | 128 ++++++++++++++++++
.../os/linux/compilerThreadTimeout_linux.hpp | 51 +++++++
src/hotspot/os/linux/globals_linux.hpp | 5 +
src/hotspot/share/compiler/compileBroker.cpp | 6 +
src/hotspot/share/compiler/compilerThread.cpp | 2 +
src/hotspot/share/compiler/compilerThread.hpp | 33 ++++-
.../arguments/TestCompileTaskTimeout.java | 56 ++++++++
.../jtreg/runtime/signal/TestSigalrm.java | 4 +-
8 files changed, 282 insertions(+), 3 deletions(-)
create mode 100644 src/hotspot/os/linux/compilerThreadTimeout_linux.cpp
create mode 100644 src/hotspot/os/linux/compilerThreadTimeout_linux.hpp
create mode 100644 test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java
diff --git a/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp b/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp
new file mode 100644
index 00000000000..609c78616f3
--- /dev/null
+++ b/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 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.
+ *
+ */
+
+#include "compiler/compilerThread.hpp"
+#include "compiler/compileTask.hpp"
+#include "compilerThreadTimeout_linux.hpp"
+#include "oops/method.hpp"
+#include "runtime/osThread.hpp"
+#include "signals_posix.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+#include
+
+#ifdef ASSERT
+void compiler_signal_handler(int signo, siginfo_t* info, void* context) {
+ CompilerThread::current()->timeout()->compiler_signal_handler(signo, info, context);
+}
+
+void CompilerThreadTimeoutLinux::compiler_signal_handler(int signo, siginfo_t* info, void* context) {
+ switch (signo) {
+ case TIMEOUT_SIGNAL: {
+ CompileTask* task = CompilerThread::current()->task();
+ const int SIZE = 512;
+ char method_name_buf[SIZE];
+ task->method()->name_and_sig_as_C_string(method_name_buf, SIZE);
+ assert(false, "compile task %d (%s) timed out after %zd ms",
+ task->compile_id(), method_name_buf, CompileTaskTimeout);
+ }
+ default: {
+ assert(false, "unexpected signal %d", signo);
+ }
+ }
+}
+#endif // ASSERT
+
+void CompilerThreadTimeoutLinux::arm() {
+#ifdef ASSERT
+ if (CompileTaskTimeout == 0) {
+ return;
+ }
+
+ const intx sec = (CompileTaskTimeout * NANOSECS_PER_MILLISEC) / NANOSECS_PER_SEC;
+ const intx nsec = (CompileTaskTimeout * NANOSECS_PER_MILLISEC) % NANOSECS_PER_SEC;
+ const struct timespec ts = {.tv_sec = sec, .tv_nsec = nsec};
+ const struct itimerspec its {.it_interval = ts, .it_value = ts};
+
+ // Start the timer.
+ timer_settime(_timer, 0, &its, nullptr);
+#endif // ASSERT
+}
+
+void CompilerThreadTimeoutLinux::disarm() {
+#ifdef ASSERT
+ if (CompileTaskTimeout == 0) {
+ return;
+ }
+
+ // Reset the timer by setting it to zero.
+ const struct itimerspec its {
+ .it_interval = {.tv_sec = 0, .tv_nsec=0},
+ .it_value = {.tv_sec = 0, .tv_nsec=0}
+ };
+ timer_settime(_timer, 0, &its, nullptr);
+#endif // ASSERT
+}
+
+bool CompilerThreadTimeoutLinux::init_timeout() {
+#ifdef ASSERT
+ if (CompileTaskTimeout == 0) {
+ return true;
+ }
+
+ JavaThread* thread = JavaThread::current();
+
+ // Create a POSIX timer sending SIGALRM to this thread only.
+ sigevent_t sev;
+ sev.sigev_value.sival_ptr = nullptr;
+ sev.sigev_signo = TIMEOUT_SIGNAL;
+ sev.sigev_notify = SIGEV_THREAD_ID;
+ #ifdef MUSL_LIBC
+ sev.sigev_notify_thread_id = thread->osthread()->thread_id();
+ #else
+ sev._sigev_un._tid = thread->osthread()->thread_id();
+ #endif // MUSL_LIBC
+ clockid_t clock;
+ int err = pthread_getcpuclockid(thread->osthread()->pthread_id(), &clock);
+ if (err != 0) {
+ return false;
+ }
+ err = timer_create(clock, &sev, &_timer);
+ if (err != 0) {
+ return false;
+ }
+
+ // Install the signal handler and check that we do not have a conflicting handler.
+ struct sigaction sigact, sigact_old;
+ err = PosixSignals::install_sigaction_signal_handler(&sigact,
+ &sigact_old,
+ TIMEOUT_SIGNAL,
+ (sa_sigaction_t)::compiler_signal_handler);
+ if (err != 0 || (sigact_old.sa_sigaction != sigact.sa_sigaction &&
+ sigact_old.sa_handler != SIG_DFL && sigact_old.sa_handler != SIG_IGN)) {
+ return false;
+ }
+#endif // ASSERT
+ return true;
+}
diff --git a/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp b/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp
new file mode 100644
index 00000000000..2dc6fa7b9c9
--- /dev/null
+++ b/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 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.
+ *
+ */
+
+#ifndef LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP
+#define LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP
+
+#include "memory/allocation.hpp"
+#include "nmt/memTag.hpp"
+#include "utilities/macros.hpp"
+
+#include
+#include
+
+class CompilerThreadTimeoutLinux : public CHeapObj {
+#ifdef ASSERT
+ public:
+ static const int TIMEOUT_SIGNAL = SIGALRM;
+ void compiler_signal_handler(int signo, siginfo_t* info, void* context);
+ private:
+ timer_t _timer;
+#endif // ASSERT
+ public:
+ CompilerThreadTimeoutLinux() DEBUG_ONLY(: _timer(nullptr)) {};
+
+ bool init_timeout();
+ void arm();
+ void disarm();
+};
+
+#endif //LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP
diff --git a/src/hotspot/os/linux/globals_linux.hpp b/src/hotspot/os/linux/globals_linux.hpp
index 542e034f59f..90e1e5e5f3f 100644
--- a/src/hotspot/os/linux/globals_linux.hpp
+++ b/src/hotspot/os/linux/globals_linux.hpp
@@ -89,6 +89,11 @@
product(bool, PrintMemoryMapAtExit, false, DIAGNOSTIC, \
"Print an annotated memory map at exit") \
\
+ develop(intx, CompileTaskTimeout, 0, \
+ "Set the timeout for compile tasks' CPU time in milliseconds."\
+ " 0 = no timeout (default)") \
+ range(0,1000000) \
+ \
// end of RUNTIME_OS_FLAGS
//
diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp
index 36663ab1088..432b0e6a346 100644
--- a/src/hotspot/share/compiler/compileBroker.cpp
+++ b/src/hotspot/share/compiler/compileBroker.cpp
@@ -218,6 +218,7 @@ CompileTaskWrapper::CompileTaskWrapper(CompileTask* task) {
CompilerThread* thread = CompilerThread::current();
thread->set_task(task);
CompileLog* log = thread->log();
+ thread->timeout()->arm();
if (log != nullptr && !task->is_unloaded()) task->log_task_start(log);
}
@@ -228,6 +229,7 @@ CompileTaskWrapper::~CompileTaskWrapper() {
if (log != nullptr && !task->is_unloaded()) task->log_task_done(log);
thread->set_task(nullptr);
thread->set_env(nullptr);
+ thread->timeout()->disarm();
if (task->is_blocking()) {
bool free_task = false;
{
@@ -1925,6 +1927,10 @@ void CompileBroker::compiler_thread_loop() {
log->end_elem();
}
+ if (!thread->init_compilation_timeout()) {
+ return;
+ }
+
// If compiler thread/runtime initialization fails, exit the compiler thread
if (!init_compiler_runtime()) {
return;
diff --git a/src/hotspot/share/compiler/compilerThread.cpp b/src/hotspot/share/compiler/compilerThread.cpp
index 4034e63bc10..7cf494aad56 100644
--- a/src/hotspot/share/compiler/compilerThread.cpp
+++ b/src/hotspot/share/compiler/compilerThread.cpp
@@ -40,6 +40,7 @@ CompilerThread::CompilerThread(CompileQueue* queue,
_can_call_java = false;
_compiler = nullptr;
_arena_stat = nullptr;
+ _timeout = nullptr;
#ifndef PRODUCT
_ideal_graph_printer = nullptr;
@@ -49,6 +50,7 @@ CompilerThread::CompilerThread(CompileQueue* queue,
CompilerThread::~CompilerThread() {
// Delete objects which were allocated on heap.
delete _counters;
+ delete _timeout;
// arenastat should have been deleted at the end of the compilation
assert(_arena_stat == nullptr, "Should be null");
}
diff --git a/src/hotspot/share/compiler/compilerThread.hpp b/src/hotspot/share/compiler/compilerThread.hpp
index e20e3017d1f..e4641780a12 100644
--- a/src/hotspot/share/compiler/compilerThread.hpp
+++ b/src/hotspot/share/compiler/compilerThread.hpp
@@ -25,7 +25,14 @@
#ifndef SHARE_COMPILER_COMPILERTHREAD_HPP
#define SHARE_COMPILER_COMPILERTHREAD_HPP
+#include "memory/allocation.hpp"
+#include "nmt/memTag.hpp"
#include "runtime/javaThread.hpp"
+#include "utilities/macros.hpp"
+
+#ifdef LINUX
+#include "compilerThreadTimeout_linux.hpp"
+#endif //LINUX
class AbstractCompiler;
class ArenaStatCounter;
@@ -38,10 +45,27 @@ class CompileQueue;
class CompilerCounters;
class IdealGraphPrinter;
+#ifndef LINUX
+class CompilerThreadTimeoutGeneric : public CHeapObj {
+ public:
+ CompilerThreadTimeoutGeneric() {};
+ void arm() {};
+ void disarm() {};
+ bool init_timeout() { return true; };
+};
+#endif // !LINUX
+
// A thread used for Compilation.
class CompilerThread : public JavaThread {
friend class VMStructs;
JVMCI_ONLY(friend class CompilerThreadCanCallJava;)
+
+#ifdef LINUX
+ typedef CompilerThreadTimeoutLinux Timeout;
+#else // LINUX
+ typedef CompilerThreadTimeoutGeneric Timeout;
+#endif // LINUX
+
private:
CompilerCounters* _counters;
@@ -57,6 +81,7 @@ class CompilerThread : public JavaThread {
ArenaStatCounter* _arena_stat;
+ Timeout* _timeout;
public:
static CompilerThread* current() {
@@ -113,7 +138,13 @@ class CompilerThread : public JavaThread {
public:
IdealGraphPrinter *ideal_graph_printer() { return _ideal_graph_printer; }
void set_ideal_graph_printer(IdealGraphPrinter *n) { _ideal_graph_printer = n; }
-#endif
+#endif // !PRODUCT
+
+ Timeout* timeout() const { return _timeout; };
+ bool init_compilation_timeout() {
+ _timeout = new Timeout();
+ return _timeout->init_timeout();
+ };
// Get/set the thread's current task
CompileTask* task() { return _task; }
diff --git a/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java b/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java
new file mode 100644
index 00000000000..42f13744cae
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 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 compiler.arguments;
+
+/*
+ * @test TestCompileTaskTimeout
+ * @bug 8308094
+ * @requires vm.debug & vm.flagless & os.name == "Linux"
+ * @summary Check functionality of CompileTaskTimeout
+ * @library /test/lib
+ * @run driver compiler.arguments.TestCompileTaskTimeout
+ */
+
+import jdk.test.lib.process.ProcessTools;
+
+public class TestCompileTaskTimeout {
+
+ public static void main(String[] args) throws Throwable {
+ ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "--version")
+ .shouldHaveExitValue(134)
+ .shouldContain("timed out after");
+
+ ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "-XX:TieredStopAtLevel=3", "--version")
+ .shouldHaveExitValue(134)
+ .shouldContain("timed out after");
+
+ ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "-XX:-TieredCompilation", "--version")
+ .shouldHaveExitValue(134)
+ .shouldContain("timed out after");
+
+ ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=200", "--version")
+ .shouldHaveExitValue(0)
+ .shouldContain("java version");
+ }
+}
\ No newline at end of file
diff --git a/test/hotspot/jtreg/runtime/signal/TestSigalrm.java b/test/hotspot/jtreg/runtime/signal/TestSigalrm.java
index b9a3c3e5060..2e485a46cf9 100644
--- a/test/hotspot/jtreg/runtime/signal/TestSigalrm.java
+++ b/test/hotspot/jtreg/runtime/signal/TestSigalrm.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 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
@@ -24,7 +24,7 @@
/*
* @test
- * @requires os.family != "windows" & os.family != "aix"
+ * @requires os.family != "windows" & os.family != "aix" & vm.flagless
*
* @summary converted from VM testbase runtime/signal/sigalrm01.
* VM testbase keywords: [signal, runtime, linux, macosx]
From a7c0f4b845c314099966f5669bfc7947bdf28004 Mon Sep 17 00:00:00 2001
From: Fredrik Bredberg
Date: Thu, 21 Aug 2025 07:47:26 +0000
Subject: [PATCH 13/54] 8365146: Remove LockingMode related code from ppc64
Reviewed-by: aboldtch, mdoerr
---
src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp | 48 +---
src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp | 76 +----
src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp | 220 ++-------------
src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 266 ------------------
src/hotspot/cpu/ppc/macroAssembler_ppc.hpp | 8 -
src/hotspot/cpu/ppc/ppc.ad | 37 +--
src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp | 21 +-
.../ppc/templateInterpreterGenerator_ppc.cpp | 2 +-
8 files changed, 50 insertions(+), 628 deletions(-)
diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp
index b548444bb48..73509c22134 100644
--- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp
@@ -228,11 +228,7 @@ int LIR_Assembler::emit_unwind_handler() {
if (method()->is_synchronized()) {
monitor_address(0, FrameMap::R4_opr);
stub = new MonitorExitStub(FrameMap::R4_opr, true, 0);
- if (LockingMode == LM_MONITOR) {
- __ b(*stub->entry());
- } else {
- __ unlock_object(R5, R6, R4, *stub->entry());
- }
+ __ unlock_object(R5, R6, R4, *stub->entry());
__ bind(*stub->continuation());
}
@@ -2618,44 +2614,20 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
// Obj may not be an oop.
if (op->code() == lir_lock) {
MonitorEnterStub* stub = (MonitorEnterStub*)op->stub();
- if (LockingMode != LM_MONITOR) {
- assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
- // Add debug info for NullPointerException only if one is possible.
- if (op->info() != nullptr) {
- if (!os::zero_page_read_protected() || !ImplicitNullChecks) {
- explicit_null_check(obj, op->info());
- } else {
- add_debug_info_for_null_check_here(op->info());
- }
- }
- __ lock_object(hdr, obj, lock, op->scratch_opr()->as_register(), *op->stub()->entry());
- } else {
- // always do slow locking
- // note: The slow locking code could be inlined here, however if we use
- // slow locking, speed doesn't matter anyway and this solution is
- // simpler and requires less duplicated code - additionally, the
- // slow locking code is the same in either case which simplifies
- // debugging.
- if (op->info() != nullptr) {
+ assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
+ // Add debug info for NullPointerException only if one is possible.
+ if (op->info() != nullptr) {
+ if (!os::zero_page_read_protected() || !ImplicitNullChecks) {
+ explicit_null_check(obj, op->info());
+ } else {
add_debug_info_for_null_check_here(op->info());
- __ null_check(obj);
}
- __ b(*op->stub()->entry());
}
+ __ lock_object(hdr, obj, lock, op->scratch_opr()->as_register(), *op->stub()->entry());
} else {
assert (op->code() == lir_unlock, "Invalid code, expected lir_unlock");
- if (LockingMode != LM_MONITOR) {
- assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
- __ unlock_object(hdr, obj, lock, *op->stub()->entry());
- } else {
- // always do slow unlocking
- // note: The slow unlocking code could be inlined here, however if we use
- // slow unlocking, speed doesn't matter anyway and this solution is
- // simpler and requires less duplicated code - additionally, the
- // slow unlocking code is the same in either case which simplifies
- // debugging.
- __ b(*op->stub()->entry());
- }
+ assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
+ __ unlock_object(hdr, obj, lock, *op->stub()->entry());
}
__ bind(*op->stub()->continuation());
}
diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp
index 23050bff453..04af473c99b 100644
--- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp
@@ -82,59 +82,13 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox
// Save object being locked into the BasicObjectLock...
std(Roop, in_bytes(BasicObjectLock::obj_offset()), Rbox);
- if (LockingMode == LM_LIGHTWEIGHT) {
- lightweight_lock(Rbox, Roop, Rmark, Rscratch, slow_int);
- } else if (LockingMode == LM_LEGACY) {
-
- if (DiagnoseSyncOnValueBasedClasses != 0) {
- load_klass(Rscratch, Roop);
- lbz(Rscratch, in_bytes(Klass::misc_flags_offset()), Rscratch);
- testbitdi(CR0, R0, Rscratch, exact_log2(KlassFlags::_misc_is_value_based_class));
- bne(CR0, slow_int);
- }
-
- // ... and mark it unlocked.
- ori(Rmark, Rmark, markWord::unlocked_value);
-
- // Save unlocked object header into the displaced header location on the stack.
- std(Rmark, BasicLock::displaced_header_offset_in_bytes(), Rbox);
-
- // Compare object markWord with Rmark and if equal exchange Rscratch with object markWord.
- assert(oopDesc::mark_offset_in_bytes() == 0, "cas must take a zero displacement");
- cmpxchgd(/*flag=*/CR0,
- /*current_value=*/Rscratch,
- /*compare_value=*/Rmark,
- /*exchange_value=*/Rbox,
- /*where=*/Roop/*+0==mark_offset_in_bytes*/,
- MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq,
- MacroAssembler::cmpxchgx_hint_acquire_lock(),
- noreg,
- &cas_failed,
- /*check without membar and ldarx first*/true);
- // If compare/exchange succeeded we found an unlocked object and we now have locked it
- // hence we are done.
- } else {
- assert(false, "Unhandled LockingMode:%d", LockingMode);
- }
+ lightweight_lock(Rbox, Roop, Rmark, Rscratch, slow_int);
b(done);
bind(slow_int);
b(slow_case); // far
- if (LockingMode == LM_LEGACY) {
- bind(cas_failed);
- // We did not find an unlocked object so see if this is a recursive case.
- sub(Rscratch, Rscratch, R1_SP);
- load_const_optimized(R0, (~(os::vm_page_size()-1) | markWord::lock_mask_in_place));
- and_(R0/*==0?*/, Rscratch, R0);
- std(R0/*==0, perhaps*/, BasicLock::displaced_header_offset_in_bytes(), Rbox);
- bne(CR0, slow_int);
- }
-
bind(done);
- if (LockingMode == LM_LEGACY) {
- inc_held_monitor_count(Rmark /*tmp*/);
- }
}
@@ -146,43 +100,17 @@ void C1_MacroAssembler::unlock_object(Register Rmark, Register Roop, Register Rb
Address mark_addr(Roop, oopDesc::mark_offset_in_bytes());
assert(mark_addr.disp() == 0, "cas must take a zero displacement");
- if (LockingMode != LM_LIGHTWEIGHT) {
- // Test first if it is a fast recursive unlock.
- ld(Rmark, BasicLock::displaced_header_offset_in_bytes(), Rbox);
- cmpdi(CR0, Rmark, 0);
- beq(CR0, done);
- }
-
// Load object.
ld(Roop, in_bytes(BasicObjectLock::obj_offset()), Rbox);
verify_oop(Roop, FILE_AND_LINE);
- if (LockingMode == LM_LIGHTWEIGHT) {
- lightweight_unlock(Roop, Rmark, slow_int);
- } else if (LockingMode == LM_LEGACY) {
- // Check if it is still a light weight lock, this is is true if we see
- // the stack address of the basicLock in the markWord of the object.
- cmpxchgd(/*flag=*/CR0,
- /*current_value=*/R0,
- /*compare_value=*/Rbox,
- /*exchange_value=*/Rmark,
- /*where=*/Roop,
- MacroAssembler::MemBarRel,
- MacroAssembler::cmpxchgx_hint_release_lock(),
- noreg,
- &slow_int);
- } else {
- assert(false, "Unhandled LockingMode:%d", LockingMode);
- }
+ lightweight_unlock(Roop, Rmark, slow_int);
b(done);
bind(slow_int);
b(slow_case); // far
// Done
bind(done);
- if (LockingMode == LM_LEGACY) {
- dec_held_monitor_count(Rmark /*tmp*/);
- }
}
diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp
index 29fb54250c2..8df2cc5d273 100644
--- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp
+++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp
@@ -946,121 +946,20 @@ void InterpreterMacroAssembler::leave_jfr_critical_section() {
// object - Address of the object to be locked.
//
void InterpreterMacroAssembler::lock_object(Register monitor, Register object) {
- if (LockingMode == LM_MONITOR) {
- call_VM_preemptable(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor);
- } else {
- // template code (for LM_LEGACY):
- //
- // markWord displaced_header = obj->mark().set_unlocked();
- // monitor->lock()->set_displaced_header(displaced_header);
- // if (Atomic::cmpxchg(/*addr*/obj->mark_addr(), /*cmp*/displaced_header, /*ex=*/monitor) == displaced_header) {
- // // We stored the monitor address into the object's mark word.
- // } else if (THREAD->is_lock_owned((address)displaced_header))
- // // Simple recursive case.
- // monitor->lock()->set_displaced_header(nullptr);
- // } else {
- // // Slow path.
- // InterpreterRuntime::monitorenter(THREAD, monitor);
- // }
+ const Register header = R7_ARG5;
+ const Register tmp = R8_ARG6;
- const Register header = R7_ARG5;
- const Register object_mark_addr = R8_ARG6;
- const Register current_header = R9_ARG7;
- const Register tmp = R10_ARG8;
+ Label done, slow_case;
- Label count_locking, done, slow_case, cas_failed;
+ assert_different_registers(header, tmp);
- assert_different_registers(header, object_mark_addr, current_header, tmp);
+ lightweight_lock(monitor, object, header, tmp, slow_case);
+ b(done);
- // markWord displaced_header = obj->mark().set_unlocked();
+ bind(slow_case);
+ call_VM_preemptable(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor);
- if (LockingMode == LM_LIGHTWEIGHT) {
- lightweight_lock(monitor, object, header, tmp, slow_case);
- b(done);
- } else if (LockingMode == LM_LEGACY) {
-
- if (DiagnoseSyncOnValueBasedClasses != 0) {
- load_klass(tmp, object);
- lbz(tmp, in_bytes(Klass::misc_flags_offset()), tmp);
- testbitdi(CR0, R0, tmp, exact_log2(KlassFlags::_misc_is_value_based_class));
- bne(CR0, slow_case);
- }
-
- // Load markWord from object into header.
- ld(header, oopDesc::mark_offset_in_bytes(), object);
-
- // Set displaced_header to be (markWord of object | UNLOCK_VALUE).
- ori(header, header, markWord::unlocked_value);
-
- // monitor->lock()->set_displaced_header(displaced_header);
- const int lock_offset = in_bytes(BasicObjectLock::lock_offset());
- const int mark_offset = lock_offset +
- BasicLock::displaced_header_offset_in_bytes();
-
- // Initialize the box (Must happen before we update the object mark!).
- std(header, mark_offset, monitor);
-
- // if (Atomic::cmpxchg(/*addr*/obj->mark_addr(), /*cmp*/displaced_header, /*ex=*/monitor) == displaced_header) {
-
- // Store stack address of the BasicObjectLock (this is monitor) into object.
- addi(object_mark_addr, object, oopDesc::mark_offset_in_bytes());
-
- // Must fence, otherwise, preceding store(s) may float below cmpxchg.
- // CmpxchgX sets CR0 to cmpX(current, displaced).
- cmpxchgd(/*flag=*/CR0,
- /*current_value=*/current_header,
- /*compare_value=*/header, /*exchange_value=*/monitor,
- /*where=*/object_mark_addr,
- MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq,
- MacroAssembler::cmpxchgx_hint_acquire_lock(),
- noreg,
- &cas_failed,
- /*check without membar and ldarx first*/true);
-
- // If the compare-and-exchange succeeded, then we found an unlocked
- // object and we have now locked it.
- b(count_locking);
- bind(cas_failed);
-
- // } else if (THREAD->is_lock_owned((address)displaced_header))
- // // Simple recursive case.
- // monitor->lock()->set_displaced_header(nullptr);
-
- // We did not see an unlocked object so try the fast recursive case.
-
- // Check if owner is self by comparing the value in the markWord of object
- // (current_header) with the stack pointer.
- sub(current_header, current_header, R1_SP);
-
- assert(os::vm_page_size() > 0xfff, "page size too small - change the constant");
- load_const_optimized(tmp, ~(os::vm_page_size()-1) | markWord::lock_mask_in_place);
-
- and_(R0/*==0?*/, current_header, tmp);
- // If condition is true we are done and hence we can store 0 in the displaced
- // header indicating it is a recursive lock.
- bne(CR0, slow_case);
- std(R0/*==0!*/, mark_offset, monitor);
- b(count_locking);
- }
-
- // } else {
- // // Slow path.
- // InterpreterRuntime::monitorenter(THREAD, monitor);
-
- // None of the above fast optimizations worked so we have to get into the
- // slow case of monitor enter.
- bind(slow_case);
- call_VM_preemptable(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor);
- // }
-
- if (LockingMode == LM_LEGACY) {
- b(done);
- align(32, 12);
- bind(count_locking);
- inc_held_monitor_count(current_header /*tmp*/);
- }
- bind(done);
- }
+ bind(done);
}
// Unlocks an object. Used in monitorexit bytecode and remove_activation.
@@ -1071,95 +970,34 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) {
//
// Throw IllegalMonitorException if object is not locked by current thread.
void InterpreterMacroAssembler::unlock_object(Register monitor) {
- if (LockingMode == LM_MONITOR) {
- call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), monitor);
- } else {
+ const Register object = R7_ARG5;
+ const Register header = R8_ARG6;
+ const Register current_header = R10_ARG8;
- // template code (for LM_LEGACY):
- //
- // if ((displaced_header = monitor->displaced_header()) == nullptr) {
- // // Recursive unlock. Mark the monitor unlocked by setting the object field to null.
- // monitor->set_obj(nullptr);
- // } else if (Atomic::cmpxchg(obj->mark_addr(), monitor, displaced_header) == monitor) {
- // // We swapped the unlocked mark in displaced_header into the object's mark word.
- // monitor->set_obj(nullptr);
- // } else {
- // // Slow path.
- // InterpreterRuntime::monitorexit(monitor);
- // }
+ Label free_slot;
+ Label slow_case;
- const Register object = R7_ARG5;
- const Register header = R8_ARG6;
- const Register object_mark_addr = R9_ARG7;
- const Register current_header = R10_ARG8;
+ assert_different_registers(object, header, current_header);
- Label free_slot;
- Label slow_case;
+ // The object address from the monitor is in object.
+ ld(object, in_bytes(BasicObjectLock::obj_offset()), monitor);
- assert_different_registers(object, header, object_mark_addr, current_header);
+ lightweight_unlock(object, header, slow_case);
- if (LockingMode != LM_LIGHTWEIGHT) {
- // Test first if we are in the fast recursive case.
- ld(header, in_bytes(BasicObjectLock::lock_offset()) +
- BasicLock::displaced_header_offset_in_bytes(), monitor);
+ b(free_slot);
- // If the displaced header is zero, we have a recursive unlock.
- cmpdi(CR0, header, 0);
- beq(CR0, free_slot); // recursive unlock
- }
+ bind(slow_case);
+ call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), monitor);
- // } else if (Atomic::cmpxchg(obj->mark_addr(), monitor, displaced_header) == monitor) {
- // // We swapped the unlocked mark in displaced_header into the object's mark word.
- // monitor->set_obj(nullptr);
+ Label done;
+ b(done); // Monitor register may be overwritten! Runtime has already freed the slot.
- // If we still have a lightweight lock, unlock the object and be done.
-
- // The object address from the monitor is in object.
- ld(object, in_bytes(BasicObjectLock::obj_offset()), monitor);
-
- if (LockingMode == LM_LIGHTWEIGHT) {
- lightweight_unlock(object, header, slow_case);
- } else {
- addi(object_mark_addr, object, oopDesc::mark_offset_in_bytes());
-
- // We have the displaced header in displaced_header. If the lock is still
- // lightweight, it will contain the monitor address and we'll store the
- // displaced header back into the object's mark word.
- // CmpxchgX sets CR0 to cmpX(current, monitor).
- cmpxchgd(/*flag=*/CR0,
- /*current_value=*/current_header,
- /*compare_value=*/monitor, /*exchange_value=*/header,
- /*where=*/object_mark_addr,
- MacroAssembler::MemBarRel,
- MacroAssembler::cmpxchgx_hint_release_lock(),
- noreg,
- &slow_case);
- }
- b(free_slot);
-
- // } else {
- // // Slow path.
- // InterpreterRuntime::monitorexit(monitor);
-
- // The lock has been converted into a heavy lock and hence
- // we need to get into the slow case.
- bind(slow_case);
- call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), monitor);
- // }
-
- Label done;
- b(done); // Monitor register may be overwritten! Runtime has already freed the slot.
-
- // Exchange worked, do monitor->set_obj(nullptr);
- align(32, 12);
- bind(free_slot);
- li(R0, 0);
- std(R0, in_bytes(BasicObjectLock::obj_offset()), monitor);
- if (LockingMode == LM_LEGACY) {
- dec_held_monitor_count(current_header /*tmp*/);
- }
- bind(done);
- }
+ // Do monitor->set_obj(nullptr);
+ align(32, 12);
+ bind(free_slot);
+ li(R0, 0);
+ std(R0, in_bytes(BasicObjectLock::obj_offset()), monitor);
+ bind(done);
}
// Load compiled (i2c) or interpreter entry when calling from interpreted and
diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp
index 396a50427f8..00a46504e14 100644
--- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp
@@ -2671,238 +2671,6 @@ address MacroAssembler::emit_trampoline_stub(int destination_toc_offset,
}
// "The box" is the space on the stack where we copy the object mark.
-void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register oop, Register box,
- Register temp, Register displaced_header, Register current_header) {
- assert(LockingMode != LM_LIGHTWEIGHT, "uses fast_lock_lightweight");
- assert_different_registers(oop, box, temp, displaced_header, current_header);
- Label object_has_monitor;
- Label cas_failed;
- Label success, failure;
-
- // Load markWord from object into displaced_header.
- ld(displaced_header, oopDesc::mark_offset_in_bytes(), oop);
-
- if (DiagnoseSyncOnValueBasedClasses != 0) {
- load_klass(temp, oop);
- lbz(temp, in_bytes(Klass::misc_flags_offset()), temp);
- testbitdi(flag, R0, temp, exact_log2(KlassFlags::_misc_is_value_based_class));
- bne(flag, failure);
- }
-
- // Handle existing monitor.
- // The object has an existing monitor iff (mark & monitor_value) != 0.
- andi_(temp, displaced_header, markWord::monitor_value);
- bne(CR0, object_has_monitor);
-
- if (LockingMode == LM_MONITOR) {
- // Set NE to indicate 'failure' -> take slow-path.
- crandc(flag, Assembler::equal, flag, Assembler::equal);
- b(failure);
- } else {
- assert(LockingMode == LM_LEGACY, "must be");
- // Set displaced_header to be (markWord of object | UNLOCK_VALUE).
- ori(displaced_header, displaced_header, markWord::unlocked_value);
-
- // Load Compare Value application register.
-
- // Initialize the box. (Must happen before we update the object mark!)
- std(displaced_header, BasicLock::displaced_header_offset_in_bytes(), box);
-
- // Must fence, otherwise, preceding store(s) may float below cmpxchg.
- // Compare object markWord with mark and if equal exchange scratch1 with object markWord.
- cmpxchgd(/*flag=*/flag,
- /*current_value=*/current_header,
- /*compare_value=*/displaced_header,
- /*exchange_value=*/box,
- /*where=*/oop,
- MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq,
- MacroAssembler::cmpxchgx_hint_acquire_lock(),
- noreg,
- &cas_failed,
- /*check without membar and ldarx first*/true);
- assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0");
- // If the compare-and-exchange succeeded, then we found an unlocked
- // object and we have now locked it.
- b(success);
-
- bind(cas_failed);
- // We did not see an unlocked object so try the fast recursive case.
-
- // Check if the owner is self by comparing the value in the markWord of object
- // (current_header) with the stack pointer.
- sub(current_header, current_header, R1_SP);
- load_const_optimized(temp, ~(os::vm_page_size()-1) | markWord::lock_mask_in_place);
-
- and_(R0/*==0?*/, current_header, temp);
- // If condition is true we are cont and hence we can store 0 as the
- // displaced header in the box, which indicates that it is a recursive lock.
- std(R0/*==0, perhaps*/, BasicLock::displaced_header_offset_in_bytes(), box);
-
- if (flag != CR0) {
- mcrf(flag, CR0);
- }
- beq(CR0, success);
- b(failure);
- }
-
- // Handle existing monitor.
- bind(object_has_monitor);
-
- // Try to CAS owner (no owner => current thread's _monitor_owner_id).
- addi(temp, displaced_header, in_bytes(ObjectMonitor::owner_offset()) - markWord::monitor_value);
- Register thread_id = displaced_header;
- ld(thread_id, in_bytes(JavaThread::monitor_owner_id_offset()), R16_thread);
- cmpxchgd(/*flag=*/flag,
- /*current_value=*/current_header,
- /*compare_value=*/(intptr_t)0,
- /*exchange_value=*/thread_id,
- /*where=*/temp,
- MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq,
- MacroAssembler::cmpxchgx_hint_acquire_lock());
-
- // Store a non-null value into the box.
- std(box, BasicLock::displaced_header_offset_in_bytes(), box);
- beq(flag, success);
-
- // Check for recursive locking.
- cmpd(flag, current_header, thread_id);
- bne(flag, failure);
-
- // Current thread already owns the lock. Just increment recursions.
- Register recursions = displaced_header;
- ld(recursions, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), temp);
- addi(recursions, recursions, 1);
- std(recursions, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), temp);
-
- // flag == EQ indicates success, increment held monitor count if LM_LEGACY is enabled
- // flag == NE indicates failure
- bind(success);
- if (LockingMode == LM_LEGACY) {
- inc_held_monitor_count(temp);
- }
-#ifdef ASSERT
- // Check that unlocked label is reached with flag == EQ.
- Label flag_correct;
- beq(flag, flag_correct);
- stop("compiler_fast_lock_object: Flag != EQ");
-#endif
- bind(failure);
-#ifdef ASSERT
- // Check that slow_path label is reached with flag == NE.
- bne(flag, flag_correct);
- stop("compiler_fast_lock_object: Flag != NE");
- bind(flag_correct);
-#endif
-}
-
-void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Register oop, Register box,
- Register temp, Register displaced_header, Register current_header) {
- assert(LockingMode != LM_LIGHTWEIGHT, "uses fast_unlock_lightweight");
- assert_different_registers(oop, box, temp, displaced_header, current_header);
- Label success, failure, object_has_monitor, not_recursive;
-
- if (LockingMode == LM_LEGACY) {
- // Find the lock address and load the displaced header from the stack.
- ld(displaced_header, BasicLock::displaced_header_offset_in_bytes(), box);
-
- // If the displaced header is 0, we have a recursive unlock.
- cmpdi(flag, displaced_header, 0);
- beq(flag, success);
- }
-
- // Handle existing monitor.
- // The object has an existing monitor iff (mark & monitor_value) != 0.
- ld(current_header, oopDesc::mark_offset_in_bytes(), oop);
- andi_(R0, current_header, markWord::monitor_value);
- bne(CR0, object_has_monitor);
-
- if (LockingMode == LM_MONITOR) {
- // Set NE to indicate 'failure' -> take slow-path.
- crandc(flag, Assembler::equal, flag, Assembler::equal);
- b(failure);
- } else {
- assert(LockingMode == LM_LEGACY, "must be");
- // Check if it is still a light weight lock, this is is true if we see
- // the stack address of the basicLock in the markWord of the object.
- // Cmpxchg sets flag to cmpd(current_header, box).
- cmpxchgd(/*flag=*/flag,
- /*current_value=*/current_header,
- /*compare_value=*/box,
- /*exchange_value=*/displaced_header,
- /*where=*/oop,
- MacroAssembler::MemBarRel,
- MacroAssembler::cmpxchgx_hint_release_lock(),
- noreg,
- &failure);
- assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0");
- b(success);
- }
-
- // Handle existing monitor.
- bind(object_has_monitor);
- STATIC_ASSERT(markWord::monitor_value <= INT_MAX);
- addi(current_header, current_header, -(int)markWord::monitor_value); // monitor
-
- ld(displaced_header, in_bytes(ObjectMonitor::recursions_offset()), current_header);
- addic_(displaced_header, displaced_header, -1);
- blt(CR0, not_recursive); // Not recursive if negative after decrement.
-
- // Recursive unlock
- std(displaced_header, in_bytes(ObjectMonitor::recursions_offset()), current_header);
- if (flag == CR0) { // Otherwise, flag is already EQ, here.
- crorc(CR0, Assembler::equal, CR0, Assembler::equal); // Set CR0 EQ
- }
- b(success);
-
- bind(not_recursive);
-
- // Set owner to null.
- // Release to satisfy the JMM
- release();
- li(temp, 0);
- std(temp, in_bytes(ObjectMonitor::owner_offset()), current_header);
- // We need a full fence after clearing owner to avoid stranding.
- // StoreLoad achieves this.
- membar(StoreLoad);
-
- // Check if the entry_list is empty.
- ld(temp, in_bytes(ObjectMonitor::entry_list_offset()), current_header);
- cmpdi(flag, temp, 0);
- beq(flag, success); // If so we are done.
-
- // Check if there is a successor.
- ld(temp, in_bytes(ObjectMonitor::succ_offset()), current_header);
- cmpdi(flag, temp, 0);
- // Invert equal bit
- crnand(flag, Assembler::equal, flag, Assembler::equal);
- beq(flag, success); // If there is a successor we are done.
-
- // Save the monitor pointer in the current thread, so we can try
- // to reacquire the lock in SharedRuntime::monitor_exit_helper().
- std(current_header, in_bytes(JavaThread::unlocked_inflated_monitor_offset()), R16_thread);
- b(failure); // flag == NE
-
- // flag == EQ indicates success, decrement held monitor count if LM_LEGACY is enabled
- // flag == NE indicates failure
- bind(success);
- if (LockingMode == LM_LEGACY) {
- dec_held_monitor_count(temp);
- }
-#ifdef ASSERT
- // Check that unlocked label is reached with flag == EQ.
- Label flag_correct;
- beq(flag, flag_correct);
- stop("compiler_fast_unlock_object: Flag != EQ");
-#endif
- bind(failure);
-#ifdef ASSERT
- // Check that slow_path label is reached with flag == NE.
- bne(flag, flag_correct);
- stop("compiler_fast_unlock_object: Flag != NE");
- bind(flag_correct);
-#endif
-}
-
void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister flag, Register obj, Register box,
Register tmp1, Register tmp2, Register tmp3) {
assert_different_registers(obj, box, tmp1, tmp2, tmp3);
@@ -4769,38 +4537,6 @@ void MacroAssembler::pop_cont_fastpath() {
bind(done);
}
-// Note: Must preserve CR0 EQ (invariant).
-void MacroAssembler::inc_held_monitor_count(Register tmp) {
- assert(LockingMode == LM_LEGACY, "");
- ld(tmp, in_bytes(JavaThread::held_monitor_count_offset()), R16_thread);
-#ifdef ASSERT
- Label ok;
- cmpdi(CR0, tmp, 0);
- bge_predict_taken(CR0, ok);
- stop("held monitor count is negativ at increment");
- bind(ok);
- crorc(CR0, Assembler::equal, CR0, Assembler::equal); // Restore CR0 EQ
-#endif
- addi(tmp, tmp, 1);
- std(tmp, in_bytes(JavaThread::held_monitor_count_offset()), R16_thread);
-}
-
-// Note: Must preserve CR0 EQ (invariant).
-void MacroAssembler::dec_held_monitor_count(Register tmp) {
- assert(LockingMode == LM_LEGACY, "");
- ld(tmp, in_bytes(JavaThread::held_monitor_count_offset()), R16_thread);
-#ifdef ASSERT
- Label ok;
- cmpdi(CR0, tmp, 0);
- bgt_predict_taken(CR0, ok);
- stop("held monitor count is <= 0 at decrement");
- bind(ok);
- crorc(CR0, Assembler::equal, CR0, Assembler::equal); // Restore CR0 EQ
-#endif
- addi(tmp, tmp, -1);
- std(tmp, in_bytes(JavaThread::held_monitor_count_offset()), R16_thread);
-}
-
// Function to flip between unlocked and locked state (fast locking).
// Branches to failed if the state is not as expected with CR0 NE.
// Falls through upon success with CR0 EQ.
@@ -4842,7 +4578,6 @@ void MacroAssembler::atomically_flip_locked_state(bool is_unlock, Register obj,
// - obj: the object to be locked
// - t1, t2: temporary register
void MacroAssembler::lightweight_lock(Register box, Register obj, Register t1, Register t2, Label& slow) {
- assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking");
assert_different_registers(box, obj, t1, t2, R0);
Label push;
@@ -4899,7 +4634,6 @@ void MacroAssembler::lightweight_lock(Register box, Register obj, Register t1, R
// - obj: the object to be unlocked
// - t1: temporary register
void MacroAssembler::lightweight_unlock(Register obj, Register t1, Label& slow) {
- assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking");
assert_different_registers(obj, t1);
#ifdef ASSERT
diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp
index 471ebb7459a..63be608094f 100644
--- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp
+++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp
@@ -697,8 +697,6 @@ class MacroAssembler: public Assembler {
void push_cont_fastpath();
void pop_cont_fastpath();
- void inc_held_monitor_count(Register tmp);
- void dec_held_monitor_count(Register tmp);
void atomically_flip_locked_state(bool is_unlock, Register obj, Register tmp, Label& failed, int semantics);
void lightweight_lock(Register box, Register obj, Register t1, Register t2, Label& slow);
void lightweight_unlock(Register obj, Register t1, Label& slow);
@@ -715,12 +713,6 @@ class MacroAssembler: public Assembler {
enum { trampoline_stub_size = 6 * 4 };
address emit_trampoline_stub(int destination_toc_offset, int insts_call_instruction_offset, Register Rtoc = noreg);
- void compiler_fast_lock_object(ConditionRegister flag, Register oop, Register box,
- Register tmp1, Register tmp2, Register tmp3);
-
- void compiler_fast_unlock_object(ConditionRegister flag, Register oop, Register box,
- Register tmp1, Register tmp2, Register tmp3);
-
void compiler_fast_lock_lightweight_object(ConditionRegister flag, Register oop, Register box,
Register tmp1, Register tmp2, Register tmp3);
diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad
index bf43ecaba79..cd71e298b7d 100644
--- a/src/hotspot/cpu/ppc/ppc.ad
+++ b/src/hotspot/cpu/ppc/ppc.ad
@@ -11573,40 +11573,8 @@ instruct partialSubtypeCheckConstSuper(rarg3RegP sub, rarg2RegP super_reg, immP
// inlined locking and unlocking
-instruct cmpFastLock(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2) %{
- predicate(LockingMode != LM_LIGHTWEIGHT);
- match(Set crx (FastLock oop box));
- effect(TEMP tmp1, TEMP tmp2);
-
- format %{ "FASTLOCK $oop, $box, $tmp1, $tmp2" %}
- ins_encode %{
- __ compiler_fast_lock_object($crx$$CondRegister, $oop$$Register, $box$$Register,
- $tmp1$$Register, $tmp2$$Register, /*tmp3*/ R0);
- // If locking was successful, crx should indicate 'EQ'.
- // The compiler generates a branch to the runtime call to
- // _complete_monitor_locking_Java for the case where crx is 'NE'.
- %}
- ins_pipe(pipe_class_compare);
-%}
-
-instruct cmpFastUnlock(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3) %{
- predicate(LockingMode != LM_LIGHTWEIGHT);
- match(Set crx (FastUnlock oop box));
- effect(TEMP tmp1, TEMP tmp2, TEMP tmp3);
-
- format %{ "FASTUNLOCK $oop, $box, $tmp1, $tmp2" %}
- ins_encode %{
- __ compiler_fast_unlock_object($crx$$CondRegister, $oop$$Register, $box$$Register,
- $tmp1$$Register, $tmp2$$Register, $tmp3$$Register);
- // If unlocking was successful, crx should indicate 'EQ'.
- // The compiler generates a branch to the runtime call to
- // _complete_monitor_unlocking_Java for the case where crx is 'NE'.
- %}
- ins_pipe(pipe_class_compare);
-%}
-
instruct cmpFastLockLightweight(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2) %{
- predicate(LockingMode == LM_LIGHTWEIGHT && !UseObjectMonitorTable);
+ predicate(!UseObjectMonitorTable);
match(Set crx (FastLock oop box));
effect(TEMP tmp1, TEMP tmp2);
@@ -11622,7 +11590,7 @@ instruct cmpFastLockLightweight(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRe
%}
instruct cmpFastLockMonitorTable(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3, flagsRegCR1 cr1) %{
- predicate(LockingMode == LM_LIGHTWEIGHT && UseObjectMonitorTable);
+ predicate(UseObjectMonitorTable);
match(Set crx (FastLock oop box));
effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr1);
@@ -11638,7 +11606,6 @@ instruct cmpFastLockMonitorTable(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iR
%}
instruct cmpFastUnlockLightweight(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3) %{
- predicate(LockingMode == LM_LIGHTWEIGHT);
match(Set crx (FastUnlock oop box));
effect(TEMP tmp1, TEMP tmp2, TEMP tmp3);
diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp
index 64bd8dc7812..2a9bad059ba 100644
--- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp
+++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp
@@ -2446,14 +2446,9 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
__ addi(r_box, R1_SP, lock_offset);
// Try fastpath for locking.
- if (LockingMode == LM_LIGHTWEIGHT) {
- // fast_lock kills r_temp_1, r_temp_2, r_temp_3.
- Register r_temp_3_or_noreg = UseObjectMonitorTable ? r_temp_3 : noreg;
- __ compiler_fast_lock_lightweight_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3_or_noreg);
- } else {
- // fast_lock kills r_temp_1, r_temp_2, r_temp_3.
- __ compiler_fast_lock_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3);
- }
+ // fast_lock kills r_temp_1, r_temp_2, r_temp_3.
+ Register r_temp_3_or_noreg = UseObjectMonitorTable ? r_temp_3 : noreg;
+ __ compiler_fast_lock_lightweight_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3_or_noreg);
__ beq(CR0, locked);
// None of the above fast optimizations worked so we have to get into the
@@ -2620,7 +2615,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
__ stw(R0, thread_(thread_state));
// Check preemption for Object.wait()
- if (LockingMode != LM_LEGACY && method->is_object_wait0()) {
+ if (method->is_object_wait0()) {
Label not_preempted;
__ ld(R0, in_bytes(JavaThread::preempt_alternate_return_offset()), R16_thread);
__ cmpdi(CR0, R0, 0);
@@ -2672,11 +2667,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
__ addi(r_box, R1_SP, lock_offset);
// Try fastpath for unlocking.
- if (LockingMode == LM_LIGHTWEIGHT) {
- __ compiler_fast_unlock_lightweight_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3);
- } else {
- __ compiler_fast_unlock_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3);
- }
+ __ compiler_fast_unlock_lightweight_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3);
__ beq(CR0, done);
// Save and restore any potential method result value around the unlocking operation.
@@ -2717,7 +2708,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
// --------------------------------------------------------------------------
// Last java frame won't be set if we're resuming after preemption
- bool maybe_preempted = LockingMode != LM_LEGACY && method->is_object_wait0();
+ bool maybe_preempted = method->is_object_wait0();
__ reset_last_Java_frame(!maybe_preempted /* check_last_java_sp */);
// Unbox oop result, e.g. JNIHandles::resolve value.
diff --git a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp
index b5f1c76c5da..199b578a36f 100644
--- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp
+++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp
@@ -1362,7 +1362,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
// convenient and the slow signature handler can use this same frame
// anchor.
- bool support_vthread_preemption = Continuations::enabled() && LockingMode != LM_LEGACY;
+ bool support_vthread_preemption = Continuations::enabled();
// We have a TOP_IJAVA_FRAME here, which belongs to us.
Label last_java_pc;
From 5febc4e3bb1f47f69fc28c266a775e19cbac9e5f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20H=C3=A4ssig?=
Date: Thu, 21 Aug 2025 08:23:32 +0000
Subject: [PATCH 14/54] 8365910: [BACKOUT] Add a compilation timeout flag to
catch long running compilations
Reviewed-by: chagedorn, dholmes
---
.../os/linux/compilerThreadTimeout_linux.cpp | 128 ------------------
.../os/linux/compilerThreadTimeout_linux.hpp | 51 -------
src/hotspot/os/linux/globals_linux.hpp | 5 -
src/hotspot/share/compiler/compileBroker.cpp | 6 -
src/hotspot/share/compiler/compilerThread.cpp | 2 -
src/hotspot/share/compiler/compilerThread.hpp | 33 +----
.../arguments/TestCompileTaskTimeout.java | 56 --------
.../jtreg/runtime/signal/TestSigalrm.java | 4 +-
8 files changed, 3 insertions(+), 282 deletions(-)
delete mode 100644 src/hotspot/os/linux/compilerThreadTimeout_linux.cpp
delete mode 100644 src/hotspot/os/linux/compilerThreadTimeout_linux.hpp
delete mode 100644 test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java
diff --git a/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp b/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp
deleted file mode 100644
index 609c78616f3..00000000000
--- a/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (c) 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.
- *
- */
-
-#include "compiler/compilerThread.hpp"
-#include "compiler/compileTask.hpp"
-#include "compilerThreadTimeout_linux.hpp"
-#include "oops/method.hpp"
-#include "runtime/osThread.hpp"
-#include "signals_posix.hpp"
-#include "utilities/globalDefinitions.hpp"
-
-#include
-
-#ifdef ASSERT
-void compiler_signal_handler(int signo, siginfo_t* info, void* context) {
- CompilerThread::current()->timeout()->compiler_signal_handler(signo, info, context);
-}
-
-void CompilerThreadTimeoutLinux::compiler_signal_handler(int signo, siginfo_t* info, void* context) {
- switch (signo) {
- case TIMEOUT_SIGNAL: {
- CompileTask* task = CompilerThread::current()->task();
- const int SIZE = 512;
- char method_name_buf[SIZE];
- task->method()->name_and_sig_as_C_string(method_name_buf, SIZE);
- assert(false, "compile task %d (%s) timed out after %zd ms",
- task->compile_id(), method_name_buf, CompileTaskTimeout);
- }
- default: {
- assert(false, "unexpected signal %d", signo);
- }
- }
-}
-#endif // ASSERT
-
-void CompilerThreadTimeoutLinux::arm() {
-#ifdef ASSERT
- if (CompileTaskTimeout == 0) {
- return;
- }
-
- const intx sec = (CompileTaskTimeout * NANOSECS_PER_MILLISEC) / NANOSECS_PER_SEC;
- const intx nsec = (CompileTaskTimeout * NANOSECS_PER_MILLISEC) % NANOSECS_PER_SEC;
- const struct timespec ts = {.tv_sec = sec, .tv_nsec = nsec};
- const struct itimerspec its {.it_interval = ts, .it_value = ts};
-
- // Start the timer.
- timer_settime(_timer, 0, &its, nullptr);
-#endif // ASSERT
-}
-
-void CompilerThreadTimeoutLinux::disarm() {
-#ifdef ASSERT
- if (CompileTaskTimeout == 0) {
- return;
- }
-
- // Reset the timer by setting it to zero.
- const struct itimerspec its {
- .it_interval = {.tv_sec = 0, .tv_nsec=0},
- .it_value = {.tv_sec = 0, .tv_nsec=0}
- };
- timer_settime(_timer, 0, &its, nullptr);
-#endif // ASSERT
-}
-
-bool CompilerThreadTimeoutLinux::init_timeout() {
-#ifdef ASSERT
- if (CompileTaskTimeout == 0) {
- return true;
- }
-
- JavaThread* thread = JavaThread::current();
-
- // Create a POSIX timer sending SIGALRM to this thread only.
- sigevent_t sev;
- sev.sigev_value.sival_ptr = nullptr;
- sev.sigev_signo = TIMEOUT_SIGNAL;
- sev.sigev_notify = SIGEV_THREAD_ID;
- #ifdef MUSL_LIBC
- sev.sigev_notify_thread_id = thread->osthread()->thread_id();
- #else
- sev._sigev_un._tid = thread->osthread()->thread_id();
- #endif // MUSL_LIBC
- clockid_t clock;
- int err = pthread_getcpuclockid(thread->osthread()->pthread_id(), &clock);
- if (err != 0) {
- return false;
- }
- err = timer_create(clock, &sev, &_timer);
- if (err != 0) {
- return false;
- }
-
- // Install the signal handler and check that we do not have a conflicting handler.
- struct sigaction sigact, sigact_old;
- err = PosixSignals::install_sigaction_signal_handler(&sigact,
- &sigact_old,
- TIMEOUT_SIGNAL,
- (sa_sigaction_t)::compiler_signal_handler);
- if (err != 0 || (sigact_old.sa_sigaction != sigact.sa_sigaction &&
- sigact_old.sa_handler != SIG_DFL && sigact_old.sa_handler != SIG_IGN)) {
- return false;
- }
-#endif // ASSERT
- return true;
-}
diff --git a/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp b/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp
deleted file mode 100644
index 2dc6fa7b9c9..00000000000
--- a/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 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.
- *
- */
-
-#ifndef LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP
-#define LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP
-
-#include "memory/allocation.hpp"
-#include "nmt/memTag.hpp"
-#include "utilities/macros.hpp"
-
-#include
-#include
-
-class CompilerThreadTimeoutLinux : public CHeapObj {
-#ifdef ASSERT
- public:
- static const int TIMEOUT_SIGNAL = SIGALRM;
- void compiler_signal_handler(int signo, siginfo_t* info, void* context);
- private:
- timer_t _timer;
-#endif // ASSERT
- public:
- CompilerThreadTimeoutLinux() DEBUG_ONLY(: _timer(nullptr)) {};
-
- bool init_timeout();
- void arm();
- void disarm();
-};
-
-#endif //LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP
diff --git a/src/hotspot/os/linux/globals_linux.hpp b/src/hotspot/os/linux/globals_linux.hpp
index 90e1e5e5f3f..542e034f59f 100644
--- a/src/hotspot/os/linux/globals_linux.hpp
+++ b/src/hotspot/os/linux/globals_linux.hpp
@@ -89,11 +89,6 @@
product(bool, PrintMemoryMapAtExit, false, DIAGNOSTIC, \
"Print an annotated memory map at exit") \
\
- develop(intx, CompileTaskTimeout, 0, \
- "Set the timeout for compile tasks' CPU time in milliseconds."\
- " 0 = no timeout (default)") \
- range(0,1000000) \
- \
// end of RUNTIME_OS_FLAGS
//
diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp
index 432b0e6a346..36663ab1088 100644
--- a/src/hotspot/share/compiler/compileBroker.cpp
+++ b/src/hotspot/share/compiler/compileBroker.cpp
@@ -218,7 +218,6 @@ CompileTaskWrapper::CompileTaskWrapper(CompileTask* task) {
CompilerThread* thread = CompilerThread::current();
thread->set_task(task);
CompileLog* log = thread->log();
- thread->timeout()->arm();
if (log != nullptr && !task->is_unloaded()) task->log_task_start(log);
}
@@ -229,7 +228,6 @@ CompileTaskWrapper::~CompileTaskWrapper() {
if (log != nullptr && !task->is_unloaded()) task->log_task_done(log);
thread->set_task(nullptr);
thread->set_env(nullptr);
- thread->timeout()->disarm();
if (task->is_blocking()) {
bool free_task = false;
{
@@ -1927,10 +1925,6 @@ void CompileBroker::compiler_thread_loop() {
log->end_elem();
}
- if (!thread->init_compilation_timeout()) {
- return;
- }
-
// If compiler thread/runtime initialization fails, exit the compiler thread
if (!init_compiler_runtime()) {
return;
diff --git a/src/hotspot/share/compiler/compilerThread.cpp b/src/hotspot/share/compiler/compilerThread.cpp
index 7cf494aad56..4034e63bc10 100644
--- a/src/hotspot/share/compiler/compilerThread.cpp
+++ b/src/hotspot/share/compiler/compilerThread.cpp
@@ -40,7 +40,6 @@ CompilerThread::CompilerThread(CompileQueue* queue,
_can_call_java = false;
_compiler = nullptr;
_arena_stat = nullptr;
- _timeout = nullptr;
#ifndef PRODUCT
_ideal_graph_printer = nullptr;
@@ -50,7 +49,6 @@ CompilerThread::CompilerThread(CompileQueue* queue,
CompilerThread::~CompilerThread() {
// Delete objects which were allocated on heap.
delete _counters;
- delete _timeout;
// arenastat should have been deleted at the end of the compilation
assert(_arena_stat == nullptr, "Should be null");
}
diff --git a/src/hotspot/share/compiler/compilerThread.hpp b/src/hotspot/share/compiler/compilerThread.hpp
index e4641780a12..e20e3017d1f 100644
--- a/src/hotspot/share/compiler/compilerThread.hpp
+++ b/src/hotspot/share/compiler/compilerThread.hpp
@@ -25,14 +25,7 @@
#ifndef SHARE_COMPILER_COMPILERTHREAD_HPP
#define SHARE_COMPILER_COMPILERTHREAD_HPP
-#include "memory/allocation.hpp"
-#include "nmt/memTag.hpp"
#include "runtime/javaThread.hpp"
-#include "utilities/macros.hpp"
-
-#ifdef LINUX
-#include "compilerThreadTimeout_linux.hpp"
-#endif //LINUX
class AbstractCompiler;
class ArenaStatCounter;
@@ -45,27 +38,10 @@ class CompileQueue;
class CompilerCounters;
class IdealGraphPrinter;
-#ifndef LINUX
-class CompilerThreadTimeoutGeneric : public CHeapObj {
- public:
- CompilerThreadTimeoutGeneric() {};
- void arm() {};
- void disarm() {};
- bool init_timeout() { return true; };
-};
-#endif // !LINUX
-
// A thread used for Compilation.
class CompilerThread : public JavaThread {
friend class VMStructs;
JVMCI_ONLY(friend class CompilerThreadCanCallJava;)
-
-#ifdef LINUX
- typedef CompilerThreadTimeoutLinux Timeout;
-#else // LINUX
- typedef CompilerThreadTimeoutGeneric Timeout;
-#endif // LINUX
-
private:
CompilerCounters* _counters;
@@ -81,7 +57,6 @@ class CompilerThread : public JavaThread {
ArenaStatCounter* _arena_stat;
- Timeout* _timeout;
public:
static CompilerThread* current() {
@@ -138,13 +113,7 @@ class CompilerThread : public JavaThread {
public:
IdealGraphPrinter *ideal_graph_printer() { return _ideal_graph_printer; }
void set_ideal_graph_printer(IdealGraphPrinter *n) { _ideal_graph_printer = n; }
-#endif // !PRODUCT
-
- Timeout* timeout() const { return _timeout; };
- bool init_compilation_timeout() {
- _timeout = new Timeout();
- return _timeout->init_timeout();
- };
+#endif
// Get/set the thread's current task
CompileTask* task() { return _task; }
diff --git a/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java b/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java
deleted file mode 100644
index 42f13744cae..00000000000
--- a/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 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 compiler.arguments;
-
-/*
- * @test TestCompileTaskTimeout
- * @bug 8308094
- * @requires vm.debug & vm.flagless & os.name == "Linux"
- * @summary Check functionality of CompileTaskTimeout
- * @library /test/lib
- * @run driver compiler.arguments.TestCompileTaskTimeout
- */
-
-import jdk.test.lib.process.ProcessTools;
-
-public class TestCompileTaskTimeout {
-
- public static void main(String[] args) throws Throwable {
- ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "--version")
- .shouldHaveExitValue(134)
- .shouldContain("timed out after");
-
- ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "-XX:TieredStopAtLevel=3", "--version")
- .shouldHaveExitValue(134)
- .shouldContain("timed out after");
-
- ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "-XX:-TieredCompilation", "--version")
- .shouldHaveExitValue(134)
- .shouldContain("timed out after");
-
- ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=200", "--version")
- .shouldHaveExitValue(0)
- .shouldContain("java version");
- }
-}
\ No newline at end of file
diff --git a/test/hotspot/jtreg/runtime/signal/TestSigalrm.java b/test/hotspot/jtreg/runtime/signal/TestSigalrm.java
index 2e485a46cf9..b9a3c3e5060 100644
--- a/test/hotspot/jtreg/runtime/signal/TestSigalrm.java
+++ b/test/hotspot/jtreg/runtime/signal/TestSigalrm.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2020, 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
@@ -24,7 +24,7 @@
/*
* @test
- * @requires os.family != "windows" & os.family != "aix" & vm.flagless
+ * @requires os.family != "windows" & os.family != "aix"
*
* @summary converted from VM testbase runtime/signal/sigalrm01.
* VM testbase keywords: [signal, runtime, linux, macosx]
From 5ede5b47d4291a18acc16833978ded038332cf9c Mon Sep 17 00:00:00 2001
From: Thomas Schatzl
Date: Thu, 21 Aug 2025 09:18:58 +0000
Subject: [PATCH 15/54] 8364650: G1: Use InvalidCSetIndex instead of UINT_MAX
for "invalid" sentinel value of young_index_in_cset
Reviewed-by: ayang, iwalulya
---
src/hotspot/share/gc/g1/g1HeapRegion.cpp | 2 +-
src/hotspot/share/gc/g1/g1HeapRegion.hpp | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.cpp b/src/hotspot/share/gc/g1/g1HeapRegion.cpp
index 03610ab520b..86b22486517 100644
--- a/src/hotspot/share/gc/g1/g1HeapRegion.cpp
+++ b/src/hotspot/share/gc/g1/g1HeapRegion.cpp
@@ -245,7 +245,7 @@ G1HeapRegion::G1HeapRegion(uint hrm_index,
_parsable_bottom(nullptr),
_garbage_bytes(0),
_incoming_refs(0),
- _young_index_in_cset(-1),
+ _young_index_in_cset(InvalidCSetIndex),
_surv_rate_group(nullptr),
_age_index(G1SurvRateGroup::InvalidAgeIndex),
_node_index(G1NUMA::UnknownNodeIndex),
diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.hpp
index 1962d3173b7..7d49633d0bc 100644
--- a/src/hotspot/share/gc/g1/g1HeapRegion.hpp
+++ b/src/hotspot/share/gc/g1/g1HeapRegion.hpp
@@ -496,10 +496,10 @@ public:
void set_index_in_opt_cset(uint index) { _index_in_opt_cset = index; }
void clear_index_in_opt_cset() { _index_in_opt_cset = InvalidCSetIndex; }
- uint young_index_in_cset() const { return _young_index_in_cset; }
+ uint young_index_in_cset() const { return _young_index_in_cset; }
void clear_young_index_in_cset() { _young_index_in_cset = 0; }
void set_young_index_in_cset(uint index) {
- assert(index != UINT_MAX, "just checking");
+ assert(index != InvalidCSetIndex, "just checking");
assert(index != 0, "just checking");
assert(is_young(), "pre-condition");
_young_index_in_cset = index;
From b735ef99b2285ec55a68896de25d29a02fdfcaf7 Mon Sep 17 00:00:00 2001
From: Thomas Schatzl
Date: Thu, 21 Aug 2025 09:19:14 +0000
Subject: [PATCH 16/54] 8364925: G1: Improve program flow around incremental
collection set building
Reviewed-by: ayang, iwalulya
---
src/hotspot/share/gc/g1/g1CollectionSet.cpp | 43 +++++++++++++++------
src/hotspot/share/gc/g1/g1CollectionSet.hpp | 16 +++-----
2 files changed, 36 insertions(+), 23 deletions(-)
diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp
index 075951ab07c..747f5664b55 100644
--- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp
+++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp
@@ -38,6 +38,15 @@
#include "utilities/globalDefinitions.hpp"
#include "utilities/quickSort.hpp"
+uint G1CollectionSet::selected_groups_cur_length() const {
+ assert(_inc_build_state == CSetBuildType::Inactive, "must be");
+ return _collection_set_groups.length();
+}
+
+uint G1CollectionSet::collection_groups_increment_length() const {
+ return selected_groups_cur_length() - _selected_groups_inc_part_start;
+}
+
G1CollectorState* G1CollectionSet::collector_state() const {
return _g1h->collector_state();
}
@@ -54,7 +63,6 @@ G1CollectionSet::G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy) :
_collection_set_cur_length(0),
_collection_set_max_length(0),
_collection_set_groups(),
- _selected_groups_cur_length(0),
_selected_groups_inc_part_start(0),
_eden_region_length(0),
_survivor_region_length(0),
@@ -122,9 +130,23 @@ void G1CollectionSet::add_old_region(G1HeapRegion* hr) {
void G1CollectionSet::start_incremental_building() {
assert(_collection_set_cur_length == 0, "Collection set must be empty before starting a new collection set.");
+ assert(selected_groups_cur_length() == 0, "Collection set groups must be empty before starting a new collection set.");
+ assert(_optional_groups.length() == 0, "Collection set optional gorups must be empty before starting a new collection set.");
+
+ continue_incremental_building();
+}
+
+void G1CollectionSet::continue_incremental_building() {
assert(_inc_build_state == Inactive, "Precondition");
- update_incremental_marker();
+ _inc_part_start = _collection_set_cur_length;
+ _selected_groups_inc_part_start = selected_groups_cur_length();
+
+ _inc_build_state = CSetBuildType::Active;
+}
+
+void G1CollectionSet::stop_incremental_building() {
+ _inc_build_state = Inactive;
}
void G1CollectionSet::finalize_incremental_building() {
@@ -343,9 +365,6 @@ static int compare_region_idx(const uint a, const uint b) {
void G1CollectionSet::finalize_old_part(double time_remaining_ms) {
double non_young_start_time_sec = os::elapsedTime();
- _selected_groups_cur_length = 0;
- _selected_groups_inc_part_start = 0;
-
if (!candidates()->is_empty()) {
candidates()->verify();
@@ -363,13 +382,8 @@ void G1CollectionSet::finalize_old_part(double time_remaining_ms) {
log_debug(gc, ergo, cset)("No candidates to reclaim.");
}
- _selected_groups_cur_length = collection_set_groups()->length();
- stop_incremental_building();
-
double non_young_end_time_sec = os::elapsedTime();
phase_times()->record_non_young_cset_choice_time_ms((non_young_end_time_sec - non_young_start_time_sec) * 1000.0);
-
- QuickSort::sort(_collection_set_regions, _collection_set_cur_length, compare_region_idx);
}
static void print_finish_message(const char* reason, bool from_marking) {
@@ -670,16 +684,21 @@ void G1CollectionSet::add_region_to_collection_set(G1HeapRegion* r) {
}
void G1CollectionSet::finalize_initial_collection_set(double target_pause_time_ms, G1SurvivorRegions* survivor) {
+ assert(_inc_part_start == 0, "must be");
+ assert(_selected_groups_inc_part_start == 0, "must be");
+
double time_remaining_ms = finalize_young_part(target_pause_time_ms, survivor);
finalize_old_part(time_remaining_ms);
+
+ stop_incremental_building();
+ QuickSort::sort(_collection_set_regions, _collection_set_cur_length, compare_region_idx);
}
bool G1CollectionSet::finalize_optional_for_evacuation(double remaining_pause_time) {
- update_incremental_marker();
+ continue_incremental_building();
uint num_regions_selected = select_optional_collection_set_regions(remaining_pause_time);
- _selected_groups_cur_length = collection_set_groups()->length();
stop_incremental_building();
_g1h->verify_region_attr_remset_is_tracked();
diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.hpp
index c703e13a056..963b43d2432 100644
--- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp
+++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp
@@ -149,9 +149,7 @@ class G1CollectionSet {
// Old gen groups selected for evacuation.
G1CSetCandidateGroupList _collection_set_groups;
- // Groups are added to the collection set in increments when performing optional evacuations.
- // We use the value below to track these increments.
- uint _selected_groups_cur_length;
+ uint selected_groups_cur_length() const;
uint _selected_groups_inc_part_start;
uint _eden_region_length;
@@ -258,14 +256,10 @@ public:
// Initialize incremental collection set info.
void start_incremental_building();
- // Start a new collection set increment.
- void update_incremental_marker() {
- _inc_build_state = Active;
- _inc_part_start = _collection_set_cur_length;
- _selected_groups_inc_part_start = _selected_groups_cur_length;
- }
+ // Start a new collection set increment, continuing the incremental building.
+ void continue_incremental_building();
// Stop adding regions to the current collection set increment.
- void stop_incremental_building() { _inc_build_state = Inactive; }
+ void stop_incremental_building();
// Iterate over the current collection set increment applying the given G1HeapRegionClosure
// from a starting position determined by the given worker id.
@@ -276,7 +270,7 @@ public:
// Returns the length of the whole current collection set in number of regions
size_t cur_length() const { return _collection_set_cur_length; }
- uint collection_groups_increment_length() const { return _selected_groups_cur_length - _selected_groups_inc_part_start; }
+ uint collection_groups_increment_length() const;
// Iterate over the entire collection set (all increments calculated so far), applying
// the given G1HeapRegionClosure on all of them.
From 9439d7630901d3e29141adf46bbe9284b86683f4 Mon Sep 17 00:00:00 2001
From: Thomas Schatzl
Date: Thu, 21 Aug 2025 09:35:57 +0000
Subject: [PATCH 17/54] 8364532: G1: In liveness tracing, print more
significant digits for the liveness value
Reviewed-by: ayang, iwalulya
---
src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp | 5 ++---
src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp | 2 +-
src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 5 +++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp
index 6c13c015eff..63b1d29f535 100644
--- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp
+++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp
@@ -63,10 +63,9 @@ void G1CSetCandidateGroup::calculate_efficiency() {
_gc_efficiency = _reclaimable_bytes / predict_group_total_time_ms();
}
-size_t G1CSetCandidateGroup::liveness() const {
+double G1CSetCandidateGroup::liveness_percent() const {
size_t capacity = length() * G1HeapRegion::GrainBytes;
-
- return (size_t) ceil(((capacity - _reclaimable_bytes) * 100.0) / capacity);
+ return ((capacity - _reclaimable_bytes) * 100.0) / capacity;
}
void G1CSetCandidateGroup::clear(bool uninstall_group_cardset) {
diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp
index 73421d40ee9..d45fe07cd6e 100644
--- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp
+++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp
@@ -102,7 +102,7 @@ public:
void calculate_efficiency();
- size_t liveness() const;
+ double liveness_percent() const;
// Comparison function to order regions in decreasing GC efficiency order. This
// will cause regions with a lot of live objects and large remembered sets to end
// up at the end of the list.
diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
index c5b8c89e2f0..210d78098b3 100644
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
@@ -2981,6 +2981,7 @@ G1CMTask::G1CMTask(uint worker_id,
#define G1PPRL_LEN_FORMAT " " UINT32_FORMAT_W(14)
#define G1PPRL_LEN_H_FORMAT " %14s"
#define G1PPRL_GID_GCEFF_FORMAT " %14.1f"
+#define G1PPRL_GID_LIVENESS_FORMAT " %9.2f"
// For summary info
#define G1PPRL_SUM_ADDR_FORMAT(tag) " " tag ":" G1PPRL_ADDR_BASE_FORMAT
@@ -3114,13 +3115,13 @@ void G1PrintRegionLivenessInfoClosure::log_cset_candidate_group_add_total(G1CSet
G1PPRL_GID_FORMAT
G1PPRL_LEN_FORMAT
G1PPRL_GID_GCEFF_FORMAT
- G1PPRL_BYTE_FORMAT
+ G1PPRL_GID_LIVENESS_FORMAT
G1PPRL_BYTE_FORMAT
G1PPRL_TYPE_H_FORMAT,
group->group_id(),
group->length(),
group->gc_efficiency(),
- group->liveness(),
+ group->liveness_percent(),
group->card_set()->mem_size(),
type);
_total_remset_bytes += group->card_set()->mem_size();
From f0e706698df5ac199198b252d77d27a05abad1da Mon Sep 17 00:00:00 2001
From: Thomas Schatzl
Date: Thu, 21 Aug 2025 09:36:16 +0000
Subject: [PATCH 18/54] 8364414: G1: Use simpler data structure for holding
collection set candidates during calculation
Reviewed-by: ayang, iwalulya
---
.../share/gc/g1/g1CollectionSetCandidates.cpp | 52 ++++------------
.../share/gc/g1/g1CollectionSetCandidates.hpp | 9 +--
.../share/gc/g1/g1CollectionSetChooser.cpp | 60 +++++++++++++------
.../share/gc/g1/g1CollectionSetChooser.hpp | 2 +-
4 files changed, 57 insertions(+), 66 deletions(-)
diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp
index 63b1d29f535..2118bf997a7 100644
--- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp
+++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp
@@ -44,12 +44,7 @@ G1CSetCandidateGroup::G1CSetCandidateGroup() :
void G1CSetCandidateGroup::add(G1HeapRegion* hr) {
G1CollectionSetCandidateInfo c(hr);
- add(c);
-}
-
-void G1CSetCandidateGroup::add(G1CollectionSetCandidateInfo& hr_info) {
- G1HeapRegion* hr = hr_info._r;
- _candidates.append(hr_info);
+ _candidates.append(c);
hr->install_cset_group(this);
}
@@ -133,31 +128,6 @@ int G1CSetCandidateGroup::compare_gc_efficiency(G1CSetCandidateGroup** gr1, G1CS
}
}
-int G1CollectionSetCandidateInfo::compare_region_gc_efficiency(G1CollectionSetCandidateInfo* ci1, G1CollectionSetCandidateInfo* ci2) {
- // Make sure that null entries are moved to the end.
- if (ci1->_r == nullptr) {
- if (ci2->_r == nullptr) {
- return 0;
- } else {
- return 1;
- }
- } else if (ci2->_r == nullptr) {
- return -1;
- }
-
- G1Policy* p = G1CollectedHeap::heap()->policy();
- double gc_efficiency1 = p->predict_gc_efficiency(ci1->_r);
- double gc_efficiency2 = p->predict_gc_efficiency(ci2->_r);
-
- if (gc_efficiency1 > gc_efficiency2) {
- return -1;
- } else if (gc_efficiency1 < gc_efficiency2) {
- return 1;
- } else {
- return 0;
- }
-}
-
G1CSetCandidateGroupList::G1CSetCandidateGroupList() : _groups(8, mtGC), _num_regions(0) { }
void G1CSetCandidateGroupList::append(G1CSetCandidateGroup* group) {
@@ -279,9 +249,9 @@ void G1CollectionSetCandidates::sort_marking_by_efficiency() {
_from_marking_groups.verify();
}
-void G1CollectionSetCandidates::set_candidates_from_marking(G1CollectionSetCandidateInfo* candidate_infos,
- uint num_infos) {
- if (num_infos == 0) {
+void G1CollectionSetCandidates::set_candidates_from_marking(G1HeapRegion** candidates,
+ uint num_candidates) {
+ if (num_candidates == 0) {
log_debug(gc, ergo, cset) ("No regions selected from marking.");
return;
}
@@ -294,7 +264,7 @@ void G1CollectionSetCandidates::set_candidates_from_marking(G1CollectionSetCandi
// the G1MixedGCCountTarget. For the first collection in a Mixed GC cycle, we can add all regions
// required to meet this threshold to the same remset group. We are certain these will be collected in
// the same MixedGC.
- uint group_limit = p->calc_min_old_cset_length(num_infos);
+ uint group_limit = p->calc_min_old_cset_length(num_candidates);
uint num_added_to_group = 0;
@@ -303,8 +273,8 @@ void G1CollectionSetCandidates::set_candidates_from_marking(G1CollectionSetCandi
current = new G1CSetCandidateGroup();
- for (uint i = 0; i < num_infos; i++) {
- G1HeapRegion* r = candidate_infos[i]._r;
+ for (uint i = 0; i < num_candidates; i++) {
+ G1HeapRegion* r = candidates[i];
assert(!contains(r), "must not contain region %u", r->hrm_index());
_contains_map[r->hrm_index()] = CandidateOrigin::Marking;
@@ -318,16 +288,16 @@ void G1CollectionSetCandidates::set_candidates_from_marking(G1CollectionSetCandi
current = new G1CSetCandidateGroup();
num_added_to_group = 0;
}
- current->add(candidate_infos[i]);
+ current->add(r);
num_added_to_group++;
}
_from_marking_groups.append(current);
- assert(_from_marking_groups.num_regions() == num_infos, "Must be!");
+ assert(_from_marking_groups.num_regions() == num_candidates, "Must be!");
- log_debug(gc, ergo, cset) ("Finished creating %u collection groups from %u regions", _from_marking_groups.length(), num_infos);
- _last_marking_candidates_length = num_infos;
+ log_debug(gc, ergo, cset) ("Finished creating %u collection groups from %u regions", _from_marking_groups.length(), num_candidates);
+ _last_marking_candidates_length = num_candidates;
verify();
}
diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp
index d45fe07cd6e..02a4d5f6d76 100644
--- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp
+++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp
@@ -48,8 +48,6 @@ struct G1CollectionSetCandidateInfo {
++_num_unreclaimed;
return _num_unreclaimed < G1NumCollectionsKeepPinned;
}
-
- static int compare_region_gc_efficiency(G1CollectionSetCandidateInfo* ci1, G1CollectionSetCandidateInfo* ci2);
};
using G1CSetCandidateGroupIterator = GrowableArrayIterator;
@@ -91,7 +89,6 @@ public:
}
void add(G1HeapRegion* hr);
- void add(G1CollectionSetCandidateInfo& hr_info);
uint length() const { return (uint)_candidates.length(); }
@@ -235,10 +232,10 @@ public:
void clear();
- // Merge collection set candidates from marking into the current marking list
+ // Merge collection set candidates from marking into the current marking candidates
// (which needs to be empty).
- void set_candidates_from_marking(G1CollectionSetCandidateInfo* candidate_infos,
- uint num_infos);
+ void set_candidates_from_marking(G1HeapRegion** candidates,
+ uint num_candidates);
// The most recent length of the list that had been merged last via
// set_candidates_from_marking(). Used for calculating minimum collection set
// regions.
diff --git a/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp b/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp
index 20d6b125b4d..aa4bd3f1e5b 100644
--- a/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp
+++ b/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp
@@ -31,15 +31,13 @@
#include "utilities/quickSort.hpp"
// Determine collection set candidates (from marking): For all regions determine
-// whether they should be a collection set candidate, calculate their efficiency,
-// sort and put them into the candidates.
+// whether they should be a collection set candidate. Calculate their efficiency,
+// sort, and put them into the collection set candidates.
+//
// Threads calculate the GC efficiency of the regions they get to process, and
// put them into some work area without sorting. At the end that array is sorted and
// moved to the destination.
class G1BuildCandidateRegionsTask : public WorkerTask {
-
- using CandidateInfo = G1CollectionSetCandidateInfo;
-
// Work area for building the set of collection set candidates. Contains references
// to heap regions with their GC efficiencies calculated. To reduce contention
// on claiming array elements, worker threads claim parts of this array in chunks;
@@ -47,14 +45,40 @@ class G1BuildCandidateRegionsTask : public WorkerTask {
// up their chunks completely.
// Final sorting will remove them.
class G1BuildCandidateArray : public StackObj {
-
uint const _max_size;
uint const _chunk_size;
- CandidateInfo* _data;
+ G1HeapRegion** _data;
uint volatile _cur_claim_idx;
+ static int compare_region_gc_efficiency(G1HeapRegion** rr1, G1HeapRegion** rr2) {
+ G1HeapRegion* r1 = *rr1;
+ G1HeapRegion* r2 = *rr2;
+ // Make sure that null entries are moved to the end.
+ if (r1 == nullptr) {
+ if (r2 == nullptr) {
+ return 0;
+ } else {
+ return 1;
+ }
+ } else if (r2 == nullptr) {
+ return -1;
+ }
+
+ G1Policy* p = G1CollectedHeap::heap()->policy();
+ double gc_efficiency1 = p->predict_gc_efficiency(r1);
+ double gc_efficiency2 = p->predict_gc_efficiency(r2);
+
+ if (gc_efficiency1 > gc_efficiency2) {
+ return -1;
+ } else if (gc_efficiency1 < gc_efficiency2) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
// Calculates the maximum array size that will be used.
static uint required_array_size(uint num_regions, uint chunk_size, uint num_workers) {
uint const max_waste = num_workers * chunk_size;
@@ -68,15 +92,15 @@ class G1BuildCandidateRegionsTask : public WorkerTask {
G1BuildCandidateArray(uint max_num_regions, uint chunk_size, uint num_workers) :
_max_size(required_array_size(max_num_regions, chunk_size, num_workers)),
_chunk_size(chunk_size),
- _data(NEW_C_HEAP_ARRAY(CandidateInfo, _max_size, mtGC)),
+ _data(NEW_C_HEAP_ARRAY(G1HeapRegion*, _max_size, mtGC)),
_cur_claim_idx(0) {
for (uint i = 0; i < _max_size; i++) {
- _data[i] = CandidateInfo();
+ _data[i] = nullptr;
}
}
~G1BuildCandidateArray() {
- FREE_C_HEAP_ARRAY(CandidateInfo, _data);
+ FREE_C_HEAP_ARRAY(G1HeapRegion*, _data);
}
// Claim a new chunk, returning its bounds [from, to[.
@@ -92,8 +116,8 @@ class G1BuildCandidateRegionsTask : public WorkerTask {
// Set element in array.
void set(uint idx, G1HeapRegion* hr) {
assert(idx < _max_size, "Index %u out of bounds %u", idx, _max_size);
- assert(_data[idx]._r == nullptr, "Value must not have been set.");
- _data[idx] = CandidateInfo(hr);
+ assert(_data[idx] == nullptr, "Value must not have been set.");
+ _data[idx] = hr;
}
void sort_by_gc_efficiency() {
@@ -101,15 +125,15 @@ class G1BuildCandidateRegionsTask : public WorkerTask {
return;
}
for (uint i = _cur_claim_idx; i < _max_size; i++) {
- assert(_data[i]._r == nullptr, "must be");
+ assert(_data[i] == nullptr, "must be");
}
- qsort(_data, _cur_claim_idx, sizeof(_data[0]), (_sort_Fn)G1CollectionSetCandidateInfo::compare_region_gc_efficiency);
+ qsort(_data, _cur_claim_idx, sizeof(_data[0]), (_sort_Fn)compare_region_gc_efficiency);
for (uint i = _cur_claim_idx; i < _max_size; i++) {
- assert(_data[i]._r == nullptr, "must be");
+ assert(_data[i] == nullptr, "must be");
}
}
- CandidateInfo* array() const { return _data; }
+ G1HeapRegion** array() const { return _data; }
};
// Per-region closure. In addition to determining whether a region should be
@@ -193,7 +217,7 @@ class G1BuildCandidateRegionsTask : public WorkerTask {
// available (for forward progress in evacuation) or the waste accumulated by the
// removed regions is above the maximum allowed waste.
// Updates number of candidates and reclaimable bytes given.
- void prune(CandidateInfo* data) {
+ void prune(G1HeapRegion** data) {
G1Policy* p = G1CollectedHeap::heap()->policy();
uint num_candidates = Atomic::load(&_num_regions_added);
@@ -211,7 +235,7 @@ class G1BuildCandidateRegionsTask : public WorkerTask {
uint max_to_prune = num_candidates - min_old_cset_length;
while (true) {
- G1HeapRegion* r = data[num_candidates - num_pruned - 1]._r;
+ G1HeapRegion* r = data[num_candidates - num_pruned - 1];
size_t const reclaimable = r->reclaimable_bytes();
if (num_pruned >= max_to_prune ||
wasted_bytes + reclaimable > allowed_waste) {
diff --git a/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp b/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp
index 691017b9d87..cb9727b3413 100644
--- a/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp
+++ b/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp
@@ -38,11 +38,11 @@ class WorkerThreads;
class G1CollectionSetChooser : public AllStatic {
static uint calculate_work_chunk_size(uint num_workers, uint num_regions);
-public:
static size_t mixed_gc_live_threshold_bytes() {
return G1HeapRegion::GrainBytes * (size_t)G1MixedGCLiveThresholdPercent / 100;
}
+public:
static bool region_occupancy_low_enough_for_evac(size_t live_bytes) {
return live_bytes < mixed_gc_live_threshold_bytes();
}
From ed260e8cae329a0c077e91ff76d104ee197fb7fd Mon Sep 17 00:00:00 2001
From: Thomas Schatzl
Date: Thu, 21 Aug 2025 09:37:34 +0000
Subject: [PATCH 19/54] 8365026: G1: Initialization should start a "full" new
collection set
Reviewed-by: ayang, kbarrett
---
src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 2 ++
src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 3 ++-
src/hotspot/share/gc/g1/g1Policy.cpp | 4 ----
3 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
index e964ecefb18..ed08d43bbbe 100644
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
@@ -1487,6 +1487,8 @@ jint G1CollectedHeap::initialize() {
_collection_set.initialize(max_num_regions());
+ start_new_collection_set();
+
allocation_failure_injector()->reset();
CPUTimeCounters::create_counter(CPUTimeGroups::CPUTimeType::gc_parallel_workers);
diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
index 210d78098b3..237704c12a8 100644
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
@@ -1962,7 +1962,8 @@ public:
};
void G1ConcurrentMark::verify_no_collection_set_oops() {
- assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint");
+ assert(SafepointSynchronize::is_at_safepoint() || !is_init_completed(),
+ "should be at a safepoint or initializing");
if (!_g1h->collector_state()->mark_or_rebuild_in_progress()) {
return;
}
diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp
index bb54d344ca0..53f0a7bf7a6 100644
--- a/src/hotspot/share/gc/g1/g1Policy.cpp
+++ b/src/hotspot/share/gc/g1/g1Policy.cpp
@@ -97,10 +97,6 @@ void G1Policy::init(G1CollectedHeap* g1h, G1CollectionSet* collection_set) {
_free_regions_at_end_of_collection = _g1h->num_free_regions();
update_young_length_bounds();
-
- // We immediately start allocating regions placing them in the collection set.
- // Initialize the collection set info.
- _collection_set->start_incremental_building();
}
void G1Policy::record_young_gc_pause_start() {
From f61b247fe3a818fc60a61c6f42a676ad94e8e976 Mon Sep 17 00:00:00 2001
From: Thomas Schatzl
Date: Thu, 21 Aug 2025 09:44:41 +0000
Subject: [PATCH 20/54] 8364962: G1: Inline
G1CollectionSet::finalize_incremental_building
Reviewed-by: ayang, kbarrett
---
src/hotspot/share/gc/g1/g1CollectionSet.cpp | 10 +++-------
src/hotspot/share/gc/g1/g1CollectionSet.hpp | 3 ---
2 files changed, 3 insertions(+), 10 deletions(-)
diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp
index 747f5664b55..90189cfdf8a 100644
--- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp
+++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp
@@ -149,11 +149,6 @@ void G1CollectionSet::stop_incremental_building() {
_inc_build_state = Inactive;
}
-void G1CollectionSet::finalize_incremental_building() {
- assert(_inc_build_state == Active, "Precondition");
- assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint");
-}
-
void G1CollectionSet::clear() {
assert_at_safepoint_on_vm_thread();
_collection_set_cur_length = 0;
@@ -306,9 +301,10 @@ void G1CollectionSet::print(outputStream* st) {
// pinned by JNI) to allow faster future evacuation. We already "paid" for this work
// when sizing the young generation.
double G1CollectionSet::finalize_young_part(double target_pause_time_ms, G1SurvivorRegions* survivors) {
- Ticks start_time = Ticks::now();
+ assert(_inc_build_state == Active, "Precondition");
+ assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint");
- finalize_incremental_building();
+ Ticks start_time = Ticks::now();
guarantee(target_pause_time_ms > 0.0,
"target_pause_time_ms = %1.6lf should be positive", target_pause_time_ms);
diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.hpp
index 963b43d2432..e12f3a82d12 100644
--- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp
+++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp
@@ -198,9 +198,6 @@ class G1CollectionSet {
// as Eden and calculate a prediction on how long the evacuation of all young regions
// will take.
double finalize_young_part(double target_pause_time_ms, G1SurvivorRegions* survivors);
- // Perform any final calculations on the incremental collection set fields before we
- // can use them.
- void finalize_incremental_building();
// Select the regions comprising the initial and optional collection set from marking
// and retained collection set candidates.
From a3fd4248b74ed800ff124cc3e7c259dca36ea446 Mon Sep 17 00:00:00 2001
From: Thomas Schatzl
Date: Thu, 21 Aug 2025 09:46:02 +0000
Subject: [PATCH 21/54] 8365115: G1: Refactor rem set statistics gather code
for group
Reviewed-by: kbarrett, ayang
---
src/hotspot/share/gc/g1/g1RemSetSummary.cpp | 55 ++++++++++-----------
1 file changed, 25 insertions(+), 30 deletions(-)
diff --git a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp
index ec876d020ec..cf032bc5d17 100644
--- a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp
+++ b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp
@@ -268,44 +268,39 @@ public:
return false;
}
- void do_cset_groups() {
- G1CollectedHeap* g1h = G1CollectedHeap::heap();
- G1CSetCandidateGroup* young_only_cset_group = g1h->young_regions_cset_group();
-
+ void accumulate_stats_for_group(G1CSetCandidateGroup* group, G1PerRegionTypeRemSetCounters* gen_counter) {
// If the group has only a single region, then stats were accumulated
- // during region iteration.
- if (young_only_cset_group->length() > 1) {
- G1CardSet* young_only_card_set = young_only_cset_group->card_set();
- size_t rs_mem_sz = young_only_card_set->mem_size();
- size_t rs_unused_mem_sz = young_only_card_set->unused_mem_size();
- size_t occupied_cards = young_only_card_set->occupied();
+ // during region iteration. Skip these.
+ if (group->length() > 1) {
+ G1CardSet* card_set = group->card_set();
- _max_group_cardset_mem_sz = rs_mem_sz;
- _max_cardset_mem_sz_group = young_only_cset_group;
+ size_t rs_mem_sz = card_set->mem_size();
+ size_t rs_unused_mem_sz = card_set->unused_mem_size();
+ size_t occupied_cards = card_set->occupied();
- // Only update cardset details
- _young.add(rs_unused_mem_sz, rs_mem_sz, occupied_cards, 0, 0, false);
+ if (rs_mem_sz > _max_group_cardset_mem_sz) {
+ _max_group_cardset_mem_sz = rs_mem_sz;
+ _max_cardset_mem_sz_group = group;
+ }
+
+ gen_counter->add(rs_unused_mem_sz, rs_mem_sz, occupied_cards, 0, 0, false);
_all.add(rs_unused_mem_sz, rs_mem_sz, occupied_cards, 0, 0, false);
}
+ }
+ void do_cset_groups() {
+ G1CollectedHeap* g1h = G1CollectedHeap::heap();
- G1PerRegionTypeRemSetCounters* current = &_old;
- for (G1CSetCandidateGroup* group : g1h->policy()->candidates()->from_marking_groups()) {
- if (group->length() > 1) {
- G1CardSet* group_card_set = group->card_set();
- size_t rs_mem_sz = group_card_set->mem_size();
- size_t rs_unused_mem_sz = group_card_set->unused_mem_size();
- size_t occupied_cards = group_card_set->occupied();
+ accumulate_stats_for_group(g1h->young_regions_cset_group(), &_young);
- if (rs_mem_sz > _max_group_cardset_mem_sz) {
- _max_group_cardset_mem_sz = rs_mem_sz;
- _max_cardset_mem_sz_group = group;
- }
-
- // Only update cardset details
- _old.add(rs_unused_mem_sz, rs_mem_sz, occupied_cards, 0, 0, false);
- _all.add(rs_unused_mem_sz, rs_mem_sz, occupied_cards, 0, 0, false);
- }
+ G1CollectionSetCandidates* candidates = g1h->policy()->candidates();
+ for (G1CSetCandidateGroup* group : candidates->from_marking_groups()) {
+ accumulate_stats_for_group(group, &_old);
+ }
+ // Skip gathering statistics for retained regions. Just verify that they have
+ // the expected amount of regions.
+ for (G1CSetCandidateGroup* group : candidates->retained_groups()) {
+ assert(group->length() == 1, "must be");
}
}
From 02fe095d29994bec28c85beb6bf2a69b0f49b206 Mon Sep 17 00:00:00 2001
From: Thomas Schatzl
Date: Thu, 21 Aug 2025 11:53:57 +0000
Subject: [PATCH 22/54] 8364934: G1: Rename members of G1CollectionSet
Reviewed-by: ayang, kbarrett
---
src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 2 +-
src/hotspot/share/gc/g1/g1CollectionSet.cpp | 101 +++++++++---------
src/hotspot/share/gc/g1/g1CollectionSet.hpp | 88 ++++++++-------
.../share/gc/g1/g1CollectionSet.inline.hpp | 6 +-
src/hotspot/share/gc/g1/g1RemSet.cpp | 2 +-
src/hotspot/share/gc/g1/g1YoungCollector.cpp | 2 +-
.../gc/g1/g1YoungGCPostEvacuateTasks.cpp | 2 +-
7 files changed, 107 insertions(+), 96 deletions(-)
diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
index ed08d43bbbe..e50821e96c1 100644
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
@@ -3159,5 +3159,5 @@ void G1CollectedHeap::finish_codecache_marking_cycle() {
void G1CollectedHeap::prepare_group_cardsets_for_scan() {
young_regions_cardset()->reset_table_scanner_for_groups();
- collection_set()->prepare_groups_for_scan();
+ collection_set()->prepare_for_scan();
}
diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp
index 90189cfdf8a..804ded144bd 100644
--- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp
+++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp
@@ -38,13 +38,13 @@
#include "utilities/globalDefinitions.hpp"
#include "utilities/quickSort.hpp"
-uint G1CollectionSet::selected_groups_cur_length() const {
+uint G1CollectionSet::groups_cur_length() const {
assert(_inc_build_state == CSetBuildType::Inactive, "must be");
- return _collection_set_groups.length();
+ return _groups.length();
}
-uint G1CollectionSet::collection_groups_increment_length() const {
- return selected_groups_cur_length() - _selected_groups_inc_part_start;
+uint G1CollectionSet::groups_increment_length() const {
+ return groups_cur_length() - _groups_inc_part_start;
}
G1CollectorState* G1CollectionSet::collector_state() const {
@@ -59,21 +59,21 @@ G1CollectionSet::G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy) :
_g1h(g1h),
_policy(policy),
_candidates(),
- _collection_set_regions(nullptr),
- _collection_set_cur_length(0),
- _collection_set_max_length(0),
- _collection_set_groups(),
- _selected_groups_inc_part_start(0),
+ _regions(nullptr),
+ _regions_max_length(0),
+ _regions_cur_length(0),
+ _groups(),
_eden_region_length(0),
_survivor_region_length(0),
_initial_old_region_length(0),
_optional_groups(),
- _inc_build_state(Inactive),
- _inc_part_start(0) {
+ _inc_build_state(CSetBuildType::Inactive),
+ _regions_inc_part_start(0),
+ _groups_inc_part_start(0) {
}
G1CollectionSet::~G1CollectionSet() {
- FREE_C_HEAP_ARRAY(uint, _collection_set_regions);
+ FREE_C_HEAP_ARRAY(uint, _regions);
abandon_all_candidates();
}
@@ -84,8 +84,8 @@ void G1CollectionSet::init_region_lengths(uint eden_cset_region_length,
_eden_region_length = eden_cset_region_length;
_survivor_region_length = survivor_cset_region_length;
- assert((size_t)young_region_length() == _collection_set_cur_length,
- "Young region length %u should match collection set length %u", young_region_length(), _collection_set_cur_length);
+ assert((size_t)young_region_length() == _regions_cur_length,
+ "Young region length %u should match collection set length %u", young_region_length(), _regions_cur_length);
_initial_old_region_length = 0;
assert(_optional_groups.length() == 0, "Should not have any optional groups yet");
@@ -93,9 +93,9 @@ void G1CollectionSet::init_region_lengths(uint eden_cset_region_length,
}
void G1CollectionSet::initialize(uint max_region_length) {
- guarantee(_collection_set_regions == nullptr, "Must only initialize once.");
- _collection_set_max_length = max_region_length;
- _collection_set_regions = NEW_C_HEAP_ARRAY(uint, max_region_length, mtGC);
+ guarantee(_regions == nullptr, "Must only initialize once.");
+ _regions_max_length = max_region_length;
+ _regions = NEW_C_HEAP_ARRAY(uint, max_region_length, mtGC);
_candidates.initialize(max_region_length);
}
@@ -105,14 +105,14 @@ void G1CollectionSet::abandon_all_candidates() {
_initial_old_region_length = 0;
}
-void G1CollectionSet::prepare_groups_for_scan () {
- collection_set_groups()->prepare_for_scan();
+void G1CollectionSet::prepare_for_scan () {
+ groups()->prepare_for_scan();
}
void G1CollectionSet::add_old_region(G1HeapRegion* hr) {
assert_at_safepoint_on_vm_thread();
- assert(_inc_build_state == Active,
+ assert(_inc_build_state == CSetBuildType::Active,
"Precondition, actively building cset or adding optional later on");
assert(hr->is_old(), "the region should be old");
@@ -121,46 +121,46 @@ void G1CollectionSet::add_old_region(G1HeapRegion* hr) {
assert(!hr->in_collection_set(), "should not already be in the collection set");
_g1h->register_old_region_with_region_attr(hr);
- assert(_collection_set_cur_length < _collection_set_max_length, "Collection set now larger than maximum size.");
- _collection_set_regions[_collection_set_cur_length++] = hr->hrm_index();
+ assert(_regions_cur_length < _regions_max_length, "Collection set now larger than maximum size.");
+ _regions[_regions_cur_length++] = hr->hrm_index();
_initial_old_region_length++;
_g1h->old_set_remove(hr);
}
void G1CollectionSet::start_incremental_building() {
- assert(_collection_set_cur_length == 0, "Collection set must be empty before starting a new collection set.");
- assert(selected_groups_cur_length() == 0, "Collection set groups must be empty before starting a new collection set.");
+ assert(_regions_cur_length == 0, "Collection set must be empty before starting a new collection set.");
+ assert(groups_cur_length() == 0, "Collection set groups must be empty before starting a new collection set.");
assert(_optional_groups.length() == 0, "Collection set optional gorups must be empty before starting a new collection set.");
continue_incremental_building();
}
void G1CollectionSet::continue_incremental_building() {
- assert(_inc_build_state == Inactive, "Precondition");
+ assert(_inc_build_state == CSetBuildType::Inactive, "Precondition");
- _inc_part_start = _collection_set_cur_length;
- _selected_groups_inc_part_start = selected_groups_cur_length();
+ _regions_inc_part_start = _regions_cur_length;
+ _groups_inc_part_start = groups_cur_length();
_inc_build_state = CSetBuildType::Active;
}
void G1CollectionSet::stop_incremental_building() {
- _inc_build_state = Inactive;
+ _inc_build_state = CSetBuildType::Inactive;
}
void G1CollectionSet::clear() {
assert_at_safepoint_on_vm_thread();
- _collection_set_cur_length = 0;
- _collection_set_groups.clear();
+ _regions_cur_length = 0;
+ _groups.clear();
}
void G1CollectionSet::iterate(G1HeapRegionClosure* cl) const {
- size_t len = _collection_set_cur_length;
+ size_t len = _regions_cur_length;
OrderAccess::loadload();
for (uint i = 0; i < len; i++) {
- G1HeapRegion* r = _g1h->region_at(_collection_set_regions[i]);
+ G1HeapRegion* r = _g1h->region_at(_regions[i]);
bool result = cl->do_heap_region(r);
if (result) {
cl->set_incomplete();
@@ -187,7 +187,7 @@ void G1CollectionSet::iterate_optional(G1HeapRegionClosure* cl) const {
void G1CollectionSet::iterate_incremental_part_from(G1HeapRegionClosure* cl,
G1HeapRegionClaimer* hr_claimer,
uint worker_id) const {
- iterate_part_from(cl, hr_claimer, _inc_part_start, increment_length(), worker_id);
+ iterate_part_from(cl, hr_claimer, _regions_inc_part_start, regions_cur_length(), worker_id);
}
void G1CollectionSet::iterate_part_from(G1HeapRegionClosure* cl,
@@ -197,29 +197,29 @@ void G1CollectionSet::iterate_part_from(G1HeapRegionClosure* cl,
uint worker_id) const {
_g1h->par_iterate_regions_array(cl,
hr_claimer,
- &_collection_set_regions[offset],
+ &_regions[offset],
length,
worker_id);
}
void G1CollectionSet::add_young_region_common(G1HeapRegion* hr) {
assert(hr->is_young(), "invariant");
- assert(_inc_build_state == Active, "Precondition");
+ assert(_inc_build_state == CSetBuildType::Active, "Precondition");
assert(!hr->in_collection_set(), "invariant");
_g1h->register_young_region_with_region_attr(hr);
// We use UINT_MAX as "invalid" marker in verification.
- assert(_collection_set_cur_length < (UINT_MAX - 1),
- "Collection set is too large with %u entries", _collection_set_cur_length);
- hr->set_young_index_in_cset(_collection_set_cur_length + 1);
+ assert(_regions_cur_length < (UINT_MAX - 1),
+ "Collection set is too large with %u entries", _regions_cur_length);
+ hr->set_young_index_in_cset(_regions_cur_length + 1);
- assert(_collection_set_cur_length < _collection_set_max_length, "Collection set larger than maximum allowed.");
- _collection_set_regions[_collection_set_cur_length] = hr->hrm_index();
+ assert(_regions_cur_length < _regions_max_length, "Collection set larger than maximum allowed.");
+ _regions[_regions_cur_length] = hr->hrm_index();
// Concurrent readers must observe the store of the value in the array before an
// update to the length field.
OrderAccess::storestore();
- _collection_set_cur_length++;
+ _regions_cur_length++;
}
void G1CollectionSet::add_survivor_regions(G1HeapRegion* hr) {
@@ -301,7 +301,7 @@ void G1CollectionSet::print(outputStream* st) {
// pinned by JNI) to allow faster future evacuation. We already "paid" for this work
// when sizing the young generation.
double G1CollectionSet::finalize_young_part(double target_pause_time_ms, G1SurvivorRegions* survivors) {
- assert(_inc_build_state == Active, "Precondition");
+ assert(_inc_build_state == CSetBuildType::Active, "Precondition");
assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint");
Ticks start_time = Ticks::now();
@@ -626,7 +626,8 @@ double G1CollectionSet::select_candidates_from_optional_groups(double time_remai
selected.append(group);
}
- log_debug(gc, ergo, cset) ("Completed with groups, selected %u", num_regions_selected);
+ log_debug(gc, ergo, cset)("Completed with groups, selected %u region in %u groups",
+ num_regions_selected, num_groups_selected);
// Remove selected groups from candidate list.
if (num_groups_selected > 0) {
_optional_groups.remove(&selected);
@@ -635,7 +636,7 @@ double G1CollectionSet::select_candidates_from_optional_groups(double time_remai
return total_prediction_ms;
}
-uint G1CollectionSet::select_optional_collection_set_regions(double time_remaining_ms) {
+uint G1CollectionSet::select_optional_groups(double time_remaining_ms) {
uint optional_regions_count = num_optional_regions();
assert(optional_regions_count > 0,
"Should only be called when there are optional regions");
@@ -670,7 +671,7 @@ void G1CollectionSet::add_group_to_collection_set(G1CSetCandidateGroup* gr) {
assert(r->rem_set()->is_complete(), "must be");
add_region_to_collection_set(r);
}
- _collection_set_groups.append(gr);
+ _groups.append(gr);
}
void G1CollectionSet::add_region_to_collection_set(G1HeapRegion* r) {
@@ -680,20 +681,20 @@ void G1CollectionSet::add_region_to_collection_set(G1HeapRegion* r) {
}
void G1CollectionSet::finalize_initial_collection_set(double target_pause_time_ms, G1SurvivorRegions* survivor) {
- assert(_inc_part_start == 0, "must be");
- assert(_selected_groups_inc_part_start == 0, "must be");
+ assert(_regions_inc_part_start == 0, "must be");
+ assert(_groups_inc_part_start == 0, "must be");
double time_remaining_ms = finalize_young_part(target_pause_time_ms, survivor);
finalize_old_part(time_remaining_ms);
stop_incremental_building();
- QuickSort::sort(_collection_set_regions, _collection_set_cur_length, compare_region_idx);
+ QuickSort::sort(_regions, _regions_cur_length, compare_region_idx);
}
bool G1CollectionSet::finalize_optional_for_evacuation(double remaining_pause_time) {
continue_incremental_building();
- uint num_regions_selected = select_optional_collection_set_regions(remaining_pause_time);
+ uint num_regions_selected = select_optional_groups(remaining_pause_time);
stop_incremental_building();
@@ -756,7 +757,7 @@ public:
void G1CollectionSet::verify_young_cset_indices() const {
assert_at_safepoint_on_vm_thread();
- G1VerifyYoungCSetIndicesClosure cl(_collection_set_cur_length);
+ G1VerifyYoungCSetIndicesClosure cl(_regions_cur_length);
iterate(&cl);
}
#endif
diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.hpp
index e12f3a82d12..2bde960fbc4 100644
--- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp
+++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp
@@ -41,19 +41,19 @@ class G1HeapRegionClosure;
// The collection set.
//
-// The set of regions that are evacuated during an evacuation pause.
+// The set of regions and candidate groups that were evacuated during an
+// evacuation pause.
//
-// At the end of a collection, before freeing the collection set, this set
-// contains all regions that were evacuated during this collection:
+// At the end of a collection, before freeing it, this set contains all regions
+// and collection set groups that were evacuated during this collection:
//
// - survivor regions from the last collection (if any)
// - eden regions allocated by the mutator
// - old gen regions evacuated during mixed gc
//
-// This set is built incrementally at mutator time as regions are retired, and
-// if this had been a mixed gc, some additional (during gc) incrementally added
-// old regions from the collection set candidates built during the concurrent
-// cycle.
+// This set is initially built at mutator time as regions are retired. If the
+// collection is a mixed gc, it contains some additional (during the pause)
+// incrementally added old regions from the collection set candidates.
//
// A more detailed overview of how the collection set changes over time follows:
//
@@ -129,6 +129,7 @@ class G1HeapRegionClosure;
// || ... after step b6)
// |SSS| ... after step 7), with three survivor regions
//
+// Candidate groups are kept in sync with the contents of the collection set regions.
class G1CollectionSet {
G1CollectedHeap* _g1h;
G1Policy* _policy;
@@ -137,46 +138,52 @@ class G1CollectionSet {
G1CollectionSetCandidates _candidates;
// The actual collection set as a set of region indices.
- // All entries in _collection_set_regions below _collection_set_cur_length are
- // assumed to be part of the collection set.
+ //
+ // All regions in _regions below _regions_cur_length are assumed to be part of the
+ // collection set.
// We assume that at any time there is at most only one writer and (one or more)
- // concurrent readers. This means we are good with using storestore and loadload
- // barriers on the writer and reader respectively only.
- uint* _collection_set_regions;
- volatile uint _collection_set_cur_length;
- uint _collection_set_max_length;
+ // concurrent readers. This means synchronization using storestore and loadload
+ // barriers on the writer and reader respectively only are sufficient.
+ //
+ // This corresponds to the regions referenced by the candidate groups further below.
+ uint* _regions;
+ uint _regions_max_length;
+
+ volatile uint _regions_cur_length;
// Old gen groups selected for evacuation.
- G1CSetCandidateGroupList _collection_set_groups;
+ G1CSetCandidateGroupList _groups;
- uint selected_groups_cur_length() const;
- uint _selected_groups_inc_part_start;
+ uint groups_cur_length() const;
uint _eden_region_length;
uint _survivor_region_length;
uint _initial_old_region_length;
// When doing mixed collections we can add old regions to the collection set, which
- // will be collected only if there is enough time. We call these optional (old) regions.
+ // will be collected only if there is enough time. We call these optional (old)
+ // groups. Regions are reachable via this list as well.
G1CSetCandidateGroupList _optional_groups;
- enum CSetBuildType {
+ enum class CSetBuildType {
Active, // We are actively building the collection set
Inactive // We are not actively building the collection set
};
CSetBuildType _inc_build_state;
- size_t _inc_part_start;
+ // Index into the _regions indicating the start of the current collection set increment.
+ size_t _regions_inc_part_start;
+ // Index into the _groups indicating the start of the current collection set increment.
+ uint _groups_inc_part_start;
G1CollectorState* collector_state() const;
G1GCPhaseTimes* phase_times();
void verify_young_cset_indices() const NOT_DEBUG_RETURN;
- // Update the incremental collection set information when adding a region.
void add_young_region_common(G1HeapRegion* hr);
- // Add the given old region to the head of the current collection set.
+ // Add the given old region to the current collection set.
void add_old_region(G1HeapRegion* hr);
void prepare_optional_group(G1CSetCandidateGroup* gr, uint cur_index);
@@ -189,14 +196,14 @@ class G1CollectionSet {
void select_candidates_from_retained(double time_remaining_ms);
- // Select regions for evacuation from the optional candidates given the remaining time
- // and return the number of actually selected regions.
- uint select_optional_collection_set_regions(double time_remaining_ms);
- double select_candidates_from_optional_groups(double time_remaining_ms, uint& num_regions_selected);
+ // Select groups for evacuation from the optional candidates given the remaining time
+ // and return the number of actually selected regions.
+ uint select_optional_groups(double time_remaining_ms);
+ double select_candidates_from_optional_groups(double time_remaining_ms, uint& num_groups_selected);
// Finalize the young part of the initial collection set. Relabel survivor regions
// as Eden and calculate a prediction on how long the evacuation of all young regions
- // will take.
+ // will take. Returns the time remaining from the given target pause time.
double finalize_young_part(double target_pause_time_ms, G1SurvivorRegions* survivors);
// Select the regions comprising the initial and optional collection set from marking
@@ -218,27 +225,29 @@ public:
// Initializes the collection set giving the maximum possible length of the collection set.
void initialize(uint max_region_length);
+ // Drop all collection set candidates (only the candidates).
void abandon_all_candidates();
G1CollectionSetCandidates* candidates() { return &_candidates; }
const G1CollectionSetCandidates* candidates() const { return &_candidates; }
- G1CSetCandidateGroupList* collection_set_groups() { return &_collection_set_groups; }
- const G1CSetCandidateGroupList* collection_set_groups() const { return &_collection_set_groups; }
+ G1CSetCandidateGroupList* groups() { return &_groups; }
+ const G1CSetCandidateGroupList* groups() const { return &_groups; }
- void prepare_groups_for_scan();
+ void prepare_for_scan();
void init_region_lengths(uint eden_cset_region_length,
uint survivor_cset_region_length);
- uint region_length() const { return young_region_length() +
- initial_old_region_length(); }
+ // Total length of the initial collection set in regions.
+ uint initial_region_length() const { return young_region_length() +
+ initial_old_region_length(); }
uint young_region_length() const { return eden_region_length() +
survivor_region_length(); }
- uint eden_region_length() const { return _eden_region_length; }
+ uint eden_region_length() const { return _eden_region_length; }
uint survivor_region_length() const { return _survivor_region_length; }
- uint initial_old_region_length() const { return _initial_old_region_length; }
+ uint initial_old_region_length() const { return _initial_old_region_length; }
uint num_optional_regions() const { return _optional_groups.num_regions(); }
bool only_contains_young_regions() const { return (initial_old_region_length() + num_optional_regions()) == 0; }
@@ -263,14 +272,14 @@ public:
void iterate_incremental_part_from(G1HeapRegionClosure* cl, G1HeapRegionClaimer* hr_claimer, uint worker_id) const;
// Returns the length of the current increment in number of regions.
- size_t increment_length() const { return _collection_set_cur_length - _inc_part_start; }
+ size_t regions_cur_length() const { return _regions_cur_length - _regions_inc_part_start; }
// Returns the length of the whole current collection set in number of regions
- size_t cur_length() const { return _collection_set_cur_length; }
+ size_t cur_length() const { return _regions_cur_length; }
- uint collection_groups_increment_length() const;
+ uint groups_increment_length() const;
// Iterate over the entire collection set (all increments calculated so far), applying
- // the given G1HeapRegionClosure on all of them.
+ // the given G1HeapRegionClosure on all of the regions.
void iterate(G1HeapRegionClosure* cl) const;
void par_iterate(G1HeapRegionClosure* cl,
G1HeapRegionClaimer* hr_claimer,
@@ -278,10 +287,11 @@ public:
void iterate_optional(G1HeapRegionClosure* cl) const;
- // Finalize the initial collection set consisting of all young regions potentially a
+ // Finalize the initial collection set consisting of all young regions and potentially a
// few old gen regions.
void finalize_initial_collection_set(double target_pause_time_ms, G1SurvivorRegions* survivor);
// Finalize the next collection set from the set of available optional old gen regions.
+ // Returns whether there still were some optional regions.
bool finalize_optional_for_evacuation(double remaining_pause_time);
// Abandon (clean up) optional collection set regions that were not evacuated in this
// pause.
diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp
index 717f6860eb6..0f166cdf9ff 100644
--- a/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp
+++ b/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp
@@ -31,8 +31,8 @@
template
inline void G1CollectionSet::merge_cardsets_for_collection_groups(CardOrRangeVisitor& cl, uint worker_id, uint num_workers) {
- uint length = collection_groups_increment_length();
- uint offset = _selected_groups_inc_part_start;
+ uint length = groups_increment_length();
+ uint offset = _groups_inc_part_start;
if (length == 0) {
return;
}
@@ -41,7 +41,7 @@ inline void G1CollectionSet::merge_cardsets_for_collection_groups(CardOrRangeVis
uint cur_pos = start_pos;
uint count = 0;
do {
- G1HeapRegionRemSet::iterate_for_merge(collection_set_groups()->at(offset + cur_pos)->card_set(), cl);
+ G1HeapRegionRemSet::iterate_for_merge(groups()->at(offset + cur_pos)->card_set(), cl);
cur_pos++;
count++;
if (cur_pos == length) {
diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp
index 44b3234d26b..6b7532a99aa 100644
--- a/src/hotspot/share/gc/g1/g1RemSet.cpp
+++ b/src/hotspot/share/gc/g1/g1RemSet.cpp
@@ -1426,7 +1426,7 @@ void G1RemSet::merge_heap_roots(bool initial_evacuation) {
}
WorkerThreads* workers = g1h->workers();
- size_t const increment_length = g1h->collection_set()->increment_length();
+ size_t const increment_length = g1h->collection_set()->regions_cur_length();
uint const num_workers = initial_evacuation ? workers->active_workers() :
MIN2(workers->active_workers(), (uint)increment_length);
diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp
index c61c766bbdc..29eab44d4a8 100644
--- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp
+++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp
@@ -271,7 +271,7 @@ void G1YoungCollector::calculate_collection_set(G1EvacInfo* evacuation_info, dou
allocator()->release_mutator_alloc_regions();
collection_set()->finalize_initial_collection_set(target_pause_time_ms, survivor_regions());
- evacuation_info->set_collection_set_regions(collection_set()->region_length() +
+ evacuation_info->set_collection_set_regions(collection_set()->initial_region_length() +
collection_set()->num_optional_regions());
concurrent_mark()->verify_no_collection_set_oops();
diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp
index bb567e2af5c..b13e7b8a62f 100644
--- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp
+++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp
@@ -887,7 +887,7 @@ public:
p->record_serial_free_cset_time_ms((Ticks::now() - serial_time).seconds() * 1000.0);
}
- double worker_cost() const override { return G1CollectedHeap::heap()->collection_set()->region_length(); }
+ double worker_cost() const override { return G1CollectedHeap::heap()->collection_set()->initial_region_length(); }
void set_max_workers(uint max_workers) override {
_active_workers = max_workers;
From 1548ac4f54edbd370aa071fa1db4474574d2987f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Paul=20H=C3=BCbner?=
Date: Thu, 21 Aug 2025 14:00:18 +0000
Subject: [PATCH 23/54] 8365378: Redundant code in
Deoptimization::print_statistics
Reviewed-by: jsjolen, coleenp
---
src/hotspot/share/runtime/deoptimization.cpp | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp
index 243903ed233..dd8ee7c93fa 100644
--- a/src/hotspot/share/runtime/deoptimization.cpp
+++ b/src/hotspot/share/runtime/deoptimization.cpp
@@ -2926,8 +2926,6 @@ void Deoptimization::print_statistics() {
if (counter != 0) {
char name[1*K];
Bytecodes::Code bc = (Bytecodes::Code)(counter & LSB_MASK);
- if (bc_case == BC_CASE_LIMIT && (int)bc == 0)
- bc = Bytecodes::_illegal;
os::snprintf_checked(name, sizeof(name), "%s/%s/%s",
trap_reason_name(reason),
trap_action_name(action),
From fb651fd6d246e69b42363e050eb8d96afb633eed Mon Sep 17 00:00:00 2001
From: Jonas Norlinder
Date: Thu, 21 Aug 2025 14:05:36 +0000
Subject: [PATCH 24/54] 8364638: Refactor and make accumulated GC CPU time code
generic
Reviewed-by: ayang, sjohanss
---
src/hotspot/share/gc/shared/collectedHeap.cpp | 55 ------------
src/hotspot/share/gc/shared/collectedHeap.hpp | 6 +-
.../gc/shared/stringdedup/stringDedup.hpp | 4 +-
.../stringdedup/stringDedupProcessor.hpp | 4 +-
src/hotspot/share/memory/universe.cpp | 59 +++++++++++++
src/hotspot/share/memory/universe.hpp | 2 +
src/hotspot/share/runtime/java.cpp | 14 +---
src/hotspot/share/runtime/vmThread.cpp | 4 +-
src/hotspot/share/runtime/vmThread.hpp | 2 +-
src/hotspot/share/services/cpuTimeUsage.cpp | 84 +++++++++++++++++++
src/hotspot/share/services/cpuTimeUsage.hpp | 50 +++++++++++
11 files changed, 205 insertions(+), 79 deletions(-)
create mode 100644 src/hotspot/share/services/cpuTimeUsage.cpp
create mode 100644 src/hotspot/share/services/cpuTimeUsage.hpp
diff --git a/src/hotspot/share/gc/shared/collectedHeap.cpp b/src/hotspot/share/gc/shared/collectedHeap.cpp
index b636e3890d3..e82ec1439ea 100644
--- a/src/hotspot/share/gc/shared/collectedHeap.cpp
+++ b/src/hotspot/share/gc/shared/collectedHeap.cpp
@@ -201,34 +201,6 @@ void CollectedHeap::print_relative_to_gc(GCWhen::Type when) const {
}
}
-class CPUTimeThreadClosure : public ThreadClosure {
-private:
- jlong _cpu_time = 0;
-
-public:
- virtual void do_thread(Thread* thread) {
- jlong cpu_time = os::thread_cpu_time(thread);
- if (cpu_time != -1) {
- _cpu_time += cpu_time;
- }
- }
- jlong cpu_time() { return _cpu_time; };
-};
-
-double CollectedHeap::elapsed_gc_cpu_time() const {
- double string_dedup_cpu_time = UseStringDeduplication ?
- os::thread_cpu_time((Thread*)StringDedup::_processor->_thread) : 0;
-
- if (string_dedup_cpu_time == -1) {
- string_dedup_cpu_time = 0;
- }
-
- CPUTimeThreadClosure cl;
- gc_threads_do(&cl);
-
- return (double)(cl.cpu_time() + _vmthread_cpu_time + string_dedup_cpu_time) / NANOSECS_PER_SEC;
-}
-
void CollectedHeap::print_before_gc() const {
print_relative_to_gc(GCWhen::BeforeGC);
}
@@ -633,36 +605,9 @@ void CollectedHeap::post_initialize() {
initialize_serviceability();
}
-void CollectedHeap::log_gc_cpu_time() const {
- LogTarget(Info, gc, cpu) out;
- if (os::is_thread_cpu_time_supported() && out.is_enabled()) {
- double process_cpu_time = os::elapsed_process_cpu_time();
- double gc_cpu_time = elapsed_gc_cpu_time();
-
- if (process_cpu_time == -1 || gc_cpu_time == -1) {
- log_warning(gc, cpu)("Could not sample CPU time");
- return;
- }
-
- double usage;
- if (gc_cpu_time > process_cpu_time ||
- process_cpu_time == 0 || gc_cpu_time == 0) {
- // This can happen e.g. for short running processes with
- // low CPU utilization
- usage = 0;
- } else {
- usage = 100 * gc_cpu_time / process_cpu_time;
- }
- out.print("GC CPU usage: %.2f%% (Process: %.4fs GC: %.4fs)", usage, process_cpu_time, gc_cpu_time);
- }
-}
-
void CollectedHeap::before_exit() {
print_tracing_info();
- // Log GC CPU usage.
- log_gc_cpu_time();
-
// Stop any on-going concurrent work and prepare for exit.
stop();
}
diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp
index 621f3a0bbc7..33d2fad8bba 100644
--- a/src/hotspot/share/gc/shared/collectedHeap.hpp
+++ b/src/hotspot/share/gc/shared/collectedHeap.hpp
@@ -36,6 +36,7 @@
#include "runtime/handles.hpp"
#include "runtime/perfDataTypes.hpp"
#include "runtime/safepoint.hpp"
+#include "services/cpuTimeUsage.hpp"
#include "services/memoryUsage.hpp"
#include "utilities/debug.hpp"
#include "utilities/formatBuffer.hpp"
@@ -89,6 +90,7 @@ public:
// ZCollectedHeap
//
class CollectedHeap : public CHeapObj {
+ friend class CPUTimeUsage::GC;
friend class VMStructs;
friend class JVMCIVMStructs;
friend class IsSTWGCActiveMark; // Block structured external access to _is_stw_gc_active
@@ -429,8 +431,6 @@ protected:
void print_relative_to_gc(GCWhen::Type when) const;
- void log_gc_cpu_time() const;
-
public:
void pre_full_gc_dump(GCTimer* timer);
void post_full_gc_dump(GCTimer* timer);
@@ -463,8 +463,6 @@ protected:
// Iterator for all GC threads (other than VM thread)
virtual void gc_threads_do(ThreadClosure* tc) const = 0;
- double elapsed_gc_cpu_time() const;
-
void print_before_gc() const;
void print_after_gc() const;
diff --git a/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp b/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp
index 43cb513df33..24d17d7d45b 100644
--- a/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp
+++ b/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp
@@ -103,9 +103,9 @@
#include "memory/allocation.hpp"
#include "memory/allStatic.hpp"
#include "oops/oopsHierarchy.hpp"
+#include "services/cpuTimeUsage.hpp"
#include "utilities/globalDefinitions.hpp"
-class CollectedHeap;
class Klass;
class StringDedupThread;
class ThreadClosure;
@@ -116,7 +116,7 @@ class ThreadClosure;
// feature. Other functions in the StringDedup class are called where
// needed, without requiring GC-specific code.
class StringDedup : public AllStatic {
- friend class CollectedHeap;
+ friend class CPUTimeUsage::GC;
friend class StringDedupThread;
class Config;
diff --git a/src/hotspot/share/gc/shared/stringdedup/stringDedupProcessor.hpp b/src/hotspot/share/gc/shared/stringdedup/stringDedupProcessor.hpp
index 5d3929c5817..7e5e64df9b4 100644
--- a/src/hotspot/share/gc/shared/stringdedup/stringDedupProcessor.hpp
+++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupProcessor.hpp
@@ -27,9 +27,9 @@
#include "gc/shared/stringdedup/stringDedup.hpp"
#include "memory/allocation.hpp"
+#include "services/cpuTimeUsage.hpp"
#include "utilities/macros.hpp"
-class CollectedHeap;
class JavaThread;
class OopStorage;
@@ -43,7 +43,7 @@ class OopStorage;
// incremental operations for resizing and for removing dead entries, so
// safepoint checks can be performed between steps in those operations.
class StringDedup::Processor : public CHeapObj {
- friend class CollectedHeap;
+ friend class CPUTimeUsage::GC;
Processor();
~Processor() = default;
diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp
index bd47a054bc0..8afa17b0b3d 100644
--- a/src/hotspot/share/memory/universe.cpp
+++ b/src/hotspot/share/memory/universe.cpp
@@ -81,11 +81,13 @@
#include "runtime/threads.hpp"
#include "runtime/timerTrace.hpp"
#include "sanitizers/leak.hpp"
+#include "services/cpuTimeUsage.hpp"
#include "services/memoryService.hpp"
#include "utilities/align.hpp"
#include "utilities/autoRestore.hpp"
#include "utilities/debug.hpp"
#include "utilities/formatBuffer.hpp"
+#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
#include "utilities/preserveException.hpp"
@@ -1300,6 +1302,63 @@ void Universe::verify(VerifyOption option, const char* prefix) {
}
}
+static void log_cpu_time() {
+ LogTarget(Info, cpu) cpuLog;
+ if (!cpuLog.is_enabled()) {
+ return;
+ }
+
+ const double process_cpu_time = os::elapsed_process_cpu_time();
+ if (process_cpu_time == 0 || process_cpu_time == -1) {
+ // 0 can happen e.g. for short running processes with
+ // low CPU utilization
+ return;
+ }
+
+ const double gc_threads_cpu_time = (double) CPUTimeUsage::GC::gc_threads() / NANOSECS_PER_SEC;
+ const double gc_vm_thread_cpu_time = (double) CPUTimeUsage::GC::vm_thread() / NANOSECS_PER_SEC;
+ const double gc_string_dedup_cpu_time = (double) CPUTimeUsage::GC::stringdedup() / NANOSECS_PER_SEC;
+ const double gc_cpu_time = (double) gc_threads_cpu_time + gc_vm_thread_cpu_time + gc_string_dedup_cpu_time;
+
+ const double elasped_time = os::elapsedTime();
+ const bool has_error = CPUTimeUsage::Error::has_error();
+
+ if (gc_cpu_time < process_cpu_time) {
+ cpuLog.print("=== CPU time Statistics =============================================================");
+ if (has_error) {
+ cpuLog.print("WARNING: CPU time sampling reported errors, numbers may be unreliable");
+ }
+ cpuLog.print(" CPUs");
+ cpuLog.print(" s %% utilized");
+ cpuLog.print(" Process");
+ cpuLog.print(" Total %30.4f %6.2f %8.1f", process_cpu_time, 100.0, process_cpu_time / elasped_time);
+ cpuLog.print(" Garbage Collection %30.4f %6.2f %8.1f", gc_cpu_time, percent_of(gc_cpu_time, process_cpu_time), gc_cpu_time / elasped_time);
+ cpuLog.print(" GC Threads %30.4f %6.2f %8.1f", gc_threads_cpu_time, percent_of(gc_threads_cpu_time, process_cpu_time), gc_threads_cpu_time / elasped_time);
+ cpuLog.print(" VM Thread %30.4f %6.2f %8.1f", gc_vm_thread_cpu_time, percent_of(gc_vm_thread_cpu_time, process_cpu_time), gc_vm_thread_cpu_time / elasped_time);
+
+ if (UseStringDeduplication) {
+ cpuLog.print(" String Deduplication %30.4f %6.2f %8.1f", gc_string_dedup_cpu_time, percent_of(gc_string_dedup_cpu_time, process_cpu_time), gc_string_dedup_cpu_time / elasped_time);
+ }
+ cpuLog.print("=====================================================================================");
+ }
+}
+
+void Universe::before_exit() {
+ log_cpu_time();
+ heap()->before_exit();
+
+ // Print GC/heap related information.
+ Log(gc, exit) log;
+ if (log.is_info()) {
+ LogStream ls_info(log.info());
+ Universe::print_on(&ls_info);
+ if (log.is_trace()) {
+ LogStream ls_trace(log.trace());
+ MutexLocker mcld(ClassLoaderDataGraph_lock);
+ ClassLoaderDataGraph::print_on(&ls_trace);
+ }
+ }
+}
#ifndef PRODUCT
void Universe::calculate_verify_data(HeapWord* low_boundary, HeapWord* high_boundary) {
diff --git a/src/hotspot/share/memory/universe.hpp b/src/hotspot/share/memory/universe.hpp
index 5d481e889c4..ee4c05e1e06 100644
--- a/src/hotspot/share/memory/universe.hpp
+++ b/src/hotspot/share/memory/universe.hpp
@@ -305,6 +305,8 @@ class Universe: AllStatic {
// The particular choice of collected heap.
static CollectedHeap* heap() { return _collectedHeap; }
+ static void before_exit();
+
DEBUG_ONLY(static bool is_stw_gc_active();)
DEBUG_ONLY(static bool is_in_heap(const void* p);)
DEBUG_ONLY(static bool is_in_heap_or_null(const void* p) { return p == nullptr || is_in_heap(p); })
diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp
index 3361ecf1558..2aaf020d6d6 100644
--- a/src/hotspot/share/runtime/java.cpp
+++ b/src/hotspot/share/runtime/java.cpp
@@ -475,19 +475,7 @@ void before_exit(JavaThread* thread, bool halt) {
NativeHeapTrimmer::cleanup();
// Run before exit and then stop concurrent GC threads
- Universe::heap()->before_exit();
-
- // Print GC/heap related information.
- Log(gc, exit) log;
- if (log.is_info()) {
- LogStream ls_info(log.info());
- Universe::print_on(&ls_info);
- if (log.is_trace()) {
- LogStream ls_trace(log.trace());
- MutexLocker mcld(ClassLoaderDataGraph_lock);
- ClassLoaderDataGraph::print_on(&ls_trace);
- }
- }
+ Universe::before_exit();
if (PrintBytecodeHistogram) {
BytecodeHistogram::print();
diff --git a/src/hotspot/share/runtime/vmThread.cpp b/src/hotspot/share/runtime/vmThread.cpp
index 1f8265484f1..c93469c1362 100644
--- a/src/hotspot/share/runtime/vmThread.cpp
+++ b/src/hotspot/share/runtime/vmThread.cpp
@@ -28,8 +28,8 @@
#include "jfr/jfrEvents.hpp"
#include "jfr/support/jfrThreadId.hpp"
#include "logging/log.hpp"
-#include "logging/logStream.hpp"
#include "logging/logConfiguration.hpp"
+#include "logging/logStream.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/oop.inline.hpp"
@@ -46,8 +46,8 @@
#include "runtime/safepoint.hpp"
#include "runtime/synchronizer.hpp"
#include "runtime/timerTrace.hpp"
-#include "runtime/vmThread.hpp"
#include "runtime/vmOperations.hpp"
+#include "runtime/vmThread.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/events.hpp"
#include "utilities/vmError.hpp"
diff --git a/src/hotspot/share/runtime/vmThread.hpp b/src/hotspot/share/runtime/vmThread.hpp
index 668ea4ce4e2..d2033f66ea5 100644
--- a/src/hotspot/share/runtime/vmThread.hpp
+++ b/src/hotspot/share/runtime/vmThread.hpp
@@ -27,8 +27,8 @@
#include "runtime/atomic.hpp"
#include "runtime/javaThread.hpp"
-#include "runtime/perfDataTypes.hpp"
#include "runtime/nonJavaThread.hpp"
+#include "runtime/perfDataTypes.hpp"
#include "runtime/task.hpp"
#include "runtime/vmOperation.hpp"
diff --git a/src/hotspot/share/services/cpuTimeUsage.cpp b/src/hotspot/share/services/cpuTimeUsage.cpp
new file mode 100644
index 00000000000..aa658a67bad
--- /dev/null
+++ b/src/hotspot/share/services/cpuTimeUsage.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 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.
+ *
+ */
+
+#include "gc/shared/collectedHeap.hpp"
+#include "gc/shared/stringdedup/stringDedup.hpp"
+#include "gc/shared/stringdedup/stringDedupProcessor.hpp"
+#include "memory/universe.hpp"
+#include "runtime/globals.hpp"
+#include "runtime/os.hpp"
+#include "runtime/perfData.hpp"
+#include "runtime/vmThread.hpp"
+#include "services/cpuTimeUsage.hpp"
+
+volatile bool CPUTimeUsage::Error::_has_error = false;
+
+static inline jlong thread_cpu_time_or_zero(Thread* thread) {
+ jlong cpu_time = os::thread_cpu_time(thread);
+ if (cpu_time == -1) {
+ CPUTimeUsage::Error::mark_error();
+ return 0;
+ }
+ return cpu_time;
+}
+
+class CPUTimeThreadClosure : public ThreadClosure {
+private:
+ jlong _cpu_time = 0;
+
+public:
+ virtual void do_thread(Thread* thread) {
+ _cpu_time += thread_cpu_time_or_zero(thread);
+ }
+ jlong cpu_time() { return _cpu_time; };
+};
+
+jlong CPUTimeUsage::GC::vm_thread() {
+ return Universe::heap()->_vmthread_cpu_time;
+}
+
+jlong CPUTimeUsage::GC::gc_threads() {
+ CPUTimeThreadClosure cl;
+ Universe::heap()->gc_threads_do(&cl);
+ return cl.cpu_time();
+}
+
+jlong CPUTimeUsage::GC::total() {
+ return gc_threads() + vm_thread() + stringdedup();
+}
+
+jlong CPUTimeUsage::GC::stringdedup() {
+ if (UseStringDeduplication) {
+ return thread_cpu_time_or_zero((Thread*)StringDedup::_processor->_thread);
+ }
+ return 0;
+}
+
+bool CPUTimeUsage::Error::has_error() {
+ return Atomic::load(&_has_error);
+}
+
+void CPUTimeUsage::Error::mark_error() {
+ Atomic::store(&_has_error, true);
+}
diff --git a/src/hotspot/share/services/cpuTimeUsage.hpp b/src/hotspot/share/services/cpuTimeUsage.hpp
new file mode 100644
index 00000000000..ae4d04947a7
--- /dev/null
+++ b/src/hotspot/share/services/cpuTimeUsage.hpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 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.
+ *
+ */
+
+#ifndef SHARE_SERVICES_CPUTIMEUSAGE_HPP
+#define SHARE_SERVICES_CPUTIMEUSAGE_HPP
+
+#include "memory/allStatic.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+namespace CPUTimeUsage {
+ class GC : public AllStatic {
+ public:
+ static jlong total();
+ static jlong gc_threads();
+ static jlong vm_thread();
+ static jlong stringdedup();
+ };
+
+ class Error : public AllStatic {
+ private:
+ static volatile bool _has_error;
+
+ public:
+ static bool has_error();
+ static void mark_error();
+ };
+}
+
+#endif // SHARE_SERVICES_CPUTIMEUSAGE_HPP
From cf70cb70bcd5292ed10d8fb08019f0da82db25dd Mon Sep 17 00:00:00 2001
From: Thomas Schatzl
Date: Thu, 21 Aug 2025 15:32:25 +0000
Subject: [PATCH 25/54] 8365024: G1: Make G1CollectionSet::_inc_build_state
assert-only
Reviewed-by: ayang, kbarrett
---
src/hotspot/share/gc/g1/g1CollectionSet.cpp | 6 +++---
src/hotspot/share/gc/g1/g1CollectionSet.hpp | 2 ++
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp
index 804ded144bd..6fbbeb41a82 100644
--- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp
+++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp
@@ -67,7 +67,7 @@ G1CollectionSet::G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy) :
_survivor_region_length(0),
_initial_old_region_length(0),
_optional_groups(),
- _inc_build_state(CSetBuildType::Inactive),
+ DEBUG_ONLY(_inc_build_state(CSetBuildType::Inactive) COMMA)
_regions_inc_part_start(0),
_groups_inc_part_start(0) {
}
@@ -142,11 +142,11 @@ void G1CollectionSet::continue_incremental_building() {
_regions_inc_part_start = _regions_cur_length;
_groups_inc_part_start = groups_cur_length();
- _inc_build_state = CSetBuildType::Active;
+ DEBUG_ONLY(_inc_build_state = CSetBuildType::Active;)
}
void G1CollectionSet::stop_incremental_building() {
- _inc_build_state = CSetBuildType::Inactive;
+ DEBUG_ONLY(_inc_build_state = CSetBuildType::Inactive;)
}
void G1CollectionSet::clear() {
diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.hpp
index 2bde960fbc4..7038cd4e677 100644
--- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp
+++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp
@@ -165,12 +165,14 @@ class G1CollectionSet {
// groups. Regions are reachable via this list as well.
G1CSetCandidateGroupList _optional_groups;
+#ifdef ASSERT
enum class CSetBuildType {
Active, // We are actively building the collection set
Inactive // We are not actively building the collection set
};
CSetBuildType _inc_build_state;
+#endif
// Index into the _regions indicating the start of the current collection set increment.
size_t _regions_inc_part_start;
// Index into the _groups indicating the start of the current collection set increment.
From d75724682390efa7cb63ae973fd9c504f7f64852 Mon Sep 17 00:00:00 2001
From: Vladimir Kozlov
Date: Thu, 21 Aug 2025 16:37:07 +0000
Subject: [PATCH 26/54] 8365891: failed: Completed task should not be in the
queue
Reviewed-by: dlong
---
src/hotspot/share/compiler/compileBroker.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp
index 36663ab1088..804345d95c5 100644
--- a/src/hotspot/share/compiler/compileBroker.cpp
+++ b/src/hotspot/share/compiler/compileBroker.cpp
@@ -480,6 +480,7 @@ void CompileQueue::purge_stale_tasks() {
MutexUnlocker ul(MethodCompileQueue_lock);
for (CompileTask* task = head; task != nullptr; ) {
CompileTask* next_task = task->next();
+ task->set_next(nullptr);
CompileTaskWrapper ctw(task); // Frees the task
task->set_failure_reason("stale task");
task = next_task;
From bdf9834b81f0565e3572de42ebd42981d1d05a5c Mon Sep 17 00:00:00 2001
From: Prasanta Sadhukhan
Date: Thu, 21 Aug 2025 16:46:19 +0000
Subject: [PATCH 27/54] 8365425: [macos26]
javax/swing/JInternalFrame/8160248/JInternalFrameDraggingTest.java fails on
macOS 26
Reviewed-by: dnguyen, kizune
---
.../8160248/JInternalFrameDraggingTest.java | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/test/jdk/javax/swing/JInternalFrame/8160248/JInternalFrameDraggingTest.java b/test/jdk/javax/swing/JInternalFrame/8160248/JInternalFrameDraggingTest.java
index 81f5e0d0802..7c3732925be 100644
--- a/test/jdk/javax/swing/JInternalFrame/8160248/JInternalFrameDraggingTest.java
+++ b/test/jdk/javax/swing/JInternalFrame/8160248/JInternalFrameDraggingTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -21,6 +21,7 @@
* questions.
*/
+import java.io.File;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Point;
@@ -28,6 +29,7 @@ import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.InputEvent;
import java.awt.image.BufferedImage;
+import javax.imageio.ImageIO;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
@@ -51,6 +53,7 @@ public class JInternalFrameDraggingTest {
private static JInternalFrame internalFrame;
private static int FRAME_SIZE = 500;
private static Color BACKGROUND_COLOR = Color.ORANGE;
+ private static final int tolerance = 10;
public static void main(String[] args) throws Exception {
try {
@@ -69,14 +72,24 @@ public class JInternalFrameDraggingTest {
BufferedImage img = robot.createScreenCapture(rect);
int testRGB = BACKGROUND_COLOR.getRGB();
+ Color testColor = new Color(testRGB);
for (int i = 1; i < size; i++) {
int rgbCW = img.getRGB(i, size / 2);
int rgbCH = img.getRGB(size / 2, i);
- if (rgbCW != testRGB || rgbCH != testRGB) {
+ Color rgbCWColor = new Color(rgbCW);
+ Color rgbCHColor = new Color(rgbCH);
+
+ if (Math.abs(rgbCWColor.getRed() - testColor.getRed()) > tolerance
+ || Math.abs(rgbCWColor.getGreen() - testColor.getGreen()) > tolerance
+ || Math.abs(rgbCWColor.getBlue() - testColor.getBlue()) > tolerance
+ || Math.abs(rgbCHColor.getRed() - testColor.getRed()) > tolerance
+ || Math.abs(rgbCHColor.getGreen() - testColor.getGreen()) > tolerance
+ || Math.abs(rgbCHColor.getBlue() - testColor.getBlue()) > tolerance) {
System.out.println("i " + i + " rgbCW " +
Integer.toHexString(rgbCW) +
" testRGB " + Integer.toHexString(testRGB) +
" rgbCH " + Integer.toHexString(rgbCH));
+ ImageIO.write(img, "png", new File("JInternalFrameDraggingTest.png"));
throw new RuntimeException("Background color is wrong!");
}
}
From 11eccfc85f8495b0cbc3965fd69911a6c7ed0140 Mon Sep 17 00:00:00 2001
From: Francesco Andreuzzi
Date: Thu, 21 Aug 2025 18:58:27 +0000
Subject: [PATCH 28/54] 8365917: Sort share/logging includes
Reviewed-by: ayang, phh
---
src/hotspot/share/logging/log.hpp | 2 +-
src/hotspot/share/logging/logDecorators.hpp | 2 +-
src/hotspot/share/logging/logFileStreamOutput.cpp | 1 +
src/hotspot/share/logging/logTag.cpp | 2 +-
test/hotspot/jtreg/sources/TestIncludesAreSorted.java | 1 +
5 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/hotspot/share/logging/log.hpp b/src/hotspot/share/logging/log.hpp
index 87c7cd926fb..7820e2c21d1 100644
--- a/src/hotspot/share/logging/log.hpp
+++ b/src/hotspot/share/logging/log.hpp
@@ -26,8 +26,8 @@
#include "logging/logLevel.hpp"
#include "logging/logPrefix.hpp"
-#include "logging/logTagSet.hpp"
#include "logging/logTag.hpp"
+#include "logging/logTagSet.hpp"
#include "utilities/debug.hpp"
class LogMessageBuffer;
diff --git a/src/hotspot/share/logging/logDecorators.hpp b/src/hotspot/share/logging/logDecorators.hpp
index 9e38f429974..5b245626ade 100644
--- a/src/hotspot/share/logging/logDecorators.hpp
+++ b/src/hotspot/share/logging/logDecorators.hpp
@@ -24,8 +24,8 @@
#ifndef SHARE_LOGGING_LOGDECORATORS_HPP
#define SHARE_LOGGING_LOGDECORATORS_HPP
-#include "utilities/globalDefinitions.hpp"
#include "logging/logSelection.hpp"
+#include "utilities/globalDefinitions.hpp"
class outputStream;
diff --git a/src/hotspot/share/logging/logFileStreamOutput.cpp b/src/hotspot/share/logging/logFileStreamOutput.cpp
index bc753676706..394c310b940 100644
--- a/src/hotspot/share/logging/logFileStreamOutput.cpp
+++ b/src/hotspot/share/logging/logFileStreamOutput.cpp
@@ -29,6 +29,7 @@
#include "logging/logMessageBuffer.hpp"
#include "memory/allocation.inline.hpp"
#include "utilities/defaultStream.hpp"
+
#include
const char* const LogFileStreamOutput::FoldMultilinesOptionKey = "foldmultilines";
diff --git a/src/hotspot/share/logging/logTag.cpp b/src/hotspot/share/logging/logTag.cpp
index d2aeeebfc79..41554c3acb8 100644
--- a/src/hotspot/share/logging/logTag.cpp
+++ b/src/hotspot/share/logging/logTag.cpp
@@ -22,9 +22,9 @@
*
*/
#include "logging/logTag.hpp"
-#include "utilities/stringUtils.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/ostream.hpp"
+#include "utilities/stringUtils.hpp"
const char* const LogTag::_name[] = {
"", // __NO_TAG
diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java
index 5d8c60e23e0..1a304a44944 100644
--- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java
+++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java
@@ -54,6 +54,7 @@ public class TestIncludesAreSorted {
"share/jfr",
"share/jvmci",
"share/libadt",
+ "share/logging",
"share/metaprogramming",
"share/oops",
"share/opto",
From 52747256bbd5490dba9ef9832025a0f7057e338f Mon Sep 17 00:00:00 2001
From: Brian Burkhalter
Date: Thu, 21 Aug 2025 19:56:46 +0000
Subject: [PATCH 29/54] 8154364: (fs) Files.isSameFile() throws
NoSuchFileException with broken symbolic links
Reviewed-by: alanb
---
.../sun/nio/fs/UnixFileAttributes.java | 27 +-
.../sun/nio/fs/UnixFileSystemProvider.java | 56 ++-
.../sun/nio/fs/WindowsFileSystemProvider.java | 20 +-
test/jdk/java/nio/file/Files/IsSameFile.java | 456 ++++++++++++++++++
test/jdk/java/nio/file/Files/Misc.java | 30 +-
5 files changed, 549 insertions(+), 40 deletions(-)
create mode 100644 test/jdk/java/nio/file/Files/IsSameFile.java
diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java
index 6fc86b66735..48dc4c07d0d 100644
--- a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java
+++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java
@@ -81,8 +81,11 @@ class UnixFileAttributes
return attrs;
}
- // get the UnixFileAttributes for a given file. Returns null if the file does not exist.
- static UnixFileAttributes getIfExists(UnixPath path) throws UnixException {
+ // get the UnixFileAttributes for a given file.
+ // Returns null if the file does not exist.
+ static UnixFileAttributes getIfExists(UnixPath path)
+ throws UnixException
+ {
UnixFileAttributes attrs = new UnixFileAttributes();
int errno = UnixNativeDispatcher.stat2(path, attrs);
if (errno == 0) {
@@ -94,6 +97,26 @@ class UnixFileAttributes
}
}
+ // get the UnixFileAttributes for a given file, optionally following links.
+ // Returns null if the file does not exist.
+ static UnixFileAttributes getIfExists(UnixPath path, boolean followLinks)
+ throws UnixException
+ {
+ UnixFileAttributes attrs = new UnixFileAttributes();
+ int flag = (followLinks) ? 0 : UnixConstants.AT_SYMLINK_NOFOLLOW;
+ try {
+ UnixNativeDispatcher.fstatat(UnixConstants.AT_FDCWD,
+ path.asByteArray(), flag, attrs);
+ } catch (UnixException x) {
+ if (x.errno() == UnixConstants.ENOENT)
+ return null;
+
+ throw x;
+ }
+
+ return attrs;
+ }
+
// get the UnixFileAttributes for an open file
static UnixFileAttributes get(int fd) throws UnixException {
UnixFileAttributes attrs = new UnixFileAttributes();
diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java
index beb9a1af41b..a1c68934604 100644
--- a/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java
+++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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
@@ -53,6 +53,7 @@ import java.nio.file.attribute.PosixFileAttributes;
import java.nio.file.attribute.PosixFileAttributeView;
import java.nio.file.spi.FileTypeDetector;
import java.util.Map;
+import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@@ -348,8 +349,32 @@ public abstract class UnixFileSystemProvider
return access(file, X_OK) == 0;
}
+ // find the key of the last accessible link in the chain
+ private UnixFileKey lastFileKey(UnixPath path) throws UnixException {
+ var fileKeys = new HashSet();
+ UnixFileKey lastFileKey = null;
+ while (path != null) {
+ UnixFileAttributes attrs = UnixFileAttributes.getIfExists(path, false);
+ if (attrs == null) {
+ break;
+ }
+ UnixFileKey fileKey = attrs.fileKey();
+ if (!attrs.isSymbolicLink()) {
+ break;
+ }
+ if (!fileKeys.add(fileKey)) {
+ throw new UnixException(ELOOP);
+ }
+ lastFileKey = fileKey;
+ byte[] target = readlink(path);
+ path = new UnixPath(theFileSystem, target);
+ }
+ return lastFileKey;
+ }
+
@Override
public boolean isSameFile(Path obj1, Path obj2) throws IOException {
+ // toUnixPath verifies its argument is a non-null UnixPath
UnixPath file1 = UnixPath.toUnixPath(obj1);
if (file1.equals(obj2))
return true;
@@ -358,21 +383,28 @@ public abstract class UnixFileSystemProvider
if (!(obj2 instanceof UnixPath file2))
return false;
- UnixFileAttributes attrs1;
- UnixFileAttributes attrs2;
+ UnixFileKey key1;
try {
- attrs1 = UnixFileAttributes.get(file1, true);
- } catch (UnixException x) {
- x.rethrowAsIOException(file1);
- return false; // keep compiler happy
+ UnixFileAttributes attrs = UnixFileAttributes.getIfExists(file1);
+ key1 = (attrs != null) ? attrs.fileKey() : lastFileKey(file1);
+ } catch (UnixException e) {
+ e.rethrowAsIOException(file1);
+ return false;
}
+
+ if (key1 == null)
+ return false;
+
+ UnixFileKey key2;
try {
- attrs2 = UnixFileAttributes.get(file2, true);
- } catch (UnixException x) {
- x.rethrowAsIOException(file2);
- return false; // keep compiler happy
+ UnixFileAttributes attrs = UnixFileAttributes.getIfExists(file2);
+ key2 = (attrs != null) ? attrs.fileKey() : lastFileKey(file2);
+ } catch (UnixException e) {
+ e.rethrowAsIOException(file2);
+ return false;
}
- return attrs1.isSameFile(attrs2);
+
+ return key1.equals(key2);
}
@Override
diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java b/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java
index 3a1bb416fe7..5e740ec1f4d 100644
--- a/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java
+++ b/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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
@@ -434,8 +434,15 @@ class WindowsFileSystemProvider
try {
h1 = file1.openForReadAttributeAccess(true);
} catch (WindowsException x) {
- x.rethrowAsIOException(file1);
+ if (x.lastError() != ERROR_FILE_NOT_FOUND &&
+ x.lastError() != ERROR_PATH_NOT_FOUND)
+ x.rethrowAsIOException(file1);
}
+
+ // if file1 does not exist, it cannot equal file2
+ if (h1 == 0L)
+ return false;
+
try {
WindowsFileAttributes attrs1 = null;
try {
@@ -447,8 +454,15 @@ class WindowsFileSystemProvider
try {
h2 = file2.openForReadAttributeAccess(true);
} catch (WindowsException x) {
- x.rethrowAsIOException(file2);
+ if (x.lastError() != ERROR_FILE_NOT_FOUND &&
+ x.lastError() != ERROR_PATH_NOT_FOUND)
+ x.rethrowAsIOException(file2);
}
+
+ // if file2 does not exist, it cannot equal file1, which does
+ if (h2 == 0L)
+ return false;
+
try {
WindowsFileAttributes attrs2 = null;
try {
diff --git a/test/jdk/java/nio/file/Files/IsSameFile.java b/test/jdk/java/nio/file/Files/IsSameFile.java
new file mode 100644
index 00000000000..00bac0fb5a7
--- /dev/null
+++ b/test/jdk/java/nio/file/Files/IsSameFile.java
@@ -0,0 +1,456 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/* @test
+ * @bug 8154364
+ * @summary Test of Files.isSameFile
+ * @requires (os.family != "windows")
+ * @library .. /test/lib
+ * @build IsSameFile jdk.test.lib.util.FileUtils
+ * @run junit IsSameFile
+ */
+import java.io.IOException;
+import java.io.FileOutputStream;
+import java.nio.file.Files;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystemException;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import jdk.test.lib.util.FileUtils;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestInstance.Lifecycle;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@TestInstance(Lifecycle.PER_CLASS)
+public class IsSameFile {
+ private Path home;
+ private Path a;
+ private Path aa;
+ private Path b;
+ private Path c;
+ private List allFiles;
+
+ @BeforeAll
+ public void init() throws IOException {
+ home = Files.createTempDirectory("TestIsSameFile");
+
+ allFiles = new ArrayList();
+ allFiles.add(a = home.resolve("a"));
+ allFiles.add(aa = home.resolve("a"));
+ allFiles.add(b = home.resolve("b"));
+ allFiles.add(c = home.resolve("c"));
+ }
+
+ public void deleteFiles() throws IOException {
+ for (Path p : allFiles)
+ Files.deleteIfExists(p);
+ }
+
+ @AfterAll
+ public void deleteHome() throws IOException {
+ TestUtil.removeAll(home);
+ }
+
+ public void test(boolean expect, Path x, Path y) throws IOException {
+ assertTrue(Files.isSameFile(x, y) == expect);
+ }
+
+ private Stream stringCompareSource() throws IOException {
+ deleteFiles();
+ List list = new ArrayList();
+ Path x = Path.of("x/y/z");
+ list.add(Arguments.of(true, x, x));
+ list.add(Arguments.of(false, Path.of("w/x/y/z"), x));
+ Path y = Path.of("v/w/x/../y/z");
+ list.add(Arguments.of(false, y, Path.of("v/w/y/z")));
+ list.add(Arguments.of(false, y, Path.of("v/w/x/y/../z")));
+ return list.stream();
+ }
+
+ @ParameterizedTest
+ @MethodSource("stringCompareSource")
+ public void stringCompare(boolean expect, Path x, Path y)
+ throws IOException {
+ test(expect, x, y);
+ }
+
+ private Stream noneExistSource() throws IOException {
+ deleteFiles();
+ List list = new ArrayList();
+ list.add(Arguments.of(true, a, a));
+ list.add(Arguments.of(true, a, aa));
+ list.add(Arguments.of(false, a, b));
+ list.add(Arguments.of(true, b, b));
+ return list.stream();
+ }
+
+ @Test
+ public void obj2Null() {
+ Path x = Path.of("x/y");
+ assertThrows(NullPointerException.class, () -> Files.isSameFile(x, null));
+ }
+
+ private static void zipStringToFile(String entry, String content,
+ Path path)
+ throws IOException
+ {
+ FileOutputStream fos = new FileOutputStream(path.toString());
+ ZipOutputStream zos = new ZipOutputStream(fos);
+
+ ZipEntry zipEntry = new ZipEntry(entry);
+ zos.putNextEntry(zipEntry);
+ zos.write(content.getBytes());
+
+ zos.close();
+ fos.close();
+ }
+
+ private Stream obj2ZipSource() throws IOException {
+ deleteFiles();
+ Files.createFile(a);
+ zipStringToFile("quote.txt", "To be determined", b);
+ FileSystem zipfs = FileSystems.newFileSystem(b);
+ List list = new ArrayList();
+ list.add(Arguments.of(false, a, zipfs.getPath(b.toString())));
+ return list.stream();
+ }
+
+ @ParameterizedTest
+ @MethodSource("obj2ZipSource")
+ public void obj2Zip(boolean expect, Path x, Path y)
+ throws IOException {
+ test(expect, x, y);
+ }
+
+ @ParameterizedTest
+ @MethodSource("noneExistSource")
+ public void noneExist(boolean expect, Path x, Path y)
+ throws IOException {
+ test(expect, x, y);
+ }
+
+ private Stream aExistsSource() throws IOException {
+ deleteFiles();
+ Files.createFile(a);
+ List list = new ArrayList();
+ list.add(Arguments.of(true, a, a));
+ list.add(Arguments.of(true, a, aa));
+ list.add(Arguments.of(false, a, b));
+ return list.stream();
+ }
+
+ @ParameterizedTest
+ @MethodSource("aExistsSource")
+ public void aExists(boolean expect, Path x, Path y) throws IOException {
+ test(expect, x, y);
+ }
+
+ private Stream abExistSource() throws IOException {
+ deleteFiles();
+ Files.createFile(a);
+ Files.createFile(b);
+ List list = new ArrayList();
+ list.add(Arguments.of(false, a, b));
+ list.add(Arguments.of(true, b, b));
+ list.add(Arguments.of(false, a, c));
+ return list.stream();
+ }
+
+ @ParameterizedTest
+ @MethodSource("abExistSource")
+ public void abExist(boolean expect, Path x, Path y)
+ throws IOException {
+ test(expect, x, y);
+ }
+
+ private Stream abcExistSource() throws IOException {
+ deleteFiles();
+ Files.createFile(a);
+ Files.createFile(b);
+ Files.createSymbolicLink(c, a);
+ List list = new ArrayList();
+ list.add(Arguments.of(true, a, c));
+ list.add(Arguments.of(false, a, b));
+ return list.stream();
+ }
+
+ @ParameterizedTest
+ @MethodSource("abcExistSource")
+ public void abcExist(boolean expect, Path x, Path y)
+ throws IOException {
+ test(expect, x, y);
+ }
+
+ private Stream bcExistSource() throws IOException {
+ deleteFiles();
+ Files.createFile(b);
+ Files.createSymbolicLink(c, a);
+ List list = new ArrayList();
+ list.add(Arguments.of(true, a, a));
+ list.add(Arguments.of(true, a, aa));
+ list.add(Arguments.of(false, a, b));
+ list.add(Arguments.of(true, b, b));
+ list.add(Arguments.of(false, a, c));
+ return list.stream();
+ }
+
+ @ParameterizedTest
+ @MethodSource("bcExistSource")
+ public void bcExist(boolean expect, Path x, Path y)
+ throws IOException {
+ test(expect, x, y);
+ }
+
+ //
+ // L1 => L2 => target
+ // L3 => L4 => target
+ //
+ private Stream equalFollowingSource() throws IOException {
+ deleteFiles();
+ Path target = home.resolve("target");
+ Files.createFile(target);
+ allFiles.add(target);
+
+ Path L2 = Path.of("link2");
+ Files.createSymbolicLink(L2, target);
+ allFiles.add(L2);
+
+ Path L1 = Path.of("link1");
+ Files.createSymbolicLink(L1, L2);
+ allFiles.add(L1);
+
+ Path L4 = Path.of("link4");
+ Files.createSymbolicLink(L4, target);
+ allFiles.add(L4);
+
+ Path L3 = Path.of("link3");
+ Files.createSymbolicLink(L3, L4);
+ allFiles.add(L3);
+
+ List list = new ArrayList();
+ list.add(Arguments.of(true, L1, L3));
+ return list.stream();
+ }
+
+ @ParameterizedTest
+ @MethodSource("equalFollowingSource")
+ public void equalFollowing(boolean expect, Path x, Path y)
+ throws IOException {
+ test(expect, x, y);
+ }
+
+ //
+ // L1 => L2 => target
+ // L3 => L4 => cible
+ //
+ private Stream unequalFollowingSource() throws IOException {
+ deleteFiles();
+ Path target = home.resolve("target");
+ Files.createFile(target);
+ allFiles.add(target);
+
+ Path L2 = Path.of("link2");
+ Files.createSymbolicLink(L2, target);
+ allFiles.add(L2);
+
+ Path L1 = Path.of("link1");
+ Files.createSymbolicLink(L1, L2);
+ allFiles.add(L1);
+
+ Path cible = home.resolve("cible");
+ Files.createFile(cible);
+ allFiles.add(cible);
+
+ Path L4 = Path.of("link4");
+ Files.createSymbolicLink(L4, cible);
+ allFiles.add(L4);
+
+ Path L3 = Path.of("link3");
+ Files.createSymbolicLink(L3, L4);
+ allFiles.add(L3);
+
+ List list = new ArrayList();
+ list.add(Arguments.of(false, L1, L3));
+ return list.stream();
+ }
+
+ @ParameterizedTest
+ @MethodSource("unequalFollowingSource")
+ public void unequalFollowing(boolean expect, Path x, Path y)
+ throws IOException {
+ test(expect, x, y);
+ }
+
+ //
+ // L1 => L2 =>
+ // L3 => L4 =>
+ //
+ private Stream unequalNotFollowingSource() throws IOException {
+ deleteFiles();
+
+ Path doesNotExist = Path.of("doesNotExist");
+
+ Path L2 = Path.of("link2");
+ Files.createSymbolicLink(L2, doesNotExist);
+ allFiles.add(L2);
+
+ Path L1 = Path.of("link1");
+ Files.createSymbolicLink(L1, L2);
+ allFiles.add(L1);
+
+ Path L4 = Path.of("link4");
+ Files.createSymbolicLink(L4, doesNotExist);
+ allFiles.add(L4);
+
+ Path L3 = Path.of("link3");
+ Files.createSymbolicLink(L3, L4);
+ allFiles.add(L3);
+
+ List list = new ArrayList();
+ list.add(Arguments.of(false, L1, L3));
+ return list.stream();
+ }
+
+ @ParameterizedTest
+ @MethodSource("unequalNotFollowingSource")
+ public void unequalNotFollowing(boolean expect, Path x, Path y)
+ throws IOException {
+ test(expect, x, y);
+ }
+
+ //
+ // L1 => L2 => L3 => L4 => target
+ //
+ // isSameFile(LX,LY) should be true for all X, Y
+ //
+ private Stream multiLinkSource() throws IOException {
+ deleteFiles();
+ Path target = home.resolve("target");
+ Files.createFile(target);
+ allFiles.add(target);
+ Path[] links = new Path[4];
+ links[3] = Files.createSymbolicLink(Path.of("link4"), target);
+ allFiles.add(links[3]);
+ for (int i = 3; i > 0; i--) {
+ links[i-1] = Files.createSymbolicLink(Path.of("link"+i), links[i]);
+ allFiles.add(links[i-1]);
+ }
+
+ List list = new ArrayList();
+ for (int i = 0; i < 4; i++) {
+ list.add(Arguments.of(true, links[i], target));
+ for (int j = i+1; j < 4; j++)
+ list.add(Arguments.of(true, links[i], links[j]));
+ }
+
+ return list.stream();
+ }
+
+ @ParameterizedTest
+ @MethodSource("multiLinkSource")
+ public void multiLink(boolean expect, Path x, Path y)
+ throws IOException {
+ test(expect, x, y);
+ }
+
+ //
+ // L1 => L2 => L3 => L4 =>
+ //
+ // isSameFile(LX,LY) should be true for all X, Y
+ //
+ private Stream multiLinkNoTargetSource() throws IOException {
+ deleteFiles();
+ Path target = home.resolve("target");
+ Files.createFile(target);
+ allFiles.add(target);
+ Path[] links = new Path[4];
+ links[3] = Files.createSymbolicLink(Path.of("link4"), target);
+ allFiles.add(links[3]);
+ Files.delete(target);
+ allFiles.remove(target);
+ for (int i = 3; i > 0; i--) {
+ links[i-1] = Files.createSymbolicLink(Path.of("link"+i), links[i]);
+ allFiles.add(links[i-1]);
+ }
+
+ List list = new ArrayList();
+ for (int i = 0; i < 4; i++) {
+ list.add(Arguments.of(false, links[i], target));
+ for (int j = i+1; j < 4; j++)
+ list.add(Arguments.of(true, links[i], links[j]));
+ }
+
+ return list.stream();
+ }
+
+ @ParameterizedTest
+ @MethodSource("multiLinkNoTargetSource")
+ public void multiLinkNoTarget(boolean expect, Path x, Path y)
+ throws IOException {
+ test(expect, x, y);
+ }
+
+ //
+ // L1 -> L2 -> L3 -> L1...
+ //
+ // This is a loop and should throw FileSystemException.
+ //
+ private Stream linkLoopSource() throws IOException {
+ deleteFiles();
+
+ Path link1 = home.resolve("L1");
+ Path link2 = home.resolve("L2");
+ Path link3 = home.resolve("L3");
+ allFiles.add(Files.createSymbolicLink(link1, link2));
+ allFiles.add(Files.createSymbolicLink(link2, link3));
+ allFiles.add(Files.createSymbolicLink(link3, link1));
+
+ List list = new ArrayList();
+ list.add(Arguments.of(true, link1, link2));
+ list.add(Arguments.of(true, link2, link3));
+ list.add(Arguments.of(true, link3, link1));
+
+ return list.stream();
+ }
+
+ @ParameterizedTest
+ @MethodSource("linkLoopSource")
+ public void linkLoop(boolean expect, Path x, Path y) throws IOException {
+ assertThrows(FileSystemException.class, () -> Files.isSameFile(x, y));
+ }
+}
diff --git a/test/jdk/java/nio/file/Files/Misc.java b/test/jdk/java/nio/file/Files/Misc.java
index 024b518141b..9ec8d7c252e 100644
--- a/test/jdk/java/nio/file/Files/Misc.java
+++ b/test/jdk/java/nio/file/Files/Misc.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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,7 +22,7 @@
*/
/* @test
- * @bug 4313887 6838333 8005566 8215467 8255576 8286160
+ * @bug 4313887 6838333 8005566 8154364 8215467 8255576 8286160
* @summary Unit test for miscellaneous methods in java.nio.file.Files
* @library .. /test/lib
* @build jdk.test.lib.Platform
@@ -113,34 +113,18 @@ public class Misc {
assertTrue(isSameFile(thisFile, thisFile));
/**
- * Test: Neither files exist
+ * Test: Neither file exists
*/
- try {
- isSameFile(thisFile, thatFile);
- throw new RuntimeException("IOException not thrown");
- } catch (IOException x) {
- }
- try {
- isSameFile(thatFile, thisFile);
- throw new RuntimeException("IOException not thrown");
- } catch (IOException x) {
- }
+ assertTrue(!isSameFile(thisFile, thatFile));
+ assertTrue(!isSameFile(thatFile, thisFile));
createFile(thisFile);
try {
/**
* Test: One file exists
*/
- try {
- isSameFile(thisFile, thatFile);
- throw new RuntimeException("IOException not thrown");
- } catch (IOException x) {
- }
- try {
- isSameFile(thatFile, thisFile);
- throw new RuntimeException("IOException not thrown");
- } catch (IOException x) {
- }
+ assertTrue(!isSameFile(thisFile, thatFile));
+ assertTrue(!isSameFile(thatFile, thisFile));
/**
* Test: Both file exists
From 3468c6e5ef7e7592cf9484736ce333fbe0eaf34d Mon Sep 17 00:00:00 2001
From: Phil Race
Date: Thu, 21 Aug 2025 20:49:04 +0000
Subject: [PATCH 30/54] 8365389: Remove static color fields from
SwingUtilities3 and WindowsMenuItemUI
Reviewed-by: psadhukhan, aivanov, dnguyen
---
.../com/sun/java/swing/SwingUtilities3.java | 21 ++------
.../swing/plaf/basic/BasicMenuItemUI.java | 9 ++--
.../windows/WindowsCheckBoxMenuItemUI.java | 4 +-
.../swing/plaf/windows/WindowsMenuItemUI.java | 51 +++++--------------
.../swing/plaf/windows/WindowsMenuUI.java | 3 +-
.../windows/WindowsRadioButtonMenuItemUI.java | 4 +-
6 files changed, 28 insertions(+), 64 deletions(-)
diff --git a/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java b/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java
index 5e1e149eb9e..91e0f8dc54d 100644
--- a/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java
+++ b/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java
@@ -69,10 +69,6 @@ public class SwingUtilities3 {
private static final Object DELEGATE_REPAINT_MANAGER_KEY =
new StringBuilder("DelegateRepaintManagerKey");
- private static Color disabledForeground;
- private static Color acceleratorSelectionForeground;
- private static Color acceleratorForeground;
-
/**
* Registers delegate RepaintManager for {@code JComponent}.
*/
@@ -204,7 +200,10 @@ public class SwingUtilities3 {
public static void paintAccText(Graphics g, MenuItemLayoutHelper lh,
- MenuItemLayoutHelper.LayoutResult lr) {
+ MenuItemLayoutHelper.LayoutResult lr,
+ Color disabledForeground,
+ Color acceleratorSelectionForeground,
+ Color acceleratorForeground) {
if (!lh.getAccText().isEmpty()) {
ButtonModel model = lh.getMenuItem().getModel();
g.setFont(lh.getAccFontMetrics().getFont());
@@ -243,18 +242,6 @@ public class SwingUtilities3 {
}
}
- public static void setDisabledForeground(Color disabledFg) {
- disabledForeground = disabledFg;
- }
-
- public static void setAcceleratorSelectionForeground(Color acceleratorSelectionFg) {
- acceleratorSelectionForeground = acceleratorSelectionFg;
- }
-
- public static void setAcceleratorForeground(Color acceleratorFg) {
- acceleratorForeground = acceleratorFg;
- }
-
public static void paintArrowIcon(Graphics g, MenuItemLayoutHelper lh,
MenuItemLayoutHelper.LayoutResult lr,
Color foreground) {
diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java
index 524f0337a8f..d361906b291 100644
--- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java
+++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java
@@ -716,11 +716,10 @@ public class BasicMenuItemUI extends MenuItemUI
private void paintAccText(Graphics g, MenuItemLayoutHelper lh,
MenuItemLayoutHelper.LayoutResult lr) {
- SwingUtilities3.setDisabledForeground(disabledForeground);
- SwingUtilities3.setAcceleratorSelectionForeground(
- acceleratorSelectionForeground);
- SwingUtilities3.setAcceleratorForeground(acceleratorForeground);
- SwingUtilities3.paintAccText(g, lh, lr);
+ SwingUtilities3.paintAccText(g, lh, lr,
+ disabledForeground,
+ acceleratorSelectionForeground,
+ acceleratorForeground);
}
private void paintText(Graphics g, MenuItemLayoutHelper lh,
diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java
index f59a59a5125..02054575d77 100644
--- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java
+++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java
@@ -84,7 +84,9 @@ public final class WindowsCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI {
int defaultTextIconGap) {
if (WindowsMenuItemUI.isVistaPainting()) {
WindowsMenuItemUI.paintMenuItem(accessor, g, c, checkIcon,
- arrowIcon, background, foreground, defaultTextIconGap,
+ arrowIcon, background, foreground,
+ disabledForeground, acceleratorSelectionForeground,
+ acceleratorForeground, defaultTextIconGap,
menuItem, getPropertyPrefix());
return;
}
diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java
index a8bafc54c33..aa90b2f35b3 100644
--- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java
+++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java
@@ -67,9 +67,6 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI {
* The instance of {@code PropertyChangeListener}.
*/
private PropertyChangeListener changeListener;
- private static Color disabledForeground;
- private static Color acceleratorSelectionForeground;
- private static Color acceleratorForeground;
final WindowsMenuItemUIAccessor accessor =
new WindowsMenuItemUIAccessor() {
@@ -167,36 +164,6 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI {
changeListener = null;
}
- private static void applyInsets(Rectangle rect, Insets insets) {
- SwingUtilities3.applyInsets(rect, insets);
- }
-
- private static void paintCheckIcon(Graphics g, MenuItemLayoutHelper lh,
- MenuItemLayoutHelper.LayoutResult lr,
- Color holdc, Color foreground) {
- SwingUtilities3.paintCheckIcon(g, lh, lr, holdc, foreground);
- }
-
- private static void paintIcon(Graphics g, MenuItemLayoutHelper lh,
- MenuItemLayoutHelper.LayoutResult lr, Color holdc) {
- SwingUtilities3.paintIcon(g, lh, lr, holdc);
- }
-
- private static void paintAccText(Graphics g, MenuItemLayoutHelper lh,
- MenuItemLayoutHelper.LayoutResult lr) {
- SwingUtilities3.setDisabledForeground(disabledForeground);
- SwingUtilities3.setAcceleratorSelectionForeground(
- acceleratorSelectionForeground);
- SwingUtilities3.setAcceleratorForeground(acceleratorForeground);
- SwingUtilities3.paintAccText(g, lh, lr);
- }
-
- private static void paintArrowIcon(Graphics g, MenuItemLayoutHelper lh,
- MenuItemLayoutHelper.LayoutResult lr,
- Color foreground) {
- SwingUtilities3.paintArrowIcon(g, lh, lr, foreground);
- }
-
protected void paintMenuItem(Graphics g, JComponent c,
Icon checkIcon, Icon arrowIcon,
Color background, Color foreground,
@@ -204,7 +171,8 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI {
if (WindowsMenuItemUI.isVistaPainting()) {
WindowsMenuItemUI.paintMenuItem(accessor, g, c, checkIcon,
arrowIcon, background, foreground,
- defaultTextIconGap, menuItem,
+ disabledForeground, acceleratorSelectionForeground,
+ acceleratorForeground, defaultTextIconGap, menuItem,
getPropertyPrefix());
return;
}
@@ -215,6 +183,9 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI {
static void paintMenuItem(WindowsMenuItemUIAccessor accessor, Graphics g,
JComponent c, Icon checkIcon, Icon arrowIcon,
Color background, Color foreground,
+ Color disabledForeground,
+ Color acceleratorSelectionForeground,
+ Color acceleratorForeground,
int defaultTextIconGap, JMenuItem menuItem, String prefix) {
// Save original graphics font and color
Font holdf = g.getFont();
@@ -224,7 +195,7 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI {
g.setFont(mi.getFont());
Rectangle viewRect = new Rectangle(0, 0, mi.getWidth(), mi.getHeight());
- applyInsets(viewRect, mi.getInsets());
+ SwingUtilities3.applyInsets(viewRect, mi.getInsets());
String acceleratorDelimiter =
UIManager.getString("MenuItem.acceleratorDelimiter");
@@ -242,8 +213,8 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI {
MenuItemLayoutHelper.LayoutResult lr = lh.layoutMenuItem();
paintBackground(accessor, g, mi, background);
- paintCheckIcon(g, lh, lr, holdc, foreground);
- paintIcon(g, lh, lr, holdc);
+ SwingUtilities3.paintCheckIcon(g, lh, lr, holdc, foreground);
+ SwingUtilities3.paintIcon(g, lh, lr, holdc);
if (lh.getCheckIcon() != null && lh.useCheckAndArrow()) {
Rectangle rect = lr.getTextRect();
@@ -267,8 +238,10 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI {
rect.x += lh.getAfterCheckIconGap();
lr.setAccRect(rect);
}
- paintAccText(g, lh, lr);
- paintArrowIcon(g, lh, lr, foreground);
+ SwingUtilities3.paintAccText(g, lh, lr, disabledForeground,
+ acceleratorSelectionForeground,
+ acceleratorForeground);
+ SwingUtilities3.paintArrowIcon(g, lh, lr, foreground);
// Restore original graphics font and color
g.setColor(holdc);
diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java
index 81c01c11036..1476c6fc152 100644
--- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java
+++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java
@@ -140,7 +140,8 @@ public final class WindowsMenuUI extends BasicMenuUI {
if (WindowsMenuItemUI.isVistaPainting()) {
WindowsMenuItemUI.paintMenuItem(accessor, g, c, checkIcon, arrowIcon,
background, foreground,
- defaultTextIconGap, menuItem,
+ disabledForeground, acceleratorSelectionForeground,
+ acceleratorForeground, defaultTextIconGap, menuItem,
getPropertyPrefix());
return;
}
diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java
index 385ab6b3634..628a4be1637 100644
--- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java
+++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java
@@ -84,7 +84,9 @@ public final class WindowsRadioButtonMenuItemUI extends BasicRadioButtonMenuItem
int defaultTextIconGap) {
if (WindowsMenuItemUI.isVistaPainting()) {
WindowsMenuItemUI.paintMenuItem(accessor, g, c, checkIcon,
- arrowIcon, background, foreground, defaultTextIconGap,
+ arrowIcon, background, foreground,
+ disabledForeground, acceleratorSelectionForeground,
+ acceleratorForeground, defaultTextIconGap,
menuItem, getPropertyPrefix());
return;
}
From 584137cf968bdfd4fdb88b5bb210bbbfa5f2d537 Mon Sep 17 00:00:00 2001
From: Dingli Zhang
Date: Fri, 22 Aug 2025 01:42:57 +0000
Subject: [PATCH 31/54] 8365844: RISC-V: TestBadFormat.java fails when running
without RVV
Reviewed-by: fjiang, chagedorn, epeter, fyang
---
.../testlibrary_tests/ir_framework/tests/TestBadFormat.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java
index ac8867f3985..a33aacd924e 100644
--- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java
+++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java
@@ -1124,8 +1124,8 @@ class BadIRAnnotationsAfterTestVM {
@Test
@FailCount(8)
- @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0"})
- @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_MAX, "> 0"}) // valid
+ @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0"}, applyIf = {"MaxVectorSize", "> 0"}) // valid, but only if MaxVectorSize > 0, otherwise, a violation is reported
+ @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_MAX, "> 0"}, applyIf = {"MaxVectorSize", "> 0"}) // valid, but only if MaxVectorSize > 0, otherwise, a violation is reported
@IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_ANY, "> 0"}) // valid
@IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE + "", "> 0"})
@IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE + "xxx", "> 0"})
From 558d06399c7a13b247ee3d0f36f4fe6118004c55 Mon Sep 17 00:00:00 2001
From: Amit Kumar
Date: Fri, 22 Aug 2025 03:43:01 +0000
Subject: [PATCH 32/54] 8361536: [s390x] Saving return_pc at wrong offset
Reviewed-by: lucy, mdoerr
---
src/hotspot/cpu/s390/stubGenerator_s390.cpp | 38 +++++++++++----------
1 file changed, 20 insertions(+), 18 deletions(-)
diff --git a/src/hotspot/cpu/s390/stubGenerator_s390.cpp b/src/hotspot/cpu/s390/stubGenerator_s390.cpp
index 34696f18848..2aa365be999 100644
--- a/src/hotspot/cpu/s390/stubGenerator_s390.cpp
+++ b/src/hotspot/cpu/s390/stubGenerator_s390.cpp
@@ -164,15 +164,16 @@ class StubGenerator: public StubCodeGenerator {
// Save non-volatile registers to ABI of caller frame.
BLOCK_COMMENT("save registers, push frame {");
- __ z_stmg(Z_R6, Z_R14, 16, Z_SP);
- __ z_std(Z_F8, 96, Z_SP);
- __ z_std(Z_F9, 104, Z_SP);
- __ z_std(Z_F10, 112, Z_SP);
- __ z_std(Z_F11, 120, Z_SP);
- __ z_std(Z_F12, 128, Z_SP);
- __ z_std(Z_F13, 136, Z_SP);
- __ z_std(Z_F14, 144, Z_SP);
- __ z_std(Z_F15, 152, Z_SP);
+ __ save_return_pc();
+ __ z_stmg(Z_R6, Z_R13, 16, Z_SP);
+ __ z_std(Z_F8, 80, Z_SP);
+ __ z_std(Z_F9, 88, Z_SP);
+ __ z_std(Z_F10, 96, Z_SP);
+ __ z_std(Z_F11, 104, Z_SP);
+ __ z_std(Z_F12, 112, Z_SP);
+ __ z_std(Z_F13, 120, Z_SP);
+ __ z_std(Z_F14, 128, Z_SP);
+ __ z_std(Z_F15, 136, Z_SP);
//
// Push ENTRY_FRAME including arguments:
@@ -337,15 +338,16 @@ class StubGenerator: public StubCodeGenerator {
__ z_lg(r_arg_result_type, result_type_offset, r_entryframe_fp);
// Restore non-volatiles.
- __ z_lmg(Z_R6, Z_R14, 16, Z_SP);
- __ z_ld(Z_F8, 96, Z_SP);
- __ z_ld(Z_F9, 104, Z_SP);
- __ z_ld(Z_F10, 112, Z_SP);
- __ z_ld(Z_F11, 120, Z_SP);
- __ z_ld(Z_F12, 128, Z_SP);
- __ z_ld(Z_F13, 136, Z_SP);
- __ z_ld(Z_F14, 144, Z_SP);
- __ z_ld(Z_F15, 152, Z_SP);
+ __ restore_return_pc();
+ __ z_lmg(Z_R6, Z_R13, 16, Z_SP);
+ __ z_ld(Z_F8, 80, Z_SP);
+ __ z_ld(Z_F9, 88, Z_SP);
+ __ z_ld(Z_F10, 96, Z_SP);
+ __ z_ld(Z_F11, 104, Z_SP);
+ __ z_ld(Z_F12, 112, Z_SP);
+ __ z_ld(Z_F13, 120, Z_SP);
+ __ z_ld(Z_F14, 128, Z_SP);
+ __ z_ld(Z_F15, 136, Z_SP);
BLOCK_COMMENT("} restore");
//
From 8e4485699235caff0074c4d25ee78539e57da63a Mon Sep 17 00:00:00 2001
From: Phil Race
Date: Fri, 22 Aug 2025 04:28:56 +0000
Subject: [PATCH 33/54] 8365180: Remove sun.awt.windows.WInputMethod.finalize()
Reviewed-by: serb, azvegint
---
.../classes/sun/awt/windows/WInputMethod.java | 38 ++++++++++++-------
.../native/libawt/windows/awt_InputMethod.cpp | 4 +-
2 files changed, 26 insertions(+), 16 deletions(-)
diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WInputMethod.java b/src/java.desktop/windows/classes/sun/awt/windows/WInputMethod.java
index e893a58f9ed..0e4e5bd585e 100644
--- a/src/java.desktop/windows/classes/sun/awt/windows/WInputMethod.java
+++ b/src/java.desktop/windows/classes/sun/awt/windows/WInputMethod.java
@@ -44,6 +44,8 @@ import java.util.Map;
import sun.awt.AWTAccessor;
import sun.awt.AWTAccessor.ComponentAccessor;
import sun.awt.im.InputMethodAdapter;
+import sun.java2d.Disposer;
+import sun.java2d.DisposerRecord;
final class WInputMethod extends InputMethodAdapter
{
@@ -124,6 +126,8 @@ final class WInputMethod extends InputMethodAdapter
public WInputMethod()
{
context = createNativeContext();
+ disposerRecord = new ContextDisposerRecord(context);
+ Disposer.addRecord(this, disposerRecord);
cmode = getConversionStatus(context);
open = getOpenStatus(context);
currentLocale = getNativeLocale();
@@ -132,16 +136,23 @@ final class WInputMethod extends InputMethodAdapter
}
}
- @Override
- @SuppressWarnings("removal")
- protected void finalize() throws Throwable
- {
- // Release the resources used by the native input context.
- if (context!=0) {
- destroyNativeContext(context);
- context=0;
+ private final ContextDisposerRecord disposerRecord;
+
+ private static final class ContextDisposerRecord implements DisposerRecord {
+
+ private final int context;
+ private volatile boolean disposed;
+
+ ContextDisposerRecord(int c) {
+ context = c;
+ }
+
+ public synchronized void dispose() {
+ if (!disposed) {
+ destroyNativeContext(context);
+ }
+ disposed = true;
}
- super.finalize();
}
@Override
@@ -151,9 +162,7 @@ final class WInputMethod extends InputMethodAdapter
@Override
public void dispose() {
- // Due to a memory management problem in Windows 98, we should retain
- // the native input context until this object is finalized. So do
- // nothing here.
+ disposerRecord.dispose();
}
/**
@@ -448,6 +457,7 @@ final class WInputMethod extends InputMethodAdapter
@Override
public void removeNotify() {
endCompositionNative(context, DISCARD_INPUT);
+ disableNativeIME(awtFocussedComponentPeer);
awtFocussedComponent = null;
awtFocussedComponentPeer = null;
}
@@ -658,8 +668,8 @@ final class WInputMethod extends InputMethodAdapter
}
- private native int createNativeContext();
- private native void destroyNativeContext(int context);
+ private static native int createNativeContext();
+ private static native void destroyNativeContext(int context);
private native void enableNativeIME(WComponentPeer peer, int context, boolean useNativeCompWindow);
private native void disableNativeIME(WComponentPeer peer);
private native void handleNativeIMEEvent(WComponentPeer peer, AWTEvent e);
diff --git a/src/java.desktop/windows/native/libawt/windows/awt_InputMethod.cpp b/src/java.desktop/windows/native/libawt/windows/awt_InputMethod.cpp
index fcc6e4c2cb8..87087870b5d 100644
--- a/src/java.desktop/windows/native/libawt/windows/awt_InputMethod.cpp
+++ b/src/java.desktop/windows/native/libawt/windows/awt_InputMethod.cpp
@@ -52,7 +52,7 @@ extern BOOL g_bUserHasChangedInputLang;
* Signature: ()I
*/
JNIEXPORT jint JNICALL
-Java_sun_awt_windows_WInputMethod_createNativeContext(JNIEnv *env, jobject self)
+Java_sun_awt_windows_WInputMethod_createNativeContext(JNIEnv *env, jclass cls)
{
TRY;
@@ -69,7 +69,7 @@ Java_sun_awt_windows_WInputMethod_createNativeContext(JNIEnv *env, jobject self)
* Signature: (I)V
*/
JNIEXPORT void JNICALL
-Java_sun_awt_windows_WInputMethod_destroyNativeContext(JNIEnv *env, jobject self, jint context)
+Java_sun_awt_windows_WInputMethod_destroyNativeContext(JNIEnv *env, jclass cls, jint context)
{
TRY_NO_VERIFY;
From f0498c2aed761d4023917bc9cd1f852a02ce977a Mon Sep 17 00:00:00 2001
From: Alan Bateman
Date: Fri, 22 Aug 2025 08:16:55 +0000
Subject: [PATCH 34/54] 8364764:
java/nio/channels/vthread/BlockingChannelOps.java subtests timed out
Reviewed-by: jpai
---
.../channels/vthread/BlockingChannelOps.java | 140 ++++++++++++++----
1 file changed, 109 insertions(+), 31 deletions(-)
diff --git a/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java b/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java
index 7ff02cdfea4..1cdd090d1be 100644
--- a/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java
+++ b/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 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
@@ -21,7 +21,7 @@
* questions.
*/
-/**
+/*
* @test id=default
* @bug 8284161
* @summary Test virtual threads doing blocking I/O on NIO channels
@@ -29,7 +29,7 @@
* @run junit BlockingChannelOps
*/
-/**
+/*
* @test id=poller-modes
* @requires (os.family == "linux") | (os.family == "mac")
* @library /test/lib
@@ -37,7 +37,7 @@
* @run junit/othervm -Djdk.pollerMode=2 BlockingChannelOps
*/
-/**
+/*
* @test id=no-vmcontinuations
* @requires vm.continuations
* @library /test/lib
@@ -62,6 +62,7 @@ import java.nio.channels.ReadableByteChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.WritableByteChannel;
+import java.util.concurrent.locks.LockSupport;
import jdk.test.lib.thread.VThreadRunner;
import org.junit.jupiter.api.Test;
@@ -161,6 +162,22 @@ class BlockingChannelOps {
});
}
+ /**
+ * SocketChannel shutdownInput while virtual thread blocked in read.
+ */
+ @Test
+ void testSocketChannelReadAsyncShutdownInput() throws Exception {
+ VThreadRunner.run(() -> {
+ try (var connection = new Connection()) {
+ SocketChannel sc = connection.channel1();
+ runAfterParkedAsync(sc::shutdownInput);
+ int n = sc.read(ByteBuffer.allocate(100));
+ assertEquals(-1, n);
+ assertTrue(sc.isOpen());
+ }
+ });
+ }
+
/**
* Virtual thread interrupted while blocked in SocketChannel read.
*/
@@ -190,13 +207,15 @@ class BlockingChannelOps {
@Test
void testSocketChannelWriteAsyncClose() throws Exception {
VThreadRunner.run(() -> {
- boolean retry = true;
- while (retry) {
+ boolean done = false;
+ while (!done) {
try (var connection = new Connection()) {
SocketChannel sc = connection.channel1();
// close sc when current thread blocks in write
- runAfterParkedAsync(sc::close);
+ runAfterParkedAsync(sc::close, true);
+
+ // write until channel is closed
try {
ByteBuffer bb = ByteBuffer.allocate(100*1024);
for (;;) {
@@ -206,30 +225,59 @@ class BlockingChannelOps {
}
} catch (AsynchronousCloseException expected) {
// closed when blocked in write
- retry = false;
+ done = true;
} catch (ClosedChannelException e) {
- // closed when not blocked in write, need to retry test
+ // closed but not blocked in write, need to retry test
+ System.err.format("%s, need to retry!%n", e);
}
}
}
});
}
+
+ /**
+ * SocketChannel shutdownOutput while virtual thread blocked in write.
+ */
+ @Test
+ void testSocketChannelWriteAsyncShutdownOutput() throws Exception {
+ VThreadRunner.run(() -> {
+ try (var connection = new Connection()) {
+ SocketChannel sc = connection.channel1();
+
+ // shutdown output when current thread blocks in write
+ runAfterParkedAsync(sc::shutdownOutput);
+ try {
+ ByteBuffer bb = ByteBuffer.allocate(100*1024);
+ for (;;) {
+ int n = sc.write(bb);
+ assertTrue(n > 0);
+ bb.clear();
+ }
+ } catch (ClosedChannelException e) {
+ // expected
+ }
+ assertTrue(sc.isOpen());
+ }
+ });
+ }
+
/**
* Virtual thread interrupted while blocked in SocketChannel write.
*/
@Test
void testSocketChannelWriteInterrupt() throws Exception {
VThreadRunner.run(() -> {
- boolean retry = true;
- while (retry) {
+ boolean done = false;
+ while (!done) {
try (var connection = new Connection()) {
SocketChannel sc = connection.channel1();
// interrupt current thread when it blocks in write
Thread thisThread = Thread.currentThread();
- runAfterParkedAsync(thisThread::interrupt);
+ runAfterParkedAsync(thisThread::interrupt, true);
+ // write until channel is closed
try {
ByteBuffer bb = ByteBuffer.allocate(100*1024);
for (;;) {
@@ -240,9 +288,10 @@ class BlockingChannelOps {
} catch (ClosedByInterruptException e) {
// closed when blocked in write
assertTrue(Thread.interrupted());
- retry = false;
+ done = true;
} catch (ClosedChannelException e) {
- // closed when not blocked in write, need to retry test
+ // closed but not blocked in write, need to retry test
+ System.err.format("%s, need to retry!%n", e);
}
}
}
@@ -734,14 +783,16 @@ class BlockingChannelOps {
@Test
void testPipeWriteAsyncClose() throws Exception {
VThreadRunner.run(() -> {
- boolean retry = true;
- while (retry) {
+ boolean done = false;
+ while (!done) {
Pipe p = Pipe.open();
try (Pipe.SinkChannel sink = p.sink();
Pipe.SourceChannel source = p.source()) {
// close sink when current thread blocks in write
- runAfterParkedAsync(sink::close);
+ runAfterParkedAsync(sink::close, true);
+
+ // write until channel is closed
try {
ByteBuffer bb = ByteBuffer.allocate(100*1024);
for (;;) {
@@ -751,9 +802,10 @@ class BlockingChannelOps {
}
} catch (AsynchronousCloseException e) {
// closed when blocked in write
- retry = false;
+ done = true;
} catch (ClosedChannelException e) {
- // closed when not blocked in write, need to retry test
+ // closed but not blocked in write, need to retry test
+ System.err.format("%s, need to retry!%n", e);
}
}
}
@@ -766,16 +818,17 @@ class BlockingChannelOps {
@Test
void testPipeWriteInterrupt() throws Exception {
VThreadRunner.run(() -> {
- boolean retry = true;
- while (retry) {
+ boolean done = false;
+ while (!done) {
Pipe p = Pipe.open();
try (Pipe.SinkChannel sink = p.sink();
Pipe.SourceChannel source = p.source()) {
// interrupt current thread when it blocks in write
Thread thisThread = Thread.currentThread();
- runAfterParkedAsync(thisThread::interrupt);
+ runAfterParkedAsync(thisThread::interrupt, true);
+ // write until channel is closed
try {
ByteBuffer bb = ByteBuffer.allocate(100*1024);
for (;;) {
@@ -786,9 +839,10 @@ class BlockingChannelOps {
} catch (ClosedByInterruptException expected) {
// closed when blocked in write
assertTrue(Thread.interrupted());
- retry = false;
+ done = true;
} catch (ClosedChannelException e) {
- // closed when not blocked in write, need to retry test
+ // closed but not blocked in write, need to retry test
+ System.err.format("%s, need to retry!%n", e);
}
}
}
@@ -848,26 +902,50 @@ class BlockingChannelOps {
}
/**
- * Runs the given task asynchronously after the current virtual thread has parked.
+ * Runs the given task asynchronously after the current virtual thread parks.
+ * @param writing if the thread will block in write
* @return the thread started to run the task
*/
- static Thread runAfterParkedAsync(ThrowingRunnable task) {
+ private static Thread runAfterParkedAsync(ThrowingRunnable task, boolean writing) {
Thread target = Thread.currentThread();
if (!target.isVirtual())
throw new WrongThreadException();
return Thread.ofPlatform().daemon().start(() -> {
try {
- Thread.State state = target.getState();
- while (state != Thread.State.WAITING
- && state != Thread.State.TIMED_WAITING) {
+ // wait for target thread to park
+ while (!isWaiting(target)) {
Thread.sleep(20);
- state = target.getState();
}
- Thread.sleep(20); // give a bit more time to release carrier
+
+ // if the target thread is parked in write then we nudge it a few times
+ // to avoid wakeup with some bytes written
+ if (writing) {
+ for (int i = 0; i < 3; i++) {
+ LockSupport.unpark(target);
+ while (!isWaiting(target)) {
+ Thread.sleep(20);
+ }
+ }
+ }
+
task.run();
+
} catch (Exception e) {
e.printStackTrace();
}
});
}
+
+ private static Thread runAfterParkedAsync(ThrowingRunnable task) {
+ return runAfterParkedAsync(task, false);
+ }
+
+ /**
+ * Return true if the given Thread is parked.
+ */
+ private static boolean isWaiting(Thread target) {
+ Thread.State state = target.getState();
+ assertNotEquals(Thread.State.TERMINATED, state);
+ return (state == Thread.State.WAITING || state == Thread.State.TIMED_WAITING);
+ }
}
From e1c58f858a64853c2d454fd00a84455ca6700055 Mon Sep 17 00:00:00 2001
From: Martin Doerr
Date: Fri, 22 Aug 2025 09:01:21 +0000
Subject: [PATCH 35/54] 8360540: nmethod entry barriers of new nmethods should
be disarmed
Reviewed-by: eosterlund, tschatzl
---
src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 3 +++
src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp | 3 +++
src/hotspot/share/gc/serial/serialHeap.cpp | 3 +++
3 files changed, 9 insertions(+)
diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
index e50821e96c1..bf512cfa19d 100644
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
@@ -74,6 +74,7 @@
#include "gc/g1/g1VMOperations.hpp"
#include "gc/g1/g1YoungCollector.hpp"
#include "gc/g1/g1YoungGCAllocationFailureInjector.hpp"
+#include "gc/shared/barrierSetNMethod.hpp"
#include "gc/shared/classUnloadingContext.hpp"
#include "gc/shared/concurrentGCBreakpoints.hpp"
#include "gc/shared/fullGCForwarding.hpp"
@@ -3079,6 +3080,8 @@ void G1CollectedHeap::register_nmethod(nmethod* nm) {
guarantee(nm != nullptr, "sanity");
RegisterNMethodOopClosure reg_cl(this, nm);
nm->oops_do(®_cl);
+ BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
+ bs_nm->disarm(nm);
}
void G1CollectedHeap::unregister_nmethod(nmethod* nm) {
diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp
index c6a9a312e5c..07ae097c5b8 100644
--- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp
+++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp
@@ -32,6 +32,7 @@
#include "gc/parallel/psPromotionManager.hpp"
#include "gc/parallel/psScavenge.hpp"
#include "gc/parallel/psVMOperations.hpp"
+#include "gc/shared/barrierSetNMethod.hpp"
#include "gc/shared/fullGCForwarding.inline.hpp"
#include "gc/shared/gcHeapSummary.hpp"
#include "gc/shared/gcLocker.inline.hpp"
@@ -861,6 +862,8 @@ void ParallelScavengeHeap::complete_loaded_archive_space(MemRegion archive_space
void ParallelScavengeHeap::register_nmethod(nmethod* nm) {
ScavengableNMethods::register_nmethod(nm);
+ BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
+ bs_nm->disarm(nm);
}
void ParallelScavengeHeap::unregister_nmethod(nmethod* nm) {
diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp
index 6b9328b8697..72f8ad85a4e 100644
--- a/src/hotspot/share/gc/serial/serialHeap.cpp
+++ b/src/hotspot/share/gc/serial/serialHeap.cpp
@@ -34,6 +34,7 @@
#include "gc/serial/serialMemoryPools.hpp"
#include "gc/serial/serialVMOperations.hpp"
#include "gc/serial/tenuredGeneration.inline.hpp"
+#include "gc/shared/barrierSetNMethod.hpp"
#include "gc/shared/cardTableBarrierSet.hpp"
#include "gc/shared/classUnloadingContext.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
@@ -432,6 +433,8 @@ bool SerialHeap::do_young_collection(bool clear_soft_refs) {
void SerialHeap::register_nmethod(nmethod* nm) {
ScavengableNMethods::register_nmethod(nm);
+ BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
+ bs_nm->disarm(nm);
}
void SerialHeap::unregister_nmethod(nmethod* nm) {
From f5f414f9fc67e55acb83e04ea270d39041cb6198 Mon Sep 17 00:00:00 2001
From: Shaojin Wen
Date: Fri, 22 Aug 2025 15:57:11 +0000
Subject: [PATCH 36/54] 8365186: Reduce size of
j.t.f.DateTimePrintContext::adjust
Reviewed-by: rriggs
---
.../time/format/DateTimePrintContext.java | 88 ++++++++++++++++++-
1 file changed, 87 insertions(+), 1 deletion(-)
diff --git a/src/java.base/share/classes/java/time/format/DateTimePrintContext.java b/src/java.base/share/classes/java/time/format/DateTimePrintContext.java
index c7eed23b7bc..d755ba3ee78 100644
--- a/src/java.base/share/classes/java/time/format/DateTimePrintContext.java
+++ b/src/java.base/share/classes/java/time/format/DateTimePrintContext.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2021, 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
@@ -120,6 +120,19 @@ final class DateTimePrintContext {
this.formatter = formatter;
}
+ /**
+ * Adjusts the given {@link TemporalAccessor} using chronology and time-zone from a formatter if present.
+ *
+ * This method serves as an optimization front-end that checks for non-null overrides in the formatter.
+ * If neither chronology nor time-zone is specified in the formatter, returns the original temporal unchanged.
+ * Otherwise, delegates to the core adjustment method {@link #adjustWithOverride(TemporalAccessor, Chronology, ZoneId)}.
+ *
+ * @implNote Optimizes for the common case where formatters don't specify chronology/time-zone
+ * by avoiding unnecessary processing. Most formatters have null for these properties.
+ * @param temporal the temporal object to adjust, not null
+ * @param formatter the formatter providing potential chronology and time-zone overrides
+ * @return the adjusted temporal, or the original if no overrides are present in the formatter
+ */
private static TemporalAccessor adjust(final TemporalAccessor temporal, DateTimeFormatter formatter) {
// normal case first (early return is an optimization)
Chronology overrideChrono = formatter.getChronology();
@@ -128,6 +141,32 @@ final class DateTimePrintContext {
return temporal;
}
+ // Placing the non-null cases in a separate method allows more flexible code optimizations
+ return adjustWithOverride(temporal, overrideChrono, overrideZone);
+ }
+
+ /**
+ * Adjusts the given {@link TemporalAccessor} with optional overriding chronology and time-zone.
+ *
+ * This method minimizes changes by returning the original temporal if the override parameters
+ * are either {@code null} or equivalent to those already present in the temporal. When overrides
+ * are applied:
+ *
+ * - If a time-zone override is provided and the temporal supports {@link ChronoField#INSTANT_SECONDS},
+ * the result is a zoned date-time using the override time-zone and chronology (defaulting to ISO if not overridden).
+ * - Other cases (including partial date-times or mixed chronology/time-zone changes) are delegated
+ * to a secondary adjustment method.
+ *
+ *
+ * @param temporal the temporal object to adjust, not null
+ * @param overrideChrono the chronology to override (null retains the original chronology)
+ * @param overrideZone the time-zone to override (null retains the original time-zone)
+ * @return the adjusted temporal, which may be the original object if no effective changes were made,
+ * or a new object with the applied overrides
+ * @implNote Optimizes for common cases where overrides are identical to existing values
+ * or where instant-based temporals can be directly converted with a time-zone.
+ */
+ private static TemporalAccessor adjustWithOverride(TemporalAccessor temporal, Chronology overrideChrono, ZoneId overrideZone) {
// ensure minimal change (early return is an optimization)
Chronology temporalChrono = temporal.query(TemporalQueries.chronology());
ZoneId temporalZone = temporal.query(TemporalQueries.zoneId());
@@ -149,6 +188,53 @@ final class DateTimePrintContext {
Chronology chrono = Objects.requireNonNullElse(effectiveChrono, IsoChronology.INSTANCE);
return chrono.zonedDateTime(Instant.from(temporal), overrideZone);
}
+ }
+
+ // Split uncommon code branches into a separate method
+ return adjustSlow(temporal, overrideZone, temporalZone, overrideChrono, effectiveChrono, temporalChrono);
+ }
+
+ /**
+ * Internal helper method to adjust temporal fields using override chronology and time-zone in complex cases.
+ *
+ * Handles non-instant temporal objects by creating a delegate {@link TemporalAccessor} that combines:
+ *
+ * - The original temporal's time-related fields
+ * - Date fields converted to the effective chronology (if available)
+ * - Override zone/chronology information for temporal queries
+ *
+ *
+ * Performs critical validation before processing:
+ *
+ * - Rejects offset changes for non-instant temporal objects with existing offsets
+ * - Verifies date field integrity when applying chronology overrides to partial dates
+ *
+ *
+ * @param temporal the original temporal object to adjust, not null
+ * @param overrideZone override time-zone (nullable)
+ * @param temporalZone original time-zone from temporal (nullable)
+ * @param overrideChrono override chronology (nullable)
+ * @param effectiveChrono precomputed effective chronology (override if present, otherwise temporal's chronology)
+ * @param temporalChrono original chronology from temporal (nullable)
+ * @return adjusted temporal accessor combining original fields with overrides
+ * @throws DateTimeException if:
+ *
+ * - Applying a {@link ZoneOffset} override to a temporal with conflicting existing offset that doesn't represent an instant
+ * - Applying chronology override to temporal with partial date fields
+ *
+ * @implNote Creates an anonymous temporal accessor that:
+ *
+ * - Delegates time-based fields to original temporal
+ * - Uses converted date fields when chronology override is applied
+ * - Responds to chronology/zone queries with effective values
+ * - Preserves precision queries from original temporal
+ *
+ */
+ private static TemporalAccessor adjustSlow(
+ TemporalAccessor temporal,
+ ZoneId overrideZone, ZoneId temporalZone,
+ Chronology overrideChrono, Chronology effectiveChrono, Chronology temporalChrono) {
+ if (overrideZone != null) {
// block changing zone on OffsetTime, and similar problem cases
if (overrideZone.normalized() instanceof ZoneOffset && temporal.isSupported(OFFSET_SECONDS) &&
temporal.get(OFFSET_SECONDS) != overrideZone.getRules().getOffset(Instant.EPOCH).getTotalSeconds()) {
From dba0d545053fb73e57ea6fda829a5bf3d0135ac5 Mon Sep 17 00:00:00 2001
From: Shaojin Wen
Date: Fri, 22 Aug 2025 16:44:47 +0000
Subject: [PATCH 37/54] 8365832: Optimize FloatingDecimal and DigitList with
byte[] and cleanup
Reviewed-by: rgiulietti, liach
---
.../share/classes/java/text/DigitList.java | 69 +++---
.../jdk/internal/math/FloatingDecimal.java | 218 ++++--------------
2 files changed, 87 insertions(+), 200 deletions(-)
diff --git a/src/java.base/share/classes/java/text/DigitList.java b/src/java.base/share/classes/java/text/DigitList.java
index 41c143178da..2895126f93b 100644
--- a/src/java.base/share/classes/java/text/DigitList.java
+++ b/src/java.base/share/classes/java/text/DigitList.java
@@ -41,6 +41,9 @@ package java.text;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
+import java.nio.charset.StandardCharsets;
+
+import jdk.internal.access.SharedSecrets;
import jdk.internal.math.FloatingDecimal;
import jdk.internal.util.ArraysSupport;
@@ -103,9 +106,9 @@ final class DigitList implements Cloneable {
*/
public int decimalAt = 0;
public int count = 0;
- public char[] digits = new char[MAX_COUNT];
+ public byte[] digits = new byte[MAX_COUNT];
- private char[] data;
+ private byte[] data;
private RoundingMode roundingMode = RoundingMode.HALF_EVEN;
private boolean isNegative = false;
@@ -154,11 +157,11 @@ final class DigitList implements Cloneable {
*/
public void append(char digit) {
if (count == digits.length) {
- char[] data = new char[ArraysSupport.newLength(count, 1, count)];
+ byte[] data = new byte[ArraysSupport.newLength(count, 1, count)];
System.arraycopy(digits, 0, data, 0, count);
digits = data;
}
- digits[count++] = digit;
+ digits[count++] = (byte) digit;
}
/**
@@ -188,7 +191,7 @@ final class DigitList implements Cloneable {
// Parse as unsigned to handle Long.MIN_VALUE, which is the one NEGATIVE value
// we represent. If we tried to just pass the digits off to parseLong,
// we'd get a parse failure.
- long v = Long.parseUnsignedLong(new String(digits, 0, count));
+ long v = Long.parseUnsignedLong(new String(digits, 0, count, StandardCharsets.ISO_8859_1));
if (v < 0) {
if (v == Long.MIN_VALUE) {
return Long.MIN_VALUE;
@@ -209,15 +212,20 @@ final class DigitList implements Cloneable {
* unlike BigDecimal("").
*/
public BigDecimal getBigDecimal() {
+ int count = this.count;
if (count == 0) {
return BigDecimal.valueOf(0, -decimalAt);
}
- if (decimalAt == count) {
- return new BigDecimal(digits, 0, count);
- } else {
- return new BigDecimal(digits, 0, count).scaleByPowerOfTen(decimalAt - count);
- }
+ char[] chars = new char[count];
+ SharedSecrets.getJavaLangAccess()
+ .inflateBytesToChars(digits, 0, chars, 0, count);
+ BigDecimal value = new BigDecimal(chars, 0, count);
+ if (decimalAt == count) {
+ return value;
+ } else {
+ return value.scaleByPowerOfTen(decimalAt - count);
+ }
}
/**
@@ -256,7 +264,7 @@ final class DigitList implements Cloneable {
// The number will overflow if it is larger than 9223372036854775807
// or smaller than -9223372036854775808.
for (int i=0; i max) return false;
if (dig < max) return true;
}
@@ -317,9 +325,10 @@ final class DigitList implements Cloneable {
boolean hasBeenRoundedUp = fdConverter.digitsRoundedUp();
boolean valueExactAsDecimal = fdConverter.decimalDigitsExact();
assert !fdConverter.isExceptional();
- String digitsString = fdConverter.toJavaFormatString();
- set(isNegative, digitsString,
+ byte[] chars = getDataChars(26);
+ int len = fdConverter.getChars(chars);
+ set(isNegative, chars, len,
hasBeenRoundedUp, valueExactAsDecimal,
maximumDigits, fixedPoint);
}
@@ -331,14 +340,11 @@ final class DigitList implements Cloneable {
* @param valueExactAsDecimal whether or not collected digits provide
* an exact decimal representation of the value.
*/
- private void set(boolean isNegative, String s,
+ private void set(boolean isNegative, byte[] source, int len,
boolean roundedUp, boolean valueExactAsDecimal,
int maximumDigits, boolean fixedPoint) {
this.isNegative = isNegative;
- int len = s.length();
- char[] source = getDataChars(len);
- s.getChars(0, len, source, 0);
decimalAt = -1;
count = 0;
@@ -349,7 +355,7 @@ final class DigitList implements Cloneable {
boolean nonZeroDigitSeen = false;
for (int i = 0; i < len; ) {
- char c = source[i++];
+ byte c = source[i++];
if (c == '.') {
decimalAt = count;
} else if (c == 'e' || c == 'E') {
@@ -633,7 +639,7 @@ final class DigitList implements Cloneable {
int left = MAX_COUNT;
int right;
while (source > 0) {
- digits[--left] = (char)('0' + (source % 10));
+ digits[--left] = (byte)('0' + (source % 10));
source /= 10;
}
decimalAt = MAX_COUNT - left;
@@ -661,11 +667,15 @@ final class DigitList implements Cloneable {
* @param fixedPoint If true, then maximumDigits is the maximum
* fractional digits to be converted. If false, total digits.
*/
+ @SuppressWarnings("deprecation")
void set(boolean isNegative, BigDecimal source, int maximumDigits, boolean fixedPoint) {
String s = source.toString();
extendDigits(s.length());
- set(isNegative, s,
+ int len = s.length();
+ byte[] chars = getDataChars(len);
+ s.getBytes(0, len, chars, 0);
+ set(isNegative, chars, len,
false, true,
maximumDigits, fixedPoint);
}
@@ -678,12 +688,13 @@ final class DigitList implements Cloneable {
* If maximumDigits is lower than the number of significant digits
* in source, the representation will be rounded. Ignored if <= 0.
*/
+ @SuppressWarnings("deprecation")
void set(boolean isNegative, BigInteger source, int maximumDigits) {
this.isNegative = isNegative;
String s = source.toString();
int len = s.length();
extendDigits(len);
- s.getChars(0, len, digits, 0);
+ s.getBytes(0, len, digits, 0);
decimalAt = len;
int right = len - 1;
@@ -734,7 +745,7 @@ final class DigitList implements Cloneable {
public Object clone() {
try {
DigitList other = (DigitList) super.clone();
- char[] newDigits = new char[digits.length];
+ byte[] newDigits = new byte[digits.length];
System.arraycopy(digits, 0, newDigits, 0, digits.length);
other.digits = newDigits;
@@ -749,8 +760,8 @@ final class DigitList implements Cloneable {
}
}
- private static int parseInt(char[] str, int offset, int strLen) {
- char c;
+ private static int parseInt(byte[] str, int offset, int strLen) {
+ byte c;
boolean positive = true;
if ((c = str[offset]) == '-') {
positive = false;
@@ -772,25 +783,25 @@ final class DigitList implements Cloneable {
}
// The digit part of -9223372036854775808L
- private static final char[] LONG_MIN_REP = "9223372036854775808".toCharArray();
+ private static final byte[] LONG_MIN_REP = "9223372036854775808".getBytes(StandardCharsets.ISO_8859_1);
public String toString() {
if (isZero()) {
return "0";
}
- return "0." + new String(digits, 0, count) + "x10^" + decimalAt;
+ return "0." + new String(digits, 0, count, StandardCharsets.ISO_8859_1) + "x10^" + decimalAt;
}
private void extendDigits(int len) {
if (len > digits.length) {
- digits = new char[len];
+ digits = new byte[len];
}
}
- private char[] getDataChars(int length) {
+ private byte[] getDataChars(int length) {
if (data == null || data.length < length) {
- data = new char[length];
+ data = new byte[length];
}
return data;
}
diff --git a/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java b/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java
index 168f76fad8f..32399310bd3 100644
--- a/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java
+++ b/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java
@@ -60,44 +60,6 @@ public class FloatingDecimal{
static final int INT_DECIMAL_DIGITS = 9;
- /**
- * Converts a double precision floating point value to a String.
- *
- * @param d The double precision value.
- * @return The value converted to a String.
- */
- public static String toJavaFormatString(double d) {
- return getBinaryToASCIIConverter(d).toJavaFormatString();
- }
-
- /**
- * Converts a single precision floating point value to a String.
- *
- * @param f The single precision value.
- * @return The value converted to a String.
- */
- public static String toJavaFormatString(float f) {
- return getBinaryToASCIIConverter(f).toJavaFormatString();
- }
-
- /**
- * Appends a double precision floating point value to an Appendable.
- * @param d The double precision value.
- * @param buf The Appendable with the value appended.
- */
- public static void appendTo(double d, Appendable buf) {
- getBinaryToASCIIConverter(d).appendTo(buf);
- }
-
- /**
- * Appends a single precision floating point value to an Appendable.
- * @param f The single precision value.
- * @param buf The Appendable with the value appended.
- */
- public static void appendTo(float f, Appendable buf) {
- getBinaryToASCIIConverter(f).appendTo(buf);
- }
-
/**
* Converts a String to a double precision floating point value.
*
@@ -131,7 +93,7 @@ public class FloatingDecimal{
* @param length Number of digits to use
* @return The double-precision value of the conversion
*/
- public static double parseDoubleSignlessDigits(int decExp, char[] digits, int length) {
+ public static double parseDoubleSignlessDigits(int decExp, byte[] digits, int length) {
return readDoubleSignlessDigits(decExp, digits, length).doubleValue();
}
@@ -140,17 +102,7 @@ public class FloatingDecimal{
* values into an ASCII String representation.
*/
public interface BinaryToASCIIConverter {
- /**
- * Converts a floating point value into an ASCII String.
- * @return The value converted to a String.
- */
- String toJavaFormatString();
-
- /**
- * Appends a floating point value to an Appendable.
- * @param buf The Appendable to receive the value.
- */
- void appendTo(Appendable buf);
+ int getChars(byte[] result);
/**
* Retrieves the decimal exponent most closely corresponding to this value.
@@ -209,19 +161,10 @@ public class FloatingDecimal{
}
@Override
- public String toJavaFormatString() {
- return image;
- }
-
- @Override
- public void appendTo(Appendable buf) {
- if (buf instanceof StringBuilder) {
- ((StringBuilder) buf).append(image);
- } else if (buf instanceof StringBuffer) {
- ((StringBuffer) buf).append(image);
- } else {
- assert false;
- }
+ @SuppressWarnings("deprecation")
+ public int getChars(byte[] chars) {
+ image.getBytes(0, image.length(), chars, 0);
+ return image.length();
}
@Override
@@ -261,8 +204,8 @@ public class FloatingDecimal{
private static final BinaryToASCIIConverter B2AC_POSITIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer(INFINITY_REP, false);
private static final BinaryToASCIIConverter B2AC_NEGATIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer("-" + INFINITY_REP, true);
private static final BinaryToASCIIConverter B2AC_NOT_A_NUMBER = new ExceptionalBinaryToASCIIBuffer(NAN_REP, false);
- private static final BinaryToASCIIConverter B2AC_POSITIVE_ZERO = new BinaryToASCIIBuffer(false, new char[]{'0'});
- private static final BinaryToASCIIConverter B2AC_NEGATIVE_ZERO = new BinaryToASCIIBuffer(true, new char[]{'0'});
+ private static final BinaryToASCIIConverter B2AC_POSITIVE_ZERO = new BinaryToASCIIBuffer(false, new byte[]{'0'});
+ private static final BinaryToASCIIConverter B2AC_NEGATIVE_ZERO = new BinaryToASCIIBuffer(true, new byte[]{'0'});
/**
* A buffered implementation of BinaryToASCIIConverter.
@@ -272,8 +215,7 @@ public class FloatingDecimal{
private int decExponent;
private int firstDigitIndex;
private int nDigits;
- private final char[] digits;
- private final char[] buffer = new char[26];
+ private final byte[] digits;
//
// The fields below provide additional information about the result of
@@ -293,13 +235,13 @@ public class FloatingDecimal{
* BinaryToASCIIBuffer may be thread-local and reused
*/
BinaryToASCIIBuffer(){
- this.digits = new char[20];
+ this.digits = new byte[20];
}
/**
* Creates a specialized value (positive and negative zeros).
*/
- BinaryToASCIIBuffer(boolean isNegative, char[] digits){
+ BinaryToASCIIBuffer(boolean isNegative, byte[] digits){
this.isNegative = isNegative;
this.decExponent = 0;
this.digits = digits;
@@ -307,24 +249,6 @@ public class FloatingDecimal{
this.nDigits = digits.length;
}
- @Override
- public String toJavaFormatString() {
- int len = getChars(buffer);
- return new String(buffer, 0, len);
- }
-
- @Override
- public void appendTo(Appendable buf) {
- int len = getChars(buffer);
- if (buf instanceof StringBuilder) {
- ((StringBuilder) buf).append(buffer, 0, len);
- } else if (buf instanceof StringBuffer) {
- ((StringBuffer) buf).append(buffer, 0, len);
- } else {
- assert false;
- }
- }
-
@Override
public int getDecimalExponent() {
return decExponent;
@@ -403,12 +327,12 @@ public class FloatingDecimal{
ivalue /= 10;
}
while ( ivalue != 0){
- digits[digitno--] = (char)(c+'0');
+ digits[digitno--] = (byte)(c+'0');
decExponent++;
c = ivalue%10;
ivalue /= 10;
}
- digits[digitno] = (char)(c+'0');
+ digits[digitno] = (byte)(c+'0');
} else {
// same algorithm as above (same bugs, too )
// but using long arithmetic.
@@ -420,12 +344,12 @@ public class FloatingDecimal{
lvalue /= 10L;
}
while ( lvalue != 0L ){
- digits[digitno--] = (char)(c+'0');
+ digits[digitno--] = (byte) (c+'0');
decExponent++;
c = (int)(lvalue%10L);
lvalue /= 10;
}
- digits[digitno] = (char)(c+'0');
+ digits[digitno] = (byte)(c+'0');
}
this.decExponent = decExponent+1;
this.firstDigitIndex = digitno;
@@ -626,7 +550,7 @@ public class FloatingDecimal{
// oops. Usually ignore leading zero.
decExp--;
} else {
- digits[ndigit++] = (char)('0' + q);
+ digits[ndigit++] = (byte)('0' + q);
}
//
// HACK! Java spec sez that we always have at least
@@ -654,7 +578,7 @@ public class FloatingDecimal{
low = true;
high = true;
}
- digits[ndigit++] = (char)('0' + q);
+ digits[ndigit++] = (byte)('0' + q);
}
lowDigitDifference = (b<<1) - tens;
exactDecimalConversion = (b == 0);
@@ -680,7 +604,7 @@ public class FloatingDecimal{
// oops. Usually ignore leading zero.
decExp--;
} else {
- digits[ndigit++] = (char)('0' + q);
+ digits[ndigit++] = (byte)('0' + q);
}
//
// HACK! Java spec sez that we always have at least
@@ -708,7 +632,7 @@ public class FloatingDecimal{
low = true;
high = true;
}
- digits[ndigit++] = (char)('0' + q);
+ digits[ndigit++] = (byte)('0' + q);
}
lowDigitDifference = (b<<1) - tens;
exactDecimalConversion = (b == 0);
@@ -741,7 +665,7 @@ public class FloatingDecimal{
// oops. Usually ignore leading zero.
decExp--;
} else {
- digits[ndigit++] = (char)('0' + q);
+ digits[ndigit++] = (byte)('0' + q);
}
//
// HACK! Java spec sez that we always have at least
@@ -758,7 +682,7 @@ public class FloatingDecimal{
Mval = Mval.multBy10(); //Mval = Mval.mult( 10 );
low = (Bval.cmp( Mval ) < 0);
high = tenSval.addAndCmp(Bval,Mval)<=0;
- digits[ndigit++] = (char)('0' + q);
+ digits[ndigit++] = (byte)('0' + q);
}
if ( high && low ){
Bval = Bval.leftShift(1);
@@ -812,7 +736,7 @@ public class FloatingDecimal{
}
// else fall through.
}
- digits[i] = (char) (q + 1);
+ digits[i] = (byte) (q + 1);
decimalDigitsRoundedUp = true;
}
@@ -845,19 +769,8 @@ public class FloatingDecimal{
}
}
- private static int insignificantDigits(long insignificant) {
- int i;
- for ( i = 0; insignificant >= 10L; i++ ) {
- insignificant /= 10L;
- }
- return i;
- }
-
/**
* Calculates
- *
- * insignificantDigitsForPow2(v) == insignificantDigits(1L<
*/
private static int insignificantDigitsForPow2(int p2) {
if (p2 > 1 && p2 < insignificantDigitsNumber.length) {
@@ -913,7 +826,14 @@ public class FloatingDecimal{
61,
};
- private int getChars(char[] result) {
+ /**
+ * Converts the decimal representation of a floating-point number into its
+ * ASCII character representation and stores it in the provided byte array.
+ *
+ * @param result the byte array to store the ASCII representation, must have length at least 26
+ * @return the number of characters written to the result array
+ */
+ public int getChars(byte[] result) {
assert nDigits <= 19 : nDigits; // generous bound on size of nDigits
int i = 0;
if (isNegative) {
@@ -927,7 +847,7 @@ public class FloatingDecimal{
i += charLength;
if (charLength < decExponent) {
charLength = decExponent - charLength;
- Arrays.fill(result,i,i+charLength,'0');
+ Arrays.fill(result, i, i + charLength, (byte) '0');
i += charLength;
result[i++] = '.';
result[i++] = '0';
@@ -935,7 +855,7 @@ public class FloatingDecimal{
result[i++] = '.';
if (charLength < nDigits) {
int t = nDigits - charLength;
- System.arraycopy(digits, firstDigitIndex+charLength, result, i, t);
+ System.arraycopy(digits, firstDigitIndex + charLength, result, i, t);
i += t;
} else {
result[i++] = '0';
@@ -945,7 +865,7 @@ public class FloatingDecimal{
result[i++] = '0';
result[i++] = '.';
if (decExponent != 0) {
- Arrays.fill(result, i, i-decExponent, '0');
+ Arrays.fill(result, i, i-decExponent, (byte) '0');
i -= decExponent;
}
System.arraycopy(digits, firstDigitIndex, result, i, nDigits);
@@ -969,15 +889,15 @@ public class FloatingDecimal{
}
// decExponent has 1, 2, or 3, digits
if (e <= 9) {
- result[i++] = (char) (e + '0');
+ result[i++] = (byte) (e + '0');
} else if (e <= 99) {
- result[i++] = (char) (e / 10 + '0');
- result[i++] = (char) (e % 10 + '0');
+ result[i++] = (byte) (e / 10 + '0');
+ result[i++] = (byte) (e % 10 + '0');
} else {
- result[i++] = (char) (e / 100 + '0');
+ result[i++] = (byte) (e / 100 + '0');
e %= 100;
- result[i++] = (char) (e / 10 + '0');
- result[i++] = (char) (e % 10 + '0');
+ result[i++] = (byte) (e / 10 + '0');
+ result[i++] = (byte) (e % 10 + '0');
}
}
return i;
@@ -1043,10 +963,10 @@ public class FloatingDecimal{
* A buffered implementation of ASCIIToBinaryConverter.
*/
static class ASCIIToBinaryBuffer implements ASCIIToBinaryConverter {
- boolean isNegative;
- int decExponent;
- byte[] digits;
- int nDigits;
+ final boolean isNegative;
+ final int decExponent;
+ final byte[] digits;
+ int nDigits;
ASCIIToBinaryBuffer( boolean negSign, int decExponent, byte[] digits, int n)
{
@@ -1765,10 +1685,10 @@ public class FloatingDecimal{
buf.decimalDigitsRoundedUp = dec.getAway();
long f = dec.getSignificand();
- char[] digits = buf.digits;
+ byte[] digits = buf.digits;
for (int i = buf.nDigits - 1; i >= 0; --i) {
long q = f / 10;
- digits[i] = (char) ((f - 10 * q) + '0');
+ digits[i] = (byte) ((f - 10 * q) + '0');
f = q;
}
return buf;
@@ -1819,58 +1739,14 @@ public class FloatingDecimal{
return buf;
}
- private static BinaryToASCIIConverter getBinaryToASCIIConverter(float f) {
- int fBits = Float.floatToRawIntBits( f );
- boolean isNegative = (fBits&FloatConsts.SIGN_BIT_MASK) != 0;
- int fractBits = fBits&FloatConsts.SIGNIF_BIT_MASK;
- int binExp = (fBits&FloatConsts.EXP_BIT_MASK) >> SINGLE_EXP_SHIFT;
- // Discover obvious special cases of NaN and Infinity.
- if ( binExp == (FloatConsts.EXP_BIT_MASK>>SINGLE_EXP_SHIFT) ) {
- if ( fractBits == 0L ){
- return isNegative ? B2AC_NEGATIVE_INFINITY : B2AC_POSITIVE_INFINITY;
- } else {
- return B2AC_NOT_A_NUMBER;
- }
- }
- // Finish unpacking
- // Normalize denormalized numbers.
- // Insert assumed high-order bit for normalized numbers.
- // Subtract exponent bias.
- int nSignificantBits;
- if ( binExp == 0 ){
- if ( fractBits == 0 ){
- // not a denorm, just a 0!
- return isNegative ? B2AC_NEGATIVE_ZERO : B2AC_POSITIVE_ZERO;
- }
- int leadingZeros = Integer.numberOfLeadingZeros(fractBits);
- int shift = leadingZeros-(31-SINGLE_EXP_SHIFT);
- fractBits <<= shift;
- binExp = 1 - shift;
- nSignificantBits = 32 - leadingZeros; // recall binExp is - shift count.
- } else {
- fractBits |= SINGLE_FRACT_HOB;
- nSignificantBits = SINGLE_EXP_SHIFT+1;
- }
- binExp -= FloatConsts.EXP_BIAS;
- BinaryToASCIIBuffer buf = getBinaryToASCIIBuffer();
- buf.setSign(isNegative);
- // call the routine that actually does all the hard work.
- buf.dtoa(binExp, ((long)fractBits)<<(EXP_SHIFT-SINGLE_EXP_SHIFT), nSignificantBits, true);
- return buf;
- }
-
- static ASCIIToBinaryConverter readDoubleSignlessDigits(int decExp, char[] digits, int length) {
+ static ASCIIToBinaryConverter readDoubleSignlessDigits(int decExp, byte[] digits, int length) {
// Prevent an extreme negative exponent from causing overflow issues in doubleValue().
// Large positive values are handled within doubleValue();
if (decExp < MIN_DECIMAL_EXPONENT) {
return A2BC_POSITIVE_ZERO;
}
- byte[] buf = new byte[length];
- for (int i = 0; i < length; i++) {
- buf[i] = (byte) digits[i];
- }
- return new ASCIIToBinaryBuffer(false, decExp, buf, length);
+ return new ASCIIToBinaryBuffer(false, decExp, digits, length);
}
/**
From e916ce8ce9af906cf86f1801fcb43e08f8188665 Mon Sep 17 00:00:00 2001
From: altrisi
Date: Fri, 22 Aug 2025 17:10:40 +0000
Subject: [PATCH 38/54] 8365878: jshell TOOLING's javap should use binary names
Reviewed-by: liach, cstein
---
.../jdk/jshell/tool/resources/TOOLING.jsh | 4 +--
test/langtools/jdk/jshell/ToolingTest.java | 31 +++++++++++++++++--
2 files changed, 31 insertions(+), 4 deletions(-)
diff --git a/src/jdk.jshell/share/classes/jdk/jshell/tool/resources/TOOLING.jsh b/src/jdk.jshell/share/classes/jdk/jshell/tool/resources/TOOLING.jsh
index b97b6341cfa..16436514383 100644
--- a/src/jdk.jshell/share/classes/jdk/jshell/tool/resources/TOOLING.jsh
+++ b/src/jdk.jshell/share/classes/jdk/jshell/tool/resources/TOOLING.jsh
@@ -8,9 +8,9 @@ void jmod(String... args) { run("jmod", args); }
void jpackage(String... args) { run("jpackage", args); }
void javap(Class> type) throws Exception {
+ if (type.isPrimitive() || type.isHidden() || type.isArray()) throw new IllegalArgumentException("Type has no class file: " + type);
try {
- var name = type.getCanonicalName();
- if (name == null) throw new IllegalArgumentException("Type not supported: " + type);
+ var name = type.getName();
if (type == Class.forName(name, false, ClassLoader.getSystemClassLoader())) {
run("javap", "-c", "-v", "-s", name);
return;
diff --git a/test/langtools/jdk/jshell/ToolingTest.java b/test/langtools/jdk/jshell/ToolingTest.java
index b36fdc03c19..f0d0e3f68eb 100644
--- a/test/langtools/jdk/jshell/ToolingTest.java
+++ b/test/langtools/jdk/jshell/ToolingTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 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
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8306560
+ * @bug 8306560 8365878
* @summary Tests for snippets and methods defined in TOOLING.jsh
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
@@ -79,4 +79,31 @@ public class ToolingTest extends ReplToolTesting {
)
);
}
+
+ @Test
+ public void testDisassembleBuiltinInnerClass() {
+ test(
+ a -> assertCommand(a, "/open TOOLING",
+ ""),
+ a -> assertCommandUserOutputContains(a, "javap(Base64.Decoder.class)",
+ "Classfile jrt:/java.base/java/util/Base64$Decoder.class",
+ "class java.util.Base64$Decoder",
+ "SourceFile: \"Base64.java\"")
+ );
+ }
+
+ @Test
+ public void testDisassembleAnonymousClass() {
+ test(
+ a -> assertCommand(a, "Object o() {return new ArrayList<>(){ };}", // must be in a method or it won't be anonymous
+ "| created method o()"),
+ a -> assertCommand(a, "/open TOOLING",
+ ""),
+ a -> assertCommandUserOutputContains(a, "javap(o().getClass())",
+ "Classfile ", // Classfile /.../TOOLING-16063368030094702464.class
+ " extends java.util.ArrayList", // class REPL.$JShell$22$1 extends java.util.ArrayList
+ "SourceFile: \"$JShell$" // SourceFile: "$JShell$22.java"
+ )
+ );
+ }
}
From 19882220ecb3eeaef763ccbb0aa4d7760c906222 Mon Sep 17 00:00:00 2001
From: Francesco Andreuzzi
Date: Fri, 22 Aug 2025 17:36:52 +0000
Subject: [PATCH 39/54] 8365829: Multiple definitions of static 'phase_names'
Reviewed-by: kbarrett
---
src/hotspot/share/opto/phasetype.cpp | 46 ++++++++++++++++++++++++++++
src/hotspot/share/opto/phasetype.hpp | 35 ++++++---------------
2 files changed, 56 insertions(+), 25 deletions(-)
create mode 100644 src/hotspot/share/opto/phasetype.cpp
diff --git a/src/hotspot/share/opto/phasetype.cpp b/src/hotspot/share/opto/phasetype.cpp
new file mode 100644
index 00000000000..3e18bd089ba
--- /dev/null
+++ b/src/hotspot/share/opto/phasetype.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ *
+ */
+
+#include "phasetype.hpp"
+
+const char* const CompilerPhaseTypeHelper::_phase_descriptions[] = {
+#define array_of_labels(name, description) description,
+ COMPILER_PHASES(array_of_labels)
+#undef array_of_labels
+};
+
+const char* const CompilerPhaseTypeHelper::_phase_names[] = {
+#define array_of_labels(name, description) #name,
+ COMPILER_PHASES(array_of_labels)
+#undef array_of_labels
+};
+
+CompilerPhaseType CompilerPhaseTypeHelper::find_phase(const char* str) {
+ for (int i = 0; i < PHASE_NUM_TYPES; i++) {
+ if (strcmp(CompilerPhaseTypeHelper::_phase_names[i], str) == 0) {
+ return (CompilerPhaseType)i;
+ }
+ }
+ return PHASE_NONE;
+}
diff --git a/src/hotspot/share/opto/phasetype.hpp b/src/hotspot/share/opto/phasetype.hpp
index 942850cf892..5c733c7dc0a 100644
--- a/src/hotspot/share/opto/phasetype.hpp
+++ b/src/hotspot/share/opto/phasetype.hpp
@@ -138,36 +138,21 @@ enum CompilerPhaseType {
};
#undef table_entry
-static const char* phase_descriptions[] = {
-#define array_of_labels(name, description) description,
- COMPILER_PHASES(array_of_labels)
-#undef array_of_labels
-};
-
-static const char* phase_names[] = {
-#define array_of_labels(name, description) #name,
- COMPILER_PHASES(array_of_labels)
-#undef array_of_labels
-};
-
class CompilerPhaseTypeHelper {
- public:
+ private:
+ static const char* const _phase_descriptions[];
+ static const char* const _phase_names[];
+
+ public:
static const char* to_name(CompilerPhaseType cpt) {
- return phase_names[cpt];
+ return _phase_names[cpt];
}
static const char* to_description(CompilerPhaseType cpt) {
- return phase_descriptions[cpt];
+ return _phase_descriptions[cpt];
}
-};
-static CompilerPhaseType find_phase(const char* str) {
- for (int i = 0; i < PHASE_NUM_TYPES; i++) {
- if (strcmp(phase_names[i], str) == 0) {
- return (CompilerPhaseType)i;
- }
- }
- return PHASE_NONE;
-}
+ static CompilerPhaseType find_phase(const char* str);
+};
class PhaseNameValidator {
private:
@@ -183,7 +168,7 @@ class PhaseNameValidator {
{
for (StringUtils::CommaSeparatedStringIterator iter(option); *iter != nullptr && _valid; ++iter) {
- CompilerPhaseType cpt = find_phase(*iter);
+ CompilerPhaseType cpt = CompilerPhaseTypeHelper::find_phase(*iter);
if (PHASE_NONE == cpt) {
const size_t len = MIN2(strlen(*iter), 63) + 1; // cap len to a value we know is enough for all phase descriptions
_bad = NEW_C_HEAP_ARRAY(char, len, mtCompiler);
From ae0dac43c09377c87e9b0452618a5b32c8568150 Mon Sep 17 00:00:00 2001
From: Naoto Sato
Date: Fri, 22 Aug 2025 17:50:22 +0000
Subject: [PATCH 40/54] 8361613: System.console() should only be available for
interactive terminal
Reviewed-by: jlahoda, smarks, alanb
---
.../share/classes/java/lang/System.java | 3 +-
.../org/jline/JdkConsoleProviderImpl.java | 2 +-
.../java/io/Console/DefaultCharsetTest.java | 69 +++++--
test/jdk/java/io/Console/LocaleTest.java | 127 ++++++------
.../java/io/Console/ModuleSelectionTest.java | 69 +++++--
test/jdk/java/io/Console/defaultCharset.exp | 32 ++++
test/jdk/java/io/Console/locale.exp | 37 ++++
test/jdk/java/io/Console/moduleSelection.exp | 30 +++
test/jdk/java/lang/IO/IO.java | 54 +-----
.../jline/JLineConsoleProviderTest.java | 30 ++-
.../jline/LazyJdkConsoleProvider.java | 40 ++--
.../jdk/internal/jline/RedirectedStdOut.java | 181 ------------------
12 files changed, 330 insertions(+), 344 deletions(-)
create mode 100644 test/jdk/java/io/Console/defaultCharset.exp
create mode 100644 test/jdk/java/io/Console/locale.exp
create mode 100644 test/jdk/java/io/Console/moduleSelection.exp
delete mode 100644 test/jdk/jdk/internal/jline/RedirectedStdOut.java
diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java
index f046ed4111a..a40c27bbf47 100644
--- a/src/java.base/share/classes/java/lang/System.java
+++ b/src/java.base/share/classes/java/lang/System.java
@@ -237,10 +237,11 @@ public final class System {
private static volatile Console cons;
/**
- * Returns the unique {@link java.io.Console Console} object associated
+ * Returns the unique {@link Console Console} object associated
* with the current Java virtual machine, if any.
*
* @return The system console, if any, otherwise {@code null}.
+ * @see Console
*
* @since 1.6
*/
diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java
index 365f6d1e68a..4e4751b264e 100644
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java
@@ -50,7 +50,7 @@ public class JdkConsoleProviderImpl implements JdkConsoleProvider {
*/
@Override
public JdkConsole console(boolean isTTY, Charset inCharset, Charset outCharset) {
- return new LazyDelegatingJdkConsoleImpl(inCharset, outCharset);
+ return isTTY ? new LazyDelegatingJdkConsoleImpl(inCharset, outCharset) : null;
}
private static class LazyDelegatingJdkConsoleImpl implements JdkConsole {
diff --git a/test/jdk/java/io/Console/DefaultCharsetTest.java b/test/jdk/java/io/Console/DefaultCharsetTest.java
index 0fca8a3cc3f..981d92ce282 100644
--- a/test/jdk/java/io/Console/DefaultCharsetTest.java
+++ b/test/jdk/java/io/Console/DefaultCharsetTest.java
@@ -21,33 +21,66 @@
* questions.
*/
-import org.junit.jupiter.api.Test;
-import static org.junit.jupiter.api.Assertions.*;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+import org.junit.jupiter.api.Assumptions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import static jdk.test.lib.Utils.*;
/**
* @test
- * @bug 8341975 8351435
+ * @bug 8341975 8351435 8361613
* @summary Tests the default charset. It should honor `stdout.encoding`
* which should be the same as System.out.charset()
- * @modules jdk.internal.le
- * @run junit/othervm -Djdk.console=jdk.internal.le -Dstdout.encoding=UTF-8 DefaultCharsetTest
- * @run junit/othervm -Djdk.console=jdk.internal.le -Dstdout.encoding=ISO-8859-1 DefaultCharsetTest
- * @run junit/othervm -Djdk.console=jdk.internal.le -Dstdout.encoding=US-ASCII DefaultCharsetTest
- * @run junit/othervm -Djdk.console=jdk.internal.le -Dstdout.encoding=foo DefaultCharsetTest
- * @run junit/othervm -Djdk.console=jdk.internal.le DefaultCharsetTest
+ * @requires (os.family == "linux") | (os.family == "mac")
+ * @library /test/lib
+ * @build jdk.test.lib.Utils
+ * jdk.test.lib.JDKToolFinder
+ * jdk.test.lib.process.ProcessTools
+ * @run junit DefaultCharsetTest
*/
public class DefaultCharsetTest {
- @Test
- public void testDefaultCharset() {
+ @BeforeAll
+ static void checkExpectAvailability() {
+ // check "expect" command availability
+ var expect = Paths.get("/usr/bin/expect");
+ Assumptions.assumeTrue(Files.exists(expect) && Files.isExecutable(expect),
+ "'" + expect + "' not found. Test ignored.");
+ }
+ @ParameterizedTest
+ @ValueSource(strings = {"UTF-8", "ISO-8859-1", "US-ASCII", "foo", ""})
+ void testDefaultCharset(String stdoutEncoding) throws Exception {
+ // invoking "expect" command
+ OutputAnalyzer oa = ProcessTools.executeProcess(
+ "expect",
+ "-n",
+ TEST_SRC + "/defaultCharset.exp",
+ TEST_CLASSES,
+ TEST_JDK + "/bin/java",
+ "-Dstdout.encoding=" + stdoutEncoding,
+ getClass().getName());
+ oa.reportDiagnosticSummary();
+ oa.shouldHaveExitValue(0);
+ }
+
+ public static void main(String... args) {
var stdoutEncoding = System.getProperty("stdout.encoding");
var sysoutCharset = System.out.charset();
var consoleCharset = System.console().charset();
- System.out.println("""
- stdout.encoding = %s
- System.out.charset() = %s
- System.console().charset() = %s
- """.formatted(stdoutEncoding, sysoutCharset.name(), consoleCharset.name()));
- assertEquals(consoleCharset, sysoutCharset,
- "Charsets for System.out and Console differ for stdout.encoding: %s".formatted(stdoutEncoding));
+ System.out.printf("""
+ stdout.encoding = %s
+ System.out.charset() = %s
+ System.console().charset() = %s
+ """, stdoutEncoding, sysoutCharset.name(), consoleCharset.name());
+ if (!consoleCharset.equals(sysoutCharset)) {
+ System.err.printf("Charsets for System.out and Console differ for stdout.encoding: %s%n", stdoutEncoding);
+ System.exit(-1);
+ }
}
}
diff --git a/test/jdk/java/io/Console/LocaleTest.java b/test/jdk/java/io/Console/LocaleTest.java
index 1cab84a9af7..e9a281749b1 100644
--- a/test/jdk/java/io/Console/LocaleTest.java
+++ b/test/jdk/java/io/Console/LocaleTest.java
@@ -21,28 +21,40 @@
* questions.
*/
-import java.io.File;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.function.Predicate;
+import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
+import org.junit.jupiter.api.Assumptions;
+import org.junit.jupiter.api.Test;
+
+import static jdk.test.lib.Utils.*;
/**
* @test
- * @bug 8330276 8351435
+ * @bug 8330276 8351435 8361613
* @summary Tests Console methods that have Locale as an argument
+ * @requires (os.family == "linux") | (os.family == "mac")
* @library /test/lib
- * @modules jdk.internal.le jdk.localedata
+ * @build jdk.test.lib.Utils
+ * jdk.test.lib.JDKToolFinder
+ * jdk.test.lib.process.ProcessTools
+ * @modules jdk.localedata
+ * @run junit LocaleTest
*/
public class LocaleTest {
- private static Calendar TODAY = new GregorianCalendar(2024, Calendar.APRIL, 22);
- private static String FORMAT = "%1$tY-%1$tB-%1$te %1$tA";
+ private static final Calendar TODAY = new GregorianCalendar(2024, Calendar.APRIL, 22);
+ private static final String FORMAT = "%1$tY-%1$tB-%1$te %1$tA";
// We want to limit the expected strings within US-ASCII charset, as
// the native encoding is determined as such, which is used by
// the `Process` class under jtreg environment.
- private static List EXPECTED = List.of(
+ private static final List EXPECTED = List.of(
String.format(Locale.UK, FORMAT, TODAY),
String.format(Locale.FRANCE, FORMAT, TODAY),
String.format(Locale.GERMANY, FORMAT, TODAY),
@@ -53,56 +65,61 @@ public class LocaleTest {
String.format((Locale)null, FORMAT, TODAY)
);
- public static void main(String... args) throws Throwable {
- if (args.length == 0) {
- // no arg will launch the child process that actually perform tests
- var pb = ProcessTools.createTestJavaProcessBuilder(
- "-Djdk.console=jdk.internal.le",
- "LocaleTest", "dummy");
- var input = new File(System.getProperty("test.src", "."), "input.txt");
- pb.redirectInput(input);
- var oa = ProcessTools.executeProcess(pb);
- if (oa.getExitValue() == -1) {
- System.out.println("System.console() returns null. Ignoring the test.");
- } else {
- var output = oa.asLines();
- var resultText =
- """
- Actual output: %s
- Expected output: %s
- """.formatted(output, EXPECTED);
- if (!output.equals(EXPECTED)) {
- throw new RuntimeException("Standard out had unexpected strings:\n" + resultText);
- } else {
- oa.shouldHaveExitValue(0);
- System.out.println("Formatting with explicit Locale succeeded.\n" + resultText);
- }
- }
- } else {
- var con = System.console();
- if (con != null) {
- // tests these additional methods that take a Locale
- con.format(Locale.UK, FORMAT, TODAY);
- con.printf("\n");
- con.printf(Locale.FRANCE, FORMAT, TODAY);
- con.printf("\n");
- con.readLine(Locale.GERMANY, FORMAT, TODAY);
- con.printf("\n");
- con.readPassword(Locale.of("es"), FORMAT, TODAY);
- con.printf("\n");
+ @Test
+ void testLocale() throws Exception {
+ // check "expect" command availability
+ var expect = Paths.get("/usr/bin/expect");
+ Assumptions.assumeTrue(Files.exists(expect) && Files.isExecutable(expect),
+ "'" + expect + "' not found. Test ignored.");
- // tests null locale
- con.format((Locale)null, FORMAT, TODAY);
- con.printf("\n");
- con.printf((Locale)null, FORMAT, TODAY);
- con.printf("\n");
- con.readLine((Locale)null, FORMAT, TODAY);
- con.printf("\n");
- con.readPassword((Locale)null, FORMAT, TODAY);
- } else {
- // Exit with -1
- System.exit(-1);
- }
+ // invoking "expect" command
+ OutputAnalyzer oa = ProcessTools.executeProcess(
+ "expect",
+ "-n",
+ TEST_SRC + "/locale.exp",
+ TEST_CLASSES,
+ TEST_JDK + "/bin/java",
+ getClass().getName());
+
+ var stdout =
+ oa.stdoutAsLines().stream().filter(Predicate.not(String::isEmpty)).toList();
+ var resultText =
+ """
+ Actual output: %s
+ Expected output: %s
+ """.formatted(stdout, EXPECTED);
+ if (!stdout.equals(EXPECTED)) {
+ throw new RuntimeException("Standard out had unexpected strings:\n" + resultText);
+ } else {
+ oa.shouldHaveExitValue(0);
+ System.out.println("Formatting with explicit Locale succeeded.\n" + resultText);
+ }
+ }
+
+ public static void main(String... args) throws Throwable {
+ var con = System.console();
+ if (con != null) {
+ // tests these additional methods that take a Locale
+ con.format(Locale.UK, FORMAT, TODAY);
+ con.printf("\n");
+ con.printf(Locale.FRANCE, FORMAT, TODAY);
+ con.printf("\n");
+ con.readLine(Locale.GERMANY, FORMAT, TODAY);
+ con.printf("\n");
+ con.readPassword(Locale.of("es"), FORMAT, TODAY);
+ con.printf("\n");
+
+ // tests null locale
+ con.format((Locale)null, FORMAT, TODAY);
+ con.printf("\n");
+ con.printf((Locale)null, FORMAT, TODAY);
+ con.printf("\n");
+ con.readLine((Locale)null, FORMAT, TODAY);
+ con.printf("\n");
+ con.readPassword((Locale)null, FORMAT, TODAY);
+ } else {
+ // Exit with -1
+ System.exit(-1);
}
}
}
diff --git a/test/jdk/java/io/Console/ModuleSelectionTest.java b/test/jdk/java/io/Console/ModuleSelectionTest.java
index d9885699ebf..332acf83fbd 100644
--- a/test/jdk/java/io/Console/ModuleSelectionTest.java
+++ b/test/jdk/java/io/Console/ModuleSelectionTest.java
@@ -23,21 +23,71 @@
/**
* @test
- * @bug 8295803 8299689 8351435
+ * @bug 8295803 8299689 8351435 8361613
* @summary Tests System.console() returns correct Console (or null) from the expected
* module.
- * @modules java.base/java.io:+open
- * @run main/othervm ModuleSelectionTest java.base
- * @run main/othervm -Djdk.console=jdk.internal.le ModuleSelectionTest jdk.internal.le
- * @run main/othervm -Djdk.console=java.base ModuleSelectionTest java.base
- * @run main/othervm --limit-modules java.base ModuleSelectionTest java.base
+ * @library /test/lib
+ * @build jdk.test.lib.Utils
+ * jdk.test.lib.process.ProcessTools
+ * @run junit ModuleSelectionTest
*/
import java.io.Console;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.stream.Stream;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+import org.junit.jupiter.api.Assumptions;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import static jdk.test.lib.Utils.*;
public class ModuleSelectionTest {
+ private static Stream options() {
+ return Stream.of(
+ Arguments.of("-Djdk.console=foo", "java.base"),
+ Arguments.of("-Djdk.console=java.base", "java.base"),
+ Arguments.of("-Djdk.console=jdk.internal.le", "jdk.internal.le"),
+ Arguments.of("--limit-modules java.base", "java.base")
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("options")
+ void testNonTTY(String opts) throws Exception {
+ opts = opts +
+ " --add-opens java.base/java.io=ALL-UNNAMED ModuleSelectionTest null";
+ OutputAnalyzer output = ProcessTools.executeTestJava(opts.split(" "));
+ output.reportDiagnosticSummary();
+ output.shouldHaveExitValue(0);
+ }
+
+ @ParameterizedTest
+ @MethodSource("options")
+ void testTTY(String opts, String expected) throws Exception {
+ // check "expect" command availability
+ var expect = Paths.get("/usr/bin/expect");
+ Assumptions.assumeTrue(Files.exists(expect) && Files.isExecutable(expect),
+ "'" + expect + "' not found. Test ignored.");
+
+ opts = "expect -n " + TEST_SRC + "/moduleSelection.exp " +
+ TEST_CLASSES + " " +
+ expected + " " +
+ TEST_JDK + "/bin/java" +
+ " --add-opens java.base/java.io=ALL-UNNAMED "
+ + opts;
+ // invoking "expect" command
+ OutputAnalyzer output = ProcessTools.executeProcess(opts.split(" "));
+ output.reportDiagnosticSummary();
+ output.shouldHaveExitValue(0);
+ }
+
public static void main(String... args) throws Throwable {
var con = System.console();
var pc = Class.forName("java.io.ProxyingConsole");
@@ -49,10 +99,7 @@ public class ModuleSelectionTest {
.findGetter(pc, "delegate", jdkc)
.invoke(con) : null;
- var expected = switch (args[0]) {
- case "java.base" -> istty ? "java.base" : "null";
- default -> args[0];
- };
+ var expected = args[0];
var actual = con == null ? "null" : impl.getClass().getModule().getName();
if (!actual.equals(expected)) {
@@ -62,7 +109,7 @@ public class ModuleSelectionTest {
Actual: %s
""".formatted(expected, actual));
} else {
- System.out.printf("%s is the expected implementation. (tty: %s)\n", impl, istty);
+ System.out.printf("%s is the expected implementation. (tty: %s)\n", actual, istty);
}
}
}
diff --git a/test/jdk/java/io/Console/defaultCharset.exp b/test/jdk/java/io/Console/defaultCharset.exp
new file mode 100644
index 00000000000..5b1418db28c
--- /dev/null
+++ b/test/jdk/java/io/Console/defaultCharset.exp
@@ -0,0 +1,32 @@
+#
+# Copyright (c) 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.
+#
+
+# simply invoking java under expect command
+set classpath [lrange $argv 0 0]
+set java [lrange $argv 1 1]
+set stdoutProp [lrange $argv 2 2]
+set clsname [lrange $argv 3 3]
+eval spawn $java -classpath $classpath $stdoutProp $clsname
+expect eof
+set result [wait]
+exit [lindex $result 3]
diff --git a/test/jdk/java/io/Console/locale.exp b/test/jdk/java/io/Console/locale.exp
new file mode 100644
index 00000000000..a88ea43feac
--- /dev/null
+++ b/test/jdk/java/io/Console/locale.exp
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 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.
+#
+
+# simply invoking java under expect command
+set classpath [lrange $argv 0 0]
+set java [lrange $argv 1 1]
+set clsname [lrange $argv 2 2]
+eval spawn -noecho $java -classpath $classpath $clsname
+
+# sends CR 4 times (readLine x 2, readPassword x 2)
+send "\r"
+send "\r"
+send "\r"
+send "\r"
+expect eof
+set result [wait]
+exit [lindex $result 3]
diff --git a/test/jdk/java/io/Console/moduleSelection.exp b/test/jdk/java/io/Console/moduleSelection.exp
new file mode 100644
index 00000000000..2b44afe72e4
--- /dev/null
+++ b/test/jdk/java/io/Console/moduleSelection.exp
@@ -0,0 +1,30 @@
+#
+# Copyright (c) 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.
+#
+
+# simply invoking java under expect command
+set classpath [lrange $argv 0 0]
+set expected [lrange $argv 1 1]
+set java [lrange $argv 2 2]
+set opts [lrange $argv 3 end]
+eval spawn $java $opts -classpath $classpath ModuleSelectionTest $expected
+expect eof
diff --git a/test/jdk/java/lang/IO/IO.java b/test/jdk/java/lang/IO/IO.java
index dbb83db5f80..2b13657b58e 100644
--- a/test/jdk/java/lang/IO/IO.java
+++ b/test/jdk/java/lang/IO/IO.java
@@ -50,10 +50,9 @@ import static org.junit.jupiter.api.Assertions.*;
/*
* @test
- * @bug 8305457 8342936 8351435 8344706
+ * @bug 8305457 8342936 8351435 8344706 8361613
* @summary java.lang.IO tests
* @library /test/lib
- * @modules jdk.internal.le
* @run junit IO
*/
@ExtendWith(IO.TimingExtension.class)
@@ -78,22 +77,6 @@ public class IO {
} catch (Exception _) { }
}
- /*
- * Unlike printTest, which tests a _default_ console that is normally
- * jdk.internal.org.jline.JdkConsoleProviderImpl, this test tests
- * jdk.internal.io.JdkConsoleImpl. Those console implementations operate
- * in different conditions and, thus, are tested separately.
- *
- * To test jdk.internal.io.JdkConsoleImpl one needs to ensure that both
- * conditions are met:
- *
- * - a non-existent console provider is requested
- * - isatty is true
- *
- * To achieve isatty, the test currently uses the EXPECT(1) Unix command,
- * which does not work for Windows. Later, a library like pty4j or JPty
- * might be used instead of EXPECT, to cover both Unix and Windows.
- */
@ParameterizedTest
@ValueSource(strings = {"println", "print"})
public void outputTestInteractive(String mode) throws Exception {
@@ -102,8 +85,6 @@ public class IO {
expect.toString(),
Path.of(testSrc, "output.exp").toAbsolutePath().toString(),
System.getProperty("test.jdk") + "/bin/java",
- "--enable-preview",
- "-Djdk.console=gibberish",
Path.of(testSrc, "Output.java").toAbsolutePath().toString(),
mode);
assertEquals(0, output.getExitValue());
@@ -130,7 +111,7 @@ public class IO {
*/
@ParameterizedTest
@MethodSource("args")
- public void inputTestInteractive(String console, String prompt) throws Exception {
+ public void inputTestInteractive(String prompt) throws Exception {
var testSrc = System.getProperty("test.src", ".");
var command = new ArrayList();
command.add(expect.toString());
@@ -138,9 +119,6 @@ public class IO {
: "input";
command.add(Path.of(testSrc, expectInputName + ".exp").toAbsolutePath().toString());
command.add(System.getProperty("test.jdk") + "/bin/java");
- command.add("--enable-preview");
- if (console != null)
- command.add("-Djdk.console=" + console);
command.add(Path.of(testSrc, "Input.java").toAbsolutePath().toString());
command.add(prompt == null ? "0" : PROMPT_NONE.equals(prompt) ? "2" : "1");
command.add(String.valueOf(prompt));
@@ -152,33 +130,11 @@ public class IO {
private static final String PROMPT_NONE = "prompt-none";
public static Stream args() {
- // cross product: consoles x prompts
- return Stream.of("jdk.internal.le", "gibberish").flatMap(console -> Stream.of(null, "?", "%s", PROMPT_NONE)
- .map(prompt -> new String[]{console, prompt}).map(Arguments::of));
+ // prompts
+ return Stream.of(null, "?", "%s", PROMPT_NONE).map(Arguments::of);
}
}
- @ParameterizedTest
- @ValueSource(strings = {"println", "print"})
- public void printTest(String mode) throws Exception {
- var file = Path.of(System.getProperty("test.src", "."), "Output.java")
- .toAbsolutePath().toString();
- var pb = ProcessTools.createTestJavaProcessBuilder("-Djdk.console=jdk.internal.le", "--enable-preview", file, mode);
- OutputAnalyzer output = ProcessTools.executeProcess(pb);
- assertEquals(0, output.getExitValue());
- assertTrue(output.getStderr().isEmpty());
- output.reportDiagnosticSummary();
- String out = output.getStdout();
- // The first half of the output is produced by Console, the second
- // half is produced by IO: those halves must match.
- // Executing Console and IO in the same VM (as opposed to
- // consecutive VM runs, which are cleaner) to be able to compare string
- // representation of objects.
- assertFalse(out.isBlank());
- assertEquals(out.substring(0, out.length() / 2),
- out.substring(out.length() / 2));
- }
-
@Test //JDK-8342936
public void printlnNoParamsTest() throws Exception {
var file = Path.of("PrintlnNoParams.java");
@@ -193,7 +149,7 @@ public class IO {
}
""");
}
- var pb = ProcessTools.createTestJavaProcessBuilder("-Djdk.console=jdk.internal.le", "--enable-preview", file.toString());
+ var pb = ProcessTools.createTestJavaProcessBuilder(file.toString());
OutputAnalyzer output = ProcessTools.executeProcess(pb);
assertEquals(0, output.getExitValue());
assertTrue(output.getStderr().isEmpty());
diff --git a/test/jdk/jdk/internal/jline/JLineConsoleProviderTest.java b/test/jdk/jdk/internal/jline/JLineConsoleProviderTest.java
index 71590040685..445da167c5f 100644
--- a/test/jdk/jdk/internal/jline/JLineConsoleProviderTest.java
+++ b/test/jdk/jdk/internal/jline/JLineConsoleProviderTest.java
@@ -23,16 +23,19 @@
/**
* @test
- * @bug 8331535 8351435 8347050
+ * @bug 8331535 8351435 8347050 8361613
* @summary Verify the jdk.internal.le's console provider works properly.
- * @modules jdk.internal.le
+ * @modules java.base/jdk.internal.io
+ * jdk.internal.le/jdk.internal.org.jline
* @library /test/lib
- * @run main/othervm -Djdk.console=jdk.internal.le JLineConsoleProviderTest
+ * @run main JLineConsoleProviderTest
*/
import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
import java.util.Objects;
+import jdk.internal.org.jline.JdkConsoleProviderImpl;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
@@ -66,8 +69,13 @@ public class JLineConsoleProviderTest {
String input,
String expectedOut) throws Exception {
ProcessBuilder builder =
- ProcessTools.createTestJavaProcessBuilder("-Djdk.console=jdk.internal.le", ConsoleTest.class.getName(),
- testName);
+ ProcessTools.createTestJavaProcessBuilder(
+ "--add-exports",
+ "java.base/jdk.internal.io=ALL-UNNAMED",
+ "--add-exports",
+ "jdk.internal.le/jdk.internal.org.jline=ALL-UNNAMED",
+ ConsoleTest.class.getName(),
+ testName);
OutputAnalyzer output = ProcessTools.executeProcess(builder, input);
output.waitFor();
@@ -98,16 +106,18 @@ public class JLineConsoleProviderTest {
public static class ConsoleTest {
public static void main(String... args) {
+ // directly instantiate JLine JdkConsole, simulating isTTY=true
+ var impl = new JdkConsoleProviderImpl().console(true, StandardCharsets.UTF_8, StandardCharsets.UTF_8);
switch (args[0]) {
case "testCorrectOutputReadLine" ->
- System.console().readLine("%%s");
+ impl.readLine(null, "%%s");
case "testCorrectOutputReadPassword" ->
- System.console().readPassword("%%s");
+ impl.readPassword(null, "%%s");
case "readAndPrint" ->
- System.out.println("'" + System.console().readLine() + "'");
+ System.out.println("'" + impl.readLine() + "'");
case "readAndPrint2" -> {
- System.out.println("1: '" +System.console().readLine() + "'");
- System.out.println("2: '" + System.console().readLine() + "'");
+ System.out.println("1: '" + impl.readLine() + "'");
+ System.out.println("2: '" + impl.readLine() + "'");
}
default -> throw new UnsupportedOperationException(args[0]);
}
diff --git a/test/jdk/jdk/internal/jline/LazyJdkConsoleProvider.java b/test/jdk/jdk/internal/jline/LazyJdkConsoleProvider.java
index acf0c848b43..a7533796b7c 100644
--- a/test/jdk/jdk/internal/jline/LazyJdkConsoleProvider.java
+++ b/test/jdk/jdk/internal/jline/LazyJdkConsoleProvider.java
@@ -23,15 +23,19 @@
/**
* @test
- * @bug 8333086 8344706
+ * @bug 8333086 8344706 8361613
* @summary Verify the JLine backend is not initialized for simple printing.
- * @enablePreview
- * @modules jdk.internal.le/jdk.internal.org.jline.reader
+ * @modules java.base/jdk.internal.io
+ * jdk.internal.le/jdk.internal.org.jline
+ * jdk.internal.le/jdk.internal.org.jline.reader
* jdk.internal.le/jdk.internal.org.jline.terminal
* @library /test/lib
* @run main LazyJdkConsoleProvider
*/
+import java.nio.charset.StandardCharsets;
+
+import jdk.internal.org.jline.JdkConsoleProviderImpl;
import jdk.internal.org.jline.reader.LineReader;
import jdk.internal.org.jline.terminal.Terminal;
@@ -41,19 +45,18 @@ import jdk.test.lib.process.ProcessTools;
public class LazyJdkConsoleProvider {
public static void main(String... args) throws Throwable {
+ // directly instantiate JLine JdkConsole, simulating isTTY=true
switch (args.length > 0 ? args[0] : "default") {
case "write" -> {
- System.console().printf("Hello!\n");
- System.console().printf("Hello!");
- System.console().format("\nHello!\n");
- System.console().flush();
- IO.println("Hello!");
- IO.print("Hello!");
- }
- case "read" -> System.console().readLine("Hello!");
- case "IO-read" -> {
- IO.readln("Hello!");
+ var impl = new JdkConsoleProviderImpl().console(true, StandardCharsets.UTF_8, StandardCharsets.UTF_8);
+ impl.println("Hello!\n");
+ impl.println("Hello!");
+ impl.format(null, "\nHello!\n");
+ impl.flush();
}
+ case "read" -> new JdkConsoleProviderImpl()
+ .console(true, StandardCharsets.UTF_8, StandardCharsets.UTF_8)
+ .readLine(null, "Hello!");
case "default" -> {
new LazyJdkConsoleProvider().runTest();
}
@@ -64,14 +67,15 @@ public class LazyJdkConsoleProvider {
record TestCase(String testKey, String expected, String notExpected) {}
TestCase[] testCases = new TestCase[] {
new TestCase("write", null, Terminal.class.getName()),
- new TestCase("read", LineReader.class.getName(), null),
- new TestCase("IO-read", null, Terminal.class.getName())
+ new TestCase("read", LineReader.class.getName(), null)
};
for (TestCase tc : testCases) {
ProcessBuilder builder =
- ProcessTools.createTestJavaProcessBuilder("--enable-preview",
- "-verbose:class",
- "-Djdk.console=jdk.internal.le",
+ ProcessTools.createTestJavaProcessBuilder("-verbose:class",
+ "--add-exports",
+ "java.base/jdk.internal.io=ALL-UNNAMED",
+ "--add-exports",
+ "jdk.internal.le/jdk.internal.org.jline=ALL-UNNAMED",
LazyJdkConsoleProvider.class.getName(),
tc.testKey());
OutputAnalyzer output = ProcessTools.executeProcess(builder, "");
diff --git a/test/jdk/jdk/internal/jline/RedirectedStdOut.java b/test/jdk/jdk/internal/jline/RedirectedStdOut.java
deleted file mode 100644
index 71419f96c73..00000000000
--- a/test/jdk/jdk/internal/jline/RedirectedStdOut.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (c) 2024, 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.
- */
-
-/**
- * @test
- * @bug 8330998 8351435
- * @summary Verify that even if the stdout is redirected java.io.Console will
- * use it for writing.
- * @modules jdk.internal.le
- * @library /test/lib
- * @run main RedirectedStdOut runRedirectAllTest
- * @run main/othervm --enable-native-access=ALL-UNNAMED RedirectedStdOut runRedirectOutOnly
- */
-
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
-import java.lang.foreign.Arena;
-import java.lang.foreign.FunctionDescriptor;
-import java.lang.foreign.Linker;
-import java.lang.foreign.MemorySegment;
-import java.lang.foreign.SymbolLookup;
-import java.lang.foreign.ValueLayout;
-import java.lang.invoke.MethodHandle;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Objects;
-import java.util.Optional;
-
-import jdk.test.lib.process.OutputAnalyzer;
-import jdk.test.lib.process.ProcessTools;
-
-public class RedirectedStdOut {
- private static final String OUTPUT = "Hello!";
-
- public static void main(String... args) throws Throwable {
- RedirectedStdOut.class.getDeclaredMethod(args[0])
- .invoke(new RedirectedStdOut());
- }
-
- //verify the case where neither stdin/out/err is attached to a terminal,
- //this test is weaker, but more reliable:
- void runRedirectAllTest() throws Exception {
- ProcessBuilder builder =
- ProcessTools.createTestJavaProcessBuilder("-Djdk.console=jdk.internal.le", ConsoleTest.class.getName());
- OutputAnalyzer output = ProcessTools.executeProcess(builder);
-
- output.waitFor();
-
- if (output.getExitValue() != 0) {
- throw new AssertionError("Unexpected return value: " + output.getExitValue() +
- ", actualOut: " + output.getStdout() +
- ", actualErr: " + output.getStderr());
- }
-
- String expectedOut = OUTPUT;
- String actualOut = output.getStdout();
-
- if (!Objects.equals(expectedOut, actualOut)) {
- throw new AssertionError("Unexpected stdout content. " +
- "Expected: '" + expectedOut + "'" +
- ", got: '" + actualOut + "'");
- }
-
- String expectedErr = "";
- String actualErr = output.getStderr();
-
- if (!Objects.equals(expectedErr, actualErr)) {
- throw new AssertionError("Unexpected stderr content. " +
- "Expected: '" + expectedErr + "'" +
- ", got: '" + actualErr + "'");
- }
- }
-
- //verify the case where stdin is attached to a terminal,
- //this test allocates pty, and it might be skipped, if the appropriate
- //native functions cannot be found
- //it also leaves the VM in a broken state (with a pty attached), and so
- //should run in a separate VM instance
- void runRedirectOutOnly() throws Throwable {
- Path stdout = Path.of(".", "stdout.txt").toAbsolutePath();
-
- Files.deleteIfExists(stdout);
-
- Linker linker = Linker.nativeLinker();
- SymbolLookup stdlib = linker.defaultLookup();
- MemorySegment parent = Arena.global().allocate(ValueLayout.ADDRESS);
- MemorySegment child = Arena.global().allocate(ValueLayout.ADDRESS);
- Optional openptyAddress = stdlib.find("openpty");
-
- if (openptyAddress.isEmpty()) {
- System.out.println("Cannot lookup openpty.");
- //does not have forkpty, ignore
- return ;
- }
-
- Optional loginttyAddress = stdlib.find("login_tty");
-
- if (loginttyAddress.isEmpty()) {
- System.out.println("Cannot lookup login_tty.");
- //does not have forkpty, ignore
- return ;
- }
-
- FunctionDescriptor openttyDescriptor =
- FunctionDescriptor.of(ValueLayout.JAVA_INT,
- ValueLayout.ADDRESS,
- ValueLayout.ADDRESS,
- ValueLayout.ADDRESS,
- ValueLayout.ADDRESS,
- ValueLayout.ADDRESS);
- MethodHandle forkpty = linker.downcallHandle(openptyAddress.get(),
- openttyDescriptor);
- int res = (int) forkpty.invoke(parent,
- child,
- MemorySegment.NULL,
- MemorySegment.NULL,
- MemorySegment.NULL);
-
- if (res != 0) {
- throw new AssertionError();
- }
-
- //set the current VM's in/out to the terminal:
- FunctionDescriptor loginttyDescriptor =
- FunctionDescriptor.of(ValueLayout.JAVA_INT,
- ValueLayout.JAVA_INT);
- MethodHandle logintty = linker.downcallHandle(loginttyAddress.get(),
- loginttyDescriptor);
- logintty.invoke(child.get(ValueLayout.JAVA_INT, 0));
-
- //createTestJavaProcessBuilder logs to (current process') System.out, but
- //that may not work since the redirect. Setting System.out to a scratch value:
- System.setOut(new PrintStream(new ByteArrayOutputStream()));
-
- ProcessBuilder builder =
- ProcessTools.createTestJavaProcessBuilder("-Djdk.console=jdk.internal.le", ConsoleTest.class.getName());
-
- builder.inheritIO();
- builder.redirectOutput(stdout.toFile());
-
- OutputAnalyzer output = ProcessTools.executeProcess(builder);
-
- output.waitFor();
-
- String expectedOut = OUTPUT;
- String actualOut = Files.readString(stdout);
-
- if (!Objects.equals(expectedOut, actualOut)) {
- throw new AssertionError("Unexpected stdout content. " +
- "Expected: '" + expectedOut + "'" +
- ", got: '" + actualOut + "'");
- }
- }
-
- public static class ConsoleTest {
- public static void main(String... args) {
- System.console().printf(OUTPUT);
- System.exit(0);
- }
- }
-}
From c01b4fc348fff37c502d38ab3bb3385a5a8cff9a Mon Sep 17 00:00:00 2001
From: Ioi Lam