();
+ ExceptionBox.visitUnboxedExceptionsRecursively(t, unfoldedExceptions::add);
+
+ unfoldedExceptions.forEach(ex -> {
+ if (ex instanceof ConfigException cfgEx) {
+ printError(cfgEx, Optional.ofNullable(cfgEx.getAdvice()));
+ } else if (ex instanceof UncheckedIOException) {
+ printError(ex.getCause(), Optional.empty());
+ } else if (ex instanceof UnexpectedResultException urex) {
+ printExternalCommandError(urex);
+ } else {
+ printError(ex, Optional.empty());
+ }
+ });
}
private void printExternalCommandError(UnexpectedResultException ex) {
diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionBox.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionBox.java
index 40503469873..0c2963f7397 100644
--- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionBox.java
+++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionBox.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, 2026, 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
@@ -25,6 +25,9 @@
package jdk.jpackage.internal.util.function;
import java.lang.reflect.InvocationTargetException;
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
public class ExceptionBox extends RuntimeException {
@@ -74,6 +77,40 @@ public class ExceptionBox extends RuntimeException {
}
}
+ /**
+ * Unboxes the specified throwable and its suppressed throwables recursively.
+ *
+ * Calls {@link #unbox(Throwable)} on the specified throwable and nested
+ * suppressed throwables, passing the result to the {@code visitor}.
+ *
+ * Throwables will be traversed in the "cause before consequence" order. E.g.:
+ * say exception "A" suppresses exceptions "B" and "C", and "B" suppresses "D".
+ * The traverse order will be "D", "B", "C", "A".
+ *
+ * If the method encounters cyclic suppressed throwables, it will fall into an
+ * infinite recursion loop, eventually causing a {@code StackOverflowError}.
+ *
+ * If the specified throwable or any of its nested suppressed throwables are of
+ * type {@link Error}, the method will keep notifying the {@code visitor} until
+ * it hits the first such throwable. When it happens, the method will throw this
+ * throwable.
+ *
+ * @param t the exception to visit
+ * @param visitor the callback to apply to every subsequently visited exception
+ */
+ public static void visitUnboxedExceptionsRecursively(Throwable t, Consumer visitor) {
+ Objects.requireNonNull(t);
+ Objects.requireNonNull(visitor);
+
+ var ex = unbox(t);
+
+ Stream.of(ex.getSuppressed()).forEach(suppressed -> {
+ visitUnboxedExceptionsRecursively(suppressed, visitor);
+ });
+
+ visitor.accept(ex);
+ }
+
public static Error reachedUnreachable() {
return new AssertionError("Reached unreachable!");
}
diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java
index 46de970a829..239ce0d0ce9 100644
--- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java
+++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java
@@ -38,11 +38,12 @@ import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
-import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiFunction;
+import java.util.function.Consumer;
import java.util.function.Function;
+import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.spi.ToolProvider;
import java.util.stream.Collectors;
@@ -53,9 +54,11 @@ import jdk.jpackage.internal.MockUtils;
import jdk.jpackage.internal.model.ConfigException;
import jdk.jpackage.internal.model.ExecutableAttributesWithCapturedOutput;
import jdk.jpackage.internal.model.JPackageException;
+import jdk.jpackage.internal.model.SelfContainedException;
import jdk.jpackage.internal.util.CommandOutputControl;
import jdk.jpackage.internal.util.CommandOutputControl.UnexpectedExitCodeException;
import jdk.jpackage.internal.util.CommandOutputControl.UnexpectedResultException;
+import jdk.jpackage.internal.util.IdentityWrapper;
import jdk.jpackage.internal.util.function.ExceptionBox;
import jdk.jpackage.test.Annotations;
import jdk.jpackage.test.JPackageCommand;
@@ -181,112 +184,157 @@ public class MainTest extends JUnitAdapter {
).map(TestSpec.Builder::create).toList();
}
-
private static List test_ErrorReporter() {
- var data = new ArrayList();
-
+ var testCases = new ArrayList();
for (var verbose : List.of(true, false)) {
- for (var makeCause : List.>of(
- ex -> ex,
- // UncheckedIOException
- ex -> {
- if (ex instanceof IOException ioex) {
- return new UncheckedIOException(ioex);
- } else {
- return null;
- }
- },
- // ExceptionBox
- ex -> {
- var rex = ExceptionBox.toUnchecked(ex);
- if (rex != ex) {
- return rex;
- } else {
- return null;
- }
- }
- )) {
- for (var expect : List.of(
- Map.entry(new IOException("I/O error"), true),
- Map.entry(new NullPointerException(), true),
- Map.entry(new JPackageException("Kaput!"), false),
- Map.entry(new ConfigException("It is broken", "Fix it!"), false),
- Map.entry(new ConfigException("It is broken. No advice how to fix it", (String)null), false),
- Map.entry(new Utils.ParseException("Malformed command line"), false),
- Map.entry(new StandardOption.AddLauncherIllegalArgumentException("Malformed value of --add-launcher option"), false)
- )) {
- var cause = makeCause.apply(expect.getKey());
- if (cause == null) {
- continue;
- }
-
- var expectedOutput = new ArrayList();
- if (expect.getValue()) {
- // An alien exception.
- expectedOutput.add(ExceptionFormatter.STACK_TRACE);
- expectedOutput.add(ExceptionFormatter.TO_STRING);
- } else {
- if (verbose) {
- expectedOutput.add(ExceptionFormatter.STACK_TRACE);
- }
- if (expect.getKey() instanceof ConfigException cex) {
- if (cex.getAdvice() != null) {
- expectedOutput.add(ExceptionFormatter.MESSAGE_WITH_ADVICE);
- } else {
- expectedOutput.add(ExceptionFormatter.GET_MESSAGE);
- }
- } else {
- expectedOutput.add(ExceptionFormatter.GET_MESSAGE);
- }
- }
-
- data.add(new ErrorReporterTestSpec(cause, expect.getKey(), verbose, expectedOutput));
- }
- }
-
- var execAttrs = new CommandOutputControl.ProcessAttributes(Optional.of(12345L), List.of("foo", "--bar"));
- for (var makeCause : List.>of(
- ex -> ex,
- ExceptionBox::toUnchecked
- )) {
-
- for (var expect : List.of(
- Map.entry(
- augmentResultWithOutput(
- CommandOutputControl.Result.build().exitCode(135).execAttrs(execAttrs).create(),
- "The quick brown fox\njumps over the lazy dog"
- ).unexpected("Kaput!"),
- ExceptionFormatter.FAILED_COMMAND_UNEXPECTED_OUTPUT_MESSAGE
- ),
- Map.entry(
- new UnexpectedExitCodeException(augmentResultWithOutput(
- CommandOutputControl.Result.build().exitCode(135).create(),
- "The quick brown fox\njumps"
- )),
- ExceptionFormatter.FAILED_COMMAND_UNEXPECTED_EXIT_CODE_MESSAGE
- ),
- Map.entry(
- augmentResultWithOutput(
- CommandOutputControl.Result.build().create(),
- "The quick brown fox\njumps"
- ).unexpected("Timed out!"),
- ExceptionFormatter.FAILED_COMMAND_TIMEDOUT_MESSAGE
- )
- )) {
- var cause = makeCause.apply(expect.getKey());
- var expectedOutput = new ArrayList();
- if (verbose) {
- expectedOutput.add(ExceptionFormatter.STACK_TRACE);
- }
- expectedOutput.add(expect.getValue());
- expectedOutput.add(ExceptionFormatter.FAILED_COMMAND_OUTPUT);
- data.add(new ErrorReporterTestSpec(cause, expect.getKey(), verbose, expectedOutput));
- }
- }
-
+ test_ErrorReporter_Exception(verbose, testCases::add);
+ test_ErrorReporter_UnexpectedResultException(verbose, testCases::add);
+ test_ErrorReporter_suppressedExceptions(verbose, testCases::add);
}
- return data;
+ return testCases;
+ }
+
+ private static void test_ErrorReporter_Exception(boolean verbose, Consumer sink) {
+
+ for (var makeCause : List.>of(
+ ex -> ex,
+ // UncheckedIOException
+ ex -> {
+ if (ex instanceof IOException ioex) {
+ return new UncheckedIOException(ioex);
+ } else {
+ return null;
+ }
+ },
+ // ExceptionBox
+ ex -> {
+ var rex = ExceptionBox.toUnchecked(ex);
+ if (rex != ex) {
+ return rex;
+ } else {
+ return null;
+ }
+ }
+ )) {
+ for (var expect : List.of(
+ new IOException("I/O error"),
+ new NullPointerException(),
+ new JPackageException("Kaput!"),
+ new ConfigException("It is broken", "Fix it!"),
+ new ConfigException("It is broken. No advice how to fix it", (String)null),
+ new Utils.ParseException("Malformed command line"),
+ new StandardOption.AddLauncherIllegalArgumentException("Malformed value of --add-launcher option")
+ )) {
+ var cause = makeCause.apply(expect);
+ if (cause == null) {
+ continue;
+ }
+
+ var expectedOutput = new ArrayList();
+ ErrorReporterTestSpec.expectExceptionFormatters(expect, verbose, expectedOutput::add);
+ sink.accept(ErrorReporterTestSpec.create(cause, expect, verbose, expectedOutput));
+ }
+ }
+ }
+
+ private static void test_ErrorReporter_UnexpectedResultException(boolean verbose, Consumer sink) {
+
+ var execAttrs = new CommandOutputControl.ProcessAttributes(Optional.of(12345L), List.of("foo", "--bar"));
+
+ for (var makeCause : List.>of(
+ ex -> ex,
+ ExceptionBox::toUnchecked
+ )) {
+
+ for (var expect : List.of(
+ augmentResultWithOutput(
+ CommandOutputControl.Result.build().exitCode(135).execAttrs(execAttrs).create(),
+ "The quick brown fox\njumps over the lazy dog"
+ ).unexpected("Kaput!"),
+ new UnexpectedExitCodeException(augmentResultWithOutput(
+ CommandOutputControl.Result.build().exitCode(135).create(),
+ "The quick brown fox\njumps"
+ )),
+ augmentResultWithOutput(
+ CommandOutputControl.Result.build().create(),
+ "The quick brown fox\njumps"
+ ).unexpected("Timed out!")
+ )) {
+ var cause = makeCause.apply(expect);
+ var expectedOutput = new ArrayList();
+ ErrorReporterTestSpec.expectExceptionFormatters(expect, verbose, expectedOutput::add);
+ sink.accept(ErrorReporterTestSpec.create(cause, expect, verbose, expectedOutput));
+ }
+ }
+ }
+
+ private static Exception suppressException(Exception main, Exception suppressed) {
+ Objects.requireNonNull(main);
+ Objects.requireNonNull(suppressed);
+
+ try (var autoCloseable = new AutoCloseable() {
+
+ @Override
+ public void close() throws Exception {
+ throw suppressed;
+ }}) {
+
+ throw main;
+ } catch (Exception ex) {
+ return ex;
+ }
+ }
+
+ private static void test_ErrorReporter_suppressedExceptions(boolean verbose, Consumer sink) {
+
+ var execAttrs = new CommandOutputControl.ProcessAttributes(Optional.of(567L), List.of("foo", "--bar"));
+
+ Supplier createUnexpectedResultException = () -> {
+ return augmentResultWithOutput(
+ CommandOutputControl.Result.build().exitCode(7).execAttrs(execAttrs).create(),
+ "The quick brown fox\njumps over the lazy dog"
+ ).unexpected("Alas");
+ };
+
+ for (var makeCause : List.>of(
+ ex -> ex,
+ ex -> {
+ var rex = ExceptionBox.toUnchecked(ex);
+ if (rex != ex) {
+ return rex;
+ } else {
+ return null;
+ }
+ }
+ )) {
+
+ for (var exceptions : List.of(
+ List.of(new JPackageException("Kaput!"), new JPackageException("Suppressed kaput")),
+ List.of(new Exception("Kaput!"), new JPackageException("Suppressed kaput")),
+ List.of(new Exception("Kaput!"), new Exception("Suppressed kaput")),
+ List.of(new Exception("Kaput!"), ExceptionBox.toUnchecked(new Exception("Suppressed kaput"))),
+ List.of(createUnexpectedResultException.get(), new Exception("Suppressed kaput")),
+ List.of(new Exception("Alas!"), createUnexpectedResultException.get()),
+ List.of(new JPackageException("Alas!"), createUnexpectedResultException.get())
+ )) {
+ var main = exceptions.getFirst();
+ var suppressed = exceptions.getLast();
+
+ var cause = makeCause.apply(suppressException(main, suppressed));
+
+ if (cause == null) {
+ continue;
+ }
+
+ var expectedOutput = new ArrayList();
+
+ ErrorReporterTestSpec.expectOutputFragments(ExceptionBox.unbox(suppressed), verbose, expectedOutput::add);
+ ErrorReporterTestSpec.expectOutputFragments(main, verbose, expectedOutput::add);
+
+ sink.accept(new ErrorReporterTestSpec(cause, verbose, expectedOutput));
+ }
+ }
}
@@ -452,6 +500,19 @@ public class MainTest extends JUnitAdapter {
}
+ private record FormattedException(ExceptionFormatter formatter, Exception exception) {
+
+ FormattedException {
+ Objects.requireNonNull(formatter);
+ Objects.requireNonNull(exception);
+ }
+
+ String format() {
+ return formatter.format(exception);
+ }
+ }
+
+
private enum ExceptionFormatter {
GET_MESSAGE(errorMessage(Exception::getMessage)),
MESSAGE_WITH_ADVICE(ex -> {
@@ -497,6 +558,10 @@ public class MainTest extends JUnitAdapter {
return formatter.apply(v);
}
+ FormattedException bind(Exception v) {
+ return new FormattedException(this, v);
+ }
+
private static Function errorMessage(Function formatter) {
Objects.requireNonNull(formatter);
return ex -> {
@@ -545,29 +610,99 @@ public class MainTest extends JUnitAdapter {
}
- record ErrorReporterTestSpec(Exception cause, Exception expect, boolean verbose, List expectOutput) {
+ record ErrorReporterTestSpec(Exception cause, boolean verbose, List expectOutput) {
ErrorReporterTestSpec {
Objects.requireNonNull(cause);
- Objects.requireNonNull(expect);
Objects.requireNonNull(expectOutput);
+ if (expectOutput.isEmpty()) {
+ throw new IllegalArgumentException();
+ }
}
- ErrorReporterTestSpec(Exception cause, boolean verbose, List expectOutput) {
- this(cause, cause, verbose, expectOutput);
+ static ErrorReporterTestSpec create(
+ Exception cause, boolean verbose, List expectOutput) {
+ return create(cause, cause, verbose, expectOutput);
+ }
+
+ static ErrorReporterTestSpec create(
+ Exception cause, Exception expect, boolean verbose, List expectOutput) {
+ Objects.requireNonNull(cause);
+ Objects.requireNonNull(expect);
+ return new ErrorReporterTestSpec(cause, verbose, expectOutput.stream().map(formatter -> {
+ return new FormattedException(formatter, expect);
+ }).toList());
+ }
+
+ static void expectExceptionFormatters(Exception ex, boolean verbose, Consumer sink) {
+ Objects.requireNonNull(ex);
+ Objects.requireNonNull(sink);
+
+ final var isSelfContained = (ex.getClass().getAnnotation(SelfContainedException.class) != null);
+
+ if (verbose || !(isSelfContained || ex instanceof UnexpectedResultException)) {
+ sink.accept(ExceptionFormatter.STACK_TRACE);
+ }
+
+ switch (ex) {
+ case ConfigException cex -> {
+ if (cex.getAdvice() != null) {
+ sink.accept(ExceptionFormatter.MESSAGE_WITH_ADVICE);
+ } else {
+ sink.accept(ExceptionFormatter.GET_MESSAGE);
+ }
+ }
+ case UnexpectedResultException urex -> {
+ if (urex instanceof UnexpectedExitCodeException) {
+ sink.accept(ExceptionFormatter.FAILED_COMMAND_UNEXPECTED_EXIT_CODE_MESSAGE);
+ } else if (urex.getResult().exitCode().isPresent()) {
+ sink.accept(ExceptionFormatter.FAILED_COMMAND_UNEXPECTED_OUTPUT_MESSAGE);
+ } else {
+ sink.accept(ExceptionFormatter.FAILED_COMMAND_TIMEDOUT_MESSAGE);
+ }
+ sink.accept(ExceptionFormatter.FAILED_COMMAND_OUTPUT);
+ }
+ default -> {
+ if (isSelfContained) {
+ sink.accept(ExceptionFormatter.GET_MESSAGE);
+ } else {
+ sink.accept(ExceptionFormatter.TO_STRING);
+ }
+ }
+ }
+ }
+
+ static void expectOutputFragments(Exception ex, boolean verbose, Consumer sink) {
+ Objects.requireNonNull(sink);
+ expectExceptionFormatters(ex, verbose, formatter -> {
+ sink.accept(formatter.bind(ex));
+ });
}
@Override
public String toString() {
var tokens = new ArrayList();
- if (cause == expect) {
+ var expect = expectOutput.stream()
+ .map(FormattedException::exception)
+ .map(IdentityWrapper::new)
+ .distinct()
+ .toList();
+
+ if (expect.size() == 1 && expect.getFirst().value() == cause) {
tokens.add(cause.toString());
} else {
- tokens.add(String.format("[%s] => [%s]", cause, expect));
+ tokens.add(String.format("[%s] => %s", cause, expect.stream().map(IdentityWrapper::value).toList()));
}
- tokens.add(expectOutput.stream().map(Enum::name).collect(Collectors.joining("+")));
+ if (expect.size() == 1) {
+ tokens.add(expectOutput.stream().map(FormattedException::formatter).map(Enum::name).collect(Collectors.joining("+")));
+ } else {
+ tokens.add(expectOutput.stream().map(fragment -> {
+ var idx = expect.indexOf(IdentityWrapper.wrapIdentity(fragment.exception()));
+ return String.format("%s@%d", fragment.formatter(), idx);
+ }).collect(Collectors.joining("+")));
+ }
if (verbose) {
tokens.add("verbose");
@@ -587,9 +722,7 @@ public class MainTest extends JUnitAdapter {
}, verbose).reportError(cause);
}
- var expected = expectOutput.stream().map(formatter -> {
- return formatter.format(expect);
- }).collect(Collectors.joining(""));
+ var expected = expectOutput.stream().map(FormattedException::format).collect(Collectors.joining(""));
assertEquals(expected, sink.toString());
}
diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/function/ExceptionBoxTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/function/ExceptionBoxTest.java
index c3ef239b02d..d7a6f0e714d 100644
--- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/function/ExceptionBoxTest.java
+++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/function/ExceptionBoxTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, 2026, 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,13 +31,19 @@ import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.UnaryOperator;
+import jdk.jpackage.internal.util.IdentityWrapper;
import jdk.jpackage.internal.util.Slot;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.EnumSource;
+import org.junit.jupiter.params.provider.MethodSource;
public class ExceptionBoxTest {
@@ -190,6 +196,16 @@ public class ExceptionBoxTest {
}
}
+ @ParameterizedTest
+ @MethodSource
+ void test_visitUnboxedExceptionsRecursively(Throwable t, List expect) {
+ var actual = new ArrayList();
+ ExceptionBox.visitUnboxedExceptionsRecursively(t, actual::add);
+ assertEquals(
+ expect.stream().map(IdentityWrapper::new).toList(),
+ actual.stream().map(IdentityWrapper::new).toList());
+ }
+
public enum InvocationTargetExceptionType {
CHECKED("throwIOException", t -> {
return t.getCause();
@@ -224,13 +240,74 @@ public class ExceptionBoxTest {
throw new Error("Kaput!");
}
- private static void assertToUnchecked(Exception cause, boolean asis) {
- Class extends Throwable> expectedType;
- if (asis) {
- expectedType = cause.getClass();
- } else {
- expectedType = ExceptionBox.class;
+ private static Collection test_visitUnboxedExceptionsRecursively() {
+
+ var testCases = new ArrayList();
+
+ testCases.addAll(test_visitUnboxedExceptionsRecursively_example());
+
+ var t = new Exception("A");
+ for (var box : List.>of(
+ ex -> ex,
+ ExceptionBox::toUnchecked,
+ InvocationTargetException::new
+ )) {
+ testCases.add(Arguments.of(box.apply(t), List.of(t)));
}
+
+ // The cause is not traversed.
+ var exWithCause = new Exception("B", t);
+ testCases.add(Arguments.of(exWithCause, List.of(exWithCause)));
+
+ var exWithSuppressed = new Exception("C");
+ exWithSuppressed.addSuppressed(t);
+ exWithSuppressed.addSuppressed(ExceptionBox.toUnchecked(t));
+ exWithSuppressed.addSuppressed(exWithCause);
+ exWithSuppressed.addSuppressed(new InvocationTargetException(exWithCause));
+ var exWithSuppressedExpect = List.of(t, t, exWithCause, exWithCause, exWithSuppressed);
+ testCases.add(Arguments.of(exWithSuppressed, exWithSuppressedExpect));
+
+ for (var box : List.>of(
+ ExceptionBox::toUnchecked,
+ InvocationTargetException::new
+ )) {
+ // Suppressed exceptions added to ExceptionBox and InvocationTargetException are omitted.
+ var exWithSuppressedBoxed = box.apply(exWithSuppressed);
+ exWithSuppressedBoxed.addSuppressed(exWithSuppressed);
+ testCases.add(Arguments.of(exWithSuppressedBoxed, exWithSuppressedExpect));
+ }
+
+ var exWithSuppressed2 = new Exception("D");
+ exWithSuppressed2.addSuppressed(t);
+ exWithSuppressed2.addSuppressed(exWithSuppressed);
+ exWithSuppressed2.addSuppressed(ExceptionBox.toUnchecked(exWithSuppressed));
+
+ var exWithSuppressed2Expect = new ArrayList();
+ exWithSuppressed2Expect.add(t);
+ exWithSuppressed2Expect.addAll(exWithSuppressedExpect);
+ exWithSuppressed2Expect.addAll(exWithSuppressedExpect);
+ exWithSuppressed2Expect.add(exWithSuppressed2);
+ testCases.add(Arguments.of(exWithSuppressed2, exWithSuppressed2Expect));
+
+ return testCases;
+ }
+
+ private static Collection test_visitUnboxedExceptionsRecursively_example() {
+
+ var a = new Exception("A");
+ var b = new Exception("B");
+ var c = new Exception("C");
+ var d = new Exception("D");
+
+ a.addSuppressed(b);
+ a.addSuppressed(c);
+
+ b.addSuppressed(d);
+
+ return List.of(Arguments.of(a, List.of(d, b, c, a)));
+ }
+
+ private static void assertToUnchecked(Exception cause, boolean asis) {
var unchecked = ExceptionBox.toUnchecked(cause);
if (asis) {
assertSame(cause, unchecked);
diff --git a/test/jdk/tools/jpackage/macosx/MacSignTest.java b/test/jdk/tools/jpackage/macosx/MacSignTest.java
index 0be494ea469..e558b671478 100644
--- a/test/jdk/tools/jpackage/macosx/MacSignTest.java
+++ b/test/jdk/tools/jpackage/macosx/MacSignTest.java
@@ -22,22 +22,23 @@
*/
import static jdk.jpackage.test.MacHelper.SignKeyOption.Type.SIGN_KEY_IDENTITY;
-import static jdk.jpackage.test.MacHelper.SignKeyOption.Type.SIGN_KEY_IDENTITY_APP_IMAGE;
import static jdk.jpackage.test.MacHelper.SignKeyOption.Type.SIGN_KEY_USER_FULL_NAME;
import static jdk.jpackage.test.MacHelper.SignKeyOption.Type.SIGN_KEY_USER_SHORT_NAME;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Collection;
+import java.util.Comparator;
import java.util.List;
+import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Stream;
+import jdk.jpackage.internal.util.function.ExceptionBox;
import jdk.jpackage.test.Annotations.Parameter;
import jdk.jpackage.test.Annotations.ParameterSupplier;
import jdk.jpackage.test.Annotations.Test;
-import jdk.jpackage.test.CannedFormattedString;
import jdk.jpackage.test.FailedCommandErrorValidator;
import jdk.jpackage.test.JPackageCommand;
import jdk.jpackage.test.JPackageStringBundle;
@@ -47,7 +48,6 @@ import jdk.jpackage.test.MacHelper.ResolvableCertificateRequest;
import jdk.jpackage.test.MacHelper.SignKeyOption;
import jdk.jpackage.test.MacHelper.SignKeyOptionWithKeychain;
import jdk.jpackage.test.MacSign;
-import jdk.jpackage.test.MacSign.CertificateType;
import jdk.jpackage.test.MacSignVerify;
import jdk.jpackage.test.PackageType;
import jdk.jpackage.test.TKit;
@@ -94,11 +94,7 @@ public class MacSignTest {
SigningBase.StandardCertificateRequest.CODESIGN,
keychain);
- new FailedCommandErrorValidator(Pattern.compile(String.format(
- "/usr/bin/codesign -s %s -vvvv --timestamp --options runtime --prefix \\S+ --keychain %s --entitlements \\S+ \\S+",
- Pattern.quote(String.format("'%s'", signingKeyOption.certRequest().name())),
- Pattern.quote(keychain.name())
- ))).exitCode(1).createGroup().mutate(group::add);
+ buildSignCommandErrorValidator(signingKeyOption).createGroup().mutate(group::add);
MacSign.withKeychain(_ -> {
@@ -107,7 +103,7 @@ public class MacSignTest {
// This is not a fatal error, just a warning.
// To make jpackage fail, specify bad additional content.
JPackageCommand.helloAppImage()
- .ignoreDefaultVerbose(true)
+ .mutate(MacSignTest::init)
.validateOutput(group.create())
.addArguments("--app-content", appContent)
.mutate(signingKeyOption::addTo)
@@ -136,11 +132,9 @@ public class MacSignTest {
MacSign.withKeychain(keychain -> {
// Build a matcher for jpackage's failed command output.
- var errorValidator = new FailedCommandErrorValidator(Pattern.compile(String.format(
- "/usr/bin/codesign -s %s -vvvv --timestamp --options runtime --prefix \\S+ --keychain %s",
- Pattern.quote(String.format("'%s'", signingKeyOption.certRequest().name())),
- Pattern.quote(keychain.name())
- ))).exitCode(1).output(String.format("%s: no identity found", signingKeyOption.certRequest().name())).createGroup();
+ var errorValidator = buildSignCommandErrorValidator(signingKeyOption, keychain)
+ .output(String.format("%s: no identity found", signingKeyOption.certRequest().name()))
+ .createGroup();
JPackageCommand.helloAppImage()
.setFakeRuntime()
@@ -157,9 +151,12 @@ public class MacSignTest {
@Parameter({"IMAGE", "EXPIRED_SIGNING_KEY_USER_NAME"})
@Parameter({"MAC_DMG", "EXPIRED_SIGNING_KEY_USER_NAME"})
@Parameter({"MAC_PKG", "EXPIRED_SIGNING_KEY_USER_NAME", "EXPIRED_SIGNING_KEY_USER_NAME_PKG"})
+ @Parameter({"MAC_PKG", "EXPIRED_SIGNING_KEY_USER_NAME_PKG", "EXPIRED_SIGNING_KEY_USER_NAME"})
@Parameter({"IMAGE", "EXPIRED_SIGN_IDENTITY"})
@Parameter({"MAC_DMG", "EXPIRED_SIGN_IDENTITY"})
+
+ // Test that jpackage doesn't print duplicated error messages.
@Parameter({"MAC_PKG", "EXPIRED_SIGN_IDENTITY"})
@Parameter({"IMAGE", "EXPIRED_CODESIGN_SIGN_IDENTITY"})
@@ -168,16 +165,41 @@ public class MacSignTest {
@Parameter({"MAC_PKG", "GOOD_CODESIGN_SIGN_IDENTITY", "EXPIRED_PKG_SIGN_IDENTITY"})
@Parameter({"MAC_PKG", "EXPIRED_CODESIGN_SIGN_IDENTITY", "GOOD_PKG_SIGN_IDENTITY"})
- public static void testExpiredCertificate(PackageType type, SignOption... options) {
+ public static void testExpiredCertificate(PackageType type, SignOption... optionIds) {
+
+ var options = Stream.of(optionIds).map(SignOption::option).toList();
+
+ var badOptions = options.stream().filter(option -> {
+ return option.certRequest().expired();
+ }).toList();
MacSign.withKeychain(keychain -> {
+
final var cmd = MacHelper.useKeychain(JPackageCommand.helloAppImage(), keychain)
- .ignoreDefaultVerbose(true)
- .addArguments(Stream.of(options).map(SignOption::args).flatMap(List::stream).toList())
+ .mutate(MacSignTest::init)
+ .addArguments(options.stream().map(SignKeyOption::asCmdlineArgs).flatMap(List::stream).toList())
.setPackageType(type);
- SignOption.configureOutputValidation(cmd, Stream.of(options).filter(SignOption::expired).toList(), opt -> {
- return JPackageStringBundle.MAIN.cannedFormattedString("error.certificate.expired", opt.identityName());
+ configureOutputValidation(cmd, expectFailures(badOptions), opt -> {
+ if (!opt.passThrough().orElse(false)) {
+ return expectConfigurationError("error.certificate.outside-validity-period", opt.certRequest().name());
+ } else {
+ var builder = buildSignCommandErrorValidator(opt, keychain);
+ switch (opt.optionName().orElseThrow()) {
+ case KEY_IDENTITY_APP_IMAGE, KEY_USER_NAME -> {
+ builder.output(String.format("%s: no identity found", opt.certRequest().name()));
+ }
+ case KEY_IDENTITY_INSTALLER -> {
+ var regexp = Pattern.compile(String.format(
+ "^productbuild: error: Cannot write product to \\S+ \\(Could not find appropriate signing identity for “%s” in keychain at “%s”\\.\\)",
+ Pattern.quote(opt.certRequest().name()),
+ Pattern.quote(keychain.name())
+ ));
+ builder.validators(TKit.assertTextStream(regexp));
+ }
+ }
+ return builder.createGroup();
+ }
}).execute(1);
}, MacSign.Keychain.UsageBuilder::addToSearchList, SigningBase.StandardKeychain.EXPIRED.keychain());
}
@@ -185,30 +207,60 @@ public class MacSignTest {
@Test
@Parameter({"IMAGE", "GOOD_SIGNING_KEY_USER_NAME"})
@Parameter({"MAC_DMG", "GOOD_SIGNING_KEY_USER_NAME"})
+ @Parameter({"MAC_PKG", "GOOD_SIGNING_KEY_USER_NAME", "GOOD_SIGNING_KEY_USER_NAME_PKG"})
@Parameter({"MAC_PKG", "GOOD_SIGNING_KEY_USER_NAME_PKG", "GOOD_SIGNING_KEY_USER_NAME"})
@Parameter({"IMAGE", "GOOD_CODESIGN_SIGN_IDENTITY"})
@Parameter({"MAC_PKG", "GOOD_CODESIGN_SIGN_IDENTITY", "GOOD_PKG_SIGN_IDENTITY"})
@Parameter({"MAC_PKG", "GOOD_PKG_SIGN_IDENTITY"})
- public static void testMultipleCertificates(PackageType type, SignOption... options) {
+ public static void testMultipleCertificates(PackageType type, SignOption... optionIds) {
+
+ var options = Stream.of(optionIds).map(SignOption::option).toList();
MacSign.withKeychain(keychain -> {
+
final var cmd = MacHelper.useKeychain(JPackageCommand.helloAppImage(), keychain)
- .ignoreDefaultVerbose(true)
- .addArguments(Stream.of(options).map(SignOption::args).flatMap(List::stream).toList())
+ .mutate(MacSignTest::init)
+ .addArguments(options.stream().map(SignKeyOption::asCmdlineArgs).flatMap(List::stream).toList())
.setPackageType(type);
- Predicate filter = opt -> {
- if (type == PackageType.MAC_PKG && options.length > 1) {
- // Only the first error will be reported and it should always be
- // for the app image signing, not for the PKG signing.
- return opt.identityType() == CertificateType.CODE_SIGN;
- } else {
- return true;
- }
- };
+ if (List.of(optionIds).equals(List.of(SignOption.GOOD_PKG_SIGN_IDENTITY))) {
+ /**
+ * Normally, if multiple signing identities share the same name, signing should
+ * fail. However, in pass-through signing, when jpackage passes signing
+ * identities without validation to signing commands, signing a .pkg installer
+ * with a name matching two signing identities succeeds.
+ */
+ var group = TKit.TextStreamVerifier.group();
- SignOption.configureOutputValidation(cmd, Stream.of(options).filter(filter).toList(), opt -> {
- return JPackageStringBundle.MAIN.cannedFormattedString("error.multiple.certs.found", opt.identityName(), keychain.name());
+ group.add(TKit.assertTextStream(JPackageStringBundle.MAIN.cannedFormattedString(
+ "warning.unsigned.app.image", "pkg").getValue()));
+
+ cmd.validateOutput(group.create().andThen(TKit.assertEndOfTextStream()));
+
+ cmd.execute();
+ return;
+ }
+
+ configureOutputValidation(cmd, expectFailures(options), opt -> {
+ if (!opt.passThrough().orElse(false)) {
+ return expectConfigurationError("error.multiple.certs.found", opt.certRequest().name(), keychain.name());
+ } else {
+ var builder = buildSignCommandErrorValidator(opt, keychain);
+ switch (opt.optionName().orElseThrow()) {
+ case KEY_IDENTITY_APP_IMAGE, KEY_USER_NAME -> {
+ builder.output(String.format("%s: ambiguous", opt.certRequest().name()));
+ }
+ case KEY_IDENTITY_INSTALLER -> {
+ var regexp = Pattern.compile(String.format(
+ "^productbuild: error: Cannot write product to \\S+ \\(Could not find appropriate signing identity for “%s” in keychain at “%s”\\.\\)",
+ Pattern.quote(opt.certRequest().name()),
+ Pattern.quote(keychain.name())
+ ));
+ builder.validators(TKit.assertTextStream(regexp));
+ }
+ }
+ return builder.createGroup();
+ }
}).execute(1);
}, MacSign.Keychain.UsageBuilder::addToSearchList, SigningBase.StandardKeychain.DUPLICATE.keychain());
}
@@ -262,7 +314,7 @@ public class MacSignTest {
GOOD_SIGNING_KEY_USER_NAME(SIGN_KEY_USER_SHORT_NAME, SigningBase.StandardCertificateRequest.CODESIGN),
GOOD_SIGNING_KEY_USER_NAME_PKG(SIGN_KEY_USER_SHORT_NAME, SigningBase.StandardCertificateRequest.PKG),
GOOD_CODESIGN_SIGN_IDENTITY(SIGN_KEY_IDENTITY, SigningBase.StandardCertificateRequest.CODESIGN),
- GOOD_PKG_SIGN_IDENTITY(SIGN_KEY_IDENTITY_APP_IMAGE, SigningBase.StandardCertificateRequest.PKG);
+ GOOD_PKG_SIGN_IDENTITY(SIGN_KEY_IDENTITY, SigningBase.StandardCertificateRequest.PKG);
SignOption(SignKeyOption.Type optionType, NamedCertificateRequestSupplier certRequestSupplier) {
this.option = new SignKeyOption(optionType, new ResolvableCertificateRequest(certRequestSupplier.certRequest(), _ -> {
@@ -270,44 +322,111 @@ public class MacSignTest {
}, certRequestSupplier.name()));
}
- boolean passThrough() {
- return option.type().mapOptionName(option.certRequest().type()).orElseThrow().passThrough();
- }
-
- boolean expired() {
- return option.certRequest().expired();
- }
-
- String identityName() {
- return option.certRequest().name();
- }
-
- CertificateType identityType() {
- return option.certRequest().type();
- }
-
- List args() {
- return option.asCmdlineArgs();
- }
-
- static JPackageCommand configureOutputValidation(JPackageCommand cmd, List options,
- Function conv) {
- options.stream().filter(SignOption::passThrough)
- .map(conv)
- .map(CannedFormattedString::getValue)
- .map(TKit::assertTextStream)
- .map(TKit.TextStreamVerifier::negate)
- .forEach(cmd::validateOutput);
-
- options.stream().filter(Predicate.not(SignOption::passThrough))
- .map(conv)
- .map(CannedFormattedString::getValue)
- .map(TKit::assertTextStream)
- .forEach(cmd::validateOutput);
-
- return cmd;
+ SignKeyOption option() {
+ return option;
}
private final SignKeyOption option;
}
+
+ private static JPackageCommand configureOutputValidation(JPackageCommand cmd, Stream options,
+ Function conv) {
+
+ // Validate jpackage's output matches expected output.
+
+ var outputValidator = options.sorted(Comparator.comparing(option -> {
+ return option.certRequest().type();
+ })).map(conv).reduce(
+ TKit.TextStreamVerifier.group(),
+ TKit.TextStreamVerifier.Group::add,
+ TKit.TextStreamVerifier.Group::add).tryCreate().map(consumer -> {
+ return consumer.andThen(TKit.assertEndOfTextStream());
+ }).orElseGet(TKit::assertEndOfTextStream);
+
+ cmd.validateOutput(outputValidator);
+
+ return cmd;
+ }
+
+ private static Stream expectFailures(Collection options) {
+
+ if (!options.stream().map(option -> {
+ return option.passThrough().orElse(false);
+ }).distinct().reduce((x, y) -> {
+ throw new IllegalArgumentException();
+ }).get()) {
+ // No pass-through signing options.
+ // This means jpackage will validate them at the configuration phase and report all detected errors.
+ return options.stream();
+ }
+
+ // Pass-through signing options.
+ // jpackage will not validate them and will report only one error at the packaging phase.
+
+ Function> filterType = type -> {
+ return option -> {
+ return option.certRequest().type() == type;
+ };
+ };
+
+ var appImageSignOption = options.stream()
+ .filter(filterType.apply(MacSign.CertificateType.CODE_SIGN)).findFirst();
+ var pkgSignOption = options.stream()
+ .filter(filterType.apply(MacSign.CertificateType.INSTALLER)).findFirst();
+
+ if (appImageSignOption.isPresent() && pkgSignOption.isPresent()) {
+ return options.stream().filter(option -> {
+ return appImageSignOption.get() == option;
+ });
+ } else {
+ return options.stream();
+ }
+ }
+
+ private static TKit.TextStreamVerifier.Group expectConfigurationError(String key, Object ... args) {
+ var str = JPackageStringBundle.MAIN.cannedFormattedString(key, args);
+ str = JPackageCommand.makeError(str);
+ return TKit.TextStreamVerifier.group().add(TKit.assertTextStream(str.getValue()).predicate(String::equals));
+ }
+
+ private static FailedCommandErrorValidator buildSignCommandErrorValidator(SignKeyOptionWithKeychain option) {
+ return buildSignCommandErrorValidator(option.signKeyOption(), option.keychain());
+ }
+
+ private static FailedCommandErrorValidator buildSignCommandErrorValidator(SignKeyOption option, MacSign.ResolvedKeychain keychain) {
+
+ Objects.requireNonNull(option);
+ Objects.requireNonNull(keychain);
+
+ String cmdlinePatternFormat;
+ String signIdentity;
+
+ switch (option.optionName().orElseThrow()) {
+ case KEY_IDENTITY_APP_IMAGE, KEY_USER_NAME -> {
+ cmdlinePatternFormat = "^/usr/bin/codesign -s %s -vvvv --timestamp --options runtime --prefix \\S+ --keychain %s";
+ if (option.passThrough().orElse(false)) {
+ signIdentity = String.format("'%s'", option.asCmdlineArgs().getLast());
+ } else {
+ signIdentity = MacSign.CertificateHash.of(option.certRequest().cert()).toString();
+ }
+ }
+ case KEY_IDENTITY_INSTALLER -> {
+ cmdlinePatternFormat = "^/usr/bin/productbuild --resources \\S+ --sign %s --keychain %s";
+ signIdentity = String.format("'%s'", option.asCmdlineArgs().getLast());
+ }
+ default -> {
+ throw ExceptionBox.reachedUnreachable();
+ }
+ }
+
+ return new FailedCommandErrorValidator(Pattern.compile(String.format(
+ cmdlinePatternFormat,
+ Pattern.quote(signIdentity),
+ Pattern.quote(keychain.name())
+ ))).exitCode(1);
+ }
+
+ private static void init(JPackageCommand cmd) {
+ cmd.setFakeRuntime().ignoreDefaultVerbose(true);
+ }
}
From 56afb460a0055206a1deb1260f6440de9d437acb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Beno=C3=AEt=20Maillard?=
Date: Wed, 11 Feb 2026 08:27:48 +0000
Subject: [PATCH 09/77] 8375038: C2: Enforce that Ideal() returns the root of
the subgraph if any change was made by checking the node hash
Reviewed-by: qamai, mchevalier
---
src/hotspot/share/opto/c2_globals.hpp | 6 ++++--
src/hotspot/share/opto/cfgnode.cpp | 9 +++++----
src/hotspot/share/opto/intrinsicnode.cpp | 6 +++---
src/hotspot/share/opto/node.cpp | 12 ++++++++----
src/hotspot/share/opto/phaseX.cpp | 14 +++++++++++++-
src/hotspot/share/opto/phaseX.hpp | 6 +++++-
.../runtime/flags/jvmFlagConstraintsCompiler.cpp | 4 ++--
.../jtreg/compiler/c2/TestVerifyIterativeGVN.java | 4 ++--
8 files changed, 42 insertions(+), 19 deletions(-)
diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp
index f470049bf7e..1662f808286 100644
--- a/src/hotspot/share/opto/c2_globals.hpp
+++ b/src/hotspot/share/opto/c2_globals.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2026, 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
@@ -694,7 +694,9 @@
"Print progress during Iterative Global Value Numbering") \
\
develop(uint, VerifyIterativeGVN, 0, \
- "Verify Iterative Global Value Numbering =EDCBA, with:" \
+ "Verify Iterative Global Value Numbering =FEDCBA, with:" \
+ " F: verify Node::Ideal does not return nullptr if the node" \
+ "hash has changed" \
" E: verify node specific invariants" \
" D: verify Node::Identity did not miss opportunities" \
" C: verify Node::Ideal did not miss opportunities" \
diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp
index efa0b55e2c2..c65bc391792 100644
--- a/src/hotspot/share/opto/cfgnode.cpp
+++ b/src/hotspot/share/opto/cfgnode.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2026, 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
@@ -2243,7 +2243,7 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) {
PhaseIterGVN* igvn = phase->is_IterGVN();
if (wait_for_cast_input_igvn(igvn)) {
igvn->_worklist.push(this);
- return nullptr;
+ return progress;
}
uncasted = true;
uin = unique_input(phase, true);
@@ -2320,6 +2320,7 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) {
PhaseIterGVN* igvn = phase->is_IterGVN();
for (uint i = 1; i < req(); i++) {
set_req_X(i, cast, igvn);
+ progress = this;
}
uin = cast;
}
@@ -2338,7 +2339,7 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) {
#endif
// Identity may not return the expected uin, if it has to wait for the region, in irreducible case
assert(ident == uin || ident->is_top() || must_wait_for_region_in_irreducible_loop(phase), "Identity must clean this up");
- return nullptr;
+ return progress;
}
Node* opt = nullptr;
@@ -2529,7 +2530,7 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// Phi references itself through all other inputs then splitting the
// Phi through memory merges would create dead loop at later stage.
if (ii == top) {
- return nullptr; // Delay optimization until graph is cleaned.
+ return progress; // Delay optimization until graph is cleaned.
}
if (ii->is_MergeMem()) {
MergeMemNode* n = ii->as_MergeMem();
diff --git a/src/hotspot/share/opto/intrinsicnode.cpp b/src/hotspot/share/opto/intrinsicnode.cpp
index 1397d31af53..c3e003ad8d3 100644
--- a/src/hotspot/share/opto/intrinsicnode.cpp
+++ b/src/hotspot/share/opto/intrinsicnode.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2026, 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
@@ -46,8 +46,8 @@ Node* StrIntrinsicNode::Ideal(PhaseGVN* phase, bool can_reshape) {
if (in(0) && in(0)->is_top()) return nullptr;
if (can_reshape) {
- Node* mem = phase->transform(in(MemNode::Memory));
- // If transformed to a MergeMem, get the desired slice
+ Node* mem = in(MemNode::Memory);
+ // If mem input is a MergeMem, get the desired slice
uint alias_idx = phase->C->get_alias_index(adr_type());
mem = mem->is_MergeMem() ? mem->as_MergeMem()->memory_at(alias_idx) : mem;
if (mem != in(MemNode::Memory)) {
diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp
index 832727a424e..cb5795a1250 100644
--- a/src/hotspot/share/opto/node.cpp
+++ b/src/hotspot/share/opto/node.cpp
@@ -1151,15 +1151,19 @@ const Type* Node::Value(PhaseGVN* phase) const {
// 'Idealize' the graph rooted at this Node.
//
// In order to be efficient and flexible there are some subtle invariants
-// these Ideal calls need to hold. Running with '-XX:VerifyIterativeGVN=1' checks
-// these invariants, although its too slow to have on by default. If you are
-// hacking an Ideal call, be sure to test with '-XX:VerifyIterativeGVN=1'
+// these Ideal calls need to hold. Some of the flag bits for '-XX:VerifyIterativeGVN'
+// can help with validating these invariants, although they are too slow to have on by default:
+// - '-XX:VerifyIterativeGVN=1' checks the def-use info
+// - '-XX:VerifyIterativeGVN=100000' checks the return value
+// If you are hacking an Ideal call, be sure to use these.
//
// The Ideal call almost arbitrarily reshape the graph rooted at the 'this'
// pointer. If ANY change is made, it must return the root of the reshaped
// graph - even if the root is the same Node. Example: swapping the inputs
// to an AddINode gives the same answer and same root, but you still have to
-// return the 'this' pointer instead of null.
+// return the 'this' pointer instead of null. If the node was already dead
+// before the Ideal call, this rule does not apply, and it is fine to return
+// nullptr even if modifications were made.
//
// You cannot return an OLD Node, except for the 'this' pointer. Use the
// Identity call to return an old Node; basically if Identity can find
diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp
index ce24c46590d..d2b2904b545 100644
--- a/src/hotspot/share/opto/phaseX.cpp
+++ b/src/hotspot/share/opto/phaseX.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2026, 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
@@ -2167,9 +2167,15 @@ Node *PhaseIterGVN::transform_old(Node* n) {
DEBUG_ONLY(dead_loop_check(k);)
DEBUG_ONLY(bool is_new = (k->outcnt() == 0);)
C->remove_modified_node(k);
+#ifndef PRODUCT
+ uint hash_before = is_verify_Ideal_return() ? k->hash() : 0;
+#endif
Node* i = apply_ideal(k, /*can_reshape=*/true);
assert(i != k || is_new || i->outcnt() > 0, "don't return dead nodes");
#ifndef PRODUCT
+ if (is_verify_Ideal_return()) {
+ assert(k->outcnt() == 0 || i != nullptr || hash_before == k->hash(), "hash changed after Ideal returned nullptr for %s", k->Name());
+ }
verify_step(k);
#endif
@@ -2193,9 +2199,15 @@ Node *PhaseIterGVN::transform_old(Node* n) {
// Try idealizing again
DEBUG_ONLY(is_new = (k->outcnt() == 0);)
C->remove_modified_node(k);
+#ifndef PRODUCT
+ uint hash_before = is_verify_Ideal_return() ? k->hash() : 0;
+#endif
i = apply_ideal(k, /*can_reshape=*/true);
assert(i != k || is_new || (i->outcnt() > 0), "don't return dead nodes");
#ifndef PRODUCT
+ if (is_verify_Ideal_return()) {
+ assert(k->outcnt() == 0 || i != nullptr || hash_before == k->hash(), "hash changed after Ideal returned nullptr for %s", k->Name());
+ }
verify_step(k);
#endif
DEBUG_ONLY(loop_count++;)
diff --git a/src/hotspot/share/opto/phaseX.hpp b/src/hotspot/share/opto/phaseX.hpp
index ce02f456c00..cc0d47bd634 100644
--- a/src/hotspot/share/opto/phaseX.hpp
+++ b/src/hotspot/share/opto/phaseX.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2026, 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
@@ -627,6 +627,10 @@ public:
// '-XX:VerifyIterativeGVN=10000'
return ((VerifyIterativeGVN % 100000) / 10000) == 1;
}
+ static bool is_verify_Ideal_return() {
+ // '-XX:VerifyIterativeGVN=100000'
+ return ((VerifyIterativeGVN % 1000000) / 100000) == 1;
+ }
protected:
// Sub-quadratic implementation of '-XX:VerifyIterativeGVN=1' (Use-Def verification).
julong _verify_counter;
diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp
index 63d3424b3ed..47a02184d29 100644
--- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp
+++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2026, 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
@@ -306,7 +306,7 @@ JVMFlag::Error TypeProfileLevelConstraintFunc(uint value, bool verbose) {
}
JVMFlag::Error VerifyIterativeGVNConstraintFunc(uint value, bool verbose) {
- const int max_modes = 5;
+ const int max_modes = 6;
uint original_value = value;
for (int i = 0; i < max_modes; i++) {
if (value % 10 > 1) {
diff --git a/test/hotspot/jtreg/compiler/c2/TestVerifyIterativeGVN.java b/test/hotspot/jtreg/compiler/c2/TestVerifyIterativeGVN.java
index 4b6215b25bd..39bb8b0a0ad 100644
--- a/test/hotspot/jtreg/compiler/c2/TestVerifyIterativeGVN.java
+++ b/test/hotspot/jtreg/compiler/c2/TestVerifyIterativeGVN.java
@@ -25,9 +25,9 @@
* @test
* @bug 8238756 8351889
* @requires vm.debug == true & vm.flavor == "server"
- * @summary Run with -Xcomp to test -XX:VerifyIterativeGVN=11111 in debug builds.
+ * @summary Run with -Xcomp to test -XX:VerifyIterativeGVN=111111 in debug builds.
*
- * @run main/othervm/timeout=300 -Xcomp -XX:VerifyIterativeGVN=11111 compiler.c2.TestVerifyIterativeGVN
+ * @run main/othervm/timeout=300 -Xcomp -XX:VerifyIterativeGVN=111111 compiler.c2.TestVerifyIterativeGVN
*/
package compiler.c2;
From 1e99cc4880f695c12705d849d41609f176f897bd Mon Sep 17 00:00:00 2001
From: Christian Stein
Date: Wed, 11 Feb 2026 09:14:31 +0000
Subject: [PATCH 10/77] 8376355: Update to use jtreg 8.2.1
Reviewed-by: iris, erikj, shade
---
make/autoconf/lib-tests.m4 | 4 ++--
make/conf/github-actions.conf | 4 ++--
make/conf/jib-profiles.js | 6 +++---
test/docs/TEST.ROOT | 4 ++--
test/hotspot/jtreg/TEST.ROOT | 4 ++--
test/jaxp/TEST.ROOT | 2 +-
test/jdk/TEST.ROOT | 4 ++--
test/langtools/TEST.ROOT | 2 +-
test/lib-test/TEST.ROOT | 4 ++--
9 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/make/autoconf/lib-tests.m4 b/make/autoconf/lib-tests.m4
index 31d48055984..faaf229eacd 100644
--- a/make/autoconf/lib-tests.m4
+++ b/make/autoconf/lib-tests.m4
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,7 @@
################################################################################
# Minimum supported versions
-JTREG_MINIMUM_VERSION=8.1
+JTREG_MINIMUM_VERSION=8.2.1
GTEST_MINIMUM_VERSION=1.14.0
################################################################################
diff --git a/make/conf/github-actions.conf b/make/conf/github-actions.conf
index bd73e909062..ebfc9191535 100644
--- a/make/conf/github-actions.conf
+++ b/make/conf/github-actions.conf
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2020, 2026, 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
@@ -26,7 +26,7 @@
# Versions and download locations for dependencies used by GitHub Actions (GHA)
GTEST_VERSION=1.14.0
-JTREG_VERSION=8.1+1
+JTREG_VERSION=8.2.1+1
LINUX_X64_BOOT_JDK_EXT=tar.gz
LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk25/bd75d5f9689641da8e1daabeccb5528b/36/GPL/openjdk-25_linux-x64_bin.tar.gz
diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js
index 93aeebc0dd6..76a94b7789e 100644
--- a/make/conf/jib-profiles.js
+++ b/make/conf/jib-profiles.js
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2026, 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
@@ -1174,9 +1174,9 @@ var getJibProfilesDependencies = function (input, common) {
jtreg: {
server: "jpg",
product: "jtreg",
- version: "8.1",
+ version: "8.2.1",
build_number: "1",
- file: "bundles/jtreg-8.1+1.zip",
+ file: "bundles/jtreg-8.2.1+1.zip",
environment_name: "JT_HOME",
environment_path: input.get("jtreg", "home_path") + "/bin",
configure_args: "--with-jtreg=" + input.get("jtreg", "home_path"),
diff --git a/test/docs/TEST.ROOT b/test/docs/TEST.ROOT
index 69e66b08b88..9a7e66b631c 100644
--- a/test/docs/TEST.ROOT
+++ b/test/docs/TEST.ROOT
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2024, 2026, 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
@@ -38,7 +38,7 @@
groups=TEST.groups
# Minimum jtreg version
-requiredVersion=8.1+1
+requiredVersion=8.2.1+1
# Use new module options
useNewOptions=true
diff --git a/test/hotspot/jtreg/TEST.ROOT b/test/hotspot/jtreg/TEST.ROOT
index 0fdbdae9bc5..d1c72b9768c 100644
--- a/test/hotspot/jtreg/TEST.ROOT
+++ b/test/hotspot/jtreg/TEST.ROOT
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2005, 2026, 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
@@ -107,7 +107,7 @@ requires.properties= \
jdk.static
# Minimum jtreg version
-requiredVersion=8.1+1
+requiredVersion=8.2.1+1
# Path to libraries in the topmost test directory. This is needed so @library
# does not need ../../../ notation to reach them
diff --git a/test/jaxp/TEST.ROOT b/test/jaxp/TEST.ROOT
index 82504c251c0..aff3b769830 100644
--- a/test/jaxp/TEST.ROOT
+++ b/test/jaxp/TEST.ROOT
@@ -23,7 +23,7 @@ modules=java.xml
groups=TEST.groups
# Minimum jtreg version
-requiredVersion=8.1+1
+requiredVersion=8.2.1+1
# Path to libraries in the topmost test directory. This is needed so @library
# does not need ../../ notation to reach them
diff --git a/test/jdk/TEST.ROOT b/test/jdk/TEST.ROOT
index f22b316e19a..cc571deab20 100644
--- a/test/jdk/TEST.ROOT
+++ b/test/jdk/TEST.ROOT
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This file identifies the root of the test-suite hierarchy.
@@ -123,7 +123,7 @@ requires.properties= \
jdk.static
# Minimum jtreg version
-requiredVersion=8.1+1
+requiredVersion=8.2.1+1
# Path to libraries in the topmost test directory. This is needed so @library
# does not need ../../ notation to reach them
diff --git a/test/langtools/TEST.ROOT b/test/langtools/TEST.ROOT
index 14636716882..434cf91b0ec 100644
--- a/test/langtools/TEST.ROOT
+++ b/test/langtools/TEST.ROOT
@@ -15,7 +15,7 @@ keys=intermittent randomness needs-src needs-src-jdk_javadoc
groups=TEST.groups
# Minimum jtreg version
-requiredVersion=8.1+1
+requiredVersion=8.2.1+1
# Use new module options
useNewOptions=true
diff --git a/test/lib-test/TEST.ROOT b/test/lib-test/TEST.ROOT
index ebdf3f1a334..f23d38c1e66 100644
--- a/test/lib-test/TEST.ROOT
+++ b/test/lib-test/TEST.ROOT
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2020, 2026, 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
@@ -29,7 +29,7 @@
keys=randomness
# Minimum jtreg version
-requiredVersion=8.1+1
+requiredVersion=8.2.1+1
# Allow querying of various System properties in @requires clauses
requires.extraPropDefns = ../jtreg-ext/requires/VMProps.java
From 57931dc6b24af2c02206b01bcc417e5607d39371 Mon Sep 17 00:00:00 2001
From: Leo Korinth
Date: Wed, 11 Feb 2026 09:14:58 +0000
Subject: [PATCH 11/77] 8377172: Change datatype of CodeEntryAlignment to uint
Reviewed-by: ayang, mhaessig
---
src/hotspot/cpu/aarch64/globals_aarch64.hpp | 4 ++--
src/hotspot/cpu/arm/globals_arm.hpp | 4 ++--
src/hotspot/cpu/ppc/globals_ppc.hpp | 4 ++--
src/hotspot/cpu/riscv/globals_riscv.hpp | 4 ++--
src/hotspot/cpu/s390/globals_s390.hpp | 4 ++--
src/hotspot/cpu/x86/globals_x86.hpp | 6 ++---
src/hotspot/cpu/x86/macroAssembler_x86.cpp | 2 +-
src/hotspot/cpu/zero/globals_zero.hpp | 4 ++--
src/hotspot/share/asm/codeBuffer.cpp | 6 ++---
src/hotspot/share/code/codeCache.cpp | 2 +-
src/hotspot/share/interpreter/interpreter.hpp | 4 ++--
.../share/jvmci/jvmciCompilerToVMInit.cpp | 11 +++++-----
src/hotspot/share/opto/constantTable.cpp | 4 ++--
.../flags/jvmFlagConstraintsCompiler.cpp | 22 +++++++++----------
.../flags/jvmFlagConstraintsCompiler.hpp | 4 ++--
src/hotspot/share/runtime/globals.hpp | 5 +++--
16 files changed, 45 insertions(+), 45 deletions(-)
diff --git a/src/hotspot/cpu/aarch64/globals_aarch64.hpp b/src/hotspot/cpu/aarch64/globals_aarch64.hpp
index 8e520314c8b..a59e83c4b69 100644
--- a/src/hotspot/cpu/aarch64/globals_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/globals_aarch64.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2019, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -39,7 +39,7 @@ define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap nulls
define_pd_global(bool, DelayCompilerStubsGeneration, COMPILER2_OR_JVMCI);
define_pd_global(size_t, CodeCacheSegmentSize, 64);
-define_pd_global(intx, CodeEntryAlignment, 64);
+define_pd_global(uint, CodeEntryAlignment, 64);
define_pd_global(intx, OptoLoopAlignment, 16);
#define DEFAULT_STACK_YELLOW_PAGES (2)
diff --git a/src/hotspot/cpu/arm/globals_arm.hpp b/src/hotspot/cpu/arm/globals_arm.hpp
index 363a9a2c25c..c568ea04122 100644
--- a/src/hotspot/cpu/arm/globals_arm.hpp
+++ b/src/hotspot/cpu/arm/globals_arm.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2026, 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
@@ -37,7 +37,7 @@ define_pd_global(bool, TrapBasedNullChecks, false); // Not needed
define_pd_global(bool, DelayCompilerStubsGeneration, false); // No need - only few compiler's stubs
define_pd_global(size_t, CodeCacheSegmentSize, 64);
-define_pd_global(intx, CodeEntryAlignment, 16);
+define_pd_global(uint, CodeEntryAlignment, 16);
define_pd_global(intx, OptoLoopAlignment, 16);
#define DEFAULT_STACK_YELLOW_PAGES (2)
diff --git a/src/hotspot/cpu/ppc/globals_ppc.hpp b/src/hotspot/cpu/ppc/globals_ppc.hpp
index 41a8e821ada..927a8cc2be3 100644
--- a/src/hotspot/cpu/ppc/globals_ppc.hpp
+++ b/src/hotspot/cpu/ppc/globals_ppc.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2024 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -60,7 +60,7 @@ define_pd_global(bool, VMContinuations, true);
// Use large code-entry alignment.
define_pd_global(size_t, CodeCacheSegmentSize, 128);
-define_pd_global(intx, CodeEntryAlignment, 64);
+define_pd_global(uint, CodeEntryAlignment, 64);
define_pd_global(intx, OptoLoopAlignment, 16);
define_pd_global(intx, InlineSmallCode, 1500);
diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp
index 390ed2daeb9..21b119266e2 100644
--- a/src/hotspot/cpu/riscv/globals_riscv.hpp
+++ b/src/hotspot/cpu/riscv/globals_riscv.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -39,7 +39,7 @@ define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap nulls
define_pd_global(bool, DelayCompilerStubsGeneration, COMPILER2_OR_JVMCI);
define_pd_global(size_t, CodeCacheSegmentSize, 64 COMPILER1_AND_COMPILER2_PRESENT(+64)); // Tiered compilation has large code-entry alignment.
-define_pd_global(intx, CodeEntryAlignment, 64);
+define_pd_global(uint, CodeEntryAlignment, 64);
define_pd_global(intx, OptoLoopAlignment, 16);
#define DEFAULT_STACK_YELLOW_PAGES (2)
diff --git a/src/hotspot/cpu/s390/globals_s390.hpp b/src/hotspot/cpu/s390/globals_s390.hpp
index 07987ea3469..d110443adf8 100644
--- a/src/hotspot/cpu/s390/globals_s390.hpp
+++ b/src/hotspot/cpu/s390/globals_s390.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2018 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -43,7 +43,7 @@ define_pd_global(size_t, CodeCacheSegmentSize, 256);
// Ideally, this is 256 (cache line size). This keeps code end data
// on separate lines. But we reduced it to 64 since 256 increased
// code size significantly by padding nops between IVC and second UEP.
-define_pd_global(intx, CodeEntryAlignment, 64);
+define_pd_global(uint, CodeEntryAlignment, 64);
define_pd_global(intx, OptoLoopAlignment, 2);
define_pd_global(intx, InlineSmallCode, 2000);
diff --git a/src/hotspot/cpu/x86/globals_x86.hpp b/src/hotspot/cpu/x86/globals_x86.hpp
index 103e22d0185..4f5b6d31e75 100644
--- a/src/hotspot/cpu/x86/globals_x86.hpp
+++ b/src/hotspot/cpu/x86/globals_x86.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2026, 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
@@ -46,9 +46,9 @@ define_pd_global(size_t, CodeCacheSegmentSize, 64 COMPILER1_AND_COMPILER2_PRES
// the uep and the vep doesn't get real alignment but just slops on by
// only assured that the entry instruction meets the 5 byte size requirement.
#if COMPILER2_OR_JVMCI
-define_pd_global(intx, CodeEntryAlignment, 32);
+define_pd_global(uint, CodeEntryAlignment, 32);
#else
-define_pd_global(intx, CodeEntryAlignment, 16);
+define_pd_global(uint, CodeEntryAlignment, 16);
#endif // COMPILER2_OR_JVMCI
define_pd_global(intx, OptoLoopAlignment, 16);
define_pd_global(intx, InlineSmallCode, 1000);
diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp
index d4d3ec85bcf..83169df3456 100644
--- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp
@@ -765,7 +765,7 @@ void MacroAssembler::align32() {
void MacroAssembler::align(uint modulus) {
// 8273459: Ensure alignment is possible with current segment alignment
- assert(modulus <= (uintx)CodeEntryAlignment, "Alignment must be <= CodeEntryAlignment");
+ assert(modulus <= CodeEntryAlignment, "Alignment must be <= CodeEntryAlignment");
align(modulus, offset());
}
diff --git a/src/hotspot/cpu/zero/globals_zero.hpp b/src/hotspot/cpu/zero/globals_zero.hpp
index 6b6c6ea983c..6dc7d81275c 100644
--- a/src/hotspot/cpu/zero/globals_zero.hpp
+++ b/src/hotspot/cpu/zero/globals_zero.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -39,7 +39,7 @@ define_pd_global(bool, UncommonNullCast, true);
define_pd_global(bool, DelayCompilerStubsGeneration, false); // Don't have compiler's stubs
define_pd_global(size_t, CodeCacheSegmentSize, 64 COMPILER1_AND_COMPILER2_PRESENT(+64)); // Tiered compilation has large code-entry alignment.
-define_pd_global(intx, CodeEntryAlignment, 32);
+define_pd_global(uint, CodeEntryAlignment, 32);
define_pd_global(intx, OptoLoopAlignment, 16);
define_pd_global(intx, InlineSmallCode, 1000);
diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp
index d94f52c18f6..ba525588f32 100644
--- a/src/hotspot/share/asm/codeBuffer.cpp
+++ b/src/hotspot/share/asm/codeBuffer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2026, 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
@@ -468,9 +468,7 @@ void CodeBuffer::compute_final_layout(CodeBuffer* dest) const {
assert(!_finalize_stubs, "non-finalized stubs");
{
- // not sure why this is here, but why not...
- int alignSize = MAX2((intx) sizeof(jdouble), CodeEntryAlignment);
- assert( (dest->_total_start - _insts.start()) % alignSize == 0, "copy must preserve alignment");
+ assert( (dest->_total_start - _insts.start()) % CodeEntryAlignment == 0, "copy must preserve alignment");
}
const CodeSection* prev_cs = nullptr;
diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp
index 481eb51bd5c..2a0256cc316 100644
--- a/src/hotspot/share/code/codeCache.cpp
+++ b/src/hotspot/share/code/codeCache.cpp
@@ -1139,7 +1139,7 @@ size_t CodeCache::freelists_length() {
void icache_init();
void CodeCache::initialize() {
- assert(CodeCacheSegmentSize >= (size_t)CodeEntryAlignment, "CodeCacheSegmentSize must be large enough to align entry points");
+ assert(CodeCacheSegmentSize >= CodeEntryAlignment, "CodeCacheSegmentSize must be large enough to align entry points");
#ifdef COMPILER2
assert(CodeCacheSegmentSize >= (size_t)OptoLoopAlignment, "CodeCacheSegmentSize must be large enough to align inner loops");
#endif
diff --git a/src/hotspot/share/interpreter/interpreter.hpp b/src/hotspot/share/interpreter/interpreter.hpp
index 576146b344e..f7d42fcb4da 100644
--- a/src/hotspot/share/interpreter/interpreter.hpp
+++ b/src/hotspot/share/interpreter/interpreter.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2026, 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
@@ -59,7 +59,7 @@ class InterpreterCodelet: public Stub {
// General info/converters
int size() const { return _size; }
static int alignment() { return HeapWordSize; }
- static int code_alignment() { return CodeEntryAlignment; }
+ static uint code_alignment() { return CodeEntryAlignment; }
// Code info
address code_begin() const { return align_up((address)this + sizeof(InterpreterCodelet), code_alignment()); }
diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp
index 3e9d8c97b88..6214f6a2746 100644
--- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2026, 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
@@ -355,7 +355,7 @@ JVMCIObjectArray CompilerToVM::initialize_intrinsics(JVMCI_TRAPS) {
return vmIntrinsics;
}
-#define PREDEFINED_CONFIG_FLAGS(do_bool_flag, do_int_flag, do_size_t_flag, do_intx_flag, do_uintx_flag) \
+#define PREDEFINED_CONFIG_FLAGS(do_bool_flag, do_uint_flag, do_int_flag, do_size_t_flag, do_intx_flag, do_uintx_flag) \
do_int_flag(AllocateInstancePrefetchLines) \
do_int_flag(AllocatePrefetchDistance) \
do_intx_flag(AllocatePrefetchInstr) \
@@ -367,7 +367,7 @@ JVMCIObjectArray CompilerToVM::initialize_intrinsics(JVMCI_TRAPS) {
do_bool_flag(CITime) \
do_bool_flag(CITimeEach) \
do_size_t_flag(CodeCacheSegmentSize) \
- do_intx_flag(CodeEntryAlignment) \
+ do_uint_flag(CodeEntryAlignment) \
do_int_flag(ContendedPaddingWidth) \
do_bool_flag(DontCompileHugeMethods) \
do_bool_flag(EagerJVMCI) \
@@ -554,16 +554,17 @@ jobjectArray readConfiguration0(JNIEnv *env, JVMCI_TRAPS) {
JVMCIENV->put_object_at(vmFlags, i++, vmFlagObj); \
}
#define ADD_BOOL_FLAG(name) ADD_FLAG(bool, name, BOXED_BOOLEAN)
+#define ADD_UINT_FLAG(name) ADD_FLAG(uint, name, BOXED_LONG)
#define ADD_INT_FLAG(name) ADD_FLAG(int, name, BOXED_LONG)
#define ADD_SIZE_T_FLAG(name) ADD_FLAG(size_t, name, BOXED_LONG)
#define ADD_INTX_FLAG(name) ADD_FLAG(intx, name, BOXED_LONG)
#define ADD_UINTX_FLAG(name) ADD_FLAG(uintx, name, BOXED_LONG)
- len = 0 + PREDEFINED_CONFIG_FLAGS(COUNT_FLAG, COUNT_FLAG, COUNT_FLAG, COUNT_FLAG, COUNT_FLAG);
+ len = 0 + PREDEFINED_CONFIG_FLAGS(COUNT_FLAG, COUNT_FLAG, COUNT_FLAG, COUNT_FLAG, COUNT_FLAG, COUNT_FLAG);
JVMCIObjectArray vmFlags = JVMCIENV->new_VMFlag_array(len, JVMCI_CHECK_NULL);
int i = 0;
JVMCIObject value;
- PREDEFINED_CONFIG_FLAGS(ADD_BOOL_FLAG, ADD_INT_FLAG, ADD_SIZE_T_FLAG, ADD_INTX_FLAG, ADD_UINTX_FLAG)
+ PREDEFINED_CONFIG_FLAGS(ADD_BOOL_FLAG, ADD_UINT_FLAG, ADD_INT_FLAG, ADD_SIZE_T_FLAG, ADD_INTX_FLAG, ADD_UINTX_FLAG)
JVMCIObjectArray vmIntrinsics = CompilerToVM::initialize_intrinsics(JVMCI_CHECK_NULL);
diff --git a/src/hotspot/share/opto/constantTable.cpp b/src/hotspot/share/opto/constantTable.cpp
index aba71e45e1c..ae4ac336d93 100644
--- a/src/hotspot/share/opto/constantTable.cpp
+++ b/src/hotspot/share/opto/constantTable.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2026, 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
@@ -158,7 +158,7 @@ void ConstantTable::calculate_offsets_and_size() {
// Align size up to the next section start (which is insts; see
// CodeBuffer::align_at_start).
assert(_size == -1, "already set?");
- _size = align_up(offset, (int)CodeEntryAlignment);
+ _size = align_up(offset, CodeEntryAlignment);
}
bool ConstantTable::emit(C2_MacroAssembler* masm) const {
diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp
index 47a02184d29..444ce321759 100644
--- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp
+++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp
@@ -163,10 +163,10 @@ JVMFlag::Error CodeCacheSegmentSizeConstraintFunc(size_t value, bool verbose) {
return JVMFlag::VIOLATES_CONSTRAINT;
}
- if (CodeCacheSegmentSize < (size_t)CodeEntryAlignment) {
+ if (CodeCacheSegmentSize < CodeEntryAlignment) {
JVMFlag::printError(verbose,
"CodeCacheSegmentSize (%zu) must be "
- "larger than or equal to CodeEntryAlignment (%zd) "
+ "larger than or equal to CodeEntryAlignment (%u) "
"to align entry points\n",
CodeCacheSegmentSize, CodeEntryAlignment);
return JVMFlag::VIOLATES_CONSTRAINT;
@@ -194,25 +194,25 @@ JVMFlag::Error CodeCacheSegmentSizeConstraintFunc(size_t value, bool verbose) {
return JVMFlag::SUCCESS;
}
-JVMFlag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose) {
+JVMFlag::Error CodeEntryAlignmentConstraintFunc(uint value, bool verbose) {
if (!is_power_of_2(value)) {
JVMFlag::printError(verbose,
- "CodeEntryAlignment (%zd) must be "
+ "CodeEntryAlignment (%u) must be "
"a power of two\n", CodeEntryAlignment);
return JVMFlag::VIOLATES_CONSTRAINT;
}
if (CodeEntryAlignment < 16) {
JVMFlag::printError(verbose,
- "CodeEntryAlignment (%zd) must be "
+ "CodeEntryAlignment (%u) must be "
"greater than or equal to %d\n",
CodeEntryAlignment, 16);
return JVMFlag::VIOLATES_CONSTRAINT;
}
- if ((size_t)CodeEntryAlignment > CodeCacheSegmentSize) {
+ if (CodeEntryAlignment > CodeCacheSegmentSize) {
JVMFlag::printError(verbose,
- "CodeEntryAlignment (%zd) must be "
+ "CodeEntryAlignment (%u) must be "
"less than or equal to CodeCacheSegmentSize (%zu) "
"to align entry points\n",
CodeEntryAlignment, CodeCacheSegmentSize);
@@ -241,10 +241,10 @@ JVMFlag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose) {
return JVMFlag::VIOLATES_CONSTRAINT;
}
- if (OptoLoopAlignment > CodeEntryAlignment) {
+ if (checked_cast(OptoLoopAlignment) > CodeEntryAlignment) {
JVMFlag::printError(verbose,
"OptoLoopAlignment (%zd) must be "
- "less or equal to CodeEntryAlignment (%zd)\n",
+ "less or equal to CodeEntryAlignment (%u)\n",
value, CodeEntryAlignment);
return JVMFlag::VIOLATES_CONSTRAINT;
}
@@ -339,10 +339,10 @@ JVMFlag::Error InitArrayShortSizeConstraintFunc(intx value, bool verbose) {
#ifdef COMPILER2
JVMFlag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) {
- if (InteriorEntryAlignment > CodeEntryAlignment) {
+ if (checked_cast(InteriorEntryAlignment) > CodeEntryAlignment) {
JVMFlag::printError(verbose,
"InteriorEntryAlignment (%zd) must be "
- "less than or equal to CodeEntryAlignment (%zd)\n",
+ "less than or equal to CodeEntryAlignment (%u)\n",
InteriorEntryAlignment, CodeEntryAlignment);
return JVMFlag::VIOLATES_CONSTRAINT;
}
diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.hpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.hpp
index 4544ad706fd..cf785800cfc 100644
--- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.hpp
+++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2026, 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 @@
f(intx, CompileThresholdConstraintFunc) \
f(intx, OnStackReplacePercentageConstraintFunc) \
f(size_t, CodeCacheSegmentSizeConstraintFunc) \
- f(intx, CodeEntryAlignmentConstraintFunc) \
+ f(uint, CodeEntryAlignmentConstraintFunc) \
f(intx, OptoLoopAlignmentConstraintFunc) \
f(uintx, ArraycopyDstPrefetchDistanceConstraintFunc) \
f(uintx, ArraycopySrcPrefetchDistanceConstraintFunc) \
diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp
index 6a2bbc9c648..6d4b9908e1c 100644
--- a/src/hotspot/share/runtime/globals.hpp
+++ b/src/hotspot/share/runtime/globals.hpp
@@ -1508,8 +1508,9 @@ const int ObjectAlignmentInBytes = 8;
range(1, 1024) \
constraint(CodeCacheSegmentSizeConstraintFunc, AfterErgo) \
\
- product_pd(intx, CodeEntryAlignment, EXPERIMENTAL, \
- "Code entry alignment for generated code (in bytes)") \
+ product_pd(uint, CodeEntryAlignment, EXPERIMENTAL, \
+ "Code entry alignment for generated code" \
+ " (in bytes, power of two)") \
constraint(CodeEntryAlignmentConstraintFunc, AfterErgo) \
\
product_pd(intx, OptoLoopAlignment, \
From 9026f49dd238d16240687c4627e42c5dbee08773 Mon Sep 17 00:00:00 2001
From: Thomas Schatzl
Date: Wed, 11 Feb 2026 09:23:52 +0000
Subject: [PATCH 12/77] 8377446: Improve parameter naming in pointer_delta()
Reviewed-by: ayang, chagedorn
---
src/hotspot/share/adlc/adlArena.cpp | 6 ++---
.../share/utilities/globalDefinitions.hpp | 23 ++++++++++---------
2 files changed, 15 insertions(+), 14 deletions(-)
diff --git a/src/hotspot/share/adlc/adlArena.cpp b/src/hotspot/share/adlc/adlArena.cpp
index ebd1f74911d..e3ae60e91a9 100644
--- a/src/hotspot/share/adlc/adlArena.cpp
+++ b/src/hotspot/share/adlc/adlArena.cpp
@@ -136,9 +136,9 @@ void *AdlArena::Acalloc( size_t items, size_t x ) {
}
//------------------------------realloc----------------------------------------
-static size_t pointer_delta(const void *left, const void *right) {
- assert(left >= right, "pointer delta underflow");
- return (uintptr_t)left - (uintptr_t)right;
+static size_t pointer_delta(const void* high, const void* low) {
+ assert(high >= low, "pointer delta underflow");
+ return (uintptr_t)high - (uintptr_t)low;
}
// Reallocate storage in AdlArena.
diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp
index 54602297759..ea4f6f99ae6 100644
--- a/src/hotspot/share/utilities/globalDefinitions.hpp
+++ b/src/hotspot/share/utilities/globalDefinitions.hpp
@@ -433,7 +433,8 @@ typedef unsigned char u_char;
typedef u_char* address;
typedef const u_char* const_address;
-// Pointer subtraction.
+// Pointer subtraction, calculating high - low. Asserts on underflow.
+//
// The idea here is to avoid ptrdiff_t, which is signed and so doesn't have
// the range we might need to find differences from one end of the heap
// to the other.
@@ -444,28 +445,28 @@ typedef const u_char* const_address;
// and then additions like
// ... top() + size ...
// are safe because we know that top() is at least size below end().
-inline size_t pointer_delta(const volatile void* left,
- const volatile void* right,
+inline size_t pointer_delta(const volatile void* high,
+ const volatile void* low,
size_t element_size) {
- assert(left >= right, "avoid underflow - left: " PTR_FORMAT " right: " PTR_FORMAT, p2i(left), p2i(right));
- return (((uintptr_t) left) - ((uintptr_t) right)) / element_size;
+ assert(high >= low, "avoid underflow - high address: " PTR_FORMAT " low address: " PTR_FORMAT, p2i(high), p2i(low));
+ return (((uintptr_t) high) - ((uintptr_t) low)) / element_size;
}
// A version specialized for HeapWord*'s.
-inline size_t pointer_delta(const HeapWord* left, const HeapWord* right) {
- return pointer_delta(left, right, sizeof(HeapWord));
+inline size_t pointer_delta(const HeapWord* high, const HeapWord* low) {
+ return pointer_delta(high, low, sizeof(HeapWord));
}
// A version specialized for MetaWord*'s.
-inline size_t pointer_delta(const MetaWord* left, const MetaWord* right) {
- return pointer_delta(left, right, sizeof(MetaWord));
+inline size_t pointer_delta(const MetaWord* high, const MetaWord* low) {
+ return pointer_delta(high, low, sizeof(MetaWord));
}
// pointer_delta_as_int is called to do pointer subtraction for nearby pointers that
// returns a non-negative int, usually used as a size of a code buffer range.
// This scales to sizeof(T).
template
-inline int pointer_delta_as_int(const volatile T* left, const volatile T* right) {
- size_t delta = pointer_delta(left, right, sizeof(T));
+inline int pointer_delta_as_int(const volatile T* high, const volatile T* low) {
+ size_t delta = pointer_delta(high, low, sizeof(T));
assert(delta <= size_t(INT_MAX), "pointer delta out of range: %zu", delta);
return static_cast(delta);
}
From e34291d8e11164ab3b6d0f6a3e8819bc29b32124 Mon Sep 17 00:00:00 2001
From: Thomas Schatzl
Date: Wed, 11 Feb 2026 09:24:18 +0000
Subject: [PATCH 13/77] 8377442: More fixes to ThreadLocalAllocBuffer after
JDK-8377179
Reviewed-by: ayang, kbarrett, iwalulya
---
src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp | 9 ++++++---
src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp | 8 +++++---
src/hotspot/share/runtime/thread.cpp | 2 +-
src/hotspot/share/runtime/thread.hpp | 3 ++-
src/hotspot/share/runtime/thread.inline.hpp | 2 +-
5 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp
index e86881d3523..d99544c0573 100644
--- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp
+++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp
@@ -459,13 +459,16 @@ size_t ThreadLocalAllocBuffer::end_reserve() {
}
size_t ThreadLocalAllocBuffer::estimated_used_bytes() const {
+ // Data races due to unsynchronized access like the following reads to _start
+ // and _top are undefined behavior. Atomic would not provide any additional
+ // guarantees, so use AtomicAccess directly.
HeapWord* start = AtomicAccess::load(&_start);
HeapWord* top = AtomicAccess::load(&_top);
- // There has been a race when retrieving _top and _start. Return 0.
- if (_top < _start) {
+ // If there has been a race when retrieving _top and _start, return 0.
+ if (top < start) {
return 0;
}
- size_t used_bytes = pointer_delta(_top, _start, 1);
+ size_t used_bytes = pointer_delta(top, start, 1);
// Comparing diff with the maximum allowed size will ensure that we don't add
// the used bytes from a semi-initialized TLAB ending up with implausible values.
// In this case also just return 0.
diff --git a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp
index a50e7c9533c..61caac7ec51 100644
--- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp
+++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp
@@ -32,8 +32,10 @@
class ThreadLocalAllocStats;
-// ThreadLocalAllocBuffer: a descriptor for thread-local storage used by
-// the threads for allocation. It is thread-private at any time.
+// ThreadLocalAllocBuffer is a descriptor for thread-local storage used by
+// mutator threads for local/private allocation. As a TLAB is thread-private,
+// there is no concurrent/parallel access to its memory or its members,
+// other than by estimated_used_bytes().
//
// Heap sampling is performed via the end and allocation_end
// fields.
@@ -123,7 +125,7 @@ public:
// Due to races with concurrent allocations and/or resetting the TLAB the return
// value may be inconsistent with any other metrics (e.g. total allocated
// bytes), and may just incorrectly return 0.
- // Intented fo external inspection only where accuracy is not 100% required.
+ // Intended for external inspection only where accuracy is not 100% required.
size_t estimated_used_bytes() const;
// Allocate size HeapWords. The memory is NOT initialized to zero.
diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp
index 355dc70ae39..f27d355f56e 100644
--- a/src/hotspot/share/runtime/thread.cpp
+++ b/src/hotspot/share/runtime/thread.cpp
@@ -485,7 +485,7 @@ void Thread::print_on(outputStream* st, bool print_extended_info) const {
(double)_statistical_info.getElapsedTime() / 1000.0
);
if (is_Java_thread() && (PrintExtendedThreadInfo || print_extended_info)) {
- size_t allocated_bytes = (size_t) const_cast(this)->cooked_allocated_bytes();
+ size_t allocated_bytes = checked_cast(cooked_allocated_bytes());
st->print("allocated=%zu%s ",
byte_size_in_proper_unit(allocated_bytes),
proper_unit_for_byte_size(allocated_bytes)
diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp
index dc09d4c68c2..0225fa808cb 100644
--- a/src/hotspot/share/runtime/thread.hpp
+++ b/src/hotspot/share/runtime/thread.hpp
@@ -405,13 +405,14 @@ class Thread: public ThreadShadow {
// Thread-Local Allocation Buffer (TLAB) support
ThreadLocalAllocBuffer& tlab() { return _tlab; }
+ const ThreadLocalAllocBuffer& tlab() const { return _tlab; }
void initialize_tlab();
void retire_tlab(ThreadLocalAllocStats* stats = nullptr);
void fill_tlab(HeapWord* start, size_t pre_reserved, size_t new_size);
jlong allocated_bytes() { return _allocated_bytes; }
void incr_allocated_bytes(jlong size) { _allocated_bytes += size; }
- inline jlong cooked_allocated_bytes();
+ inline jlong cooked_allocated_bytes() const;
ThreadHeapSampler& heap_sampler() { return _heap_sampler; }
diff --git a/src/hotspot/share/runtime/thread.inline.hpp b/src/hotspot/share/runtime/thread.inline.hpp
index b194f5e2a7f..d2ac34c3e46 100644
--- a/src/hotspot/share/runtime/thread.inline.hpp
+++ b/src/hotspot/share/runtime/thread.inline.hpp
@@ -36,7 +36,7 @@
#include "runtime/os.hpp"
#endif
-inline jlong Thread::cooked_allocated_bytes() {
+inline jlong Thread::cooked_allocated_bytes() const {
jlong allocated_bytes = AtomicAccess::load_acquire(&_allocated_bytes);
size_t used_bytes = 0;
if (UseTLAB) {
From 1bce8e47383cb1f89d7325ce6645f4bb195f91ba Mon Sep 17 00:00:00 2001
From: Afshin Zafari
Date: Wed, 11 Feb 2026 09:30:55 +0000
Subject: [PATCH 14/77] 8366957: Amalloc may return null despite contrary
AllocFailType
Reviewed-by: jsjolen, dholmes, kbarrett
---
src/hotspot/share/memory/arena.cpp | 5 ++++-
test/hotspot/gtest/nmt/test_nmt_malloclimit.cpp | 14 +++++++++++++-
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/src/hotspot/share/memory/arena.cpp b/src/hotspot/share/memory/arena.cpp
index 2de3f837c00..75cd909b028 100644
--- a/src/hotspot/share/memory/arena.cpp
+++ b/src/hotspot/share/memory/arena.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2023 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -330,6 +330,9 @@ void* Arena::grow(size_t x, AllocFailType alloc_failmode) {
size_t len = MAX2(ARENA_ALIGN(x), (size_t) Chunk::size);
if (MemTracker::check_exceeds_limit(x, _mem_tag)) {
+ if (alloc_failmode == AllocFailStrategy::EXIT_OOM) {
+ vm_exit_out_of_memory(x, OOM_MALLOC_ERROR, "MallocLimit in Arena::grow");
+ }
return nullptr;
}
diff --git a/test/hotspot/gtest/nmt/test_nmt_malloclimit.cpp b/test/hotspot/gtest/nmt/test_nmt_malloclimit.cpp
index da357285148..48da390e06f 100644
--- a/test/hotspot/gtest/nmt/test_nmt_malloclimit.cpp
+++ b/test/hotspot/gtest/nmt/test_nmt_malloclimit.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2023 SAP SE. All rights reserved.
- * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2026, 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,6 +23,7 @@
*/
#include "memory/allocation.hpp"
+#include "memory/arena.hpp"
#include "nmt/mallocLimit.hpp"
#include "nmt/memTracker.hpp"
#include "nmt/nmtCommon.hpp"
@@ -155,3 +156,14 @@ TEST_VM_FATAL_ERROR_MSG(NMT, MallocLimitDeathTestOnStrDup, ".*MallocLimit: reach
char* p = os::strdup("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", mtTest);
}
}
+
+TEST_VM_FATAL_ERROR_MSG(NMT, MallocLimitDeathTestOnArenaGrow, ".*MallocLimit in Arena::grow.*") {
+ // We fake the correct assert if NMT is off to make the test pass (there is no way to execute a death test conditionally)
+ if (!MemTracker::enabled()) {
+ fatal("Fake message please ignore: MallocLimit in Arena::grow");
+ }
+ // the real test
+ MallocLimitHandler::initialize("test:10m:oom");
+ Arena ar(mtTest);
+ ar.Amalloc(10 * M, AllocFailStrategy::EXIT_OOM);
+}
From 6a5eb26dcf9e9dcf16e80b7c46f16a236a893aef Mon Sep 17 00:00:00 2001
From: Jaikiran Pai
Date: Wed, 11 Feb 2026 11:03:03 +0000
Subject: [PATCH 15/77] 8377656: JUnit test
java/util/zip/ZipFile/ZipFileInputStreamSkipTest.java uses private methods
for BeforeAll/AfterAll
Reviewed-by: cstein, alanb
---
.../jdk/java/util/zip/ZipFile/ZipFileInputStreamSkipTest.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/jdk/java/util/zip/ZipFile/ZipFileInputStreamSkipTest.java b/test/jdk/java/util/zip/ZipFile/ZipFileInputStreamSkipTest.java
index 131f7a5c51c..1b7b93785af 100644
--- a/test/jdk/java/util/zip/ZipFile/ZipFileInputStreamSkipTest.java
+++ b/test/jdk/java/util/zip/ZipFile/ZipFileInputStreamSkipTest.java
@@ -69,7 +69,7 @@ public class ZipFileInputStreamSkipTest {
* @throws IOException If an error occurs creating the Zip Files
*/
@BeforeAll
- private static void createZip() throws IOException {
+ static void createZip() throws IOException {
Entry e0 = Entry.of("Entry-0", ZipEntry.STORED, "Tennis Pro");
Entry e1 = Entry.of("Entry-1", ZipEntry.STORED,
"United States Tennis Association");
@@ -98,7 +98,7 @@ public class ZipFileInputStreamSkipTest {
* @throws IOException If an error occurs during cleanup
*/
@AfterAll
- private static void cleanUp() throws IOException {
+ static void cleanUp() throws IOException {
Files.deleteIfExists(STORED_ZIPFILE);
Files.deleteIfExists(DEFLATED_ZIPFILE);
}
From 0097db564319b6b0f50507f8c9598f124588e5f3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johan=20Sj=C3=B6len?=
Date: Wed, 11 Feb 2026 11:25:24 +0000
Subject: [PATCH 16/77] 8364655: Loading class with nested annotations causes
stack overflow in VM
Reviewed-by: dholmes, fbredberg
---
.../share/classfile/classFileParser.cpp | 21 +++--
.../runtime/ClassFile/NestedAnnotations.java | 77 +++++++++++++++++++
2 files changed, 91 insertions(+), 7 deletions(-)
create mode 100644 test/hotspot/jtreg/runtime/ClassFile/NestedAnnotations.java
diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp
index 817d0c64d11..c1f00cbe536 100644
--- a/src/hotspot/share/classfile/classFileParser.cpp
+++ b/src/hotspot/share/classfile/classFileParser.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2026, 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
@@ -1017,7 +1017,8 @@ public:
};
-static int skip_annotation_value(const u1*, int, int); // fwd decl
+static int skip_annotation_value(const u1* buffer, int limit, int index, int recursion_depth); // fwd decl
+static const int max_recursion_depth = 5;
// Safely increment index by val if does not pass limit
#define SAFE_ADD(index, limit, val) \
@@ -1025,23 +1026,29 @@ if (index >= limit - val) return limit; \
index += val;
// Skip an annotation. Return >=limit if there is any problem.
-static int skip_annotation(const u1* buffer, int limit, int index) {
+static int skip_annotation(const u1* buffer, int limit, int index, int recursion_depth = 0) {
assert(buffer != nullptr, "invariant");
+ if (recursion_depth > max_recursion_depth) {
+ return limit;
+ }
// annotation := atype:u2 do(nmem:u2) {member:u2 value}
// value := switch (tag:u1) { ... }
SAFE_ADD(index, limit, 4); // skip atype and read nmem
int nmem = Bytes::get_Java_u2((address)buffer + index - 2);
while (--nmem >= 0 && index < limit) {
SAFE_ADD(index, limit, 2); // skip member
- index = skip_annotation_value(buffer, limit, index);
+ index = skip_annotation_value(buffer, limit, index, recursion_depth + 1);
}
return index;
}
// Skip an annotation value. Return >=limit if there is any problem.
-static int skip_annotation_value(const u1* buffer, int limit, int index) {
+static int skip_annotation_value(const u1* buffer, int limit, int index, int recursion_depth) {
assert(buffer != nullptr, "invariant");
+ if (recursion_depth > max_recursion_depth) {
+ return limit;
+ }
// value := switch (tag:u1) {
// case B, C, I, S, Z, D, F, J, c: con:u2;
// case e: e_class:u2 e_name:u2;
@@ -1073,12 +1080,12 @@ static int skip_annotation_value(const u1* buffer, int limit, int index) {
SAFE_ADD(index, limit, 2); // read nval
int nval = Bytes::get_Java_u2((address)buffer + index - 2);
while (--nval >= 0 && index < limit) {
- index = skip_annotation_value(buffer, limit, index);
+ index = skip_annotation_value(buffer, limit, index, recursion_depth + 1);
}
}
break;
case '@':
- index = skip_annotation(buffer, limit, index);
+ index = skip_annotation(buffer, limit, index, recursion_depth + 1);
break;
default:
return limit; // bad tag byte
diff --git a/test/hotspot/jtreg/runtime/ClassFile/NestedAnnotations.java b/test/hotspot/jtreg/runtime/ClassFile/NestedAnnotations.java
new file mode 100644
index 00000000000..e523c2ed736
--- /dev/null
+++ b/test/hotspot/jtreg/runtime/ClassFile/NestedAnnotations.java
@@ -0,0 +1,77 @@
+ /*
+ * Copyright (c) 2026, 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 NestedAnnotations
+ * @summary The JVM handles nested annotations
+ * @bug 8364655
+ * @requires vm.flagless
+ * @library /test/lib
+ * @library /testlibrary/asm
+ * @modules java.base/jdk.internal.misc
+ * java.desktop
+ * java.management
+ * @run driver NestedAnnotations
+ */
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassWriter;
+
+import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
+
+import static org.objectweb.asm.Opcodes.*;
+
+public class NestedAnnotations {
+ static void test() throws Exception {
+ var cw = new ClassWriter(0);
+ cw.visit(V17, 0, "Annotations", null, "java/lang/Object", null);
+ final int number_of_annotations = 65535;
+ var av = cw.visitAnnotation("LTest;", true);
+ var stack = new ArrayList(number_of_annotations + 1);
+ stack.add(av);
+ for (int i = 0; i < number_of_annotations; i++) {
+ stack.add(av = av.visitAnnotation("value", "LTest;"));
+ }
+ for (int i = number_of_annotations; i != 0;) {
+ stack.get(--i).visitEnd();
+ }
+
+ cw.visitEnd();
+ // Does not matter whether the class is hidden, used for simplicity's sake.
+ MethodHandles.lookup().defineHiddenClass(cw.toByteArray(), true);
+ }
+
+ public static void main(String[] args) throws Exception {
+ if (args.length == 1 && args[0].equals("testIt")) {
+ test();
+ } else {
+ OutputAnalyzer oa = ProcessTools.executeTestJava("NestedAnnotations", "testIt");
+ oa.shouldHaveExitValue(0);
+ }
+ }
+}
+
From a532e509ed60f6e8bfd66cdc6973f4d9042bb056 Mon Sep 17 00:00:00 2001
From: Yasumasa Suenaga
Date: Wed, 11 Feb 2026 12:04:19 +0000
Subject: [PATCH 17/77] 8377395:
serviceability/sa/TestJhsdbJstackMixedCore.java fails due to NPE because
"because "this.cfa" is null"
Reviewed-by: cjplummer, kevinw
---
.../linux/native/libsaproc/libproc_impl.c | 7 +++----
test/hotspot/jtreg/ProblemList.txt | 1 -
.../jtreg/serviceability/sa/TestJhsdbJstackMixedCore.java | 4 ++--
3 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c
index 74563aa0d6c..e2681be73fe 100644
--- a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c
+++ b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2026, 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
@@ -187,9 +187,8 @@ static bool fill_addr_info(lib_info* lib) {
lib->exec_end = (uintptr_t)-1L;
for (ph = phbuf, cnt = 0; cnt < ehdr.e_phnum; cnt++, ph++) {
if (ph->p_type == PT_LOAD) {
- uintptr_t unaligned_start = lib->base + ph->p_vaddr;
- uintptr_t aligned_start = align_down(unaligned_start, ph->p_align);
- uintptr_t aligned_end = align_up(unaligned_start + ph->p_memsz, ph->p_align);
+ uintptr_t aligned_start = lib->base + align_down(ph->p_vaddr, ph->p_align);
+ uintptr_t aligned_end = aligned_start + align_up(ph->p_memsz, ph->p_align);
if ((lib->end == (uintptr_t)-1L) || (lib->end < aligned_end)) {
lib->end = aligned_end;
}
diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt
index 147d1ce2d78..3e4814180f6 100644
--- a/test/hotspot/jtreg/ProblemList.txt
+++ b/test/hotspot/jtreg/ProblemList.txt
@@ -140,7 +140,6 @@ serviceability/sa/TestJmapCore.java 8318754 macosx-aarch64
serviceability/sa/TestJmapCoreMetaspace.java 8318754 macosx-aarch64
serviceability/sa/ClhsdbThreadContext.java 8356704 windows-x64
-serviceability/sa/TestJhsdbJstackMixedCore.java 8377395 linux-x64
serviceability/jvmti/stress/StackTrace/NotSuspended/GetStackTraceNotSuspendedStressTest.java 8315980 linux-all,windows-x64
diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedCore.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedCore.java
index d781e8c5c09..84a62eb65e5 100644
--- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedCore.java
+++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedCore.java
@@ -37,7 +37,7 @@ import jtreg.SkippedException;
/**
* @test
- * @bug 8374482 8376264 8376284
+ * @bug 8374482 8376264 8376284 8377395
* @requires (os.family == "linux") & (vm.hasSA)
* @requires os.arch == "amd64"
* @library /test/lib
@@ -66,7 +66,7 @@ public class TestJhsdbJstackMixedCore {
out.shouldContain("__restore_rt ");
out.shouldContain("Java_jdk_test_lib_apps_LingeredApp_crash");
- out.shouldContain("* jdk.test.lib.apps.LingeredApp.crash()");
+ out.shouldContain("jdk.test.lib.apps.LingeredApp.crash()");
}
public static void main(String... args) throws Throwable {
From a8a88d79927b8c4704f5b7aa3948f13812fd87c3 Mon Sep 17 00:00:00 2001
From: Yasumasa Suenaga
Date: Wed, 11 Feb 2026 14:11:51 +0000
Subject: [PATCH 18/77] 8374469: Mixed jstack does not work on Windows
Reviewed-by: cjplummer, kevinw
---
.../debugger/windbg/WindbgCDebugger.java | 28 +++++-
.../debugger/windbg/WindbgDebugger.java | 6 +-
.../debugger/windbg/WindbgDebuggerLocal.java | 9 +-
.../windows/amd64/WindowsAMD64CFrame.java | 87 ++++++++++++++-----
.../windows/native/libsaproc/sawindbg.cpp | 39 ++++++++-
.../sa/TestJhsdbJstackMixed.java | 11 ++-
6 files changed, 150 insertions(+), 30 deletions(-)
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgCDebugger.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgCDebugger.java
index 64bdb8c1c72..04f374de80e 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgCDebugger.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgCDebugger.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2026, 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 sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.debugger.amd64.*;
import sun.jvm.hotspot.debugger.windows.amd64.*;
+import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.utilities.AddressOps;
class WindbgCDebugger implements CDebugger {
@@ -66,14 +67,35 @@ class WindbgCDebugger implements CDebugger {
return null;
}
+ private JavaThread mapThreadProxyToJavaThread(ThreadProxy thread) {
+ var threads = VM.getVM().getThreads();
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ var jt = threads.getJavaThreadAt(i);
+ if (thread.equals(jt.getThreadProxy())) {
+ return jt;
+ }
+ }
+
+ // not found
+ return null;
+ }
+
public CFrame topFrameForThread(ThreadProxy thread) throws DebuggerException {
if (dbg.getCPU().equals("amd64")) {
AMD64ThreadContext context = (AMD64ThreadContext) thread.getContext();
+
+ // rbp is not needed null check because it could be used as GPR by compiler (cl.exe) option.
Address rbp = context.getRegisterAsAddress(AMD64ThreadContext.RBP);
- if (rbp == null) return null;
+
+ Address rsp = context.getRegisterAsAddress(AMD64ThreadContext.RSP);
+ if (rsp == null) return null;
Address pc = context.getRegisterAsAddress(AMD64ThreadContext.RIP);
if (pc == null) return null;
- return new WindowsAMD64CFrame(dbg, rbp, pc);
+
+ // get JavaThread as the owner from ThreadProxy
+ JavaThread ownerThread = mapThreadProxyToJavaThread(thread);
+
+ return new WindowsAMD64CFrame(dbg, ownerThread, rsp, rbp, pc);
} else {
// unsupported CPU!
return null;
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebugger.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebugger.java
index 46edb2f55b2..82dc28515d3 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebugger.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebugger.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2026, 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
@@ -85,4 +85,8 @@ public interface WindbgDebugger extends JVMDebugger {
// public ThreadProxy getThreadForIdentifierAddress(Address addr);
public int getAddressSize();
+
+ public static record SenderRegs(Address nextSP, Address nextFP, Address nextPC) {};
+
+ public SenderRegs getSenderRegs(Address sp, Address fp, Address pc);
}
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java
index 9ed05b31319..4864b94fd86 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2026, 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
@@ -229,6 +229,12 @@ public class WindbgDebuggerLocal extends DebuggerBase implements WindbgDebugger
return lookupByAddress0(address);
}
+ public synchronized SenderRegs getSenderRegs(Address sp, Address fp, Address pc) {
+ // sp and pc should not be null, but fp might be null because it could be used as GPR.
+ long[] rawSenderRegs = getSenderRegs0(sp.asLongValue(), fp == null ? 0L : fp.asLongValue(), pc.asLongValue());
+ return rawSenderRegs == null ? null : new SenderRegs(newAddress(rawSenderRegs[0]), newAddress(rawSenderRegs[1]), newAddress(rawSenderRegs[2]));
+ }
+
/** From the Debugger interface */
public MachineDescription getMachineDescription() {
return machDesc;
@@ -644,6 +650,7 @@ public class WindbgDebuggerLocal extends DebuggerBase implements WindbgDebugger
private native String consoleExecuteCommand0(String cmd);
private native long lookupByName0(String objName, String symName);
private native ClosestSymbol lookupByAddress0(long address);
+ private native long[] getSenderRegs0(long sp, long fp, long pc);
// helper called lookupByAddress0
private ClosestSymbol createClosestSymbol(String symbol, long diff) {
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windows/amd64/WindowsAMD64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windows/amd64/WindowsAMD64CFrame.java
index 69ad04da51b..b004a84fff4 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windows/amd64/WindowsAMD64CFrame.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windows/amd64/WindowsAMD64CFrame.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2026, 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
@@ -29,43 +29,74 @@ import sun.jvm.hotspot.debugger.amd64.*;
import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.debugger.cdbg.basic.*;
import sun.jvm.hotspot.debugger.windbg.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.runtime.amd64.*;
public class WindowsAMD64CFrame extends BasicCFrame {
+ private JavaThread ownerThread;
+ private Address rsp;
private Address rbp;
private Address pc;
- private static final int ADDRESS_SIZE = 8;
-
/** Constructor for topmost frame */
- public WindowsAMD64CFrame(WindbgDebugger dbg, Address rbp, Address pc) {
+ public WindowsAMD64CFrame(WindbgDebugger dbg, JavaThread ownerThread, Address rsp, Address rbp, Address pc) {
super(dbg.getCDebugger());
+ this.ownerThread = ownerThread;
+ this.rsp = rsp;
this.rbp = rbp;
this.pc = pc;
this.dbg = dbg;
}
+ @Override
public CFrame sender(ThreadProxy thread) {
- AMD64ThreadContext context = (AMD64ThreadContext) thread.getContext();
- Address rsp = context.getRegisterAsAddress(AMD64ThreadContext.RSP);
+ return sender(thread, null, null, null);
+ }
- if ( (rbp == null) || rbp.lessThan(rsp) ) {
- return null;
- }
+ @Override
+ public CFrame sender(ThreadProxy th, Address nextSP, Address nextFP, Address nextPC) {
+ if (nextSP == null && nextPC == null) {
+ // GetStackTrace() by Windows Debug API would unwind frame with given SP, FP, and PC.
+ // However it would not work for dynamic generated code like CodeBlob because
+ // HotSpot would not register unwind info like RtlAddFunctionTable().
+ // Thus SA should check whether current PC is in CodeCache at first when nextPC is null.
+ var cb = VM.getVM().getCodeCache().findBlob(pc);
+ if (cb != null) {
+ if (cb.getFrameSize() > 0) {
+ nextSP = rsp.addOffsetTo(cb.getFrameSize());
+ nextPC = nextSP.getAddressAt(-1 * VM.getVM().getAddressSize());
- // Check alignment of rbp
- if ( dbg.getAddressValue(rbp) % ADDRESS_SIZE != 0) {
+ // Set nextFP to null when PreserveFramePointer is disabled because We could not find out
+ // frame pointer of sender frame - it might be omitted.
+ nextFP = VM.getVM().getCommandLineBooleanFlag("PreserveFramePointer") ? rsp.getAddressAt(0) : null;
+ } else {
+ // Use Frame (AMD64Frame) to access slots on stack.
+ var frame = toFrame();
+ nextSP = frame.getSenderSP();
+ nextPC = frame.getSenderPC();
+ nextFP = frame.getLink();
+ }
+ return new WindowsAMD64CFrame(dbg, ownerThread, nextSP, nextFP, nextPC);
+ }
+
+ WindbgDebugger.SenderRegs senderRegs = dbg.getSenderRegs(rsp, rbp, pc);
+ if (senderRegs == null) {
return null;
- }
+ }
- Address nextRBP = rbp.getAddressAt( 0 * ADDRESS_SIZE);
- if (nextRBP == null || nextRBP.lessThanOrEqual(rbp)) {
- return null;
+ if (senderRegs.nextSP() == null || senderRegs.nextSP().lessThanOrEqual(rsp)) {
+ return null;
+ }
+ nextSP = senderRegs.nextSP();
+
+ if (senderRegs.nextPC() == null) {
+ return null;
+ }
+ nextPC = senderRegs.nextPC();
+
+ nextFP = senderRegs.nextFP();
}
- Address nextPC = rbp.getAddressAt( 1 * ADDRESS_SIZE);
- if (nextPC == null) {
- return null;
- }
- return new WindowsAMD64CFrame(dbg, nextRBP, nextPC);
+ return new WindowsAMD64CFrame(dbg, ownerThread, nextSP, nextFP, nextPC);
}
public Address pc() {
@@ -76,5 +107,21 @@ public class WindowsAMD64CFrame extends BasicCFrame {
return rbp;
}
+ @Override
+ public Frame toFrame() {
+ // Find the top of JavaVFrame related to this CFrame. The Windows GetStackTrace DbgHelp API
+ // cannot get FP for java frames.
+ for (JavaVFrame vf = ownerThread.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) {
+ Frame f = vf.getFrame();
+ if (f.getSP().equals(rsp) && f.getPC().equals(pc)) {
+ return f;
+ } else if (f.getSP().greaterThanOrEqual(rsp)) {
+ return f;
+ }
+ }
+
+ return new AMD64Frame(rsp, localVariableBase(), pc);
+ }
+
private WindbgDebugger dbg;
}
diff --git a/src/jdk.hotspot.agent/windows/native/libsaproc/sawindbg.cpp b/src/jdk.hotspot.agent/windows/native/libsaproc/sawindbg.cpp
index f2994c0d827..0c16400bf3b 100644
--- a/src/jdk.hotspot.agent/windows/native/libsaproc/sawindbg.cpp
+++ b/src/jdk.hotspot.agent/windows/native/libsaproc/sawindbg.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2026, 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
@@ -906,3 +906,40 @@ JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLoc
CHECK_EXCEPTION_(0);
return res;
}
+
+/*
+ * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal
+ * Method: getSenderRegs0
+ * Signature: (JJJ)[J
+ */
+JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_getSenderRegs0
+ (JNIEnv *env, jobject obj, jlong sp, jlong fp, jlong pc) {
+ IDebugControl* ptrIDebugControl = (IDebugControl*)env->GetLongField(obj, ptrIDebugControl_ID);
+ CHECK_EXCEPTION_(nullptr);
+
+ // GetStackTrace() returns call frames from specified fp, sp, and pc.
+ // The top of frame would point current frame, hence we refer 2nd frame
+ // as a sender and get registers from it.
+ DEBUG_STACK_FRAME frames[2];
+ ULONG filled;
+ HRESULT dbg_result = ptrIDebugControl->GetStackTrace(fp, sp, pc, frames, 2, &filled);
+ if (dbg_result != S_OK || filled != 2) {
+ return nullptr;
+ }
+
+ jlongArray result = env->NewLongArray(3);
+ CHECK_EXCEPTION_(nullptr);
+ if (result == nullptr) {
+ return nullptr;
+ }
+
+ jlong regs[] = {
+ static_cast(frames[1].StackOffset),
+ static_cast(frames[1].FrameOffset),
+ static_cast(frames[1].InstructionOffset)
+ };
+ env->SetLongArrayRegion(result, 0, 3, regs);
+ CHECK_EXCEPTION_(nullptr);
+
+ return result;
+}
diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixed.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixed.java
index b02d3f3aef3..42ff12e519d 100644
--- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixed.java
+++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixed.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -35,8 +35,8 @@ import jdk.test.lib.process.OutputAnalyzer;
/**
* @test
* @key randomness
- * @bug 8208091
- * @requires (os.family == "linux") & (vm.hasSA)
+ * @bug 8208091 8374469
+ * @requires (os.family == "linux" | os.family == "windows") & (vm.hasSA)
* @requires (os.arch != "riscv64" | !(vm.cpu.features ~= ".*qemu.*"))
* @library /test/lib
* @run driver TestJhsdbJstackMixed
@@ -50,8 +50,11 @@ public class TestJhsdbJstackMixed {
private static final Pattern LINE_PATTERN = Pattern
.compile(LINE_MATCHER_STR);
private static final String HEX_STR_PATTERN = "0x([a-fA-F0-9]+)";
- private static final String FIB_SPLIT_PATTERN = NATIVE_FUNCTION_NAME
+
+ // On windows the native symbol will be prefixed with "NoFramePointer!"
+ private static final String FIB_SPLIT_PATTERN = "(NoFramePointer!)?" + NATIVE_FUNCTION_NAME
+ "\\s+\\+";
+
private static final Pattern HEX_PATTERN = Pattern.compile(HEX_STR_PATTERN);
private static final int ADDRESS_ALIGNMENT_X86 = 4;
From b3fc013b4f8171c8ee735d6fdcad696ae6e431ee Mon Sep 17 00:00:00 2001
From: Albert Mingkun Yang
Date: Wed, 11 Feb 2026 14:24:13 +0000
Subject: [PATCH 19/77] 8377143: Parallel: Remove special treatment in
JstatGcCapacityResults.java
Reviewed-by: kevinw, tschatzl
---
.../jstat/utils/JstatGcCapacityResults.java | 36 +++----------------
1 file changed, 5 insertions(+), 31 deletions(-)
diff --git a/test/hotspot/jtreg/serviceability/tmtools/jstat/utils/JstatGcCapacityResults.java b/test/hotspot/jtreg/serviceability/tmtools/jstat/utils/JstatGcCapacityResults.java
index cee7bebbd50..9f5355bcdbc 100644
--- a/test/hotspot/jtreg/serviceability/tmtools/jstat/utils/JstatGcCapacityResults.java
+++ b/test/hotspot/jtreg/serviceability/tmtools/jstat/utils/JstatGcCapacityResults.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2026, 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
@@ -88,18 +88,11 @@ public class JstatGcCapacityResults extends JstatResults {
assertThat(EC <= NGC, "EC > NGC (eden space capacity > new generation capacity)");
// Verify relative size of NGC and S0C + S1C + EC.
- // The rule depends on if the tenured GC is parallel or not.
- // For parallell GC: NGC >= S0C + S1C + EC
- // For non-parallell GC: NGC == S0C + S1C + EC
- boolean isTenuredParallelGC = isTenuredParallelGC();
+ // NGC == S0C + S1C + EC
String errMsg = String.format(
- "NGC %s (S0C + S1C + EC) (NGC = %.1f, S0C = %.1f, S1C = %.1f, EC = %.1f, (S0C + S1C + EC) = %.1f)",
- isTenuredParallelGC ? "<" : "!=", NGC, S0C, S1C, EC, S0C + S1C + EC);
- if (isTenuredParallelGC) {
- assertThat(NGC >= S0C + S1C + EC, errMsg);
- } else {
- assertThat(checkFloatIsSum(NGC, S0C, S1C, EC), errMsg);
- }
+ "NGC != (S0C + S1C + EC) (NGC = %.1f, S0C = %.1f, S1C = %.1f, EC = %.1f, (S0C + S1C + EC) = %.1f)",
+ NGC, S0C, S1C, EC, S0C + S1C + EC);
+ assertThat(checkFloatIsSum(NGC, S0C, S1C, EC), errMsg);
// Check Old Gen consistency
float OGCMN = getFloatValue("OGCMN");
@@ -121,23 +114,4 @@ public class JstatGcCapacityResults extends JstatResults {
assertThat(MC >= MCMN, "MC < MCMN (generation capacity < min generation capacity)");
assertThat(MC <= MCMX, "MGC > MCMX (generation capacity > max generation capacity)");
}
-
- /**
- * Check if the tenured generation are currently using a parallel GC.
- */
- protected static boolean isTenuredParallelGC() {
- // Currently the only parallel GC for the tenured generation is PS MarkSweep.
- List parallelGCs = Arrays.asList(new String[] { "PS MarkSweep"});
- try {
- List beans = ManagementFactory.getGarbageCollectorMXBeans();
- for (GarbageCollectorMXBean bean : beans) {
- if (parallelGCs.contains(bean.getName())) {
- return true;
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return false;
- }
}
From b98899b441222ce9cd6a2a74e86193c091e088e6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?=
Date: Wed, 11 Feb 2026 16:43:36 +0000
Subject: [PATCH 20/77] 8377461: Add ZipFile test for incorrect number of
entries reported in ENDTOT
Reviewed-by: lancea
---
.../util/zip/ZipFile/IncorrectEndTot.java | 117 ++++++++++++++++++
1 file changed, 117 insertions(+)
create mode 100644 test/jdk/java/util/zip/ZipFile/IncorrectEndTot.java
diff --git a/test/jdk/java/util/zip/ZipFile/IncorrectEndTot.java b/test/jdk/java/util/zip/ZipFile/IncorrectEndTot.java
new file mode 100644
index 00000000000..0b6fc4a35fd
--- /dev/null
+++ b/test/jdk/java/util/zip/ZipFile/IncorrectEndTot.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2026, 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
+ * @summary Verify that ZipFile::size reports the actual number of entries
+ * even with an incorrect ENDTOT field
+ * @run junit IncorrectEndTot
+ */
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.file.Files;
+import java.util.Collections;
+import java.util.stream.Stream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class IncorrectEndTot {
+
+ // File to use for this test
+ File file = new File("incorrect-end-centot.zip");
+
+ // Return scenarios for correct and incorrect ENDTOT fields
+ public static Stream scenarios() {
+ return Stream.of(
+ Arguments.of(10, 10), // CEN agrees with ENDTOT
+ Arguments.of(10, 11), // CEN has one less than ENDTOT
+ Arguments.of(11, 10), // CEN has one more than ENDTOT
+ Arguments.of(0, 0), // Empty ZIP, correct ENDTOT
+ Arguments.of(0, 10) // Empty ZIP, incorrect ENDTOT
+ );
+ }
+
+ /**
+ * Delete the file used by this test
+ */
+ @AfterEach
+ public void cleanup() {
+ file.delete();
+ }
+
+ /**
+ * Verify that ZipFile::size reports the actual number of CEN records,
+ * regardless of the ENDTOT field.
+ *
+ * @param actual number of entries in the ZIP file
+ * @param reported number reported in ENDTOT
+ * @throws IOException if an unexpected error occurs
+ */
+ @ParameterizedTest
+ @MethodSource("scenarios")
+ public void shouldCountActualEntries(int actual, int reported) throws IOException {
+ createZip(file, actual, reported);
+ try (ZipFile zf = new ZipFile(file)) {
+ assertEquals(actual, zf.size());
+ assertEquals(actual, Collections.list(zf.entries()).size());
+ assertEquals(actual, zf.stream().count());
+ }
+ }
+
+ /**
+ * Create a ZIP file with a number of entries, possibly reporting an incorrect number in
+ * the ENDTOT field
+ * @param file the file to write to
+ * @param numEntries the number of entries to generate
+ * @param reported the number of entries to report in the END header's ENDTOT field
+ * @throws IOException
+ */
+ private static void createZip(File file, int numEntries, int reported) throws IOException {
+ // Create a ZIP
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try (ZipOutputStream zo = new ZipOutputStream(out)) {
+ for (int i = 0; i < numEntries; i++) {
+ zo.putNextEntry(new ZipEntry("entry_" + i));
+ }
+ }
+ byte[] bytes = out.toByteArray();
+
+ // Update the ENDTOT field to report a possibly incorrect number
+ ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
+ buf.putShort(bytes.length - ZipFile.ENDHDR + ZipFile.ENDTOT, (short) reported);
+
+ // Write to disk
+ Files.write(file.toPath(), bytes);
+ }
+}
From 708970a1a6f9c05f21d15918066a07d7f896a04a Mon Sep 17 00:00:00 2001
From: Ben Taylor
Date: Wed, 11 Feb 2026 16:58:21 +0000
Subject: [PATCH 21/77] 8377045: Shenandoah: Convert ShenandoahLock related
code to use Atomic
Reviewed-by: wkemper, xpeng
---
.../share/gc/shenandoah/shenandoahLock.cpp | 13 +++++-----
.../share/gc/shenandoah/shenandoahLock.hpp | 25 ++++++++++---------
2 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp b/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp
index 7a3b33f5fd0..7eec0b9af64 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp
@@ -24,7 +24,6 @@
#include "gc/shenandoah/shenandoahLock.hpp"
-#include "runtime/atomicAccess.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/os.hpp"
@@ -46,8 +45,8 @@ void ShenandoahLock::contended_lock_internal(JavaThread* java_thread) {
int ctr = os::is_MP() ? 0xFF : 0;
int yields = 0;
// Apply TTAS to avoid more expensive CAS calls if the lock is still held by other thread.
- while (AtomicAccess::load(&_state) == locked ||
- AtomicAccess::cmpxchg(&_state, unlocked, locked) != unlocked) {
+ while (_state.load_relaxed() == locked ||
+ _state.compare_exchange(unlocked, locked) != unlocked) {
if (ctr > 0 && !SafepointSynchronize::is_synchronizing()) {
// Lightly contended, spin a little if no safepoint is pending.
SpinPause();
@@ -113,11 +112,11 @@ ShenandoahReentrantLock::~ShenandoahReentrantLock() {
void ShenandoahReentrantLock::lock() {
Thread* const thread = Thread::current();
- Thread* const owner = AtomicAccess::load(&_owner);
+ Thread* const owner = _owner.load_relaxed();
if (owner != thread) {
ShenandoahSimpleLock::lock();
- AtomicAccess::store(&_owner, thread);
+ _owner.store_relaxed(thread);
}
_count++;
@@ -130,13 +129,13 @@ void ShenandoahReentrantLock::unlock() {
_count--;
if (_count == 0) {
- AtomicAccess::store(&_owner, (Thread*)nullptr);
+ _owner.store_relaxed((Thread*)nullptr);
ShenandoahSimpleLock::unlock();
}
}
bool ShenandoahReentrantLock::owned_by_self() const {
Thread* const thread = Thread::current();
- Thread* const owner = AtomicAccess::load(&_owner);
+ Thread* const owner = _owner.load_relaxed();
return owner == thread;
}
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp b/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp
index fbdf4971354..2e44810cd5d 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp
@@ -27,6 +27,7 @@
#include "gc/shenandoah/shenandoahPadding.hpp"
#include "memory/allocation.hpp"
+#include "runtime/atomic.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/safepoint.hpp"
@@ -35,9 +36,9 @@ private:
enum LockState { unlocked = 0, locked = 1 };
shenandoah_padding(0);
- volatile LockState _state;
+ Atomic _state;
shenandoah_padding(1);
- Thread* volatile _owner;
+ Atomic _owner;
shenandoah_padding(2);
template
@@ -48,33 +49,33 @@ public:
ShenandoahLock() : _state(unlocked), _owner(nullptr) {};
void lock(bool allow_block_for_safepoint) {
- assert(AtomicAccess::load(&_owner) != Thread::current(), "reentrant locking attempt, would deadlock");
+ assert(_owner.load_relaxed() != Thread::current(), "reentrant locking attempt, would deadlock");
if ((allow_block_for_safepoint && SafepointSynchronize::is_synchronizing()) ||
- (AtomicAccess::cmpxchg(&_state, unlocked, locked) != unlocked)) {
+ (_state.compare_exchange(unlocked, locked) != unlocked)) {
// 1. Java thread, and there is a pending safepoint. Dive into contended locking
// immediately without trying anything else, and block.
// 2. Fast lock fails, dive into contended lock handling.
contended_lock(allow_block_for_safepoint);
}
- assert(AtomicAccess::load(&_state) == locked, "must be locked");
- assert(AtomicAccess::load(&_owner) == nullptr, "must not be owned");
- DEBUG_ONLY(AtomicAccess::store(&_owner, Thread::current());)
+ assert(_state.load_relaxed() == locked, "must be locked");
+ assert(_owner.load_relaxed() == nullptr, "must not be owned");
+ DEBUG_ONLY(_owner.store_relaxed(Thread::current());)
}
void unlock() {
- assert(AtomicAccess::load(&_owner) == Thread::current(), "sanity");
- DEBUG_ONLY(AtomicAccess::store(&_owner, (Thread*)nullptr);)
+ assert(_owner.load_relaxed() == Thread::current(), "sanity");
+ DEBUG_ONLY(_owner.store_relaxed((Thread*)nullptr);)
OrderAccess::fence();
- AtomicAccess::store(&_state, unlocked);
+ _state.store_relaxed(unlocked);
}
void contended_lock(bool allow_block_for_safepoint);
bool owned_by_self() {
#ifdef ASSERT
- return _state == locked && _owner == Thread::current();
+ return _state.load_relaxed() == locked && _owner.load_relaxed() == Thread::current();
#else
ShouldNotReachHere();
return false;
@@ -111,7 +112,7 @@ public:
class ShenandoahReentrantLock : public ShenandoahSimpleLock {
private:
- Thread* volatile _owner;
+ Atomic _owner;
uint64_t _count;
public:
From 39a1d1c801a9cbf8d21051a9af7f6279873ae260 Mon Sep 17 00:00:00 2001
From: Phil Race
Date: Wed, 11 Feb 2026 19:23:03 +0000
Subject: [PATCH 22/77] 8376998: [macOS] Remove AppContext from AppEventHandler
Reviewed-by: serb, dnguyen
---
.../com/apple/eawt/_AppEventHandler.java | 58 +++++--------------
.../share/classes/sun/awt/SunToolkit.java | 6 +-
2 files changed, 19 insertions(+), 45 deletions(-)
diff --git a/src/java.desktop/macosx/classes/com/apple/eawt/_AppEventHandler.java b/src/java.desktop/macosx/classes/com/apple/eawt/_AppEventHandler.java
index d1b747a8f30..418cace016e 100644
--- a/src/java.desktop/macosx/classes/com/apple/eawt/_AppEventHandler.java
+++ b/src/java.desktop/macosx/classes/com/apple/eawt/_AppEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2026, 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
@@ -59,11 +59,10 @@ import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
-import java.util.IdentityHashMap;
+import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
-import java.util.Map;
-import sun.awt.AppContext;
+import java.util.Set;
import sun.awt.SunToolkit;
final class _AppEventHandler {
@@ -480,26 +479,22 @@ final class _AppEventHandler {
}
abstract static class _AppEventMultiplexor {
- private final Map listenerToAppContext =
- new IdentityHashMap();
+ private final Set listeners = new HashSet();
boolean nativeListenerRegistered;
// called from AppKit Thread-0
void dispatch(final _NativeEvent event, final Object... args) {
- // grab a local ref to the listeners and its contexts as an array of the map's entries
- final ArrayList> localEntries;
+ // grab a local ref to the listeners as an array
+ final ArrayList localList;
synchronized (this) {
- if (listenerToAppContext.size() == 0) {
+ if (listeners.size() == 0) {
return;
}
- localEntries = new ArrayList>(listenerToAppContext.size());
- localEntries.addAll(listenerToAppContext.entrySet());
+ localList = new ArrayList(listeners.size());
+ localList.addAll(listeners);
}
-
- for (final Map.Entry e : localEntries) {
- final L listener = e.getKey();
- final AppContext listenerContext = e.getValue();
- SunToolkit.invokeLaterOnAppContext(listenerContext, new Runnable() {
+ for (final L listener : localList) {
+ SunToolkit.invokeLater(new Runnable() {
public void run() {
performOnListener(listener, event);
}
@@ -508,7 +503,7 @@ final class _AppEventHandler {
}
synchronized void addListener(final L listener) {
- setListenerContext(listener, AppContext.getAppContext());
+ listeners.add(listener);
if (!nativeListenerRegistered) {
registerNativeListener();
@@ -517,19 +512,11 @@ final class _AppEventHandler {
}
synchronized void removeListener(final L listener) {
- listenerToAppContext.remove(listener);
+ listeners.remove(listener);
}
abstract void performOnListener(L listener, final _NativeEvent event);
void registerNativeListener() { }
-
- private void setListenerContext(L listener, AppContext listenerContext) {
- if (listenerContext == null) {
- throw new RuntimeException(
- "Attempting to add a listener from a thread group without AppContext");
- }
- listenerToAppContext.put(listener, AppContext.getAppContext());
- }
}
abstract static class _BooleanAppEventMultiplexor extends _AppEventMultiplexor {
@@ -561,22 +548,19 @@ final class _AppEventHandler {
*/
abstract static class _AppEventDispatcher {
H _handler;
- AppContext handlerContext;
// called from AppKit Thread-0
void dispatch(final _NativeEvent event) {
// grab a local ref to the handler
final H localHandler;
- final AppContext localHandlerContext;
synchronized (_AppEventDispatcher.this) {
localHandler = _handler;
- localHandlerContext = handlerContext;
}
if (localHandler == null) {
performDefaultAction(event);
} else {
- SunToolkit.invokeLaterOnAppContext(localHandlerContext, new Runnable() {
+ SunToolkit.invokeLater(new Runnable() {
public void run() {
performUsing(localHandler, event);
}
@@ -586,22 +570,10 @@ final class _AppEventHandler {
synchronized void setHandler(final H handler) {
this._handler = handler;
-
- setHandlerContext(AppContext.getAppContext());
-
}
void performDefaultAction(final _NativeEvent event) { } // by default, do nothing
abstract void performUsing(final H handler, final _NativeEvent event);
-
- protected void setHandlerContext(AppContext ctx) {
- if (ctx == null) {
- throw new RuntimeException(
- "Attempting to set a handler from a thread group without AppContext");
- }
-
- handlerContext = ctx;
- }
}
abstract static class _QueuingAppEventDispatcher extends _AppEventDispatcher {
@@ -624,8 +596,6 @@ final class _AppEventHandler {
synchronized void setHandler(final H handler) {
this._handler = handler;
- setHandlerContext(AppContext.getAppContext());
-
// dispatch any events in the queue
if (queuedEvents != null) {
// grab a local ref to the queue, so the real one can be nulled out
diff --git a/src/java.desktop/share/classes/sun/awt/SunToolkit.java b/src/java.desktop/share/classes/sun/awt/SunToolkit.java
index 1f92189a62f..51353c7d937 100644
--- a/src/java.desktop/share/classes/sun/awt/SunToolkit.java
+++ b/src/java.desktop/share/classes/sun/awt/SunToolkit.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2026, 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
@@ -538,6 +538,10 @@ public abstract class SunToolkit extends Toolkit
postEvent(targetToAppContext(peerEvent.getSource()), peerEvent);
}
+ public static void invokeLater(Runnable dispatcher) {
+ invokeLaterOnAppContext(AppContext.getAppContext(), dispatcher);
+ }
+
/*
* Execute a chunk of code on the Java event handler thread. The
* method takes into account provided AppContext and sets
From e515c10f3a092955c847c88dcadebb763a807852 Mon Sep 17 00:00:00 2001
From: William Kemper
Date: Wed, 11 Feb 2026 20:10:59 +0000
Subject: [PATCH 23/77] 8377396: GenShen: Consolidate and simplify in place
region promotions
Reviewed-by: shade, kdnilsen
---
.../shenandoahGenerationalHeuristics.cpp | 114 +------
.../heuristics/shenandoahOldHeuristics.hpp | 2 +-
.../shenandoahGenerationalEvacuationTask.cpp | 199 +----------
.../shenandoahGenerationalEvacuationTask.hpp | 1 +
.../shenandoah/shenandoahInPlacePromoter.cpp | 311 ++++++++++++++++++
.../shenandoah/shenandoahInPlacePromoter.hpp | 91 +++++
6 files changed, 423 insertions(+), 295 deletions(-)
create mode 100644 src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.cpp
create mode 100644 src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.hpp
diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp
index 80e6decf57d..029b917deab 100644
--- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp
+++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp
@@ -30,6 +30,7 @@
#include "gc/shenandoah/shenandoahGeneration.hpp"
#include "gc/shenandoah/shenandoahGenerationalHeap.inline.hpp"
#include "gc/shenandoah/shenandoahHeapRegion.inline.hpp"
+#include "gc/shenandoah/shenandoahInPlacePromoter.hpp"
#include "gc/shenandoah/shenandoahOldGeneration.hpp"
#include "gc/shenandoah/shenandoahTrace.hpp"
#include "gc/shenandoah/shenandoahYoungGeneration.hpp"
@@ -403,17 +404,9 @@ size_t ShenandoahGenerationalHeuristics::select_aged_regions(const size_t old_pr
bool* const candidate_regions_for_promotion_by_copy = heap->collection_set()->preselected_regions();
ShenandoahMarkingContext* const ctx = heap->marking_context();
- const size_t old_garbage_threshold =
- (ShenandoahHeapRegion::region_size_bytes() * heap->old_generation()->heuristics()->get_old_garbage_threshold()) / 100;
-
- const size_t pip_used_threshold = (ShenandoahHeapRegion::region_size_bytes() * ShenandoahGenerationalMinPIPUsage) / 100;
-
size_t promo_potential = 0;
size_t candidates = 0;
- // Tracks the padding of space above top in regions eligible for promotion in place
- size_t promote_in_place_pad = 0;
-
// Sort the promotion-eligible regions in order of increasing live-data-bytes so that we can first reclaim regions that require
// less evacuation effort. This prioritizes garbage first, expanding the allocation pool early before we reclaim regions that
// have more live data.
@@ -422,20 +415,7 @@ size_t ShenandoahGenerationalHeuristics::select_aged_regions(const size_t old_pr
ResourceMark rm;
AgedRegionData* sorted_regions = NEW_RESOURCE_ARRAY(AgedRegionData, num_regions);
- ShenandoahFreeSet* freeset = heap->free_set();
-
- // Any region that is to be promoted in place needs to be retired from its Collector or Mutator partition.
- idx_t pip_low_collector_idx = freeset->max_regions();
- idx_t pip_high_collector_idx = -1;
- idx_t pip_low_mutator_idx = freeset->max_regions();
- idx_t pip_high_mutator_idx = -1;
- size_t collector_regions_to_pip = 0;
- size_t mutator_regions_to_pip = 0;
-
- size_t pip_mutator_regions = 0;
- size_t pip_collector_regions = 0;
- size_t pip_mutator_bytes = 0;
- size_t pip_collector_bytes = 0;
+ ShenandoahInPlacePromotionPlanner in_place_promotions(heap);
for (idx_t i = 0; i < num_regions; i++) {
ShenandoahHeapRegion* const r = heap->get_region(i);
@@ -444,77 +424,19 @@ size_t ShenandoahGenerationalHeuristics::select_aged_regions(const size_t old_pr
continue;
}
if (heap->is_tenurable(r)) {
- if ((r->garbage() < old_garbage_threshold) && (r->used() > pip_used_threshold)) {
+ if (in_place_promotions.is_eligible(r)) {
// We prefer to promote this region in place because it has a small amount of garbage and a large usage.
- HeapWord* tams = ctx->top_at_mark_start(r);
- HeapWord* original_top = r->top();
- if (!heap->is_concurrent_old_mark_in_progress() && tams == original_top) {
- // No allocations from this region have been made during concurrent mark. It meets all the criteria
- // for in-place-promotion. Though we only need the value of top when we fill the end of the region,
- // we use this field to indicate that this region should be promoted in place during the evacuation
- // phase.
- r->save_top_before_promote();
- size_t remnant_bytes = r->free();
- size_t remnant_words = remnant_bytes / HeapWordSize;
- assert(ShenandoahHeap::min_fill_size() <= PLAB::min_size(), "Implementation makes invalid assumptions");
- if (remnant_words >= ShenandoahHeap::min_fill_size()) {
- ShenandoahHeap::fill_with_object(original_top, remnant_words);
- // Fill the remnant memory within this region to assure no allocations prior to promote in place. Otherwise,
- // newly allocated objects will not be parsable when promote in place tries to register them. Furthermore, any
- // new allocations would not necessarily be eligible for promotion. This addresses both issues.
- r->set_top(r->end());
- // The region r is either in the Mutator or Collector partition if remnant_words > heap()->plab_min_size.
- // Otherwise, the region is in the NotFree partition.
- ShenandoahFreeSetPartitionId p = free_set->membership(i);
- if (p == ShenandoahFreeSetPartitionId::Mutator) {
- mutator_regions_to_pip++;
- if (i < pip_low_mutator_idx) {
- pip_low_mutator_idx = i;
- }
- if (i > pip_high_mutator_idx) {
- pip_high_mutator_idx = i;
- }
- pip_mutator_regions++;
- pip_mutator_bytes += remnant_bytes;
- } else if (p == ShenandoahFreeSetPartitionId::Collector) {
- collector_regions_to_pip++;
- if (i < pip_low_collector_idx) {
- pip_low_collector_idx = i;
- }
- if (i > pip_high_collector_idx) {
- pip_high_collector_idx = i;
- }
- pip_collector_regions++;
- pip_collector_bytes += remnant_bytes;
- } else {
- assert((p == ShenandoahFreeSetPartitionId::NotFree) && (remnant_words < heap->plab_min_size()),
- "Should be NotFree if not in Collector or Mutator partitions");
- // In this case, the memory is already counted as used and the region has already been retired. There is
- // no need for further adjustments to used. Further, the remnant memory for this region will not be
- // unallocated or made available to OldCollector after pip.
- remnant_bytes = 0;
- }
- promote_in_place_pad += remnant_bytes;
- free_set->prepare_to_promote_in_place(i, remnant_bytes);
- } else {
- // Since the remnant is so small that this region has already been retired, we don't have to worry about any
- // accidental allocations occurring within this region before the region is promoted in place.
-
- // This region was already not in the Collector or Mutator set, so no need to remove it.
- assert(free_set->membership(i) == ShenandoahFreeSetPartitionId::NotFree, "sanity");
- }
- }
- // Else, we do not promote this region (either in place or by copy) because it has received new allocations.
-
- // During evacuation, we exclude from promotion regions for which age > tenure threshold, garbage < garbage-threshold,
- // used > pip_used_threshold, and get_top_before_promote() != tams
+ // Note that if this region has been used recently for allocation, it will not be promoted and it will
+ // not be selected for promotion by evacuation.
+ in_place_promotions.prepare(r);
} else {
// Record this promotion-eligible candidate region. After sorting and selecting the best candidates below,
// we may still decide to exclude this promotion-eligible region from the current collection set. If this
// happens, we will consider this region as part of the anticipated promotion potential for the next GC
// pass; see further below.
sorted_regions[candidates]._region = r;
- sorted_regions[candidates++]._live_data = r->get_live_data_bytes();
+ sorted_regions[candidates]._live_data = r->get_live_data_bytes();
+ candidates++;
}
} else {
// We only evacuate & promote objects from regular regions whose garbage() is above old-garbage-threshold.
@@ -533,7 +455,7 @@ size_t ShenandoahGenerationalHeuristics::select_aged_regions(const size_t old_pr
// in the current cycle and we will anticipate that they will be promoted in the next cycle. This will cause
// us to reserve more old-gen memory so that these objects can be promoted in the subsequent cycle.
if (heap->is_aging_cycle() && heap->age_census()->is_tenurable(r->age() + 1)) {
- if (r->garbage() >= old_garbage_threshold) {
+ if (r->garbage() >= in_place_promotions.old_garbage_threshold()) {
promo_potential += r->get_live_data_bytes();
}
}
@@ -542,21 +464,7 @@ size_t ShenandoahGenerationalHeuristics::select_aged_regions(const size_t old_pr
// Subsequent regions may be selected if they have smaller live data.
}
- if (pip_mutator_regions + pip_collector_regions > 0) {
- freeset->account_for_pip_regions(pip_mutator_regions, pip_mutator_bytes, pip_collector_regions, pip_collector_bytes);
- }
-
- // Retire any regions that have been selected for promote in place
- if (collector_regions_to_pip > 0) {
- freeset->shrink_interval_if_range_modifies_either_boundary(ShenandoahFreeSetPartitionId::Collector,
- pip_low_collector_idx, pip_high_collector_idx,
- collector_regions_to_pip);
- }
- if (mutator_regions_to_pip > 0) {
- freeset->shrink_interval_if_range_modifies_either_boundary(ShenandoahFreeSetPartitionId::Mutator,
- pip_low_mutator_idx, pip_high_mutator_idx,
- mutator_regions_to_pip);
- }
+ in_place_promotions.update_free_set();
// Sort in increasing order according to live data bytes. Note that candidates represents the number of regions
// that qualify to be promoted by evacuation.
@@ -589,8 +497,6 @@ size_t ShenandoahGenerationalHeuristics::select_aged_regions(const size_t old_pr
}
log_info(gc, ergo)("Promotion potential of aged regions with sufficient garbage: " PROPERFMT, PROPERFMTARGS(promo_potential));
-
- heap->old_generation()->set_pad_for_promote_in_place(promote_in_place_pad);
heap->old_generation()->set_promotion_potential(promo_potential);
return old_consumed;
}
diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp
index fc7a35aa6c8..e657ac58ae4 100644
--- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp
+++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp
@@ -128,7 +128,7 @@ private:
// The value of command-line argument ShenandoahOldGarbageThreshold represents the percent of garbage that must
// be present within an old-generation region before that region is considered a good candidate for inclusion in
- // the collection set under normal circumstances. For our purposes, normal circustances are when the memory consumed
+ // the collection set under normal circumstances. For our purposes, normal circumstances are when the memory consumed
// by the old generation is less than 50% of the soft heap capacity. When the old generation grows beyond the 50%
// threshold, we dynamically adjust the old garbage threshold, allowing us to invest in packing the old generation
// more tightly so that more memory can be made available to the more frequent young GC cycles. This variable
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp
index c9b956f9c2f..6912750378e 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp
@@ -24,14 +24,11 @@
*/
#include "gc/shenandoah/shenandoahAsserts.hpp"
-#include "gc/shenandoah/shenandoahFreeSet.hpp"
+#include "gc/shenandoah/shenandoahGeneration.hpp"
#include "gc/shenandoah/shenandoahGenerationalEvacuationTask.hpp"
-#include "gc/shenandoah/shenandoahGenerationalHeap.inline.hpp"
#include "gc/shenandoah/shenandoahHeap.inline.hpp"
-#include "gc/shenandoah/shenandoahOldGeneration.hpp"
-#include "gc/shenandoah/shenandoahScanRemembered.inline.hpp"
+#include "gc/shenandoah/shenandoahInPlacePromoter.hpp"
#include "gc/shenandoah/shenandoahUtils.hpp"
-#include "gc/shenandoah/shenandoahYoungGeneration.hpp"
class ShenandoahConcurrentEvacuator : public ObjectClosure {
private:
@@ -77,10 +74,10 @@ void ShenandoahGenerationalEvacuationTask::work(uint worker_id) {
void ShenandoahGenerationalEvacuationTask::do_work() {
if (_only_promote_regions) {
// No allocations will be made, do not enter oom-during-evac protocol.
- assert(ShenandoahHeap::heap()->collection_set()->is_empty(), "Should not have a collection set here");
+ assert(_heap->collection_set()->is_empty(), "Should not have a collection set here");
promote_regions();
} else {
- assert(!ShenandoahHeap::heap()->collection_set()->is_empty(), "Should have a collection set here");
+ assert(!_heap->collection_set()->is_empty(), "Should have a collection set here");
ShenandoahEvacOOMScope oom_evac_scope;
evacuate_and_promote_regions();
}
@@ -95,16 +92,16 @@ void log_region(const ShenandoahHeapRegion* r, LogStream* ls) {
}
void ShenandoahGenerationalEvacuationTask::promote_regions() {
- ShenandoahHeapRegion* r;
LogTarget(Debug, gc) lt;
-
+ ShenandoahInPlacePromoter promoter(_heap);
+ ShenandoahHeapRegion* r;
while ((r = _regions->next()) != nullptr) {
if (lt.is_enabled()) {
LogStream ls(lt);
log_region(r, &ls);
}
- maybe_promote_region(r);
+ promoter.maybe_promote_region(r);
if (_heap->check_cancelled_gc_and_yield(_concurrent)) {
break;
@@ -115,6 +112,7 @@ void ShenandoahGenerationalEvacuationTask::promote_regions() {
void ShenandoahGenerationalEvacuationTask::evacuate_and_promote_regions() {
LogTarget(Debug, gc) lt;
ShenandoahConcurrentEvacuator cl(_heap);
+ ShenandoahInPlacePromoter promoter(_heap);
ShenandoahHeapRegion* r;
while ((r = _regions->next()) != nullptr) {
@@ -127,7 +125,7 @@ void ShenandoahGenerationalEvacuationTask::evacuate_and_promote_regions() {
assert(r->has_live(), "Region %zu should have been reclaimed early", r->index());
_heap->marked_object_iterate(r, &cl);
} else {
- maybe_promote_region(r);
+ promoter.maybe_promote_region(r);
}
if (_heap->check_cancelled_gc_and_yield(_concurrent)) {
@@ -135,182 +133,3 @@ void ShenandoahGenerationalEvacuationTask::evacuate_and_promote_regions() {
}
}
}
-
-
-void ShenandoahGenerationalEvacuationTask::maybe_promote_region(ShenandoahHeapRegion* r) {
- if (r->is_young() && r->is_active() && _heap->is_tenurable(r)) {
- if (r->is_humongous_start()) {
- // We promote humongous_start regions along with their affiliated continuations during evacuation rather than
- // doing this work during a safepoint. We cannot put humongous regions into the collection set because that
- // triggers the load-reference barrier (LRB) to copy on reference fetch.
- //
- // Aged humongous continuation regions are handled with their start region. If an aged regular region has
- // more garbage than the old garbage threshold, we'll promote by evacuation. If there is room for evacuation
- // in this cycle, the region will be in the collection set. If there is not room, the region will be promoted
- // by evacuation in some future GC cycle.
-
- // We do not promote primitive arrays because there's no performance penalty keeping them in young. When/if they
- // become garbage, reclaiming the memory from young is much quicker and more efficient than reclaiming them from old.
- oop obj = cast_to_oop(r->bottom());
- if (!obj->is_typeArray()) {
- promote_humongous(r);
- }
- } else if (r->is_regular() && (r->get_top_before_promote() != nullptr)) {
- // Likewise, we cannot put promote-in-place regions into the collection set because that would also trigger
- // the LRB to copy on reference fetch.
- //
- // If an aged regular region has received allocations during the current cycle, we do not promote because the
- // newly allocated objects do not have appropriate age; this region's age will be reset to zero at end of cycle.
- promote_in_place(r);
- }
- }
-}
-
-// When we promote a region in place, we can continue to use the established marking context to guide subsequent remembered
-// set scans of this region's content. The region will be coalesced and filled prior to the next old-gen marking effort.
-// We identify the entirety of the region as DIRTY to force the next remembered set scan to identify the "interesting pointers"
-// contained herein.
-void ShenandoahGenerationalEvacuationTask::promote_in_place(ShenandoahHeapRegion* region) {
- assert(!_generation->is_old(), "Sanity check");
- ShenandoahMarkingContext* const marking_context = _heap->young_generation()->complete_marking_context();
- HeapWord* const tams = marking_context->top_at_mark_start(region);
- size_t region_size_bytes = ShenandoahHeapRegion::region_size_bytes();
-
- {
- const size_t old_garbage_threshold =
- (region_size_bytes * _heap->old_generation()->heuristics()->get_old_garbage_threshold()) / 100;
- assert(!_heap->is_concurrent_old_mark_in_progress(), "Cannot promote in place during old marking");
- assert(region->garbage_before_padded_for_promote() < old_garbage_threshold,
- "Region %zu has too much garbage for promotion", region->index());
- assert(region->is_young(), "Only young regions can be promoted");
- assert(region->is_regular(), "Use different service to promote humongous regions");
- assert(_heap->is_tenurable(region), "Only promote regions that are sufficiently aged");
- assert(region->get_top_before_promote() == tams, "Region %zu has been used for allocations before promotion", region->index());
- }
-
- ShenandoahOldGeneration* const old_gen = _heap->old_generation();
- ShenandoahYoungGeneration* const young_gen = _heap->young_generation();
-
- // Rebuild the remembered set information and mark the entire range as DIRTY. We do NOT scan the content of this
- // range to determine which cards need to be DIRTY. That would force us to scan the region twice, once now, and
- // once during the subsequent remembered set scan. Instead, we blindly (conservatively) mark everything as DIRTY
- // now and then sort out the CLEAN pages during the next remembered set scan.
- //
- // Rebuilding the remembered set consists of clearing all object registrations (reset_object_range()) here,
- // then registering every live object and every coalesced range of free objects in the loop that follows.
- ShenandoahScanRemembered* const scanner = old_gen->card_scan();
- scanner->reset_object_range(region->bottom(), region->end());
- scanner->mark_range_as_dirty(region->bottom(), region->get_top_before_promote() - region->bottom());
-
- HeapWord* obj_addr = region->bottom();
- while (obj_addr < tams) {
- oop obj = cast_to_oop(obj_addr);
- if (marking_context->is_marked(obj)) {
- assert(obj->klass() != nullptr, "klass should not be null");
- // This thread is responsible for registering all objects in this region. No need for lock.
- scanner->register_object_without_lock(obj_addr);
- obj_addr += obj->size();
- } else {
- HeapWord* next_marked_obj = marking_context->get_next_marked_addr(obj_addr, tams);
- assert(next_marked_obj <= tams, "next marked object cannot exceed tams");
- size_t fill_size = next_marked_obj - obj_addr;
- assert(fill_size >= ShenandoahHeap::min_fill_size(), "previously allocated objects known to be larger than min_size");
- ShenandoahHeap::fill_with_object(obj_addr, fill_size);
- scanner->register_object_without_lock(obj_addr);
- obj_addr = next_marked_obj;
- }
- }
- // We do not need to scan above TAMS because restored top equals tams
- assert(obj_addr == tams, "Expect loop to terminate when obj_addr equals tams");
-
- {
- ShenandoahHeapLocker locker(_heap->lock());
-
- HeapWord* update_watermark = region->get_update_watermark();
- // pip_unpadded is memory too small to be filled above original top
- size_t pip_unpadded = (region->end() - region->top()) * HeapWordSize;
- assert((region->top() == region->end())
- || (pip_unpadded == (size_t) ((region->end() - region->top()) * HeapWordSize)), "Invariant");
- assert(pip_unpadded < ShenandoahHeap::min_fill_size() * HeapWordSize, "Sanity");
- size_t pip_pad_bytes = (region->top() - region->get_top_before_promote()) * HeapWordSize;
- assert((pip_unpadded == 0) || (pip_pad_bytes == 0), "Only one of pip_unpadded and pip_pad_bytes is non-zero");
-
- // Now that this region is affiliated with old, we can allow it to receive allocations, though it may not be in the
- // is_collector_free range. We'll add it to that range below.
- region->restore_top_before_promote();
-#ifdef ASSERT
- size_t region_to_be_used_in_old = region->used();
- assert(region_to_be_used_in_old + pip_pad_bytes + pip_unpadded == region_size_bytes, "invariant");
-#endif
-
- // The update_watermark was likely established while we had the artificially high value of top. Make it sane now.
- assert(update_watermark >= region->top(), "original top cannot exceed preserved update_watermark");
- region->set_update_watermark(region->top());
-
- // Transfer this region from young to old, increasing promoted_reserve if available space exceeds plab_min_size()
- _heap->free_set()->add_promoted_in_place_region_to_old_collector(region);
- region->set_affiliation(OLD_GENERATION);
- region->set_promoted_in_place();
- }
-}
-
-void ShenandoahGenerationalEvacuationTask::promote_humongous(ShenandoahHeapRegion* region) {
- ShenandoahMarkingContext* marking_context = _heap->marking_context();
- oop obj = cast_to_oop(region->bottom());
- assert(_generation->is_mark_complete(), "sanity");
- assert(region->is_young(), "Only young regions can be promoted");
- assert(region->is_humongous_start(), "Should not promote humongous continuation in isolation");
- assert(_heap->is_tenurable(region), "Only promote regions that are sufficiently aged");
- assert(marking_context->is_marked(obj), "promoted humongous object should be alive");
-
- const size_t used_bytes = obj->size() * HeapWordSize;
- const size_t spanned_regions = ShenandoahHeapRegion::required_regions(used_bytes);
- const size_t region_size_bytes = ShenandoahHeapRegion::region_size_bytes();
- const size_t humongous_waste = spanned_regions * region_size_bytes - obj->size() * HeapWordSize;
- const size_t index_limit = region->index() + spanned_regions;
-
- ShenandoahOldGeneration* const old_gen = _heap->old_generation();
- ShenandoahGeneration* const young_gen = _heap->young_generation();
- {
- // We need to grab the heap lock in order to avoid a race when changing the affiliations of spanned_regions from
- // young to old.
- ShenandoahHeapLocker locker(_heap->lock());
-
- // We promote humongous objects unconditionally, without checking for availability. We adjust
- // usage totals, including humongous waste, after evacuation is done.
- log_debug(gc)("promoting humongous region %zu, spanning %zu", region->index(), spanned_regions);
-
- // For this region and each humongous continuation region spanned by this humongous object, change
- // affiliation to OLD_GENERATION and adjust the generation-use tallies. The remnant of memory
- // in the last humongous region that is not spanned by obj is currently not used.
- for (size_t i = region->index(); i < index_limit; i++) {
- ShenandoahHeapRegion* r = _heap->get_region(i);
- log_debug(gc)("promoting humongous region %zu, from " PTR_FORMAT " to " PTR_FORMAT,
- r->index(), p2i(r->bottom()), p2i(r->top()));
- // We mark the entire humongous object's range as dirty after loop terminates, so no need to dirty the range here
- r->set_affiliation(OLD_GENERATION);
- r->set_promoted_in_place();
- }
-
- ShenandoahFreeSet* freeset = _heap->free_set();
- freeset->transfer_humongous_regions_from_mutator_to_old_collector(spanned_regions, humongous_waste);
- }
-
- // Since this region may have served previously as OLD, it may hold obsolete object range info.
- HeapWord* const humongous_bottom = region->bottom();
- ShenandoahScanRemembered* const scanner = old_gen->card_scan();
- scanner->reset_object_range(humongous_bottom, humongous_bottom + spanned_regions * ShenandoahHeapRegion::region_size_words());
- // Since the humongous region holds only one object, no lock is necessary for this register_object() invocation.
- scanner->register_object_without_lock(humongous_bottom);
-
- if (obj->is_typeArray()) {
- // Primitive arrays don't need to be scanned.
- log_debug(gc)("Clean cards for promoted humongous object (Region %zu) from " PTR_FORMAT " to " PTR_FORMAT,
- region->index(), p2i(humongous_bottom), p2i(humongous_bottom + obj->size()));
- scanner->mark_range_as_clean(humongous_bottom, obj->size());
- } else {
- log_debug(gc)("Dirty cards for promoted humongous object (Region %zu) from " PTR_FORMAT " to " PTR_FORMAT,
- region->index(), p2i(humongous_bottom), p2i(humongous_bottom + obj->size()));
- scanner->mark_range_as_dirty(humongous_bottom, obj->size());
- }
-}
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.hpp
index de47184ffff..1ff58b42e8c 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.hpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.hpp
@@ -27,6 +27,7 @@
#include "gc/shared/workerThread.hpp"
+class ShenandoahGeneration;
class ShenandoahGenerationalHeap;
class ShenandoahHeapRegion;
class ShenandoahRegionIterator;
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.cpp b/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.cpp
new file mode 100644
index 00000000000..83f4217df83
--- /dev/null
+++ b/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.cpp
@@ -0,0 +1,311 @@
+/*
+ * Copyright Amazon.com Inc. 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/plab.hpp"
+#include "gc/shenandoah/shenandoahFreeSet.hpp"
+#include "gc/shenandoah/shenandoahGenerationalHeap.inline.hpp"
+#include "gc/shenandoah/shenandoahHeap.inline.hpp"
+#include "gc/shenandoah/shenandoahHeapRegion.inline.hpp"
+#include "gc/shenandoah/shenandoahInPlacePromoter.hpp"
+#include "gc/shenandoah/shenandoahMarkingContext.hpp"
+#include "gc/shenandoah/shenandoahOldGeneration.hpp"
+#include "gc/shenandoah/shenandoahYoungGeneration.hpp"
+
+ShenandoahInPlacePromotionPlanner::RegionPromotions::RegionPromotions(ShenandoahFreeSet* free_set)
+ : _low_idx(free_set->max_regions())
+ , _high_idx(-1)
+ , _regions(0)
+ , _bytes(0)
+ , _free_set(free_set)
+{
+}
+
+void ShenandoahInPlacePromotionPlanner::RegionPromotions::increment(idx_t region_index, size_t remnant_bytes) {
+ if (region_index < _low_idx) {
+ _low_idx = region_index;
+ }
+ if (region_index > _high_idx) {
+ _high_idx = region_index;
+ }
+ _regions++;
+ _bytes += remnant_bytes;
+}
+
+void ShenandoahInPlacePromotionPlanner::RegionPromotions::update_free_set(ShenandoahFreeSetPartitionId partition_id) const {
+ if (_regions > 0) {
+ _free_set->shrink_interval_if_range_modifies_either_boundary(partition_id, _low_idx, _high_idx, _regions);
+ }
+}
+
+ShenandoahInPlacePromotionPlanner::ShenandoahInPlacePromotionPlanner(const ShenandoahGenerationalHeap* heap)
+ : _old_garbage_threshold(ShenandoahHeapRegion::region_size_bytes() * heap->old_generation()->heuristics()->get_old_garbage_threshold() / 100)
+ , _pip_used_threshold(ShenandoahHeapRegion::region_size_bytes() * ShenandoahGenerationalMinPIPUsage / 100)
+ , _heap(heap)
+ , _free_set(_heap->free_set())
+ , _marking_context(_heap->marking_context())
+ , _mutator_regions(_free_set)
+ , _collector_regions(_free_set)
+ , _pip_padding_bytes(0)
+{
+}
+
+bool ShenandoahInPlacePromotionPlanner::is_eligible(const ShenandoahHeapRegion* region) const {
+ return region->garbage() < _old_garbage_threshold && region->used() > _pip_used_threshold;
+}
+
+void ShenandoahInPlacePromotionPlanner::prepare(ShenandoahHeapRegion* r) {
+ HeapWord* tams = _marking_context->top_at_mark_start(r);
+ HeapWord* original_top = r->top();
+
+ if (_heap->is_concurrent_mark_in_progress() || tams != original_top) {
+ // We do not promote this region (either in place or by copy) because it has received new allocations.
+ // During evacuation, we exclude from promotion regions for which age > tenure threshold, garbage < garbage-threshold,
+ // used > pip_used_threshold, and get_top_before_promote() != tams.
+ // TODO: Such a region should have had its age reset to zero when it was used for allocation?
+ return;
+ }
+
+ // No allocations from this region have been made during concurrent mark. It meets all the criteria
+ // for in-place-promotion. Though we only need the value of top when we fill the end of the region,
+ // we use this field to indicate that this region should be promoted in place during the evacuation
+ // phase.
+ r->save_top_before_promote();
+ size_t remnant_bytes = r->free();
+ size_t remnant_words = remnant_bytes / HeapWordSize;
+ assert(ShenandoahHeap::min_fill_size() <= PLAB::min_size(), "Implementation makes invalid assumptions");
+ if (remnant_words >= ShenandoahHeap::min_fill_size()) {
+ ShenandoahHeap::fill_with_object(original_top, remnant_words);
+ // Fill the remnant memory within this region to assure no allocations prior to promote in place. Otherwise,
+ // newly allocated objects will not be parsable when promote in place tries to register them. Furthermore, any
+ // new allocations would not necessarily be eligible for promotion. This addresses both issues.
+ r->set_top(r->end());
+ // The region r is either in the Mutator or Collector partition if remnant_words > heap()->plab_min_size.
+ // Otherwise, the region is in the NotFree partition.
+ const idx_t i = r->index();
+ ShenandoahFreeSetPartitionId p = _free_set->membership(i);
+ if (p == ShenandoahFreeSetPartitionId::Mutator) {
+ _mutator_regions.increment(i, remnant_bytes);
+ } else if (p == ShenandoahFreeSetPartitionId::Collector) {
+ _collector_regions.increment(i, remnant_bytes);
+ } else {
+ assert((p == ShenandoahFreeSetPartitionId::NotFree) && (remnant_words < _heap->plab_min_size()),
+ "Should be NotFree if not in Collector or Mutator partitions");
+ // In this case, the memory is already counted as used and the region has already been retired. There is
+ // no need for further adjustments to used. Further, the remnant memory for this region will not be
+ // unallocated or made available to OldCollector after pip.
+ remnant_bytes = 0;
+ }
+
+ _pip_padding_bytes += remnant_bytes;
+ _free_set->prepare_to_promote_in_place(i, remnant_bytes);
+ } else {
+ // Since the remnant is so small that this region has already been retired, we don't have to worry about any
+ // accidental allocations occurring within this region before the region is promoted in place.
+
+ // This region was already not in the Collector or Mutator set, so no need to remove it.
+ assert(_free_set->membership(r->index()) == ShenandoahFreeSetPartitionId::NotFree, "sanity");
+ }
+}
+
+void ShenandoahInPlacePromotionPlanner::update_free_set() const {
+ _heap->old_generation()->set_pad_for_promote_in_place(_pip_padding_bytes);
+
+ if (_mutator_regions._regions + _collector_regions._regions > 0) {
+ _free_set->account_for_pip_regions(_mutator_regions._regions, _mutator_regions._bytes,
+ _collector_regions._regions, _collector_regions._bytes);
+ }
+
+ // Retire any regions that have been selected for promote in place
+ _mutator_regions.update_free_set(ShenandoahFreeSetPartitionId::Mutator);
+ _collector_regions.update_free_set(ShenandoahFreeSetPartitionId::Collector);
+}
+
+void ShenandoahInPlacePromoter::maybe_promote_region(ShenandoahHeapRegion* r) const {
+ if (r->is_young() && r->is_active() && _heap->is_tenurable(r)) {
+ if (r->is_humongous_start()) {
+ // We promote humongous_start regions along with their affiliated continuations during evacuation rather than
+ // doing this work during a safepoint. We cannot put humongous regions into the collection set because that
+ // triggers the load-reference barrier (LRB) to copy on reference fetch.
+ //
+ // Aged humongous continuation regions are handled with their start region. If an aged regular region has
+ // more garbage than ShenandoahOldGarbageThreshold, we'll promote by evacuation. If there is room for evacuation
+ // in this cycle, the region will be in the collection set. If there is no room, the region will be promoted
+ // by evacuation in some future GC cycle.
+
+ // We do not promote primitive arrays because there's no performance penalty keeping them in young. When/if they
+ // become garbage, reclaiming the memory from young is much quicker and more efficient than reclaiming them from old.
+ oop obj = cast_to_oop(r->bottom());
+ if (!obj->is_typeArray()) {
+ promote_humongous(r);
+ }
+ } else if (r->is_regular() && (r->get_top_before_promote() != nullptr)) {
+ // Likewise, we cannot put promote-in-place regions into the collection set because that would also trigger
+ // the LRB to copy on reference fetch.
+ //
+ // If an aged regular region has received allocations during the current cycle, we do not promote because the
+ // newly allocated objects do not have appropriate age; this region's age will be reset to zero at end of cycle.
+ promote(r);
+ }
+ }
+}
+
+// When we promote a region in place, we can continue to use the established marking context to guide subsequent remembered
+// set scans of this region's content. The region will be coalesced and filled prior to the next old-gen marking effort.
+// We identify the entirety of the region as DIRTY to force the next remembered set scan to identify the "interesting pointers"
+// contained herein.
+void ShenandoahInPlacePromoter::promote(ShenandoahHeapRegion* region) const {
+
+ ShenandoahMarkingContext* const marking_context = _heap->young_generation()->complete_marking_context();
+ HeapWord* const tams = marking_context->top_at_mark_start(region);
+ size_t region_size_bytes = ShenandoahHeapRegion::region_size_bytes();
+
+ {
+ const size_t old_garbage_threshold =
+ (region_size_bytes * _heap->old_generation()->heuristics()->get_old_garbage_threshold()) / 100;
+ assert(!_heap->is_concurrent_old_mark_in_progress(), "Cannot promote in place during old marking");
+ assert(region->garbage_before_padded_for_promote() < old_garbage_threshold,
+ "Region %zu has too much garbage for promotion", region->index());
+ assert(region->is_young(), "Only young regions can be promoted");
+ assert(region->is_regular(), "Use different service to promote humongous regions");
+ assert(_heap->is_tenurable(region), "Only promote regions that are sufficiently aged");
+ assert(region->get_top_before_promote() == tams, "Region %zu has been used for allocations before promotion", region->index());
+ }
+
+ ShenandoahOldGeneration* const old_gen = _heap->old_generation();
+
+ // Rebuild the remembered set information and mark the entire range as DIRTY. We do NOT scan the content of this
+ // range to determine which cards need to be DIRTY. That would force us to scan the region twice, once now, and
+ // once during the subsequent remembered set scan. Instead, we blindly (conservatively) mark everything as DIRTY
+ // now and then sort out the CLEAN pages during the next remembered set scan.
+ //
+ // Rebuilding the remembered set consists of clearing all object registrations (reset_object_range()) here,
+ // then registering every live object and every coalesced range of free objects in the loop that follows.
+ ShenandoahScanRemembered* const scanner = old_gen->card_scan();
+ scanner->reset_object_range(region->bottom(), region->end());
+ scanner->mark_range_as_dirty(region->bottom(), region->get_top_before_promote() - region->bottom());
+
+ HeapWord* obj_addr = region->bottom();
+ while (obj_addr < tams) {
+ oop obj = cast_to_oop(obj_addr);
+ if (marking_context->is_marked(obj)) {
+ assert(obj->klass() != nullptr, "klass should not be null");
+ // This thread is responsible for registering all objects in this region. No need for lock.
+ scanner->register_object_without_lock(obj_addr);
+ obj_addr += obj->size();
+ } else {
+ HeapWord* next_marked_obj = marking_context->get_next_marked_addr(obj_addr, tams);
+ assert(next_marked_obj <= tams, "next marked object cannot exceed tams");
+ size_t fill_size = next_marked_obj - obj_addr;
+ assert(fill_size >= ShenandoahHeap::min_fill_size(), "previously allocated objects known to be larger than min_size");
+ ShenandoahHeap::fill_with_object(obj_addr, fill_size);
+ scanner->register_object_without_lock(obj_addr);
+ obj_addr = next_marked_obj;
+ }
+ }
+ // We do not need to scan above TAMS because restored top equals tams
+ assert(obj_addr == tams, "Expect loop to terminate when obj_addr equals tams");
+
+
+ {
+ ShenandoahHeapLocker locker(_heap->lock());
+#ifdef ASSERT
+ HeapWord* update_watermark = region->get_update_watermark();
+ // pip_unpadded is memory too small to be filled above original top
+ size_t pip_unpadded = (region->end() - region->top()) * HeapWordSize;
+ assert((region->top() == region->end())
+ || (pip_unpadded == (size_t) ((region->end() - region->top()) * HeapWordSize)), "Invariant");
+ assert(pip_unpadded < ShenandoahHeap::min_fill_size() * HeapWordSize, "Sanity");
+ size_t pip_pad_bytes = (region->top() - region->get_top_before_promote()) * HeapWordSize;
+ assert((pip_unpadded == 0) || (pip_pad_bytes == 0), "Only one of pip_unpadded and pip_pad_bytes is non-zero");
+#endif
+
+ // Now that this region is affiliated with old, we can allow it to receive allocations, though it may not be in the
+ // is_collector_free range. We'll add it to that range below.
+ region->restore_top_before_promote();
+
+ assert(region->used() + pip_pad_bytes + pip_unpadded == region_size_bytes, "invariant");
+
+ // The update_watermark was likely established while we had the artificially high value of top. Make it sane now.
+ assert(update_watermark >= region->top(), "original top cannot exceed preserved update_watermark");
+ region->set_update_watermark(region->top());
+
+ // Transfer this region from young to old, increasing promoted_reserve if available space exceeds plab_min_size()
+ _heap->free_set()->add_promoted_in_place_region_to_old_collector(region);
+ region->set_affiliation(OLD_GENERATION);
+ region->set_promoted_in_place();
+ }
+}
+
+void ShenandoahInPlacePromoter::promote_humongous(ShenandoahHeapRegion* region) const {
+ oop obj = cast_to_oop(region->bottom());
+
+ assert(region->is_young(), "Only young regions can be promoted");
+ assert(region->is_humongous_start(), "Should not promote humongous continuation in isolation");
+ assert(_heap->is_tenurable(region), "Only promote regions that are sufficiently aged");
+ assert(_heap->marking_context()->is_marked(obj), "Promoted humongous object should be alive");
+ assert(!obj->is_typeArray(), "Don't promote humongous primitives");
+
+ const size_t used_bytes = obj->size() * HeapWordSize;
+ const size_t spanned_regions = ShenandoahHeapRegion::required_regions(used_bytes);
+ const size_t region_size_bytes = ShenandoahHeapRegion::region_size_bytes();
+ const size_t humongous_waste = spanned_regions * region_size_bytes - obj->size() * HeapWordSize;
+ const size_t index_limit = region->index() + spanned_regions;
+
+ ShenandoahOldGeneration* const old_gen = _heap->old_generation();
+ {
+ // We need to grab the heap lock in order to avoid a race when changing the affiliations of spanned_regions from
+ // young to old.
+ ShenandoahHeapLocker locker(_heap->lock());
+
+ // We promote humongous objects unconditionally, without checking for availability. We adjust
+ // usage totals, including humongous waste, after evacuation is done.
+ log_debug(gc)("promoting humongous region %zu, spanning %zu", region->index(), spanned_regions);
+
+ // For this region and each humongous continuation region spanned by this humongous object, change
+ // affiliation to OLD_GENERATION and adjust the generation-use tallies. The remnant of memory
+ // in the last humongous region that is not spanned by obj is currently not used.
+ for (size_t i = region->index(); i < index_limit; i++) {
+ ShenandoahHeapRegion* r = _heap->get_region(i);
+ log_debug(gc)("promoting humongous region %zu, from " PTR_FORMAT " to " PTR_FORMAT,
+ r->index(), p2i(r->bottom()), p2i(r->top()));
+ // We mark the entire humongous object's range as dirty after loop terminates, so no need to dirty the range here
+ r->set_affiliation(OLD_GENERATION);
+ r->set_promoted_in_place();
+ }
+
+ ShenandoahFreeSet* freeset = _heap->free_set();
+ freeset->transfer_humongous_regions_from_mutator_to_old_collector(spanned_regions, humongous_waste);
+ }
+
+ // Since this region may have served previously as OLD, it may hold obsolete object range info.
+ HeapWord* const humongous_bottom = region->bottom();
+ ShenandoahScanRemembered* const scanner = old_gen->card_scan();
+ scanner->reset_object_range(humongous_bottom, humongous_bottom + spanned_regions * ShenandoahHeapRegion::region_size_words());
+ // Since the humongous region holds only one object, no lock is necessary for this register_object() invocation.
+ scanner->register_object_without_lock(humongous_bottom);
+
+ log_debug(gc)("Dirty cards for promoted humongous object (Region %zu) from " PTR_FORMAT " to " PTR_FORMAT,
+ region->index(), p2i(humongous_bottom), p2i(humongous_bottom + obj->size()));
+ scanner->mark_range_as_dirty(humongous_bottom, obj->size());
+}
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.hpp b/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.hpp
new file mode 100644
index 00000000000..939107dd3ac
--- /dev/null
+++ b/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.hpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright Amazon.com Inc. 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_GC_SHENANDOAH_SHENANDOAHINPLACEPROMOTER_HPP
+#define SHARE_GC_SHENANDOAH_SHENANDOAHINPLACEPROMOTER_HPP
+
+#include "gc/shenandoah/shenandoahSimpleBitMap.hpp"
+
+class ShenandoahFreeSet;
+class ShenandoahMarkingContext;
+class ShenandoahGenerationalHeap;
+class ShenandoahHeapRegion;
+
+class ShenandoahInPlacePromotionPlanner {
+ using idx_t = ShenandoahSimpleBitMap::idx_t;
+
+ struct RegionPromotions {
+ idx_t _low_idx;
+ idx_t _high_idx;
+ size_t _regions;
+ size_t _bytes;
+ ShenandoahFreeSet* _free_set;
+
+ explicit RegionPromotions(ShenandoahFreeSet* free_set);
+ void increment(idx_t region_index, size_t remnant_bytes);
+ void update_free_set(ShenandoahFreeSetPartitionId partition_id) const;
+ };
+
+ const size_t _old_garbage_threshold;
+ const size_t _pip_used_threshold;
+
+ const ShenandoahGenerationalHeap* _heap;
+ ShenandoahFreeSet* _free_set;
+ const ShenandoahMarkingContext* _marking_context;
+
+ // Any region that is to be promoted in place needs to be retired from its Collector or Mutator partition.
+ RegionPromotions _mutator_regions;
+ RegionPromotions _collector_regions;
+
+ // Tracks the padding of space above top in regions eligible for promotion in place
+ size_t _pip_padding_bytes;
+public:
+ explicit ShenandoahInPlacePromotionPlanner(const ShenandoahGenerationalHeap* heap);
+
+ // Returns true if this region has garbage below and usage above the configurable thresholds
+ bool is_eligible(const ShenandoahHeapRegion* region) const;
+
+ // Prepares the region for promotion by moving top to the end to prevent allocations
+ void prepare(ShenandoahHeapRegion* region);
+
+ // Notifies the free set of in place promotions
+ void update_free_set() const;
+
+ size_t old_garbage_threshold() const { return _old_garbage_threshold; }
+};
+
+class ShenandoahInPlacePromoter {
+ ShenandoahGenerationalHeap* _heap;
+public:
+ explicit ShenandoahInPlacePromoter(ShenandoahGenerationalHeap* heap) : _heap(heap) {}
+
+ // If the region still meets the criteria for promotion in place, it will be promoted
+ void maybe_promote_region(ShenandoahHeapRegion* region) const;
+
+private:
+ void promote(ShenandoahHeapRegion* region) const;
+ void promote_humongous(ShenandoahHeapRegion* region) const;
+};
+
+#endif // SHARE_GC_SHENANDOAH_SHENANDOAHINPLACEPROMOTER_HPP
From 0867f9b1b4bfa090cce1403cdbcce56a2e91127c Mon Sep 17 00:00:00 2001
From: Ioi Lam
Date: Wed, 11 Feb 2026 23:00:50 +0000
Subject: [PATCH 24/77] 8377307: Refactor code for AOT cache pointer
compression
Reviewed-by: jsjolen, xuelei, asmehra
---
.../share/cds/aotCompressedPointers.cpp | 30 ++++
.../share/cds/aotCompressedPointers.hpp | 142 ++++++++++++++++++
src/hotspot/share/cds/aotMetaspace.cpp | 6 +-
src/hotspot/share/cds/archiveBuilder.cpp | 20 +--
src/hotspot/share/cds/archiveBuilder.hpp | 43 +-----
src/hotspot/share/cds/archiveUtils.cpp | 14 +-
src/hotspot/share/cds/archiveUtils.hpp | 56 +------
src/hotspot/share/cds/dynamicArchive.cpp | 9 +-
src/hotspot/share/cds/filemap.cpp | 12 +-
src/hotspot/share/cds/filemap.hpp | 35 ++---
src/hotspot/share/cds/heapShared.cpp | 4 +-
src/hotspot/share/cds/lambdaFormInvokers.cpp | 13 +-
src/hotspot/share/cds/lambdaFormInvokers.hpp | 7 +-
.../share/cds/lambdaProxyClassDictionary.cpp | 28 ++--
.../share/cds/lambdaProxyClassDictionary.hpp | 57 ++++---
src/hotspot/share/cds/runTimeClassInfo.cpp | 19 +--
src/hotspot/share/cds/runTimeClassInfo.hpp | 27 ++--
.../share/classfile/compactHashtable.hpp | 12 +-
src/hotspot/share/classfile/symbolTable.cpp | 3 +-
.../classfile/systemDictionaryShared.cpp | 9 +-
src/hotspot/share/include/cds.h | 4 +-
src/hotspot/share/oops/trainingData.cpp | 6 +-
src/hotspot/share/runtime/sharedRuntime.cpp | 7 +-
src/hotspot/share/runtime/sharedRuntime.hpp | 2 +-
src/hotspot/share/runtime/vmStructs.cpp | 4 +-
.../sun/jvm/hotspot/memory/FileMapInfo.java | 8 +-
26 files changed, 343 insertions(+), 234 deletions(-)
create mode 100644 src/hotspot/share/cds/aotCompressedPointers.cpp
create mode 100644 src/hotspot/share/cds/aotCompressedPointers.hpp
diff --git a/src/hotspot/share/cds/aotCompressedPointers.cpp b/src/hotspot/share/cds/aotCompressedPointers.cpp
new file mode 100644
index 00000000000..c3efa7a7185
--- /dev/null
+++ b/src/hotspot/share/cds/aotCompressedPointers.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2026, 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 "cds/aotCompressedPointers.hpp"
+#include "cds/archiveBuilder.hpp"
+
+size_t AOTCompressedPointers::compute_byte_offset(address p) {
+ return ArchiveBuilder::current()->any_to_offset(p);
+}
diff --git a/src/hotspot/share/cds/aotCompressedPointers.hpp b/src/hotspot/share/cds/aotCompressedPointers.hpp
new file mode 100644
index 00000000000..ead48ef9948
--- /dev/null
+++ b/src/hotspot/share/cds/aotCompressedPointers.hpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2026, 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_CDS_AOTCOMPRESSEDPOINTERS_HPP
+#define SHARE_CDS_AOTCOMPRESSEDPOINTERS_HPP
+
+#include "cds/cds_globals.hpp"
+#include "memory/allStatic.hpp"
+#include "memory/metaspace.hpp"
+#include "metaprogramming/enableIf.hpp"
+#include "utilities/align.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/macros.hpp"
+
+class AOTCompressedPointers: public AllStatic {
+public:
+ // For space saving, we can encode the location of metadata objects in the "rw" and "ro"
+ // regions using a 32-bit offset from the bottom of the mapped AOT metaspace.
+ // Currently we allow only up to 2GB total size in the rw and ro regions (which are
+ // contiguous to each other).
+ enum class narrowPtr : u4;
+ static constexpr size_t MaxMetadataOffsetBytes = 0x7FFFFFFF;
+
+ // In the future, this could return a different numerical value than
+ // narrowp if the encoding contains shifts.
+ inline static size_t get_byte_offset(narrowPtr narrowp) {
+ return checked_cast(narrowp);
+ }
+
+ inline static narrowPtr null() {
+ return static_cast(0);
+ }
+
+ // Encoding ------
+
+ // ptr can point to one of the following
+ // - an object in the ArchiveBuilder's buffer.
+ // - an object in the currently mapped AOT cache rw/ro regions.
+ // - an object that has been copied into the ArchiveBuilder's buffer.
+ template
+ static narrowPtr encode_not_null(T ptr) {
+ address p = reinterpret_cast(ptr);
+ return encode_byte_offset(compute_byte_offset(p));
+ }
+
+ template
+ static narrowPtr encode(T ptr) { // may be null
+ if (ptr == nullptr) {
+ return null();
+ } else {
+ return encode_not_null(ptr);
+ }
+ }
+
+ // ptr must be in the currently mapped AOT cache rw/ro regions.
+ template
+ static narrowPtr encode_address_in_cache(T ptr) {
+ assert(Metaspace::in_aot_cache(ptr), "must be");
+ address p = reinterpret_cast(ptr);
+ address base = reinterpret_cast(SharedBaseAddress);
+ return encode_byte_offset(pointer_delta(p, base, 1));
+ }
+
+ template
+ static narrowPtr encode_address_in_cache_or_null(T ptr) {
+ if (ptr == nullptr) {
+ return null();
+ } else {
+ return encode_address_in_cache(ptr);
+ }
+ }
+
+ // Decoding -----
+
+ // If base_address is null, decode an address within the mapped aot cache range.
+ template
+ static T decode_not_null(narrowPtr narrowp, address base_address = nullptr) {
+ assert(narrowp != null(), "sanity");
+ if (base_address == nullptr) {
+ T p = reinterpret_cast(reinterpret_cast(SharedBaseAddress) + get_byte_offset(narrowp));
+ assert(Metaspace::in_aot_cache(p), "must be");
+ return p;
+ } else {
+ // This is usually called before the cache is fully mapped.
+ return reinterpret_cast(base_address + get_byte_offset(narrowp));
+ }
+ }
+
+ template
+ static T decode(narrowPtr narrowp, address base_address = nullptr) { // may be null
+ if (narrowp == null()) {
+ return nullptr;
+ } else {
+ return decode_not_null(narrowp, base_address);
+ }
+ }
+
+private:
+ static size_t compute_byte_offset(address p);
+
+ static narrowPtr encode_byte_offset(size_t offset) {
+ assert(offset != 0, "offset 0 is in protection zone");
+ precond(offset <= MaxMetadataOffsetBytes);
+ return checked_cast(offset);
+ }
+};
+
+// Type casts -- declared as global functions to save a few keystrokes
+
+// A simple type cast. No change in numerical value.
+inline AOTCompressedPointers::narrowPtr cast_from_u4(u4 narrowp) {
+ return checked_cast(narrowp);
+}
+
+// A simple type cast. No change in numerical value.
+// !!!DO NOT CALL THIS if you want a byte offset!!!
+inline u4 cast_to_u4(AOTCompressedPointers::narrowPtr narrowp) {
+ return checked_cast(narrowp);
+}
+
+#endif // SHARE_CDS_AOTCOMPRESSEDPOINTERS_HPP
diff --git a/src/hotspot/share/cds/aotMetaspace.cpp b/src/hotspot/share/cds/aotMetaspace.cpp
index 8bb8387f1ab..544eaa07a4d 100644
--- a/src/hotspot/share/cds/aotMetaspace.cpp
+++ b/src/hotspot/share/cds/aotMetaspace.cpp
@@ -2106,7 +2106,7 @@ MapArchiveResult AOTMetaspace::map_archive(FileMapInfo* mapinfo, char* mapped_ba
// Currently, only static archive uses early serialized data.
char* buffer = mapinfo->early_serialized_data();
intptr_t* array = (intptr_t*)buffer;
- ReadClosure rc(&array, (intptr_t)mapped_base_address);
+ ReadClosure rc(&array, (address)mapped_base_address);
early_serialize(&rc);
}
@@ -2152,7 +2152,7 @@ void AOTMetaspace::initialize_shared_spaces() {
// shared string/symbol tables.
char* buffer = static_mapinfo->serialized_data();
intptr_t* array = (intptr_t*)buffer;
- ReadClosure rc(&array, (intptr_t)SharedBaseAddress);
+ ReadClosure rc(&array, (address)SharedBaseAddress);
serialize(&rc);
// Finish initializing the heap dump mode used in the archive
@@ -2164,7 +2164,7 @@ void AOTMetaspace::initialize_shared_spaces() {
if (dynamic_mapinfo != nullptr) {
intptr_t* buffer = (intptr_t*)dynamic_mapinfo->serialized_data();
- ReadClosure rc(&buffer, (intptr_t)SharedBaseAddress);
+ ReadClosure rc(&buffer, (address)SharedBaseAddress);
DynamicArchive::serialize(&rc);
}
diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp
index e65bd3985ac..cb9459172b3 100644
--- a/src/hotspot/share/cds/archiveBuilder.cpp
+++ b/src/hotspot/share/cds/archiveBuilder.cpp
@@ -24,6 +24,7 @@
#include "cds/aotArtifactFinder.hpp"
#include "cds/aotClassLinker.hpp"
+#include "cds/aotCompressedPointers.hpp"
#include "cds/aotLogging.hpp"
#include "cds/aotMapLogger.hpp"
#include "cds/aotMetaspace.hpp"
@@ -175,10 +176,10 @@ ArchiveBuilder::ArchiveBuilder() :
_mapped_static_archive_bottom(nullptr),
_mapped_static_archive_top(nullptr),
_buffer_to_requested_delta(0),
- _pz_region("pz", MAX_SHARED_DELTA), // protection zone -- used only during dumping; does NOT exist in cds archive.
- _rw_region("rw", MAX_SHARED_DELTA),
- _ro_region("ro", MAX_SHARED_DELTA),
- _ac_region("ac", MAX_SHARED_DELTA),
+ _pz_region("pz"), // protection zone -- used only during dumping; does NOT exist in cds archive.
+ _rw_region("rw"),
+ _ro_region("ro"),
+ _ac_region("ac"),
_ptrmap(mtClassShared),
_rw_ptrmap(mtClassShared),
_ro_ptrmap(mtClassShared),
@@ -990,16 +991,15 @@ void ArchiveBuilder::make_training_data_shareable() {
_src_obj_table.iterate_all(clean_td);
}
-uintx ArchiveBuilder::buffer_to_offset(address p) const {
+size_t ArchiveBuilder::buffer_to_offset(address p) const {
address requested_p = to_requested(p);
- assert(requested_p >= _requested_static_archive_bottom, "must be");
- return requested_p - _requested_static_archive_bottom;
+ return pointer_delta(requested_p, _requested_static_archive_bottom, 1);
}
-uintx ArchiveBuilder::any_to_offset(address p) const {
+size_t ArchiveBuilder::any_to_offset(address p) const {
if (is_in_mapped_static_archive(p)) {
assert(CDSConfig::is_dumping_dynamic_archive(), "must be");
- return p - _mapped_static_archive_bottom;
+ return pointer_delta(p, _mapped_static_archive_bottom, 1);
}
if (!is_in_buffer_space(p)) {
// p must be a "source" address
@@ -1008,7 +1008,7 @@ uintx ArchiveBuilder::any_to_offset(address p) const {
return buffer_to_offset(p);
}
-address ArchiveBuilder::offset_to_buffered_address(u4 offset) const {
+address ArchiveBuilder::offset_to_buffered_address(size_t offset) const {
address requested_addr = _requested_static_archive_bottom + offset;
address buffered_addr = requested_addr - _buffer_to_requested_delta;
assert(is_in_buffer_space(buffered_addr), "bad offset");
diff --git a/src/hotspot/share/cds/archiveBuilder.hpp b/src/hotspot/share/cds/archiveBuilder.hpp
index 2284dbf70f8..b3667ea11b4 100644
--- a/src/hotspot/share/cds/archiveBuilder.hpp
+++ b/src/hotspot/share/cds/archiveBuilder.hpp
@@ -329,49 +329,22 @@ public:
return current()->buffer_to_requested_delta();
}
- inline static u4 to_offset_u4(uintx offset) {
- guarantee(offset <= MAX_SHARED_DELTA, "must be 32-bit offset " INTPTR_FORMAT, offset);
- return (u4)offset;
- }
-
public:
- static const uintx MAX_SHARED_DELTA = ArchiveUtils::MAX_SHARED_DELTA;;
-
// The address p points to an object inside the output buffer. When the archive is mapped
// at the requested address, what's the offset of this object from _requested_static_archive_bottom?
- uintx buffer_to_offset(address p) const;
+ size_t buffer_to_offset(address p) const;
- // Same as buffer_to_offset, except that the address p points to either (a) an object
- // inside the output buffer, or (b), an object in the currently mapped static archive.
- uintx any_to_offset(address p) const;
+ // Same as buffer_to_offset, except that the address p points to one of the following:
+ // - an object in the ArchiveBuilder's buffer.
+ // - an object in the currently mapped AOT cache rw/ro regions.
+ // - an object that has been copied into the ArchiveBuilder's buffer.
+ size_t any_to_offset(address p) const;
// The reverse of buffer_to_offset()
- address offset_to_buffered_address(u4 offset) const;
+ address offset_to_buffered_address(size_t offset) const;
template
- u4 buffer_to_offset_u4(T p) const {
- uintx offset = buffer_to_offset((address)p);
- return to_offset_u4(offset);
- }
-
- template
- u4 any_to_offset_u4(T p) const {
- assert(p != nullptr, "must not be null");
- uintx offset = any_to_offset((address)p);
- return to_offset_u4(offset);
- }
-
- template
- u4 any_or_null_to_offset_u4(T p) const {
- if (p == nullptr) {
- return 0;
- } else {
- return any_to_offset_u4(p);
- }
- }
-
- template
- T offset_to_buffered(u4 offset) const {
+ T offset_to_buffered(size_t offset) const {
return (T)offset_to_buffered_address(offset);
}
diff --git a/src/hotspot/share/cds/archiveUtils.cpp b/src/hotspot/share/cds/archiveUtils.cpp
index 842668509cf..c13b447bb87 100644
--- a/src/hotspot/share/cds/archiveUtils.cpp
+++ b/src/hotspot/share/cds/archiveUtils.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2026, 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,6 +22,7 @@
*
*/
+#include "cds/aotCompressedPointers.hpp"
#include "cds/aotLogging.hpp"
#include "cds/aotMetaspace.hpp"
#include "cds/archiveBuilder.hpp"
@@ -201,13 +202,13 @@ char* DumpRegion::expand_top_to(char* newtop) {
commit_to(newtop);
_top = newtop;
- if (_max_delta > 0) {
+ if (ArchiveBuilder::is_active() && ArchiveBuilder::current()->is_in_buffer_space(_base)) {
uintx delta = ArchiveBuilder::current()->buffer_to_offset((address)(newtop-1));
- if (delta > _max_delta) {
+ if (delta > AOTCompressedPointers::MaxMetadataOffsetBytes) {
// This is just a sanity check and should not appear in any real world usage. This
// happens only if you allocate more than 2GB of shared objects and would require
// millions of shared classes.
- aot_log_error(aot)("Out of memory in the CDS archive: Please reduce the number of shared classes.");
+ aot_log_error(aot)("Out of memory in the %s: Please reduce the number of shared classes.", CDSConfig::type_of_archive_being_written());
AOTMetaspace::unrecoverable_writing_error();
}
}
@@ -331,9 +332,8 @@ void WriteClosure::do_ptr(void** p) {
void ReadClosure::do_ptr(void** p) {
assert(*p == nullptr, "initializing previous initialized pointer.");
- intptr_t obj = nextPtr();
- assert(obj >= 0, "sanity.");
- *p = (obj != 0) ? (void*)(_base_address + obj) : (void*)obj;
+ u4 narrowp = checked_cast(nextPtr());
+ *p = AOTCompressedPointers::decode(cast_from_u4(narrowp), _base_address);
}
void ReadClosure::do_u4(u4* p) {
diff --git a/src/hotspot/share/cds/archiveUtils.hpp b/src/hotspot/share/cds/archiveUtils.hpp
index 79d894f0144..e5d1efa5eab 100644
--- a/src/hotspot/share/cds/archiveUtils.hpp
+++ b/src/hotspot/share/cds/archiveUtils.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2026, 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
@@ -153,7 +153,6 @@ private:
char* _base;
char* _top;
char* _end;
- uintx _max_delta;
bool _is_packed;
ReservedSpace* _rs;
VirtualSpace* _vs;
@@ -161,9 +160,9 @@ private:
void commit_to(char* newtop);
public:
- DumpRegion(const char* name, uintx max_delta = 0)
+ DumpRegion(const char* name)
: _name(name), _base(nullptr), _top(nullptr), _end(nullptr),
- _max_delta(max_delta), _is_packed(false),
+ _is_packed(false),
_rs(nullptr), _vs(nullptr) {}
char* expand_top_to(char* newtop);
@@ -237,13 +236,13 @@ public:
class ReadClosure : public SerializeClosure {
private:
intptr_t** _ptr_array;
- intptr_t _base_address;
+ address _base_address;
inline intptr_t nextPtr() {
return *(*_ptr_array)++;
}
public:
- ReadClosure(intptr_t** ptr_array, intptr_t base_address) :
+ ReadClosure(intptr_t** ptr_array, address base_address) :
_ptr_array(ptr_array), _base_address(base_address) {}
void do_ptr(void** p);
@@ -260,7 +259,6 @@ class ArchiveUtils {
template static Array* archive_ptr_array(GrowableArray* tmp_array);
public:
- static const uintx MAX_SHARED_DELTA = 0x7FFFFFFF;
static void log_to_classlist(BootstrapInfo* bootstrap_specifier, TRAPS) NOT_CDS_RETURN;
static bool has_aot_initialized_mirror(InstanceKlass* src_ik);
@@ -273,50 +271,6 @@ public:
static Array* archive_array(GrowableArray* tmp_array) {
return archive_ptr_array(tmp_array);
}
-
- // The following functions translate between a u4 offset and an address in the
- // the range of the mapped CDS archive (e.g., Metaspace::in_aot_cache()).
- // Since the first 16 bytes in this range are dummy data (see ArchiveBuilder::reserve_buffer()),
- // we know that offset 0 never represents a valid object. As a result, an offset of 0
- // is used to encode a nullptr.
- //
- // Use the "archived_address_or_null" variants if a nullptr may be encoded.
-
- // offset must represent an object of type T in the mapped shared space. Return
- // a direct pointer to this object.
- template T static offset_to_archived_address(u4 offset) {
- assert(offset != 0, "sanity");
- T p = (T)(SharedBaseAddress + offset);
- assert(Metaspace::in_aot_cache(p), "must be");
- return p;
- }
-
- template T static offset_to_archived_address_or_null(u4 offset) {
- if (offset == 0) {
- return nullptr;
- } else {
- return offset_to_archived_address(offset);
- }
- }
-
- // p must be an archived object. Get its offset from SharedBaseAddress
- template static u4 archived_address_to_offset(T p) {
- uintx pn = (uintx)p;
- uintx base = (uintx)SharedBaseAddress;
- assert(Metaspace::in_aot_cache(p), "must be");
- assert(pn > base, "sanity"); // No valid object is stored at 0 offset from SharedBaseAddress
- uintx offset = pn - base;
- assert(offset <= MAX_SHARED_DELTA, "range check");
- return static_cast(offset);
- }
-
- template static u4 archived_address_or_null_to_offset(T p) {
- if (p == nullptr) {
- return 0;
- } else {
- return archived_address_to_offset(p);
- }
- }
};
class HeapRootSegments {
diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp
index d39cf3775e4..cd6890555d3 100644
--- a/src/hotspot/share/cds/dynamicArchive.cpp
+++ b/src/hotspot/share/cds/dynamicArchive.cpp
@@ -25,6 +25,7 @@
#include "cds/aotArtifactFinder.hpp"
#include "cds/aotClassLinker.hpp"
#include "cds/aotClassLocation.hpp"
+#include "cds/aotCompressedPointers.hpp"
#include "cds/aotLogging.hpp"
#include "cds/aotMetaspace.hpp"
#include "cds/archiveBuilder.hpp"
@@ -75,13 +76,13 @@ public:
return 0;
}
- u4 a_offset = ArchiveBuilder::current()->any_to_offset_u4(a_name);
- u4 b_offset = ArchiveBuilder::current()->any_to_offset_u4(b_name);
+ u4 a_narrowp = cast_to_u4(AOTCompressedPointers::encode_not_null(a_name));
+ u4 b_narrowp = cast_to_u4(AOTCompressedPointers::encode_not_null(b_name));
- if (a_offset < b_offset) {
+ if (a_narrowp < b_narrowp) {
return -1;
} else {
- assert(a_offset > b_offset, "must be");
+ assert(a_narrowp > b_narrowp, "must be");
return 1;
}
}
diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp
index 7cd736885ad..a779fcddfcf 100644
--- a/src/hotspot/share/cds/filemap.cpp
+++ b/src/hotspot/share/cds/filemap.cpp
@@ -298,11 +298,11 @@ void FileMapHeader::print(outputStream* st) {
st->print_cr("- compressed_class_ptrs: %d", _compressed_class_ptrs);
st->print_cr("- narrow_klass_pointer_bits: %d", _narrow_klass_pointer_bits);
st->print_cr("- narrow_klass_shift: %d", _narrow_klass_shift);
- st->print_cr("- cloned_vtables_offset: 0x%zx", _cloned_vtables_offset);
- st->print_cr("- early_serialized_data_offset: 0x%zx", _early_serialized_data_offset);
- st->print_cr("- serialized_data_offset: 0x%zx", _serialized_data_offset);
+ st->print_cr("- cloned_vtables: %u", cast_to_u4(_cloned_vtables));
+ st->print_cr("- early_serialized_data: %u", cast_to_u4(_early_serialized_data));
+ st->print_cr("- serialized_data: %u", cast_to_u4(_serialized_data));
st->print_cr("- jvm_ident: %s", _jvm_ident);
- st->print_cr("- class_location_config_offset: 0x%zx", _class_location_config_offset);
+ st->print_cr("- class_location_config: %d", cast_to_u4(_class_location_config));
st->print_cr("- verify_local: %d", _verify_local);
st->print_cr("- verify_remote: %d", _verify_remote);
st->print_cr("- has_platform_or_app_classes: %d", _has_platform_or_app_classes);
@@ -1767,10 +1767,6 @@ void FileMapInfo::print(outputStream* st) const {
}
}
-void FileMapHeader::set_as_offset(char* p, size_t *offset) {
- *offset = ArchiveBuilder::current()->any_to_offset((address)p);
-}
-
int FileMapHeader::compute_crc() {
char* start = (char*)this;
// start computing from the field after _header_size to end of base archive name.
diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp
index ec7b58a6d19..56b88df378a 100644
--- a/src/hotspot/share/cds/filemap.hpp
+++ b/src/hotspot/share/cds/filemap.hpp
@@ -25,6 +25,7 @@
#ifndef SHARE_CDS_FILEMAP_HPP
#define SHARE_CDS_FILEMAP_HPP
+#include "cds/aotCompressedPointers.hpp"
#include "cds/aotMappedHeap.hpp"
#include "cds/aotMetaspace.hpp"
#include "cds/aotStreamedHeap.hpp"
@@ -104,7 +105,7 @@ public:
class FileMapHeader: private CDSFileMapHeaderBase {
friend class CDSConstants;
friend class VMStructs;
-
+ using narrowPtr = AOTCompressedPointers::narrowPtr;
private:
// The following fields record the states of the VM during dump time.
// They are compared with the runtime states to see if the archive
@@ -122,16 +123,16 @@ private:
bool _compressed_class_ptrs; // save the flag UseCompressedClassPointers
int _narrow_klass_pointer_bits; // save number of bits in narrowKlass
int _narrow_klass_shift; // save shift width used to pre-compute narrowKlass IDs in archived heap objects
- size_t _cloned_vtables_offset; // The address of the first cloned vtable
- size_t _early_serialized_data_offset; // Data accessed using {ReadClosure,WriteClosure}::serialize()
- size_t _serialized_data_offset; // Data accessed using {ReadClosure,WriteClosure}::serialize()
+ narrowPtr _cloned_vtables; // The address of the first cloned vtable
+ narrowPtr _early_serialized_data; // Data accessed using {ReadClosure,WriteClosure}::serialize()
+ narrowPtr _serialized_data; // Data accessed using {ReadClosure,WriteClosure}::serialize()
// The following fields are all sanity checks for whether this archive
// will function correctly with this JVM and the bootclasspath it's
// invoked with.
char _jvm_ident[JVM_IDENT_MAX]; // identifier string of the jvm that created this dump
- size_t _class_location_config_offset;
+ narrowPtr _class_location_config;
bool _verify_local; // BytecodeVerificationLocal setting
bool _verify_remote; // BytecodeVerificationRemote setting
@@ -160,12 +161,8 @@ private:
bool _type_profile_casts;
int _spec_trap_limit_extra_entries;
- template T from_mapped_offset(size_t offset) const {
- return (T)(mapped_base_address() + offset);
- }
- void set_as_offset(char* p, size_t *offset);
- template void set_as_offset(T p, size_t *offset) {
- set_as_offset((char*)p, offset);
+ template T decode(narrowPtr narrowp) const {
+ return AOTCompressedPointers::decode_not_null(narrowp, reinterpret_cast(mapped_base_address()));
}
public:
@@ -193,9 +190,9 @@ public:
bool compact_headers() const { return _compact_headers; }
uintx max_heap_size() const { return _max_heap_size; }
CompressedOops::Mode narrow_oop_mode() const { return _narrow_oop_mode; }
- char* cloned_vtables() const { return from_mapped_offset(_cloned_vtables_offset); }
- char* early_serialized_data() const { return from_mapped_offset(_early_serialized_data_offset); }
- char* serialized_data() const { return from_mapped_offset(_serialized_data_offset); }
+ char* cloned_vtables() const { return decode(_cloned_vtables); }
+ char* early_serialized_data() const { return decode(_early_serialized_data); }
+ char* serialized_data() const { return decode(_serialized_data); }
bool object_streaming_mode() const { return _object_streaming_mode; }
const char* jvm_ident() const { return _jvm_ident; }
char* requested_base_address() const { return _requested_base_address; }
@@ -218,9 +215,9 @@ public:
void set_mapped_heap_header(AOTMappedHeapHeader header) { _mapped_heap_header = header; }
void set_has_platform_or_app_classes(bool v) { _has_platform_or_app_classes = v; }
- void set_cloned_vtables(char* p) { set_as_offset(p, &_cloned_vtables_offset); }
- void set_early_serialized_data(char* p) { set_as_offset(p, &_early_serialized_data_offset); }
- void set_serialized_data(char* p) { set_as_offset(p, &_serialized_data_offset); }
+ void set_cloned_vtables(char* p) { _cloned_vtables = AOTCompressedPointers::encode_not_null(p); }
+ void set_early_serialized_data(char* p) { _early_serialized_data = AOTCompressedPointers::encode_not_null(p); }
+ void set_serialized_data(char* p) { _serialized_data = AOTCompressedPointers::encode_not_null(p); }
void set_mapped_base_address(char* p) { _mapped_base_address = p; }
void set_rw_ptrmap_start_pos(size_t n) { _rw_ptrmap_start_pos = n; }
void set_ro_ptrmap_start_pos(size_t n) { _ro_ptrmap_start_pos = n; }
@@ -228,11 +225,11 @@ public:
void copy_base_archive_name(const char* name);
void set_class_location_config(AOTClassLocationConfig* table) {
- set_as_offset(table, &_class_location_config_offset);
+ _class_location_config = AOTCompressedPointers::encode_not_null(table);
}
AOTClassLocationConfig* class_location_config() {
- return from_mapped_offset(_class_location_config_offset);
+ return decode(_class_location_config);
}
void set_requested_base(char* b) {
diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp
index 69a098c67b3..c01e6ded25a 100644
--- a/src/hotspot/share/cds/heapShared.cpp
+++ b/src/hotspot/share/cds/heapShared.cpp
@@ -25,6 +25,7 @@
#include "cds/aotArtifactFinder.hpp"
#include "cds/aotClassInitializer.hpp"
#include "cds/aotClassLocation.hpp"
+#include "cds/aotCompressedPointers.hpp"
#include "cds/aotLogging.hpp"
#include "cds/aotMappedHeapLoader.hpp"
#include "cds/aotMappedHeapWriter.hpp"
@@ -1148,8 +1149,7 @@ public:
ArchivedKlassSubGraphInfoRecord* record = HeapShared::archive_subgraph_info(&info);
Klass* buffered_k = ArchiveBuilder::get_buffered_klass(klass);
unsigned int hash = SystemDictionaryShared::hash_for_shared_dictionary((address)buffered_k);
- u4 delta = ArchiveBuilder::current()->any_to_offset_u4(record);
- _writer->add(hash, delta);
+ _writer->add(hash, AOTCompressedPointers::encode_not_null(record));
}
return true; // keep on iterating
}
diff --git a/src/hotspot/share/cds/lambdaFormInvokers.cpp b/src/hotspot/share/cds/lambdaFormInvokers.cpp
index 19dae28c5b5..3ff5705b79d 100644
--- a/src/hotspot/share/cds/lambdaFormInvokers.cpp
+++ b/src/hotspot/share/cds/lambdaFormInvokers.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2026, 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,6 +23,7 @@
*/
#include "cds/aotClassFilter.hpp"
+#include "cds/aotCompressedPointers.hpp"
#include "cds/aotMetaspace.hpp"
#include "cds/archiveBuilder.hpp"
#include "cds/cdsConfig.hpp"
@@ -52,7 +53,7 @@
#include "runtime/mutexLocker.hpp"
GrowableArrayCHeap* LambdaFormInvokers::_lambdaform_lines = nullptr;
-Array* LambdaFormInvokers::_static_archive_invokers = nullptr;
+Array* LambdaFormInvokers::_static_archive_invokers = nullptr;
static bool _stop_appending = false;
#define NUM_FILTER 4
@@ -252,7 +253,7 @@ void LambdaFormInvokers::dump_static_archive_invokers() {
}
}
if (count > 0) {
- _static_archive_invokers = ArchiveBuilder::new_ro_array(count);
+ _static_archive_invokers = ArchiveBuilder::new_ro_array(count);
int index = 0;
for (int i = 0; i < len; i++) {
char* str = _lambdaform_lines->at(i);
@@ -261,7 +262,7 @@ void LambdaFormInvokers::dump_static_archive_invokers() {
Array* line = ArchiveBuilder::new_ro_array((int)str_len);
strncpy(line->adr_at(0), str, str_len);
- _static_archive_invokers->at_put(index, ArchiveBuilder::current()->any_to_offset_u4(line));
+ _static_archive_invokers->at_put(index, AOTCompressedPointers::encode_not_null(line));
index++;
}
}
@@ -274,8 +275,8 @@ void LambdaFormInvokers::dump_static_archive_invokers() {
void LambdaFormInvokers::read_static_archive_invokers() {
if (_static_archive_invokers != nullptr) {
for (int i = 0; i < _static_archive_invokers->length(); i++) {
- u4 offset = _static_archive_invokers->at(i);
- Array* line = ArchiveUtils::offset_to_archived_address*>(offset);
+ narrowPtr encoded = _static_archive_invokers->at(i);
+ Array* line = AOTCompressedPointers::decode_not_null*>(encoded);
char* str = line->adr_at(0);
append(str);
}
diff --git a/src/hotspot/share/cds/lambdaFormInvokers.hpp b/src/hotspot/share/cds/lambdaFormInvokers.hpp
index 583a863a1c2..9b91850f5b1 100644
--- a/src/hotspot/share/cds/lambdaFormInvokers.hpp
+++ b/src/hotspot/share/cds/lambdaFormInvokers.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2026, 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,6 +24,8 @@
#ifndef SHARE_CDS_LAMBDAFORMINVOKERS_HPP
#define SHARE_CDS_LAMBDAFORMINVOKERS_HPP
+
+#include "cds/aotCompressedPointers.hpp"
#include "memory/allStatic.hpp"
#include "oops/oopHandle.hpp"
#include "runtime/handles.hpp"
@@ -35,10 +37,11 @@ class Array;
class SerializeClosure;
class LambdaFormInvokers : public AllStatic {
+ using narrowPtr = AOTCompressedPointers::narrowPtr;
private:
static GrowableArrayCHeap* _lambdaform_lines;
// For storing LF form lines (LF_RESOLVE only) in read only table.
- static Array* _static_archive_invokers;
+ static Array* _static_archive_invokers;
static void regenerate_class(char* name, ClassFileStream& st, TRAPS);
public:
static void append(char* line);
diff --git a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp
index d091067c116..4d212dbf2c2 100644
--- a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp
+++ b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2026, 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,6 +23,7 @@
*/
#include "cds/aotClassFilter.hpp"
+#include "cds/aotCompressedPointers.hpp"
#include "cds/archiveBuilder.hpp"
#include "cds/cdsConfig.hpp"
#include "cds/cdsProtectionDomain.hpp"
@@ -49,11 +50,11 @@ unsigned int LambdaProxyClassKey::hash() const {
}
unsigned int RunTimeLambdaProxyClassKey::hash() const {
- return primitive_hash(_caller_ik) +
- primitive_hash(_invoked_name) +
- primitive_hash(_invoked_type) +
- primitive_hash(_method_type) +
- primitive_hash(_instantiated_method_type);
+ return primitive_hash(cast_to_u4(_caller_ik)) +
+ primitive_hash(cast_to_u4(_invoked_name)) +
+ primitive_hash(cast_to_u4(_invoked_type)) +
+ primitive_hash(cast_to_u4(_method_type)) +
+ primitive_hash(cast_to_u4(_instantiated_method_type));
}
#ifndef PRODUCT
@@ -71,12 +72,12 @@ void LambdaProxyClassKey::print_on(outputStream* st) const {
void RunTimeLambdaProxyClassKey::print_on(outputStream* st) const {
ResourceMark rm;
st->print_cr("LambdaProxyClassKey : " INTPTR_FORMAT " hash: %0x08x", p2i(this), hash());
- st->print_cr("_caller_ik : %d", _caller_ik);
- st->print_cr("_instantiated_method_type : %d", _instantiated_method_type);
- st->print_cr("_invoked_name : %d", _invoked_name);
- st->print_cr("_invoked_type : %d", _invoked_type);
- st->print_cr("_member_method : %d", _member_method);
- st->print_cr("_method_type : %d", _method_type);
+ st->print_cr("_caller_ik : %d", cast_to_u4(_caller_ik));
+ st->print_cr("_instantiated_method_type : %d", cast_to_u4(_instantiated_method_type));
+ st->print_cr("_invoked_name : %d", cast_to_u4(_invoked_name));
+ st->print_cr("_invoked_type : %d", cast_to_u4(_invoked_type));
+ st->print_cr("_member_method : %d", cast_to_u4(_member_method));
+ st->print_cr("_method_type : %d", cast_to_u4(_method_type));
}
void RunTimeLambdaProxyClassInfo::print_on(outputStream* st) const {
@@ -418,8 +419,7 @@ public:
(RunTimeLambdaProxyClassInfo*)ArchiveBuilder::ro_region_alloc(byte_size);
runtime_info->init(key, info);
unsigned int hash = runtime_info->hash();
- u4 delta = _builder->any_to_offset_u4((void*)runtime_info);
- _writer->add(hash, delta);
+ _writer->add(hash, AOTCompressedPointers::encode_not_null(runtime_info));
return true;
}
};
diff --git a/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp b/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp
index 91e508bfdc5..dfb75532917 100644
--- a/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp
+++ b/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2026, 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
@@ -25,8 +25,9 @@
#ifndef SHARE_CDS_LAMBDAPROXYCLASSINFO_HPP
#define SHARE_CDS_LAMBDAPROXYCLASSINFO_HPP
+#include "cds/aotCompressedPointers.hpp"
#include "cds/aotMetaspace.hpp"
-#include "cds/archiveBuilder.hpp"
+#include "classfile/compactHashtable.hpp"
#include "classfile/javaClasses.hpp"
#include "memory/metaspaceClosure.hpp"
#include "utilities/growableArray.hpp"
@@ -132,19 +133,20 @@ public:
};
class RunTimeLambdaProxyClassKey {
- u4 _caller_ik;
- u4 _invoked_name;
- u4 _invoked_type;
- u4 _method_type;
- u4 _member_method;
- u4 _instantiated_method_type;
+ using narrowPtr = AOTCompressedPointers::narrowPtr;
+ narrowPtr _caller_ik;
+ narrowPtr _invoked_name;
+ narrowPtr _invoked_type;
+ narrowPtr _method_type;
+ narrowPtr _member_method;
+ narrowPtr _instantiated_method_type;
- RunTimeLambdaProxyClassKey(u4 caller_ik,
- u4 invoked_name,
- u4 invoked_type,
- u4 method_type,
- u4 member_method,
- u4 instantiated_method_type) :
+ RunTimeLambdaProxyClassKey(narrowPtr caller_ik,
+ narrowPtr invoked_name,
+ narrowPtr invoked_type,
+ narrowPtr method_type,
+ narrowPtr member_method,
+ narrowPtr instantiated_method_type) :
_caller_ik(caller_ik),
_invoked_name(invoked_name),
_invoked_type(invoked_type),
@@ -154,15 +156,12 @@ class RunTimeLambdaProxyClassKey {
public:
static RunTimeLambdaProxyClassKey init_for_dumptime(LambdaProxyClassKey& key) {
- assert(ArchiveBuilder::is_active(), "sanity");
- ArchiveBuilder* b = ArchiveBuilder::current();
-
- u4 caller_ik = b->any_to_offset_u4(key.caller_ik());
- u4 invoked_name = b->any_to_offset_u4(key.invoked_name());
- u4 invoked_type = b->any_to_offset_u4(key.invoked_type());
- u4 method_type = b->any_to_offset_u4(key.method_type());
- u4 member_method = b->any_or_null_to_offset_u4(key.member_method()); // could be null
- u4 instantiated_method_type = b->any_to_offset_u4(key.instantiated_method_type());
+ narrowPtr caller_ik = AOTCompressedPointers::encode_not_null(key.caller_ik());
+ narrowPtr invoked_name = AOTCompressedPointers::encode_not_null(key.invoked_name());
+ narrowPtr invoked_type = AOTCompressedPointers::encode_not_null(key.invoked_type());
+ narrowPtr method_type = AOTCompressedPointers::encode_not_null(key.method_type());
+ narrowPtr member_method = AOTCompressedPointers::encode(key.member_method()); // could be null
+ narrowPtr instantiated_method_type = AOTCompressedPointers::encode_not_null(key.instantiated_method_type());
return RunTimeLambdaProxyClassKey(caller_ik, invoked_name, invoked_type, method_type,
member_method, instantiated_method_type);
@@ -176,12 +175,12 @@ public:
Symbol* instantiated_method_type) {
// All parameters must be in shared space, or else you'd get an assert in
// ArchiveUtils::to_offset().
- return RunTimeLambdaProxyClassKey(ArchiveUtils::archived_address_to_offset(caller_ik),
- ArchiveUtils::archived_address_to_offset(invoked_name),
- ArchiveUtils::archived_address_to_offset(invoked_type),
- ArchiveUtils::archived_address_to_offset(method_type),
- ArchiveUtils::archived_address_or_null_to_offset(member_method), // could be null
- ArchiveUtils::archived_address_to_offset(instantiated_method_type));
+ return RunTimeLambdaProxyClassKey(AOTCompressedPointers::encode_address_in_cache(caller_ik),
+ AOTCompressedPointers::encode_address_in_cache(invoked_name),
+ AOTCompressedPointers::encode_address_in_cache(invoked_type),
+ AOTCompressedPointers::encode_address_in_cache(method_type),
+ AOTCompressedPointers::encode_address_in_cache_or_null(member_method), // could be null
+ AOTCompressedPointers::encode_address_in_cache(instantiated_method_type));
}
unsigned int hash() const;
diff --git a/src/hotspot/share/cds/runTimeClassInfo.cpp b/src/hotspot/share/cds/runTimeClassInfo.cpp
index fe940ca6c18..a1f50ab4ffa 100644
--- a/src/hotspot/share/cds/runTimeClassInfo.cpp
+++ b/src/hotspot/share/cds/runTimeClassInfo.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2026, 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,15 +22,15 @@
*
*/
+#include "cds/aotCompressedPointers.hpp"
#include "cds/archiveBuilder.hpp"
#include "cds/dumpTimeClassInfo.hpp"
#include "cds/runTimeClassInfo.hpp"
#include "classfile/systemDictionaryShared.hpp"
void RunTimeClassInfo::init(DumpTimeClassInfo& info) {
- ArchiveBuilder* builder = ArchiveBuilder::current();
InstanceKlass* k = info._klass;
- _klass_offset = builder->any_to_offset_u4(k);
+ _klass = AOTCompressedPointers::encode_not_null(k);
if (!SystemDictionaryShared::is_builtin(k)) {
CrcInfo* c = crc();
@@ -50,8 +50,8 @@ void RunTimeClassInfo::init(DumpTimeClassInfo& info) {
RTVerifierConstraint* vf_constraints = verifier_constraints();
char* flags = verifier_constraint_flags();
for (i = 0; i < _num_verifier_constraints; i++) {
- vf_constraints[i]._name = builder->any_to_offset_u4(info._verifier_constraints->at(i).name());
- vf_constraints[i]._from_name = builder->any_or_null_to_offset_u4(info._verifier_constraints->at(i).from_name());
+ vf_constraints[i]._name = AOTCompressedPointers::encode_not_null(info._verifier_constraints->at(i).name());
+ vf_constraints[i]._from_name = AOTCompressedPointers::encode(info._verifier_constraints->at(i).from_name());
}
for (i = 0; i < _num_verifier_constraints; i++) {
flags[i] = info._verifier_constraint_flags->at(i);
@@ -61,14 +61,14 @@ void RunTimeClassInfo::init(DumpTimeClassInfo& info) {
if (_num_loader_constraints > 0) {
RTLoaderConstraint* ld_constraints = loader_constraints();
for (i = 0; i < _num_loader_constraints; i++) {
- ld_constraints[i]._name = builder->any_to_offset_u4(info._loader_constraints->at(i).name());
+ ld_constraints[i]._name = AOTCompressedPointers::encode_not_null(info._loader_constraints->at(i).name());
ld_constraints[i]._loader_type1 = info._loader_constraints->at(i).loader_type1();
ld_constraints[i]._loader_type2 = info._loader_constraints->at(i).loader_type2();
}
}
if (k->is_hidden() && info.nest_host() != nullptr) {
- _nest_host_offset = builder->any_to_offset_u4(info.nest_host());
+ _nest_host = AOTCompressedPointers::encode_not_null(info.nest_host());
}
if (k->has_archived_enum_objs()) {
int num = info.num_enum_klass_static_fields();
@@ -83,11 +83,12 @@ void RunTimeClassInfo::init(DumpTimeClassInfo& info) {
InstanceKlass* RunTimeClassInfo::klass() const {
if (AOTMetaspace::in_aot_cache(this)) {
// is inside a mmaped CDS archive.
- return ArchiveUtils::offset_to_archived_address(_klass_offset);
+ return AOTCompressedPointers::decode_not_null(_klass);
} else {
// is a temporary copy of a RunTimeClassInfo that's being initialized
// by the ArchiveBuilder.
- return ArchiveBuilder::current()->offset_to_buffered(_klass_offset);
+ size_t byte_offset = AOTCompressedPointers::get_byte_offset(_klass);
+ return ArchiveBuilder::current()->offset_to_buffered(byte_offset);
}
}
diff --git a/src/hotspot/share/cds/runTimeClassInfo.hpp b/src/hotspot/share/cds/runTimeClassInfo.hpp
index 371924f9065..d63a04698bb 100644
--- a/src/hotspot/share/cds/runTimeClassInfo.hpp
+++ b/src/hotspot/share/cds/runTimeClassInfo.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2026, 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
@@ -25,6 +25,7 @@
#ifndef SHARE_CDS_RUNTIMECLASSINFO_HPP
#define SHARE_CDS_RUNTIMECLASSINFO_HPP
+#include "cds/aotCompressedPointers.hpp"
#include "cds/aotMetaspace.hpp"
#include "cds/archiveBuilder.hpp"
#include "cds/archiveUtils.hpp"
@@ -41,8 +42,10 @@ class Method;
class Symbol;
class RunTimeClassInfo {
- public:
- enum : char {
+ using narrowPtr = AOTCompressedPointers::narrowPtr;
+
+public:
+ enum : char {
FROM_FIELD_IS_PROTECTED = 1 << 0,
FROM_IS_ARRAY = 1 << 1,
FROM_IS_OBJECT = 1 << 2
@@ -56,19 +59,19 @@ class RunTimeClassInfo {
// This is different than DumpTimeClassInfo::DTVerifierConstraint. We use
// u4 instead of Symbol* to save space on 64-bit CPU.
struct RTVerifierConstraint {
- u4 _name;
- u4 _from_name;
- Symbol* name() { return ArchiveUtils::offset_to_archived_address(_name); }
+ narrowPtr _name;
+ narrowPtr _from_name;
+ Symbol* name() { return AOTCompressedPointers::decode_not_null(_name); }
Symbol* from_name() {
- return (_from_name == 0) ? nullptr : ArchiveUtils::offset_to_archived_address(_from_name);
+ return AOTCompressedPointers::decode(_from_name);
}
};
struct RTLoaderConstraint {
- u4 _name;
+ narrowPtr _name;
char _loader_type1;
char _loader_type2;
- Symbol* constraint_name() { return ArchiveUtils::offset_to_archived_address(_name); }
+ Symbol* constraint_name() { return AOTCompressedPointers::decode_not_null(_name); }
};
struct RTEnumKlassStaticFields {
int _num;
@@ -76,8 +79,8 @@ class RunTimeClassInfo {
};
private:
- u4 _klass_offset;
- u4 _nest_host_offset;
+ narrowPtr _klass;
+ narrowPtr _nest_host;
int _num_verifier_constraints;
int _num_loader_constraints;
@@ -185,7 +188,7 @@ public:
InstanceKlass* nest_host() {
assert(!ArchiveBuilder::is_active(), "not called when dumping archive");
- return ArchiveUtils::offset_to_archived_address_or_null(_nest_host_offset);
+ return AOTCompressedPointers::decode(_nest_host); // may be null
}
RTLoaderConstraint* loader_constraints() {
diff --git a/src/hotspot/share/classfile/compactHashtable.hpp b/src/hotspot/share/classfile/compactHashtable.hpp
index 944fb876521..2fe92be0f6d 100644
--- a/src/hotspot/share/classfile/compactHashtable.hpp
+++ b/src/hotspot/share/classfile/compactHashtable.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2026, 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
@@ -25,6 +25,7 @@
#ifndef SHARE_CLASSFILE_COMPACTHASHTABLE_HPP
#define SHARE_CLASSFILE_COMPACTHASHTABLE_HPP
+#include "cds/aotCompressedPointers.hpp"
#include "cds/cds_globals.hpp"
#include "oops/array.hpp"
#include "oops/symbol.hpp"
@@ -123,6 +124,9 @@ public:
~CompactHashtableWriter();
void add(unsigned int hash, u4 encoded_value);
+ void add(unsigned int hash, AOTCompressedPointers::narrowPtr encoded_value) {
+ add(hash, cast_to_u4(encoded_value));
+ }
void dump(SimpleCompactHashtable *cht, const char* table_name);
private:
@@ -371,11 +375,11 @@ public:
//
// OffsetCompactHashtable -- This is used to store many types of objects
// in the CDS archive. On 64-bit platforms, we save space by using a 32-bit
-// offset from the CDS base address.
+// narrowPtr from the CDS base address.
template
-inline V read_value_from_compact_hashtable(address base_address, u4 offset) {
- return (V)(base_address + offset);
+inline V read_value_from_compact_hashtable(address base_address, u4 narrowp) {
+ return AOTCompressedPointers::decode_not_null(cast_from_u4(narrowp), base_address);
}
template <
diff --git a/src/hotspot/share/classfile/symbolTable.cpp b/src/hotspot/share/classfile/symbolTable.cpp
index c49aa10fa0d..20aa7f0776d 100644
--- a/src/hotspot/share/classfile/symbolTable.cpp
+++ b/src/hotspot/share/classfile/symbolTable.cpp
@@ -22,6 +22,7 @@
*
*/
+#include "cds/aotCompressedPointers.hpp"
#include "cds/archiveBuilder.hpp"
#include "cds/cdsConfig.hpp"
#include "cds/dynamicArchive.hpp"
@@ -690,7 +691,7 @@ void SymbolTable::copy_shared_symbol_table(GrowableArray* symbols,
assert(fixed_hash == hash_symbol((const char*)sym->bytes(), sym->utf8_length(), false),
"must not rehash during dumping");
sym->set_permanent();
- writer->add(fixed_hash, builder->buffer_to_offset_u4((address)sym));
+ writer->add(fixed_hash, AOTCompressedPointers::encode_not_null(sym));
}
}
diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp
index afc190c36cf..cfb20412ab8 100644
--- a/src/hotspot/share/classfile/systemDictionaryShared.cpp
+++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2026, 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
@@ -25,6 +25,7 @@
#include "cds/aotClassFilter.hpp"
#include "cds/aotClassLocation.hpp"
+#include "cds/aotCompressedPointers.hpp"
#include "cds/aotLogging.hpp"
#include "cds/aotMetaspace.hpp"
#include "cds/archiveBuilder.hpp"
@@ -1282,11 +1283,10 @@ unsigned int SystemDictionaryShared::hash_for_shared_dictionary(address ptr) {
class CopySharedClassInfoToArchive : StackObj {
CompactHashtableWriter* _writer;
bool _is_builtin;
- ArchiveBuilder *_builder;
public:
CopySharedClassInfoToArchive(CompactHashtableWriter* writer,
bool is_builtin)
- : _writer(writer), _is_builtin(is_builtin), _builder(ArchiveBuilder::current()) {}
+ : _writer(writer), _is_builtin(is_builtin) {}
void do_entry(InstanceKlass* k, DumpTimeClassInfo& info) {
if (!info.is_excluded() && info.is_builtin() == _is_builtin) {
@@ -1299,11 +1299,10 @@ public:
Symbol* name = info._klass->name();
name = ArchiveBuilder::current()->get_buffered_addr(name);
hash = SystemDictionaryShared::hash_for_shared_dictionary((address)name);
- u4 delta = _builder->buffer_to_offset_u4((address)record);
if (_is_builtin && info._klass->is_hidden()) {
// skip
} else {
- _writer->add(hash, delta);
+ _writer->add(hash, AOTCompressedPointers::encode_not_null(record));
}
if (log_is_enabled(Trace, aot, hashtables)) {
ResourceMark rm;
diff --git a/src/hotspot/share/include/cds.h b/src/hotspot/share/include/cds.h
index a7bc896172c..76de42db755 100644
--- a/src/hotspot/share/include/cds.h
+++ b/src/hotspot/share/include/cds.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -40,7 +40,7 @@
#define CDS_DYNAMIC_ARCHIVE_MAGIC 0xf00baba8
#define CDS_PREIMAGE_ARCHIVE_MAGIC 0xcafea07c
#define CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION 13
-#define CURRENT_CDS_ARCHIVE_VERSION 19
+#define CURRENT_CDS_ARCHIVE_VERSION 20
typedef struct CDSFileMapRegion {
int _crc; // CRC checksum of this region.
diff --git a/src/hotspot/share/oops/trainingData.cpp b/src/hotspot/share/oops/trainingData.cpp
index 1a16fd70e44..f52c22ad38a 100644
--- a/src/hotspot/share/oops/trainingData.cpp
+++ b/src/hotspot/share/oops/trainingData.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, 2026, 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,6 +22,7 @@
*
*/
+#include "cds/aotCompressedPointers.hpp"
#include "cds/cdsConfig.hpp"
#include "ci/ciEnv.hpp"
#include "ci/ciMetadata.hpp"
@@ -512,8 +513,7 @@ void TrainingData::dump_training_data() {
#endif // ASSERT
td = ArchiveBuilder::current()->get_buffered_addr(td);
uint hash = TrainingData::Key::cds_hash(td->key());
- u4 delta = ArchiveBuilder::current()->buffer_to_offset_u4((address)td);
- writer.add(hash, delta);
+ writer.add(hash, AOTCompressedPointers::encode_not_null(td));
}
writer.dump(&_archived_training_data_dictionary_for_dumping, "training data dictionary");
}
diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp
index d426fd31a43..ae3835dd344 100644
--- a/src/hotspot/share/runtime/sharedRuntime.cpp
+++ b/src/hotspot/share/runtime/sharedRuntime.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2026, 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,9 +22,11 @@
*
*/
+#include "cds/aotCompressedPointers.hpp"
#include "cds/archiveBuilder.hpp"
#include "cds/archiveUtils.inline.hpp"
#include "classfile/classLoader.hpp"
+#include "classfile/compactHashtable.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/stringTable.hpp"
#include "classfile/vmClasses.hpp"
@@ -2933,8 +2935,7 @@ public:
assert(buffered_entry != nullptr,"sanity check");
uint hash = fp->compute_hash();
- u4 delta = _builder->buffer_to_offset_u4((address)buffered_entry);
- _writer->add(hash, delta);
+ _writer->add(hash, AOTCompressedPointers::encode_not_null(buffered_entry));
if (lsh.is_enabled()) {
address fp_runtime_addr = (address)buffered_fp + ArchiveBuilder::current()->buffer_to_requested_delta();
address entry_runtime_addr = (address)buffered_entry + ArchiveBuilder::current()->buffer_to_requested_delta();
diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp
index 11bd39c839f..a026a4b7d69 100644
--- a/src/hotspot/share/runtime/sharedRuntime.hpp
+++ b/src/hotspot/share/runtime/sharedRuntime.hpp
@@ -25,7 +25,6 @@
#ifndef SHARE_RUNTIME_SHAREDRUNTIME_HPP
#define SHARE_RUNTIME_SHAREDRUNTIME_HPP
-#include "classfile/compactHashtable.hpp"
#include "code/codeBlob.hpp"
#include "code/vmreg.hpp"
#include "interpreter/linkResolver.hpp"
@@ -38,6 +37,7 @@
class AdapterHandlerEntry;
class AdapterFingerPrint;
class MetaspaceClosure;
+class SerializeClosure;
class vframeStream;
// Runtime is the base class for various runtime interfaces
diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp
index f65a3441bf4..1bbef8537ff 100644
--- a/src/hotspot/share/runtime/vmStructs.cpp
+++ b/src/hotspot/share/runtime/vmStructs.cpp
@@ -22,6 +22,7 @@
*
*/
+#include "cds/aotCompressedPointers.hpp"
#include "cds/filemap.hpp"
#include "classfile/classLoaderDataGraph.hpp"
#include "classfile/javaClasses.hpp"
@@ -762,7 +763,7 @@
CDS_ONLY(nonstatic_field(FileMapInfo, _header, FileMapHeader*)) \
CDS_ONLY( static_field(FileMapInfo, _current_info, FileMapInfo*)) \
CDS_ONLY(nonstatic_field(FileMapHeader, _regions[0], CDSFileMapRegion)) \
- CDS_ONLY(nonstatic_field(FileMapHeader, _cloned_vtables_offset, size_t)) \
+ CDS_ONLY(nonstatic_field(FileMapHeader, _cloned_vtables, AOTCompressedPointers::narrowPtr)) \
CDS_ONLY(nonstatic_field(FileMapHeader, _mapped_base_address, char*)) \
CDS_ONLY(nonstatic_field(CDSFileMapRegion, _mapped_base, char*)) \
CDS_ONLY(nonstatic_field(CDSFileMapRegion, _used, size_t)) \
@@ -1203,6 +1204,7 @@
\
/* all enum types */ \
\
+ declare_integer_type(AOTCompressedPointers::narrowPtr) \
declare_integer_type(Bytecodes::Code) \
declare_integer_type(InstanceKlass::ClassState) \
declare_integer_type(JavaThreadState) \
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FileMapInfo.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FileMapInfo.java
index 94200e31b7e..14d8af58e4d 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FileMapInfo.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FileMapInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -97,10 +97,12 @@ public class FileMapInfo {
headerObj = VMObjectFactory.newObject(FileMapHeader.class, header);
// char* mapped_base_address = header->_mapped_base_address
- // size_t cloned_vtable_offset = header->_cloned_vtable_offset
+ // narrowPtr cloned_vtable_narrowPtr = header->_cloned_vtable_offset
+ // size_t cloned_vtable_offset = AOTCompressedPointers::get_byte_offset(cloned_vtable_narrowPtr);
// CppVtableInfo** vtablesIndex = mapped_base_address + cloned_vtable_offset;
mapped_base_address = get_AddressField(FileMapHeader_type, header, "_mapped_base_address");
- long cloned_vtable_offset = get_CIntegerField(FileMapHeader_type, header, "_cloned_vtables_offset");
+ long cloned_vtable_narrowPtr = get_CIntegerField(FileMapHeader_type, header, "_cloned_vtables");
+ long cloned_vtable_offset = cloned_vtable_narrowPtr; // Currently narrowPtr is the same as offset
vtablesIndex = mapped_base_address.addOffsetTo(cloned_vtable_offset);
// CDSFileMapRegion* rw_region = &header->_region[rw];
From 961d32842d7841701a33659493a84b4d2c4d2f82 Mon Sep 17 00:00:00 2001
From: Jesper Wilhelmsson
Date: Wed, 11 Feb 2026 23:31:23 +0000
Subject: [PATCH 25/77] 8377509: Add licenses for gcc 14.2.0
Reviewed-by: dholmes
---
src/java.base/share/legal/gcc.md | 2084 ++++++++++++++++++++++++++++++
1 file changed, 2084 insertions(+)
create mode 100644 src/java.base/share/legal/gcc.md
diff --git a/src/java.base/share/legal/gcc.md b/src/java.base/share/legal/gcc.md
new file mode 100644
index 00000000000..b78ca12caa9
--- /dev/null
+++ b/src/java.base/share/legal/gcc.md
@@ -0,0 +1,2084 @@
+## GCC - libgcc and libstdc++ 14.2.0
+
+### GNU GENERAL PUBLIC LICENSE v3
+
+```
+ Version 3, 29 June 2007
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+ Preamble
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+ The precise terms and conditions for copying, distribution and
+modification follow.
+ TERMS AND CONDITIONS
+ 0. Definitions.
+ "This License" refers to version 3 of the GNU General Public License.
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+ 1. Source Code.
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+ The Corresponding Source for a work in source code form is that
+same work.
+ 2. Basic Permissions.
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+ 4. Conveying Verbatim Copies.
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+ 5. Conveying Modified Source Versions.
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+ 6. Conveying Non-Source Forms.
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+ 7. Additional Terms.
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+ 8. Termination.
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+ 9. Acceptance Not Required for Having Copies.
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+ 10. Automatic Licensing of Downstream Recipients.
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+ 11. Patents.
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+ 12. No Surrender of Others' Freedom.
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+ 13. Use with the GNU Affero General Public License.
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+ 14. Revised Versions of this License.
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+ 15. Disclaimer of Warranty.
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+ 16. Limitation of Liability.
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+ 17. Interpretation of Sections 15 and 16.
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+ END OF TERMS AND CONDITIONS
+ How to Apply These Terms to Your New Programs
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ Copyright (C)
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+ This program 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 for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+Also add information on how to contact you by electronic and paper mail.
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
+```
+
+### GCC RUNTIME LIBRARY EXCEPTION v3.1
+
+```
+Version 3.1, 31 March 2009
+Copyright (C) 2009 Free Software Foundation, Inc.
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+This GCC Runtime Library Exception ("Exception") is an additional
+permission under section 7 of the GNU General Public License, version
+3 ("GPLv3"). It applies to a given file (the "Runtime Library") that
+bears a notice placed by the copyright holder of the file stating that
+the file is governed by GPLv3 along with this Exception.
+When you use GCC to compile a program, GCC may combine portions of
+certain GCC header files and runtime libraries with the compiled
+program. The purpose of this Exception is to allow compilation of
+non-GPL (including proprietary) programs to use, in this way, the
+header files and runtime libraries covered by this Exception.
+0. Definitions.
+A file is an "Independent Module" if it either requires the Runtime
+Library for execution after a Compilation Process, or makes use of an
+interface provided by the Runtime Library, but is not otherwise based
+on the Runtime Library.
+"GCC" means a version of the GNU Compiler Collection, with or without
+modifications, governed by version 3 (or a specified later version) of
+the GNU General Public License (GPL) with the option of using any
+subsequent versions published by the FSF.
+"GPL-compatible Software" is software whose conditions of propagation,
+modification and use would permit combination with GCC in accord with
+the license of GCC.
+"Target Code" refers to output from any compiler for a real or virtual
+target processor architecture, in executable form or suitable for
+input to an assembler, loader, linker and/or execution
+phase. Notwithstanding that, Target Code does not include data in any
+format that is used as a compiler intermediate representation, or used
+for producing a compiler intermediate representation.
+The "Compilation Process" transforms code entirely represented in
+non-intermediate languages designed for human-written code, and/or in
+Java Virtual Machine byte code, into Target Code. Thus, for example,
+use of source code generators and preprocessors need not be considered
+part of the Compilation Process, since the Compilation Process can be
+understood as starting with the output of the generators or
+preprocessors.
+A Compilation Process is "Eligible" if it is done using GCC, alone or
+with other GPL-compatible software, or if it is done without using any
+work based on GCC. For example, using non-GPL-compatible Software to
+optimize any GCC intermediate representations would not qualify as an
+Eligible Compilation Process.
+1. Grant of Additional Permission.
+You have permission to propagate a work of Target Code formed by
+combining the Runtime Library with Independent Modules, even if such
+propagation would otherwise violate the terms of GPLv3, provided that
+all Target Code was generated by Eligible Compilation Processes. You
+may then convey such a combination under terms of your choice,
+consistent with the licensing of the Independent Modules.
+2. No Weakening of GCC Copyleft.
+The availability of this Exception does not imply any general
+presumption that third-party software is unaffected by the copyleft
+requirements of the license of GCC.
+```
+
+### GNU GENERAL PUBLIC LICENSE v2
+
+```
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+ Preamble
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+ NO WARRANTY
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ Copyright (C)
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+ This program 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 for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+Also add information on how to contact you by electronic and paper mail.
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+ , 1 April 1989
+ Ty Coon, President of Vice
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+```
+
+### GNU LESSER GENERAL PUBLIC LICENSE v3
+
+```
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+ 0. Additional Definitions.
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+ 1. Exception to Section 3 of the GNU GPL.
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+ 2. Conveying Modified Versions.
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+ 3. Object Code Incorporating Material from Library Header Files.
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+ 4. Combined Works.
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+ d) Do one of the following:
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+ 5. Combined Libraries.
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+ 6. Revised Versions of the GNU Lesser General Public License.
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
+```
+
+### GNU LESSER GENERAL PUBLIC LICENSE v2.1
+
+```
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+ Preamble
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations
+below.
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it
+becomes a de-facto standard. To achieve this, non-free programs must
+be allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control
+compilation and installation of the library.
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+ a) The modified work must itself be a software library.
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+ c) Accompany the work with a written offer, valid for at least
+ three years, to give the same user the materials specified in
+ Subsection 6a, above, for a charge no more than the cost of
+ performing this distribution.
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply, and the section as a whole is intended to apply in other
+circumstances.
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License
+may add an explicit geographical distribution limitation excluding those
+countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+ NO WARRANTY
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms
+of the ordinary General Public License).
+ To apply these terms, attach the following notices to the library.
+It is safest to attach them to the start of each source file to most
+effectively convey the exclusion of warranty; and each file should
+have at least the "copyright" line and a pointer to where the full
+notice is found.
+
+ Copyright (C)
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ This library 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
+ Lesser General Public License for more details.
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+Also add information on how to contact you by electronic and paper mail.
+You should also get your employer (if you work as a programmer) or
+your school, if any, to sign a "copyright disclaimer" for the library,
+if necessary. Here is a sample; alter the names:
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James
+ Random Hacker.
+ , 1 April 1990
+ Ty Coon, President of Vice
+That's all there is to it!
+```
+
+### GNU Free Documentation License v1.3
+
+```
+ GNU Free Documentation License
+ Version 1.3, 3 November 2008
+ Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
+
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+0. PREAMBLE
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document "free" in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+This License is a kind of "copyleft", which means that derivative
+works of the document must themselves be free in the same sense. It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does. But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book. We recommend this License
+principally for works whose purpose is instruction or reference.
+1. APPLICABILITY AND DEFINITIONS
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License. Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein. The "Document", below,
+refers to any such manual or work. Any member of the public is a
+licensee, and is addressed as "you". You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+A "Modified Version" of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+A "Secondary Section" is a named appendix or a front-matter section of
+the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall
+subject (or to related matters) and contains nothing that could fall
+directly within that overall subject. (Thus, if the Document is in
+part a textbook of mathematics, a Secondary Section may not explain
+any mathematics.) The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+The "Invariant Sections" are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License. If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant. The Document may contain zero
+Invariant Sections. If the Document does not identify any Invariant
+Sections then there are none.
+The "Cover Texts" are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License. A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+A "Transparent" copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters. A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text. A copy that is not "Transparent" is called "Opaque".
+Examples of suitable formats for Transparent copies include plain
+ASCII without markup, Texinfo input format, LaTeX input format, SGML
+or XML using a publicly available DTD, and standard-conforming simple
+HTML, PostScript or PDF designed for human modification. Examples of
+transparent image formats include PNG, XCF and JPG. Opaque formats
+include proprietary formats that can be read and edited only by
+proprietary word processors, SGML or XML for which the DTD and/or
+processing tools are not generally available, and the
+machine-generated HTML, PostScript or PDF produced by some word
+processors for output purposes only.
+The "Title Page" means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page. For works in
+formats which do not have any title page as such, "Title Page" means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+The "publisher" means any person or entity that distributes copies of
+the Document to the public.
+A section "Entitled XYZ" means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language. (Here XYZ stands for a
+specific section name mentioned below, such as "Acknowledgements",
+"Dedications", "Endorsements", or "History".) To "Preserve the Title"
+of such a section when you modify the Document means that it remains a
+section "Entitled XYZ" according to this definition.
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document. These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+2. VERBATIM COPYING
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no
+other conditions whatsoever to those of this License. You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute. However, you may accept
+compensation in exchange for copies. If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+3. COPYING IN QUANTITY
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover. Both covers must also clearly and legibly identify
+you as the publisher of these copies. The front cover must present
+the full title with all words of the title equally prominent and
+visible. You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to
+give them a chance to provide you with an updated version of the
+Document.
+4. MODIFICATIONS
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it. In addition, you must do these things in the Modified Version:
+A. Use in the Title Page (and on the covers, if any) a title distinct
+ from that of the Document, and from those of previous versions
+ (which should, if there were any, be listed in the History section
+ of the Document). You may use the same title as a previous version
+ if the original publisher of that version gives permission.
+B. List on the Title Page, as authors, one or more persons or entities
+ responsible for authorship of the modifications in the Modified
+ Version, together with at least five of the principal authors of the
+ Document (all of its principal authors, if it has fewer than five),
+ unless they release you from this requirement.
+C. State on the Title page the name of the publisher of the
+ Modified Version, as the publisher.
+D. Preserve all the copyright notices of the Document.
+E. Add an appropriate copyright notice for your modifications
+ adjacent to the other copyright notices.
+F. Include, immediately after the copyright notices, a license notice
+ giving the public permission to use the Modified Version under the
+ terms of this License, in the form shown in the Addendum below.
+G. Preserve in that license notice the full lists of Invariant Sections
+ and required Cover Texts given in the Document's license notice.
+H. Include an unaltered copy of this License.
+I. Preserve the section Entitled "History", Preserve its Title, and add
+ to it an item stating at least the title, year, new authors, and
+ publisher of the Modified Version as given on the Title Page. If
+ there is no section Entitled "History" in the Document, create one
+ stating the title, year, authors, and publisher of the Document as
+ given on its Title Page, then add an item describing the Modified
+ Version as stated in the previous sentence.
+J. Preserve the network location, if any, given in the Document for
+ public access to a Transparent copy of the Document, and likewise
+ the network locations given in the Document for previous versions
+ it was based on. These may be placed in the "History" section.
+ You may omit a network location for a work that was published at
+ least four years before the Document itself, or if the original
+ publisher of the version it refers to gives permission.
+K. For any section Entitled "Acknowledgements" or "Dedications",
+ Preserve the Title of the section, and preserve in the section all
+ the substance and tone of each of the contributor acknowledgements
+ and/or dedications given therein.
+L. Preserve all the Invariant Sections of the Document,
+ unaltered in their text and in their titles. Section numbers
+ or the equivalent are not considered part of the section titles.
+M. Delete any section Entitled "Endorsements". Such a section
+ may not be included in the Modified Version.
+N. Do not retitle any existing section to be Entitled "Endorsements"
+ or to conflict in title with any Invariant Section.
+O. Preserve any Warranty Disclaimers.
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant. To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+You may add a section Entitled "Endorsements", provided it contains
+nothing but endorsements of your Modified Version by various
+parties--for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version. Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity. If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+5. COMBINING DOCUMENTS
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy. If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+In the combination, you must combine any sections Entitled "History"
+in the various original documents, forming one section Entitled
+"History"; likewise combine any sections Entitled "Acknowledgements",
+and any sections Entitled "Dedications". You must delete all sections
+Entitled "Endorsements".
+6. COLLECTIONS OF DOCUMENTS
+You may make a collection consisting of the Document and other
+documents released under this License, and replace the individual
+copies of this License in the various documents with a single copy
+that is included in the collection, provided that you follow the rules
+of this License for verbatim copying of each of the documents in all
+other respects.
+You may extract a single document from such a collection, and
+distribute it individually under this License, provided you insert a
+copy of this License into the extracted document, and follow this
+License in all other respects regarding verbatim copying of that
+document.
+7. AGGREGATION WITH INDEPENDENT WORKS
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an "aggregate" if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+8. TRANSLATION
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections. You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers. In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+If a section in the Document is Entitled "Acknowledgements",
+"Dedications", or "History", the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+9. TERMINATION
+You may not copy, modify, sublicense, or distribute the Document
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense, or distribute it is void, and
+will automatically terminate your rights under this License.
+However, if you cease all violation of this License, then your license
+from a particular copyright holder is reinstated (a) provisionally,
+unless and until the copyright holder explicitly and finally
+terminates your license, and (b) permanently, if the copyright holder
+fails to notify you of the violation by some reasonable means prior to
+60 days after the cessation.
+Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, receipt of a copy of some or all of the same material does
+not give you any rights to use it.
+10. FUTURE REVISIONS OF THIS LICENSE
+The Free Software Foundation may publish new, revised versions of the
+GNU Free Documentation License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in
+detail to address new problems or concerns. See
+http://www.gnu.org/copyleft/.
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation. If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation. If the Document
+specifies that a proxy can decide which future versions of this
+License can be used, that proxy's public statement of acceptance of a
+version permanently authorizes you to choose that version for the
+Document.
+11. RELICENSING
+"Massive Multiauthor Collaboration Site" (or "MMC Site") means any
+World Wide Web server that publishes copyrightable works and also
+provides prominent facilities for anybody to edit those works. A
+public wiki that anybody can edit is an example of such a server. A
+"Massive Multiauthor Collaboration" (or "MMC") contained in the site
+means any set of copyrightable works thus published on the MMC site.
+"CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0
+license published by Creative Commons Corporation, a not-for-profit
+corporation with a principal place of business in San Francisco,
+California, as well as future copyleft versions of that license
+published by that same organization.
+"Incorporate" means to publish or republish a Document, in whole or in
+part, as part of another Document.
+An MMC is "eligible for relicensing" if it is licensed under this
+License, and if all works that were first published under this License
+somewhere other than this MMC, and subsequently incorporated in whole or
+in part into the MMC, (1) had no cover texts or invariant sections, and
+(2) were thus incorporated prior to November 1, 2008.
+The operator of an MMC Site may republish an MMC contained in the site
+under CC-BY-SA on the same site at any time before August 1, 2009,
+provided the MMC is eligible for relicensing.
+ADDENDUM: How to use this License for your documents
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+ Copyright (c) YEAR YOUR NAME.
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.3
+ or any later version published by the Free Software Foundation;
+ with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+ A copy of the license is included in the section entitled "GNU
+ Free Documentation License".
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the "with...Texts." line with this:
+ with the Invariant Sections being LIST THEIR TITLES, with the
+ Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
+```
+
+### The Regents of the University of California
+
+```
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. [rescinded 22 July 1999]
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+```
+
+### The Go Authors
+
+```
+Copyright (c) 2009 The Go Authors. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+```
+
+### Apache License v2.0
+
+```
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+ 1. Definitions.
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+ END OF TERMS AND CONDITIONS
+ APPENDIX: How to apply the Apache License to your work.
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+ Copyright [yyyy] [name of copyright owner]
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+```
+
From 370929f8268a859071d111f44ad1cb6fbceb31d7 Mon Sep 17 00:00:00 2001
From: Chen Liang
Date: Wed, 11 Feb 2026 23:44:43 +0000
Subject: [PATCH 26/77] 8377601: JavacTemplateTestBase not reporting javac
crashes
Reviewed-by: vromero
---
.../tools/javac/combo/JavacTemplateTestBase.java | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/test/langtools/lib/combo/tools/javac/combo/JavacTemplateTestBase.java b/test/langtools/lib/combo/tools/javac/combo/JavacTemplateTestBase.java
index dd3f5639c21..ed5936210a8 100644
--- a/test/langtools/lib/combo/tools/javac/combo/JavacTemplateTestBase.java
+++ b/test/langtools/lib/combo/tools/javac/combo/JavacTemplateTestBase.java
@@ -237,19 +237,17 @@ public abstract class JavacTemplateTestBase {
if (classpaths.size() > 0)
fm.setLocation(StandardLocation.CLASS_PATH, classpaths);
JavacTask ct = (JavacTask) systemJavaCompiler.getTask(null, fm, diags, compileOptions, null, files);
+ File destDir;
if (generate) {
- File destDir = new File(root, Integer.toString(counter.incrementAndGet()));
+ destDir = new File(root, Integer.toString(counter.incrementAndGet()));
// @@@ Assert that this directory didn't exist, or start counter at max+1
destDir.mkdirs();
fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(destDir));
- ct.generate();
- return destDir;
- }
- else {
- ct.call();
- // Failed result will show up in diags
- return nullDir;
+ } else {
+ destDir = nullDir;
}
+ ct.generate(); // throws ISE if javac crashes
+ return destDir;
}
}
From 24f67917c28a71fec1e4641b5b5ac0ff6a75d5a2 Mon Sep 17 00:00:00 2001
From: Yasumasa Suenaga
Date: Thu, 12 Feb 2026 01:58:22 +0000
Subject: [PATCH 27/77] 8374577: Heap dump from core does not contain
HPROF_GC_ROOT_JAVA_FRAME
Reviewed-by: cjplummer, amenkov, kevinw, aturbanov
---
.../hotspot/interpreter/OopMapCacheEntry.java | 4 +-
.../sun/jvm/hotspot/oops/ConstantPool.java | 9 ++--
.../hotspot/runtime/InterpretedVFrame.java | 46 +++++++++----------
.../hotspot/utilities/HeapHprofBinWriter.java | 29 +++++++++++-
.../serviceability/sa/ClhsdbDumpheap.java | 18 +++++++-
5 files changed, 75 insertions(+), 31 deletions(-)
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/OopMapCacheEntry.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/OopMapCacheEntry.java
index 75d9589a74f..fda97b4f337 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/OopMapCacheEntry.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/OopMapCacheEntry.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2026, 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
@@ -96,7 +96,7 @@ public class OopMapCacheEntry {
Method method() { return method; }
int bci() { return bci; }
- int numberOfEntries() { return maskSize; }
+ public int numberOfEntries() { return maskSize; }
boolean entryAt(int offset) {
return mask.at(offset);
}
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java
index 3a4ea5546a1..9d19a1d7df1 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2026, 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
@@ -253,13 +253,16 @@ public class ConstantPool extends Metadata implements ClassConstants {
return res;
}
+ private int invokedynamicBootstrapRefIndexAt(int indyIndex) {
+ return getCache().getIndyEntryAt(indyIndex).getConstantPoolIndex();
+ }
+
// Translate index, which could be CPCache index or Indy index, to a constant pool index
public int to_cp_index(int index, int code) {
Assert.that(getCache() != null, "'index' is a rewritten index so this class must have been rewritten");
switch(code) {
case Bytecodes._invokedynamic:
- int poolIndex = getCache().getIndyEntryAt(index).getConstantPoolIndex();
- return invokeDynamicNameAndTypeRefIndexAt(poolIndex);
+ return invokedynamicBootstrapRefIndexAt(index);
case Bytecodes._getfield:
case Bytecodes._getstatic:
case Bytecodes._putfield:
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/InterpretedVFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/InterpretedVFrame.java
index 75750548ef5..ae9c048f9d7 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/InterpretedVFrame.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/InterpretedVFrame.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2026, 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
@@ -37,21 +37,18 @@ public class InterpretedVFrame extends JavaVFrame {
}
public StackValueCollection getLocals() {
- Method m = getMethod();
-
- int length = (int) m.getMaxLocals();
-
- if (m.isNative()) {
- // If the method is native, getMaxLocals is not telling the truth.
- // maxlocals then equals the size of parameters
- length = (int) m.getSizeOfParameters();
- }
-
- StackValueCollection result = new StackValueCollection(length);
-
// Get oopmap describing oops and int for current bci
OopMapCacheEntry oopMask = getMethod().getMaskFor(getBCI());
+ // If the method is native, method()->max_locals() is not telling the truth.
+ // For our purposes, max locals instead equals the size of parameters.
+ Method method = getMethod();
+ int maxLocals = method.isNative() ? (int)method.getSizeOfParameters() : (int)method.getMaxLocals();
+
+ int length = maxLocals;
+
+ StackValueCollection result = new StackValueCollection(length);
+
// handle locals
for(int i = 0; i < length; i++) {
// Find stack location
@@ -74,26 +71,27 @@ public class InterpretedVFrame extends JavaVFrame {
}
public StackValueCollection getExpressions() {
- int length = getFrame().getInterpreterFrameExpressionStackSize();
-
- if (getMethod().isNative()) {
- // If the method is native, there is no expression stack
- length = 0;
- }
-
- int nofLocals = (int) getMethod().getMaxLocals();
- StackValueCollection result = new StackValueCollection(length);
-
// Get oopmap describing oops and int for current bci
OopMapCacheEntry oopMask = getMethod().getMaskFor(getBCI());
+ int maskLen = oopMask.numberOfEntries();
+
+ // If the method is native, method()->max_locals() is not telling the truth.
+ // For our purposes, max locals instead equals the size of parameters.
+ Method method = getMethod();
+ int maxLocals = method.isNative() ? (int)method.getSizeOfParameters() : (int)method.getMaxLocals();
+
+ int length = maskLen - maxLocals;
+
+ StackValueCollection result = new StackValueCollection(length);
+
for(int i = 0; i < length; i++) {
// Find stack location
Address addr = addressOfExpressionStackAt(i);
// Depending on oop/int put it in the right package
StackValue sv;
- if (oopMask.isOop(i + nofLocals)) {
+ if (oopMask.isOop(i + maxLocals)) {
// oop value
sv = new StackValue(addr.getOopHandleAt(0), 0);
} else {
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java
index 72861d9c30d..ce048bf2d86 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2026, 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
@@ -888,6 +888,16 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
out.writeInt(index);
out.writeInt(DUMMY_STACK_TRACE_ID);
writeLocalJNIHandles(jt, index);
+
+ int depth = 0;
+ var jvf = jt.getLastJavaVFrameDbg();
+ while (jvf != null) {
+ writeStackRefs(index, depth, jvf.getLocals());
+ writeStackRefs(index, depth, jvf.getExpressions());
+
+ depth++;
+ jvf = jvf.javaSender();
+ }
}
protected void writeLocalJNIHandles(JavaThread jt, int index) throws IOException {
@@ -926,6 +936,23 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
}
}
+ protected void writeStackRefs(int threadIndex, int frameIndex, StackValueCollection values) throws IOException {
+ for (int index = 0; index < values.size(); index++) {
+ if (values.get(index).getType() == BasicType.getTObject()) {
+ OopHandle oopHandle = values.oopHandleAt(index);
+ Oop oop = objectHeap.newOop(oopHandle);
+ if (oop != null) {
+ int size = BYTE_SIZE + OBJ_ID_SIZE + INT_SIZE * 2;
+ writeHeapRecordPrologue(size);
+ out.writeByte((byte) HPROF_GC_ROOT_JAVA_FRAME);
+ writeObjectID(oop);
+ out.writeInt(threadIndex);
+ out.writeInt(frameIndex);
+ }
+ }
+ }
+ }
+
protected void writeGlobalJNIHandle(Address handleAddr) throws IOException {
OopHandle oopHandle = handleAddr.getOopHandleAt(0);
Oop oop = objectHeap.newOop(oopHandle);
diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbDumpheap.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbDumpheap.java
index ee9872867ac..722c641f5b9 100644
--- a/test/hotspot/jtreg/serviceability/sa/ClhsdbDumpheap.java
+++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbDumpheap.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2026, 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,11 +27,14 @@ import java.util.Map;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.io.IOException;
import static jdk.test.lib.Asserts.assertTrue;
import static jdk.test.lib.Asserts.assertFalse;
+import static jdk.test.lib.Asserts.fail;
import jdk.test.lib.hprof.HprofParser;
import jdk.test.lib.apps.LingeredApp;
+import jdk.test.lib.hprof.model.Root;
import jdk.test.lib.hprof.parser.HprofReader;
import jtreg.SkippedException;
@@ -66,9 +69,22 @@ public class ClhsdbDumpheap {
}
}
+ private static void verifyLocalRefs(String file) throws IOException {
+ try (var snapshot = HprofReader.readFile(file, false, 0)) {
+ for (var root = snapshot.getRoots(); root.hasMoreElements();) {
+ if (root.nextElement().getType() == Root.JAVA_LOCAL) {
+ // expected
+ return;
+ }
+ }
+ }
+ fail("HPROF_GC_ROOT_JAVA_FRAME not found");
+ }
+
private static void verifyDumpFile(File dump) throws Exception {
assertTrue(dump.exists() && dump.isFile(), "Could not create dump file " + dump.getAbsolutePath());
printStackTraces(dump.getAbsolutePath());
+ verifyLocalRefs(dump.getAbsolutePath());
}
private static class SubTest {
From 5868d351e28a30a3178e1d3cf09404c6245c2082 Mon Sep 17 00:00:00 2001
From: Amit Kumar
Date: Thu, 12 Feb 2026 03:43:12 +0000
Subject: [PATCH 28/77] 8377651: [s390x] build failure without c1 & c2 compiler
Reviewed-by: aph, mdoerr
---
.../s390/gc/g1/g1BarrierSetAssembler_s390.cpp | 104 +++++++++---------
1 file changed, 52 insertions(+), 52 deletions(-)
diff --git a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp
index 272136fc28c..617bc7cd00c 100644
--- a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp
+++ b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2024 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -129,6 +129,57 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas
}
}
+static void generate_post_barrier(MacroAssembler* masm,
+ const Register store_addr,
+ const Register new_val,
+ const Register thread,
+ const Register tmp1,
+ const Register tmp2,
+ Label& done,
+ bool new_val_may_be_null) {
+
+ __ block_comment("generate_post_barrier {");
+
+ assert(thread == Z_thread, "must be");
+ assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, noreg);
+
+ // Does store cross heap regions?
+ if (VM_Version::has_DistinctOpnds()) {
+ __ z_xgrk(tmp1, store_addr, new_val); // tmp1 := store address ^ new value
+ } else {
+ __ z_lgr(tmp1, store_addr);
+ __ z_xgr(tmp1, new_val);
+ }
+ __ z_srag(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes)
+ __ branch_optimized(Assembler::bcondEqual, done);
+
+ // Crosses regions, storing null?
+ if (new_val_may_be_null) {
+ __ z_ltgr(new_val, new_val);
+ __ z_bre(done);
+ } else {
+#ifdef ASSERT
+ __ z_ltgr(new_val, new_val);
+ __ asm_assert(Assembler::bcondNotZero, "null oop not allowed (G1 post)", 0x322); // Checked by caller.
+#endif
+ }
+
+ __ z_srag(tmp1, store_addr, CardTable::card_shift());
+
+ Address card_table_addr(thread, in_bytes(G1ThreadLocalData::card_table_base_offset()));
+ __ z_alg(tmp1, card_table_addr); // tmp1 := card address
+
+ if(UseCondCardMark) {
+ __ z_cli(0, tmp1, G1CardTable::clean_card_val());
+ __ branch_optimized(Assembler::bcondNotEqual, done);
+ }
+
+ static_assert(G1CardTable::dirty_card_val() == 0, "must be to use z_mvi");
+ __ z_mvi(0, tmp1, G1CardTable::dirty_card_val()); // *(card address) := dirty_card_val
+
+ __ block_comment("} generate_post_barrier");
+}
+
#if defined(COMPILER2)
#undef __
@@ -204,57 +255,6 @@ void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm,
BLOCK_COMMENT("} generate_c2_pre_barrier_stub");
}
-static void generate_post_barrier(MacroAssembler* masm,
- const Register store_addr,
- const Register new_val,
- const Register thread,
- const Register tmp1,
- const Register tmp2,
- Label& done,
- bool new_val_may_be_null) {
-
- __ block_comment("generate_post_barrier {");
-
- assert(thread == Z_thread, "must be");
- assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, noreg);
-
- // Does store cross heap regions?
- if (VM_Version::has_DistinctOpnds()) {
- __ z_xgrk(tmp1, store_addr, new_val); // tmp1 := store address ^ new value
- } else {
- __ z_lgr(tmp1, store_addr);
- __ z_xgr(tmp1, new_val);
- }
- __ z_srag(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes)
- __ branch_optimized(Assembler::bcondEqual, done);
-
- // Crosses regions, storing null?
- if (new_val_may_be_null) {
- __ z_ltgr(new_val, new_val);
- __ z_bre(done);
- } else {
-#ifdef ASSERT
- __ z_ltgr(new_val, new_val);
- __ asm_assert(Assembler::bcondNotZero, "null oop not allowed (G1 post)", 0x322); // Checked by caller.
-#endif
- }
-
- __ z_srag(tmp1, store_addr, CardTable::card_shift());
-
- Address card_table_addr(thread, in_bytes(G1ThreadLocalData::card_table_base_offset()));
- __ z_alg(tmp1, card_table_addr); // tmp1 := card address
-
- if(UseCondCardMark) {
- __ z_cli(0, tmp1, G1CardTable::clean_card_val());
- __ branch_optimized(Assembler::bcondNotEqual, done);
- }
-
- static_assert(G1CardTable::dirty_card_val() == 0, "must be to use z_mvi");
- __ z_mvi(0, tmp1, G1CardTable::dirty_card_val()); // *(card address) := dirty_card_val
-
- __ block_comment("} generate_post_barrier");
-}
-
void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm,
Register store_addr,
Register new_val,
From 6abb29cc07e033e9a747b5a8a62e831c8f629c14 Mon Sep 17 00:00:00 2001
From: Jatin Bhateja
Date: Thu, 12 Feb 2026 06:52:08 +0000
Subject: [PATCH 29/77] 8376794: Enable copy and mismatch Partial Inlining for
AMD AVX512 targets
Reviewed-by: sviswanathan, thartmann
---
src/hotspot/cpu/x86/vm_version_x86.cpp | 63 +++++++++----------
.../vector/ArrayMismatchBenchmark.java | 43 +++++++++++++
2 files changed, 74 insertions(+), 32 deletions(-)
diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp
index c65c1c7d219..ef62a29c834 100644
--- a/src/hotspot/cpu/x86/vm_version_x86.cpp
+++ b/src/hotspot/cpu/x86/vm_version_x86.cpp
@@ -1659,41 +1659,40 @@ void VM_Version::get_processor_features() {
if (FLAG_IS_DEFAULT(AllocatePrefetchInstr) && supports_3dnow_prefetch()) {
FLAG_SET_DEFAULT(AllocatePrefetchInstr, 3);
}
-#ifdef COMPILER2
- if (UseAVX > 2) {
- if (FLAG_IS_DEFAULT(ArrayOperationPartialInlineSize) ||
- (!FLAG_IS_DEFAULT(ArrayOperationPartialInlineSize) &&
- ArrayOperationPartialInlineSize != 0 &&
- ArrayOperationPartialInlineSize != 16 &&
- ArrayOperationPartialInlineSize != 32 &&
- ArrayOperationPartialInlineSize != 64)) {
- int inline_size = 0;
- if (MaxVectorSize >= 64 && AVX3Threshold == 0) {
- inline_size = 64;
- } else if (MaxVectorSize >= 32) {
- inline_size = 32;
- } else if (MaxVectorSize >= 16) {
- inline_size = 16;
- }
- if(!FLAG_IS_DEFAULT(ArrayOperationPartialInlineSize)) {
- warning("Setting ArrayOperationPartialInlineSize as %d", inline_size);
- }
- ArrayOperationPartialInlineSize = inline_size;
- }
-
- if (ArrayOperationPartialInlineSize > MaxVectorSize) {
- ArrayOperationPartialInlineSize = MaxVectorSize >= 16 ? MaxVectorSize : 0;
- if (ArrayOperationPartialInlineSize) {
- warning("Setting ArrayOperationPartialInlineSize as MaxVectorSize=%zd", MaxVectorSize);
- } else {
- warning("Setting ArrayOperationPartialInlineSize as %zd", ArrayOperationPartialInlineSize);
- }
- }
- }
-#endif
}
#ifdef COMPILER2
+ if (UseAVX > 2) {
+ if (FLAG_IS_DEFAULT(ArrayOperationPartialInlineSize) ||
+ (!FLAG_IS_DEFAULT(ArrayOperationPartialInlineSize) &&
+ ArrayOperationPartialInlineSize != 0 &&
+ ArrayOperationPartialInlineSize != 16 &&
+ ArrayOperationPartialInlineSize != 32 &&
+ ArrayOperationPartialInlineSize != 64)) {
+ int inline_size = 0;
+ if (MaxVectorSize >= 64 && AVX3Threshold == 0) {
+ inline_size = 64;
+ } else if (MaxVectorSize >= 32) {
+ inline_size = 32;
+ } else if (MaxVectorSize >= 16) {
+ inline_size = 16;
+ }
+ if(!FLAG_IS_DEFAULT(ArrayOperationPartialInlineSize)) {
+ warning("Setting ArrayOperationPartialInlineSize as %d", inline_size);
+ }
+ ArrayOperationPartialInlineSize = inline_size;
+ }
+
+ if (ArrayOperationPartialInlineSize > MaxVectorSize) {
+ ArrayOperationPartialInlineSize = MaxVectorSize >= 16 ? MaxVectorSize : 0;
+ if (ArrayOperationPartialInlineSize) {
+ warning("Setting ArrayOperationPartialInlineSize as MaxVectorSize=%zd", MaxVectorSize);
+ } else {
+ warning("Setting ArrayOperationPartialInlineSize as %zd", ArrayOperationPartialInlineSize);
+ }
+ }
+ }
+
if (FLAG_IS_DEFAULT(OptimizeFill)) {
if (MaxVectorSize < 32 || (!EnableX86ECoreOpts && !VM_Version::supports_avx512vlbw())) {
OptimizeFill = false;
diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/ArrayMismatchBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/ArrayMismatchBenchmark.java
index 2d327958594..876ed43b32e 100644
--- a/test/micro/org/openjdk/bench/jdk/incubator/vector/ArrayMismatchBenchmark.java
+++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/ArrayMismatchBenchmark.java
@@ -26,6 +26,7 @@ package org.openjdk.bench.jdk.incubator.vector;
import jdk.incubator.vector.ByteVector;
+import jdk.incubator.vector.ShortVector;
import jdk.incubator.vector.DoubleVector;
import jdk.incubator.vector.IntVector;
import jdk.incubator.vector.LongVector;
@@ -59,6 +60,9 @@ public class ArrayMismatchBenchmark {
byte[] byteData1;
byte[] byteData2;
+ short[] shortData1;
+ short[] shortData2;
+
int[] intData1;
int[] intData2;
@@ -69,6 +73,7 @@ public class ArrayMismatchBenchmark {
double[] doubleData2;
static final VectorSpecies BYTE_SPECIES_PREFERRED = ByteVector.SPECIES_PREFERRED;
+ static final VectorSpecies